Merge: Beef up OrderedTree API
authorJean Privat <jean@pryen.org>
Wed, 23 Sep 2015 18:20:22 +0000 (14:20 -0400)
committerJean Privat <jean@pryen.org>
Wed, 23 Sep 2015 18:20:22 +0000 (14:20 -0400)
This add services to the class OrderedTree

Pull-Request: #1732
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

78 files changed:
benchmarks/polygons/nit/bench_polygon.nit
contrib/brainfuck/brainfuck.nit
contrib/friendz/src/grid.nit
contrib/memory/.gitignore [new file with mode: 0644]
contrib/memory/Makefile [new file with mode: 0644]
contrib/memory/README.md [new file with mode: 0644]
contrib/memory/art/drawing.svg [new file with mode: 0644]
contrib/memory/art/icon.svg [new file with mode: 0644]
contrib/memory/assets/bing.wav [new file with mode: 0644]
contrib/memory/assets/boing.wav [new file with mode: 0644]
contrib/memory/assets/click.wav [new file with mode: 0644]
contrib/memory/assets/cymbal.wav [new file with mode: 0644]
contrib/memory/assets/dart.wav [new file with mode: 0644]
contrib/memory/assets/duh.wav [new file with mode: 0644]
contrib/memory/assets/grunt.wav [new file with mode: 0644]
contrib/memory/assets/honkhonk.wav [new file with mode: 0644]
contrib/memory/assets/level.wav [new file with mode: 0644]
contrib/memory/assets/line_end.wav [new file with mode: 0644]
contrib/memory/assets/penalty.wav [new file with mode: 0644]
contrib/memory/assets/squishy-hit.wav [new file with mode: 0644]
contrib/memory/assets/whip.wav [new file with mode: 0644]
contrib/memory/assets/woodthunk.wav [new file with mode: 0644]
contrib/memory/org.nitlanguage.memory.txt [new file with mode: 0644]
contrib/memory/package.ini [new file with mode: 0644]
contrib/memory/src/memory.nit [new file with mode: 0644]
contrib/nitcc/src/autom.nit
contrib/nitcc/src/nitcc_semantic.nit
contrib/nitcc/src/re2nfa.nit
contrib/pep8analysis/src/location.nit
contrib/pep8analysis/src/model/operands.nit
contrib/pep8analysis/src/parser/lexer.nit
examples/rosettacode/vignere_cipher.nit
lib/base64.nit
lib/bcm2835/bcm2835.nit
lib/binary/binary.nit
lib/binary/serialization.nit
lib/bitmap/bitmap.nit
lib/buffered_ropes.nit
lib/console.nit
lib/core/bytes.nit
lib/core/fixed_ints.nit
lib/core/kernel.nit
lib/core/math.nit
lib/core/stream.nit
lib/core/text/abstract_text.nit
lib/core/text/flat.nit
lib/core/text/native.nit
lib/core/text/ropes.nit
lib/crypto.nit
lib/geometry/README.md [new file with mode: 0644]
lib/geometry/polygon.nit
lib/json/json_lexer.nit
lib/json/static.nit
lib/mnit/numbers.nit
lib/saxophonit/lexer.nit
lib/saxophonit/saxophonit.nit
src/compiler/abstract_compiler.nit
src/compiler/separate_compiler.nit
src/doc/doc_phases/doc_console.nit
src/interpreter/naive_interpreter.nit
src/location.nit
src/parser/lexer_work.nit
src/toolcontext.nit
tests/base_eq_int4.nit [new file with mode: 0644]
tests/base_eq_int4b.nit [new file with mode: 0644]
tests/base_eq_int4c.nit [new file with mode: 0644]
tests/base_primitive_null.nit
tests/sav/base_eq_int4.res [new file with mode: 0644]
tests/sav/base_eq_int4b.res [new file with mode: 0644]
tests/sav/base_eq_int4c.res [new file with mode: 0644]
tests/sav/error_class_glob.res
tests/sav/nitce/fixme/base_gen_reassign_alt4.res
tests/sav/nitce/fixme/base_gen_reassign_alt5.res
tests/sav/nitce/fixme/base_gen_reassign_alt6.res
tests/sav/nituml_args3.res
tests/sav/nituml_args4.res
tests/test_string_unicode.nit
tests/test_unicode_4bytes.nit

index 695f4aa..d2224b9 100644 (file)
@@ -25,7 +25,7 @@ fun bench_add_vertices(n: Int) do
        var randompoints = generate_points(n + 1)
        var points = randompoints.clone
        points.remove_at(points.length -1)
-       var poly = new ConvexPolygon.with_vertices(randompoints)
+       var poly = new ConvexPolygon(randompoints)
        poly.sort_ccw
        poly.add_vertex(randompoints.last)
 end
@@ -45,7 +45,7 @@ end
 # Bench the convexity verificatioon
 fun bench_convexity(n : Int) do
        var randompoints = generate_points(n)
-       var poly = new ConvexPolygon.with_vertices(randompoints)
+       var poly = new ConvexPolygon(randompoints)
        poly.sort_ccw
        poly.is_convex
 end
@@ -54,7 +54,7 @@ end
 fun bench_contain(n : Int) do
        srand_from(50)
        var randompoints = generate_points(n)
-       var poly = new ConvexPolygon.with_vertices(randompoints)
+       var poly = new ConvexPolygon(randompoints)
        poly.sort_ccw
        var point = new Point[Float](0.0, 0.0)
        poly.contain(point)
@@ -64,7 +64,7 @@ end
 fun bench_sorting(n : Int) do
        var randompoints = generate_points(n)
        randompoints.shuffle
-       var poly = new ConvexPolygon.with_vertices(randompoints)
+       var poly = new ConvexPolygon(randompoints)
        poly.sort_ccw
 
 end
@@ -73,8 +73,8 @@ end
 fun bench_intersection(n : Int) do
        var r1 = generate_points(n)
        var r2 = generate_points(n)
-       var poly1 = new ConvexPolygon.with_vertices(r1)
-       var poly2 = new ConvexPolygon.with_vertices(r2)
+       var poly1 = new ConvexPolygon(r1)
+       var poly2 = new ConvexPolygon(r2)
        poly1.sort_ccw
        poly2.sort_ccw
        poly1.intersects(poly2)
index f7de908..4216952 100644 (file)
@@ -18,29 +18,24 @@ module brainfuck
 # Interpreter for Brainfuck source code.
 class BFInterpreter
        # Data cells
-       var dr = new Array[Char]
+       var dr = new Array[Byte]
        # Data pointer
        var dp = 0
        # Instruction pointer
        var ip = 0
 
        # The program being interpreted
-       var program: String
-
-       # Contains the set of valid instructions, used in next
-       var valid_instr: Set[Char] is noinit
+       var program: Bytes
 
        # Create an interpreter for `program`.
        init do
-               valid_instr = new HashSet[Char]
-               valid_instr.add_all "><[].,+-".chars
-               dr.add 0.ascii
+               dr.add 0u8
        end
 
        # Create an interpreter for the file located at `path`.
        init from_file(path: String) do
                var ifs = new FileReader.open(path)
-               init(ifs.read_all)
+               init(ifs.read_all_bytes)
        end
 
        # Starts the interpretation of the loaded program
@@ -48,50 +43,43 @@ class BFInterpreter
                loop
                        if ip >= program.length then break
                        eval
-                       next
-               end
-       end
-
-       # Go to the next executable instruction
-       fun next do
-               ip += 1
-               while ip < program.length and not valid_instr.has(program[ip]) do
                        ip += 1
                end
        end
 
+
        # Evaluates the current instruction
        fun eval do
                var instr = program[ip]
-               if instr == '.' then printn dr[dp]
-               if instr == '[' then
-                       if dr[dp] == 0.ascii then
+               if instr == '.'.ascii then printn dr[dp].ascii
+               if instr == '['.ascii then
+                       if dr[dp] == 0u8 then
                                ip = find_matching_rbra
                                return
                        end
                end
-               if instr == ']' then
-                       if dr[dp] != 0.ascii then
+               if instr == ']'.ascii then
+                       if dr[dp] != 0u8 then
                                ip = find_matching_lbra
                                return
                        end
                end
-               if instr == '>' then
+               if instr == '>'.ascii then
                        dp += 1
-                       if dp >= dr.length then dr.add(0.ascii)
+                       if dp >= dr.length then dr.add(0u8)
                end
-               if instr == '<' then
+               if instr == '<'.ascii then
                        dp -= 1
                        if dp < 0 then abort
                end
-               if instr == '+' then
-                       dr[dp] = (dr[dp].ascii + 1).ascii
+               if instr == '+'.ascii then
+                       dr[dp] = dr[dp] + 1u8
                end
-               if instr == '-' then
-                       dr[dp] = (dr[dp].ascii - 1).ascii
+               if instr == '-'.ascii then
+                       dr[dp] = dr[dp] - 1u8
                end
-               if instr == ',' then
-                       dr[dp] = getc
+               if instr == ','.ascii then
+                       dr[dp] = getc.ascii
                end
        end
 
@@ -101,14 +89,14 @@ class BFInterpreter
                var lbracnt = 0
                loop
                        if pos > program.length then abort
-                       if program[pos] == ']' then
+                       if program[pos] == ']'.ascii then
                                if lbracnt > 0 then
                                        lbracnt -= 1
                                else
                                        break
                                end
                        end
-                       if program[pos] == '[' then lbracnt += 1
+                       if program[pos] == '['.ascii then lbracnt += 1
                        pos += 1
                end
                return pos
@@ -120,14 +108,14 @@ class BFInterpreter
                var rbracnt = 0
                loop
                        if pos < 0 then abort
-                       if program[pos] == '[' then
+                       if program[pos] == '['.ascii then
                                if rbracnt > 0 then
                                        rbracnt -= 1
                                else
                                        break
                                end
                        end
-                       if program[pos] == ']' then rbracnt += 1
+                       if program[pos] == ']'.ascii then rbracnt += 1
                        pos -= 1
                end
                return pos
index 3a141f6..6f1c883 100644 (file)
@@ -249,13 +249,13 @@ class Grid
                                else if c >= 'A' and c <= 'I' then
                                        var t = self.get(x,y)
                                        assert t != null
-                                       t.update(c.ascii-'A'.ascii+1)
+                                       t.update(c.code_point-'A'.code_point+1)
                                        t.fixed = true
                                        x += 1
                                else if c >= 'a' and c <= 'i' then
                                        var t = self.get(x,y)
                                        assert t != null
-                                       t.update(c.ascii-'a'.ascii+1)
+                                       t.update(c.code_point-'a'.code_point+1)
                                        x += 1
                                else if c >= '1' and c <= '9' then
                                        rle = c.to_i
@@ -289,16 +289,16 @@ class Grid
                                if k == 0 then
                                        if t.fixed then c = '#'
                                else
-                                       b.add(0x1b.ascii)
+                                       b.add(0x1b.code_point)
                                        b.add('[')
                                        b.append ansicols[k]
-                                       c = (k + 'a'.ascii - 1).ascii
+                                       c = (k + 'a'.code_point - 1).code_point
                                        if t.fixed then c = c.to_upper
                                        b.append("m")
                                end
                                b.add(c)
                                if k != 0 then
-                                       b.add(0x1b.ascii)
+                                       b.add(0x1b.code_point)
                                        b.append("[0m")
 
                                end
diff --git a/contrib/memory/.gitignore b/contrib/memory/.gitignore
new file mode 100644 (file)
index 0000000..c4781eb
--- /dev/null
@@ -0,0 +1,3 @@
+assets/images/
+res/
+src/drawing.nit
diff --git a/contrib/memory/Makefile b/contrib/memory/Makefile
new file mode 100644 (file)
index 0000000..8e39e1d
--- /dev/null
@@ -0,0 +1,36 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+all: bin/memory
+
+bin/memory: assets/images/drawing.png src/*.nit
+       mkdir -p bin
+       ../../bin/nitc -o bin/memory src/memory.nit -m ../../lib/mnit/linux/linux.nit
+
+assets/images/drawing.png: art/drawing.svg
+       mkdir -p assets/images/
+       ../inkscape_tools/bin/svg_to_png_and_nit art/drawing.svg -a assets/ -s src/ -x 4
+
+res/drawable-ldpi/icon.png: art/icon.svg
+       mkdir -p res/
+       ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
+
+android: bin/memory.apk
+bin/memory.apk: assets/images/drawing.png src/*.nit res/drawable-ldpi/icon.png
+       mkdir -p bin
+       ../../bin/nitc -o bin/memory.apk src/memory.nit -m ../../lib/mnit/android/android.nit -m ../../lib/android/landscape.nit
+
+android-release: assets/images/drawing.png src/*.nit res/drawable-ldpi/icon.png
+       mkdir -p bin
+       ../../bin/nitc -o bin/memory.apk src/memory.nit -m ../../lib/mnit/android/android.nit -m ../../lib/android/  landscape.nit  --release
diff --git a/contrib/memory/README.md b/contrib/memory/README.md
new file mode 100644 (file)
index 0000000..ffbcdae
--- /dev/null
@@ -0,0 +1,31 @@
+# Memorize Shapes and Colors
+
+A memory-based game where figures are cliqued in sequence by the computer and should be replayed by the player in the same order.
+As the player progresses, more figures are added and the sequences to remember become longer.
+
+The player can make up to 2 errors to solve a single level.
+At the 3rd error, the level has to be replayed.
+
+The game use a very simple user interface and features big figures with bright colors and simple distinguishable shapes; that makes it suitable for young children.
+
+The game offers three modes (difficulty level)
+
+Easy (for young children):
+
+* Start with 2 figures, 1 to remember
+* Figures are easily distinguishable
+* Figures remain on place
+* After 3 errors, the same level is replayed
+
+Medium (for normal player):
+
+* Like easy but:
+* Start with 3 figures, 3 to remember
+* Figures are moved after the sequence played by the computer
+* After 3 errors, a new level is produced
+
+Hard (for hypermnesic players)
+
+* Like medium but:
+* Figures use overlapping combinations of colors and shapes
+* Figures are shuffled completely
diff --git a/contrib/memory/art/drawing.svg b/contrib/memory/art/drawing.svg
new file mode 100644 (file)
index 0000000..7a4cd1c
--- /dev/null
@@ -0,0 +1,368 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="509.0834"
+   height="324.85132"
+   viewBox="0 0 509.08342 324.85131"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="drawing.svg"
+   inkscape:export-filename="/home/privat/prog/nit/contrib/memory/art/drawing.png"
+   inkscape:export-xdpi="900"
+   inkscape:export-ydpi="900">
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="326.44213"
+     inkscape:cy="188.58838"
+     inkscape:document-units="pt"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1136"
+     inkscape:window-x="1600"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:snap-text-baseline="false"
+     units="pt" />
+  <defs
+     id="defs4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     transform="translate(-112.50514,-37.583924)"
+     id="layer1"
+     inkscape:groupmode="layer"
+     inkscape:label="Calque 1">
+    <path
+       transform="matrix(1.0790955,0,0,1.1325291,-9.0916016,-22.007078)"
+       inkscape:label="#path3338"
+       inkscape:transform-center-y="-3.9327809"
+       inkscape:transform-center-x="1.3947101"
+       d="m 180.81731,133.12338 -25.13223,-13.03035 -24.98194,13.31622 4.62632,-27.92877 -20.38433,-19.644302 27.99145,-4.230572 12.38374,-25.457066 12.67335,25.314133 28.03789,3.910967 -20.15889,19.87557 z"
+       inkscape:randomized="0"
+       inkscape:rounded="0"
+       inkscape:flatsided="false"
+       sodipodi:arg2="1.5650921"
+       sodipodi:arg1="0.9367736"
+       sodipodi:r2="21.315176"
+       sodipodi:r1="42.630352"
+       sodipodi:cy="98.778198"
+       sodipodi:cx="155.56349"
+       sodipodi:sides="5"
+       id="0star"
+       style="fill:#ffffff;fill-opacity:1;stroke:#808080;stroke-width:4.52288342;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       sodipodi:type="star" />
+    <ellipse
+       inkscape:label="#path3342"
+       ry="43.75"
+       rx="43.750004"
+       cy="87.475639"
+       cx="256.61908"
+       id="0circle"
+       style="fill:#ffffff;stroke:#808080;stroke-width:5.00000048;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <rect
+       inkscape:label="#rect3346"
+       y="44.975639"
+       x="319.36441"
+       height="81.250008"
+       width="81.250008"
+       id="0rect"
+       style="fill:#ffffff;stroke:#808080;stroke-width:5.00000048;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <path
+       transform="matrix(1.138458,0.01858784,-0.01944847,1.1911688,-113.46281,-38.903848)"
+       inkscape:label="#path3348"
+       inkscape:transform-center-y="-4.0794014"
+       inkscape:transform-center-x="0.47783259"
+       d="m 536.391,131.10309 -47.49475,0.72114 -15.36253,-44.947336 38.00017,-28.500132 38.84794,27.33329 z"
+       inkscape:randomized="0"
+       inkscape:rounded="0"
+       inkscape:flatsided="true"
+       sodipodi:arg2="1.5556138"
+       sodipodi:arg1="0.92729522"
+       sodipodi:r2="32.545895"
+       sodipodi:r1="40.406101"
+       sodipodi:cy="98.778206"
+       sodipodi:cx="512.14734"
+       sodipodi:sides="5"
+       id="0penta"
+       style="fill:#ffffff;stroke:#808080;stroke-width:4.2930603;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       sodipodi:type="star" />
+    <path
+       transform="matrix(0.9848695,-0.0389352,0.04401556,1.1133778,-29.129711,11.863574)"
+       inkscape:label="#path3350"
+       inkscape:transform-center-y="-5.2078962"
+       inkscape:transform-center-x="-1.6611955"
+       d="m 652.55851,129.08278 -88.77492,-3.29401 47.24016,-75.23433 z"
+       inkscape:randomized="0"
+       inkscape:rounded="0"
+       inkscape:flatsided="true"
+       sodipodi:arg2="1.6078845"
+       sodipodi:arg1="0.56068699"
+       sodipodi:r2="34.010933"
+       sodipodi:r1="51.289494"
+       sodipodi:cy="101.80866"
+       sodipodi:cx="609.12195"
+       sodipodi:sides="3"
+       id="0triangle"
+       style="fill:#ffffff;stroke:#808080;stroke-width:4.77111959;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       sodipodi:type="star" />
+    <g
+       transform="translate(-7.1428071,-28.263269)"
+       style="fill:#ffffff;stroke:#808080;stroke-width:5.00000048;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       inkscape:label="#g3356"
+       id="0cross">
+      <path
+         style="fill:#ffffff;stroke:#808080;stroke-width:5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         d="m 42.5625,125.5 0,31.25 -31.25,0 0,25 31.25,0 0,31.25 25,0 0,-31.25 31.25,0 0,-25 -31.25,0 0,-31.25 -25,0 z"
+         transform="translate(114.94512,48.417475)"
+         id="rect3352"
+         inkscape:connector-curvature="0" />
+    </g>
+    <rect
+       inkscape:label="#rect3341"
+       transform="matrix(0.68019493,0.73303128,-0.73365707,0.67951991,0,0)"
+       ry="0"
+       y="-93.236977"
+       x="286.09988"
+       height="61.163219"
+       width="62.66906"
+       id="0diamond"
+       style="fill:#ffffff;stroke:#808080;stroke-width:5.00000143;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <path
+       inkscape:label="#path3350"
+       inkscape:connector-curvature="0"
+       id="0moon"
+       d="m 368.00103,142.79236 a 50.857007,43.749388 0 0 0 -50.85758,43.75075 50.857007,43.749388 0 0 0 50.85758,43.74925 50.857007,43.749388 0 0 0 36.5966,-13.44214 37.525559,30.468323 0 0 1 -3.51512,0.16013 37.525559,30.468323 0 0 1 -37.52646,-30.46724 37.525559,30.468323 0 0 1 37.52646,-30.46873 37.525559,30.468323 0 0 1 3.56094,0.14501 50.857007,43.749388 0 0 0 -36.64242,-13.42703 z"
+       style="fill:#ffffff;stroke:#808080;stroke-width:5.00000048;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <path
+       inkscape:label="#path3356"
+       inkscape:connector-curvature="0"
+       id="0spiral"
+       d="m 467.10669,144.22922 c -20.15895,-0.32141 -38.9065,16.76425 -41.19858,37.60291 -3.86937,23.35281 16.7358,47.48676 39.64103,45.31644 12.20102,-0.76865 23.76919,-8.45705 29.03604,-20.00332 6.61043,-13.59525 3.19101,-31.78746 -8.72849,-41.00231 -11.91023,-9.84408 -31.5447,-7.79332 -40.34686,5.46911 -8.25602,11.53909 -5.3078,30.58816 7.47626,37.21364 10.28179,6.05468 25.63854,1.15001 29.0991,-11.11553 3.04684,-9.25632 -2.65279,-21.09349 -12.45674,-22.21563 -7.74971,-1.31975 -16.07358,6.63167 -13.65087,14.90034 1.37551,7.39459 14.12722,8.17257 14.08847,-0.22482 -0.0955,-2.72794 -2.63922,-5.69968 -5.32908,-4.79848 4.38499,-3.96292 10.36557,1.52768 9.81632,6.69218 0.19607,6.907 -6.58875,11.92951 -12.86343,10.71083 -8.21344,-0.99562 -14.24185,-9.85518 -12.49382,-18.25737 1.54211,-10.78621 12.75113,-18.38943 22.89359,-15.65962 11.86257,2.42582 20.00065,15.79672 17.20605,27.99309 -2.41584,13.54418 -15.7679,23.59081 -28.91368,21.59767 -14.20193,-1.45306 -26.32571,-14.644 -26.46485,-29.59643 -0.8484,-17.59211 12.58621,-34.40757 29.59974,-35.87494 17.64776,-2.34404 36.43269,10.56977 40.14043,28.9258 3.86993,15.99133 -2.31691,34.4508 -15.45688,44.18203 -0.10231,3.94543 4.80831,7.62163 7.87431,4.41178 19.69304,-16.79994 22.96064,-50.96148 5.42672,-70.6373 -8.57029,-10.04432 -21.48622,-15.8896 -34.39478,-15.63007 z"
+       style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#808080;stroke-width:5.00000048;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:accumulate" />
+    <g
+       id="0heart"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:113.93434906px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#808080;stroke-width:4.7127285;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       transform="matrix(1.0677772,0,0,1.0541795,-59.938025,-33.284976)">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2998"
+         d="m 572.55695,170.41572 c 7.52883,8e-5 13.44436,4.35792 17.74661,13.07352 1.55765,3.44925 2.37358,6.0825 2.44781,7.89974 l 0.1669,0 c 1.29802,-6.00819 3.65311,-10.99652 7.06526,-14.96501 4.00544,-4.00542 8.51163,-6.00817 13.51858,-6.00825 7.75131,8e-5 13.96355,4.15393 18.63672,12.46157 1.18672,3.07837 1.78013,5.97123 1.78022,8.67859 -9e-5,9.27205 -3.85724,18.11753 -11.57145,26.53647 l -29.42933,35.32632 -0.3338,0 -31.26518,-38.33045 c -6.2308,-7.603 -9.34619,-15.4471 -9.34618,-23.53234 -10e-6,-7.8255 3.69024,-14.03773 11.07077,-18.63672 3.11537,-1.66888 6.28639,-2.50336 9.51307,-2.50344"
+         style="stroke:#808080;stroke-width:4.7127285;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    </g>
+    <path
+       style="fill:#000000;fill-opacity:0.57983195;fill-rule:nonzero;stroke:#000000;stroke-width:2.50000024;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 261.37374,293.86379 c -21.42857,-42.85714 -21.42857,-42.85714 -21.42857,-42.85714 l 40.71428,25 z"
+       id="0cursor"
+       inkscape:connector-curvature="0"
+       inkscape:label="#path3043" />
+    <g
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:125%;font-family:'Droid Sans';-inkscape-font-specification:'Droid Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="0hard0"
+       inkscape:label="#text5595"
+       transform="matrix(0.7,0,0,0.7,64.765671,18.829203)">
+      <g
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;line-height:125%;font-family:'Droid Sans';-inkscape-font-specification:'Droid Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="text5638">
+        <path
+           d="m 361.89825,341.57028 q -1.58203,0 -2.63671,1.11328 -1.03516,1.11328 -1.19141,3.4961 l 7.59766,0 q -0.0195,-0.9961 -0.25391,-1.83594 -0.23438,-0.83984 -0.70313,-1.44531 -0.46875,-0.625 -1.17187,-0.97657 -0.70313,-0.35156 -1.64063,-0.35156 z m 0.76172,18.39844 q -2.34375,0 -4.3164,-0.68359 -1.97266,-0.6836 -3.39844,-2.05079 -1.42578,-1.38671 -2.22656,-3.47656 -0.78125,-2.10937 -0.78125,-4.9414 0,-2.8711 0.72265,-5.01954 0.72266,-2.14843 2.01172,-3.57421 1.3086,-1.44532 3.125,-2.16797 1.83594,-0.72266 4.0625,-0.72266 2.16797,0 3.90625,0.66406 1.75781,0.64453 2.96875,1.91407 1.23047,1.26953 1.875,3.125 0.66406,1.83593 0.66406,4.21875 l 0,2.89062 -13.32031,0 q 0.0391,1.25 0.39063,2.26563 0.37109,0.99609 1.01562,1.69921 0.66406,0.6836 1.58203,1.05469 0.9375,0.3711 2.12891,0.3711 0.99609,0 1.875,-0.0977 0.89844,-0.11719 1.73828,-0.33203 0.83984,-0.21485 1.66016,-0.52735 0.82031,-0.33203 1.67968,-0.76171 l 0,4.60937 q -0.78125,0.41016 -1.58203,0.70313 -0.78125,0.27343 -1.66015,0.46875 -0.87891,0.19531 -1.89453,0.27343 -1.01563,0.0977 -2.22657,0.0977 z"
+           style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           id="path5643"
+           inkscape:connector-curvature="0" />
+        <path
+           d="m 389.02716,359.57809 -1.15234,-2.96875 -0.17578,0 q -0.64454,0.87891 -1.28907,1.52344 -0.64453,0.625 -1.40625,1.03516 -0.76172,0.41015 -1.71875,0.60547 -0.9375,0.19531 -2.1875,0.19531 -1.32812,0 -2.46093,-0.41016 -1.13282,-0.42968 -1.97266,-1.26953 -0.82031,-0.85937 -1.28906,-2.14844 -0.46875,-1.30859 -0.46875,-3.08593 0,-3.47657 2.22656,-5.11719 2.22656,-1.66016 6.66016,-1.83594 l 3.47656,-0.11719 0,-1.64062 q 0,-1.34766 -0.78125,-1.99219 -0.78125,-0.64453 -2.1875,-0.64453 -1.40625,0 -2.75391,0.41016 -1.32812,0.41015 -2.67578,1.09375 l -1.93359,-3.94532 q 1.64062,-0.91796 3.63281,-1.44531 1.99219,-0.52734 4.17969,-0.52734 4.08203,0 6.25,1.91406 2.1875,1.91406 2.1875,5.82031 l 0,14.55078 -4.16016,0 z m -1.75781,-10.11718 -1.97266,0.0781 q -1.1914,0.0391 -2.01172,0.3125 -0.82031,0.27344 -1.32812,0.74219 -0.48828,0.44922 -0.72266,1.09375 -0.21484,0.625 -0.21484,1.40625 0,1.36719 0.66406,1.95312 0.66406,0.56641 1.73828,0.56641 0.82031,0 1.52344,-0.27344 0.70312,-0.29297 1.21094,-0.83984 0.52734,-0.56641 0.82031,-1.36719 0.29297,-0.82031 0.29297,-1.875 l 0,-1.79687 z"
+           style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           id="path5645"
+           inkscape:connector-curvature="0" />
+        <path
+           d="m 413.87091,353.09372 q 0,1.71875 -0.625,3.00781 -0.625,1.28906 -1.77734,2.14844 -1.15235,0.85937 -2.79297,1.28906 -1.64063,0.42969 -3.67188,0.42969 -1.07422,0 -1.99218,-0.0781 -0.91797,-0.0586 -1.73829,-0.21484 -0.82031,-0.15625 -1.58203,-0.39062 -0.76172,-0.23438 -1.54297,-0.58594 l 0,-4.92188 q 0.82032,0.41016 1.71875,0.74219 0.91797,0.33203 1.81641,0.58594 0.89844,0.23437 1.73828,0.37109 0.85938,0.13672 1.58203,0.13672 0.80078,0 1.36719,-0.13672 0.56641,-0.15625 0.91797,-0.41015 0.37109,-0.27344 0.52734,-0.625 0.17578,-0.3711 0.17578,-0.78125 0,-0.41016 -0.13671,-0.72266 -0.11719,-0.33203 -0.56641,-0.68359 -0.44922,-0.3711 -1.32813,-0.82032 -0.85937,-0.46875 -2.32421,-1.13281 -1.42579,-0.64453 -2.48047,-1.26953 -1.03516,-0.64453 -1.71875,-1.42578 -0.66407,-0.78125 -0.9961,-1.77735 -0.33203,-1.01562 -0.33203,-2.40234 0,-1.52344 0.58594,-2.65625 0.58594,-1.15234 1.66016,-1.91406 1.07421,-0.76172 2.57812,-1.13281 1.52344,-0.39063 3.37891,-0.39063 1.95312,0 3.71093,0.44922 1.75782,0.44922 3.61329,1.34766 l -1.79688,4.21875 q -1.48437,-0.70313 -2.83203,-1.15235 -1.34766,-0.44922 -2.69531,-0.44922 -1.21094,0 -1.75782,0.42969 -0.52734,0.42969 -0.52734,1.17188 0,0.39062 0.13672,0.70312 0.13672,0.29297 0.54687,0.625 0.41016,0.3125 1.15235,0.70313 0.74219,0.37109 1.93359,0.91796 1.38672,0.60547 2.5,1.21094 1.11328,0.58594 1.91406,1.34766 0.80079,0.76172 1.23047,1.77734 0.42969,1.01563 0.42969,2.46094 z"
+           style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           id="path5647"
+           inkscape:connector-curvature="0" />
+        <path
+           d="m 415.41388,337.74216 6.52344,0 3.51562,12.28515 q 0.3125,1.01563 0.44922,2.16797 0.15625,1.15235 0.19531,2.07031 l 0.11719,0 q 0.0391,-0.44921 0.0977,-0.99609 0.0781,-0.54687 0.17578,-1.11328 0.0977,-0.56641 0.21484,-1.11328 0.13672,-0.56641 0.27344,-1.01563 l 3.4375,-12.28515 6.5625,0 -8.63281,24.6289 q -1.21094,3.45703 -3.30078,5.13672 -2.08985,1.67969 -5.23438,1.67969 -1.01562,0 -1.75781,-0.11719 -0.74219,-0.0977 -1.26953,-0.21484 l 0,-4.72656 q 0.41015,0.0977 1.03515,0.17578 0.625,0.0781 1.3086,0.0781 0.9375,0 1.60156,-0.2539 0.66406,-0.25391 1.13281,-0.72266 0.48828,-0.44922 0.82031,-1.09375 0.35157,-0.64453 0.60547,-1.44531 l 0.3711,-1.09375 -8.24219,-22.03125 z"
+           style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           id="path5649"
+           inkscape:connector-curvature="0" />
+      </g>
+    </g>
+    <g
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;line-height:125%;font-family:'Droid Sans';-inkscape-font-specification:'Droid Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="0hard1"
+       inkscape:label="#text5599"
+       transform="matrix(0.7,0,0,0.7,55.673321,14.516296)">
+      <path
+         d="m 372.53442,411.00665 -5.95703,0 0,-12.7539 q 0,-2.36328 -0.70312,-3.53516 -0.70313,-1.19141 -2.20703,-1.19141 -1.13282,0 -1.89453,0.46875 -0.74219,0.46875 -1.19141,1.38672 -0.44922,0.91797 -0.64453,2.26563 -0.19531,1.34765 -0.19531,3.08594 l 0,10.27343 -5.95704,0 0,-21.83593 4.55079,0 0.80078,2.79296 0.33203,0 q 0.46875,-0.83984 1.11328,-1.44531 0.66406,-0.60547 1.44531,-0.99609 0.78125,-0.39063 1.66016,-0.56641 0.8789,-0.19531 1.77734,-0.19531 2.2461,0 3.8086,0.78125 1.58203,0.76172 2.42187,2.42187 l 0.48828,0 q 0.46875,-0.83984 1.13281,-1.44531 0.66407,-0.60547 1.46485,-0.99609 0.80078,-0.39063 1.67969,-0.56641 0.89843,-0.19531 1.79687,-0.19531 3.51563,0 5.29297,1.91406 1.79687,1.89453 1.79687,6.09375 l 0,14.23828 -5.97656,0 0,-12.7539 q 0,-2.36328 -0.70312,-3.53516 -0.70313,-1.19141 -2.20703,-1.19141 -2.12891,0 -3.02735,1.69922 -0.89844,1.67969 -0.89844,4.82422 l 0,10.95703 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path5626"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 400.2688,392.99884 q -1.58203,0 -2.63672,1.11328 -1.03516,1.11328 -1.19141,3.4961 l 7.59766,0 q -0.0195,-0.9961 -0.25391,-1.83594 -0.23437,-0.83985 -0.70312,-1.44531 -0.46875,-0.625 -1.17188,-0.97657 -0.70312,-0.35156 -1.64062,-0.35156 z m 0.76172,18.39844 q -2.34375,0 -4.31641,-0.6836 -1.97265,-0.68359 -3.39844,-2.05078 -1.42578,-1.38672 -2.22656,-3.47656 -0.78125,-2.10937 -0.78125,-4.94141 0,-2.87109 0.72266,-5.01953 0.72265,-2.14843 2.01172,-3.57422 1.30859,-1.44531 3.125,-2.16796 1.83593,-0.72266 4.0625,-0.72266 2.16797,0 3.90625,0.66406 1.75781,0.64453 2.96875,1.91406 1.23047,1.26954 1.875,3.125 0.66406,1.83594 0.66406,4.21875 l 0,2.89063 -13.32031,0 q 0.0391,1.25 0.39062,2.26562 0.3711,0.9961 1.01563,1.69922 0.66406,0.6836 1.58203,1.05469 0.9375,0.37109 2.1289,0.37109 0.9961,0 1.875,-0.0976 0.89844,-0.11719 1.73829,-0.33203 0.83984,-0.21485 1.66015,-0.52735 0.82031,-0.33203 1.67969,-0.76172 l 0,4.60938 q -0.78125,0.41016 -1.58203,0.70312 -0.78125,0.27344 -1.66016,0.46875 -0.8789,0.19532 -1.89453,0.27344 -1.01562,0.0977 -2.22656,0.0977 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path5628"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 421.14771,411.39728 q -1.67969,0 -3.06641,-0.72266 -1.38672,-0.72265 -2.38281,-2.1289 -0.9961,-1.42579 -1.5625,-3.53516 -0.54688,-2.10938 -0.54688,-4.88281 0,-2.8125 0.54688,-4.92188 0.5664,-2.1289 1.58203,-3.55469 1.03515,-1.44531 2.46094,-2.16796 1.42578,-0.72266 3.14453,-0.72266 1.05468,0 1.93359,0.25391 0.87891,0.23437 1.58203,0.68359 0.70313,0.42969 1.25,1.01562 0.56641,0.56641 0.9961,1.25 l 0.19531,0 q -0.11719,-0.76171 -0.21485,-1.54296 -0.0976,-0.66407 -0.17578,-1.40625 -0.0586,-0.76172 -0.0586,-1.40625 l 0,-6.99219 5.95703,0 0,30.39062 -4.55078,0 -1.15234,-2.83203 -0.25391,0 q -0.41016,0.66406 -0.9375,1.26953 -0.52734,0.58594 -1.23047,1.01563 -0.68359,0.42969 -1.5625,0.68359 -0.85937,0.25391 -1.95312,0.25391 z m 2.16796,-4.7461 q 1.05469,0 1.79688,-0.35156 0.74219,-0.37109 1.19141,-1.09375 0.46875,-0.74219 0.68359,-1.83594 0.23437,-1.09375 0.25391,-2.55859 l 0,-0.64453 q 0,-1.58203 -0.19532,-2.8125 -0.19531,-1.23047 -0.64453,-2.05078 -0.44922,-0.83985 -1.21094,-1.26953 -0.76171,-0.42969 -1.91406,-0.42969 -1.875,0 -2.7539,1.69922 -0.87891,1.67969 -0.87891,4.90234 0,3.22266 0.87891,4.84375 0.89843,1.60156 2.79296,1.60156 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path5630"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 438.76489,383.52618 q 0,-0.83984 0.25391,-1.38671 0.25391,-0.56641 0.68359,-0.89844 0.44922,-0.35156 1.03516,-0.48828 0.60547,-0.13672 1.26953,-0.13672 0.66406,0 1.25,0.13672 0.58594,0.13672 1.01563,0.48828 0.44921,0.33203 0.70312,0.89844 0.27344,0.54687 0.27344,1.38671 0,0.82032 -0.27344,1.38672 -0.25391,0.56641 -0.70312,0.91797 -0.42969,0.33203 -1.01563,0.48828 -0.58594,0.13672 -1.25,0.13672 -0.66406,0 -1.26953,-0.13672 -0.58594,-0.15625 -1.03516,-0.48828 -0.42968,-0.35156 -0.68359,-0.91797 -0.25391,-0.5664 -0.25391,-1.38672 z m 6.21094,27.48047 -5.95703,0 0,-21.83593 5.95703,0 0,21.83593 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path5632"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 465.48364,411.00665 -0.80078,-2.79297 -0.3125,0 q -0.48828,0.83985 -1.17187,1.44532 -0.66407,0.58593 -1.46485,0.97656 -0.80078,0.39062 -1.69922,0.56641 -0.89843,0.19531 -1.83593,0.19531 -1.60157,0 -2.91016,-0.44922 -1.30859,-0.46875 -2.24609,-1.44531 -0.9375,-0.97657 -1.44532,-2.48047 -0.50781,-1.50391 -0.50781,-3.61328 l 0,-14.23828 5.95703,0 0,12.7539 q 0,2.36328 0.70313,3.55469 0.72265,1.17187 2.28515,1.17187 1.17188,0 1.95313,-0.46875 0.78125,-0.46875 1.23047,-1.38671 0.46875,-0.91797 0.66406,-2.26563 0.19531,-1.34766 0.19531,-3.08594 l 0,-10.27343 5.95703,0 0,21.83593 -4.55078,0 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path5634"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 495.03442,411.00665 -5.95703,0 0,-12.7539 q 0,-2.36328 -0.70312,-3.53516 -0.70313,-1.19141 -2.20703,-1.19141 -1.13282,0 -1.89453,0.46875 -0.74219,0.46875 -1.19141,1.38672 -0.44922,0.91797 -0.64453,2.26563 -0.19531,1.34765 -0.19531,3.08594 l 0,10.27343 -5.95704,0 0,-21.83593 4.55079,0 0.80078,2.79296 0.33203,0 q 0.46875,-0.83984 1.11328,-1.44531 0.66406,-0.60547 1.44531,-0.99609 0.78125,-0.39063 1.66016,-0.56641 0.8789,-0.19531 1.77734,-0.19531 2.2461,0 3.8086,0.78125 1.58203,0.76172 2.42187,2.42187 l 0.48828,0 q 0.46875,-0.83984 1.13281,-1.44531 0.66407,-0.60547 1.46485,-0.99609 0.80078,-0.39063 1.67969,-0.56641 0.89843,-0.19531 1.79687,-0.19531 3.51563,0 5.29297,1.91406 1.79687,1.89453 1.79687,6.09375 l 0,14.23828 -5.97656,0 0,-12.7539 q 0,-2.36328 -0.70312,-3.53516 -0.70313,-1.19141 -2.20703,-1.19141 -2.12891,0 -3.02735,1.69922 -0.89844,1.67969 -0.89844,4.82422 l 0,10.95703 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path5636"
+         inkscape:connector-curvature="0" />
+    </g>
+    <g
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;line-height:125%;font-family:'Droid Sans';-inkscape-font-specification:'Droid Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="0hard2"
+       inkscape:label="#text5603"
+       transform="matrix(0.7,0,0,0.7,55.939641,18.659146)">
+      <path
+         d="m 375.58685,458.14954 -5.95703,0 0,-12.75391 q 0,-2.36328 -0.74219,-3.53516 -0.72265,-1.1914 -2.24609,-1.1914 -1.15234,0 -1.93359,0.46875 -0.78125,0.46875 -1.25,1.38672 -0.46875,0.91796 -0.66407,2.26562 -0.19531,1.34766 -0.19531,3.08594 l 0,10.27344 -5.95703,0 0,-30.39063 5.95703,0 0,6.19141 q 0,0.82031 -0.0391,1.73828 -0.0391,0.89844 -0.0977,1.66015 -0.0781,0.89844 -0.13672,1.75782 l 0.3125,0 q 0.95704,-1.69922 2.44141,-2.44141 1.48438,-0.76172 3.35938,-0.76172 1.62109,0 2.92968,0.46875 1.32813,0.44922 2.26563,1.42578 0.9375,0.97657 1.44531,2.5 0.50781,1.50391 0.50781,3.61328 l 0,14.23829 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path5652"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 394.39545,458.14954 -1.15235,-2.96875 -0.17578,0 q -0.64453,0.8789 -1.28906,1.52343 -0.64453,0.625 -1.40625,1.03516 -0.76172,0.41016 -1.71875,0.60547 -0.9375,0.19531 -2.1875,0.19531 -1.32813,0 -2.46094,-0.41016 -1.13281,-0.42968 -1.97265,-1.26953 -0.82032,-0.85937 -1.28907,-2.14843 -0.46875,-1.3086 -0.46875,-3.08594 0,-3.47656 2.22657,-5.11719 2.22656,-1.66016 6.66015,-1.83594 l 3.47656,-0.11718 0,-1.64063 q 0,-1.34766 -0.78125,-1.99219 -0.78125,-0.64453 -2.1875,-0.64453 -1.40625,0 -2.7539,0.41016 -1.32813,0.41015 -2.67578,1.09375 l -1.9336,-3.94531 q 1.64063,-0.91797 3.63282,-1.44532 1.99218,-0.52734 4.17968,-0.52734 4.08203,0 6.25,1.91406 2.1875,1.91406 2.1875,5.82031 l 0,14.55079 -4.16015,0 z m -1.75782,-10.11719 -1.97265,0.0781 q -1.19141,0.0391 -2.01172,0.3125 -0.82031,0.27344 -1.32813,0.74219 -0.48828,0.44922 -0.72265,1.09375 -0.21485,0.625 -0.21485,1.40625 0,1.36719 0.66407,1.95313 0.66406,0.5664 1.73828,0.5664 0.82031,0 1.52344,-0.27344 0.70312,-0.29296 1.21093,-0.83984 0.52735,-0.56641 0.82032,-1.36719 0.29296,-0.82031 0.29296,-1.875 l 0,-1.79687 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path5654"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 416.07513,435.90344 q 0.23438,0 0.50782,0.0195 0.29297,0 0.54687,0.0391 0.27344,0.0195 0.48828,0.0586 0.23438,0.0195 0.35157,0.0586 l 0,5.58594 q -0.15625,-0.0391 -0.42969,-0.0781 -0.27344,-0.0391 -0.58594,-0.0586 -0.29297,-0.0391 -0.58594,-0.0391 -0.29297,-0.0195 -0.48828,-0.0195 -1.15234,0 -2.1289,0.29297 -0.95704,0.29297 -1.66016,0.95703 -0.68359,0.64453 -1.07422,1.71875 -0.37109,1.05469 -0.37109,2.59765 l 0,11.11329 -5.95703,0 0,-21.83594 4.51171,0 0.87891,3.28125 0.29297,0 q 0.46875,-0.83985 1.01562,-1.52344 0.54688,-0.68359 1.21094,-1.15234 0.6836,-0.48828 1.52344,-0.74219 0.85937,-0.27344 1.95312,-0.27344 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path5656"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 428.45795,458.54016 q -1.67969,0 -3.06641,-0.72266 -1.38672,-0.72265 -2.38281,-2.1289 -0.9961,-1.42578 -1.5625,-3.53516 -0.54688,-2.10937 -0.54688,-4.88281 0,-2.8125 0.54688,-4.92188 0.5664,-2.1289 1.58203,-3.55468 1.03516,-1.44532 2.46094,-2.16797 1.42578,-0.72266 3.14453,-0.72266 1.05469,0 1.93359,0.25391 0.87891,0.23437 1.58203,0.68359 0.70313,0.42969 1.25,1.01563 0.56641,0.5664 0.9961,1.25 l 0.19531,0 q -0.11719,-0.76172 -0.21484,-1.54297 -0.0977,-0.66406 -0.17579,-1.40625 -0.0586,-0.76172 -0.0586,-1.40625 l 0,-6.99219 5.95703,0 0,30.39063 -4.55078,0 -1.15234,-2.83204 -0.25391,0 q -0.41016,0.66407 -0.9375,1.26954 -0.52734,0.58593 -1.23047,1.01562 -0.68359,0.42969 -1.5625,0.68359 -0.85937,0.25391 -1.95312,0.25391 z m 2.16797,-4.74609 q 1.05468,0 1.79687,-0.35157 0.74219,-0.37109 1.19141,-1.09375 0.46875,-0.74218 0.68359,-1.83593 0.23438,-1.09375 0.25391,-2.5586 l 0,-0.64453 q 0,-1.58203 -0.19532,-2.8125 -0.19531,-1.23047 -0.64453,-2.05078 -0.44922,-0.83984 -1.21093,-1.26953 -0.76172,-0.42969 -1.91407,-0.42969 -1.875,0 -2.7539,1.69922 -0.87891,1.67969 -0.87891,4.90234 0,3.22266 0.87891,4.84375 0.89843,1.60157 2.79297,1.60157 z"
+         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path5658"
+         inkscape:connector-curvature="0" />
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:151.59999084px;line-height:125%;font-family:'Droid Sans';-inkscape-font-specification:'Droid Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ff0000;fill-opacity:1;stroke:#550000;stroke-width:2.50000022;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;"
+       x="105.09922"
+       y="363.60458"
+       id="0error"
+       sodipodi:linespacing="125%"
+       transform="scale(1.0032264,0.99678398)"
+       inkscape:label="#text3394"><tspan
+         sodipodi:role="line"
+         id="tspan3396"
+         x="105.09922"
+         y="363.60458">✘</tspan></text>
+    <path
+       inkscape:connector-curvature="0"
+       id="0n0"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.75000016;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 404.02266,260.24844 q 0,-3.75976 -0.71167,-5.29052 -0.69825,-1.54419 -2.36328,-1.54419 -1.66504,0 -2.37671,1.54419 -0.71167,1.53076 -0.71167,5.29052 0,3.80005 0.71167,5.35767 0.71167,1.55762 2.37671,1.55762 1.65161,0 2.36328,-1.55762 0.71167,-1.55762 0.71167,-5.35767 z m 5.16967,0.0403 q 0,4.98169 -2.14843,7.69409 -2.14844,2.69897 -6.09619,2.69897 -3.96119,0 -6.10962,-2.69897 -2.14844,-2.7124 -2.14844,-7.69409 0,-4.99512 2.14844,-7.69409 2.14843,-2.71241 6.10962,-2.71241 3.94775,0 6.09619,2.71241 2.14843,2.69897 2.14843,7.69409 z"
+       inkscape:label="#path4209" />
+    <path
+       inkscape:connector-curvature="0"
+       id="0n1"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.75000016;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 415.63426,266.72061 4.56543,0 0,-12.95776 -4.68628,0.96679 0,-3.51806 4.65942,-0.9668 4.91456,0 0,16.47583 4.56543,0 0,3.57178 -14.01856,0 0,-3.57178 z"
+       inkscape:label="#path4211" />
+    <path
+       inkscape:connector-curvature="0"
+       id="0n2"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.75000016;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 442.68776,266.49234 8.82202,0 0,3.80005 -14.56909,0 0,-3.80005 7.31812,-6.45874 q 0.98022,-0.88623 1.45019,-1.73218 0.46997,-0.84595 0.46997,-1.75903 0,-1.40991 -0.95337,-2.26929 -0.93994,-0.85937 -2.51098,-0.85937 -1.2085,0 -2.64527,0.52368 -1.43676,0.51025 -3.07495,1.53076 l 0,-4.4043 q 1.74561,-0.57739 3.45093,-0.8728 1.70532,-0.30884 3.34351,-0.30884 3.59863,0 5.58593,1.58448 2.00074,1.58447 2.00074,4.41772 0,1.63818 -0.84595,3.06152 -0.84595,1.40992 -3.55835,3.78662 l -4.28345,3.75977 z"
+       inkscape:label="#path4213" />
+    <path
+       inkscape:connector-curvature="0"
+       id="0n3"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.75000016;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 469.28474,259.48306 q 2.02759,0.52368 3.07495,1.82617 1.06079,1.28907 1.06079,3.2898 0,2.98096 -2.28271,4.53857 -2.28272,1.54419 -6.66016,1.54419 -1.54419,0 -3.10181,-0.25512 -1.54418,-0.2417 -3.06152,-0.73853 l 0,-3.98804 q 1.4502,0.7251 2.87354,1.10108 1.43676,0.36255 2.81982,0.36255 2.05444,0 3.14209,-0.71167 1.10107,-0.71167 1.10107,-2.04102 0,-1.36963 -1.12792,-2.06787 -1.11451,-0.71167 -3.30323,-0.71167 l -2.06787,0 0,-3.33008 2.17529,0 q 1.94703,0 2.90039,-0.60425 0.95337,-0.61767 0.95337,-1.86645 0,-1.15479 -0.92651,-1.78589 -0.92651,-0.6311 -2.61841,-0.6311 -1.24878,0 -2.52441,0.28198 -1.27564,0.28198 -2.53784,0.83252 l 0,-3.78662 q 1.53076,-0.42969 3.03466,-0.64453 1.50391,-0.21485 2.95411,-0.21485 3.90747,0 5.84106,1.28907 1.94702,1.27563 1.94702,3.85375 0,1.75904 -0.92651,2.88697 -0.92652,1.1145 -2.73926,1.57104 z"
+       inkscape:label="#path4215" />
+    <path
+       inkscape:connector-curvature="0"
+       id="0n4"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.75000016;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 488.08015,254.50137 -5.66651,8.39234 5.66651,0 0,-8.39234 z m -0.85938,-4.25659 5.74707,0 0,12.64893 2.86011,0 0,3.74634 -2.86011,0 0,3.65234 -4.88769,0 0,-3.65234 -8.88916,0 0,-4.43116 8.02978,-11.96411 z"
+       inkscape:label="#path4217" />
+    <path
+       inkscape:connector-curvature="0"
+       id="0n5"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.75000016;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 502.39748,250.24478 12.85034,0 0,3.80005 -8.72803,0 0,3.10181 q 0.59082,-0.16114 1.18164,-0.2417 0.60425,-0.094 1.24878,-0.094 3.66577,0 5.70679,1.8396 2.04101,1.82618 2.04101,5.10254 0,3.24951 -2.229,5.08911 -2.21558,1.8396 -6.16333,1.8396 -1.70532,0 -3.38379,-0.33569 -1.66504,-0.32227 -3.31665,-0.99365 l 0,-4.06861 q 1.63818,0.93995 3.10181,1.40992 1.47705,0.46997 2.77954,0.46997 1.87988,0 2.9541,-0.91309 1.08765,-0.92651 1.08765,-2.49756 0,-1.58447 -1.08765,-2.49756 -1.07422,-0.91308 -2.9541,-0.91308 -1.1145,0 -2.37671,0.29541 -1.26221,0.28198 -2.7124,0.88623 l 0,-11.2793 z"
+       inkscape:label="#path4219" />
+    <path
+       inkscape:connector-curvature="0"
+       id="0n6"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.75000016;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 531.06232,260.39615 q -1.3562,0 -2.04101,0.88623 -0.67139,0.8728 -0.67139,2.63184 0,1.75903 0.67139,2.64526 0.68481,0.8728 2.04101,0.8728 1.36963,0 2.04102,-0.8728 0.68481,-0.88623 0.68481,-2.64526 0,-1.75904 -0.68481,-2.63184 -0.67139,-0.88623 -2.04102,-0.88623 z m 6.39161,-9.62769 0,3.70606 q -1.27564,-0.60425 -2.40357,-0.88623 -1.12793,-0.29541 -2.20215,-0.29541 -2.30957,0 -3.59863,1.28906 -1.28906,1.27563 -1.50391,3.80005 0.88623,-0.65796 1.92017,-0.98023 1.03394,-0.33569 2.25586,-0.33569 3.07495,0 4.95483,1.79932 1.89331,1.79931 1.89331,4.71313 0,3.22266 -2.10815,5.16968 -2.10815,1.93359 -5.65308,1.93359 -3.90747,0 -6.0559,-2.63183 -2.13501,-2.64527 -2.13501,-7.49268 0,-4.96826 2.49755,-7.80151 2.51099,-2.84668 6.875,-2.84668 1.38306,0 2.68555,0.21484 1.30249,0.21485 2.57813,0.64453 z"
+       inkscape:label="#path4221" />
+    <path
+       inkscape:connector-curvature="0"
+       id="0n7"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.75000016;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 544.88277,250.24478 15.1062,0 0,2.91382 -7.81494,17.13379 -5.0354,0 7.39868,-16.24756 -9.65454,0 0,-3.80005 z"
+       inkscape:label="#path4223" />
+    <path
+       inkscape:connector-curvature="0"
+       id="0n8"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.75000016;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 574.0981,261.32266 q -1.4502,0 -2.22901,0.79224 -0.77881,0.79224 -0.77881,2.26929 0,1.47705 0.77881,2.26928 0.77881,0.77881 2.22901,0.77881 1.43676,0 2.20214,-0.77881 0.76538,-0.79223 0.76538,-2.26928 0,-1.49048 -0.76538,-2.26929 -0.76538,-0.79224 -2.20214,-0.79224 z m -3.7732,-1.70532 q -1.82617,-0.55054 -2.75268,-1.69189 -0.92652,-1.14136 -0.92652,-2.84668 0,-2.53785 1.89331,-3.86719 1.89331,-1.32935 5.55909,-1.32935 3.63891,0 5.53222,1.32935 1.89331,1.31592 1.89331,3.86719 0,1.70532 -0.93994,2.84668 -0.92651,1.14135 -2.75268,1.69189 2.04101,0.56396 3.07495,1.8396 1.04736,1.26221 1.04736,3.1958 0,2.98096 -1.9873,4.51172 -1.97388,1.51733 -5.86792,1.51733 -3.90748,0 -5.90821,-1.51733 -1.9873,-1.53076 -1.9873,-4.51172 0,-1.93359 1.03393,-3.1958 1.04737,-1.27564 3.08838,-1.8396 z m 1.2085,-4.01489 q 0,1.19507 0.65796,1.8396 0.67138,0.64453 1.90674,0.64453 1.20849,0 1.86645,-0.64453 0.65796,-0.64453 0.65796,-1.8396 0,-1.19507 -0.65796,-1.82617 -0.65796,-0.64454 -1.86645,-0.64454 -1.23536,0 -1.90674,0.64454 -0.65796,0.64453 -0.65796,1.82617 z"
+       inkscape:label="#path4225" />
+    <path
+       inkscape:connector-curvature="0"
+       id="0n9"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.75000016;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 589.0734,269.84927 0,-3.70605 q 1.23535,0.57739 2.36328,0.8728 1.12793,0.28198 2.229,0.28198 2.30958,0 3.59864,-1.27563 1.28906,-1.28906 1.51733,-3.81348 -0.91308,0.67139 -1.94702,1.00708 -1.03394,0.3357 -2.24243,0.3357 -3.07495,0 -4.96826,-1.78589 -1.87989,-1.79932 -1.87989,-4.72656 0,-3.23609 2.09473,-5.18311 2.10815,-1.94702 5.63965,-1.94702 3.9209,0 6.06934,2.64526 2.14843,2.64527 2.14843,7.47925 0,4.96826 -2.51098,7.81494 -2.51099,2.83325 -6.88843,2.83325 -1.40991,0 -2.69898,-0.21484 -1.28906,-0.20142 -2.52441,-0.61768 z m 6.37817,-9.65454 q 1.3562,0 2.04102,-0.8728 0.68481,-0.88623 0.68481,-2.64526 0,-1.74561 -0.68481,-2.63184 -0.68482,-0.88623 -2.04102,-0.88623 -1.3562,0 -2.04101,0.88623 -0.68482,0.88623 -0.68482,2.63184 0,1.75903 0.68482,2.64526 0.68481,0.8728 2.04101,0.8728 z"
+       inkscape:label="#path4227" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:31.96330261px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.75000012;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="274.35486"
+       y="-433.2915"
+       id="0reload"
+       sodipodi:linespacing="125%"
+       inkscape:label="#text4239"
+       transform="matrix(-0.00170809,1.0146722,-0.98553716,-0.00165905,0,0)"><tspan
+         sodipodi:role="line"
+         id="tspan4241"
+         x="274.35486"
+         y="-433.2915"
+         style="stroke-width:1.75000012;stroke-miterlimit:4;stroke-dasharray:none">↻</tspan></text>
+  </g>
+</svg>
diff --git a/contrib/memory/art/icon.svg b/contrib/memory/art/icon.svg
new file mode 100644 (file)
index 0000000..8a5990d
--- /dev/null
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="43.642509mm"
+   height="44.651615mm"
+   viewBox="0 0 154.63881 158.21438"
+   id="svg6343"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="icon.svg">
+  <defs
+     id="defs6345" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.1542002"
+     inkscape:cx="-80.961712"
+     inkscape:cy="22.846199"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1136"
+     inkscape:window-x="1600"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0" />
+  <metadata
+     id="metadata6348">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-113.70362,-86.112208)">
+    <g
+       transform="translate(9.99238,-85.305267)"
+       style="fill:#ff41ff;fill-opacity:1;stroke:#803980;stroke-width:5.00000048;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       inkscape:label="#g3356"
+       id="0cross">
+      <path
+         inkscape:connector-curvature="0"
+         style="fill:#ff41ff;fill-opacity:1;stroke:#803980;stroke-width:5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         d="m 42.5625,125.5 0,31.25 -31.25,0 0,25 31.25,0 0,31.25 25,0 0,-31.25 31.25,0 0,-25 -31.25,0 0,-31.25 -25,0 z"
+         transform="translate(114.94512,48.417475)"
+         id="rect3352" />
+    </g>
+    <path
+       transform="matrix(1.138458,0.01858784,-0.01944847,1.1911688,-359.02128,61.200173)"
+       inkscape:label="#path3348"
+       inkscape:transform-center-y="-4.0794014"
+       inkscape:transform-center-x="0.47783259"
+       d="m 536.391,131.10309 -47.49475,0.72114 -15.36253,-44.947336 38.00017,-28.500132 38.84794,27.33329 z"
+       inkscape:randomized="0"
+       inkscape:rounded="0"
+       inkscape:flatsided="true"
+       sodipodi:arg2="1.5556138"
+       sodipodi:arg1="0.92729522"
+       sodipodi:r2="32.545895"
+       sodipodi:r1="40.406101"
+       sodipodi:cy="98.778206"
+       sodipodi:cx="512.14734"
+       sodipodi:sides="5"
+       id="0penta"
+       style="fill:#00ffff;fill-opacity:1;stroke:#3a8080;stroke-width:4.2930603;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       sodipodi:type="star" />
+    <path
+       inkscape:label="#path3356"
+       inkscape:connector-curvature="0"
+       id="0spiral"
+       d="m 157.88015,154.33473 c -20.15895,-0.32141 -38.9065,16.76425 -41.19858,37.60291 -3.86937,23.35281 16.7358,47.48676 39.64103,45.31644 12.20102,-0.76865 23.76919,-8.45705 29.03604,-20.00332 6.61043,-13.59525 3.19101,-31.78746 -8.72849,-41.00231 -11.91023,-9.84408 -31.5447,-7.79332 -40.34686,5.46911 -8.25602,11.53909 -5.3078,30.58816 7.47626,37.21364 10.28179,6.05468 25.63854,1.15001 29.0991,-11.11553 3.04684,-9.25632 -2.65279,-21.09349 -12.45674,-22.21563 -7.74971,-1.31975 -16.07358,6.63167 -13.65087,14.90034 1.37551,7.39459 14.12722,8.17257 14.08847,-0.22482 -0.0955,-2.72794 -2.63922,-5.69968 -5.32908,-4.79848 4.38499,-3.96292 10.36557,1.52768 9.81632,6.69218 0.19607,6.907 -6.58875,11.92951 -12.86343,10.71083 -8.21344,-0.99562 -14.24185,-9.85518 -12.49382,-18.25737 1.54211,-10.78621 12.75113,-18.38943 22.89359,-15.65962 11.86257,2.42582 20.00065,15.79672 17.20605,27.99309 -2.41584,13.54418 -15.7679,23.59081 -28.91368,21.59767 -14.20193,-1.45306 -26.32571,-14.644 -26.46485,-29.59643 -0.8484,-17.59211 12.58621,-34.40757 29.59974,-35.87494 17.64776,-2.34404 36.43269,10.56977 40.14043,28.9258 3.86993,15.99133 -2.31691,34.4508 -15.45688,44.18203 -0.10231,3.94543 4.80831,7.62163 7.87431,4.41178 19.69304,-16.79994 22.96064,-50.96148 5.42672,-70.6373 -8.57029,-10.04432 -21.48622,-15.8896 -34.39478,-15.63007 z"
+       style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#808036;stroke-width:5.00000048;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:accumulate" />
+  </g>
+</svg>
diff --git a/contrib/memory/assets/bing.wav b/contrib/memory/assets/bing.wav
new file mode 100644 (file)
index 0000000..c7cae5b
Binary files /dev/null and b/contrib/memory/assets/bing.wav differ
diff --git a/contrib/memory/assets/boing.wav b/contrib/memory/assets/boing.wav
new file mode 100644 (file)
index 0000000..70c529f
Binary files /dev/null and b/contrib/memory/assets/boing.wav differ
diff --git a/contrib/memory/assets/click.wav b/contrib/memory/assets/click.wav
new file mode 100644 (file)
index 0000000..3d07b83
Binary files /dev/null and b/contrib/memory/assets/click.wav differ
diff --git a/contrib/memory/assets/cymbal.wav b/contrib/memory/assets/cymbal.wav
new file mode 100644 (file)
index 0000000..b55bac4
Binary files /dev/null and b/contrib/memory/assets/cymbal.wav differ
diff --git a/contrib/memory/assets/dart.wav b/contrib/memory/assets/dart.wav
new file mode 100644 (file)
index 0000000..422e2c2
Binary files /dev/null and b/contrib/memory/assets/dart.wav differ
diff --git a/contrib/memory/assets/duh.wav b/contrib/memory/assets/duh.wav
new file mode 100644 (file)
index 0000000..054e1fe
Binary files /dev/null and b/contrib/memory/assets/duh.wav differ
diff --git a/contrib/memory/assets/grunt.wav b/contrib/memory/assets/grunt.wav
new file mode 100644 (file)
index 0000000..f0d8350
Binary files /dev/null and b/contrib/memory/assets/grunt.wav differ
diff --git a/contrib/memory/assets/honkhonk.wav b/contrib/memory/assets/honkhonk.wav
new file mode 100644 (file)
index 0000000..b107329
Binary files /dev/null and b/contrib/memory/assets/honkhonk.wav differ
diff --git a/contrib/memory/assets/level.wav b/contrib/memory/assets/level.wav
new file mode 100644 (file)
index 0000000..2d30b6e
Binary files /dev/null and b/contrib/memory/assets/level.wav differ
diff --git a/contrib/memory/assets/line_end.wav b/contrib/memory/assets/line_end.wav
new file mode 100644 (file)
index 0000000..aead13e
Binary files /dev/null and b/contrib/memory/assets/line_end.wav differ
diff --git a/contrib/memory/assets/penalty.wav b/contrib/memory/assets/penalty.wav
new file mode 100644 (file)
index 0000000..2ad3af0
Binary files /dev/null and b/contrib/memory/assets/penalty.wav differ
diff --git a/contrib/memory/assets/squishy-hit.wav b/contrib/memory/assets/squishy-hit.wav
new file mode 100644 (file)
index 0000000..dbd958b
Binary files /dev/null and b/contrib/memory/assets/squishy-hit.wav differ
diff --git a/contrib/memory/assets/whip.wav b/contrib/memory/assets/whip.wav
new file mode 100644 (file)
index 0000000..b907832
Binary files /dev/null and b/contrib/memory/assets/whip.wav differ
diff --git a/contrib/memory/assets/woodthunk.wav b/contrib/memory/assets/woodthunk.wav
new file mode 100644 (file)
index 0000000..2001e38
Binary files /dev/null and b/contrib/memory/assets/woodthunk.wav differ
diff --git a/contrib/memory/org.nitlanguage.memory.txt b/contrib/memory/org.nitlanguage.memory.txt
new file mode 100644 (file)
index 0000000..1bef17b
--- /dev/null
@@ -0,0 +1,16 @@
+Categories:Nit,Games
+License:Apache2
+Web Site:http://nitlanguage.org
+Source Code:http://nitlanguage.org/nit.git/tree/HEAD:/contrib/memory
+Issue Tracker:https://github.com/nitlang/nit/issues
+
+Summary: memory-based game using shapes and colors
+Description:
+A memory-based game where figures are cliqued in sequence by the computer and should be replayed by the player in the same order.
+As the player progresses, more figures are added and the sequences to remember become longer.
+
+The player can make up to 2 errors to solve a single level.
+At the 3rd error, the level has to be replayed.
+
+The game use a very simple user interface and features big figures with bright colors and simple distinguishable shapes; that makes it suitable for young children.
+.
diff --git a/contrib/memory/package.ini b/contrib/memory/package.ini
new file mode 100644 (file)
index 0000000..d271a73
--- /dev/null
@@ -0,0 +1,11 @@
+[package]
+name=memory
+tags=game
+maintainer=Jean Privat <jean@pryen.org>
+license=Apache-2.0
+[upstream]
+browse=https://github.com/nitlang/nit/tree/master/contrib/memory/
+git=https://github.com/nitlang/nit.git
+git.directory=contrib/memory/
+homepage=http://nitlanguage.org
+issues=https://github.com/nitlang/nit/issues
diff --git a/contrib/memory/src/memory.nit b/contrib/memory/src/memory.nit
new file mode 100644 (file)
index 0000000..3e9877d
--- /dev/null
@@ -0,0 +1,1000 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# A game of memory using shapes and colors
+#
+# # Features and TODO
+#
+# * [X] Various shapes, colors and sounds
+# * [X] 3 difficulty modes
+# * [X] Saved high scores
+# * [ ] Level selection
+#
+# The remaining issues are
+#
+# * Crappy event system
+# * Crappy UI element placement
+module memory is
+       app_name("Memorize Shapes and Colors")
+       app_version(0, 1, git_revision)
+end
+
+import mnit
+import app::audio
+import mnit::opengles1
+import app::data_store
+
+import drawing
+
+# A figure to click on
+class Button
+       # The place, starting from 0.
+       # Will be used to derive the display place.
+       var place: Int
+
+       # The color of the figure
+       var color: Color
+
+       # The shape of the figure
+       var shape: Image
+
+       # The sound of the figure
+       var sound: Sound
+
+       # x-coordinate on the display
+       var x: Float = 0.0
+       # y-coordinate on the display
+       var y: Float = 0.0
+       # width on the display
+       var w: Float = 0.0
+       # height the display
+       var h: Float = 0.0
+
+       # Event time to live (from 1.0 downto 0.0)
+       var ttl: Float = 0.0
+
+       # Is there a big error on the button?
+       var error = false
+
+       # The initial position (according to shuffle)
+       var from: Pos is noinit
+
+       # The current path if shuffling
+       var path: nullable BPath = null
+
+       # The second path if hard shuffling
+       var path2: nullable BPath = null
+
+       # Is there an hard shuffling?
+       var hard = false
+
+       # The optional text on the button (in the menu)
+       var text: nullable Image = null
+
+       # The color of the text
+       var text_color: nullable Color = null
+
+       # The high score on the menu button
+       var text_max: Int = 0
+
+       # Draw on the display
+       fun blit_on(display: Display)
+       do
+               if ttl > 0.0 then
+                       ttl -= 0.1
+                       if ttl <= 0.0 then
+                               ttl = 0.0
+                               path = path2
+                               path2 = null
+                               if path != null then ttl = path.duration
+                               error = false
+                       end
+               end
+
+               var x = self.x
+               var y = self.y
+               var p = 0.0
+               if ttl > 0.0 then
+                       if path != null then
+                               var pos = to_pos
+                               path.update(pos, ttl)
+                               x = pos.x
+                               y = pos.y
+                               if hard then
+                                       p = ttl/5.0
+                                       if path2 != null then
+                                               p = 1.0 - p
+                                       end
+                               end
+                       else if error then
+                               # nothing
+                       else
+                               y -= ttl * h / 10.0
+                       end
+               end
+
+               if not app.player then
+                       p = 0.2.lerp(p, 1.0)
+               end
+
+               color.set(display, p)
+               display.blit_centered(shape, x, y)
+               var text = self.text
+               if text != null then
+                       text.scale = shape.scale
+                       text_color.set(display, p)
+                       display.blit_centered(text, x, y - h/8.0)
+                       if text_max > 0 then
+                               app.blit_number(text_max, app.scale, x, y + h/8.0)
+                       end
+               end
+               if display isa Opengles1Display then
+                       display.reset_color
+               end
+               if error then
+                       app.drawing.error.scale = app.scale
+                       display.blit_centered(app.drawing.error, x, y)
+               end
+       end
+
+       redef fun to_s do
+               return "{place},{color},{shape},{sound}"
+       end
+
+       # Check collision
+       fun has(x,y: Float): Bool
+       do
+               return (self.x - x).abs*2.0 <= w and (self.y - y).abs*2.0 <= h
+       end
+
+       # Return a new pos centered on the button
+       fun to_pos: Pos do return new Pos(x, y)
+end
+
+# A rbg color
+class Color
+       # red (from 0.0 to 1.0)
+       var r: Float
+       # green (from 0.0 to 1.0)
+       var g: Float
+       # blue (from 0.0 to 1.0)
+       var b: Float
+
+       # Globally change the color of the display.
+       # The color will be used for the next blit operations.
+       # The color of the display has to be reseted manually (see `Opengles1Display::reset_color`).
+       fun set(display: Display, p: Float)
+       do
+               if display isa Opengles1Display then
+                       display.color(p.lerp(r,1.0),p.lerp(g,1.0),p.lerp(b,1.0),p.lerp(1.0,0.0))
+               end
+       end
+end
+
+# A point in the display coordinates
+class Pos
+       # x coordinate
+       var x: Float
+       # y coordinate
+       var y: Float
+       redef fun to_s do return "({x},{y})"
+end
+
+# A cubic Bézier path between two points with two handles.
+class BPath
+       # The origin point
+       var from: Pos
+       # The handle of the origin point
+       var from_handle: Pos
+       # The handle of the destination point
+       var to_handle: Pos
+       # The destination point
+       var to: Pos
+       # The duration on the path
+       var duration: Float
+
+       # Update the coordinates of `cursor` for an absolute time to destination `ttd`
+       fun update(cursor: Pos, ttd: Float)
+       do
+               var p = 1.0 - ttd / duration
+               if p <= 0.0 then
+                       cursor.x = from.x
+                       cursor.y = from.y
+                       return
+               end
+               if p >= 1.1 then
+                       cursor.x = to.x
+                       cursor.y = to.y
+               end
+               var bx = p.cerp(from.x, from_handle.x, to_handle.x, to.x)
+               var by = p.cerp(from.y, from_handle.y, to_handle.y, to.y)
+               cursor.x = bx
+               cursor.y = by
+       end
+end
+
+redef class App
+
+       # # Assets and resources
+
+       # All the images assets
+       var drawing = new DrawingImages
+
+       # Array of all available colors for the figures
+       var colors = new Array[Color]
+
+       # Array of all available shapes for the figures
+       var shapes = new Array[Image]
+
+       # Array of all available sounds for the figures
+       var sounds = new Array[Sound]
+
+       # The sound to play on error (error)
+       var snd_penalty: Sound is noautoinit
+
+       # The sound of other ui element
+       var snd_click: Sound is noautoinit
+
+       redef fun on_create
+       do
+               colors.clear
+               colors.add new Color(0.9, 0.6, 0.0)
+               colors.add new Color(0.6, 0.0, 0.9)
+               colors.add new Color(0.6, 0.5, 0.4)
+               colors.add new Color(1.0, 0.0, 0.0)
+               colors.add new Color(1.0, 1.0, 0.0)
+               colors.add new Color(1.0, 0.0, 1.0)
+               colors.add new Color(0.0, 1.0, 0.0)
+               colors.add new Color(0.0, 1.0, 1.0)
+               colors.add new Color(0.0, 0.0, 1.0)
+
+               drawing.load_all(self)
+               shapes.clear
+               shapes.add drawing.circle
+               shapes.add drawing.rect
+               shapes.add drawing.cross
+               shapes.add drawing.penta
+               shapes.add drawing.star
+               shapes.add drawing.triangle
+               shapes.add drawing.heart
+               shapes.add drawing.diamond
+               shapes.add drawing.moon
+               shapes.add drawing.spiral
+
+               number_images = new NumberImages(drawing.n)
+
+               sounds.clear
+               sounds.add new Sound("bing.wav")
+               sounds.add new Sound("boing.wav")
+               sounds.add new Sound("cymbal.wav")
+               sounds.add new Sound("dart.wav")
+               sounds.add new Sound("duh.wav")
+               sounds.add new Sound("grunt.wav")
+               sounds.add new Sound("honkhonk.wav")
+               sounds.add new Sound("line_end.wav")
+               sounds.add new Sound("squishy-hit.wav")
+               sounds.add new Sound("woodthunk.wav")
+               sounds.add new Sound("whip.wav")
+
+               snd_penalty = new Sound("penalty.wav")
+               snd_click = new Sound("click.wav")
+
+               # Force load the sounds. Required because bug #1728
+               for s in sounds do s.load
+               snd_penalty.load
+
+               is_menu = data_store["game"] != true
+               mode = data_int("mode") or else 0
+               current_level = data_int("level") or else 0
+
+               max_levels[0] = data_int("max_0") or else 0
+               max_levels[1] = data_int("max_1") or else 0
+               max_levels[2] = data_int("max_2") or else 0
+
+               print "max_levels: {max_levels}"
+
+               reload = new Button(-1, new Color(1.0,1.0,1.0), drawing.reload, snd_click)
+
+               if is_menu then
+                       new_menu
+               else
+                       new_game
+               end
+       end
+
+       # Get a positive numeric value from the store
+       fun data_int(name: String): nullable Int
+       do
+               var x = data_store[name]
+               if x isa Int then return x else return null
+       end
+
+       # # Level information
+
+       # Number of buttons for the next game
+       var size = 5
+
+       # Length of the memory sequence for the next game
+       var length = 5
+
+       # Do a hard deal?
+       var hard_deal = false
+
+       # No shuffle (0), easy shuffle (1), or hard shuffle (2)?
+       var shuffling = 0
+
+       # Is a new deal make on replay?
+       # If true, a new set of figures and a new sequence is produced
+       # If false, the same is reused.
+       var deal_on_replay = true
+
+       # Current buttons in the game
+       var buttons = new Array[Button]
+
+       # The sequence of the buttons to memorize
+       var level = new Array[Button]
+
+       # The number of errors (crosses) in the current level. (in [0..3])
+       var error = 0
+
+       # Is the player playing?
+       # If false it means that the game is showing the sequence to memorize
+       var player = false
+
+       # Next button on the level (to show or guess according to `player`)
+       var cpt = 0
+
+       # Time to live before the next event
+       var ttl = 0.0
+
+       # Are we in the menu?
+       var is_menu = true
+
+       # In the end of game, is this a win of a lose?
+       var is_win = false
+
+       # Reset everything and create a menu
+       fun new_menu
+       do
+               is_menu = true
+               size = 3
+               length = 0
+               shuffling = 0
+
+               data_store["game"] = false
+
+               colors.shuffle
+               shapes.shuffle
+               sounds.shuffle
+
+               buttons.clear
+               for i in [0..size[ do
+                       var b = new Button(i, colors[i], shapes[i], sounds[i])
+                       buttons.add b
+                       b.text = drawing.hard[i]
+                       b.text_color = colors[3+i]
+                       b.text_max = max_levels[i]
+               end
+
+               # Start the scene
+               start_scene
+       end
+
+       # The current mode: easy (0), medium (1), hard (2)
+       var mode = 0
+
+       # The current level (from 0)
+       var current_level = 0
+
+       # Hight scores of each mode
+       var max_levels: Array[Int] = [0, 0, 0]
+
+       # Reset everything and create a new game using `mode` and `level`
+       fun new_game
+       do
+               print "Next game: mode={mode} level={current_level}"
+               data_store["game"] = true
+               data_store["mode"] = mode
+               data_store["level"] = current_level
+               if max_levels[mode] < current_level then
+                       max_levels[mode] = current_level
+                       data_store["max_{mode}"] = current_level
+               end
+
+               if mode == 0 then
+                       hard_deal = false
+                       shuffling = 0
+                       deal_on_replay = false
+                       size = 2
+                       length = 1
+               else if mode == 1 then
+                       hard_deal = false
+                       shuffling = 1
+                       deal_on_replay = true
+                       size = 3
+                       length = 3
+               else
+                       hard_deal = true
+                       shuffling = 2
+                       deal_on_replay = true
+                       size = 3
+                       length = 3
+               end
+               for i in [0..current_level[ do
+                       length += 1
+                       if length > size + 2 then
+                               size += 1
+                               length -= 1
+                       end
+                       if size > 16 then size = 16
+               end
+
+               deal_game
+       end
+
+       # Reset the buttons and deal a new game using `size` and `length`
+       fun deal_game
+       do
+               is_menu = false
+
+               # Randomize the deal
+               colors.shuffle
+               shapes.shuffle
+               sounds.shuffle
+
+               # Setup the figure
+               buttons.clear
+               if not hard_deal then
+                       # With the easy deal, each button is easily distinguishable
+                       for i in [0..size[ do
+                               var b = new Button(i, colors[i%colors.length], shapes[i%shapes.length], sounds[i%sounds.length])
+                               buttons.add b
+                       end
+               else
+                       # With the hard deal, use overlapping combinations of colors and shapes
+                       var sqrt = size.to_f.sqrt
+                       var ncol = sqrt.floor.to_i
+                       var nsha = sqrt.ceil.to_i
+                       while ncol*nsha < size do ncol += 1
+
+                       # Randomly swap the numbers of colors/shapes
+                       if 2.rand == 0 then
+                               var t = ncol
+                               ncol = nsha
+                               nsha = t
+                       end
+
+                       # Deal combinations (up to `size`)
+                       for i in [0..ncol[ do
+                               for j in [0..nsha[ do
+                                       if buttons.length >= size then break
+                                       var b = new Button(buttons.length, colors[i], shapes[j], sounds.rand)
+                                       buttons.add b
+                               end
+                       end
+
+                       # A last shuffle to break the colors/shapes grid
+                       buttons.shuffle
+               end
+
+               # Deal the level (i.e. sequence to memorize)
+               # To increase distribution, determinate a maximum number of repetition
+               # of a single button
+               var rep = (length.to_f / size.to_f).ceil.to_i
+               var pool = buttons * rep
+               pool.shuffle
+
+               level.clear
+               for i in [0..length[ do
+                       level.add pool[i]
+               end
+
+               print "newgame size={size} length={length}"
+
+               # Start the scene
+               start_scene
+       end
+
+       # Cause a replay on the same level
+       # On easy mode, the same level is replayed exactly
+       # On other modes, a new deal is made
+       fun replay_game
+       do
+               if deal_on_replay then
+                       deal_game
+               else
+                       start_scene
+               end
+       end
+
+       # Reset the state of the scene and start with `fly_in`
+       fun start_scene
+       do
+               player = false
+               cpt = -1
+               path = null
+               error = 0
+
+               # Ask for a redraw
+               first_frame = true
+       end
+
+       # # Placement and moves
+
+       # Locations used to place buttons on the screen
+       private var locations: Array[Array[Float]] = [
+               [0.0, 1.0],
+               [0.0, 1.0, 0.5],
+               [0.0, 1.0, 0.0, 1.0],
+               [0.0, 1.0, 2.0, 0.5, 1.5],
+               [0.0, 1.0, 2.0, 0.0, 1.0, 2.0],
+               [0.5, 1.5, 0.0, 1.0, 2.0, 0.5, 1.5],
+               [0.0, 1.0, 2.0, 0.0, 2.0, 0.0, 1.0, 2.0],
+               [0.0, 1.0, 2.0, 0.0, 1.0, 2.0, 0.0, 1.0, 2.0],
+               [0.5, 1.5, 2.5, 0.0, 1.0, 2.0, 3.0, 0.5, 1.5, 2.5],
+               [0.0, 1.0, 2.0, 3.0, 0.0, 1.5, 3.0, 0.0, 1.0, 2.0, 3.0],
+               [0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0],
+               [0.5, 1.5, 2.5, 0.0, 1.5, 3.0, 0.0, 1.0, 2.0, 3.0, 0.5, 1.5, 2.5],
+               [0.5, 1.5, 2.5, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0, 0.5, 1.5, 2.5],
+               [0.5, 1.5, 2.5, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0],
+               [0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0]]
+
+
+       # The scale of the figures.
+       # According to the screen dimensions and the number of figures
+       var scale = 0.0
+
+       # The scale of the UI
+       # According to the screen dimensions
+       var ui_scale = 0.0
+
+       # Compute then location on the display for each button
+       #
+       # The method can be called when there is a change in the buttons (or the display).
+       fun locate(display: Display)
+       do
+               # The locations depend of the number of buttons (from 2 to 9)
+               var n = buttons.length
+               var locs = locations[n-2]
+               var columns = if n <= 4 then 2 else if n <= 9 then 3 else 4
+               var rows = if n <= 2 then 1 else if n <= 6 then 2 else if n <= 12 then 3 else 4
+
+               # Compute basic dimensions according to the screen
+               var slotw = display.width / columns
+               var sloth = display.height / rows
+               var subw = slotw - slotw/5
+               var subh = sloth - sloth/5
+
+               # Compute the figure scale
+               var img = drawing.circle
+               var xs = subw.to_f / img.width.to_f
+               var ys = subh.to_f / img.height.to_f
+               scale = xs.min(ys)
+
+               # Compute the UI scale
+               xs = display.width.to_f / img.width.to_f
+               ys = display.height.to_f / img.height.to_f
+               ui_scale = xs.min(ys) / 4.0
+
+               var last = -1.0
+               var row = 0.0
+               var cpt = 0
+               for b in buttons do
+                       b.place = cpt
+                       var col = locs[cpt]
+                       if col <= last then
+                               row += 1.0
+                       end
+                       last = col
+
+                       b.x = (col + 0.5) * slotw.to_f
+                       b.y = (row + 0.5) * sloth.to_f
+                       img = b.shape
+                       img.scale = scale
+                       b.w = (img.width.to_f * scale)
+                       b.h = (img.height.to_f * scale)
+
+                       cpt += 1
+               end
+
+               left.x = -150.0 * scale
+               left.y = (display.height / 2).to_f
+               right.x = display.width.to_f + 150.0 * scale
+               right.y = left.y
+
+               # Other UI elements
+
+               if not is_menu then
+                       var reload = self.reload
+                       drawing.reload.scale = ui_scale
+                       reload.x = display.width.to_f - (drawing.reload.width.to_f / 2.0 * 1.2 ) * ui_scale
+                       reload.y = drawing.reload.height.to_f / 2.0 * 1.2 * ui_scale
+                       reload.w = drawing.reload.width.to_f * ui_scale
+                       reload.h = drawing.reload.height.to_f * ui_scale
+               end
+       end
+
+       # The origin point of the cursor on the left
+       var left = new Pos(0.0, 0.0)
+
+       # The destination point of the cursor on the right
+       var right = new Pos(0.0, 0.0)
+
+       # The current cursor position
+       var cursor = new Pos(0.0, 0.0)
+
+       # The current cursor path
+       var path: nullable BPath = null
+
+       # The reload button
+       var reload: Button is noautoinit
+
+       # Safe point for a cursor on the i-th button of the level
+       fun path_pos(i: Int): Pos
+       do
+               if i < 0 then return left
+               if i >= level.length then return right
+               return level[i].to_pos
+       end
+
+       # A random point outside of the screen
+       fun far_away(display: Display): Pos
+       do
+               var a = (2.0*pi).rand
+               var w = display.width.to_f / 2.0
+               var h = display.height.to_f / 2.0
+               var x = w + a.cos * w * 1.8
+               var y = h + a.sin * h * 1.8
+               return new Pos(x, y)
+       end
+
+       # Create a BPath between two point with some nice handle values
+       fun new_path(from, to: Pos, ttl: Float): BPath
+       do
+               var a = atan2(to.y-from.y, to.x-from.x)
+               a += pi * (2.0.rand - 1.0)
+               var radius = 300.0 * scale
+               var fh = new Pos(from.x + a.cos*radius, from.y + a.sin*radius)
+               #var th = new Pos(to.x - a.cos*radius, to.y - a.sin*radius)
+               var path = new BPath(from, fh, to, to, ttl)
+               return path
+       end
+
+       # Initial placement of buttons
+       fun fly_in(display: Display)
+       do
+               for b in buttons do
+                       var from = far_away(display)
+                       var to = b.to_pos
+                       var path = new_path(from, to, 5.0)
+                       b.path = path
+                       b.ttl = 5.0
+               end
+               ttl = 6.0
+       end
+
+       # Final leaving of buttons
+       fun fly_out(display: Display)
+       do
+               for b in buttons do
+                       var from = b.to_pos
+                       var to = far_away(display)
+                       b.x = to.x
+                       b.y = to.y
+                       var path = new_path(from, to, 5.0)
+                       b.path = path
+                       b.ttl = 5.0
+                       b.hard = false
+               end
+               ttl = 6.0
+       end
+
+       # Randomly permute the content of `buttons` such that no element appears in its original position.
+       fun derangement
+       do
+               # The simplest algorithm is to shuffle until no buttons is at the same place
+               # This is also quite efficient and converges extremely quickly
+               var redo = true
+               while redo do
+                       redo = false
+                       buttons.shuffle
+                       for i in [0..size[ do
+                               if i == buttons[i].place then
+                                       redo = true
+                                       break
+                               end
+                       end
+               end
+       end
+
+       # Shuffling the place of each button on the screen
+       fun shuffle(display: Display)
+       do
+               for b in buttons do
+                       b.from = b.to_pos
+               end
+
+               derangement
+
+               locate(display)
+               for b in buttons do
+                       var from = b.from
+                       var to = b.to_pos
+                       #print "shuffle move {b.place}: {from} -> {to}"
+                       b.path = new_path(from, to, 5.0)
+                       b.ttl = 5.0
+               end
+               ttl = 5.0
+       end
+
+       # Shuffle the place of each button in a hard way
+       fun hard_shuffle(display: Display)
+       do
+               for b in buttons do
+                       b.from = b.to_pos
+                       b.hard = true
+               end
+
+               derangement
+
+               locate(display)
+               for b in buttons do
+                       var from = b.from
+                       var to = b.to_pos
+                       var midx = display.width.to_f / 2.0
+                       var midy = display.height.to_f / 2.0
+                       var mid = new Pos(midx, midy)
+                       #print "shuffle move {b.place}: {from} -> {to}"
+                       b.path = new_path(from, mid, 5.0)
+                       b.path2 = new_path(mid, to, 5.0)
+                       b.ttl = 5.0
+               end
+               ttl = 5.0
+       end
+
+       # Setup the next cursor path
+       fun setpath
+       do
+               if is_menu then return
+               var from = path_pos(cpt-1)
+               var to = path_pos(cpt)
+               #print "cursor {cpt-1}->{cpt}: {from} -> {to}"
+               path = new_path(from, to, 4.0)
+               cursor.x = from.x
+               cursor.y = from.y
+               ttl = 5.0
+       end
+
+       # Main loop, drawing and inputs
+
+       # Flag used to ask for a (re-)computation of the display layout
+       private var first_frame = true
+
+       redef fun frame_core(display)
+       do
+               if first_frame then
+                       locate(display)
+                       if cpt == -1 then
+                               fly_in(display)
+                       end
+                       first_frame = false
+               end
+
+               # Clear the screen
+               display.clear(1.0, 1.0, 1.0)
+
+               # Manage events
+               # This is a crappy ad hoc organic implementation
+               if not player then
+                       ttl -= 0.1
+                       if path != null then path.update(cursor, ttl)
+                       if ttl <= 0.0 then
+                               ttl = 0.0
+                               if is_menu then
+                                       # Menu animation is over
+                                       player = true
+                               else if cpt < 0 then
+                                       # Level place animation is over
+                                       cpt += 1
+                                       setpath
+                               else if cpt < level.length then
+                                       # The cursor is playing
+                                       var b = level[cpt]
+                                       b.ttl = 1.0
+                                       b.sound.play
+                                       cpt += 1
+                                       setpath
+                               else if cpt == level.length then
+                                       # The cursor is out, run the shuffle
+                                       path = null
+                                       if shuffling == 1 then
+                                               shuffle(display)
+                                       else if shuffling > 1 then
+                                               hard_shuffle(display)
+                                       end
+                                       cpt += 1
+                               else
+                                       # The shuffling is over, start playing
+                                       player = true
+                                       cpt = 0
+                               end
+                       end
+               else if ttl > 0.0 then
+                       ttl -= 0.1
+                       if ttl <= 0.0 then
+                               ttl = 0.0
+                               if cpt == level.length then
+                                       fly_out(display)
+                                       cpt += 1
+                               else
+                                       if is_menu then
+                                               new_game
+                                       else if is_win then
+                                               current_level += 1
+                                               new_game
+                                       else
+                                               replay_game
+                                       end
+                               end
+                       end
+               end
+
+               # Display each button
+               for b in buttons do
+                       b.blit_on(display)
+               end
+
+               # Display the cursor
+               if path != null then
+                       drawing.cursor.scale = scale
+                       display.blit(drawing.cursor, cursor.x, cursor.y)
+               end
+
+               if not is_menu then
+                       blit_number(current_level, ui_scale, 10.0 * scale, 10.0 * scale)
+                       reload.blit_on(display)
+               end
+       end
+
+       # Blit a number somewhere
+       fun blit_number(number: Int, scale: Float, x, y: Float)
+       do
+               for img in number_images.imgs do img.scale = scale
+               display.blit_number(number_images, number, x.to_i, y.to_i)
+       end
+
+       # Images with the numbers
+       private var number_images: NumberImages is noautoinit
+
+       # A player click on a button
+       fun action(b: Button)
+       do
+               if is_menu then
+                       b.sound.play
+                       mode = b.place
+                       current_level = 0
+                       ttl = 0.1
+                       cpt = level.length
+                       is_win = true
+                       return
+               end
+               if cpt >= level.length then return
+               if b == level[cpt] then
+                       b.sound.play
+                       b.ttl = 1.0
+
+                       cpt += 1
+                       if cpt >= level.length then
+                               is_win = true
+                               print "Won!"
+                               ttl = 2.0
+                       end
+               else
+                       error += 1
+                       print "Err {error}"
+                       b.error = true
+                       b.ttl = 3.0
+                       snd_penalty.play
+                       if error > 2 then
+                               is_win = false
+                               print "Lose!"
+                               for b2 in buttons do
+                                       b2.error = true
+                                       b2.ttl = 3.0
+                               end
+                               ttl = 3.0
+                               cpt = level.length
+                       end
+               end
+       end
+
+       redef fun input(ie)
+       do
+               # Quit?
+               if ie isa QuitEvent then
+                       quit = true
+                       return true
+               end
+
+               # On click (or tap)
+               if ie isa PointerEvent and ie.depressed then
+                       if player then
+                               for b in buttons do
+                                       if b.has(ie.x, ie.y) then
+                                               action(b)
+                                               return true
+                                       end
+                               end
+                       end
+
+                       if not is_menu then
+                               if reload.has(ie.x, ie.y) then
+                                       reload.sound.play
+                                       reload.ttl = 1.0
+                                       replay_game
+                                       return true
+                               end
+                       end
+               end
+
+               # Special commands
+               if ie isa KeyEvent and ie.is_down then
+                       var c = ie.name
+
+                       if c == "4" or c == "escape" then
+                               # 4 is *back* on android
+                               if is_menu then
+                                       # quit = true # broken
+                                       new_menu
+                               else
+                                       new_menu
+                               end
+                               return true
+                       end
+
+                       if is_menu then
+                               return false
+                       end
+
+                       if c == "[+]" or c == "=" then
+                               # [+] is keypad `+`
+                               size += 1
+                               deal_game
+                               return true
+                       else if c == "[-]" or c == "-" then
+                               size -= 1
+                               deal_game
+                               return true
+                       else if c == "[*]" or c == "]" then
+                               length += 1
+                               deal_game
+                               return true
+                       else if c == "[/]" or c == "[" then
+                               length -= 1
+                               deal_game
+                               return true
+                       else if c == "space" or c == "82" then
+                               # 82 is *menu* on android
+                               reload.sound.play
+                               reload.ttl = 1.0
+                               replay_game
+                               return true
+                       end
+
+                       print "got keydown: `{c}`"
+               end
+
+               return false
+       end
+end
index 19e113c..946b420 100644 (file)
@@ -714,7 +714,7 @@ private class DFAGenerator
                        else
                                add("\tredef fun trans(char) do\n")
 
-                               add("\t\tvar c = char.ascii\n")
+                               add("\t\tvar c = char.code_point\n")
                                var haslast = false
                                var last = -1
                                for sym, next in trans do
@@ -791,14 +791,14 @@ class TSymbol
                if f <= 32 then
                        res = "#{f}"
                else
-                       res = f.ascii.to_s
+                       res = f.code_point.to_s
                end
                var l = last
                if f == l then return res
                res += " .. "
                if l == null then return res
                if l <= 32 or l >= 127 then return res + "#{l}"
-               return res + l.ascii.to_s
+               return res + l.code_point.to_s
        end
 end
 
index af417d4..795cee0 100644 (file)
@@ -588,7 +588,7 @@ redef class Token
                if text != null then
                        var nfa = new Automaton.epsilon
                        for c in text.chars do
-                               nfa.concat(new Automaton.atom(c.ascii))
+                               nfa.concat(new Automaton.atom(c.code_point))
                        end
                        return nfa
                end
index d0d90ac..886eaea 100644 (file)
@@ -38,7 +38,7 @@ redef class Nstr
        do
                var a = new Automaton.epsilon
                for c in self.value.chars do
-                       var b = new Automaton.atom(c.ascii)
+                       var b = new Automaton.atom(c.code_point)
                        a.concat(b)
                end
                return a
@@ -46,19 +46,19 @@ redef class Nstr
 end
 
 redef class Nch_dec
-       redef fun value: String do return text.substring_from(1).to_i.ascii.to_s
+       redef fun value: String do return text.substring_from(1).to_i.code_point.to_s
        redef fun make_rfa: Automaton
        do
-               var a = new Automaton.atom(self.value.chars.first.ascii)
+               var a = new Automaton.atom(self.value.chars.first.code_point)
                return a
        end
 end
 
 redef class Nch_hex
-       redef fun value: String do return text.substring_from(2).to_hex.ascii.to_s
+       redef fun value: String do return text.substring_from(2).to_hex.code_point.to_s
        redef fun make_rfa: Automaton
        do
-               var a = new Automaton.atom(self.value.chars.first.ascii)
+               var a = new Automaton.atom(self.value.chars.first.code_point)
                return a
        end
 end
@@ -227,7 +227,7 @@ redef class Nre_class
                        exit(1)
                        abort
                end
-               var a = new Automaton.cla(c1.chars.first.ascii, c2.chars.first.ascii)
+               var a = new Automaton.cla(c1.chars.first.code_point, c2.chars.first.code_point)
                return a
        end
 end
index 6fd9edf..634b695 100644 (file)
@@ -165,7 +165,7 @@ class Location
        # * `"0;32"` for green
        fun colored_line(color: String): String
        do
-               var esc = 27.ascii
+               var esc = 27.code_point
                var def = "{esc}[0m"
                var col = "{esc}[{color}m"
 
index 592e1af..d74d1f1 100644 (file)
@@ -24,12 +24,12 @@ redef class ANumberValue
 end
 
 redef class ACharValue
-       redef fun to_i do return n_char.content.first.ascii
+       redef fun to_i do return n_char.content.first.code_point
 end
 
 redef class AStringValue
        # legal but no not recommended
-       redef fun to_i do return n_string.content.first.ascii
+       redef fun to_i do return n_string.content.first.code_point
 end
 
 redef class AHexValue
index 912336c..718ee98 100644 (file)
@@ -337,7 +337,7 @@ class Lexer
                        if sp >= string_len then
                                dfa_state = -1
                        else
-                               var c = string[sp].ascii
+                               var c = string[sp].code_point
                                if c >= 255 then c = 255
                                sp += 1
 
index 73a3f41..565c19e 100644 (file)
@@ -19,7 +19,7 @@ fun encrypt(src, key: String): String do
                        continue
                end
 
-               out.add(((c.ascii + key[j].ascii - 2 * 'A'.ascii) % 26 + 'A'.ascii).ascii)
+               out.add(((c.ascii + key[j].ascii - 2u8 * 'A'.ascii) % 26u8 + 'A'.ascii).ascii)
                j = (j + 1) % key.length
        end
 
@@ -39,7 +39,7 @@ fun decrypt(src, key: String): String do
                        continue
                end
 
-               out.add(((c.ascii - key[j].ascii + 26) % 26 + 'A'.ascii).ascii)
+               out.add(((c.ascii - key[j].ascii + 26u8) % 26u8 + 'A'.ascii).ascii)
                j = (j + 1) % key.length
        end
 
index 4eae395..cb73b3b 100644 (file)
@@ -42,7 +42,7 @@ redef class NativeString
        #     assert "string".encode_base64 == "c3RyaW5n"
        private fun encode_base64(length: Int, padding: nullable Byte): Bytes do
                var base64_bytes = once base64_chars
-               if padding == null then padding = '='.ascii.to_b
+               if padding == null then padding = '='.ascii
                var steps = length / 3
                var bytes_in_last_step = length % 3
                var result_length = steps * 4
@@ -81,7 +81,7 @@ redef class NativeString
        #
        # REQUIRE: `length % 4 == 0`
        private fun decode_base64(length: Int, padding: nullable Byte): Bytes do
-               if padding == null then padding = '='.ascii.to_b
+               if padding == null then padding = '='.ascii
                var inv = once inverted_base64_chars
                if length == 0 then return new Bytes.empty
                assert length % 4 == 0 else print "base64::decode_base64 only supports strings of length multiple of 4"
index dad9899..48f0ed2 100644 (file)
@@ -442,10 +442,10 @@ class HD44780
                                #write(true, "C0".to_hex)
                                # instead we use the following which may not be portable
 
-                               for s in [count..40[ do write(false, ' '.ascii)
+                               for s in [count..40[ do write(false, ' '.code_point)
                                count = 0
                        else
-                               write(false, c.ascii)
+                               write(false, c.code_point)
                                count += 1
                        end
                end
index b6909cd..c15cb52 100644 (file)
@@ -107,7 +107,7 @@ redef abstract class Writer
        # Compared to `write_string`, this method supports null bytes in `text`.
        fun write_block(text: Text)
        do
-               write_int64 text.length
+               write_int64 text.bytelen
                write text
        end
 
@@ -197,7 +197,7 @@ redef abstract class Reader
        do
                var length = read_int64
                if length == 0 then return ""
-               return read(length)
+               return read_bytes(length).to_s
        end
 
        # Read a floating point on 32 bits and return it as a `Float`
index d36f9c0..e069304 100644 (file)
 # The serialized data format uses a dictionary structure similar to BSON:
 #
 # ~~~raw
-# object = 0x01                   # null
-#        | 0x02 id attributes     # New object
-#        | 0x03 id                # Ref to object
-#        | 0x04 int64             # Int
-#        | 0x05 int8              # Bool (int8 != 0)
-#        | 0x06 int8              # Char
-#        | 0x07 double(64 bits)   # Float
-#        | 0x08 block             # String
-#        | 0x09 block             # NativeString
-#        | 0x0A flat_array;       # Array[nullable Object]
+# object = 0x01                    # null
+#        | 0x02 id attributes      # New object
+#        | 0x03 id                 # Ref to object
+#        | 0x04 int64              # Int
+#        | 0x05 int8               # Bool (int8 != 0)
+#        | 0x06 utf8 byte sequence # Char
+#        | 0x07 double(64 bits)    # Float
+#        | 0x08 block              # String
+#        | 0x09 block              # NativeString
+#        | 0x0A flat_array;        # Array[nullable Object]
 #
 # block = int64 int8*;
 # cstring = int8* 0x00;
@@ -128,6 +128,9 @@ class BinaryDeserializer
        # Tree of attributes, deserialized but not yet claimed
        private var unclaimed_attributes = new UnrolledList[HashMap[String, nullable Object]]
 
+       # Buffer for one char
+       private var char_buf: NativeString is lazy do return new NativeString(4)
+
        # Read and deserialize the next attribute name and value
        #
        # A `peeked_char` can suffix the next attribute name.
@@ -217,9 +220,17 @@ class BinaryDeserializer
                if kind == kind_bool then return stream.read_bool
                if kind == kind_float then return stream.read_double
                if kind == kind_char then
+                       var bf = char_buf
                        var b = stream.read_byte
-                       if b == null then return 0
-                       return b.to_i.ascii
+                       if b == null then return '�'
+                       var ln = b.u8len
+                       bf[0] = b
+                       for i in [1 .. ln[ do
+                               b = stream.read_byte
+                               if b == null then return '�'
+                               bf[i] = b
+                       end
+                       return bf.to_s_with_length(ln)[0]
                end
                if kind == kind_string then return stream.read_block
                if kind == kind_native_string then return stream.read_block.to_cstring
@@ -382,8 +393,7 @@ redef class Char
        redef fun serialize_to_binary(v)
        do
                v.stream.write_byte kind_char
-               # Fix when UTF-8
-               v.stream.write_byte self.ascii.to_b
+               for i in bytes do v.stream.write_byte i
        end
 end
 
index e408402..0aceff5 100644 (file)
@@ -211,11 +211,11 @@ class Bitmap
                var fw = new FileWriter.open(path)
                # Write bitmap header
                for x in [0..self.bitmap_header.length[ do
-                       fw.write(self.bitmap_header[x].ascii.to_s)
+                       fw.write(self.bitmap_header[x].code_point.to_s)
                end
                # Write dib header
                for x in [0..self.dib_header.length[ do
-                       fw.write(self.dib_header[x].ascii.to_s)
+                       fw.write(self.dib_header[x].code_point.to_s)
                end
                # Write color table (if any)
                # Write data (no padding for now)
@@ -226,9 +226,9 @@ class Bitmap
                                var red = pixel >> 16
                                var green = (pixel & 0x00FF00) >> 8
                                var blue = pixel & 0x000000FF
-                               fw.write(red.ascii.to_s)
-                               fw.write(green.ascii.to_s)
-                               fw.write(blue.ascii.to_s)
+                               fw.write(red.code_point.to_s)
+                               fw.write(green.code_point.to_s)
+                               fw.write(blue.code_point.to_s)
                        end
                end
                fw.close
index 8ed1f6b..fcc90c7 100644 (file)
@@ -109,7 +109,7 @@ private class Leaf
 
        redef fun substrings do return new LeafSubstrings(self)
 
-       redef fun [](i) do return buf[i].to_i.ascii
+       redef fun [](i) do return buf[i].to_i.code_point
 
        init do
                bns = buf.ns
index c0a8772..0020b7a 100644 (file)
@@ -18,7 +18,7 @@ module console
 # A ANSI/VT100 escape sequence.
 abstract class TermEscape
        # The US-ASCII ESC character.
-       protected fun esc: Char do return 27.ascii
+       protected fun esc: Char do return 27.code_point
 
        # The Control Sequence Introducer (CSI).
        protected fun csi: String do return "{esc}["
index 356f386..227759a 100644 (file)
@@ -32,18 +32,18 @@ redef class Byte
        #
        # ~~~nit
        # intrude import core::bytes
-       # assert not '/'.ascii.to_b.is_valid_hexdigit
-       # assert '0'.ascii.to_b.is_valid_hexdigit
-       # assert '9'.ascii.to_b.is_valid_hexdigit
-       # assert not ':'.ascii.to_b.is_valid_hexdigit
-       # assert not '@'.ascii.to_b.is_valid_hexdigit
-       # assert 'A'.ascii.to_b.is_valid_hexdigit
-       # assert 'F'.ascii.to_b.is_valid_hexdigit
-       # assert not 'G'.ascii.to_b.is_valid_hexdigit
-       # assert not '`'.ascii.to_b.is_valid_hexdigit
-       # assert 'a'.ascii.to_b.is_valid_hexdigit
-       # assert 'f'.ascii.to_b.is_valid_hexdigit
-       # assert not 'g'.ascii.to_b.is_valid_hexdigit
+       # assert not '/'.ascii.is_valid_hexdigit
+       # assert '0'.ascii.is_valid_hexdigit
+       # assert '9'.ascii.is_valid_hexdigit
+       # assert not ':'.ascii.is_valid_hexdigit
+       # assert not '@'.ascii.is_valid_hexdigit
+       # assert 'A'.ascii.is_valid_hexdigit
+       # assert 'F'.ascii.is_valid_hexdigit
+       # assert not 'G'.ascii.is_valid_hexdigit
+       # assert not '`'.ascii.is_valid_hexdigit
+       # assert 'a'.ascii.is_valid_hexdigit
+       # assert 'f'.ascii.is_valid_hexdigit
+       # assert not 'g'.ascii.is_valid_hexdigit
        # ~~~
        private fun is_valid_hexdigit: Bool do
                return (self >= 0x30u8 and self <= 0x39u8) or
index 17ef576..36f21a3 100644 (file)
@@ -158,6 +158,9 @@ universal Int8
        redef fun to_i32 is intern
        redef fun to_u32 is intern
 
+       # Returns `self` as a Char according to its ASCII value.
+       fun ascii: Char `{ return (uint32_t)self; `}
+
        redef fun distance(i) do return (self - i).to_i
 
        redef fun <=>(other)
@@ -271,6 +274,9 @@ universal Int16
        redef fun *(i) is intern
        redef fun /(i) is intern
 
+       # Returns `self` as a Char according to its ASCII value.
+       fun ascii: Char `{ return (uint32_t)self; `}
+
        # Modulo of `self` with `i`.
        #
        # Returns the remainder of division of `self` by `i`.
@@ -425,6 +431,9 @@ universal UInt16
        redef fun zero do return 0.to_u16
        redef fun value_of(val) do return val.to_u16
 
+       # Returns `self` as a Char according to its ASCII value.
+       fun ascii: Char `{ return (uint32_t)self; `}
+
        # `i` bits shift to the left
        #
        #     assert 5u16 << 1    == 10u16
@@ -558,6 +567,9 @@ universal Int32
        redef fun *(i) is intern
        redef fun /(i) is intern
 
+       # Returns `self` as a Char according to its ASCII value.
+       fun ascii: Char `{ return (uint32_t)self; `}
+
        # Modulo of `self` with `i`.
        #
        # Returns the remainder of division of `self` by `i`.
@@ -701,6 +713,9 @@ universal UInt32
        redef fun *(i) is intern
        redef fun /(i) is intern
 
+       # Returns `self` as a Char according to its ASCII value.
+       fun ascii: Char `{ return (uint32_t)self; `}
+
        # Modulo of `self` with `i`.
        #
        # Returns the remainder of division of `self` by `i`.
index b2ac524..650360a 100644 (file)
@@ -651,6 +651,11 @@ universal Byte
        #     assert 5u8 >> 1    == 2u8
        fun >>(i: Int): Byte `{ return self >> i; `}
 
+       # Returns the character equivalent of `self`
+       #
+       # REQUIRE: `self <= 127u8`
+       fun ascii: Char `{ return (uint32_t)self; `}
+
        redef fun to_i is intern
        redef fun to_f is intern
        redef fun to_b do return self
@@ -797,11 +802,12 @@ universal Int
                end
        end
 
-       # The character whose ASCII value is `self`.
+       # The character which code point (unicode-wise) is `self`
        #
-       #     assert 65.ascii   == 'A'
-       #     assert 10.ascii   == '\n'
-       fun ascii: Char is intern
+       #     assert 65.code_point == 'A'
+       #     assert 10.code_point == '\n'
+       #     assert 0x220B.code_point == '∋'
+       fun code_point: Char `{ return (uint32_t)self; `}
 
        # Number of digits of an integer in base `b` (plus one if negative)
        #
@@ -861,9 +867,9 @@ universal Int
        do
                assert self >= 0 and self <= 36 # TODO plan for this
                if self < 10 then
-                       return (self + '0'.ascii).ascii
+                       return (self + '0'.code_point).code_point
                else
-                       return (self + ('a'.ascii - 10)).ascii
+                       return (self - 10 + 'a'.code_point).code_point
                end
        end
 
@@ -905,7 +911,7 @@ universal Char
                        printf("%c", self);
                }
        `}
-       redef fun hash do return ascii
+       redef fun hash do return code_point
        redef fun ==(o) is intern
        redef fun !=(o) is intern
 
@@ -919,7 +925,7 @@ universal Char
 
        redef fun distance(c)
        do
-               var d = self.ascii - c.ascii
+               var d = self.code_point - c.code_point
                if d >= 0 then
                        return d
                else
@@ -936,17 +942,32 @@ universal Char
                if self == '-' then
                        return -1
                else if is_digit then
-                       return self.ascii - '0'.ascii
+                       return self.code_point - '0'.code_point
                else
-                       return self.to_lower.ascii - 'a'.ascii + 10
+                       return self.to_lower.code_point - 'a'.code_point + 10
                end
        end
 
-       # the ascii value of self
+       # The ascii value of `self`
+       #
+       #     assert 'a'.ascii    == 97u8
+       #     assert '\n'.ascii   == 10u8
+       #
+       # REQUIRE: `is_ascii`
+       fun ascii: Byte do return code_point.to_b
+
+       # The unicode code point value of `self`
+       #
+       #     assert 'A'.code_point == 65
+       #     assert '\n'.code_point == 10
+       #     assert '∋'.code_point == 0x220B
+       fun code_point: Int `{ return (long)self; `}
+
+       # Is `self` an ASCII character ?
        #
-       #     assert 'a'.ascii    == 97
-       #     assert '\n'.ascii   == 10
-       fun ascii: Int is intern
+       #     assert 'x'.is_ascii
+       #     assert not 'ま'.is_ascii
+       fun is_ascii: Bool do return code_point <= 127
 
        # Return the lower case version of self.
        # If self is not a letter, then return self
@@ -957,7 +978,7 @@ universal Char
        fun to_lower: Char
        do
                if is_upper then
-                       return (ascii + ('a'.distance('A'))).ascii
+                       return (code_point + ('a'.distance('A'))).code_point
                else
                        return self
                end
@@ -972,7 +993,7 @@ universal Char
        fun to_upper: Char
        do
                if is_lower then
-                       return (ascii - ('a'.distance('A'))).ascii
+                       return (code_point - ('a'.distance('A'))).code_point
                else
                        return self
                end
@@ -1033,7 +1054,7 @@ universal Char
        #     assert '\t'.is_whitespace == true
        fun is_whitespace: Bool
        do
-               var i = ascii
+               var i = code_point
                return i <= 0x20 or i == 0x7F
        end
 end
index 50b36e9..c08c735 100644 (file)
@@ -333,6 +333,45 @@ redef class Float
        # assert -0.5.lerp(0.0, 128.0) == -64.0
        # ~~~
        fun lerp(a, b: Float): Float do return (1.0 - self) * a + self * b
+
+       # Quadratic Bézier interpolation between `a` and `b` with an `handle` using `self` as weight
+       #
+       # ~~~
+       # assert  0.00.qerp(0.0, 32.0, 128.0) == 0.0
+       # assert  0.25.qerp(0.0, 32.0, 128.0) == 20.0
+       # assert  0.50.qerp(0.0, 32.0, 128.0) == 48.0
+       # assert  0.75.qerp(0.0, 32.0, 128.0) == 84.0
+       # assert  1.00.qerp(0.0, 32.0, 128.0) == 128.0
+       # ~~~
+       fun qerp(a, handle, b: Float): Float do
+               var p = self
+               var i = 1.0 - p
+               var r =     i*i * a +
+                       2.0*i*p * handle +
+                           p*p * b
+               return r
+       end
+
+       # Cubic Bézier interpolation between `a` and `b` with two handles using `self` as weight
+       #
+       # The Cubic Bézier interpolation is the most common one and use two control points.
+       #
+       # ~~~
+       # assert  0.00.cerp(0.0, 32.0, 128.0, 64.0) == 0.0
+       # assert  0.25.cerp(0.0, 32.0, 128.0, 64.0) == 32.5
+       # assert  0.50.cerp(0.0, 32.0, 128.0, 64.0) == 68.0
+       # assert  0.75.cerp(0.0, 32.0, 128.0, 64.0) == 85.5
+       # assert  1.00.cerp(0.0, 32.0, 128.0, 64.0) == 64.0
+       # ~~~
+       fun cerp(a, a_handle, b_handle, b: Float): Float do
+               var p = self
+               var i = 1.0 - p
+               var r =     i*i*i  * a +
+                       3.0*i*i*p * a_handle +
+                       3.0*i*p*p * b_handle +
+                           p*p*p * b
+               return r
+       end
 end
 
 # Positive float infinite (IEEE 754)
index 4b1e826..b4a0e2b 100644 (file)
@@ -275,7 +275,7 @@ abstract class Reader
        # ~~~
        # var w = new StringReader(" Hello, \n\t World!")
        # assert w.read_word == "Hello,"
-       # assert w.read_char == '\n'.ascii
+       # assert w.read_char == '\n'
        # assert w.read_word == "World!"
        # assert w.read_word == ""
        # ~~~
@@ -441,7 +441,7 @@ abstract class BufferedReader
                        return null
                end
                # TODO: Fix when supporting UTF-8
-               var c = _buffer[_buffer_pos].to_i.ascii
+               var c = _buffer[_buffer_pos].to_i.code_point
                _buffer_pos += 1
                return c
        end
index b1e6a04..63fb920 100644 (file)
@@ -543,7 +543,7 @@ abstract class Text
 
                if c >= '0' and c <= '9' then
                        res.add('_')
-                       res.append(c.ascii.to_s)
+                       res.append(c.code_point.to_s)
                        res.add('d')
                        start = 1
                end
@@ -555,7 +555,7 @@ abstract class Text
                                continue
                        end
                        if underscore then
-                               res.append('_'.ascii.to_s)
+                               res.append('_'.code_point.to_s)
                                res.add('d')
                        end
                        if c >= '0' and c <= '9' then
@@ -566,13 +566,13 @@ abstract class Text
                                underscore = true
                        else
                                res.add('_')
-                               res.append(c.ascii.to_s)
+                               res.append(c.code_point.to_s)
                                res.add('d')
                                underscore = false
                        end
                end
                if underscore then
-                       res.append('_'.ascii.to_s)
+                       res.append('_'.code_point.to_s)
                        res.add('d')
                end
                return res.to_s
@@ -587,7 +587,7 @@ abstract class Text
        # Three digits are always used to avoid following digits to be interpreted as an element
        # of the octal sequence.
        #
-       #     assert "{0.ascii}{1.ascii}{8.ascii}{31.ascii}{32.ascii}".escape_to_c == "\\000\\001\\010\\037 "
+       #     assert "{0.code_point}{1.code_point}{8.code_point}{31.code_point}{32.code_point}".escape_to_c == "\\000\\001\\010\\037 "
        #
        # The exceptions are the common `\t` and `\n`.
        fun escape_to_c: String
@@ -605,9 +605,9 @@ abstract class Text
                                b.append("\\\'")
                        else if c == '\\' then
                                b.append("\\\\")
-                       else if c.ascii < 32 then
+                       else if c.code_point < 32 then
                                b.add('\\')
-                               var oct = c.ascii.to_base(8, false)
+                               var oct = c.code_point.to_base(8, false)
                                # Force 3 octal digits since it is the
                                # maximum allowed in the C specification
                                if oct.length == 1 then
@@ -680,8 +680,8 @@ abstract class Text
                        else if c == ':' or c == ' ' or c == '#' then
                                b.add('\\')
                                b.add(c)
-                       else if c.ascii < 32 or c == ';' or c == '|' or c == '\\' or c == '=' then
-                               b.append("?{c.ascii.to_base(16, false)}")
+                       else if c.code_point < 32 or c == ';' or c == '|' or c == '\\' or c == '=' then
+                               b.append("?{c.code_point.to_base(16, false)}")
                        else
                                b.add(c)
                        end
@@ -695,7 +695,7 @@ abstract class Text
        #     assert s.length        ==  2
        #     var u = s.unescape_nit
        #     assert u.length        ==  1
-       #     assert u.chars[0].ascii      ==  10 # (the ASCII value of the "new line" character)
+       #     assert u.chars[0].code_point      ==  10 # (the ASCII value of the "new line" character)
        fun unescape_nit: String
        do
                var res = new Buffer.with_cap(self.length)
@@ -787,7 +787,7 @@ abstract class Text
                        if c == '%' then
                                if i + 2 >= length then
                                        # What follows % has been cut off
-                                       buf[l] = '?'.ascii.to_b
+                                       buf[l] = '?'.ascii
                                else
                                        i += 1
                                        var hex_s = substring(i, 2)
@@ -797,11 +797,11 @@ abstract class Text
                                                i += 1
                                        else
                                                # What follows a % is not Hex
-                                               buf[l] = '?'.ascii.to_b
+                                               buf[l] = '?'.ascii
                                                i -= 1
                                        end
                                end
-                       else buf[l] = c.ascii.to_b
+                       else buf[l] = c.ascii
 
                        i += 1
                        l += 1
@@ -905,7 +905,7 @@ abstract class Text
 
                        for i in [0..length[ do
                                var char = chars[i]
-                               h = (h << 5) + h + char.ascii
+                               h = (h << 5) + h + char.code_point
                        end
 
                        hash_cache = h
@@ -1050,7 +1050,7 @@ private abstract class StringByteView
 
        redef fun is_empty do return target.is_empty
 
-       redef fun length do return target.length
+       redef fun length do return target.bytelen
 
        redef fun iterator do return self.iterator_from(0)
 
@@ -1573,9 +1573,15 @@ end
 
 redef class Char
 
+       # Returns a sequence with the UTF-8 bytes of `self`
+       #
+       #     assert 'a'.bytes == [0x61u8]
+       #     assert 'ま'.bytes == [0xE3u8, 0x81u8, 0xBEu8]
+       fun bytes: SequenceRead[Byte] do return to_s.bytes
+
        # Length of `self` in a UTF-8 String
        private fun u8char_len: Int do
-               var c = self.ascii
+               var c = self.code_point
                if c < 0x80 then return 1
                if c <= 0x7FF then return 2
                if c <= 0xFFFF then return 3
index 52de988..4d2ff48 100644 (file)
@@ -1035,7 +1035,7 @@ redef class NativeString
                        end
                        var ok_c: Bool
                        var c = char_at(pos)
-                       var cp = c.ascii
+                       var cp = c.code_point
                        if nxst == 1 then
                                ok_c = cp >= 0 and cp <= 0x7F
                        else if nxst == 2 then
index acc9a12..4028ea0 100644 (file)
@@ -16,7 +16,7 @@ import math
 
 redef class Byte
        # Gives the length of the UTF-8 char starting with `self`
-       private fun u8len: Int do
+       fun u8len: Int do
                if self & 0b1000_0000u8 == 0u8 then
                        return 1
                else if self & 0b1110_0000u8 == 0b1100_0000u8 then
index 3e7b761..c164529 100644 (file)
@@ -468,7 +468,7 @@ class RopeBuffer
                        rp = 0
                end
                # TODO: Fix when supporting UTF-8
-               ns[rp] = c.ascii.to_b
+               ns[rp] = c.ascii
                rp += 1
                _bytelen += 1
                rpos = rp
index 310f725..011347d 100644 (file)
@@ -30,7 +30,7 @@ redef class Char
                x = x % 26
                if x < 0 then x += 26
                var up = false
-               var val = ascii
+               var val = code_point
                if is_upper then
                        up = true
                        val += 32
@@ -38,7 +38,7 @@ redef class Char
                val += x
                if val > 122 then val -= 26
                if up then val -= 32
-               return val.ascii
+               return val.code_point
        end
 end
 
diff --git a/lib/geometry/README.md b/lib/geometry/README.md
new file mode 100644 (file)
index 0000000..3e20f59
--- /dev/null
@@ -0,0 +1,56 @@
+Basic geometry data structures and services.
+
+# Points and Lines
+
+The very basics of geometry needs, for two and three-dimensional space.
+
+# Boxes and detection collision
+
+Boxes module introduces Bounding boxes for Points and Lines and services to detect collision or inclusion between boxes.
+It means a simple and fast way to test collision but not really accurate since it uses bounding boxes.
+
+# Quadtrees
+
+A QuadTree is a tree data structure in which each internal node has exactly four children
+They're most often used to partition two-dimensional space by recursively subdividing
+it into four quadrants or regions.
+
+* They decompose space into adaptable cells
+* Each cell has a maximum capacity. When maximum is reached, the cell splits.
+
+Quadtrees are using Boxed objects to determine their distribution in the 2D space.
+
+This API provides two different types of Quadtree : Static and Dynamic (respectively `SQuadTree` and `DQuadTree`).
+
+* Static: When you create the QuadTree, you need to specify the region that it will cover
+
+* Dynamic: You just need to fill the quadtree with objects, and when the threshold is reached,
+it will automatically divide the current region, depending on the distribution of objects already in the region.
+
+# Polygons
+
+Some basic polygon services.
+
+This module contains interesting algorithms for `ConvexPolygon`only at the moment. A Convex polygon can be defined as follow :
+
+* All its interior angles are less than 180°. this means that all the vertices of the polygon
+will point outwards, away from the interior of the shape.
+
+* Every point on every line segment between two points inside or on the boundary of the polygon
+remains inside or on the boundary.
+
+* The polygon is entirely contained in a closed half-plane defined by each of its edges.
+
+* For each edge, the interior points are all on the same side of the line that the edge defines.
+
+* The angle at each vertex contains all other vertices in its edges and interior.
+
+A polygon which is not convex is called concave. Convex polygon are used because most
+geometric problems are simpler and faster on convex objects than on non-convex ones.
+
+Services provided :
+
+* Point in convex polygon
+* Intersection of convex polygon
+* Convex hull of a set of points
+* Triangulation of polygon
index 7d274a5..039fb94 100644 (file)
@@ -19,18 +19,12 @@ module polygon
 
 import points_and_lines
 
-# Convex Polygon class
-class ConvexPolygon
-
+# Abstraction of a Polygon
+abstract class APolygon
        # Vertices of this polygon
-       var points = new Array[Point[Float]]
+       var points: Array[Point[Float]]
 
-       # Init this polygon with a list of `points`
-       # REQUIRE `pts.length == 3`
-       init with_vertices(pts: Array[Point[Float]]) do
-               assert pts.length >= 3
-               points.add_all(pts)
-       end
+       init do assert points.length >= 3
 
        # Get an array of the x coordinates of the vertices
        private fun x_coordinates: Array[Float] do
@@ -75,7 +69,7 @@ class ConvexPolygon
        # var p3 = new Point[Float](0.0, 5.0)
        # var p4 = new Point[Float](5.0, 5.0)
        # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4)
-       # var poly = new ConvexPolygon.with_vertices(arr)
+       # var poly = new ConvexPolygon(arr)
        # poly.sort_ccw
        # assert poly.points == [p4, p2, p1, p3]
        # ~~~
@@ -92,7 +86,7 @@ class ConvexPolygon
        # var p3 = new Point[Float](0.0, 5.0)
        # var p4 = new Point[Float](5.0, 5.0)
        # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4)
-       # var poly = new ConvexPolygon.with_vertices(arr)
+       # var poly = new ConvexPolygon(arr)
        # poly.sort_cw
        # assert poly.points == [p3, p1, p2, p4]
        # ~~~
@@ -101,7 +95,7 @@ class ConvexPolygon
                sorter.sort(points)
        end
 
-       # Does this polygon intersects `other` ?
+       # Is `self` convex ?
        #
        # ~~~
        # var p1 = new Point[Float](0.0, 0.0)
@@ -109,31 +103,20 @@ class ConvexPolygon
        # var p3 = new Point[Float](0.0, 5.0)
        # var p4 = new Point[Float](5.0, 5.0)
        # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4)
-       # var poly = new ConvexPolygon.with_vertices(arr)
+       # var poly = new ConvexPolygon(arr)
        # poly.sort_ccw
-       # p1 = new Point[Float](2.5, 2.5)
-       # p2 = new Point[Float](7.5, 2.5)
-       # p3 = new Point[Float](2.5, 7.5)
-       # p4 = new Point[Float](7.5, 7.5)
-       # arr = new Array[Point[Float]].with_items(p1, p2, p3, p4)
-       # var poly2 = new ConvexPolygon.with_vertices(arr)
-       # poly2.sort_ccw
-       # assert poly.intersects(poly2)
+       # assert poly.is_convex
        # ~~~
-       fun intersects(other: ConvexPolygon): Bool do
-               assert is_convex
-
-               var axes1 = axes
-               var axes2 = other.axes
-               for axis in axes1 do
-                       var project1 = project(axis)
-                       var project2 = other.project(axis)
-                       if not project1.overlap(project2) then return false
-               end
-               for axis in axes2 do
-                       var project1 = project(axis)
-                       var project2 = other.project(axis)
-                       if not project1.overlap(project2) then return false
+       fun is_convex: Bool do
+               var prev = points[points.length - 2]
+               var curr = points[points.length - 1]
+               var next = points[0]
+               var is_ccw = turn_left(prev, curr, next)
+               for i in [1..points.length[ do
+                       prev = curr
+                       curr= next
+                       next = points[i]
+                       if turn_left(prev ,curr, next) != is_ccw then return false
                end
                return true
        end
@@ -151,7 +134,36 @@ class ConvexPolygon
                return projection
        end
 
-       # Is this polygon convex ?
+       # Remove  `p` from the vertices, keeping at least 3 vertices
+       fun delete_vertex(p: Point[Float]) do
+               assert points.length > 3
+               points.remove(p)
+       end
+
+       # Does `self` intersects with `other`
+       fun intersects(other: APolygon): Bool is abstract
+
+       # Is `p` contained in `self` ?
+       fun contain(p: Point[Float]): Bool is abstract
+
+       # Add a vertex to `self`
+       fun add_vertex(p: Point[Float]): Bool do
+               points.add(p)
+               return true
+       end
+end
+
+# A simple polygon
+class Polygon
+       super APolygon
+       # TODO: implement algorithms for concave polygons ?
+end
+
+# Convex Polygon class
+class ConvexPolygon
+       super APolygon
+
+       # Does this polygon intersects `other` ?
        #
        # ~~~
        # var p1 = new Point[Float](0.0, 0.0)
@@ -159,26 +171,35 @@ class ConvexPolygon
        # var p3 = new Point[Float](0.0, 5.0)
        # var p4 = new Point[Float](5.0, 5.0)
        # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4)
-       # var poly = new ConvexPolygon.with_vertices(arr)
+       # var poly = new ConvexPolygon(arr)
        # poly.sort_ccw
-       # assert poly.is_convex
+       # p1 = new Point[Float](2.5, 2.5)
+       # p2 = new Point[Float](7.5, 2.5)
+       # p3 = new Point[Float](2.5, 7.5)
+       # p4 = new Point[Float](7.5, 7.5)
+       # arr = new Array[Point[Float]].with_items(p1, p2, p3, p4)
+       # var poly2 = new ConvexPolygon(arr)
+       # poly2.sort_ccw
+       # assert poly.intersects(poly2)
        # ~~~
-       fun is_convex: Bool do
-               var prev = points[points.length - 2]
-               var curr = points[points.length - 1]
-               var next = points[0]
-               var is_ccw = turn_left(prev, curr, next)
-               for i in [1..points.length[ do
-                       prev = curr
-                       curr= next
-                       next = points[i]
-                       if turn_left(prev ,curr, next) != is_ccw then return false
+       redef fun intersects(other) do
+               assert is_convex
+
+               var axes1 = axes
+               var axes2 = other.axes
+               for axis in axes1 do
+                       var project1 = project(axis)
+                       var project2 = other.project(axis)
+                       if not project1.overlap(project2) then return false
+               end
+               for axis in axes2 do
+                       var project1 = project(axis)
+                       var project2 = other.project(axis)
+                       if not project1.overlap(project2) then return false
                end
                return true
        end
 
-       # Check if `p` is in the polygon
-       #
        # ~~~
        # var p1 = new Point[Float](0.0, 0.0)
        # var p2 = new Point[Float](5.0, 0.0)
@@ -186,11 +207,11 @@ class ConvexPolygon
        # var p4 = new Point[Float](5.0, 5.0)
        # var p5 = new Point[Float](2.5, 2.5)
        # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4)
-       # var poly = new ConvexPolygon.with_vertices(arr)
+       # var poly = new ConvexPolygon(arr)
        # poly.sort_ccw
        # assert poly.contain(p5)
        # ~~~
-       fun contain(p : Point[Float]): Bool do
+       redef fun contain(p) do
                var prev = points[points.length - 1]
                var curr = p
                var next = points[0]
@@ -212,7 +233,7 @@ class ConvexPolygon
        # var p3 = new Point[Float](0.0, 5.0)
        # var p4 = new Point[Float](5.0, 5.0)
        # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4)
-       # var poly = new ConvexPolygon.with_vertices(arr)
+       # var poly = new ConvexPolygon(arr)
        # poly.sort_ccw
        # assert poly.is_ccw
        # ~~~
@@ -230,12 +251,7 @@ class ConvexPolygon
                return not turn_left(prev, points[min_index], next)
        end
 
-       # Remove  `p` from the vertices, keeping at least 3 vertices
-       fun delete_vertex(p: Point[Float]) do
-               if points.length > 3 then
-                       points.remove(p)
-               end
-       end
+
 
        # Add a vertex to the polygon
        #
@@ -245,15 +261,15 @@ class ConvexPolygon
        # var p3 = new Point[Float](0.0, 5.0)
        # var p4 = new Point[Float](5.0, 5.0)
        # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4)
-       # var poly = new ConvexPolygon.with_vertices(arr)
+       # var poly = new ConvexPolygon(arr)
        # var p5 = new Point[Float](2.5, 7.5)
        # assert poly.add_vertex(p5)
        # ~~~
-       fun add_vertex(p: Point[Float]): Bool do
+       redef fun add_vertex(p) do
                assert points.length >= 3
                var temp_list = points.clone
                temp_list.add(p)
-               var temp_polygon = new ConvexPolygon.with_vertices(temp_list)
+               var temp_polygon = new ConvexPolygon(temp_list)
                temp_polygon.sort_ccw
                if temp_polygon.is_convex then
                        points = temp_polygon.points
@@ -269,9 +285,7 @@ private class Projection
        var min: Float is writable
        var max: Float is writable
 
-       fun overlap(other: Projection): Bool do
-               return not (min > other.max or other.min > max)
-       end
+       fun overlap(other: Projection): Bool do return not (min > other.max or other.min > max)
 end
 
 private class PointXCompare
@@ -279,7 +293,7 @@ private class PointXCompare
 
        redef type COMPARED: Point[Float]
 
-       redef fun compare(a,b : COMPARED): Int do
+       redef fun compare(a,b) do
                if a.x == b.x then
                        if a.y == b.y then return 0
                        if a.y > b.y then return - 1
@@ -317,15 +331,17 @@ private abstract class PolygonSorter
        end
 end
 
+#TODO: CounterClockWise and ClockWise sorts are broken in some cases of concave polygons
+
 # Sort the vertices of a polygon in counter clockwise order
 private class CounterClockWiseSort
        super PolygonSorter
 
-       redef fun compare(a,b: COMPARED): Int do
+       redef fun compare(a,b) do
                if a.x == b.x and a.y == b.y then return 0
                if a.x - center.x >= 0.0 and b.x - center.x < 0.0 then return -1
                if a.x - center.x < 0.0 and b.x - center.x >= 0.0 then return 1
-               if a.x - center.x == 0.0 and b.x - center.x == 0 then
+               if a.x - center.x == 0.0 and b.x - center.x == 0.0 then
                        if a.y - center.y >= 0.0 or b.y - center.y >= 0.0 then
                                if a.y > b.y then return -1
                                return 1
@@ -349,7 +365,7 @@ end
 private class ClockWiseSort
        super PolygonSorter
 
-       redef fun compare(a,b: COMPARED): Int do
+       redef fun compare(a,b) do
                if a.x == b.x and a.y == b.y then return 0
                if a.x - center.x >= 0.0 and b.x - center.x < 0.0 then return 1
                if a.x - center.x < 0.0 and b.x - center.x >= 0.0 then return -1
@@ -373,7 +389,6 @@ private class ClockWiseSort
        end
 end
 
-
 # Get the convex hull of the set of `points`
 #
 # ~~~
@@ -410,7 +425,7 @@ fun convex_hull(points: Array[Point[Float]]): ConvexPolygon do
        pl1.remove_at(pl1.length - 1)
        pl2.remove_at(pl2.length -1)
        pl2.add_all(pl1)
-       return new ConvexPolygon.with_vertices(pl2)
+       return new ConvexPolygon(pl2)
 end
 
 # Is the angle between [p1,p2] and [p2,p3] going left (counter clockwise) or right (clockwise) ?
@@ -424,3 +439,49 @@ end
 fun turn_left(p1, p2, p3: Point[Float]): Bool do
        return ((p2.x - p1.x) * (p3.y - p2.y) - (p3.x - p2.x) * (p2.y - p1.y)) > 0.0
 end
+
+# Split a polygon into triangles
+# Useful for converting a concave polygon into multiple convex ones
+fun triangulate(pts: Array[Point[Float]], results: Array[ConvexPolygon]) do
+       var poly = new Polygon(pts)
+       poly.sort_ccw
+       pts = poly.points
+       recursive_triangulate(pts, results)
+end
+
+private fun recursive_triangulate(pts: Array[Point[Float]], results: Array[ConvexPolygon]) do
+       if pts.length == 3 then
+               results.add(new ConvexPolygon(pts))
+               return
+       end
+       var prev = pts[pts.length - 1]
+       var curr = pts[0]
+       var next = pts[1]
+       for i in [1..pts.length[ do
+               if turn_left(prev, curr, next) then
+                       prev = pts[i-1]
+                       curr = next
+                       if i+1 == pts.length then next = pts[pts.length - 1] else next = pts[i+1]
+                       continue
+               end
+               var contains = false
+               var triangle = new ConvexPolygon(new Array[Point[Float]].with_items(prev, curr, next))
+               for p in pts do
+                       if p != prev and p != curr and p != next then
+                               if triangle.contain(p) then
+                                       contains = true
+                                       break
+                               end
+                       end
+               end
+               if not contains then
+                       results.add(triangle)
+                       pts.remove(curr)
+                       recursive_triangulate(pts, results)
+                       break
+               end
+               prev = pts[i-1]
+               curr = next
+               if i+1 == pts.length then next = pts[pts.length - 1] else next = pts[i+1]
+       end
+end
index 88b270b..b6bf2c1 100644 (file)
@@ -47,7 +47,7 @@ end
 private class DFAState0
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 8 then return null
                if c <= 10 then return dfastate_1
                if c <= 31 then return null
@@ -84,7 +84,7 @@ private class DFAState1
                return null
        end
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 8 then return null
                if c <= 10 then return dfastate_1
                if c <= 31 then return null
@@ -95,7 +95,7 @@ end
 private class DFAState2
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 33 then return dfastate_2
                if c <= 34 then return dfastate_29
                if c <= 91 then return dfastate_2
@@ -116,7 +116,7 @@ end
 private class DFAState4
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 47 then return null
                if c <= 57 then return dfastate_5
                return null
@@ -132,7 +132,7 @@ private class DFAState5
                return t
        end
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 45 then return null
                if c <= 46 then return dfastate_24
                if c <= 47 then return null
@@ -177,7 +177,7 @@ end
 private class DFAState9
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 96 then return null
                if c <= 97 then return dfastate_20
                return null
@@ -186,7 +186,7 @@ end
 private class DFAState10
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 116 then return null
                if c <= 117 then return dfastate_17
                return null
@@ -195,7 +195,7 @@ end
 private class DFAState11
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 113 then return null
                if c <= 114 then return dfastate_14
                return null
@@ -224,7 +224,7 @@ end
 private class DFAState14
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 116 then return null
                if c <= 117 then return dfastate_15
                return null
@@ -233,7 +233,7 @@ end
 private class DFAState15
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 100 then return null
                if c <= 101 then return dfastate_16
                return null
@@ -252,7 +252,7 @@ end
 private class DFAState17
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 107 then return null
                if c <= 108 then return dfastate_18
                return null
@@ -261,7 +261,7 @@ end
 private class DFAState18
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 107 then return null
                if c <= 108 then return dfastate_19
                return null
@@ -280,7 +280,7 @@ end
 private class DFAState20
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 107 then return null
                if c <= 108 then return dfastate_21
                return null
@@ -289,7 +289,7 @@ end
 private class DFAState21
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 114 then return null
                if c <= 115 then return dfastate_22
                return null
@@ -298,7 +298,7 @@ end
 private class DFAState22
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 100 then return null
                if c <= 101 then return dfastate_23
                return null
@@ -317,7 +317,7 @@ end
 private class DFAState24
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 47 then return null
                if c <= 57 then return dfastate_28
                return null
@@ -326,7 +326,7 @@ end
 private class DFAState25
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 42 then return null
                if c <= 43 then return dfastate_26
                if c <= 44 then return null
@@ -339,7 +339,7 @@ end
 private class DFAState26
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 47 then return null
                if c <= 57 then return dfastate_27
                return null
@@ -355,7 +355,7 @@ private class DFAState27
                return t
        end
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 47 then return null
                if c <= 57 then return dfastate_27
                return null
@@ -371,7 +371,7 @@ private class DFAState28
                return t
        end
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 47 then return null
                if c <= 57 then return dfastate_28
                if c <= 68 then return null
@@ -394,7 +394,7 @@ end
 private class DFAState30
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 33 then return null
                if c <= 34 then return dfastate_2
                if c <= 46 then return null
@@ -418,7 +418,7 @@ end
 private class DFAState31
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 47 then return null
                if c <= 57 then return dfastate_32
                if c <= 64 then return null
@@ -431,7 +431,7 @@ end
 private class DFAState32
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 47 then return null
                if c <= 57 then return dfastate_33
                if c <= 64 then return null
@@ -444,7 +444,7 @@ end
 private class DFAState33
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 47 then return null
                if c <= 57 then return dfastate_34
                if c <= 64 then return null
@@ -457,7 +457,7 @@ end
 private class DFAState34
        super DFAState
        redef fun trans(char) do
-               var c = char.ascii
+               var c = char.code_point
                if c <= 47 then return null
                if c <= 57 then return dfastate_2
                if c <= 64 then return null
index fdb9f65..966f2c9 100644 (file)
@@ -99,22 +99,22 @@ redef class Text
                                buffer.append "\\\""
                        else if char == '\/' then
                                buffer.append "\\/"
-                       else if char < 16.ascii then
+                       else if char < 16.code_point then
                                if char == '\n' then
                                        buffer.append "\\n"
                                else if char == '\r' then
                                        buffer.append "\\r"
                                else if char == '\t' then
                                        buffer.append "\\t"
-                               else if char == 0x0C.ascii then
+                               else if char == 0x0C.code_point then
                                        buffer.append "\\f"
-                               else if char == 0x08.ascii then
+                               else if char == 0x08.code_point then
                                        buffer.append "\\b"
                                else
-                                       buffer.append "\\u000{char.ascii.to_hex}"
+                                       buffer.append "\\u000{char.code_point.to_hex}"
                                end
                        else if char < ' ' then
-                               buffer.append "\\u00{char.ascii.to_hex}"
+                               buffer.append "\\u00{char.code_point.to_hex}"
                        else
                                buffer.add char
                        end
@@ -435,9 +435,9 @@ redef class Nstring
                                i += 1
                                char = text[i]
                                if char == 'b' then
-                                       char = 0x08.ascii
+                                       char = 0x08.code_point
                                else if char == 'f' then
-                                       char = 0x0C.ascii
+                                       char = 0x0C.code_point
                                else if char == 'n' then
                                        char = '\n'
                                else if char == 'r' then
@@ -450,7 +450,7 @@ redef class Nstring
                                        if code >= 128 then
                                                char = '?'
                                        else
-                                               char = code.ascii
+                                               char = code.code_point
                                        end
                                        i += 4
                                end
index 1b7a017..e7462b4 100644 (file)
@@ -41,7 +41,7 @@ redef class Display
        do
                var str = number.to_s
                for c in str.chars do
-                       var d = c.ascii-'0'.ascii
+                       var d = c.code_point-'0'.code_point
                        assert d >= 0 and d <= 9
                        var img = imgs.imgs[d]
                        blit(img, x, y)
index acfe9fa..92f293b 100644 (file)
@@ -49,9 +49,9 @@ class XophonLexer
        # read the next byte. Else, return `-1`.
        fun expect_delimiter: Int do
                if accept('"') then
-                       return '"'.ascii
+                       return '"'.code_point
                else if accept('\'') then
-                       return '\''.ascii
+                       return '\''.code_point
                else
                        fire_unexpected_char(". Expecting `\"` or `'`")
                        return -1
@@ -71,7 +71,7 @@ class XophonLexer
        # If the last read byte is forbidden, fire a fatal error instead.
        fun expect_xml_char(buffer: Buffer): Bool do
                if is_xml_char then
-                       buffer.chars.push(last_char.ascii)
+                       buffer.chars.push(last_char.code_point)
                        read_char
                        return true
                else if eof then
@@ -91,7 +91,7 @@ class XophonLexer
                        buffer.chars.push(' ')
                        read_char
                        return true
-               else if last_char == '<'.ascii then
+               else if last_char == '<'.code_point then
                        return fire_fatal_error("`<` is forbidden in attribute values.")
                else
                        return expect_xml_char(buffer)
@@ -127,10 +127,10 @@ class XophonLexer
        # Is the last read byte matches the `NameStartChar` production?
        fun is_name_start_char: Bool do
                # TODO: Handle code points above 0x7F.
-               return ['A'.ascii .. 'Z'.ascii].has(last_char) or
-                               ['a'.ascii .. 'z'.ascii].has(last_char) or
-                               last_char == '_'.ascii or
-                               last_char == ':'.ascii or
+               return ['A'.code_point .. 'Z'.code_point].has(last_char) or
+                               ['a'.code_point .. 'z'.code_point].has(last_char) or
+                               last_char == '_'.code_point or
+                               last_char == ':'.code_point or
                                last_char > 127
        end
 
@@ -138,8 +138,8 @@ class XophonLexer
        fun is_name_char: Bool do
                # TODO: Handle code points above 0x7F.
                return is_name_start_char or
-                               last_char == '-'.ascii or
-                               last_char == '.'.ascii or
+                               last_char == '-'.code_point or
+                               last_char == '.'.code_point or
                                is_digit
        end
 
@@ -150,10 +150,10 @@ class XophonLexer
                if not is_name_start_char then
                        return fire_unexpected_char(" at the beginning of a name")
                end
-               buffer.chars.push(last_char.ascii)
+               buffer.chars.push(last_char.code_point)
                read_char
                while is_name_char do
-                       buffer.chars.push(last_char.ascii)
+                       buffer.chars.push(last_char.code_point)
                        read_char
                end
                return true
@@ -187,14 +187,14 @@ class XophonLexer
 
        # Is the last read byte matches the `[0-9]` production?
        fun is_digit: Bool do
-               return ['0'.ascii .. '9'.ascii].has(last_char)
+               return ['0'.code_point .. '9'.code_point].has(last_char)
        end
 
        # Accept a `[0-9]+` token.
        fun accept_digits(buffer: Buffer): Bool do
                if is_digit then
                        loop
-                               buffer.chars.push(last_char.ascii)
+                               buffer.chars.push(last_char.code_point)
                                read_char
                                if not is_digit then return true
                        end
@@ -210,16 +210,16 @@ class XophonLexer
 
        # Is `last_char` matches the `[0-9a-fA-F]` production?
        fun is_hex: Bool do
-               return ['0'.ascii .. '9'.ascii].has(last_char) or
-                               ['A'.ascii .. 'Z'.ascii].has(last_char) or
-                               ['a'.ascii .. 'Z'.ascii].has(last_char)
+               return ['0'.code_point .. '9'.code_point].has(last_char) or
+                               ['A'.code_point .. 'Z'.code_point].has(last_char) or
+                               ['a'.code_point .. 'Z'.code_point].has(last_char)
        end
 
        # Expect a `[0-9a-fA-F]+` token.
        fun expect_hex(buffer: Buffer): Bool do
                if is_hex then
                        loop
-                               buffer.chars.push(last_char.ascii)
+                               buffer.chars.push(last_char.code_point)
                                read_char
                                if not is_hex then return true
                        end
@@ -247,7 +247,7 @@ class XophonLexer
                else if last_char < 0 then
                        fire_fatal_error("Internal error: Already at the end of the file.")
                        return
-               else if last_char == '\n'.ascii then
+               else if last_char == '\n'.code_point then
                        locator.line_number += 1
                        locator.column_number = 1
                else
@@ -264,7 +264,7 @@ class XophonLexer
                # XML 1.0 end-of-line handling
                # Note: Regardless the XML version, any EOL defined by the
                # recommandation MUST be reported as a single LINE FEED.
-               if was_cr and last_char == '\n'.ascii then
+               if was_cr and last_char == '\n'.code_point then
                        # EOL already reported. => Skip this byte.
                        s = input.read_byte
                        if s == null then
@@ -273,10 +273,10 @@ class XophonLexer
                                last_char = s.to_i
                        end
                end
-               was_cr = last_char == '\r'.ascii
+               was_cr = last_char == '\r'.code_point
                if was_cr then
                        # Regardless the following byte, '\r' always introduce an EOL.
-                       last_char = '\n'.ascii
+                       last_char = '\n'.code_point
                end
        end
 
@@ -303,7 +303,7 @@ class XophonLexer
        fun is_int(c: Int): Bool do return last_char == c
 
        # Does the last read byte equal `c`?
-       fun is_char(c: Char): Bool do return last_char == c.ascii
+       fun is_char(c: Char): Bool do return last_char == c.code_point
 
        # Expect the specified byte.
        fun accept_int(expected: Int): Bool do
@@ -317,7 +317,7 @@ class XophonLexer
 
        # Accept the specified byte.
        fun accept(expected: Char): Bool do
-               return accept_int(expected.ascii)
+               return accept_int(expected.code_point)
        end
 
        # Ensure the last read byte is equal to `expected`.
@@ -330,7 +330,7 @@ class XophonLexer
        # Return `true` if and only if the last read byte as the expected value.
        fun expect_int(expected: Int, context: String): Bool do
                return accept_int(expected) or
-                               fire_unexpected_char("{context}. Expecting `{expected.ascii}`.")
+                               fire_unexpected_char("{context}. Expecting `{expected.code_point}`.")
        end
 
        # Ensure the last read byte is equal to `expected`.
@@ -363,7 +363,7 @@ class XophonLexer
                        if not accept(chars[i]) then
                                if is_xml_char then
                                        return fire_fatal_error("Unexpected " +
-                                                       "`{expected.substring(0, i)}{last_char.ascii.to_s}`" +
+                                                       "`{expected.substring(0, i)}{last_char.code_point.to_s}`" +
                                                        "{context}. Expecting `{expected}`.")
                                else if eof then
                                        return fire_fatal_error("Unexpected end of file{context}. " +
@@ -386,7 +386,7 @@ class XophonLexer
        # Return `false`.
        fun fire_unexpected_char(rest_of_message: String): Bool do
                if is_xml_char then
-                       return fire_fatal_error("Unexpected character `{last_char.ascii.to_s}`{rest_of_message}.")
+                       return fire_fatal_error("Unexpected character `{last_char.code_point.to_s}`{rest_of_message}.")
                else if eof then
                        return fire_fatal_error("Unexpected end of file{rest_of_message}.")
                else
index 2693086..d5ddeb3 100644 (file)
@@ -656,14 +656,14 @@ class XophonReader
                if lexer.accept('#') then
                        if lexer.accept('x') then
                                if lexer.expect_hex(ref) then
-                                       buffer.chars.add(ref.to_hex.ascii)
+                                       buffer.chars.add(ref.to_hex.code_point)
                                        return lexer.expect(';', "")
                                else
                                        return lexer.fire_unexpected_char(
                                                        ". Expecting an hexadecimal digit")
                                end
                        else if lexer.accept_digits(ref) then
-                               buffer.chars.add(ref.to_i.ascii)
+                               buffer.chars.add(ref.to_i.code_point)
                                return lexer.expect(';', "")
                        else
                                return lexer.fire_unexpected_char(" in a character reference. " +
index 2f83449..b79e9ba 100644 (file)
@@ -1552,10 +1552,10 @@ abstract class AbstractCompilerVisitor
        do
                var t = mmodule.char_type
 
-               if value.ascii < 128 then
+               if value.code_point < 128 then
                        return new RuntimeVariable("'{value.to_s.escape_to_c}'", t, t)
                else
-                       return new RuntimeVariable("{value.ascii}", t, t)
+                       return new RuntimeVariable("{value.code_point}", t, t)
                end
        end
 
@@ -2243,9 +2243,6 @@ redef class AMethPropdef
                        else if pname == "to_b" then
                                v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
                                return true
-                       else if pname == "ascii" then
-                               v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
-                               return true
                        end
                else if cname == "Char" then
                        if pname == "object_id" then
@@ -2279,9 +2276,6 @@ redef class AMethPropdef
                        else if pname == "to_i" then
                                v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
                                return true
-                       else if pname == "ascii" then
-                               v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
-                               return true
                        end
                else if cname == "Byte" then
                        if pname == "output" then
@@ -2351,9 +2345,6 @@ redef class AMethPropdef
                        else if pname == "to_u32" then
                                v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
                                return true
-                       else if pname == "ascii" then
-                               v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
-                               return true
                        end
                else if cname == "Bool" then
                        if pname == "output" then
@@ -2539,9 +2530,6 @@ redef class AMethPropdef
                        else if pname == "to_f" then
                                v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
                                return true
-                       else if pname == "ascii" then
-                               v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
-                               return true
                        else if pname == "&" then
                                v.ret(v.new_expr("{arguments[0]} & {arguments[1]}", ret.as(not null)))
                                return true
@@ -2641,9 +2629,6 @@ redef class AMethPropdef
                        else if pname == "unary ~" then
                                v.ret(v.new_expr("~{arguments[0]}", ret.as(not null)))
                                return true
-                       else if pname == "ascii" then
-                               v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
-                               return true
                        end
                else if cname == "UInt16" then
                        if pname == "output" then
@@ -2731,9 +2716,6 @@ redef class AMethPropdef
                        else if pname == "unary ~" then
                                v.ret(v.new_expr("~{arguments[0]}", ret.as(not null)))
                                return true
-                       else if pname == "ascii" then
-                               v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
-                               return true
                        end
                else if cname == "Int32" then
                        if pname == "output" then
@@ -2821,9 +2803,6 @@ redef class AMethPropdef
                        else if pname == "unary ~" then
                                v.ret(v.new_expr("~{arguments[0]}", ret.as(not null)))
                                return true
-                       else if pname == "ascii" then
-                               v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
-                               return true
                        end
                else if cname == "UInt32" then
                        if pname == "output" then
@@ -2911,9 +2890,6 @@ redef class AMethPropdef
                        else if pname == "unary ~" then
                                v.ret(v.new_expr("~{arguments[0]}", ret.as(not null)))
                                return true
-                       else if pname == "ascii" then
-                               v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
-                               return true
                        end
                end
                if pname == "exit" then
index ff5f3ba..00f3f00 100644 (file)
@@ -998,10 +998,13 @@ class SeparateCompiler
                        # use some Huffman coding.
                        if t.name == "Int" then
                                class_info[1] = t
+                               t.mclass_type.tag_value = 1
                        else if t.name == "Char" then
                                class_info[2] = t
+                               t.mclass_type.tag_value = 2
                        else if t.name == "Bool" then
                                class_info[3] = t
+                               t.mclass_type.tag_value = 3
                        else
                                continue
                        end
@@ -1858,7 +1861,7 @@ class SeparateCompilerVisitor
                        else
                                var mtype1 = value1.mtype.as(MClassType)
                                self.require_declaration("class_{mtype1.c_name}")
-                               self.add("{res} = ({value2} != NULL) && ({value2}->class == &class_{mtype1.c_name}); /* is_same_type_test */")
+                               self.add("{res} = ({value2} != NULL) && ({class_info(value2)} == &class_{mtype1.c_name}); /* is_same_type_test */")
                        end
                else
                        self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {class_info(value1)} == {class_info(value2)}); /* is_same_type_test */")
@@ -1891,20 +1894,58 @@ class SeparateCompilerVisitor
                        value2 = tmp
                end
                if value1.mtype.is_c_primitive then
-                       if value2.mtype == value1.mtype then
+                       var t1 = value1.mtype
+                       assert t1 == value1.mcasttype
+
+                       # Fast case: same C type.
+                       if value2.mtype == t1 then
+                               # Same exact C primitive representation.
                                self.add("{res} = {value1} == {value2};")
-                       else if value2.mtype.is_c_primitive then
-                               self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
-                       else if value1.mtype.is_tagged then
-                               self.add("{res} = ({value2} != NULL) && ({self.autobox(value2, value1.mtype)} == {value1});")
+                               return res
+                       end
+
+                       # Complex case: value2 has a different representation
+                       # Thus, it should be checked if `value2` is type-compatible with `value1`
+                       # This compatibility is done statically if possible and dynamically else
+
+                       # Conjunction (ands) of dynamic tests according to the static knowledge
+                       var tests = new Array[String]
+
+                       var t2 = value2.mcasttype
+                       if t2 isa MNullableType then
+                               # The destination type cannot be null
+                               tests.add("({value2} != NULL)")
+                               t2 = t2.mtype
+                       else if t2 isa MNullType then
+                               # `value2` is known to be null, thus incompatible with a primitive
+                               self.add("{res} = 0; /* incompatible types {t1} vs. {t2}*/")
+                               return res
+                       end
+
+                       if t2 == t1 then
+                               # Same type but different representation.
+                       else if t2.is_c_primitive then
+                               # Type of `value2` is a different primitive type, thus incompatible
+                               self.add("{res} = 0; /* incompatible types {t1} vs. {t2}*/")
+                               return res
+                       else if t1.is_tagged then
+                               # To be equal, `value2` should also be correctly tagged
+                               tests.add("({extract_tag(value2)} == {t1.tag_value})")
                        else
-                               var mtype1 = value1.mtype.as(MClassType)
-                               self.require_declaration("class_{mtype1.c_name}")
-                               self.add("{res} = ({value2} != NULL) && ({value2}->class == &class_{mtype1.c_name});")
-                               self.add("if ({res}) \{")
-                               self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
-                               self.add("\}")
+                               # To be equal, `value2` should also be boxed with the same class
+                               self.require_declaration("class_{t1.c_name}")
+                               tests.add "({class_info(value2)} == &class_{t1.c_name})"
                        end
+
+                       # Compare the unboxed `value2` with `value1`
+                       if tests.not_empty then
+                               self.add "if ({tests.join(" && ")}) \{"
+                       end
+                       self.add "{res} = {self.autobox(value2, t1)} == {value1};"
+                       if tests.not_empty then
+                               self.add "\} else {res} = 0;"
+                       end
+
                        return res
                end
                var maybe_null = true
@@ -2327,6 +2368,12 @@ redef class MType
        # Are values of `self` tagged?
        # If false, it means that the type is not primitive, or is boxed.
        var is_tagged = false
+
+       # The tag value of the type
+       #
+       # ENSURE `is_tagged == (tag_value > 0)`
+       # ENSURE `not is_tagged == (tag_value == 0)`
+       var tag_value = 0
 end
 
 redef class MEntity
index e4f6bb1..b118019 100644 (file)
@@ -551,8 +551,8 @@ private class Pager
                                b.append("\\\\")
                        else if c == '`' then
                                b.append("'")
-                       else if c.ascii < 32 then
-                               b.append("\\{c.ascii.to_base(8, false)}")
+                       else if c.code_point < 32 then
+                               b.append("\\{c.code_point.to_base(8, false)}")
                        else
                                b.add(c)
                        end
index b484f15..da7b288 100644 (file)
@@ -972,8 +972,6 @@ redef class AMethPropdef
                                return v.bool_instance(recvval >= args[1].to_i)
                        else if pname == "<=>" then
                                return v.int_instance(recvval <=> args[1].to_i)
-                       else if pname == "ascii" then
-                               return v.char_instance(recvval.ascii)
                        else if pname == "to_f" then
                                return v.float_instance(recvval.to_f)
                        else if pname == "to_b" then
@@ -1045,9 +1043,7 @@ redef class AMethPropdef
                        end
                else if cname == "Char" then
                        var recv = args[0].val.as(Char)
-                       if pname == "ascii" then
-                               return v.int_instance(recv.ascii)
-                       else if pname == "successor" then
+                       if pname == "successor" then
                                return v.char_instance(recv.successor(args[1].to_i))
                        else if pname == "predecessor" then
                                return v.char_instance(recv.predecessor(args[1].to_i))
index 786ffc2..0c5b55d 100644 (file)
@@ -246,7 +246,7 @@ class Location
        # * `"0;32"` for green
        fun colored_line(color: String): String
        do
-               var esc = 27.ascii
+               var esc = 27.code_point
                var def = "{esc}[0m"
                var col = "{esc}[{color}m"
 
index 94810af..e061613 100644 (file)
@@ -173,7 +173,7 @@ class Lexer
                                # This does not corrupt the lexer and works perfectly on any character.
                                #
                                # TL;DR: Java fucked up, need retarded solution to cope for retarded decision
-                               var c = string[sp].ascii
+                               var c = string[sp].code_point
                                if c >= 256 then c = 255
                                sp += 1
 
index 8be85d4..98b746a 100644 (file)
@@ -84,7 +84,7 @@ class Message
        # A colored version of the message including the original source line
        fun to_color_string: String
        do
-               var esc = 27.ascii
+               var esc = 27.code_point
                #var red = "{esc}[0;31m"
                #var bred = "{esc}[1;31m"
                #var green = "{esc}[0;32m"
diff --git a/tests/base_eq_int4.nit b/tests/base_eq_int4.nit
new file mode 100644 (file)
index 0000000..60144b2
--- /dev/null
@@ -0,0 +1,196 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+var i = 1
+var b = true
+var f = 1u8
+var ni: nullable Int = 1
+var nb: nullable Bool = true
+var nf: nullable Byte = 1u8
+var oi: nullable Object = 1
+var ob: nullable Object = true
+var of: nullable Object = 1u8
+
+
+(i == i).output
+(b == i).output
+(f == i).output
+
+'\n'.output
+
+(i == ni).output
+(b == ni).output
+(f == ni).output
+
+'\n'.output
+
+(i == oi).output
+(b == oi).output
+(f == oi).output
+
+'\n'.output
+'\n'.output
+
+(ni == i).output
+(nb == i).output
+(nf == i).output
+
+'\n'.output
+
+(ni == ni).output
+(nb == ni).output
+(nf == ni).output
+
+'\n'.output
+
+(ni == oi).output
+(nb == oi).output
+(nf == oi).output
+
+'\n'.output
+'\n'.output
+
+(oi == i).output
+(ob == i).output
+(of == i).output
+
+'\n'.output
+
+(oi == ni).output
+(ob == ni).output
+(of == ni).output
+
+'\n'.output
+
+(oi == oi).output
+(ob == oi).output
+(of == oi).output
+
+'\n'.output
+'\n'.output
+'\n'.output
+
+(i == b).output
+(b == b).output
+(f == b).output
+
+'\n'.output
+
+(i == nb).output
+(b == nb).output
+(f == nb).output
+
+'\n'.output
+
+(i == ob).output
+(b == ob).output
+(f == ob).output
+
+'\n'.output
+'\n'.output
+
+(ni == b).output
+(nb == b).output
+(nf == b).output
+
+'\n'.output
+
+(ni == nb).output
+(nb == nb).output
+(nf == nb).output
+
+'\n'.output
+
+(ni == ob).output
+(nb == ob).output
+(nf == ob).output
+
+'\n'.output
+'\n'.output
+
+(oi == b).output
+(ob == b).output
+(of == b).output
+
+'\n'.output
+
+(oi == nb).output
+(ob == nb).output
+(of == nb).output
+
+'\n'.output
+
+(oi == ob).output
+(ob == ob).output
+(of == ob).output
+
+'\n'.output
+'\n'.output
+'\n'.output
+
+(i == f).output
+(b == f).output
+(f == f).output
+
+'\n'.output
+
+(i == nf).output
+(b == nf).output
+(f == nf).output
+
+'\n'.output
+
+(i == of).output
+(b == of).output
+(f == of).output
+
+'\n'.output
+'\n'.output
+
+(ni == f).output
+(nb == f).output
+(nf == f).output
+
+'\n'.output
+
+(ni == nf).output
+(nb == nf).output
+(nf == nf).output
+
+'\n'.output
+
+(ni == of).output
+(nb == of).output
+(nf == of).output
+
+'\n'.output
+'\n'.output
+
+(oi == f).output
+(ob == f).output
+(of == f).output
+
+'\n'.output
+
+(oi == nf).output
+(ob == nf).output
+(of == nf).output
+
+'\n'.output
+
+(oi == of).output
+(ob == of).output
+(of == of).output
diff --git a/tests/base_eq_int4b.nit b/tests/base_eq_int4b.nit
new file mode 100644 (file)
index 0000000..fea2020
--- /dev/null
@@ -0,0 +1,196 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+var i = 1
+var b = true
+var f = 1u8
+var ni: nullable Int = 1
+var nb: nullable Bool = true
+var nf: nullable Byte = 1u8
+var oi: nullable Object = 1
+var ob: nullable Object = true
+var of: nullable Object = 1u8
+
+
+(i.is_same_instance(i)).output
+(b.is_same_instance(i)).output
+(f.is_same_instance(i)).output
+
+'\n'.output
+
+(i.is_same_instance(ni)).output
+(b.is_same_instance(ni)).output
+(f.is_same_instance(ni)).output
+
+'\n'.output
+
+(i.is_same_instance(oi)).output
+(b.is_same_instance(oi)).output
+(f.is_same_instance(oi)).output
+
+'\n'.output
+'\n'.output
+
+(ni.is_same_instance(i)).output
+(nb.is_same_instance(i)).output
+(nf.is_same_instance(i)).output
+
+'\n'.output
+
+(ni.is_same_instance(ni)).output
+(nb.is_same_instance(ni)).output
+(nf.is_same_instance(ni)).output
+
+'\n'.output
+
+(ni.is_same_instance(oi)).output
+(nb.is_same_instance(oi)).output
+(nf.is_same_instance(oi)).output
+
+'\n'.output
+'\n'.output
+
+(oi.is_same_instance(i)).output
+(ob.is_same_instance(i)).output
+(of.is_same_instance(i)).output
+
+'\n'.output
+
+(oi.is_same_instance(ni)).output
+(ob.is_same_instance(ni)).output
+(of.is_same_instance(ni)).output
+
+'\n'.output
+
+(oi.is_same_instance(oi)).output
+(ob.is_same_instance(oi)).output
+(of.is_same_instance(oi)).output
+
+'\n'.output
+'\n'.output
+'\n'.output
+
+(i.is_same_instance(b)).output
+(b.is_same_instance(b)).output
+(f.is_same_instance(b)).output
+
+'\n'.output
+
+(i.is_same_instance(nb)).output
+(b.is_same_instance(nb)).output
+(f.is_same_instance(nb)).output
+
+'\n'.output
+
+(i.is_same_instance(ob)).output
+(b.is_same_instance(ob)).output
+(f.is_same_instance(ob)).output
+
+'\n'.output
+'\n'.output
+
+(ni.is_same_instance(b)).output
+(nb.is_same_instance(b)).output
+(nf.is_same_instance(b)).output
+
+'\n'.output
+
+(ni.is_same_instance(nb)).output
+(nb.is_same_instance(nb)).output
+(nf.is_same_instance(nb)).output
+
+'\n'.output
+
+(ni.is_same_instance(ob)).output
+(nb.is_same_instance(ob)).output
+(nf.is_same_instance(ob)).output
+
+'\n'.output
+'\n'.output
+
+(oi.is_same_instance(b)).output
+(ob.is_same_instance(b)).output
+(of.is_same_instance(b)).output
+
+'\n'.output
+
+(oi.is_same_instance(nb)).output
+(ob.is_same_instance(nb)).output
+(of.is_same_instance(nb)).output
+
+'\n'.output
+
+(oi.is_same_instance(ob)).output
+(ob.is_same_instance(ob)).output
+(of.is_same_instance(ob)).output
+
+'\n'.output
+'\n'.output
+'\n'.output
+
+(i.is_same_instance(f)).output
+(b.is_same_instance(f)).output
+(f.is_same_instance(f)).output
+
+'\n'.output
+
+(i.is_same_instance(nf)).output
+(b.is_same_instance(nf)).output
+(f.is_same_instance(nf)).output
+
+'\n'.output
+
+(i.is_same_instance(of)).output
+(b.is_same_instance(of)).output
+(f.is_same_instance(of)).output
+
+'\n'.output
+'\n'.output
+
+(ni.is_same_instance(f)).output
+(nb.is_same_instance(f)).output
+(nf.is_same_instance(f)).output
+
+'\n'.output
+
+(ni.is_same_instance(nf)).output
+(nb.is_same_instance(nf)).output
+(nf.is_same_instance(nf)).output
+
+'\n'.output
+
+(ni.is_same_instance(of)).output
+(nb.is_same_instance(of)).output
+(nf.is_same_instance(of)).output
+
+'\n'.output
+'\n'.output
+
+(oi.is_same_instance(f)).output
+(ob.is_same_instance(f)).output
+(of.is_same_instance(f)).output
+
+'\n'.output
+
+(oi.is_same_instance(nf)).output
+(ob.is_same_instance(nf)).output
+(of.is_same_instance(nf)).output
+
+'\n'.output
+
+(oi.is_same_instance(of)).output
+(ob.is_same_instance(of)).output
+(of.is_same_instance(of)).output
diff --git a/tests/base_eq_int4c.nit b/tests/base_eq_int4c.nit
new file mode 100644 (file)
index 0000000..89e2882
--- /dev/null
@@ -0,0 +1,196 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+var i = 1
+var b = true
+var f = 1u8
+var ni: Int = 0
+var nb: Bool = false
+var nf: Byte = 0u8
+var oi: Object = 1
+var ob: Object = true
+var of: Object = 1u8
+
+
+(i.is_same_type(i)).output
+(b.is_same_type(i)).output
+(f.is_same_type(i)).output
+
+'\n'.output
+
+(i.is_same_type(ni)).output
+(b.is_same_type(ni)).output
+(f.is_same_type(ni)).output
+
+'\n'.output
+
+(i.is_same_type(oi)).output
+(b.is_same_type(oi)).output
+(f.is_same_type(oi)).output
+
+'\n'.output
+'\n'.output
+
+(ni.is_same_type(i)).output
+(nb.is_same_type(i)).output
+(nf.is_same_type(i)).output
+
+'\n'.output
+
+(ni.is_same_type(ni)).output
+(nb.is_same_type(ni)).output
+(nf.is_same_type(ni)).output
+
+'\n'.output
+
+(ni.is_same_type(oi)).output
+(nb.is_same_type(oi)).output
+(nf.is_same_type(oi)).output
+
+'\n'.output
+'\n'.output
+
+(oi.is_same_type(i)).output
+(ob.is_same_type(i)).output
+(of.is_same_type(i)).output
+
+'\n'.output
+
+(oi.is_same_type(ni)).output
+(ob.is_same_type(ni)).output
+(of.is_same_type(ni)).output
+
+'\n'.output
+
+(oi.is_same_type(oi)).output
+(ob.is_same_type(oi)).output
+(of.is_same_type(oi)).output
+
+'\n'.output
+'\n'.output
+'\n'.output
+
+(i.is_same_type(b)).output
+(b.is_same_type(b)).output
+(f.is_same_type(b)).output
+
+'\n'.output
+
+(i.is_same_type(nb)).output
+(b.is_same_type(nb)).output
+(f.is_same_type(nb)).output
+
+'\n'.output
+
+(i.is_same_type(ob)).output
+(b.is_same_type(ob)).output
+(f.is_same_type(ob)).output
+
+'\n'.output
+'\n'.output
+
+(ni.is_same_type(b)).output
+(nb.is_same_type(b)).output
+(nf.is_same_type(b)).output
+
+'\n'.output
+
+(ni.is_same_type(nb)).output
+(nb.is_same_type(nb)).output
+(nf.is_same_type(nb)).output
+
+'\n'.output
+
+(ni.is_same_type(ob)).output
+(nb.is_same_type(ob)).output
+(nf.is_same_type(ob)).output
+
+'\n'.output
+'\n'.output
+
+(oi.is_same_type(b)).output
+(ob.is_same_type(b)).output
+(of.is_same_type(b)).output
+
+'\n'.output
+
+(oi.is_same_type(nb)).output
+(ob.is_same_type(nb)).output
+(of.is_same_type(nb)).output
+
+'\n'.output
+
+(oi.is_same_type(ob)).output
+(ob.is_same_type(ob)).output
+(of.is_same_type(ob)).output
+
+'\n'.output
+'\n'.output
+'\n'.output
+
+(i.is_same_type(f)).output
+(b.is_same_type(f)).output
+(f.is_same_type(f)).output
+
+'\n'.output
+
+(i.is_same_type(nf)).output
+(b.is_same_type(nf)).output
+(f.is_same_type(nf)).output
+
+'\n'.output
+
+(i.is_same_type(of)).output
+(b.is_same_type(of)).output
+(f.is_same_type(of)).output
+
+'\n'.output
+'\n'.output
+
+(ni.is_same_type(f)).output
+(nb.is_same_type(f)).output
+(nf.is_same_type(f)).output
+
+'\n'.output
+
+(ni.is_same_type(nf)).output
+(nb.is_same_type(nf)).output
+(nf.is_same_type(nf)).output
+
+'\n'.output
+
+(ni.is_same_type(of)).output
+(nb.is_same_type(of)).output
+(nf.is_same_type(of)).output
+
+'\n'.output
+'\n'.output
+
+(oi.is_same_type(f)).output
+(ob.is_same_type(f)).output
+(of.is_same_type(f)).output
+
+'\n'.output
+
+(oi.is_same_type(nf)).output
+(ob.is_same_type(nf)).output
+(of.is_same_type(nf)).output
+
+'\n'.output
+
+(oi.is_same_type(of)).output
+(ob.is_same_type(of)).output
+(of.is_same_type(of)).output
index 2ba5388..130d8fd 100644 (file)
@@ -49,7 +49,7 @@ class A
                o = _c
                (o == null).output
                (not o == '\0').output
-               #alt3#_c.ascii.output
+               #alt3#_c.code_point.output
        end
 end
 
diff --git a/tests/sav/base_eq_int4.res b/tests/sav/base_eq_int4.res
new file mode 100644 (file)
index 0000000..cf1d59c
--- /dev/null
@@ -0,0 +1,117 @@
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
diff --git a/tests/sav/base_eq_int4b.res b/tests/sav/base_eq_int4b.res
new file mode 100644 (file)
index 0000000..cf1d59c
--- /dev/null
@@ -0,0 +1,117 @@
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
diff --git a/tests/sav/base_eq_int4c.res b/tests/sav/base_eq_int4c.res
new file mode 100644 (file)
index 0000000..cf1d59c
--- /dev/null
@@ -0,0 +1,117 @@
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
index b41f1d6..3d8ae36 100644 (file)
@@ -6,7 +6,7 @@
 ../lib/core/kernel.nit:431,1--486,3: Error: `kernel#Numeric` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
 ../lib/core/kernel.nit:492,1--515,3: Error: `kernel#Bool` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
 ../lib/core/kernel.nit:517,1--599,3: Error: `kernel#Float` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/core/kernel.nit:601,1--697,3: Error: `kernel#Byte` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/core/kernel.nit:699,1--884,3: Error: `kernel#Int` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/core/kernel.nit:886,1--1039,3: Error: `kernel#Char` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/core/kernel.nit:1041,1--1048,3: Error: `kernel#Pointer` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/core/kernel.nit:601,1--702,3: Error: `kernel#Byte` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/core/kernel.nit:704,1--890,3: Error: `kernel#Int` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/core/kernel.nit:892,1--1060,3: Error: `kernel#Char` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/core/kernel.nit:1062,1--1069,3: Error: `kernel#Pointer` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
index 8e5869f..d556892 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/core/kernel.nit:720)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/core/kernel.nit:725)
 11
 21
 31
index 8e5869f..d556892 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/core/kernel.nit:720)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/core/kernel.nit:725)
 11
 21
 31
index 8e5869f..d556892 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/core/kernel.nit:720)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/core/kernel.nit:725)
 11
 21
 31
index 6584bce..700f951 100644 (file)
@@ -51,19 +51,19 @@ Float [
 Numeric -> Float [dir=back arrowtail=open style=dashed];
 
 Byte [
- label = "{Byte||+ %(i: Byte): Byte\l+ \<\<(i: Int): Byte\l+ \>\>(i: Int): Byte\l}"
+ label = "{Byte||+ %(i: Byte): Byte\l+ \<\<(i: Int): Byte\l+ \>\>(i: Int): Byte\l+ ascii(): Char\l}"
 ]
 Discrete -> Byte [dir=back arrowtail=open style=dashed];
 Numeric -> Byte [dir=back arrowtail=open style=dashed];
 
 Int [
- label = "{Int||+ %(i: Int): Int\l+ \<\<(i: Int): Int\l+ \>\>(i: Int): Int\l+ ascii(): Char\l+ digit_count(b: Int): Int\l+ digit_count_base_10(): Int\l+ to_c(): Char\l+ abs(): Int\l}"
+ label = "{Int||+ %(i: Int): Int\l+ \<\<(i: Int): Int\l+ \>\>(i: Int): Int\l+ code_point(): Char\l+ digit_count(b: Int): Int\l+ digit_count_base_10(): Int\l+ to_c(): Char\l+ abs(): Int\l}"
 ]
 Discrete -> Int [dir=back arrowtail=open style=dashed];
 Numeric -> Int [dir=back arrowtail=open style=dashed];
 
 Char [
- label = "{Char||+ to_i(): Int\l+ ascii(): Int\l+ to_lower(): Char\l+ to_upper(): Char\l+ is_digit(): Bool\l+ is_lower(): Bool\l+ is_upper(): Bool\l+ is_letter(): Bool\l+ is_whitespace(): Bool\l}"
+ label = "{Char||+ to_i(): Int\l+ ascii(): Byte\l+ code_point(): Int\l+ is_ascii(): Bool\l+ to_lower(): Char\l+ to_upper(): Char\l+ is_digit(): Bool\l+ is_lower(): Bool\l+ is_upper(): Bool\l+ is_letter(): Bool\l+ is_whitespace(): Bool\l}"
 ]
 Discrete -> Char [dir=back arrowtail=open style=dashed];
 
index 90afcec..f01534c 100644 (file)
@@ -51,19 +51,19 @@ Float [
 Numeric -> Float [dir=back arrowtail=open style=dashed];
 
 Byte [
- label = "{Byte||+ %(i: Byte): Byte\l+ \<\<(i: Int): Byte\l+ \>\>(i: Int): Byte\l}"
+ label = "{Byte||+ %(i: Byte): Byte\l+ \<\<(i: Int): Byte\l+ \>\>(i: Int): Byte\l+ ascii(): Char\l}"
 ]
 Discrete -> Byte [dir=back arrowtail=open style=dashed];
 Numeric -> Byte [dir=back arrowtail=open style=dashed];
 
 Int [
- label = "{Int||+ %(i: Int): Int\l+ \<\<(i: Int): Int\l+ \>\>(i: Int): Int\l+ ascii(): Char\l+ digit_count(b: Int): Int\l+ digit_count_base_10(): Int\l+ to_c(): Char\l+ abs(): Int\l}"
+ label = "{Int||+ %(i: Int): Int\l+ \<\<(i: Int): Int\l+ \>\>(i: Int): Int\l+ code_point(): Char\l+ digit_count(b: Int): Int\l+ digit_count_base_10(): Int\l+ to_c(): Char\l+ abs(): Int\l}"
 ]
 Discrete -> Int [dir=back arrowtail=open style=dashed];
 Numeric -> Int [dir=back arrowtail=open style=dashed];
 
 Char [
- label = "{Char||+ to_i(): Int\l+ ascii(): Int\l+ to_lower(): Char\l+ to_upper(): Char\l+ is_digit(): Bool\l+ is_lower(): Bool\l+ is_upper(): Bool\l+ is_letter(): Bool\l+ is_whitespace(): Bool\l}"
+ label = "{Char||+ to_i(): Int\l+ ascii(): Byte\l+ code_point(): Int\l+ is_ascii(): Bool\l+ to_lower(): Char\l+ to_upper(): Char\l+ is_digit(): Bool\l+ is_lower(): Bool\l+ is_upper(): Bool\l+ is_letter(): Bool\l+ is_whitespace(): Bool\l}"
 ]
 Discrete -> Char [dir=back arrowtail=open style=dashed];
 
index 9dee4a7..4b09f4d 100644 (file)
@@ -17,5 +17,5 @@
 var a = "éè"
 print(a.length)
 for i in [0..a.length[ do
-       print("{i} is {a.chars[i]} ({a.chars[i].ascii})")
+       print("{i} is {a.chars[i]} ({a.chars[i].code_point})")
 end
index de412ac..3739f9c 100644 (file)
@@ -16,5 +16,5 @@ intrude import core::text::flat
 import core
 
 var s = "𐏓􏿿".as(FlatString)
-print s.items.char_at(0).ascii.to_hex
-print s.items.char_at(4).ascii.to_hex
+print s.items.char_at(0).code_point.to_hex
+print s.items.char_at(4).code_point.to_hex