Merge: glesv2: services for textures, shaders, framebuffers, renderbuffers & more...
authorJean Privat <jean@pryen.org>
Mon, 28 Sep 2015 14:37:02 +0000 (10:37 -0400)
committerJean Privat <jean@pryen.org>
Mon, 28 Sep 2015 14:37:02 +0000 (10:37 -0400)
Intro wrappers to work with textures, shaders, framebuffers and renderbuffers, synchronize with server and set clear values of buffers. Update most of the remaining enumerations and some more services to the new API style. Add a makefile to generate a wrapper stub from the local GLES2/gl2.h header file.

FYI, there's approximatly only 65 functions left to wrap, out of 141.

Pull-Request: #1743
Reviewed-by: Jean Privat <jean@pryen.org>

93 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/mnit_test/package.ini
contrib/nitcc/src/autom.nit
contrib/nitcc/src/nitcc_semantic.nit
contrib/nitcc/src/re2nfa.nit
contrib/nitcc/tests/packages.ini [moved from contrib/nitcc/tests/package.ini with 100% similarity]
contrib/pep8analysis/src/location.nit
contrib/pep8analysis/src/model/operands.nit
contrib/pep8analysis/src/parser/lexer.nit
examples/draw_operation.ini
examples/mnit_ballz/org.nitlanguage.ballz.txt [moved from examples/mnit_ballz/org.nitlanguage.ballz_android.txt with 100% similarity]
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/collection/abstract_collection.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/gen_nit.ini [new file with mode: 0644]
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/ordered_tree.nit
lib/saxophonit/lexer.nit
lib/saxophonit/saxophonit.nit
lib/text_stat.ini [new file with mode: 0644]
misc/vim/syntax/nit.vim
src/compiler/abstract_compiler.nit
src/compiler/separate_compiler.nit
src/doc/doc_phases/doc_console.nit
src/interpreter/naive_interpreter.nit
src/loader.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/nitls_args1.res
tests/sav/nitls_args2.res
tests/sav/nitls_args4.res
tests/sav/nituml_args3.res
tests/sav/nituml_args4.res
tests/sav/test_with.res [new file with mode: 0644]
tests/test_string_unicode.nit
tests/test_unicode_4bytes.nit
tests/test_with.nit [new file with mode: 0644]

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..ac91a73
--- /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..77756da
--- /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..9a79f36
--- /dev/null
@@ -0,0 +1,12 @@
+[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
+apk=http://nitlanguage.org/fdroid/apk/memory.apk
diff --git a/contrib/memory/src/memory.nit b/contrib/memory/src/memory.nit
new file mode 100644 (file)
index 0000000..e184b99
--- /dev/null
@@ -0,0 +1,1001 @@
+# 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_namespace "org.nitlanguage.memory"
+       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 adcdf8f..5247640 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name=mnit_test
-tags=
+tags=testing
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
 license=Apache-2.0
 [upstream]
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 189e88d..4ae4096 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name=draw_operation
-tags=
+tags=example
 maintainer=Alexis Laferrière <alexis.laf@xymus.net>
 license=Apache-2.0
 [upstream]
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 5192797..aca4fdc 100644 (file)
@@ -228,6 +228,16 @@ interface Iterator[E]
        # Iterate over `self`
        fun iterator: Iterator[E] do return self
 
+       # Pre-iteration hook.
+       #
+       # Used to inform `self` that the iteration is starting.
+       # Specific iterators can use this to prepare some resources.
+       #
+       # Is automatically invoked at the beginning of `for` structures.
+       #
+       # Do nothing by default.
+       fun start do end
+
        # Post-iteration hook.
        #
        # Used to inform `self` that the iteration is over.
@@ -708,6 +718,16 @@ interface MapIterator[K, V]
        # Set a new `item` at `key`.
        #fun item=(item: E) is abstract
 
+       # Pre-iteration hook.
+       #
+       # Used to inform `self` that the iteration is starting.
+       # Specific iterators can use this to prepare some resources.
+       #
+       # Is automatically invoked at the beginning of `for` structures.
+       #
+       # Do nothing by default.
+       fun start do end
+
        # Post-iteration hook.
        #
        # Used to inform `self` that the iteration is over.
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..e8cb232 100644 (file)
@@ -39,6 +39,26 @@ abstract class Stream
 
        # close the stream
        fun close is abstract
+
+       # Pre-work hook.
+       #
+       # Used to inform `self` that operations will start.
+       # Specific streams can use this to prepare some resources.
+       #
+       # Is automatically invoked at the beginning of `with` structures.
+       #
+       # Do nothing by default.
+       fun start do end
+
+       # Post-work hook.
+       #
+       # Used to inform `self` that the operations are over.
+       # Specific streams can use this to free some resources.
+       #
+       # Is automatically invoked at the end of `woth` structures.
+       #
+       # call `close` by default.
+       fun finish do close
 end
 
 # A `Stream` that can be read from
@@ -275,7 +295,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 == ""
        # ~~~
@@ -425,6 +445,13 @@ interface Writable
        end
 end
 
+redef class Bytes
+       super Writable
+       redef fun write_to(s) do s.write_bytes(self)
+
+       redef fun write_to_string do return to_s
+end
+
 redef class Text
        super Writable
        redef fun write_to(stream) do stream.write(self)
@@ -441,7 +468,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/gen_nit.ini b/lib/gen_nit.ini
new file mode 100644 (file)
index 0000000..0f1530c
--- /dev/null
@@ -0,0 +1,11 @@
+[package]
+name=gen_nit
+tags=devel
+maintainer=Alexis Laferrière <alexis.laf@xymus.net>
+license=Apache-2.0
+[upstream]
+browse=https://github.com/nitlang/nit/tree/master/lib/gen_nit.nit
+git=https://github.com/nitlang/nit.git
+git.directory=lib/gen_nit.nit
+homepage=http://nitlanguage.org
+issues=https://github.com/nitlang/nit/issues
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 2a6a10c..d1dde15 100644 (file)
@@ -61,6 +61,7 @@ module ordered_tree
 class OrderedTree[E: Object]
        super Writable
        super Collection[E]
+       super Cloneable
 
        # The roots of the tree (in sequence)
        var roots = new Array[E]
@@ -69,17 +70,75 @@ class OrderedTree[E: Object]
        # For each element, the ordered array of its direct sub-elements.
        var sub = new HashMap[E, Array[E]]
 
+       # The parent of each element.
+       #
+       # Roots have `null` as parent.
+       private var parents = new HashMap[E, nullable E]
+
+       redef fun length do return parents.length
+
+       redef fun has(e) do return parents.has_key(e)
+
+       # The parent of the element `e`
+       #
+       # Roots have `null` as parent.
+       #
+       # ~~~
+       # var tree = new OrderedTree[Int]
+       # tree.add(1, 2)
+       # assert tree.parent(2) == 1
+       # assert tree.parent(1) == null
+       # ~~~
+       fun parent(e: E): nullable E do return parents[e]
+
        # Add a new element `e` in the tree.
+       #
        # `p` is the parent of `e`.
-       # if `p` is null, then `e` is a root element.
+       # If `p` is null, then `e` is a root element.
+       #
+       # If `e` is already in the tree, it is detached from its old
+       # parent and attached to the new parent `p`.
        fun add(p: nullable E, e: E)
        do
+               detach(e)
+               parents[e] = p
                if p == null then
                        roots.add(e)
-               else if sub.has_key(p) then
-                       sub[p].add(e)
                else
-                       sub[p] = [e]
+                       if not has(p) then add(null, p)
+                       if sub.has_key(p) then
+                               sub[p].add(e)
+                       else
+                               sub[p] = [e]
+                       end
+               end
+       end
+
+       # Append all nodes `es` as children of `p`.
+       fun add_all(p: nullable E, es: Collection[E])
+       do
+               for e in es do add(p, e)
+       end
+
+       # Temporary remove `e`.
+       #
+       # Children of `e` are left untouched in the tree.
+       # This make the tree inconstant until `e` is added back.
+       private fun detach(e: E)
+       do
+               var old_parent = parents.get_or_null(e)
+               if old_parent != null then
+                       var subs = sub[old_parent]
+                       subs.remove(e)
+                       if subs.is_empty then
+                               # remove the sub when all children are detached
+                               # so that `==` and `hash` are sane
+                               # Otherwise an empty array will be considered
+                               # differently than no array.
+                               sub.keys.remove(old_parent)
+                       end
+               else if roots.has(e) then
+                       roots.remove(e)
                end
        end
 
@@ -98,6 +157,7 @@ class OrderedTree[E: Object]
        do
                if not sub.has_key(e) then return
                var subs = sub[e]
+               if subs.is_empty then return
                var last = subs.last
                for e2 in subs do
                        if e2 != last then
@@ -130,16 +190,11 @@ class OrderedTree[E: Object]
        # Order is preserved
        #
        #     var tree = new OrderedTree[Int]
-       #     tree.add(null, 1)
-       #     tree.add(1, 11)
-       #     tree.add(11, 111)
-       #     tree.add(11, 112)
-       #     tree.add(1, 12)
-       #     tree.add(12, 121)
-       #     tree.add(12, 122)
-       #     tree.add(null, 2)
-       #     tree.add(2, 21)
-       #     tree.add(2, 22)
+       #     tree.add_all(null, [1, 2])
+       #     tree.add_all(1, [11, 12])
+       #     tree.add_all(11, [111, 112])
+       #     tree.add_all(12, [121, 122])
+       #     tree.add_all(2, [21, 22])
        #     assert tree.to_a == [1, 11, 111, 112, 12, 121, 122, 2, 21, 22]
        redef fun to_a: Array[E] do
                var res = new Array[E]
@@ -165,21 +220,60 @@ class OrderedTree[E: Object]
        redef fun first do return roots.first
 
        #     var tree = new OrderedTree[Int]
-       #     tree.add(null, 1)
-       #     tree.add(1, 11)
-       #     tree.add(11, 111)
-       #     tree.add(11, 112)
-       #     tree.add(1, 12)
-       #     tree.add(12, 121)
-       #     tree.add(12, 122)
-       #     tree.add(null, 2)
-       #     tree.add(2, 21)
-       #     tree.add(2, 22)
+       #     tree.add_all(null, [1, 2])
+       #     tree.add_all(1, [11, 12])
+       #     tree.add_all(11, [111, 112])
+       #     tree.add_all(12, [121, 122])
+       #     tree.add_all(2, [21, 22])
        #     var order = [1, 11, 111, 112, 12, 121, 122, 2, 21, 22]
-       #     var res = new Array[Int]
-       #     for i in tree do res.add(i)
-       #     assert res == order
+       #     assert tree.iterator.to_a == order
        redef fun iterator do return new OrderedTreeIterator[E](self)
+
+       # Two trees are equal if they have the same nodes in the same order
+       #
+       # ~~~
+       # var t1 = new OrderedTree[Int]
+       # t1.add_all(null, [1, 2])
+       # t1.add_all(1, [11, 12])
+       #
+       # var t2 = new OrderedTree[Int]
+       # t2.add_all(null, [1, 2])
+       #
+       # assert t1 != t2
+       #
+       # t2.add_all(1, [11, 12])
+       #
+       # assert t1 == t2
+       # ~~~
+       redef fun ==(other)
+       do
+               if not other isa OrderedTree[Object] then return false
+               return roots == other.roots and sub == other.sub
+       end
+
+       redef fun hash
+       do
+               return roots.hash + sub.hash
+       end
+
+       # Shallow clone of the tree.
+       #
+       # ~~~
+       # var t = new OrderedTree[Int]
+       # t.add_all(null, [1, 2])
+       # t.add_all(1, [11, 12])
+       #
+       # assert t.clone == t
+       # ~~~
+       redef fun clone
+       do
+               var res = new OrderedTree[E]
+               res.add_all(null, roots)
+               for p, es in sub do
+                       res.add_all(p, es)
+               end
+               return res
+       end
 end
 
 # An Iterator over an OrderedTree
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. " +
diff --git a/lib/text_stat.ini b/lib/text_stat.ini
new file mode 100644 (file)
index 0000000..fb0ab2b
--- /dev/null
@@ -0,0 +1,11 @@
+[package]
+name=text_stat
+tags=debug,lib
+maintainer=Lucas Bajolet <r4pass@hotmail.com>
+license=Apache-2.0
+[upstream]
+browse=https://github.com/nitlang/nit/tree/master/lib/text_stat.nit
+git=https://github.com/nitlang/nit.git
+git.directory=lib/text_stat.nit
+homepage=http://nitlanguage.org
+issues=https://github.com/nitlang/nit/issues
index 2930d81..b5d86ac 100644 (file)
@@ -88,7 +88,7 @@ syn match  NITComment "#.*" contains=NITTodo,@Spell
 " Keywords
 syn keyword NITKeyword  abstract intern new
 syn keyword NITDefine   private public protected intrude readable writable redef
-syn keyword NITControl   if while for assert and or in as isa once break continue return abort
+syn keyword NITControl   if while for with assert and or in as isa once break continue return abort
 syn keyword NITClass     nullable
 syn keyword NITInclude   special
 syn keyword NITTodo      FIXME NOTE TODO XXX contained
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 a59ccf0..a914b56 100644 (file)
@@ -323,7 +323,7 @@ redef class ModelBuilder
        fun identify_file(path: String): nullable ModulePath
        do
                # special case for not a nit file
-               if path.file_extension != "nit" then
+               if not path.has_suffix(".nit") then
                        # search dirless files in known -I paths
                        if not path.chars.has('/') then
                                var res = search_module_in_paths(null, path, self.paths)
@@ -352,10 +352,12 @@ redef class ModelBuilder
                end
 
                # Fast track, the path is already known
-               var pn = path.basename(".nit")
+               if identified_files_by_path.has_key(path) then return identified_files_by_path[path]
                var rp = module_absolute_path(path)
                if identified_files_by_path.has_key(rp) then return identified_files_by_path[rp]
 
+               var pn = path.basename(".nit")
+
                # Search for a group
                var mgrouppath = path.join_path("..").simplify_path
                var mgroup = get_mgroup(mgrouppath)
@@ -380,6 +382,7 @@ redef class ModelBuilder
                mgroup.module_paths.add(res)
 
                identified_files_by_path[rp] = res
+               identified_files_by_path[path] = res
                identified_files.add(res)
                return res
        end
@@ -393,10 +396,15 @@ redef class ModelBuilder
        # Note: `paths` is also used to look for mgroups
        fun get_mgroup(dirpath: String): nullable MGroup
        do
-               if not dirpath.file_exists then do
+               var stat = dirpath.file_stat
+
+               if stat == null then do
+                       # search dirless directories in known -I paths
+                       if dirpath.chars.has('/') then return null
                        for p in paths do
                                var try = p / dirpath
-                               if try.file_exists then
+                               stat = try.file_stat
+                               if stat != null then
                                        dirpath = try
                                        break label
                                end
@@ -404,20 +412,19 @@ redef class ModelBuilder
                        return null
                end label
 
+               # Filter out non-directories
+               if not stat.is_dir then
+                       return null
+               end
+
+               # Fast track, the path is already known
                var rdp = module_absolute_path(dirpath)
                if mgroups.has_key(rdp) then
                        return mgroups[rdp]
                end
 
-               # Filter out non-directories
-               var stat = dirpath.file_stat
-               if stat == null or not stat.is_dir then
-                       mgroups[rdp] = null
-                       return null
-               end
-
                # By default, the name of the package or group is the base_name of the directory
-               var pn = rdp.basename(".nit")
+               var pn = rdp.basename
 
                # Check `package.ini` that indicate a package
                var ini = null
@@ -525,23 +532,24 @@ redef class ModelBuilder
                        var fp = p/f
                        var g = get_mgroup(fp)
                        # Recursively scan for groups of the same package
-                       if g != null and g.mpackage == mgroup.mpackage then
+                       if g == null then
+                               identify_file(fp)
+                       else if g.mpackage == mgroup.mpackage then
                                scan_group(g)
                        end
-                       identify_file(fp)
                end
        end
 
        # Transform relative paths (starting with '../') into absolute paths
        private fun module_absolute_path(path: String): String do
-               return getcwd.join_path(path).simplify_path
+               return path.realpath
        end
 
        # Try to load a module AST using a path.
        # Display an error if there is a problem (IO / lexer / parser) and return null
        fun load_module_ast(filename: String): nullable AModule
        do
-               if filename.file_extension != "nit" then
+               if not filename.has_suffix(".nit") then
                        self.toolcontext.error(null, "Error: file `{filename}` is not a valid nit module.")
                        return null
                end
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 19b7801..eca970e 100644 (file)
@@ -10,4 +10,3 @@ project1 (\e[33mproject1\e[m)
 `--subdir (\e[33mproject1/subdir\e[m)
    |--\e[1mmodule4\e[m (\e[33mproject1/subdir/module4.nit\e[m)
    `--\e[1mmodule_0\e[m (\e[33mproject1/subdir/module_0.nit\e[m)
-\e[1mproject2\e[m (\e[33mproject1/project2/project2.nit\e[m)
index 19b7801..eca970e 100644 (file)
@@ -10,4 +10,3 @@ project1 (\e[33mproject1\e[m)
 `--subdir (\e[33mproject1/subdir\e[m)
    |--\e[1mmodule4\e[m (\e[33mproject1/subdir/module4.nit\e[m)
    `--\e[1mmodule_0\e[m (\e[33mproject1/subdir/module_0.nit\e[m)
-\e[1mproject2\e[m (\e[33mproject1/project2/project2.nit\e[m)
index a8b51a5..267bbdb 100644 (file)
@@ -8,4 +8,3 @@ project1/subdir/\e[1mmodule_0\e[m (\e[33mproject1/subdir/module_0.nit\e[m)
 project1/\e[1mmodule_01\e[m (\e[33mproject1/module_01.nit\e[m)
 project1/\e[1mmodule_02\e[m (\e[33mproject1/module_02.nit\e[m)
 project1/\e[1mproject1\e[m (\e[33mproject1/project1.nit\e[m)
-project2/\e[1mproject2\e[m (\e[33mproject1/project2/project2.nit\e[m)
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];
 
diff --git a/tests/sav/test_with.res b/tests/sav/test_with.res
new file mode 100644 (file)
index 0000000..bd8974e
--- /dev/null
@@ -0,0 +1,9 @@
+1
+2
+3
+4
+1
+one
+2
+two
+# Regression test for the Nit project
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
diff --git a/tests/test_with.nit b/tests/test_with.nit
new file mode 100644 (file)
index 0000000..89757d4
--- /dev/null
@@ -0,0 +1,32 @@
+# 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.
+
+var a = [1,2,3,4]
+with i = a.iterator do while i.is_ok do
+       print i.item
+       i.next
+end
+
+var m = new HashMap[Int, String]
+m[1] = "one"
+m[2] = "two"
+with i = m.iterator do while i.is_ok do
+       print i.key
+       print i.item
+       i.next
+end
+
+with f = "README.md".to_path.open_ro do
+       print f.read_line
+end