Merge: make nitunit more colorful (and useful?)
authorJean Privat <jean@pryen.org>
Thu, 26 May 2016 13:06:39 +0000 (09:06 -0400)
committerJean Privat <jean@pryen.org>
Thu, 26 May 2016 13:06:39 +0000 (09:06 -0400)
This series move more information in the UnitTest class, this allow specific and unified way of displaying the test results.

See the asciinema: https://asciinema.org/a/108jd2a3tkfifg3wzoacg0a65

Comments? Needs? Ideas?

Pull-Request: #2121
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

57 files changed:
NOTICE
contrib/friendz/src/friendz.nit
contrib/tinks/src/game/framework.nit
contrib/xymus_net/.gitignore [new file with mode: 0644]
contrib/xymus_net/Makefile [new file with mode: 0644]
contrib/xymus_net/README.md [new file with mode: 0644]
contrib/xymus_net/package.ini [new file with mode: 0644]
contrib/xymus_net/xymus_net.nit [moved from lib/nitcorn/examples/src/xymus_net.nit with 96% similarity]
examples/rosettacode/perlin_noise.nit
lib/a_star.nit
lib/android/input_events.nit
lib/bucketed_game.nit
lib/core/text/abstract_text.nit
lib/core/text/flat.nit
lib/core/text/ropes.nit
lib/crapto/crapto.nit
lib/crapto/examples/repeating_key_xor_cipher.txt [new file with mode: 0644]
lib/crapto/examples/repeating_key_xor_solve.nit [new file with mode: 0644]
lib/crapto/xor.nit [new file with mode: 0644]
lib/crypto/basic_ciphers.nit [moved from lib/crypto.nit with 91% similarity]
lib/crypto/crypto.nit [new file with mode: 0644]
lib/crypto/package.ini [moved from lib/crypto.ini with 89% similarity]
lib/crypto/xor_ciphers.nit [new file with mode: 0644]
lib/gamnit/cameras.nit
lib/gamnit/limit_fps.nit
lib/mnit/mnit_fps.nit
lib/nitcorn/README.md
lib/nitcorn/examples/Makefile
lib/noise.nit
lib/performance_analysis.nit
lib/popcorn/README.md
lib/popcorn/examples/middlewares/example_advanced_logger.nit
lib/popcorn/pop_middlewares.nit
lib/postgresql/native_postgres.nit
lib/postgresql/postgres.nit [new file with mode: 0644]
lib/realtime.nit
lib/serialization/caching.nit
src/interpreter/dynamic_loading_ffi/on_demand_compiler.nit
tests/listfull.sh
tests/niti.skip
tests/nitvm.skip
tests/repeating_key_xor_solve.args [new file with mode: 0644]
tests/sav/repeating_key_xor_solve.res [new file with mode: 0644]
tests/sav/repeating_key_xor_solve_args1.res [new file with mode: 0644]
tests/sav/test_copy_to_native.res [new file with mode: 0644]
tests/sav/test_copy_to_native_alt1.res [new file with mode: 0644]
tests/sav/test_copy_to_native_alt2.res [new file with mode: 0644]
tests/sav/test_nativestring_fill_from.res [new file with mode: 0644]
tests/sav/test_nativestring_fill_from_alt1.res [new file with mode: 0644]
tests/sav/test_nativestring_fill_from_alt2.res [new file with mode: 0644]
tests/sav/test_nativestring_fill_from_alt3.res [new file with mode: 0644]
tests/sav/test_postgres_nity.res [moved from tests/sav/xymus_net.res with 100% similarity]
tests/sav/test_realtime.res [deleted file]
tests/test_copy_to_native.nit [moved from tests/test_realtime.nit with 57% similarity]
tests/test_kill_process.nit
tests/test_nativestring_fill_from.nit [new file with mode: 0644]
tests/test_postgres_nity.nit [new file with mode: 0644]

diff --git a/NOTICE b/NOTICE
index 2e08fad..33a5cff 100644 (file)
--- a/NOTICE
+++ b/NOTICE
@@ -2,39 +2,48 @@ This product includes software developed as part of the Nit Language
 project ( http://nitlanguage.org ).
 
 Files: *
-Copyright: 2004-2015 Jean Privat <jean@pryen.org>
+Copyright: 2004-2016 Jean Privat <jean@pryen.org>
            2006-2008 Floréal Morandat <morandat@lirmm.fr>
            2009      Julien Chevalier <chevjulien@gmail.com>
            2009-2011 Jean-Sebastien Gelinas <calestar@gmail.com>
-           2009-2015 Alexis Laferrière <alexis.laf@xymus.net>
+           2009-2016 Alexis Laferrière <alexis.laf@xymus.net>
            2011      Matthieu Auger <matthieu.auger@gmail.com>
-           2011-2015 Alexandre Terrasa <alexandre@moz-code.org>
+           2011-2016 Alexandre Terrasa <alexandre@moz-code.org>
            2012      Alexandre Pennetier <alexandre.pennetier@me.com>
-           2013-2015 Lucas Bajolet <r4pass@hotmail.com>
+           2013-2016 Lucas Bajolet <r4pass@hotmail.com>
            2013      Stefan Lage <lagestfan@gmail.com>
            2013      Nathan Heu <heu.nathan@courrier.uqam.ca>
            2013      Matthieu Lucas <lucasmatthieu@gmail.com>
-           2014-2015 Romain Chanoir <romain.chanoir@viacesi.fr>
-           2014      Frédéric Vachon <fredvac@gmail.com>
+           2014-2016 Romain Chanoir <romain.chanoir@viacesi.fr>
+           2014-2015 Frédéric Vachon <fredvac@gmail.com>
            2014      Johan Kayser <johan.kayser@viacesi.fr>
            2014-2015 Julien Pagès <julien.projet@gmail.com>
            2014      Geoffrey Hecht <geoffrey.hecht@gmail.com>
-           2014      Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
+           2014-2016 Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
            2015      Arthur Delamare <arthur.delamare@viacesi.fr>
+           2015-2016 Mehdi Ait Younes <overpex@gmail.com>
+           2015      Renata Carvalho <renatawm@gmail.com>
+           2015      Simon Zeni <simonzeni@gmail.com>
+           2015      Anis Boubaker <anis@boubaker.ca>
+           2015      Istvan SZALAI <szalai972@gmail.com>
+           2015      Hervé Matysiak <herve.matysiak@viacesi.fr>
+           2015      Jean-Philippe Caissy <jean-philippe.caissy@shopify.com>
+           2015      Alexandre Blondin Massé <alexandre.blondin.masse@gmail.com>
+           2015-2016 Guilherme Mansur <guilhermerpmansur@gmail.com>
 License: Apache 2.0 (see LICENSE)
 Comment: The main license of the work, except for the following exceptions
 
 Files: lib/*
        clib/*
        share/nitdoc/*
-Copyright: 2004-2015 Jean Privat <jean@pryen.org>
+Copyright: 2004-2016 Jean Privat <jean@pryen.org>
            2006-2008 Floréal Morandat <morandat@lirmm.fr>
            2009-2011 Jean-Sebastien Gelinas <calestar@gmail.com>
-           2009-2015 Alexis Laferrière <alexis.laf@xymus.net>
+           2009-2016 Alexis Laferrière <alexis.laf@xymus.net>
            2009      Julien Chevalier <chevjulien@gmail.com>
-           2011-2015 Alexandre Terrasa <alexandre@moz-concept.com>
+           2011-2016 Alexandre Terrasa <alexandre@moz-concept.com>
            2012      Alexandre Pennetier <alexandre.pennetier@me.com>
-           2013-2015 Lucas Bajolet <r4pass@hotmail.com>
+           2013-2016 Lucas Bajolet <r4pass@hotmail.com>
            2013      Nathan Heu <heu.nathan@courrier.uqam.ca>
            2013      Matthieu Lucas <lucasmatthieu@gmail.com>
            2013      Stefan Lage <lagestfan@gmail.com>
@@ -48,7 +57,11 @@ Copyright: 2004-2015 Jean Privat <jean@pryen.org>
            2014      Maxime Leroy <maxime.leroy76@gmail.com>
            2014      Johann Dubois <johann.dubois@outlook.com>
            2014-2015 Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
-           2014      Alexandre Blondin Massé <alexandre.blondin.masse@gmail.com>
+           2014-2015 Alexandre Blondin Massé <alexandre.blondin.masse@gmail.com>
+           2015      Mehdi Ait Younes <overpex@gmail.com>
+           2015      Budi Kurniawan <budi2020@gmail.com>
+           2015-2016 Philippe Pepos Petitclerc <ppeposp@gmail.com>
+           2015-2016 Guilherme Mansur <guilhermerpmansur@gmail.com>
 Licence: BSD 2 (see LICENSE-BSD)
 Comment: Use of libraries and resources is basically unrestricted. We hold the copyright
          on the compiler and the tools but not on the programs made by the users.
index c0554fe..762eb1d 100644 (file)
@@ -1609,22 +1609,10 @@ redef class App
                game.save
        end
 
-       # Maximum wanted frame per second
-       var max_fps = 30
-
-       # clock used to track FPS
-       private var clock = new Clock
-
        redef fun frame_core(display)
        do
                game.step
                game.draw(display)
-               var dt = clock.lapse
-               var target_dt = 1000000000 / max_fps
-               if dt.sec == 0 and dt.nanosec < target_dt then
-                       var sleep_t = target_dt - dt.nanosec
-                       sys.nanosleep(0, sleep_t)
-               end
        end
 
        redef fun input(input_event)
index 49c74b0..9472da6 100644 (file)
@@ -41,7 +41,7 @@ class TGame
                var dt = clock.lapse
                tick += 1
 
-               var turn = new TTurn(self, tick, dt.to_f, dt.millisec)
+               var turn = new TTurn(self, tick, dt, ((dt-dt.floor)*1000.0).to_i)
                return turn
        end
 
diff --git a/contrib/xymus_net/.gitignore b/contrib/xymus_net/.gitignore
new file mode 100644 (file)
index 0000000..b2285d4
--- /dev/null
@@ -0,0 +1 @@
+xymus.net
diff --git a/contrib/xymus_net/Makefile b/contrib/xymus_net/Makefile
new file mode 100644 (file)
index 0000000..eff98e3
--- /dev/null
@@ -0,0 +1,9 @@
+all: xymus.net
+
+xymus.net: ../benitlux/src/server/benitlux_restful.nit $(shell ../../bin/nitls -M xymus_net.nit)
+       ../../bin/nitc -o $@ xymus_net.nit
+
+../benitlux/src/server/benitlux_restful.nit:
+       make -C ../benitlux src/server/benitlux_restful.nit
+
+pre-build: ../benitlux/src/server/benitlux_restful.nit
diff --git a/contrib/xymus_net/README.md b/contrib/xymus_net/README.md
new file mode 100644 (file)
index 0000000..5bb2c31
--- /dev/null
@@ -0,0 +1,5 @@
+Web server source and config of xymus.net
+
+This module acts also as an example to merge multiple `nitcorn` projects into one server.
+
+See the server online at http://xymus.net/.
diff --git a/contrib/xymus_net/package.ini b/contrib/xymus_net/package.ini
new file mode 100644 (file)
index 0000000..249a39a
--- /dev/null
@@ -0,0 +1,11 @@
+[package]
+name=xymus_net
+tags=web,example
+maintainer=Alexis Laferrière <alexis.laf@xymus.net>
+license=Apache-2.0
+[upstream]
+browse=https://github.com/nitlang/nit/tree/master/contrib/xymus.net/
+git=https://github.com/nitlang/nit.git
+git.directory=contrib/xymus.net/
+homepage=http://xymus.net/
+issues=https://github.com/nitlang/nit/issues
similarity index 96%
rename from lib/nitcorn/examples/src/xymus_net.nit
rename to contrib/xymus_net/xymus_net.nit
index 1233db4..726cb6a 100644 (file)
@@ -1,6 +1,6 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
 #
-# Copyright 2014-2015 Alexis Laferrière <alexis.laf@xymus.net>
+# Copyright 2014-2016 Alexis Laferrière <alexis.laf@xymus.net>
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ import privileges
 # Use actions defined by contribs
 import tnitter
 import benitlux::benitlux_controller
+import benitlux::benitlux_restful
 import opportunity::opportunity_controller
 import nitiwiki::wiki_edit
 
@@ -173,6 +174,7 @@ var vps_vh = new VirtualHost("vps.xymus.net:80")
 var tnitter_vh = new VirtualHost("tnitter.xymus.net:80")
 var pep8_vh = new VirtualHost("pep8.xymus.net:80")
 var benitlux_vh = new VirtualHost("benitlux.xymus.net:80")
+var benitlux_admin_vh = new VirtualHost("localhost:8081")
 
 var factory = new HttpFactory.and_libevent
 factory.config.virtual_hosts.add default_vh
@@ -180,6 +182,7 @@ factory.config.virtual_hosts.add vps_vh
 factory.config.virtual_hosts.add tnitter_vh
 factory.config.virtual_hosts.add pep8_vh
 factory.config.virtual_hosts.add benitlux_vh
+factory.config.virtual_hosts.add benitlux_admin_vh
 
 # Ports are open, drop to a low-privileged user if we are root
 var user_group = new UserGroup("nitcorn", "nitcorn")
@@ -228,6 +231,8 @@ benitlux_vh.routes.add new Route("/push/", benitlux_push)
 benitlux_vh.routes.add new Route("/static/", shared_file_server)
 benitlux_vh.routes.add new Route(null, benitlux_sub)
 
+benitlux_admin_vh.routes.add new Route(null, new BenitluxAdminAction(benitlux_db))
+
 # Opportunity service
 var opportunity = new OpportunityWelcome
 var opportunity_rest = new OpportunityRESTAction
index 0733bbf..a5cd314 100644 (file)
@@ -8,69 +8,7 @@
 # See: <http://rosettacode.org/wiki/Perlin_noise>
 module perlin_noise
 
-redef universal Float
-       # Smoothened `self`
-       fun fade: Float do return self*self*self*(self*(self*6.0-15.0)+10.0)
-end
-
-# Improved noise
-class ImprovedNoise
-       # Permutations
-       var p: Array[Int] = [151,160,137,91,90,15,
-               131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
-               190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
-               88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
-               77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
-               102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
-               135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
-               5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
-               223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
-               129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
-               251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
-               49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
-               138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180]
-
-       # Noise value in [-1..1] at 3d coordinates `x, y, z`
-       fun noise(x, y, z: Float): Float
-       do
-               var xx = x.to_i & 255
-               var yy = y.to_i & 255
-               var zz = z.to_i & 255
-
-               x -= x.floor
-               y -= y.floor
-               z -= z.floor
-
-               var u = x.fade
-               var v = y.fade
-               var w = z.fade
-
-               var a  = p[xx  ] + yy
-               var aa = p[a   ] + zz
-               var ab = p[a+1 ] + zz
-               var b  = p[xx+1] + yy
-               var ba = p[b   ] + zz
-               var bb = p[b+1 ] + zz
-
-               return w.lerp(v.lerp(u.lerp(grad(p[aa  ], x,     y,     z    ),
-                                           grad(p[ba  ], x-1.0, y,     z    )),
-                                    u.lerp(grad(p[ab  ], x,     y-1.0, z    ),
-                                           grad(p[bb  ], x-1.0, y-1.0, z    ))),
-                      v.lerp(u.lerp(grad(p[aa+1], x,     y,     z-1.0),
-                                           grad(p[ba+1], x-1.0, y,     z-1.0)),
-                                    u.lerp(grad(p[ab+1], x,     y-1.0, z-1.0),
-                                           grad(p[bb+1], x-1.0, y-1.0, z-1.0))))
-       end
-
-       # Value at a corner of the grid
-       fun grad(hash: Int, x, y, z: Float): Float
-       do
-               var h = hash & 15
-               var u = if h < 8 then x else y
-               var v = if h < 4 then y else if h == 12 or h == 14 then x else z
-               return (if h.is_even then u else -u) + (if h & 2 == 0 then v else -v)
-       end
-end
+import noise
 
 var map = new ImprovedNoise
 print map.noise(3.14, 42.0, 7.0).to_precision(17)
index 7b7ce02..cc0cba3 100644 (file)
@@ -188,6 +188,14 @@ class Node
                end
        end
 
+       # Find the closest node accepted by `cond` under `max_cost`
+       fun find_closest(max_cost: Int, context: PathContext, cond: nullable TargetCondition[N]): nullable N
+       do
+               var path = path_to_alts(null, max_cost, context, cond)
+               if path == null then return null
+               return path.nodes.last
+       end
+
        # We customize the serialization process to avoid problems with recursive
        # serialization engines. These engines, such as `JsonSerializer`,
        # are at danger to serialize the graph as a very deep tree.
index 8aea378..5ee9d87 100644 (file)
@@ -70,6 +70,8 @@ private extern class NativeAndroidMotionEvent `{AInputEvent *`}
        `}
 
        fun action: AMotionEventAction `{ return AMotionEvent_getAction(self); `}
+
+       fun native_down_time: Int `{ return AMotionEvent_getDownTime(self); `}
 end
 
 private extern class AMotionEventAction `{ int32_t `}
@@ -149,6 +151,11 @@ class AndroidMotionEvent
                        return null
                end
        end
+
+       # Time when the user originally pressed down to start a stream of position events
+       #
+       # The return value is in the `java.lang.System.nanoTime()` time base.
+       fun down_time: Int do return native.native_down_time
 end
 
 # A pointer event
index b5542e4..28129a5 100644 (file)
@@ -26,6 +26,7 @@
 module bucketed_game is serialize
 
 import serialization
+import counter
 
 # Something acting on the game
 abstract class Turnable[G: Game]
@@ -65,6 +66,9 @@ class Buckets[G: Game]
        private var buckets: Array[BUCKET] =
                [for b in n_buckets.times do new HashSet[Bucketable[G]]] is lazy
 
+       # Stats on delays asked when adding an event with `act_in` and `act_next`
+       private var delays = new Counter[Int]
+
        # Add the Bucketable event `e` at `at_tick`.
        fun add_at(e: Bucketable[G], at_tick: Int)
        do
@@ -106,6 +110,26 @@ class Buckets[G: Game]
                        end
                end
        end
+
+       # Get some statistics on both the current held events and historic expired events
+       fun stats: String
+       do
+               var entries = 0
+               var instances = new HashSet[Bucketable[G]]
+               var max = 0
+               var min = 100000
+               for bucket in buckets do
+                       var len = bucket.length
+                       entries += len
+                       instances.add_all bucket
+                       min = min.min(len)
+                       max = max.max(len)
+               end
+               var avg = entries.to_f / buckets.length.to_f
+
+               return "{buckets.length} buckets; uniq/tot:{instances.length}/{entries}, avg:{avg.to_precision(1)}, min:{min}, max:{max}\n" +
+                       "history:{delays.sum}, avg:{delays.avg}, min:{delays[delays.min.as(not null)]}, max:{delays[delays.max.as(not null)]}"
+       end
 end
 
 # Game related event
@@ -123,16 +147,16 @@ end
 # Game logic on the client
 class ThinGame
 
-       # Game tick when `self` should act.
+       # Current game tick
        #
        # Default is 0.
-       var tick: Int = 0 is protected writable
+       var tick: Int = 0 is writable
 end
 
 # Game turn on the client
 class ThinGameTurn[G: ThinGame]
 
-       # Game tick when `self` should act.
+       # Game tick when happened this turn
        var tick: Int is protected writable
 
        # Game events occurred for `self`.
@@ -153,10 +177,18 @@ class GameTurn[G: Game]
        end
 
        # Insert the Bucketable event `e` to be executed at next tick.
-       fun act_next(e: Bucketable[G]) do game.buckets.add_at(e, tick + 1)
+       fun act_next(e: Bucketable[G])
+       do
+               game.buckets.add_at(e, tick + 1)
+               game.buckets.delays.inc(1)
+       end
 
        # Insert the Bucketable event `e` to be executed at tick `t`.
-       fun act_in(e: Bucketable[G], t: Int) do game.buckets.add_at(e, tick + t)
+       fun act_in(e: Bucketable[G], t: Int)
+       do
+               game.buckets.add_at(e, tick + t)
+               game.buckets.delays.inc(t)
+       end
 
        # Add and `apply` a game `event`.
        fun add_event( event : GameEvent )
index c9d1279..d7dfa48 100644 (file)
@@ -2160,6 +2160,11 @@ redef class NativeString
        # SEE: `abstract_text::Text` for more info on the difference
        # between `Text::bytelen` and `Text::length`.
        fun to_s_full(bytelen, unilen: Int): String is abstract
+
+       # Copies the content of `src` to `self`
+       #
+       # NOTE: `self` must be large enough to withold `self.bytelen` bytes
+       fun fill_from(src: Text) do src.copy_to_native(self, src.bytelen, 0, 0)
 end
 
 redef class NativeArray[E]
index 2fa0bcb..9e70321 100644 (file)
@@ -369,6 +369,10 @@ redef class FlatText
                end
                return res
        end
+
+       redef fun copy_to_native(dst, n, src_off, dst_off) do
+               _items.copy_to(dst, n, first_byte + src_off, dst_off)
+       end
 end
 
 # Immutable strings of characters.
index f370e49..0bf97b8 100644 (file)
@@ -221,23 +221,16 @@ private class Concat
        end
 
        redef fun copy_to_native(dest, n, src_offset, dest_offset) do
-               var subs = new RopeSubstrings.from(self, src_offset)
-               var st = src_offset - subs.pos
-               var off = dest_offset
-               while n > 0 do
-                       var it = subs.item
-                       if n > it.length then
-                               var cplen = it.length - st
-                               it._items.copy_to(dest, cplen, st, off)
-                               off += cplen
-                               n -= cplen
-                       else
-                               it._items.copy_to(dest, n, st, off)
-                               n = 0
-                       end
-                       subs.next
-                       st = 0
+               var l = _left
+               if src_offset < l.bytelen then
+                       var lcopy = l.bytelen - src_offset
+                       lcopy = if lcopy > n then n else lcopy
+                       l.copy_to_native(dest, lcopy, src_offset, dest_offset)
+                       dest_offset += lcopy
+                       n -= lcopy
+                       src_offset = 0
                end
+               _right.copy_to_native(dest, n, src_offset, dest_offset)
        end
 
        # Returns a balanced version of `self`
index 6662877..5f3f017 100644 (file)
@@ -16,3 +16,4 @@
 module crapto
 
 import english_utils
+import xor
diff --git a/lib/crapto/examples/repeating_key_xor_cipher.txt b/lib/crapto/examples/repeating_key_xor_cipher.txt
new file mode 100644 (file)
index 0000000..cecdb81
--- /dev/null
@@ -0,0 +1,64 @@
+HUIfTQsPAh9PE048GmllH0kcDk4TAQsHThsBFkU2AB4BSWQgVB0dQzNTTmVS
+BgBHVBwNRU0HBAxTEjwMHghJGgkRTxRMIRpHKwAFHUdZEQQJAGQmB1MANxYG
+DBoXQR0BUlQwXwAgEwoFR08SSAhFTmU+Fgk4RQYFCBpGB08fWXh+amI2DB0P
+QQ1IBlUaGwAdQnQEHgFJGgkRAlJ6f0kASDoAGhNJGk9FSA8dDVMEOgFSGQEL
+QRMGAEwxX1NiFQYHCQdUCxdBFBZJeTM1CxsBBQ9GB08dTnhOSCdSBAcMRVhI
+CEEATyBUCHQLHRlJAgAOFlwAUjBpZR9JAgJUAAELB04CEFMBJhAVTQIHAh9P
+G054MGk2UgoBCVQGBwlTTgIQUwg7EAYFSQ8PEE87ADpfRyscSWQzT1QCEFMa
+TwUWEXQMBk0PAg4DQ1JMPU4ALwtJDQhOFw0VVB1PDhxFXigLTRkBEgcKVVN4
+Tk9iBgELR1MdDAAAFwoFHww6Ql5NLgFBIg4cSTRWQWI1Bk9HKn47CE8BGwFT
+QjcEBx4MThUcDgYHKxpUKhdJGQZZVCFFVwcDBVMHMUV4LAcKQR0JUlk3TwAm
+HQdJEwATARNFTg5JFwQ5C15NHQYEGk94dzBDADsdHE4UVBUaDE5JTwgHRTkA
+Umc6AUETCgYAN1xGYlUKDxJTEUgsAA0ABwcXOwlSGQELQQcbE0c9GioWGgwc
+AgcHSAtPTgsAABY9C1VNCAINGxgXRHgwaWUfSQcJABkRRU8ZAUkDDTUWF01j
+OgkRTxVJKlZJJwFJHQYADUgRSAsWSR8KIgBSAAxOABoLUlQwW1RiGxpOCEtU
+YiROCk8gUwY1C1IJCAACEU8QRSxORTBSHQYGTlQJC1lOBAAXRTpCUh0FDxhU
+ZXhzLFtHJ1JbTkoNVDEAQU4bARZFOwsXTRAPRlQYE042WwAuGxoaAk5UHAoA
+ZCYdVBZ0ChQLSQMYVAcXQTwaUy1SBQsTAAAAAAAMCggHRSQJExRJGgkGAAdH
+MBoqER1JJ0dDFQZFRhsBAlMMIEUHHUkPDxBPH0EzXwArBkkdCFUaDEVHAQAN
+U29lSEBAWk44G09fDXhxTi0RAk4ITlQbCk0LTx4cCjBFeCsGHEETAB1EeFZV
+IRlFTi4AGAEORU4CEFMXPBwfCBpOAAAdHUMxVVUxUmM9ElARGgZBAg4PAQQz
+DB4EGhoIFwoKUDFbTCsWBg0OTwEbRSonSARTBDpFFwsPCwIATxNOPBpUKhMd
+Th5PAUgGQQBPCxYRdG87TQoPD1QbE0s9GkFiFAUXR0cdGgkADwENUwg1DhdN
+AQsTVBgXVHYaKkg7TgNHTB0DAAA9DgQACjpFX0BJPQAZHB1OeE5PYjYMAg5M
+FQBFKjoHDAEAcxZSAwZOBREBC0k2HQxiKwYbR0MVBkVUHBZJBwp0DRMDDk5r
+NhoGACFVVWUeBU4MRREYRVQcFgAdQnQRHU0OCxVUAgsAK05ZLhdJZChWERpF
+QQALSRwTMRdeTRkcABcbG0M9Gk0jGQwdR1ARGgNFDRtJeSchEVIDBhpBHQlS
+WTdPBzAXSQ9HTBsJA0UcQUl5bw0KB0oFAkETCgYANlVXKhcbC0sAGgdFUAIO
+ChZJdAsdTR0HDBFDUk43GkcrAAUdRyonBwpOTkJEUyo8RR8USSkOEENSSDdX
+RSAdDRdLAA0HEAAeHQYRBDYJC00MDxVUZSFQOV1IJwYdB0dXHRwNAA9PGgMK
+OwtTTSoBDBFPHU54W04mUhoPHgAdHEQAZGU/OjV6RSQMBwcNGA5SaTtfADsX
+GUJHWREYSQAnSARTBjsIGwNOTgkVHRYANFNLJ1IIThVIHQYKAGQmBwcKLAwR
+DB0HDxNPAU94Q083UhoaBkcTDRcAAgYCFkU1RQUEBwFBfjwdAChPTikBSR0T
+TwRIEVIXBgcURTULFk0OBxMYTwFUN0oAIQAQBwkHVGIzQQAGBR8EdCwRCEkH
+ElQcF0w0U05lUggAAwANBxAAHgoGAwkxRRMfDE4DARYbTn8aKmUxCBsURVQf
+DVlOGwEWRTIXFwwCHUEVHRcAMlVDKRsHSUdMHQMAAC0dCAkcdCIeGAxOazkA
+BEk2HQAjHA1OAFIbBxNJAEhJBxctDBwKSRoOVBwbTj8aQS4dBwlHKjUECQAa
+BxscEDMNUhkBC0ETBxdULFUAJQAGARFJGk9FVAYGGlMNMRcXTRoBDxNPeG43
+TQA7HRxJFUVUCQhBFAoNUwctRQYFDE43PT9SUDdJUydcSWRtcwANFVAHAU5T
+FjtFGgwbCkEYBhlFeFsABRcbAwZOVCYEWgdPYyARNRcGAQwKQRYWUlQwXwAg
+ExoLFAAcARFUBwFOUwImCgcDDU5rIAcXUj0dU2IcBk4TUh0YFUkASEkcC3QI
+GwMMQkE9SB8AMk9TNlIOCxNUHQZCAAoAHh1FXjYCDBsFABkOBkk7FgALVQRO
+D0EaDwxOSU8dGgI8EVIBAAUEVA5SRjlUQTYbCk5teRsdRVQcDhkDADBFHwhJ
+AQ8XClJBNl4AC1IdBghVEwARABoHCAdFXjwdGEkDCBMHBgAwW1YnUgAaRyon
+B0VTGgoZUwE7EhxNCAAFVAMXTjwaTSdSEAESUlQNBFJOZU5LXHQMHE0EF0EA
+Bh9FeRp5LQdFTkAZREgMU04CEFMcMQQAQ0lkay0ABwcqXwA1FwgFAk4dBkIA
+CA4aB0l0PD1MSQ8PEE87ADtbTmIGDAILAB0cRSo3ABwBRTYKFhROHUETCgZU
+MVQHYhoGGksABwdJAB0ASTpFNwQcTRoDBBgDUkksGioRHUkKCE5THEVCC08E
+EgF0BBwJSQoOGkgGADpfADETDU5tBzcJEFMLTx0bAHQJCx8ADRJUDRdMN1RH
+YgYGTi5jMURFeQEaSRAEOkURDAUCQRkKUmQ5XgBIKwYbQFIRSBVJGgwBGgtz
+RRNNDwcVWE8BT3hJVCcCSQwGQx9IBE4KTwwdASEXF01jIgQATwZIPRpXKwYK
+BkdEGwsRTxxDSToGMUlSCQZOFRwKUkQ5VEMnUh0BR0MBGgAAZDwGUwY7CBdN
+HB5BFwMdUz0aQSwWSQoITlMcRUILTxoCEDUXF01jNw4BTwVBNlRBYhAIGhNM
+EUgIRU5CRFMkOhwGBAQLTVQOHFkvUkUwF0lkbXkbHUVUBgAcFA0gRQYFCBpB
+PU8FQSsaVycTAkJHYhsRSQAXABxUFzFFFggICkEDHR1OPxoqER1JDQhNEUgK
+TkJPDAUAJhwQAg0XQRUBFgArU04lUh0GDlNUGwpOCU9jeTY1HFJARE4xGA4L
+ACxSQTZSDxsJSw1ICFUdBgpTNjUcXk0OAUEDBxtUPRpCLQtFTgBPVB8NSRoK
+SREKLUUVAklkERgOCwAsUkE2Ug8bCUsNSAhVHQYKUyI7RQUFABoEVA0dWXQa
+Ry1SHgYOVBFIB08XQ0kUCnRvPgwQTgUbGBwAOVREYhAGAQBJEUgETgpPGR8E
+LUUGBQgaQRIaHEshGk03AQANR1QdBAkAFwAcUwE9AFxNY2QxGA4LACxSQTZS
+DxsJSw1ICFUdBgpTJjsIF00GAE1ULB1NPRpPLF5JAgJUVAUAAAYKCAFFXjUe
+DBBOFRwOBgA+T04pC0kDElMdC0VXBgYdFkU2CgtNEAEUVBwTWXhTVG5SGg8e
+AB0cRSo+AwgKRSANExlJCBQaBAsANU9TKxFJL0dMHRwRTAtPBRwQMAAATQcB
+FlRlIkw5QwA2GggaR0YBBg5ZTgIcAAw3SVIaAQcVEU8QTyEaYy0fDE4ITlhI
+Jk8DCkkcC3hFMQIEC0EbAVIqCFZBO1IdBgZUVA4QTgUWSR4QJwwRTWM=
diff --git a/lib/crapto/examples/repeating_key_xor_solve.nit b/lib/crapto/examples/repeating_key_xor_solve.nit
new file mode 100644 (file)
index 0000000..f88e2d9
--- /dev/null
@@ -0,0 +1,38 @@
+# 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 base64
+import crapto
+
+# Check usage
+if args.length != 1 then
+       print "Usage: repeating_key_xor_solve <cipher_file>"
+       exit 1
+end
+
+# Read the cipher from the file
+var cipher_bytes = args[0].to_path.read_all_bytes.decode_base64
+
+# Create a RepeatingKeyXorCipher object to manipulate your ciphertext
+var xorcipher = new RepeatingKeyXorCipher
+xorcipher.ciphertext = cipher_bytes
+
+# Try to find the best candidate key
+xorcipher.find_key
+
+# Decrypt the cipher according to the found key
+xorcipher.decrypt
+
+# Check the resulting plaintext out...
+print xorcipher.plaintext
diff --git a/lib/crapto/xor.nit b/lib/crapto/xor.nit
new file mode 100644 (file)
index 0000000..8745c1a
--- /dev/null
@@ -0,0 +1,150 @@
+# 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.
+
+# Cryptographic attacks and utilities for XOR-based algorithms.
+module xor
+
+import combinations
+import crypto
+import english_utils
+
+redef class SingleByteXorCipher
+       # Tries to find key using frequency analysis on all possible plaintexts.
+       # Populates `self.key`
+       fun find_key do
+
+               # Accumulate best result
+               var max = 0.0
+               var best = 0.to_b
+
+               # Iterate on possible values for a byte
+               var xor_b = new Bytes.with_capacity(1)
+               for b in [0 .. 255] do
+                       # Need `Bytes` to pass to xor
+                       xor_b[0] = b.to_b
+
+                       # Xor and evaluate result
+                       var xored = ciphertext.xorcipher(xor_b)
+                       var result = xored.to_s.english_scoring
+                       if result > max then
+                               max = result
+                               best = b.to_b
+                       end
+               end
+
+               self.key = best
+
+       end
+end
+
+redef class RepeatingKeyXorCipher
+       # Attempts to find the key by using frequency analysis on the resulting plaintexts.
+       # Best key lengths are estimated using the hamming distance of blocks of keylength bytes.
+       # Ciphertext is then transposed in such a way that it can be solved by sequences of
+       # SingleByteXor (one for each offset in the key).
+       #
+       # `min_keylength` and `max_keylength` are limits as to what key lengths are tested.
+       # `considered_keylength_count` is the number of best key lengths that are kept to be
+       # analysed by the SingleByteXor frequency analysis.
+       fun find_key(min_keylength, max_keylength, considered_keylength_count: nullable Int)  do
+
+               # Set default values
+               if min_keylength == null then min_keylength = 2
+               if max_keylength == null then max_keylength = 40
+               if considered_keylength_count == null then considered_keylength_count = 3
+
+               # Find the best candidate key lengths based on the normalized hamming distances
+               var best_sizes = get_normalized_hamming_distances(min_keylength, max_keylength, considered_keylength_count)
+
+               var best = 0.0
+               var best_key: nullable Bytes = null
+               for ks in best_sizes do
+
+                       # Rearrange ciphertext to be in SingleByteXORable blocks
+                       var transposed = transpose_ciphertext(ks)
+
+                       var key = new Bytes.empty
+                       for slot in transposed do
+                               var sbx = new SingleByteXorCipher
+                               sbx.ciphertext = slot
+                               sbx.find_key
+                               key.add sbx.key
+                       end
+
+                       # Evaluate the resulting plaintext based on english frequency analysis
+                       var eng_score = ciphertext.xorcipher(key).to_s.english_scoring
+                       if eng_score > best then
+                               best_key = key
+                               best = eng_score
+                       end
+
+                       assert best_key != null
+                       self.key = best_key
+
+               end
+       end
+
+       # Computes the normalized hamming distances between blocks of ciphertext of length between `min_length` and `max_length`.
+       # The `considered_keylength_count` smallest results are returned
+       private fun get_normalized_hamming_distances(min_keylength, max_keylength, considered_keylength_count: Int): Array[Int] do
+
+               var normalized_distances = new HashMap[Float, Int]
+
+               # Iterate over all given key lengths
+               for ks in [min_keylength .. max_keylength[ do
+
+                       # Initialize the blocks of size `ks`
+                       var blocks = new Array[Bytes]
+                       while (blocks.length + 1) * ks < ciphertext.length do
+                               blocks.add(ciphertext.slice(blocks.length * ks, ks))
+                       end
+
+                       # Compute the normalized hamming distance with all block combinations
+                       var pairs = new CombinationCollection[Bytes](blocks, 2)
+                       var hamming_dists = new Array[Float]
+                       for p in pairs do
+                               hamming_dists.add(p[0].hamming_distance(p[1]).to_f / ks.to_f)
+                       end
+
+                       # Normalize the results based on the number of blocks
+                       var normalized = 0.0
+                       for dist in hamming_dists do normalized += dist
+                       normalized /= hamming_dists.length.to_f
+                       normalized_distances[normalized] = ks
+
+               end
+
+               # Collect the best candidates
+               var distances = normalized_distances.keys.to_a
+               default_comparator.sort(distances)
+               var best_distances = distances.subarray(0, considered_keylength_count)
+               var best_sizes = [for d in best_distances do normalized_distances[d]]
+
+               return best_sizes
+       end
+
+       # Returns a rearranged format of the ciphertext where every byte of a slot will be XORed with the same offset of a key of length `keylength`.
+       private fun transpose_ciphertext(keylength: Int): Array[Bytes] do
+               var transposed = new Array[Bytes]
+               for i in [0 .. keylength[ do
+                       transposed.add(new Bytes.empty)
+               end
+
+               for byte_idx in [0 .. ciphertext.length[ do
+                       transposed[byte_idx % keylength].add(ciphertext[byte_idx])
+               end
+
+               return transposed
+       end
+end
similarity index 91%
rename from lib/crypto.nit
rename to lib/crypto/basic_ciphers.nit
index 2abe5d7..e4a133c 100644 (file)
@@ -12,8 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Mix of all things cryptography-related
-module crypto
+# Basic cryptographic ciphers and utilities.
+module basic_ciphers
 
 redef class Char
        # Rotates self of `x`
@@ -157,20 +157,21 @@ redef class Text
 end
 
 redef class Bytes
-
-       # Returns `self` xored with `key`
-       #
-       # The key is cycled through until the `self` has been completely xored.
-       #
-       #     assert "goodmorning".to_bytes.xorcipher(" ".to_bytes) == "GOODMORNING".bytes
-       fun xorcipher(key: Bytes): Bytes do
-               var xored = new Bytes.with_capacity(self.length)
-
-               for i in self.length.times do
-                       xored.add(self[i] ^ key[i % key.length])
+       # Computes the edit/hamming distance of two sequences of bytes.
+       #
+       #     assert "this is a test".to_bytes.hamming_distance("wokka wokka!!!".bytes) == 37
+       #     assert "this is a test".to_bytes.hamming_distance("this is a test".bytes) == 0
+       #
+       fun hamming_distance(other: SequenceRead[Byte]): Int do
+               var diff = 0
+               for idx in self.length.times do
+                       var res_byte = self[idx] ^ other[idx]
+                       for bit in [0..8[ do
+                               if res_byte & 1u8 == 1u8 then diff += 1
+                               res_byte = res_byte >> 1
+                       end
                end
-
-               return xored
+               return diff
        end
 end
 
diff --git a/lib/crypto/crypto.nit b/lib/crypto/crypto.nit
new file mode 100644 (file)
index 0000000..4709403
--- /dev/null
@@ -0,0 +1,19 @@
+# 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.
+
+# Mix of all things cryptography-related
+module crypto
+
+import basic_ciphers
+import xor_ciphers
similarity index 89%
rename from lib/crypto.ini
rename to lib/crypto/package.ini
index e8b4cf1..24f6b14 100644 (file)
@@ -6,6 +6,6 @@ license=Apache-2.0
 [upstream]
 browse=https://github.com/nitlang/nit/tree/master/lib/crypto.nit
 git=https://github.com/nitlang/nit.git
-git.directory=lib/crypto.nit
+git.directory=lib/crypto/crypto.nit
 homepage=http://nitlanguage.org
 issues=https://github.com/nitlang/nit/issues
diff --git a/lib/crypto/xor_ciphers.nit b/lib/crypto/xor_ciphers.nit
new file mode 100644 (file)
index 0000000..1c4807c
--- /dev/null
@@ -0,0 +1,88 @@
+# 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.
+
+# XOR oriented cryptographic ciphers and utilities.
+module xor_ciphers
+
+redef class Bytes
+       # Returns `self` xored with `key`
+       #
+       # The key is cycled through until the `self` has been completely xored.
+       #
+       #     assert "goodmorning".to_bytes.xorcipher(" ".to_bytes) == "GOODMORNING".bytes
+       fun xorcipher(key: Bytes): Bytes do
+               var xored = new Bytes.with_capacity(self.length)
+
+               for i in self.length.times do
+                       xored.add(self[i] ^ key[i % key.length])
+               end
+
+               return xored
+       end
+end
+
+# Base class to modelize cryptographic ciphers
+abstract class Cipher
+
+       # Encrypted data
+       var ciphertext = new Bytes.empty is writable
+
+       # Unencrypted data
+       var plaintext = new Bytes.empty is writable
+
+       # Encrypt plaintext and populate `self.ciphertext`
+       fun encrypt is abstract
+
+       # Decrypt ciphertext and populate `self.plaintext`
+       fun decrypt is abstract
+
+end
+
+# Simple XOR cipher where the whole plaintext is XORed with a single byte.
+class SingleByteXorCipher
+       super Cipher
+
+       # Cryptographic key used in encryption and decryption.
+       var key: Byte = 0.to_b
+
+       redef fun encrypt do
+               var key_bytes = new Bytes.with_capacity(1)
+               key_bytes.add(key)
+               ciphertext = plaintext.xorcipher(key_bytes)
+       end
+
+       redef fun decrypt do
+               var key_bytes = new Bytes.with_capacity(1)
+               key_bytes.add(key)
+               plaintext = ciphertext.xorcipher(key_bytes)
+       end
+end
+
+# XOR cipher where the key is repeated to match the length of the message.
+class RepeatingKeyXorCipher
+       super Cipher
+
+       # Cryptographic key used in encryption and decryption.
+       var key = new Bytes.empty
+
+       redef fun encrypt do
+               assert key.length > 0
+               ciphertext = plaintext.xorcipher(key)
+       end
+
+       redef fun decrypt do
+               assert key.length > 0
+               plaintext = ciphertext.xorcipher(key)
+       end
+end
index a1eed2f..245d071 100644 (file)
@@ -162,6 +162,35 @@ class EulerCamera
                yaw = 0.0
                roll = 0.0
        end
+
+       # Convert the position `x, y` on screen, to world coordinates on the plane at `target_z`
+       #
+       # `target_z` defaults to `0.0` and specifies the Z coordinates of the plane
+       # on which to project the screen position `x, y`.
+       #
+       # This method assumes that the camera is looking along the Z axis towards higher values.
+       # Using it in a different orientation can be useful, but won't result in valid
+       # world coordinates.
+       fun camera_to_world(x, y: Numeric, target_z: nullable Float): Point[Float]
+       do
+               # TODO, this method could be tweaked to support projecting the 2D point,
+               # on the near plane (x,y) onto a given distance no matter to orientation
+               # of the camera.
+
+               target_z = target_z or else 0.0
+
+               # Convert from pixel units / window resolution to
+               # units on the near clipping wall to
+               # units on the target wall at Z = 0
+               var near_height = (field_of_view_y/2.0).tan * near
+               var cross_screen_to_near = near_height / (display.height.to_f/2.0)
+               var cross_near_to_target = (position.z - target_z) / near
+               var mod = cross_screen_to_near * cross_near_to_target * 1.72 # FIXME drop the magic number
+
+               var wx = position.x + (x.to_f-display.width.to_f/2.0) * mod
+               var wy = position.y - (y.to_f-display.height.to_f/2.0) * mod
+               return new Point[Float](wx, wy)
+       end
 end
 
 # Orthogonal camera to draw UI objects with services to work with screens of different sizes
index f16609f..896f07f 100644 (file)
@@ -47,7 +47,7 @@ redef class App
        private var frame_count = 0
 
        # Deadline used to compute `current_fps`
-       private var frame_count_deadline = 5
+       private var frame_count_deadline = 5.0
 
        # Check and sleep to maintain a frame-rate bellow `maximum_fps`
        #
@@ -55,12 +55,12 @@ redef class App
        # Is automatically called at the end of `full_frame`.
        fun limit_fps
        do
-               var t = clock.total.sec
+               var t = clock.total
                if t >= frame_count_deadline then
                        var cfps = frame_count.to_f / 5.0
                        self.current_fps = cfps
                        frame_count = 0
-                       frame_count_deadline = t + 5
+                       frame_count_deadline = t + 5.0
                end
                frame_count += 1
 
index 3841bc6..f4abd92 100644 (file)
@@ -44,19 +44,19 @@ redef class App
        private var frame_count = 0
 
        # Deadline used to compute `current_fps`
-       private var frame_count_deadline = 0
+       private var frame_count_deadline = 0.0
 
        # Check and sleep to maitain a frame-rate bellow `maximum_fps`
        # Also periodically uptate `current_fps`
        # Is automatically called at the end of `full_frame`.
        fun limit_fps
        do
-               var t = clock.total.sec
+               var t = clock.total
                if t >= frame_count_deadline then
                        var cfps = frame_count.to_f / 5.0
                        self.current_fps = cfps
                        frame_count = 0
-                       frame_count_deadline = t + 5
+                       frame_count_deadline = t + 5.0
                end
                frame_count += 1
 
index 6bc8b36..2db66b8 100644 (file)
@@ -26,7 +26,8 @@ and the FFI enables calling services in different languages.
 A minimal example follows with a custom `Action` and using `FileServer`.
 
 More general examples are available at `lib/nitcorn/examples/`.
-It includes the configuration of `http://xymus.net/` which merges many other _nitcorn_ applications.
+For an example of a larger project merging many _nitcorn_ applications into one server,
+take a look at the configuration of `http://xymus.net/` at `../contrib/xymus_net/xymus_net.nit`.
 
 Larger projects using _nitcorn_ can be found in the `contrib/` folder:
 * _opportunity_ is a meetup planner heavily based on _nitcorn_.
index d1bdeae..b1bbed9 100644 (file)
@@ -2,10 +2,6 @@ all: bin/restful_annot
        mkdir -p bin/
        ../../../bin/nitc --dir bin src/nitcorn_hello_world.nit src/simple_file_server.nit
 
-xymus.net:
-       mkdir -p bin/
-       ../../../bin/nitc --dir bin/ src/xymus_net.nit
-
 pre-build: src/restful_annot_gen.nit
 src/restful_annot_gen.nit:
        ../../../bin/nitrestful -o $@ src/restful_annot.nit
index ba09bc1..cf4d0fa 100644 (file)
@@ -359,3 +359,72 @@ redef universal Int
                return self & 0x3FFF_FFFF
        end
 end
+
+redef universal Float
+       # Smoothened `self`, used by `ImprovedNoise`
+       private fun fade: Float do return self*self*self*(self*(self*6.0-15.0)+10.0)
+end
+
+# Direct translation of Ken Perlin's improved noise Java implementation
+#
+# This implementation differs from `PerlinNoise` on two main points.
+# This noise is calculated for a 3D point, vs 2D in `PerlinNoise`.
+# `PerlinNoise` is based off a customizable seed, while this noise has a static data source.
+class ImprovedNoise
+
+       # Permutations
+       private var p: Array[Int] = [151,160,137,91,90,15,
+               131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
+               190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
+               88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
+               77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
+               102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
+               135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
+               5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
+               223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
+               129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
+               251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
+               49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
+               138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180] * 2
+
+       # Noise value in [-1..1] at 3D coordinates `x, y, z`
+       fun noise(x, y, z: Float): Float
+       do
+               var xx = x.floor.to_i & 255
+               var yy = y.floor.to_i & 255
+               var zz = z.floor.to_i & 255
+
+               x -= x.floor
+               y -= y.floor
+               z -= z.floor
+
+               var u = x.fade
+               var v = y.fade
+               var w = z.fade
+
+               var a  = p[xx  ] + yy
+               var aa = p[a   ] + zz
+               var ab = p[a+1 ] + zz
+               var b  = p[xx+1] + yy
+               var ba = p[b   ] + zz
+               var bb = p[b+1 ] + zz
+
+               return w.lerp(v.lerp(u.lerp(grad(p[aa  ], x,     y,     z    ),
+                                           grad(p[ba  ], x-1.0, y,     z    )),
+                                    u.lerp(grad(p[ab  ], x,     y-1.0, z    ),
+                                           grad(p[bb  ], x-1.0, y-1.0, z    ))),
+                      v.lerp(u.lerp(grad(p[aa+1], x,     y,     z-1.0),
+                                           grad(p[ba+1], x-1.0, y,     z-1.0)),
+                                    u.lerp(grad(p[ab+1], x,     y-1.0, z-1.0),
+                                           grad(p[bb+1], x-1.0, y-1.0, z-1.0))))
+       end
+
+       # Value at a corner of the grid
+       private fun grad(hash: Int, x, y, z: Float): Float
+       do
+               var h = hash & 15
+               var u = if h < 8 then x else y
+               var v = if h < 4 then y else if h == 12 or h == 14 then x else z
+               return (if h.is_even then u else -u) + (if h & 2 == 0 then v else -v)
+       end
+end
index 4763061..b9e436a 100644 (file)
@@ -122,11 +122,8 @@ class PerfEntry
        # Total execution time of this event
        var sum = 0.0
 
-       # Register a new event execution time with a `Timespec`
-       fun add(lapse: Timespec) do add_float lapse.to_f
-
-       # Register a new event execution time in seconds using a `Float`
-       fun add_float(time: Float)
+       # Register a new event execution time in seconds
+       fun add(time: Float)
        do
                if time.to_f < min.to_f or count == 0 then min = time
                if time.to_f > max.to_f then max = time
index 08f7c9a..4712faf 100644 (file)
@@ -505,7 +505,7 @@ class LogHandler
        redef fun all(req, res) do
                var timer = req.timer
                if timer != null then
-                       print "{req.method} {req.uri} {res.color_status} ({timer.total})"
+                       print "{req.method} {req.uri} {res.color_status} ({timer.total}s)"
                else
                        print "{req.method} {req.uri} {res.color_status}"
                end
index b97d10c..7f8e3b1 100644 (file)
@@ -34,7 +34,7 @@ class LogHandler
        redef fun all(req, res) do
                var timer = req.timer
                if timer != null then
-                       print "{req.method} {req.uri} {res.color_status} ({timer.total})"
+                       print "{req.method} {req.uri} {res.color_status} ({timer.total}s)"
                else
                        print "{req.method} {req.uri} {res.color_status}"
                end
index 38e4bd9..518d9dc 100644 (file)
@@ -48,7 +48,7 @@ class ConsoleLog
        redef fun all(req, res) do
                var clock = req.clock
                if clock != null then
-                       print "{req.method} {req.uri} {status(res)} ({clock.total})"
+                       print "{req.method} {req.uri} {status(res)} ({clock.total}s)"
                else
                        print "{req.method} {req.uri} {status(res)}"
                end
index 4d22201..d32c908 100644 (file)
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# A native wrapper ove the postgres c api
 module native_postgres is pkgconfig("libpq")
 
 in "C header" `{
@@ -30,7 +31,9 @@ extern class ExecStatusType `{int`}
   new nonfatal_error  `{ return PGRES_NONFATAL_ERROR; `}
   new fatal_error     `{ return PGRES_FATAL_ERROR; `}
 
-  fun is_ok: Bool `{return self == PGRES_TUPLES_OK || self == PGRES_COMMAND_OK; `}
+  fun is_ok: Bool `{
+    return !(self == PGRES_BAD_RESPONSE || self == PGRES_NONFATAL_ERROR || self == PGRES_FATAL_ERROR);
+  `}
 
   redef fun to_s import NativeString.to_s `{
     char * err = PQresStatus(self);
@@ -46,7 +49,7 @@ extern class ConnStatusType `{int`}
   fun is_ok: Bool `{return self == CONNECTION_OK; `}
 end
 
-extern class PGResult `{PGresult *`}
+extern class NativePGResult `{PGresult *`}
   # Frees the memory block associated with the result
   fun clear `{PQclear(self); `}
 
@@ -83,27 +86,27 @@ end
 extern class NativePostgres `{PGconn *`}
 
   # Connect to a new database using the conninfo string as a parameter
-  new connectdb(conninfo: String) import String.to_cstring `{
+  new connectdb(conninfo: Text) import Text.to_cstring `{
     PGconn * self = NULL;
-    self = PQconnectdb(String_to_cstring(conninfo));
+    self = PQconnectdb(Text_to_cstring(conninfo));
     return self;
   `}
 
   # Submits a query to the server and waits for the result returns the ExecStatustype of the query
-  fun exec(query: String): PGResult import String.to_cstring `{
-    PGresult *res = PQexec(self, String_to_cstring(query));
+  fun exec(query: Text): NativePGResult import Text.to_cstring `{
+    PGresult *res = PQexec(self, Text_to_cstring(query));
     return res;
   `}
 
   # Prepares a statement with the given parameters
-  fun prepare(stmt: String, query: String, nParams: Int):PGResult import String.to_cstring `{
+  fun prepare(stmt: String, query: String, nParams: Int): NativePGResult import String.to_cstring `{
     const char * stmtName = String_to_cstring(stmt);
     const char * queryStr = String_to_cstring(query);
     PGresult * res = PQprepare(self, stmtName, queryStr, nParams, NULL);
     return res;
   `}
 
-  fun exec_prepared(stmt: String, nParams: Int, values: Array[String], pLengths: Array[Int], pFormats: Array[Int], resultFormat: Int):PGResult import String.to_cstring, Array[String].[], Array[Int].[] `{
+  fun exec_prepared(stmt: String, nParams: Int, values: Array[String], pLengths: Array[Int], pFormats: Array[Int], resultFormat: Int): NativePGResult import String.to_cstring, Array[String].[], Array[Int].[] `{
     const char * stmtName = String_to_cstring(stmt);
     const char * paramValues[nParams];
     int paramLengths[nParams];
diff --git a/lib/postgresql/postgres.nit b/lib/postgresql/postgres.nit
new file mode 100644 (file)
index 0000000..22e498f
--- /dev/null
@@ -0,0 +1,144 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2016 Guilherme Mansur<guilhermerpmansur@gmail.com>
+#
+# 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.
+
+# Services to manipulate a Postgres database
+#
+# For more information, refer to the documentation of http://www.postgresql.org/docs/manuals/
+#
+# ### Usage example
+#
+# ~~~
+# class Animal
+#   var name: String
+#   var kind: String
+#   var age: Int
+# end
+#
+# var animals = new Array[Animal]
+# var dog = new Animal("Lassy", "dog", 10)
+# var cat = new Animal("Garfield", "cat", 3)
+# var turtle = new Animal("George", "turtle", 123)
+#
+# animals.add(dog)
+# animals.add(cat)
+# animals.add(turtle)
+#
+# var db = new Postgres.open("dbname=postgres")
+#
+# assert db_is_open: not db.is_closed
+# assert create_table: db.create_table("IF NOT EXISTS animals (aname TEXT PRIMARY KEY, kind TEXT NOT NULL, age INT NOT NULL)") else print db.error
+#
+# for animal in animals do
+#   assert insert: db.insert("INTO animals VALUES('{animal.name}', '{animal.kind}', {animal.age})") else print db.error
+# end
+#
+# var result = db.raw_execute("SELECT * FROM animals")
+# assert  result.is_ok
+# assert drop_table: db.execute("DROP TABLE animals")
+# db.finish
+# assert db_is_closed: db.is_closed
+# ~~~
+module postgres
+
+private import native_postgres
+
+# A connection to a Postgres database
+class Postgres
+  private var native_connection: NativePostgres
+
+  var is_closed = true
+
+  # Open the connnection with the database using the `conninfo`
+  init open(conninfo: Text)
+  do
+    init(new NativePostgres.connectdb(conninfo))
+    if native_connection.status.is_ok then is_closed = false
+  end
+
+  # Close this connection with the database
+  fun finish
+  do
+    if is_closed then return
+
+    is_closed = true
+
+    native_connection.finish
+  end
+
+  fun prepare(stmt_name:String, query:String, num_params: Int):PGResult do return new PGResult(native_connection.prepare(stmt_name, query, num_params))
+
+  fun exec_prepared(stmt_name: String, num_params: Int, values: Array[String], param_lengths: Array[Int], param_formats: Array[Int], result_format: Int):PGResult do
+    return new PGResult(native_connection.exec_prepared(stmt_name, num_params, values, param_lengths, param_formats, result_format))
+  end
+
+  # Executes a `query` and returns the raw `PGResult`
+  fun raw_execute(query: Text): PGResult do return new PGResult(native_connection.exec(query))
+
+  # Execute the `sql` statement and returns `true` on success
+  fun execute(query: Text): Bool do return native_connection.exec(query).status.is_ok
+
+  # Create a table on the DB with a statement beginning with "CREATE TABLE ", followed by `rest`
+  #
+  # This method does not escape special characters.
+  fun create_table(rest: Text): Bool do return execute("CREATE TABLE " + rest)
+
+  # Insert in the DB with a statement beginning with "INSERT ", followed by `rest`
+  #
+  # This method does not escape special characters.
+  fun insert(rest: Text): Bool do return execute("INSERT " + rest)
+
+  # Replace in the DB with a statement beginning with "REPLACE", followed by `rest`
+  #
+  # This method does not escape special characters.
+  fun replace(rest: Text): Bool do return execute("REPLACE " + rest)
+
+  # The latest error message on the connection an empty string if none
+  fun error: String do return native_connection.error
+
+  # The status of this connection
+  fun is_valid: Bool do return native_connection.status.is_ok
+
+  # Resets the connection to the database
+  fun reset do native_connection.reset
+end
+
+# The result of a given query
+class PGResult
+  private var pg_result: NativePGResult
+
+  fun clear do pg_result.clear
+
+  # Returns the number of rows in the query result
+  fun ntuples:Int do return pg_result.ntuples
+
+  # Returns the number of columns in each row of the query result
+  fun nfields:Int do return pg_result.nfields
+
+  # Returns the ExecStatusType of a result
+  fun is_ok:Bool do return pg_result.status.is_ok
+
+  # Returns the field name of a given `column_number`
+  fun fname(column_number:Int):String do return pg_result.fname(column_number)
+
+  # Returns the column number associated with the `column_name`
+  fun fnumber(column_name:String):Int do return pg_result.fnumber(column_name)
+
+  # Returns a single field value of one row of the result at `row_number`, `column_number`
+  fun value(row_number:Int, column_number:Int):String  do return pg_result.value(row_number, column_number)
+
+  # Tests wether a field specified by the `row_number` and `column_number` is null.
+  fun is_null(row_number:Int, column_number: Int): Bool do return pg_result.is_null(row_number, column_number)
+end
index 8cfa4da..243b5d8 100644 (file)
@@ -73,13 +73,16 @@ extern class Timespec `{struct timespec*`}
                clock_gettime(CLOCK_MONOTONIC, self);
        `}
 
-       # Substract a Timespec from `self`.
-       fun - ( o : Timespec ) : Timespec
+       # Subtract `other` from `self`
+       fun -(other: Timespec): Timespec
        do
-               var s = sec - o.sec
-               var ns = nanosec - o.nanosec
-               if ns > nanosec then s += 1
-               return new Timespec( s, ns )
+               var s = sec - other.sec
+               var ns = nanosec - other.nanosec
+               if ns < 0 then
+                       s -= 1
+                       ns += 1000000000
+               end
+               return new Timespec(s, ns)
        end
 
        # Number of whole seconds of elapsed time.
@@ -117,15 +120,33 @@ extern class Timespec `{struct timespec*`}
 end
 
 # Keeps track of real time
+#
+# ~~~
+# var clock = new Clock
+#
+# # sleeping at least 1s
+# 1.0.sleep
+# assert clock.total >= 1.0
+# assert clock.lapse >= 1.0
+#
+# # sleeping at least 5ms
+# 0.005.sleep
+# assert clock.total >= 1.005
+# assert clock.lapse >= 0.005
+# ~~~
 class Clock
-       # Time at instanciation
+       super FinalizableOnce
+
+       # TODO use less mallocs
+
+       # Time at creation
        protected var time_at_beginning = new Timespec.monotonic_now
 
        # Time at last time a lapse method was called
        protected var time_at_last_lapse = new Timespec.monotonic_now
 
        # Smallest time frame reported by clock
-       fun resolution : Timespec `{
+       fun resolution: Timespec `{
                struct timespec* tv = malloc( sizeof(struct timespec) );
 #ifdef __MACH__
                clock_serv_t cclock;
@@ -142,18 +163,43 @@ class Clock
                return tv;
        `}
 
-       # Return timelapse since instanciation of this instance
-       fun total : Timespec
+       # Seconds since the creation of this instance
+       fun total: Float
        do
-               return new Timespec.monotonic_now - time_at_beginning
+               var now = new Timespec.monotonic_now
+               var diff = now - time_at_beginning
+               var r = diff.to_f
+               diff.free
+               now.free
+               return r
        end
 
-       # Return timelapse since last call to lapse
-       fun lapse : Timespec
+       # Seconds since the last call to `lapse`
+       fun lapse: Float
        do
                var nt = new Timespec.monotonic_now
                var dt = nt - time_at_last_lapse
+               var r = dt.to_f
+               dt.free
+               time_at_last_lapse.free
                time_at_last_lapse = nt
-               return dt
+               return r
+       end
+
+       # Seconds since the last call to `lapse`, without resetting the lapse counter
+       fun peek_lapse: Float
+       do
+               var nt = new Timespec.monotonic_now
+               var dt = nt - time_at_last_lapse
+               var r = dt.to_f
+               nt.free
+               dt.free
+               return r
+       end
+
+       redef fun finalize_once
+       do
+               time_at_beginning.free
+               time_at_last_lapse.free
        end
 end
index 4541428..3554d22 100644 (file)
@@ -55,7 +55,7 @@ end
 # then using a reference.
 class SerializerCache
        # Map of already serialized objects to the reference id
-       private var sent: Map[Serializable, Int] = new StrictHashMap[Serializable, Int]
+       protected var sent: Map[Serializable, Int] = new StrictHashMap[Serializable, Int]
 
        # Is `object` known?
        fun has_object(object: Serializable): Bool do return sent.keys.has(object)
@@ -88,7 +88,7 @@ end
 # Used by `Deserializer` to find already deserialized objects by their reference.
 class DeserializerCache
        # Map of references to already deserialized objects.
-       private var received: Map[Int, Object] = new StrictHashMap[Int, Object]
+       protected var received: Map[Int, Object] = new StrictHashMap[Int, Object]
 
        # Is there an object associated to `id`?
        fun has_id(id: Int): Bool do return received.keys.has(id)
index 4207a01..4e4a5b3 100644 (file)
@@ -128,7 +128,12 @@ redef class AModule
                srcs.add_all mmodule.ffi_files
 
                # Compiler options specific to this module
-               var ldflags = mmodule.ldflags[""].join(" ")
+               var ldflags_array = mmodule.ldflags[""]
+               if ldflags_array.has("-lrt") and system("sh -c 'uname -s 2>/dev/null || echo not' | grep Darwin >/dev/null") == 0 then
+                       # Remove -lrt on OS X
+                       ldflags_array.remove "-lrt"
+               end
+               var ldflags = ldflags_array.join(" ")
 
                # Protect pkg-config
                var pkgconfigs = mmodule.pkgconfigs
index a28ab28..70e648a 100755 (executable)
@@ -9,7 +9,6 @@ ls -1 -- "%s\n" "$@" \
        ../examples/*/src/*_android.nit \
        ../examples/*/src/*_linux.nit \
        ../examples/*/src/*_null.nit \
-       ../examples/nitcorn/src/*.nit \
        ../lib/*/examples/*.nit \
        ../lib/*/examples/*/*.nit \
        ../contrib/friendz/src/solver_cmd.nit \
index 571f594..4634f40 100644 (file)
@@ -40,3 +40,4 @@ test_ffi_c_lots_of_refs
 test_rubix_cube
 test_rubix_visual
 test_csv
+repeating_key_xor_solve
index 47cb8a0..a68b4cc 100644 (file)
@@ -40,3 +40,4 @@ test_ffi_c_lots_of_refs
 test_rubix_visual
 test_rubix_cube
 test_csv
+repeating_key_xor_solve
diff --git a/tests/repeating_key_xor_solve.args b/tests/repeating_key_xor_solve.args
new file mode 100644 (file)
index 0000000..2f6c9ff
--- /dev/null
@@ -0,0 +1 @@
+../lib/crapto/examples/repeating_key_xor_cipher.txt
diff --git a/tests/sav/repeating_key_xor_solve.res b/tests/sav/repeating_key_xor_solve.res
new file mode 100644 (file)
index 0000000..8a61309
--- /dev/null
@@ -0,0 +1 @@
+Usage: repeating_key_xor_solve <cipher_file>
diff --git a/tests/sav/repeating_key_xor_solve_args1.res b/tests/sav/repeating_key_xor_solve_args1.res
new file mode 100644 (file)
index 0000000..f81264e
--- /dev/null
@@ -0,0 +1,80 @@
+I'm back and I'm ringin' the bell 
+A rockin' on the mike while the fly girls yell 
+In ecstasy in the back of me 
+Well that's my DJ Deshay cuttin' all them Z's 
+Hittin' hard and the girlies goin' crazy 
+Vanilla's on the mike, man I'm not lazy. 
+
+I'm lettin' my drug kick in 
+It controls my mouth and I begin 
+To just let it flow, let my concepts go 
+My posse's to the side yellin', Go Vanilla Go! 
+
+Smooth 'cause that's the way I will be 
+And if you don't give a damn, then 
+Why you starin' at me 
+So get off 'cause I control the stage 
+There's no dissin' allowed 
+I'm in my own phase 
+The girlies sa y they love me and that is ok 
+And I can dance better than any kid n' play 
+
+Stage 2 -- Yea the one ya' wanna listen to 
+It's off my head so let the beat play through 
+So I can funk it up and make it sound good 
+1-2-3 Yo -- Knock on some wood 
+For good luck, I like my rhymes atrocious 
+Supercalafragilisticexpialidocious 
+I'm an effect and that you can bet 
+I can take a fly girl and make her wet. 
+
+I'm like Samson -- Samson to Delilah 
+There's no denyin', You can try to hang 
+But you'll keep tryin' to get my style 
+Over and over, practice makes perfect 
+But not if you're a loafer. 
+
+You'll get nowhere, no place, no time, no girls 
+Soon -- Oh my God, homebody, you probably eat 
+Spaghetti with a spoon! Come on and say it! 
+
+VIP. Vanilla Ice yep, yep, I'm comin' hard like a rhino 
+Intoxicating so you stagger like a wino 
+So punks stop trying and girl stop cryin' 
+Vanilla Ice is sellin' and you people are buyin' 
+'Cause why the freaks are jockin' like Crazy Glue 
+Movin' and groovin' trying to sing along 
+All through the ghetto groovin' this here song 
+Now you're amazed by the VIP posse. 
+
+Steppin' so hard like a German Nazi 
+Startled by the bases hittin' ground 
+There's no trippin' on mine, I'm just gettin' down 
+Sparkamatic, I'm hangin' tight like a fanatic 
+You trapped me once and I thought that 
+You might have it 
+So step down and lend me your ear 
+'89 in my time! You, '90 is my year. 
+
+You're weakenin' fast, YO! and I can tell it 
+Your body's gettin' hot, so, so I can smell it 
+So don't be mad and don't be sad 
+'Cause the lyrics belong to ICE, You can call me Dad 
+You're pitchin' a fit, so step back and endure 
+Let the witch doctor, Ice, do the dance to cure 
+So come up close and don't be square 
+You wanna battle me -- Anytime, anywhere 
+
+You thought that I was weak, Boy, you're dead wrong 
+So come on, everybody and sing this song 
+
+Say -- Play that funky music Say, go white boy, go white boy go 
+play that funky music Go white boy, go white boy, go 
+Lay down and boogie and play that funky music till you die. 
+
+Play that funky music Come on, Come on, let me hear 
+Play that funky music white boy you say it, say it 
+Play that funky music A little louder now 
+Play that funky music, white boy Come on, Come on, Come on 
+Play that funky music 
+
diff --git a/tests/sav/test_copy_to_native.res b/tests/sav/test_copy_to_native.res
new file mode 100644 (file)
index 0000000..764d170
--- /dev/null
@@ -0,0 +1 @@
+gâštr
diff --git a/tests/sav/test_copy_to_native_alt1.res b/tests/sav/test_copy_to_native_alt1.res
new file mode 100644 (file)
index 0000000..785cb5d
--- /dev/null
@@ -0,0 +1 @@
+gâštr%D
diff --git a/tests/sav/test_copy_to_native_alt2.res b/tests/sav/test_copy_to_native_alt2.res
new file mode 100644 (file)
index 0000000..ec88d9a
--- /dev/null
@@ -0,0 +1 @@
+gâštré
diff --git a/tests/sav/test_nativestring_fill_from.res b/tests/sav/test_nativestring_fill_from.res
new file mode 100644 (file)
index 0000000..2c26c70
--- /dev/null
@@ -0,0 +1 @@
+S&éstr
diff --git a/tests/sav/test_nativestring_fill_from_alt1.res b/tests/sav/test_nativestring_fill_from_alt1.res
new file mode 100644 (file)
index 0000000..0667158
--- /dev/null
@@ -0,0 +1 @@
+S&éstrS&éstr
diff --git a/tests/sav/test_nativestring_fill_from_alt2.res b/tests/sav/test_nativestring_fill_from_alt2.res
new file mode 100644 (file)
index 0000000..2c26c70
--- /dev/null
@@ -0,0 +1 @@
+S&éstr
diff --git a/tests/sav/test_nativestring_fill_from_alt3.res b/tests/sav/test_nativestring_fill_from_alt3.res
new file mode 100644 (file)
index 0000000..f28809f
--- /dev/null
@@ -0,0 +1 @@
+&éstr
diff --git a/tests/sav/test_realtime.res b/tests/sav/test_realtime.res
deleted file mode 100644 (file)
index 65b7078..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-sleeping 1s
-true
-true
-sleeping 5000ns
-true
-true
-true
similarity index 57%
rename from tests/test_realtime.nit
rename to tests/test_copy_to_native.nit
index 6101a3d..380c02a 100644 (file)
@@ -1,7 +1,5 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
 #
-# Copyright 2012 Alexis Laferrière <alexis.laf@xymus.net>
-#
 # 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
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import realtime
-
-redef extern class Timespec
-       fun simplify : Int
-       do
-               return sec*1000000 + nanosec/1000
-       end
-end
-
-var c = new Clock
-var t0 = c.total.simplify
-
-print "sleeping 1s"
-nanosleep(1, 0)
-print c.total.sec >= 1
-print c.lapse.sec >= 1
-
-var t1 = c.total.simplify
+import core
+#alt1 intrude import core::text::ropes
+#alt2 intrude import core::text::ropes
 
-print "sleeping 5000ns"
-nanosleep(0, 5000)
-print c.lapse.nanosec >= 5000
+var ons = new NativeString(9)
+var base_str = "%Dégâštr"
 
-var t2 = c.total.simplify
+var str: String = base_str
+#alt1 str = new Concat(base_str, base_str)
+#alt2 str = new Concat(base_str, base_str.substring_from(2))
 
-print t0 <= t1
-print t1 <= t2
+var copy_len = (str.bytelen - 4).min(9)
+str.copy_to_native(ons, copy_len, 4, 0)
+print ons.to_s_with_length(copy_len)
index 21728c1..a9f3e61 100644 (file)
@@ -21,12 +21,11 @@ var clock = new Clock
 var p = new Process("sleep", "10")
 
 # Send some signals
-p.signal(sigalarm)
+p.signal sigalarm
 p.kill
 
 # Wait for it to die
 p.wait
-var lapse = clock.lapse
 
 # Let's be generous here, as long as it does not take 5 secs out of 10 it's OK
-print lapse.sec < 5
+print clock.lapse < 5.0
diff --git a/tests/test_nativestring_fill_from.nit b/tests/test_nativestring_fill_from.nit
new file mode 100644 (file)
index 0000000..1b9e491
--- /dev/null
@@ -0,0 +1,27 @@
+# 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.
+
+#alt1 intrude import core::text::ropes
+import core
+
+var src_s = "S&éstr"
+var cpstr: Text = src_s
+#alt1 cpstr = new Concat(src_s, src_s)
+#alt2 cpstr = new FlatBuffer.from(src_s)
+#alt3 cpstr = cpstr.substring(1, 5)
+
+var ns = new NativeString(cpstr.bytelen)
+ns.fill_from(cpstr)
+
+print ns.to_s_with_length(cpstr.bytelen)
diff --git a/tests/test_postgres_nity.nit b/tests/test_postgres_nity.nit
new file mode 100644 (file)
index 0000000..9565335
--- /dev/null
@@ -0,0 +1,49 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2016 Guilherme Mansur <guilhermerpmansur@gmail.com>
+#
+# 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.
+
+module test_postgres_nity
+
+import postgresql::postgres
+
+var db = new Postgres.open("dbname=postgres")
+assert open_db: not db.is_closed else print db.error
+
+assert create_table: db.create_table("IF NOT EXISTS users (uname TEXT PRIMARY KEY, pass TEXT NOT NULL, activated INTEGER, perc FLOAT)") else
+  print db.error
+end
+
+assert insert1: db.insert("INTO users VALUES('Bob', 'zzz', 1, 77.7)") else
+  print db.error
+end
+
+assert insert2: db.insert("INTO users VALUES('Guilherme', 'xxx', 1, 88)") else
+  print db.error
+end
+
+var result = db.raw_execute("SELECT * FROM users")
+
+assert raw_exec: result.is_ok else print db.error
+
+assert postgres_nfields: result.nfields == 4 else print_error db.error
+assert postgres_fname: result.fname(0) == "uname" else print_error db.error
+assert postgres_isnull: result.is_null(0,0) == false else print_error db.error
+assert postgres_value: result.value(0,0) == "Bob" else print_error db.error
+
+assert drop_table: db.execute("DROP TABLE users") else print db.error
+
+db.finish
+
+assert db.is_closed else print db.error