diff --git a/code/projects/ao.cpp b/code/projects/ao.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..265a2780a1079d77bd299e88c7d00f0dacc99e88
--- /dev/null
+++ b/code/projects/ao.cpp
@@ -0,0 +1,265 @@
+
+#include <omp.h>
+#include <chrono>
+#include <random>
+#include <stdint.h>
+
+#include "options.h"
+
+#include "vec.h"
+#include "mat.h"
+
+#include "color.h"
+#include "image.h"
+#include "image_io.h"
+
+#include "gltf/gltf.h"
+#include "gltf/scene.h"
+#include "orbiter.h"
+
+#include "sampler.h"
+#include "sampler_sobol.h"
+
+//~ typedef Squares Sampler;
+typedef LCG Sampler;
+//~ typedef Sobol Sampler;
+//~ typedef SobolGray Sampler;
+//~ typedef Owen Sampler;
+//~ typedef OwenFast Sampler;
+//~ typedef FCRNG Sampler;
+
+Options options;
+
+
+Vector sample_k( const float u2, const float u3 )
+{
+    // genere une direction ~ 1 / 2pi
+    float phi= float(2*M_PI) * u2;
+    float cos_theta= u3;
+    float sin_theta= std::sqrt(1 - std::min(float(1.0), cos_theta*cos_theta));
+    return Vector(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta);
+}
+
+float pdf_k( const Vector&n, const Vector& v ) // global
+{
+    if(dot(n, v) < 0) return 0;
+    return 1 / float(2*M_PI);
+}
+
+Vector sample_cos( const float u2, const float u3 )
+{
+    // genere une direction ~ cos theta / pi
+    float phi= float(2*M_PI) * u2;
+    float cos_theta= std::sqrt(u3);
+    float sin_theta= std::sqrt(1 - std::min(float(1.0), cos_theta*cos_theta));
+    return Vector(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta);
+}
+
+float pdf_cos( const Vector&n, const Vector& v ) // global
+{
+    return std::max(float(0), dot(n, v)) / float(M_PI);
+}
+
+
+struct alpha_filter
+{
+    const Scene& scene;
+    FCRNG& rng;
+    
+    alpha_filter( const Scene& _scene, FCRNG& _rng ) : scene(_scene), rng(_rng) {}
+    
+    bool operator() ( const Hit& hit ) const
+    {
+        const GLTFMaterial& material= scene.material(hit);
+        if(material.color_texture == -1) 
+            return true;
+        if(scene.textures[material.color_texture].opaque)
+            return true;
+        
+        vec3 uv_lod= scene.texcoords_lod(hit);
+        Color diffuse= scene.textures[material.color_texture].sample(uv_lod.x, uv_lod.y, uv_lod.z);
+        
+        return (rng.sample() <= diffuse.a);
+    }
+};
+
+
+
+int main( const int argc, const char **argv )
+{
+    options= Options(argv, argv + argc);
+    
+    Scene scene= read_scene(options.filename);
+    if(scene.gltf.nodes.empty())
+        return 1;   // pas de geometrie, pas d'image
+    
+    // transformations 
+    Transform view;
+    Transform view_inv;
+    Transform projection;
+    float aspect= 1;
+    
+    if(options.orbiter_filename)
+    {
+        Orbiter camera;
+        if(camera.read_orbiter(options.orbiter_filename) == false)
+            return 1;    // pas de camera, pas d'image
+        
+        view= camera.view();
+        view_inv= Inverse(view);
+        projection= camera.projection();
+        aspect= camera.aspect();
+    }
+    else if(scene.gltf.cameras.size())
+    {
+        view= scene.camera.view;
+        view_inv= Inverse(scene.camera.view);
+        projection= scene.camera.projection;
+        aspect= scene.camera.aspect;
+    }
+    else
+       return 1;   // pas de camera, pas d'image
+    
+    // proportions largeur/hauteur de la camera gltf
+    int samples= options.samples;
+    int width= 1024;
+    int height= width / aspect;
+    Image image(width, height);
+    Image aov_normal(width, height);
+    Image aov_albedo(width, height);
+    
+    // charge les textures + parametres de filtrage en fonction de l'image
+    read_textures(options.filename, scene, width, height);
+    //~ read_textures(options.filename, scene, 256, 256);
+    
+    // 
+    printf("glTF lights %d\n", int(scene.gltf.lights.size()));
+    
+
+    // 
+    Transform viewport= Viewport(image.width(), image.height());
+    Transform inv= Inverse(viewport * projection * view);
+    
+    int lines= 0;
+    auto cpu_start= std::chrono::high_resolution_clock::now();
+    
+    // c'est parti ! parcours tous les pixels de l'image
+#pragma omp parallel for schedule(dynamic, 1)
+    for(int py= 0; py < image.height(); py++)
+    {
+    #pragma omp atomic
+        lines++;
+        
+        if(omp_get_thread_num() == 0)
+        {
+            printf("%d/%d %d%%...\r", lines, image.height(), 100 * lines / image.height());
+            fflush(stdout);
+        }
+        
+        for(int px= 0; px < image.width(); px++)
+        {
+            const unsigned seed= (py * image.width() + px) * samples * 127;
+            Sampler rng( seed );
+            FCRNG alpha_rng( seed );
+            
+            Color color;
+            Vector normal;
+            Color albedo;
+            
+            for(int i= 0; i < samples; i++)
+            {
+                rng.index(i);
+                float x= rng.sample();
+                float y= rng.sample();
+                
+                // generer le rayon
+                Point origine= inv(Point(px + x, py + y, 0));
+                Point extremite= inv(Point(px + x, py + y, 1));
+                Ray ray(origine, extremite);
+                
+                // calculer les intersections avec tous les triangles
+                if(Hit hit= scene.bvh.intersect(ray, alpha_filter(scene, alpha_rng)))                
+                {
+                    Point p= scene.position(hit, ray);
+                    Vector pn= scene.normal(hit);
+                    
+                    // matiere emissive, si la source est orientee vers la camera
+                    if(dot(pn, ray.d) < 0)
+                    {
+                        const GLTFMaterial& material= scene.material(hit);
+                        color= color + material.emission;
+                        // suppose que les normales des sources sont correctes...
+                    }
+                    
+                    if(dot(pn, ray.d) > 0)
+                        // mais ce n'est pas toujours le cas pour le reste de la geometrie...
+                        pn= -pn;
+                    
+                    // eclairage ambiant
+                    Brdf brdf= scene.brdf(hit, pn);
+                    {
+                        World world(pn);
+                        // genere une direction ~ cos / pi
+                        Vector l= world( sample_cos(rng.sample(), rng.sample()) );
+                        float pdf= pdf_cos(pn, l);
+                        
+                        //~ // genere une direction ~ 1/2pi
+                        //~ Vector l= world( sample_k(rng.sample(), rng.sample()) );
+                        //~ float pdf= pdf_k(pn, l);
+                        
+                        //~ // genere la direction en fonction de la matiere
+                        //~ Vector l= brdf.sample(rng.sample(), rng.sample(), rng.sample(), normalize(ray.o - p));
+                        //~ float pdf= brdf.pdf(l, normalize(ray.o - p));
+                        
+                        if(pdf == 0)
+                        {
+                            color= color + Black();
+                            //~ color= color + Red();   // compte les echantillons qui n'ont pas reussit a generer une direction "valide"
+                        }
+                        else 
+                            if( dot(l, Vector(0, 1, 0)) > 0 && scene.visible( offset_point(p, pn), l) )
+                            {
+                                // V= 1;
+                                Color fr= brdf.f(l, normalize(ray.o - p));
+                                float cos_theta= std::max(float(0), dot(pn, l));
+                                
+                                color= color + fr * cos_theta / pdf;
+                                //~ color= color + Black();
+                            }
+                    }
+                    
+                    normal= normal + pn;
+                    albedo= albedo + brdf.f(pn, normalize(ray.o - p));
+                }
+            }
+            
+            image(px, py)= Color(color / float(samples), 1);    // force une couleur opaque...
+            aov_normal(px, py)= Color(normal / float(samples), 1);    // force une couleur opaque...
+            aov_albedo(px, py)= Color(albedo / float(samples), 1);    // force une couleur opaque...
+        }
+    }
+
+    auto cpu_stop= std::chrono::high_resolution_clock::now();
+    auto cpu_time= std::chrono::duration_cast<std::chrono::milliseconds>(cpu_stop - cpu_start).count();
+    printf("cpu  %ds %03dms\n", int(cpu_time / 1000), int(cpu_time % 1000));
+    
+    char tmp[1024];
+    //~ sprintf(tmp, "%s-%05u-%04u.png", options.prefix, unsigned(cpu_time), samples);
+    sprintf(tmp, "%s-%04u.png", options.prefix, samples);
+    printf("writing '%s'...\n", tmp);
+    write_image_preview(image, tmp);
+    
+    //~ sprintf(tmp, "%s-%05u-%04u.pfm", options.prefix, unsigned(cpu_time), samples);
+    sprintf(tmp, "%s-%04u.pfm", options.prefix, samples);
+    printf("writing '%s'...\n", tmp);
+    write_image_pfm(image, tmp);
+    
+    sprintf(tmp, "%s-normals-%04u.pfm", options.prefix, samples);
+    write_image_pfm(aov_normal, tmp);
+    
+    sprintf(tmp, "%s-albedo-%04u.pfm", options.prefix, samples);
+    write_image_pfm(aov_albedo, tmp);
+    printf("\n");
+    
+    return 0;
+}
diff --git a/code/projects/errors.cpp b/code/projects/errors.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7e27b825d0647a0092d51580a696f5f43bbe5342
--- /dev/null
+++ b/code/projects/errors.cpp
@@ -0,0 +1,326 @@
+
+#include <cstdio>
+#include <cstring>
+#include <cfloat>
+#include <algorithm>
+
+
+#include "image.h"
+#include "image_io.h"
+
+
+struct cell
+{
+    Image image;
+    
+    const char *filename;
+    const char *title;
+
+    int x, y;
+    int nspp;
+    int time;
+};
+
+
+// 
+int render_nspp( const char *filename )
+{
+    int n= -1;
+    
+    // suppose que le nom de fichier est de la forme 'prefix-nspp.[pfm|png]'
+    const char *ext= strrchr(filename, '.');
+    if(ext)
+    {
+        if(strcmp(ext, ".pfm") == 0 || strcmp(ext, ".png") == 0 )
+        {
+            const char *last= strrchr(filename, '-');
+            if(sscanf(last, "-%d.", &n) == 1)
+                return n;
+        }
+    }
+    
+    printf("\n[error] filename '%s'... doesn't match 'prefix-nspp.[pfm|png]'\n", filename);
+    return 0;
+}
+
+
+unsigned render_time( const char *filename )
+{
+    unsigned d= 0;
+    
+    // suppose que le nom de fichier est de la forme 'prefix-time-nspp.[pfm|png]'
+    const char *ext= strrchr(filename, '.');
+    if(ext)
+    {
+        if(strcmp(ext, ".pfm") == 0 || strcmp(ext, ".png") == 0 )
+        {
+            char tmp[1024];
+            strcpy(tmp, filename);
+            char *last= strrchr(tmp, '-');
+            if(last)
+            {
+                *last= 0;
+                const char *prev= strrchr(tmp, '-');
+                if(prev)
+                {
+                    if(sscanf(prev, "-%d", &d) == 1)
+                        return d;
+                }
+            }
+        }
+    }
+    
+    //~ printf("\n[warning] filename '%s'... doesn't match 'prefix-time-nspp.[pfm|png]'\n", filename);
+    return 0;
+}
+
+
+// mse d'une vignette 
+std::pair<double, double> Mlocal( /* ref */ const Image &A, /* image */ const Image &B,
+    int mX, int mY,
+    int MX, int MY ,
+    double &vmin, double &vmax)
+{
+    double val= 0.0;
+    double var= 0.0;
+    vmax= -1.0;
+    vmin= 100000.0;
+    
+    int cpt= 0;
+    for(int i=mX; i <= MX; ++i)
+    for(int j=mY; j <= MY; ++j)
+    {
+        Color d= A(i, j) - B(i, j);
+        double v= (std::abs(d.r) + std::abs(d.g) + std::abs(d.b)) / 3;
+        
+        vmax= std::max(vmax, v);
+        // ne compte pas les pixels noirs
+        Color pixel= A(i, j);
+        if(pixel.r + pixel.g + pixel .b  > 0) 
+            vmin= std::min(vmin, v); 
+        
+        val += v;
+        var += v*v;
+        cpt++;
+    }
+    
+    val /= double(cpt);
+    var /= double(cpt);
+    var= (var - val*val);
+    return std::make_pair(val, var);
+}
+
+
+Image read( const char *filename )
+{
+    if(pfm_image(filename))
+        return read_image_pfm(filename);
+        
+    return read_image(filename);
+}
+
+
+/*! renvoie le chemin d'acces a un fichier. le chemin est toujours termine par /
+    pathname("path/to/file") == "path/to/"
+    pathname("file") == "./"
+ */
+std::string path_name( const std::string& filename )
+{
+    std::string path= filename;
+#ifndef WIN32
+    std::replace(path.begin(), path.end(), '\\', '/');   // linux, macos : remplace les \ par /.
+    size_t slash = path.find_last_of( '/' );
+    if(slash != std::string::npos)
+        return path.substr(0, slash +1); // inclus le slash
+    else
+        return "./";
+#else
+    std::replace(path.begin(), path.end(), '/', '\\');   // windows : remplace les / par \.
+    size_t slash = path.find_last_of( '\\' );
+    if(slash != std::string::npos)
+        return path.substr(0, slash +1); // inclus le slash
+    else
+        return ".\\";
+#endif
+}
+
+
+std::string normalize_path( const std::string& file )
+{
+    std::string tmp= file;
+    
+#ifndef WIN32
+    std::replace(tmp.begin(), tmp.end(), '\\', '/');   // linux, macos : remplace les \ par /.
+#else
+    std::replace(tmp.begin(), tmp.end(), '/', '\\');   // windows : remplace les / par \.
+#endif
+    return tmp;
+}
+
+std::string base_name( const std::string& filename )
+{
+    std::string nfilename= normalize_path(filename);
+    size_t slash = nfilename.find_last_of( '/' );
+    if(slash != std::string::npos)
+        return nfilename.substr(slash +1);
+    else
+        return nfilename;
+}
+
+std::string change_extension( const std::string& filename, const std::string& ext )
+{
+    size_t pos= filename.rfind(".");
+    
+    return filename.substr(0, pos).append(ext);
+}
+
+std::string change_prefix( const std::string& prefix, const std::string& filename )
+{
+    std::string path= path_name(filename);
+    std::string file= base_name(filename);
+    
+    path.append(prefix).append(file);
+    return path;
+}
+
+
+int main( int argc, const char *argv[] )
+{
+    if(argc < 2)
+    {
+        printf("usage: %s reference.[pfm|png] --line 1 [--title \"...\"] image.[pfm|png] [--line 2 images --line 3 images] \n", argv[0]);
+        return 0;
+    }
+    
+    //
+    Image reference;
+    if(argc > 1)
+        reference= read(argv[1]);
+        
+    if(reference.size() == 0)
+    {
+        printf("[error] loading reference image '%s'...\n", argv[1]);
+        return 1;
+    }
+    
+    // charge les images
+    int rows= 0;
+    int columns= 0;
+    std::vector< std::vector<cell> > grid;
+    {
+        std::vector<cell> cells;
+        
+        int x= 0;
+        int y= -1;
+        int last_row= -1;
+        const char *last_title= nullptr;
+        
+        for(int option= 2; option < argc; )
+        {
+            if(argv[option][0] == '-')
+            {
+                // nouvelle ligne
+                if(strcmp(argv[option], "--line") == 0 && option +1 < argc)
+                {
+                    int row= 0;
+                    if(sscanf(argv[option+1], "%d", &row) != 1)
+                        break;
+                    
+                    x= 0;
+                    //~ y++;
+                    y= row -1;
+                    option+= 2;
+                    
+                    printf("line %d\n", row);
+                }
+                else if(strcmp(argv[option], "--title") == 0 && option +1 < argc)
+                {
+                    last_title= argv[option+1];
+                    option+= 2;
+                }
+                else
+                {
+                    printf("[error] parsing option '%s'...\n", argv[option]);
+                    return 1;
+                }
+            }
+            else
+            {
+                const char *filename= argv[option];
+                int n= render_nspp(filename);
+                int render= render_time(filename);
+                cells.push_back( {Image(), filename, last_title, x, y, n, render} );
+                
+                printf("x %d y %d: '%s' %s, nspp %d, render %dms\n", x, y, last_title, filename, n, render);
+                
+                x++;
+                option++;
+            }
+        }
+        
+        // chargement parallele des images
+    #pragma omp parallel for
+        for(int i= 0; i < int(cells.size()); i++)
+            cells[i].image= read(cells[i].filename);
+        
+        // dimensions de la grille
+        for(auto const & cell : cells)
+        {
+            rows= std::max(rows, cell.y +1);
+            columns= std::max(columns, cell.x +1);
+        }
+        
+        // cree la grille
+        grid.resize(rows);
+        for(int i= 0; i < rows; i++)
+            grid[i].resize(columns);
+        
+        // copie les images a leur place
+        for(auto const & cell : cells)
+        {
+            int x= cell.x;
+            int y= cell.y;
+            assert(x < columns);
+            assert(y < rows);
+            grid[y][x]= cell;   // move ?
+        }
+    }
+    
+    // mse global
+#pragma omp parallel for schedule(dynamic, 1)
+    for(int r= 0; r < rows; r++)
+    {
+        if(!grid[r][0].title)
+            continue;
+        
+        printf("mse %s\n", grid[r][0].title);
+        char filename[1024];
+        sprintf(filename, "%smse_%s.txt", path_name(grid[r][0].filename).c_str(), grid[r][0].title);
+        
+        //~ printf("mse file '%s'\n", filename);
+        FILE *out= fopen(filename, "wt");
+        if(out)
+        {
+            printf("writing '%s'...\n", filename);
+            
+            //~ fprintf(out, "# %s\n", grid[r][0].title);
+            fprintf(out, "#Nbpts    #Mean   #Min    #Max\n");
+            for(int c= 0; c < columns; c++)
+            {
+                if(grid[r][c].image.size() == 0)
+                    continue;
+                    
+                double vmin, vmax;
+                std::pair<double, double> stat= Mlocal(reference, grid[r][c].image, 0, 0, grid[r][c].image.width()-1, grid[r][c].image.height()-1, vmin, vmax);
+                
+                double mse= stat.first;
+                fprintf(out, "%d %.15f %.15f %.15f\n", grid[r][c].nspp, mse, vmin, vmax);
+                //~ fprintf(out, "%d %.15f %.15f %.15f\n", grid[r][c].time, mse, vmin, vmax);
+            }
+            
+            fclose(out);
+        }
+    }
+    
+    return  0;
+}
diff --git a/code/projects/options.h b/code/projects/options.h
new file mode 100644
index 0000000000000000000000000000000000000000..42b04ca17072f467d6dd481b06b462ac1618f519
--- /dev/null
+++ b/code/projects/options.h
@@ -0,0 +1,167 @@
+
+#ifndef _OPTIONS_H
+#define _OPTIONS_H
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+#include <vector>
+
+
+struct Options
+{
+    const char *filename= nullptr;
+    const char *orbiter_filename= nullptr;
+    const char *prefix= "image";
+    int samples= 32;
+    int depth= 1;
+    
+    Options( const char **begin, const char **end ) : options(begin, end)
+    {
+        if(options.size() > 1)
+        {
+            filename= option(1, filename);
+            filename= value("--scene", filename);
+            orbiter_filename= value("--camera", orbiter_filename);
+            
+            prefix= value("--prefix", prefix);
+            samples= value_int("-s", "32");
+            depth= value_int("--lenght", "1");
+        }
+        
+        if(options.size() == 1 || flag("--help") || flag("-h") || flag("--verbose") || flag("-v"))
+        {
+            printf("filename: '%s'\n", filename);
+            printf("camera: '%s'\n", orbiter_filename);
+            printf("output prefix: '%s'\n", prefix);
+            printf("samples: %u\n", samples);
+            printf("path lenght: %u\n", depth);
+        }
+    }
+    
+    
+    Options() = default;
+    Options( const Options& ) = delete;
+    Options& operator= ( const Options& ) = default;
+    
+    // option placee
+    const char *option( const unsigned position, const char *default_value )
+    {
+        if(position >= options.size())
+            return default_value;
+        if(options[position] == nullptr)
+            return default_value;
+        
+        const char *value= options[position];
+        if(value[0] == '-')
+        {
+            printf("invalid option: [%u] = '%s'\n", position, value);
+            exit(1);
+        }
+        
+        options[position]= nullptr;
+        return value;
+    }
+    
+    // recherche des options
+    int find( const char *name )
+    {
+        for(int i= 0; i < int(options.size()); i++)
+            if(options[i] && std::string(options[i]) == std::string(name))
+                return i;
+        return -1;
+    }
+
+    // cherche un flag, renvoie un bool
+    bool flag( const char *name )
+    {
+        int index= find(name);
+        if(index != -1)
+            options[index]= nullptr;
+        
+        return (index != -1);
+    }
+
+    int find_value( const char *name, const int n= 1 )
+    {
+        int index= find(name);
+        if(index < 0 || index + n >= int(options.size()))
+            return -1;
+        
+        for(int i= index; i <= index + n; i++)
+            if(options[i] == nullptr)
+                return -1;
+        return index;
+    }
+    
+    // cherche une option et renvoie sa valeur ou la valeur par defaut
+    const char *value( const char *name, const char *default_value )
+    {
+        int index= find_value(name, 1);
+        if(index < 0)
+            return default_value;
+        
+        const char *tmp= options[index+1];
+        options[index]= nullptr;
+        options[index+1]= nullptr;
+        return tmp;
+    }
+
+    // cherche une option, renvoie un int
+    int value_int( const char *name, const char *default_value )
+    {
+        const char *str= value(name, default_value);
+        
+        int v= 0;
+        if(sscanf(str, "%d", &v) == 1)
+            return v;
+        
+        // erreur parametre invalide.
+        printf("invalid int parameter: %s = '%s'\n", name, str);
+        
+        exit(1);
+        return 0;
+    }
+    
+    // cherche une option, renvoie un unsigned long int 
+    size_t value_long( const char *name, const char *default_value )
+    {
+        const char *str= value(name, default_value);
+        
+        unsigned long int v= 0;
+        if(sscanf(str, "%lu", &v) == 1)
+            return v;
+        
+        // erreur parametre invalide.
+        printf("invalid int parameter: %s = '%s'\n", name, str);
+        
+        exit(1);
+        return 0;
+    }
+
+    // cherche une option, renvoie un bool
+    bool value_bool( const char *name, const char *default_value )
+    {
+        const char *str= value(name, default_value);
+        if(std::string(str) == "true" || std::string(str) == "on" || std::string(str) == "1")
+            return true;
+        if(std::string(str) == "false" || std::string(str) == "off" || std::string(str) == "0")
+            return false;
+        
+        // erreur parametre invalide.
+        printf("invalid bool parameter: %s = '%s'\n", name, str);
+        
+        exit(1);
+        return false;
+    }
+    
+protected:
+    std::vector<const char *> options = std::vector<const char *>();
+};
+
+extern Options options;
+
+#endif
+    
+    
diff --git a/code/projects/owen_fast.h b/code/projects/owen_fast.h
new file mode 100644
index 0000000000000000000000000000000000000000..17f93d18e2edebbdf82332060f1f3f37a33e920b
--- /dev/null
+++ b/code/projects/owen_fast.h
@@ -0,0 +1,115 @@
+
+#ifndef OWEN_FAST_H
+#define OWEN_FAST_H
+
+#include <cstdint>
+
+
+// renvoie 0 ou 1, valeur du ieme bit de x
+inline unsigned owen_bit( const unsigned x, const unsigned position )
+{
+    return (x >> position) & 1u;
+}
+
+
+// permute les bits 0 .. 31 de a
+// meme construction que OwenScrambler de pbrt 4, mais plus decompose, plus lisible et plus rapide... 
+// cf https://github.com/mmp/pbrt-v4/blob/39e01e61f8de07b99859df04b271a02a53d9aeb2/src/pbrt/util/lowdiscrepancy.h#L240
+unsigned owen_scramble( const unsigned a, const unsigned seed )
+{
+    FCRNG rng(seed);
+
+    // 
+    unsigned node_index= 0;
+    unsigned flip= rng.index(node_index).sample_range(2);
+    unsigned digit= owen_bit(a, 31);
+    unsigned b= (digit ^ flip) << 31;
+    
+    for(unsigned i= 1; i < 32; i++)
+    {
+        node_index= 2*node_index + digit +1;
+        // heap layout, root i= 0, left 2i+1, right 2i+2
+        
+        flip= rng.index(node_index).sample_range(2);
+        digit= owen_bit(a, 31 - i);
+        b= b | (digit ^ flip) << (31 - i);
+    }
+    
+    return b;
+}
+
+// permutation inverse
+unsigned owen_inverse_scramble( const unsigned b, const unsigned seed )
+{
+    FCRNG rng(seed);
+    
+    //
+    unsigned node_index= 0;
+    unsigned flip= rng.index(node_index).sample_range(2);
+    unsigned digit= owen_bit(b, 31) ^ flip;
+    unsigned a= digit << 31;
+    
+    for(unsigned i= 1; i < 32; i++)
+    {
+        node_index= 2*node_index + digit +1;
+        // heap layout, root i= 0, left 2i+1, right 2i+2
+        
+        unsigned flip= rng.index(node_index).sample_range(2);
+        digit= owen_bit(b, 31 - i) ^ flip;
+        a= a | digit << (31 - i);
+    }
+    
+    return a;
+}
+
+
+// permute les bits 0 .. nbits de a
+unsigned owen_scramble( const unsigned a, const unsigned seed, const unsigned nbits )
+{
+    FCRNG rng(seed);
+    
+    // 
+    unsigned node_index= 0;
+    unsigned flip= rng.index(node_index).sample_range(2);
+    unsigned digit= owen_bit(a, nbits);
+    unsigned b= (digit ^ flip) << nbits;
+    
+    for(unsigned i= 1; i < nbits+1; i++)
+    {
+        node_index= 2*node_index + digit +1;
+        // heap layout, root i= 0, left 2i+1, right 2i+2
+        
+        unsigned flip= rng.index(node_index).sample_range(2);
+        digit= owen_bit(a, nbits - i);
+        b= b | (digit ^ flip) << (nbits - i);
+    }
+    
+    return b;
+}
+
+
+// cf FastOwenScrambler, pbrt 4
+// https://github.com/mmp/pbrt-v4/blob/39e01e61f8de07b99859df04b271a02a53d9aeb2/src/pbrt/util/lowdiscrepancy.h#L221
+inline unsigned reverse_bits( unsigned n ) 
+{
+    n = (n << 16) | (n >> 16);
+    n = ((n & 0x00ff00ff) << 8) | ((n & 0xff00ff00) >> 8);
+    n = ((n & 0x0f0f0f0f) << 4) | ((n & 0xf0f0f0f0) >> 4);
+    n = ((n & 0x33333333) << 2) | ((n & 0xcccccccc) >> 2);
+    n = ((n & 0x55555555) << 1) | ((n & 0xaaaaaaaa) >> 1);
+    return n;
+}
+
+// permute tous les bits directement.
+unsigned owen_scramble_fast4( const unsigned a, const unsigned seed )
+{
+    unsigned v= reverse_bits(a);
+    v ^= v * 0x3d20adea;
+    v += seed;
+    v *= (seed >> 16) | 1;
+    v ^= v * 0x05526c56;
+    v ^= v * 0x53a22864;
+    return reverse_bits(v);
+}
+
+#endif
diff --git a/code/projects/path.cpp b/code/projects/path.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8b4cc7692e6b66bcc823604f227a8f61f86fe68d
--- /dev/null
+++ b/code/projects/path.cpp
@@ -0,0 +1,372 @@
+
+
+#include <omp.h>
+#include <chrono>
+#include <random>
+#include <stdint.h>
+
+#include "options.h"
+
+#include "vec.h"
+#include "mat.h"
+
+#include "color.h"
+#include "image.h"
+#include "image_io.h"
+
+#include "gltf/gltf.h"
+#include "gltf/scene.h"
+#include "orbiter.h"
+
+#include "sampler.h"
+#include "sampler_sobol.h"
+
+//~ typedef Squares Sampler;
+typedef LCG Sampler;
+//~ typedef Sobol Sampler;
+//~ typedef SobolGray Sampler;
+//~ typedef Owen Sampler;
+//~ typedef OwenFast Sampler;
+//~ typedef FCRNG Sampler;
+
+Options options;
+
+
+Color direct( const Point& o, const Point& p, const Brdf& pbrdf, const Scene& scene, Sampler& rng )
+{
+    Color color;
+    
+    /* strategie 1 : genere un point sur une source
+     */
+    const Source& source= scene.sources.sample( rng.sample() );
+    Point s= source.sample( rng.sample(), rng.sample() );
+    Vector sn= source.n;
+    
+    Vector l= normalize( Vector(p, s) );
+    float cos_theta= std::max(float(0), dot(pbrdf.world.n, l));
+    float cos_theta_s= std::max(float(0), dot(sn, -l));
+    float G= cos_theta_s / distance2(p, s);
+    float pdf= source.pdf(s) * scene.sources.pdf(source);
+    
+    if(pdf * cos_theta * cos_theta_s > 0
+    && scene.visible( offset_point(p, pbrdf.world.n), offset_point(s, sn) ))
+    {
+        Color fr= pbrdf.f(l, normalize(o - p));
+        color= color + source.emission * G * fr * cos_theta / pdf;
+    }
+    
+    /* strategie 2 : genere une direction en fonction de la matiere
+        
+        Vector l= pbrdf.sample( rng.sample(), rng.sample(), rng.sample(), normalize(o - p));
+        float pdf= pbrdf.pdf( l, normalize(o - p) );
+        float cos_theta= std::max(float(0), dot(pbrdf.world.n, l));
+        if(pdf * cos_theta > 0
+        && scene.visible(offset_point(p, pbrdf.world.n), l))
+        {
+            Color fr= pbrdf.f(l, normalize(o - p));
+            color= color + Color(0.02) * fr * cos_theta / pdf;
+        }
+    */
+    
+    return color;
+}
+
+// mis multi-sample, evalue les 2 integrales + ponderation de chaque echantillon
+Color direct_mis( const Point& o, const Point& p, const Brdf& pbrdf, Hit& qhit, const Scene& scene, Sampler& rng )
+{
+    Color color;
+    
+    // strategie 1 : selectionne une source + un point sur la source
+    {
+        const Source& source= scene.sources.sample( rng.sample() );
+        Point s= source.sample( rng.sample(), rng.sample() );
+        
+        Vector sn= source.n;
+        Vector l= normalize( Vector(p, s) );
+        float cos_theta= std::max(float(0), dot(pbrdf.world.n, l));
+        float cos_theta_s= std::max(float(0), dot(sn, -l));
+        float G= cos_theta_s / distance2(p, s);
+        if(G * cos_theta > 0)
+        {
+            float pdf1= source.pdf(s) * scene.sources.pdf(source);
+            if(pdf1 > 0)
+            {
+                if(scene.visible( offset_point(p, pbrdf.world.n), offset_point(s, sn) ) )
+                {
+                    float pdf2= pbrdf.pdf(l, normalize( Vector(p, o) )) * G;
+                    float w= (pdf1*pdf1) / (pdf1*pdf1 + pdf2*pdf2); // pdf1 et pdf2 sur les aires, power heuristic
+                    
+                    Color fr= pbrdf.f(l, normalize(o - p));
+                    color= color + w * source.emission * fr * G * cos_theta / pdf1;
+                }
+            }
+        }
+    }
+    
+    // strategie 2 : selectionne un terme de la brdf et genere une direcion
+    {
+        Vector l= pbrdf.sample( rng.sample(), rng.sample(), rng.sample(), normalize(o - p) );
+        float pdf2= pbrdf.pdf(l, normalize(o - p) );
+        if(pdf2 > 0)
+        {
+            Ray ray( offset_point(p, pbrdf.world.n), l );
+            if(Hit hit= scene.intersect(ray))
+            {
+                Color emission= scene.material(hit).emission;
+                if(emission.max() > 0)
+                {
+                    Point s= ray.o + ray.d * hit.t;
+                    Vector sn= scene.normal(hit);
+                    float cos_theta= std::max(float(0), dot(pbrdf.world.n, l));
+                    float cos_theta_s= std::max(float(0), dot(sn, -l));
+                    float G= cos_theta_s / distance2(p, s);
+                    if(G * cos_theta > 0)
+                    {
+                        pdf2= pdf2 * G;
+                        float pdf1= 1 / scene.sources.area;
+                        float w= (pdf2*pdf2) / (pdf1*pdf1 + pdf2*pdf2); // pdf1 et pdf2 sur les aires, power heuristic
+                        
+                        Color fr= pbrdf.f(l, normalize(o - p));
+                        color= color + w * emission * fr * G * cos_theta / pdf2;
+                    }
+                }
+                else
+                    // conserve le point pour prolonger le chemin...
+                    qhit= hit;
+            }
+        }
+    }
+    
+    return color;
+}
+
+
+Color path( const int depth, const Point& o, const Point& p, const Brdf& pbrdf, const Scene& scene, Sampler& rng )
+{
+    Hit qhit;
+    
+    //~ Color color= direct(o, p, pbrdf, scene, rng );
+    Color color= direct_mis(o, p, pbrdf, qhit, scene, rng );
+    if(depth == 0)
+        return color;
+    
+    // recuperer l'intersection mis du direct... cf direct_mis, elimine un rayon par rebond
+    if(qhit)
+    {
+        Point q= scene.position(qhit);
+        Vector l= normalize(q - p);
+        float pdf= pbrdf.pdf(l, normalize(o - p));
+        if(pdf > 0) // ne devrait pas arriver...
+        {
+            Vector qn= scene.normal(qhit);
+            Brdf qbrdf= scene.brdf(qhit, qn);
+            
+            float cos_theta= std::max(float(0), dot(pbrdf.world.n, l));
+            Color fr= pbrdf.f(l, normalize(o - p));
+            return color + path(depth -1, p, q, qbrdf, scene, rng) * fr * cos_theta / pdf;
+        }
+    }
+    
+    /* sinon genere une direction pour prolonger le chemin...
+        Vector l= pbrdf.sample( rng.sample(), rng.sample(), rng.sample(), normalize(o - p) );
+        float pdf= pbrdf.pdf(l, normalize(Vector(p, o)));
+        if(pdf > 0)
+        {
+            Ray ray( offset_point(p, pbrdf.world.n), l );
+            if(Hit hit= scene.intersect(ray))
+            {
+                Point q= scene.position(hit, ray);
+                Vector qn= scene.normal(hit);
+                Brdf qbrdf= scene.brdf(hit, qn);
+                
+                float cos_theta= std::max(float(0), dot(pbrdf.world.n, l));
+                Color fr= pbrdf.f(l, normalize(o - p));
+                return color + path(depth -1, p, q, qbrdf, scene, rng) * fr * cos_theta / pdf;
+            }
+        }
+    */
+    
+    return color;
+}
+
+
+
+struct alpha_filter
+{
+    const Scene& scene;
+    FCRNG& rng;
+    
+    alpha_filter( const Scene& _scene, FCRNG& _rng ) : scene(_scene), rng(_rng) {}
+    
+    bool operator() ( const Hit& hit ) const
+    {
+        const GLTFMaterial& material= scene.material(hit);
+        if(material.color_texture == -1) 
+            return true;
+        if(scene.textures[material.color_texture].opaque)
+            return true;
+        
+        vec3 uv_lod= scene.texcoords_lod(hit);
+        Color diffuse= scene.textures[material.color_texture].sample(uv_lod.x, uv_lod.y, uv_lod.z);
+        
+        return (rng.sample() <= diffuse.a);
+    }
+};
+
+
+
+int main( const int argc, const char **argv )
+{
+    options= Options(argv, argv + argc);
+    
+    Scene scene= read_scene(options.filename);
+    if(scene.gltf.nodes.empty())
+        return 1;   // pas de geometrie, pas d'image
+    
+    // transformations 
+    Transform view;
+    Transform view_inv;
+    Transform projection;
+    float aspect= 1;
+    
+    if(options.orbiter_filename)
+    {
+        Orbiter camera;
+        if(camera.read_orbiter(options.orbiter_filename) == false)
+            return 1;    // pas de camera, pas d'image
+        
+        view= camera.view();
+        view_inv= Inverse(view);
+        projection= camera.projection();
+        aspect= camera.aspect();
+    }
+    else if(scene.gltf.cameras.size())
+    {
+        view= scene.camera.view;
+        view_inv= Inverse(scene.camera.view);
+        projection= scene.camera.projection;
+        aspect= scene.camera.aspect;
+    }
+    else
+       return 1;   // pas de camera, pas d'image
+    
+    // proportions largeur/hauteur de la camera gltf
+    int samples= options.samples;
+    int width= 1024;
+    int height= width / aspect;
+    Image image(width, height);
+    Image aov_normal(width, height);
+    Image aov_albedo(width, height);
+    
+    // charge les textures + parametres de filtrage en fonction de l'image
+    read_textures(options.filename, scene, width, height);
+    //~ read_textures(options.filename, scene, 256, 256);
+    
+    // 
+    printf("glTF lights %d\n", int(scene.gltf.lights.size()));
+    
+
+    // 
+    Transform viewport= Viewport(image.width(), image.height());
+    Transform inv= Inverse(viewport * projection * view);
+    
+    unsigned maxdims= 0;
+    unsigned lines= 0;
+    auto cpu_start= std::chrono::high_resolution_clock::now();
+    
+    // c'est parti ! parcours tous les pixels de l'image
+#pragma omp parallel for schedule(dynamic, 1)
+    for(int py= 0; py < image.height(); py++)
+    {
+    #pragma omp atomic
+        lines++;
+        
+        if(omp_get_thread_num() == 0)
+        {
+            printf("%d/%d %d%%...\r", lines, image.height(), 100 * lines / image.height());
+            fflush(stdout);
+        }
+        
+        for(int px= 0; px < image.width(); px++)
+        {
+            const unsigned seed= (py * image.width() + px) * samples * 127;
+            Sampler rng( seed );
+            FCRNG alpha_rng( seed );
+            
+            Color color;
+            Vector normal;
+            Color albedo;
+            
+            for(int i= 0; i < samples; i++)
+            {
+                rng.index(i);
+                float x= rng.sample();
+                float y= rng.sample();
+                
+                // generer le rayon
+                Point origine= inv(Point(px + x, py + y, 0));
+                Point extremite= inv(Point(px + x, py + y, 1));
+                Ray ray(origine, extremite);
+                
+                // calculer les intersections avec tous les triangles
+                //~ if(Hit hit= scene.bvh.intersect(ray))
+                if(Hit hit= scene.bvh.intersect(ray, alpha_filter(scene, alpha_rng)))                
+                {
+                    Point p= scene.position(hit, ray);
+                    Vector pn= scene.normal(hit);
+                    
+                    // matiere emissive, si la source est orientee vers la camera
+                    if(dot(pn, ray.d) < 0)
+                    {
+                        const GLTFMaterial& material= scene.material(hit);
+                        color= color + material.emission;
+                        // suppose que les normales des sources sont correctes...
+                    }
+                    
+                    if(dot(pn, ray.d) > 0)
+                        // mais ce n'est pas toujours le cas pour le reste de la geometrie...
+                        pn= -pn;
+                    
+                    Brdf brdf= scene.brdf(hit, pn);
+                    //~ color= color + direct(origine, p, brdf, scene, rng);
+                    color= color + path(options.depth, origine, p, brdf, scene, rng);
+                    
+                    normal= normal + pn;
+                    albedo= albedo + brdf.f(pn, normalize(ray.o - p));
+                }
+            }
+            
+            image(px, py)= Color(color / float(samples), 1);    // force une couleur opaque...
+            aov_normal(px, py)= Color(normal / float(samples), 1);    // force une couleur opaque...
+            aov_albedo(px, py)= Color(albedo / float(samples), 1);    // force une couleur opaque...
+            
+            maxdims= std::max(rng.d, maxdims);
+        }
+    }
+    
+    printf("sampler dimensions %u\n", maxdims);
+    
+    auto cpu_stop= std::chrono::high_resolution_clock::now();
+    auto cpu_time= std::chrono::duration_cast<std::chrono::milliseconds>(cpu_stop - cpu_start).count();
+    printf("cpu  %ds %03dms\n", int(cpu_time / 1000), int(cpu_time % 1000));
+    
+    char tmp[1024];
+    //~ sprintf(tmp, "%s-%05u-%04u.png", options.prefix, unsigned(cpu_time), samples);
+    sprintf(tmp, "%s-%04u.png", options.prefix, samples);
+    printf("writing '%s'...\n", tmp);
+    write_image_preview(image, tmp);
+    
+    //~ sprintf(tmp, "%s-%05u-%04u.pfm", options.prefix, unsigned(cpu_time), samples);
+    sprintf(tmp, "%s-%04u.pfm", options.prefix, samples);
+    printf("writing '%s'...\n", tmp);
+    write_image_pfm(image, tmp);
+    
+    sprintf(tmp, "%s-normals-%04u.pfm", options.prefix, samples);
+    write_image_pfm(aov_normal, tmp);
+    
+    sprintf(tmp, "%s-albedo-%04u.pfm", options.prefix, samples);
+    write_image_pfm(aov_albedo, tmp);
+    printf("\n");
+    
+    return 0;
+}
diff --git a/code/projects/sampler.h b/code/projects/sampler.h
new file mode 100644
index 0000000000000000000000000000000000000000..9f0444262c1bf188fc7d2afb637fb5184ba5b4ef
--- /dev/null
+++ b/code/projects/sampler.h
@@ -0,0 +1,129 @@
+
+#ifndef _SAMPLER_H
+#define _SAMPLER_H
+
+
+inline float uint_to_float( const unsigned x )
+{
+    return float(x >> 8) / float(1u << 24);
+}
+
+inline double uint_to_double( const unsigned x )
+{
+    return double(uint64_t(x) << 20) / double(uint64_t(1) << 52);
+}
+
+
+struct Squares
+{
+    uint64_t n;
+    
+    Squares( ) : n(0) {}
+    Squares( const uint64_t first ) : n(first) {}
+    
+    Squares& index( const unsigned i ) { return *this; }
+    float sample( ) { return uint_to_float( squares32(n++) ); }
+    float sample( const uint64_t id ) { return uint_to_float( squares32(id) ); }
+    
+    inline unsigned squares32( const uint64_t n, const uint64_t key= 0xc8e4fd154ce32f6d )
+    {
+       uint64_t x, y, z;
+       
+       y = x = n * key; 
+       z = y + key;
+       x = x*x + y; x = (x>>32) | (x<<32);       /* round 1 */
+       x = x*x + z; x = (x>>32) | (x<<32);       /* round 2 */
+       x = x*x + y; x = (x>>32) | (x<<32);       /* round 3 */
+
+       return (x*x + z) >> 32;                   /* round 4 */
+    }
+};
+
+
+struct LCG
+{
+    std::default_random_engine rng;
+    std::uniform_real_distribution<float> uniform;
+    unsigned d;
+    
+    LCG( ) : rng(), uniform(), d(0) {}
+    LCG( const unsigned seed ) : rng( hash(seed) ), uniform(), d(0) {}
+    // seed est un compteur, pas du tout adapte comme init du lcg, mais hash(seed) est suffisament uniforme
+    
+    LCG& index( const unsigned i ) { d= 0; return *this; }
+    float sample( ) { d++; return uniform(rng); }
+    
+    static unsigned hash( unsigned x )
+    {
+        x ^= x >> 16;
+        x *= 0x21f0aaad;
+        x ^= x >> 15;
+        x *= 0xd35a2d97;
+        x ^= x >> 15;
+        return x;
+    }    
+};
+
+
+// counter based rng, cf "Parallel Random Numbers: As Easy as 1, 2, 3"
+// https://www.thesalmons.org/john/random123/
+// le code est quand meme bien degueu et l'etat interne des generateurs est un peu trop gros.
+// openrand a serieusement nettoye l'implem. cf https://github.com/msu-sparta/OpenRAND/blob/main/include/openrand/philox.h
+
+// du coup, plus simple et de qualite raisonnable :
+// "PRNS with 32 bits of state"
+// https://marc-b-reynolds.github.io/shf/2017/09/27/LPRNS.html
+// pas les memes constantes que dans le blog, mais small crush passe sans probleme, donc j'imagine que ca suffit.
+// et c'est mieux que std::default_random_engine qui echoue a la moitiee des tests de small crush...
+struct FCRNG
+{
+    unsigned n;
+    unsigned key;
+    
+    FCRNG( ) : n(0), key(123451) {}
+    FCRNG( const unsigned s ) : n(), key() { seed(s); }
+    
+    void seed( const unsigned s ) { n= 0; key= (s << 1) | 1u; }
+    
+    FCRNG& index( const unsigned i ) { n= i; return *this;}
+    
+    unsigned sample_int( ) { return hash(n++ * key); }  
+    // \todo pour le premier point n= 0 et 0*key == 0 aussi, marche pas tres bien avant d'avoir quelques bits a 1 dans n...
+    // cf utilisation dans owen...
+    
+    float sample( ) { return uint_to_float( sample_int() ); }
+    
+    unsigned sample_range( const unsigned range )
+    {
+        // Efficiently Generating a Number in a Range
+        // cf http://www.pcg-random.org/posts/bounded-rands.html
+        unsigned divisor= (uint64_t(1) << 32) / range;
+        if(divisor == 0) return 0;
+        
+        while(true)
+        {
+            unsigned x= sample_int() / divisor;
+            if(x < range) return x;
+        }
+    }
+    
+    // c++ interface
+    unsigned operator() ( ) { return sample_int(); }
+    static constexpr unsigned min( ) { return 0; }
+    static constexpr unsigned max( ) { return (uint64_t(1) << 32) -1 ;}
+    typedef unsigned result_type;
+    
+    static unsigned hash( unsigned x )
+    {
+        x ^= x >> 16;
+        x *= 0x21f0aaad;
+        x ^= x >> 15;
+        x *= 0xd35a2d97;
+        x ^= x >> 15;
+        return x;
+    }
+    // cf "hash prospector" https://github.com/skeeto/hash-prospector/blob/master/README.md
+};
+
+
+#endif
diff --git a/code/projects/sampler_sobol.h b/code/projects/sampler_sobol.h
new file mode 100644
index 0000000000000000000000000000000000000000..57f1f52f73c1bcf5dbee8d5dd93351972c15887d
--- /dev/null
+++ b/code/projects/sampler_sobol.h
@@ -0,0 +1,159 @@
+
+#ifndef _SAMPLER_SOBOL_H
+#define _SAMPLER_SOBOL_H
+
+#include <array>
+
+#include "sampler.h"
+#include "owen_fast.h"
+#include "sobol_matrices.h"
+
+
+struct Sobol
+{
+    Sobol( ) = default;
+    
+    Sobol( const unsigned seed ) : n(0), d(0), scrambles()
+    {
+        FCRNG rng(seed);
+        for(unsigned d= 0; d < sobol_matrices_size; d++)
+            scrambles[d]= rng.sample_int();
+    }
+    
+    Sobol& index( const unsigned i ) 
+    { 
+        n= i; 
+        d= 0; 
+        return *this; 
+    }
+    
+    float sample( ) 
+    {
+        float x= sobol_sample_float(d, n, scrambles[d]);
+        d++; 
+        return x; 
+    }
+
+    unsigned n;
+    unsigned d;
+    
+protected:
+    std::array<unsigned, sobol_matrices_size> scrambles;
+};
+
+
+struct SobolGray
+{
+    SobolGray( ) = default;
+    
+    SobolGray( const unsigned seed ) : n(0), d(0), scrambles(), points(), code(0), bit(0)
+    {
+        FCRNG rng(seed);
+        for(unsigned d= 0; d < sobol_matrices_size; d++)
+            scrambles[d]= rng.sample_int() ;
+    }
+    
+    SobolGray& index( const unsigned i ) 
+    {
+        assert(i == 0 || i == n+1);
+        
+        n= i; 
+        d= 0;
+        
+        // previous state
+        if(i == 0) 
+            return *this;
+        
+        unsigned ncode= graycode(i);
+        bit= trailing_zeroes(code ^ ncode);
+        code= ncode;
+        return *this; 
+    }
+    
+    float sample( ) 
+    {
+        if(n > 0) 
+            points[d]= points[d] ^ sobol_matrices[d][bit];
+        
+        float x= uint_to_float(points[d] ^ scrambles[d]);
+        d++; 
+        return x; 
+    }
+
+    unsigned n;
+    unsigned d;
+    
+protected:
+    std::array<unsigned, sobol_matrices_size> scrambles;
+    std::array<unsigned, sobol_matrices_size> points;
+    unsigned code;
+    unsigned bit;
+};
+
+
+struct Owen
+{
+    Owen( ) = default;
+    
+    Owen( const unsigned seed ) : n(0), d(0), scrambles()
+    {
+        FCRNG rng(seed);
+        for(unsigned d= 0; d < sobol_matrices_size; d++)
+            scrambles[d]= rng.sample_int();
+    }
+    
+    Owen& index( const unsigned i ) 
+    { 
+        n= i; 
+        d= 0; 
+        return *this; 
+    }
+    
+    float sample( ) 
+    {
+        float x= uint_to_float( owen_scramble( sobol_sample(d, n), scrambles[d]) );
+        d++; 
+        return x; 
+    }
+
+    unsigned n;
+    unsigned d;
+
+protected:
+    std::array<unsigned, sobol_matrices_size> scrambles;
+};
+
+
+struct OwenFast
+{
+    OwenFast( ) = default;
+    
+    OwenFast( const unsigned seed ) : n(0), d(0), scrambles()
+    {
+        FCRNG rng(seed);
+        for(unsigned d= 0; d < sobol_matrices_size; d++)
+            scrambles[d]= rng.sample_int();
+    }
+    
+    OwenFast& index( const unsigned i ) 
+    { 
+        n= i; 
+        d= 0; 
+        return *this; 
+    }
+    
+    float sample( ) 
+    {
+        float x= uint_to_float( owen_scramble_fast4( sobol_sample(d, n), scrambles[d]) );
+        d++; 
+        return x; 
+    }
+
+    unsigned n;
+    unsigned d;
+    
+protected:
+    std::array<unsigned, sobol_matrices_size> scrambles;
+};
+
+#endif
diff --git a/code/projects/sobol_matrices.cpp b/code/projects/sobol_matrices.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..988dd0544b8b7dd8641d366d5aabfd2384c676bd
--- /dev/null
+++ b/code/projects/sobol_matrices.cpp
@@ -0,0 +1,133 @@
+
+#include <array>
+
+std::array<unsigned, 32> sobol_matrices[128] {
+    { 0x80000000, 0x40000000, 0x20000000, 0x10000000, 0x08000000, 0x04000000, 0x02000000, 0x01000000, 0x00800000, 0x00400000, 0x00200000, 0x00100000, 0x00080000, 0x00040000, 0x00020000, 0x00010000, 0x00008000, 0x00004000, 0x00002000, 0x00001000, 0x00000800, 0x00000400, 0x00000200, 0x00000100, 0x00000080, 0x00000040, 0x00000020, 0x00000010, 0x00000008, 0x00000004, 0x00000002, 0x00000001 },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0xf0000000, 0x88000000, 0xcc000000, 0xaa000000, 0xff000000, 0x80800000, 0xc0c00000, 0xa0a00000, 0xf0f00000, 0x88880000, 0xcccc0000, 0xaaaa0000, 0xffff0000, 0x80008000, 0xc000c000, 0xa000a000, 0xf000f000, 0x88008800, 0xcc00cc00, 0xaa00aa00, 0xff00ff00, 0x80808080, 0xc0c0c0c0, 0xa0a0a0a0, 0xf0f0f0f0, 0x88888888, 0xcccccccc, 0xaaaaaaaa, 0xffffffff },
+    { 0x80000000, 0xc0000000, 0x60000000, 0x90000000, 0xe8000000, 0x5c000000, 0x8e000000, 0xc5000000, 0x68800000, 0x9cc00000, 0xee600000, 0x55900000, 0x80680000, 0xc09c0000, 0x60ee0000, 0x90550000, 0xe8808000, 0x5cc0c000, 0x8e606000, 0xc5909000, 0x6868e800, 0x9c9c5c00, 0xeeee8e00, 0x5555c500, 0x8000e880, 0xc0005cc0, 0x60008e60, 0x9000c590, 0xe8006868, 0x5c009c9c, 0x8e00eeee, 0xc5005555 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0x50000000, 0xf8000000, 0x74000000, 0xa2000000, 0x93000000, 0xd8800000, 0x25400000, 0x59e00000, 0xe6d00000, 0x78080000, 0xb40c0000, 0x82020000, 0xc3050000, 0x208f8000, 0x51474000, 0xfbea2000, 0x75d93000, 0xa0858800, 0x914e5400, 0xdbe79e00, 0x25db6d00, 0x58800080, 0xe54000c0, 0x79e00020, 0xb6d00050, 0x800800f8, 0xc00c0074, 0x200200a2, 0x50050093 },
+    { 0x80000000, 0x40000000, 0x20000000, 0xb0000000, 0xf8000000, 0xdc000000, 0x7a000000, 0x9d000000, 0x5a800000, 0x2fc00000, 0xa1600000, 0xf0b00000, 0xda880000, 0x6fc40000, 0x81620000, 0x40bb0000, 0x22878000, 0xb3c9c000, 0xfb65a000, 0xddb2d000, 0x78022800, 0x9c0b3c00, 0x5a0fb600, 0x2d0ddb00, 0xa2878080, 0xf3c9c040, 0xdb65a020, 0x6db2d0b0, 0x800228f8, 0x400b3cdc, 0x200fb67a, 0xb00ddb9d },
+    { 0x80000000, 0x40000000, 0x60000000, 0x30000000, 0xc8000000, 0x24000000, 0x56000000, 0xfb000000, 0xe0800000, 0x70400000, 0xa8600000, 0x14300000, 0x9ec80000, 0xdf240000, 0xb6d60000, 0x8bbb0000, 0x48008000, 0x64004000, 0x36006000, 0xcb003000, 0x2880c800, 0x54402400, 0xfe605600, 0xef30fb00, 0x7e48e080, 0xaf647040, 0x1eb6a860, 0x9f8b1430, 0xd6c81ec8, 0xbb249f24, 0x80d6d6d6, 0x40bbbbbb },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0xd0000000, 0x58000000, 0x94000000, 0x3e000000, 0xe3000000, 0xbe800000, 0x23c00000, 0x1e200000, 0xf3100000, 0x46780000, 0x67840000, 0x78460000, 0x84670000, 0xc6788000, 0xa784c000, 0xd846a000, 0x5467d000, 0x9e78d800, 0x33845400, 0xe6469e00, 0xb7673300, 0x20f86680, 0x104477c0, 0xf8668020, 0x4477c010, 0x668020f8, 0x77c01044, 0x8020f866, 0xc0104477 },
+    { 0x80000000, 0x40000000, 0xa0000000, 0x50000000, 0x88000000, 0x24000000, 0x12000000, 0x2d000000, 0x76800000, 0x9e400000, 0x08200000, 0x64100000, 0xb2280000, 0x7d140000, 0xfea20000, 0xba490000, 0x1a248000, 0x491b4000, 0xc4b5a000, 0xe3739000, 0xf6800800, 0xde400400, 0xa8200a00, 0x34100500, 0x3a280880, 0x59140240, 0xeca20120, 0x974902d0, 0x6ca48768, 0xd75b49e4, 0xcc95a082, 0x87639641 },
+    { 0x80000000, 0x40000000, 0xa0000000, 0x50000000, 0x28000000, 0xd4000000, 0x6a000000, 0x71000000, 0x38800000, 0x58400000, 0xea200000, 0x31100000, 0x98a80000, 0x08540000, 0xc22a0000, 0xe5250000, 0xf2b28000, 0x79484000, 0xfaa42000, 0xbd731000, 0x18a80800, 0x48540400, 0x622a0a00, 0xb5250500, 0xdab28280, 0xad484d40, 0x90a426a0, 0xcc731710, 0x20280b88, 0x10140184, 0x880a04a2, 0x84350611 },
+    { 0x80000000, 0x40000000, 0xe0000000, 0xb0000000, 0x98000000, 0x94000000, 0x8a000000, 0x5b000000, 0x33800000, 0xd9c00000, 0x72200000, 0x3f100000, 0xc1b80000, 0xa6ec0000, 0x53860000, 0x29f50000, 0x0a3a8000, 0x1b2ac000, 0xd392e000, 0x69ff7000, 0xea380800, 0xab2c0400, 0x4ba60e00, 0xfde50b00, 0x60028980, 0xf006c940, 0x7834e8a0, 0x241a75b0, 0x123a8b38, 0xcf2ac99c, 0xb992e922, 0x82ff78f1 },
+    { 0x80000000, 0x40000000, 0xa0000000, 0x10000000, 0x08000000, 0x6c000000, 0x9e000000, 0x23000000, 0x57800000, 0xadc00000, 0x7fa00000, 0x91d00000, 0x49880000, 0xced40000, 0x880a0000, 0x2c0f0000, 0x3e0d8000, 0x3317c000, 0x5fb06000, 0xc1f8b000, 0xe18d8800, 0xb2d7c400, 0x1e106a00, 0x6328b100, 0xf7858880, 0xbdc3c2c0, 0x77ba63e0, 0xfdf7b330, 0xd7800df8, 0xedc0081c, 0xdfa0041a, 0x81d00a2d },
+    { 0x80000000, 0x40000000, 0x20000000, 0x30000000, 0x58000000, 0xac000000, 0x96000000, 0x2b000000, 0xd4800000, 0x09400000, 0xe2a00000, 0x52500000, 0x4e280000, 0xc71c0000, 0x629e0000, 0x12670000, 0x6e138000, 0xf731c000, 0x3a98a000, 0xbe449000, 0xf83b8800, 0xdc2dc400, 0xee06a200, 0xb7239300, 0x1aa80d80, 0x8e5c0ec0, 0xa03e0b60, 0x703701b0, 0x783b88c8, 0x9c2dca54, 0xce06a74a, 0x87239795 },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0x50000000, 0xf8000000, 0x8c000000, 0xe2000000, 0x33000000, 0x0f800000, 0x21400000, 0x95a00000, 0x5e700000, 0xd8080000, 0x1c240000, 0xba160000, 0xef370000, 0x15868000, 0x9e6fc000, 0x781b6000, 0x4c349000, 0x420e8800, 0x630bcc00, 0xf7ad6a00, 0xad739500, 0x77800780, 0x6d4004c0, 0xd7a00420, 0x3d700630, 0x2f880f78, 0xb1640ad4, 0xcdb6077a, 0x824706d7 },
+    { 0x80000000, 0xc0000000, 0x60000000, 0x90000000, 0x38000000, 0xc4000000, 0x42000000, 0xa3000000, 0xf1800000, 0xaa400000, 0xfce00000, 0x85100000, 0xe0080000, 0x500c0000, 0x58060000, 0x54090000, 0x7a038000, 0x670c4000, 0xb3842000, 0x094a3000, 0x0d6f1800, 0x2f5aa400, 0x1ce7ce00, 0xd5145100, 0xb8000080, 0x040000c0, 0x22000060, 0x33000090, 0xc9800038, 0x6e4000c4, 0xbee00042, 0x261000a3 },
+    { 0x80000000, 0x40000000, 0x20000000, 0xf0000000, 0xa8000000, 0x54000000, 0x9a000000, 0x9d000000, 0x1e800000, 0x5cc00000, 0x7d200000, 0x8d100000, 0x24880000, 0x71c40000, 0xeba20000, 0x75df0000, 0x6ba28000, 0x35d14000, 0x4ba3a000, 0xc5d2d000, 0xe3a16800, 0x91db8c00, 0x79aef200, 0x0cdf4100, 0x672a8080, 0x50154040, 0x1a01a020, 0xdd0dd0f0, 0x3e83e8a8, 0xaccacc54, 0xd52d529a, 0xd91d919d },
+    { 0x80000000, 0xc0000000, 0x20000000, 0xd0000000, 0xd8000000, 0xc4000000, 0x46000000, 0x85000000, 0xa5800000, 0x76c00000, 0xada00000, 0x6ab00000, 0x2da80000, 0xaabc0000, 0x0daa0000, 0x7ab10000, 0xd5a78000, 0xbebd4000, 0x93a3e000, 0x3bb51000, 0x3629b800, 0x4d727c00, 0x9b836200, 0x27c4d700, 0xb629b880, 0x8d727cc0, 0xbb836220, 0xf7c4d7d0, 0x6e29b858, 0x49727c04, 0xfd836266, 0x72c4d755 },
+    { 0x80000000, 0x40000000, 0x20000000, 0xf0000000, 0x38000000, 0x14000000, 0xf6000000, 0x67000000, 0x8f800000, 0x50400000, 0x8aa00000, 0x0ff00000, 0x12a80000, 0xabf40000, 0xfcaa0000, 0x28fb0000, 0xbd298000, 0x0bba4000, 0x4e06e000, 0x330c3000, 0x59861800, 0xc74d3400, 0x3d2cb200, 0x4bb2cb00, 0x6e061880, 0xc30d3440, 0x618cb220, 0xd342cbf0, 0xcb2e18b8, 0x2cb93454, 0xe186b2d6, 0x9349cb97 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0xf0000000, 0x68000000, 0x64000000, 0x36000000, 0x6d000000, 0x41800000, 0xe0400000, 0xd2e00000, 0x9bf00000, 0x0ce80000, 0x52fc0000, 0x5b6a0000, 0x2fb30000, 0xa00c8000, 0x30054000, 0x4807e000, 0x940f9000, 0x5e01f800, 0x090e9400, 0x778a5600, 0x8d416b00, 0x9369f880, 0x7bb294c0, 0xde005620, 0xc9026bf0, 0x578d78e8, 0x7d4bd4a4, 0xfb6db616, 0x1fbefb9d },
+    { 0x80000000, 0x40000000, 0xa0000000, 0x50000000, 0x98000000, 0xf4000000, 0xae000000, 0xbb000000, 0xe7800000, 0x95c00000, 0x1c200000, 0xd0300000, 0xdba80000, 0x55f40000, 0xff820000, 0x21c10000, 0x12238000, 0x3b3a4000, 0xa42b6000, 0x3430f000, 0x4da69800, 0x4af3ec00, 0x2e043a00, 0xfb0a1f00, 0x47851880, 0xc5c9ac40, 0x842f5aa0, 0x243aef50, 0x75a38018, 0xeefa40b4, 0x180b600e, 0xb400f0eb },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0xb0000000, 0xb8000000, 0x3c000000, 0xce000000, 0x41000000, 0x21800000, 0x51c00000, 0x09600000, 0x85700000, 0xf2780000, 0x8e9c0000, 0x60020000, 0x70030000, 0x58038000, 0x8c02c000, 0x7602e000, 0x7d00f000, 0xef833800, 0x10c10400, 0x28e08600, 0xd4b14700, 0xfb182580, 0x0bee15c0, 0x9279c9e0, 0xfe9d3a70, 0x38000008, 0xfc00000c, 0x2e00000e, 0xf100000b },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0xd0000000, 0x68000000, 0x3c000000, 0x8a000000, 0x51000000, 0xa9800000, 0xddc00000, 0x5ba00000, 0x39d00000, 0x95f80000, 0x56d40000, 0x0a020000, 0x91030000, 0x49838000, 0x0dc34000, 0x33a1a000, 0x05d0f000, 0x1ffa2800, 0x07d54400, 0xa380a600, 0x4cc07700, 0x1222ee80, 0x3413a740, 0xa65bf7e0, 0x5305ab50, 0x15f80008, 0x96d4000c, 0xea02000e, 0x4103000d },
+    { 0x80000000, 0x40000000, 0x60000000, 0xd0000000, 0x38000000, 0x8c000000, 0x7e000000, 0x71000000, 0xc8800000, 0x04c00000, 0x1ba00000, 0xbb700000, 0x4a980000, 0xc3bc0000, 0xa6020000, 0x6d010000, 0xee818000, 0x29c34000, 0x9520e000, 0x42b23000, 0xe7b9f800, 0x0d0dc400, 0x3fb92200, 0x110d1300, 0x19bbee80, 0x3c0cadc0, 0x973a4a60, 0xc5cf7ef0, 0x3a180008, 0x0b7c0004, 0xa3a20006, 0x7771000d },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0x90000000, 0x08000000, 0x64000000, 0x6a000000, 0x89000000, 0xa5800000, 0xcb400000, 0x18200000, 0xad900000, 0xaf880000, 0x72f40000, 0x25820000, 0x0b430000, 0xb8228000, 0x3d924000, 0xa7882000, 0x16f59000, 0x4f83a800, 0x82412400, 0x1da01600, 0xf6d16d00, 0xbfa84080, 0xbb672640, 0xe0091620, 0xf0b4efd0, 0x38228008, 0xfd92400c, 0x0788200a, 0x86f59009 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0xd0000000, 0x48000000, 0x8c000000, 0xd6000000, 0x39000000, 0xd5800000, 0x32400000, 0xb2a00000, 0x72100000, 0x53d80000, 0x82cc0000, 0xcb820000, 0x47430000, 0x91208000, 0xa9534000, 0x7cf92000, 0x4e9e3000, 0xfcf95800, 0x8e9fe400, 0xdcf9d600, 0x5e9c8900, 0x94f96a80, 0xd29fb840, 0x42f9b760, 0xeb9c9f30, 0x97788008, 0xd9df400c, 0x25db2002, 0xabcd300d },
+    { 0x80000000, 0xc0000000, 0x20000000, 0x50000000, 0xd8000000, 0xf4000000, 0x3e000000, 0x95000000, 0x8f800000, 0x3d400000, 0xf3200000, 0x2ef00000, 0xadc80000, 0x0a0c0000, 0x8b220000, 0x4af30000, 0x6bc88000, 0x3b0d4000, 0xe2a16000, 0x16b0d000, 0x29687800, 0xbdbf1400, 0x33cb5e00, 0x0f0c2500, 0xfca1b480, 0xd3b0afc0, 0x7eeb6920, 0x74fe4d30, 0xfee87808, 0xb4ff140c, 0xdeeb5e02, 0xe4fc2505 },
+    { 0x80000000, 0x40000000, 0xa0000000, 0xb0000000, 0x98000000, 0xa4000000, 0x7a000000, 0xd5000000, 0x02800000, 0x60400000, 0x51e00000, 0x88700000, 0x8c280000, 0x47c40000, 0x0be20000, 0xad710000, 0xb6aa8000, 0x3386c000, 0xb8006000, 0x54039000, 0x42036800, 0xc1019400, 0xe0826a00, 0x11431100, 0x2960af80, 0x3d3175c0, 0xdf4a3aa0, 0xaff49e10, 0xd62b6808, 0x62c59404, 0x31606a0a, 0xd932110b },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0x30000000, 0x18000000, 0x34000000, 0x8a000000, 0x9d000000, 0x67800000, 0x82400000, 0x40e00000, 0x60f00000, 0x91480000, 0x29440000, 0x2d620000, 0xbfb30000, 0x162a8000, 0xfbf4c000, 0xe4ca6000, 0xc207d000, 0x2002a800, 0xf001b400, 0xb8037e00, 0x04021900, 0x92034b80, 0xa90327c0, 0xed81f320, 0x1f40d810, 0x27602808, 0xe2b1740c, 0xd1ab1e0a, 0x49b6c903 },
+    { 0x80000000, 0x40000000, 0xe0000000, 0xd0000000, 0x08000000, 0x4c000000, 0x02000000, 0xb5000000, 0x36800000, 0xc2c00000, 0x14200000, 0x07500000, 0x1bf80000, 0x50340000, 0x48a20000, 0xac910000, 0xd35b8000, 0xbca74000, 0x7bfa2000, 0xc0343000, 0xa0a18800, 0x30909400, 0xd95b7a00, 0x45a57b00, 0x4f7a7880, 0xb7f6f940, 0x82013de0, 0xf502dfd0, 0xd6820808, 0x12c3d404, 0x1c235a0e, 0x4b504b0d },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0x50000000, 0x68000000, 0x4c000000, 0x76000000, 0xf7000000, 0x36800000, 0xd7400000, 0x87e00000, 0xef300000, 0xa3a80000, 0xd5440000, 0x23aa0000, 0x15470000, 0xc3a98000, 0x45464000, 0xaba82000, 0x09477000, 0xdda9f800, 0xfe44ac00, 0xeb292200, 0x2907f100, 0x6ccb3d80, 0xc6344dc0, 0xcf61b320, 0x137318d0, 0xeccb3d88, 0x06344dcc, 0x2f61b32e, 0x437318d5 },
+    { 0x80000000, 0x40000000, 0x60000000, 0x90000000, 0xc8000000, 0x74000000, 0x52000000, 0x03000000, 0xeb800000, 0x6f400000, 0x64600000, 0xdaf00000, 0x17980000, 0x297c0000, 0xa59a0000, 0xfa7d0000, 0xe61b8000, 0x713f4000, 0x1878a000, 0xdcce9000, 0xb661e800, 0x99f29c00, 0x9c184600, 0xd63e2100, 0x09fa5780, 0x548e0ac0, 0xa380a9e0, 0x5b413f30, 0x56625788, 0x49f20ac4, 0x341aa9e6, 0x323c3f39 },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0xd0000000, 0xb8000000, 0x04000000, 0x6e000000, 0x97000000, 0xf2800000, 0xedc00000, 0x13600000, 0x5c900000, 0xdb580000, 0x31e40000, 0x09da0000, 0xcc270000, 0x02b88000, 0x44b44000, 0x0fe26000, 0xe6505000, 0x9ab9d800, 0x50b50c00, 0x79e29200, 0xa552fb00, 0xbe38bf80, 0x2e77d940, 0xf6000ae0, 0x830112d0, 0x84803f88, 0xaec3994c, 0x37e26aea, 0x225142dd },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0x30000000, 0x68000000, 0xec000000, 0x22000000, 0x2b000000, 0x36800000, 0x9d400000, 0x6a200000, 0x16700000, 0x4de80000, 0x330c0000, 0x936a0000, 0x824f0000, 0x3b498000, 0x8f3fc000, 0x28202000, 0xcd707000, 0xf36aa800, 0x724fdc00, 0xb34bf200, 0x533e6900, 0x62207a80, 0x0a7140c0, 0xe7ea6520, 0xc40d90f0, 0xefe9fa88, 0xd80e80cc, 0x45ea452e, 0x2f0de0f3 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0x30000000, 0x28000000, 0xd4000000, 0x8a000000, 0xff000000, 0x84800000, 0x73c00000, 0x13200000, 0xc2b00000, 0xfb380000, 0x361c0000, 0x401a0000, 0xe0af0000, 0x11228000, 0x19b3c000, 0xfdb82000, 0x5edf9000, 0x75b88800, 0x7adfac00, 0xf7baba00, 0x61ddf300, 0xd1387e80, 0x391e55c0, 0xcc9ba860, 0x776cbeb0, 0xa000f688, 0xf001f9cc, 0x08011262, 0xe4014db3 },
+    { 0x80000000, 0x40000000, 0xa0000000, 0x50000000, 0xb8000000, 0x84000000, 0x1a000000, 0xaf000000, 0xbd800000, 0xdfc00000, 0x14e00000, 0x43500000, 0xda380000, 0x4e1c0000, 0x4cda0000, 0x364d0000, 0x29608000, 0xdc904000, 0x6ed86000, 0x5d4f5000, 0x2ee08800, 0xfc51ac00, 0x7fb81e00, 0x45dc8300, 0xfa3a4580, 0x5e1d6240, 0x54dbd360, 0xe24ec930, 0x8b62cd88, 0xf790ce44, 0xc959cd6a, 0x2d8f4a35 },
+    { 0x80000000, 0x40000000, 0xe0000000, 0x70000000, 0x08000000, 0xf4000000, 0xf6000000, 0x8b000000, 0xc9800000, 0x55400000, 0x67200000, 0xf3f00000, 0x34780000, 0x57440000, 0x1ada0000, 0xb1f50000, 0xa9818000, 0x6540c000, 0x8f23a000, 0x77f21000, 0xca7bf800, 0x2845fc00, 0x255afe00, 0x6fb67900, 0x07233a80, 0xc3f25ac0, 0xdc7aed60, 0xd34482d0, 0xe4d94288, 0xcef766c4, 0x9603b36e, 0xbb00ebd7 },
+    { 0x80000000, 0x40000000, 0xe0000000, 0x90000000, 0x68000000, 0xf4000000, 0x62000000, 0xdf000000, 0x79800000, 0xdd400000, 0x76e00000, 0x2cf00000, 0xcfb80000, 0x51ec0000, 0xc8da0000, 0x845d0000, 0x9b818000, 0x42434000, 0xef622000, 0x61b19000, 0xd1582800, 0x891cac00, 0x65626e00, 0x0ab10900, 0x2adbbd80, 0x1b5d86c0, 0x02014560, 0x0f032470, 0xf1821588, 0xb9426ac4, 0x7ce10b6e, 0x07f3bd79 },
+    { 0x80000000, 0xc0000000, 0x60000000, 0x50000000, 0x18000000, 0xdc000000, 0x42000000, 0x37000000, 0x20800000, 0xf1400000, 0x28600000, 0x94900000, 0x87880000, 0xa83c0000, 0x556a0000, 0xe6ef0000, 0xf8038000, 0x4c024000, 0x3a01e000, 0xbb023000, 0x7a816800, 0x1a43ac00, 0x4ae18a00, 0x52d31900, 0x8f682380, 0xcded9740, 0xfa80bfa0, 0xda43f2b0, 0x2ae2cb88, 0x02d07b4c, 0x976ad5a6, 0x11eddbb5 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0xf0000000, 0xf8000000, 0x34000000, 0x62000000, 0xf5000000, 0xa8800000, 0xfcc00000, 0x8e200000, 0x53f00000, 0xc7780000, 0x95740000, 0xb8020000, 0xd4e50000, 0xb2808000, 0xfdc0c000, 0x64a02000, 0xaa30f000, 0x19d8f800, 0x0e443400, 0x935a6200, 0xe761f500, 0x657a2880, 0x40913cc0, 0xe0022e20, 0xd0e563f0, 0x08809f78, 0xccc09174, 0x56200202, 0x97f0e5e5 },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0xf0000000, 0xf8000000, 0xec000000, 0x7e000000, 0x61000000, 0x5c800000, 0xe6c00000, 0xdda00000, 0x2a700000, 0x93380000, 0x13cc0000, 0xd3ce0000, 0x73790000, 0x83a08000, 0x7b70c000, 0x97b8a000, 0xe90cf000, 0x886ef800, 0xd409ec00, 0x3218fe00, 0xef7ca100, 0xc556fc80, 0x56c516c0, 0x4556a5a0, 0x96c50670, 0xe556cd38, 0x66c542cc, 0x1d56574e, 0x8ac549b9 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0xb0000000, 0x58000000, 0x2c000000, 0x9a000000, 0xf9000000, 0x3c800000, 0xb2c00000, 0xad200000, 0x3a300000, 0x89980000, 0x448c0000, 0x2eea0000, 0x6f810000, 0xef208000, 0x2f30c000, 0x0f182000, 0xbf4cb000, 0xe74a5800, 0xcb712c00, 0x51981a00, 0xa88c3900, 0x94ea1c80, 0x268102c0, 0x8ba07520, 0xb1f0d630, 0x38383398, 0x7c7c0d8c, 0x52524a6a, 0x3d3df141 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0xb0000000, 0xd8000000, 0xac000000, 0x8e000000, 0x09000000, 0x9e800000, 0xa1c00000, 0xcaa00000, 0x33700000, 0x95780000, 0x085c0000, 0x24b60000, 0x6a350000, 0x43788000, 0x6d5cc000, 0x14362000, 0x72f5b000, 0xcf585800, 0x53ec6c00, 0xc5eeae00, 0x40d9b900, 0xe016c680, 0x9045cdc0, 0x6880e4a0, 0x74c04a70, 0x2220f3f8, 0x87b0b59c, 0x9758b816, 0x3fecfc45 },
+    { 0x80000000, 0x40000000, 0xe0000000, 0xf0000000, 0xa8000000, 0x2c000000, 0xa2000000, 0x2d000000, 0xda800000, 0xf9400000, 0xec600000, 0x02b00000, 0x3d480000, 0x825c0000, 0x7d4a0000, 0x62610000, 0x8dc88000, 0xca1c4000, 0xa1aae000, 0x6891f000, 0x8c602800, 0xb2b06c00, 0x75484200, 0x5e5cdd00, 0x774a7280, 0x6361d540, 0xf548ce60, 0x1e5c6fb0, 0x974a07c8, 0x93618b1c, 0x5d48b92a, 0x325c0cd1 },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0x30000000, 0xc8000000, 0x7c000000, 0x82000000, 0x4f000000, 0xbe800000, 0xedc00000, 0x21600000, 0xab700000, 0x78680000, 0x746c0000, 0x1e9a0000, 0xfdcb0000, 0x39088000, 0x2f1cc000, 0x4ef2e000, 0xc5a73000, 0x6d924800, 0xe1d7bc00, 0x4b7ae200, 0x487bbf00, 0xbc801680, 0x62c061c0, 0x7fe08b60, 0x76b0a870, 0x91088ce8, 0xa31caaac, 0xe4f2037a, 0xc6a7f47b },
+    { 0x80000000, 0xc0000000, 0x20000000, 0x10000000, 0x98000000, 0x2c000000, 0x06000000, 0xcd000000, 0x8a800000, 0x1bc00000, 0xffa00000, 0xad500000, 0x7af80000, 0xb3dc0000, 0x5b2e0000, 0x1f290000, 0x9d588000, 0xf28cc000, 0x07d62000, 0x71f51000, 0xd4f61800, 0xda65ec00, 0x632ea600, 0xe3291d00, 0x2358b280, 0x038ce7c0, 0x135641a0, 0x8b355c50, 0xa7d6ee78, 0xa1f5891c, 0x6cf6880e, 0xe665b4b9 },
+    { 0x80000000, 0x40000000, 0xa0000000, 0x90000000, 0x98000000, 0x54000000, 0x3a000000, 0x9d000000, 0x7e800000, 0x7f400000, 0x17200000, 0xab500000, 0x6df80000, 0x96a40000, 0x83d20000, 0x71e10000, 0xc0d88000, 0xe0f44000, 0x30aaa000, 0x08059000, 0xcc2a1800, 0x6e451400, 0xa78a1a00, 0xe3554d00, 0x01d2c680, 0x68e1fb40, 0xbc589520, 0xc6b4b250, 0xfb0a1178, 0x1515b0e4, 0xf272c872, 0xb1f12cf1 },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0xb0000000, 0x08000000, 0x84000000, 0xb2000000, 0xb9000000, 0xbe800000, 0x4fc00000, 0x55600000, 0xf8f00000, 0xac280000, 0x66d40000, 0xb30a0000, 0x8bb50000, 0xc7c88000, 0x11e4c000, 0xaa42e000, 0xa591b000, 0xd0ea8800, 0x78854400, 0x6c80d200, 0x86c0c900, 0x03e05680, 0x83307bc0, 0x4348ef60, 0xa324c5f0, 0x13a2a0a8, 0x1ba19014, 0x9f22d8ea, 0x2d61fc85 },
+    { 0x80000000, 0xc0000000, 0x60000000, 0x30000000, 0x78000000, 0x24000000, 0x9e000000, 0x47000000, 0x67800000, 0xf7400000, 0xdf200000, 0xb3100000, 0x71680000, 0x8c4c0000, 0x32520000, 0xe5d50000, 0xaa528000, 0x31d5c000, 0x2c52e000, 0x62d5f000, 0xadd29800, 0xf695d400, 0x8b720600, 0xf5c59300, 0x42ba6180, 0x3dd96440, 0xdea0bea0, 0xe750d750, 0x37c84fc8, 0xbf1c9b1c, 0x839a1d9a, 0x09c94ec9 },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0xb0000000, 0x78000000, 0x9c000000, 0xee000000, 0x1b000000, 0xcb800000, 0xc3400000, 0xc7a00000, 0x05100000, 0x88680000, 0xc4740000, 0x225a0000, 0x3da10000, 0x345a8000, 0x7aa1c000, 0xf1da6000, 0x12e17000, 0x85fa1800, 0x48b1ec00, 0x2432f600, 0x92d5f700, 0x45803d80, 0xa8403440, 0x94207a20, 0xea50f150, 0xd9c81248, 0x46648524, 0x8fb24812, 0x21952485 },
+    { 0x80000000, 0x40000000, 0x60000000, 0x10000000, 0x58000000, 0x7c000000, 0xc2000000, 0xe1000000, 0x0d800000, 0xd7c00000, 0x2aa00000, 0xf5300000, 0x9ba80000, 0xc0f40000, 0x20c60000, 0x702f0000, 0x48668000, 0x241f4000, 0xbe4ee000, 0x232b5000, 0xec28b800, 0xda342c00, 0xfde6fa00, 0xdfdf8d00, 0x6eee1780, 0x5b1b0ac0, 0xe0000520, 0x500093f0, 0x38008488, 0x6c008e04, 0x9a000bce, 0x9d00d8eb },
+    { 0x80000000, 0x40000000, 0x20000000, 0x30000000, 0xb8000000, 0xac000000, 0x72000000, 0xb1000000, 0x03800000, 0xd2c00000, 0xc1600000, 0x9b900000, 0x4e480000, 0x0b740000, 0x864e0000, 0x3f0b0000, 0x68068000, 0x447f4000, 0x7648a000, 0xe7747000, 0xd44e9800, 0xbe0b9c00, 0xd3864a00, 0x3abf5d00, 0xc528d180, 0xcde413c0, 0x99865ae0, 0x67bfd550, 0x94a8c528, 0x9e24cde4, 0xe3669986, 0x82ef67bf },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0x70000000, 0x88000000, 0x44000000, 0x4a000000, 0x47000000, 0xdd800000, 0x42400000, 0xc3200000, 0x77100000, 0x75b80000, 0x966c0000, 0x715e0000, 0xfc950000, 0xa6e68000, 0xd9f9c000, 0x28386000, 0x142cb000, 0x527e6800, 0xfb853400, 0x5b5e4200, 0x0b95c300, 0x1366f780, 0xafb9b540, 0x2918f6a0, 0x603cc150, 0xb0469498, 0x68a9927c, 0x34a09b66, 0xc250ebb9 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0x50000000, 0xd8000000, 0xfc000000, 0xf6000000, 0xd5000000, 0xbf800000, 0x2c400000, 0xeee00000, 0x09700000, 0x19080000, 0x21640000, 0xad6a0000, 0xd3130000, 0x22828000, 0x9707c000, 0x98e0a000, 0x1c709000, 0x8688f800, 0x5d24ac00, 0x9b8a2e00, 0x26632900, 0xcd8ac980, 0x63633940, 0x8a0af160, 0xe323b530, 0x4aea8fe8, 0xc3534414, 0x1a623a62, 0x1b774b77 },
+    { 0x80000000, 0x40000000, 0x60000000, 0x50000000, 0x58000000, 0xac000000, 0x6a000000, 0x85000000, 0xfb800000, 0xa8c00000, 0x84200000, 0xae300000, 0x4b080000, 0xe0740000, 0x10860000, 0x388f0000, 0xfc2e8000, 0x320b4000, 0x2980e000, 0x91c01000, 0x2da03800, 0x7ff0fc00, 0x06a83200, 0xcf842900, 0x4e2e9180, 0x5b0b2dc0, 0xd800ffa0, 0xec0046f0, 0x0a00af28, 0xd5001e44, 0xa380038e, 0x04c074fb },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0x50000000, 0xe8000000, 0x44000000, 0x5e000000, 0xad000000, 0xef800000, 0x68400000, 0x84600000, 0xfe500000, 0xfd280000, 0x07f40000, 0x2c620000, 0xda4f0000, 0x53068000, 0x12dfc000, 0x6f802000, 0xa8403000, 0x24602800, 0xae501400, 0x15283a00, 0x43f41100, 0x72621780, 0x774f2b40, 0xbc86bbe0, 0x7a9fda10, 0xebe00118, 0x56100f94, 0xd948174a, 0xa9a415fd },
+    { 0x80000000, 0xc0000000, 0x60000000, 0xb0000000, 0x18000000, 0x04000000, 0xda000000, 0x09000000, 0x22800000, 0xe8400000, 0xbc600000, 0x0e300000, 0x7b580000, 0x378c0000, 0x14c20000, 0x874d0000, 0x99d48000, 0xbfb94000, 0x18802000, 0x91403000, 0xe6e01800, 0x52702c00, 0x05380600, 0x34bc0100, 0x971a3680, 0x51810240, 0x13f688a0, 0xde847a10, 0x466c8f18, 0x1745738c, 0x91fa26d6, 0x73f111e3 },
+    { 0x80000000, 0x40000000, 0x20000000, 0x50000000, 0x88000000, 0x9c000000, 0x2e000000, 0x05000000, 0xab800000, 0x1c400000, 0x6e200000, 0x25100000, 0xfba80000, 0x94040000, 0xf26e0000, 0x0b070000, 0xfeaa8000, 0x3fd1c000, 0xee202000, 0x65101000, 0xdba80800, 0xc4041400, 0x7a6e2200, 0x97072700, 0xd0aa8b80, 0x3ad1c140, 0x45a00ae0, 0x79501710, 0xb5881388, 0xe1141d44, 0x81c61cea, 0x03030201 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0x50000000, 0xc8000000, 0x3c000000, 0x3e000000, 0x67000000, 0xf9800000, 0xcc400000, 0x66600000, 0xb3100000, 0xaba80000, 0x5d240000, 0xc4fe0000, 0xb8cf0000, 0x66bb8000, 0x71a8c000, 0x10602000, 0x28103000, 0x4c280800, 0xa6641400, 0x931e3200, 0xfb9f0f00, 0x95738f80, 0xf89cd9c0, 0x86b61e60, 0x01bb0310, 0x880d9198, 0xdc13f8c4, 0x4e6db8ea, 0xff03e849 },
+    { 0x80000000, 0x40000000, 0x20000000, 0xb0000000, 0x58000000, 0x44000000, 0x7e000000, 0x69000000, 0x5b800000, 0xdc400000, 0x5a200000, 0x87100000, 0xdad80000, 0x9bec0000, 0xbc420000, 0xca0f0000, 0x6f7c8000, 0xc6d9c000, 0xa1a02000, 0xab501000, 0xf8f80800, 0xe8fc2c00, 0x409a1600, 0x7ce31100, 0xf6be9f80, 0xb996da40, 0xcf7cb6e0, 0x36d9e710, 0xd9a03e88, 0x5f501dc4, 0xdef828b6, 0xc5fc1bfb },
+    { 0x80000000, 0x40000000, 0xa0000000, 0xb0000000, 0x48000000, 0x74000000, 0xc2000000, 0xe7000000, 0xb5800000, 0xba400000, 0x9b200000, 0xa3d00000, 0x2f180000, 0x81840000, 0xd82a0000, 0xcc190000, 0x5e078000, 0xe138c000, 0xd8982000, 0x9cc41000, 0x568a2800, 0x65892c00, 0xa23f9200, 0xb76cdd00, 0xedaa1080, 0x365929c0, 0x65278560, 0xf2e8c290, 0xbf8014c8, 0x694025f4, 0x4ca01346, 0x4e9035a1 },
+    { 0x80000000, 0x40000000, 0xa0000000, 0xf0000000, 0x98000000, 0xb4000000, 0x52000000, 0x07000000, 0xbf800000, 0x5a400000, 0x3b200000, 0x91d00000, 0xd3380000, 0xfdec0000, 0x954a0000, 0x58f10000, 0xb5df8000, 0x091dc000, 0x86b82000, 0xa4ac1000, 0x7bea2800, 0xd0613c00, 0x2847a600, 0x8c61ed00, 0x166a3480, 0xcd2111c0, 0x0ce787e0, 0xb7f1ea90, 0x667208c8, 0x151d1974, 0x1895884e, 0x15ecc2bb },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0x70000000, 0xf8000000, 0x4c000000, 0xa6000000, 0x89000000, 0x6e800000, 0x1a400000, 0x17600000, 0x4bf00000, 0xa2f80000, 0x7c5c0000, 0x7e360000, 0x551b0000, 0x40808000, 0x272d4000, 0x93982000, 0x7eac3000, 0x524e3800, 0x43071c00, 0xd1d6be00, 0x75c65300, 0xd7e08980, 0xacdd5240, 0xd16003a0, 0x72f02a90, 0xd47803d8, 0x5a1c1dfc, 0x37563f3e, 0xdbeb2e57 },
+    { 0x80000000, 0x40000000, 0x20000000, 0x30000000, 0xb8000000, 0x3c000000, 0xde000000, 0xdf000000, 0x29800000, 0x32400000, 0xe9200000, 0x62900000, 0x71d80000, 0x5e3c0000, 0x9f2e0000, 0x09e70000, 0x026b8000, 0x5176c000, 0x5ef82000, 0xafac1000, 0x81760800, 0xb69b0c00, 0x3be5ae00, 0xeb41cf00, 0x33eb9780, 0x2f36e7c0, 0xf1d82260, 0x1e3c1090, 0xbf2e1c48, 0x39e71ba4, 0xba6b85f6, 0x6d76ef4f },
+    { 0x80000000, 0x40000000, 0xa0000000, 0xd0000000, 0xf8000000, 0x3c000000, 0x6e000000, 0x19000000, 0x50800000, 0xca400000, 0x7b200000, 0xafd00000, 0x97a80000, 0x4b9c0000, 0x55ae0000, 0x64ef0000, 0xf0288000, 0x68524000, 0x64082000, 0x820c1000, 0x8f262800, 0x75a33400, 0xf4aebe00, 0xa8614f00, 0x842ebb80, 0xf2215640, 0xa70e9c20, 0xb1f15690, 0xa6a6a8c8, 0xdf6d40f4, 0xcd88886a, 0x68c27fa7 },
+    { 0x80000000, 0x40000000, 0x60000000, 0xd0000000, 0xc8000000, 0xbc000000, 0x4e000000, 0x57000000, 0x80800000, 0x0a400000, 0xfd200000, 0x8db00000, 0xffa80000, 0xa6840000, 0x110e0000, 0x4bdf0000, 0x74d78000, 0xb8724000, 0x84082000, 0x8a741000, 0xbd061800, 0xedab3400, 0x2fd1b200, 0x6ed96f00, 0xad59b380, 0x05ed45c0, 0x23ff9820, 0x38b66690, 0x8e263548, 0x771b286c, 0x30f9866a, 0x121d6761 },
+    { 0x80000000, 0x40000000, 0x20000000, 0xb0000000, 0xa8000000, 0xd4000000, 0xfa000000, 0xf9000000, 0x92800000, 0x19400000, 0x42a00000, 0x21500000, 0x8ef80000, 0xa7040000, 0x59920000, 0x36f90000, 0x2b2e8000, 0xffd04000, 0x51922000, 0x12f91000, 0x592e8800, 0x62d06c00, 0x91120a00, 0x26b92500, 0x730eb680, 0xa3c05240, 0xcfca2ea0, 0xb9ad2350, 0xe6c4a628, 0x136d5a14, 0x338e8d1e, 0xd7804a91 },
+    { 0x80000000, 0x40000000, 0xe0000000, 0xb0000000, 0x58000000, 0x1c000000, 0x72000000, 0x4f000000, 0xa1800000, 0x77400000, 0x4da00000, 0xbd300000, 0xaef80000, 0x369c0000, 0x8ab60000, 0xa8850000, 0x0fe18000, 0xea0dc000, 0xf3362000, 0x83c51000, 0xd041b800, 0xa83dec00, 0xa44e3600, 0xde191700, 0x6557a480, 0xf288ffc0, 0xa4d79e60, 0x75c8cad0, 0x517797e8, 0x64f8c08c, 0xd58f8dde, 0x0164eb77 },
+    { 0x80000000, 0x40000000, 0xa0000000, 0x50000000, 0x88000000, 0x34000000, 0xa2000000, 0x03000000, 0x41800000, 0xf7400000, 0x03a00000, 0x04100000, 0x9a080000, 0x4f140000, 0x0fb20000, 0xea550000, 0xd73b8000, 0x13a1c000, 0x2c122000, 0xfe451000, 0x6533a800, 0x38b5d400, 0x09a00200, 0x23101d00, 0x51880080, 0xdf5414c0, 0x67923260, 0x2e0530d0, 0xad13a868, 0xace5c1c4, 0xfb8816e2, 0xa8543e15 },
+    { 0x80000000, 0x40000000, 0xe0000000, 0xd0000000, 0xb8000000, 0x1c000000, 0x82000000, 0xfb000000, 0xed800000, 0x87400000, 0xffa00000, 0x24300000, 0xde480000, 0x992c0000, 0xc6e60000, 0xd2dd0000, 0x64938000, 0x59a7c000, 0x01462000, 0xaaed1000, 0xd8dbb800, 0xeb8bf400, 0x92200e00, 0xe3701700, 0xc1e81880, 0x6d1c0ac0, 0xa0ae1560, 0x57f126d0, 0x20759f68, 0x707af7cc, 0x8855acf2, 0x740ad79b },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0x10000000, 0x48000000, 0xac000000, 0x06000000, 0x95000000, 0x05800000, 0xc9400000, 0x3be00000, 0x08100000, 0xcc680000, 0xb6740000, 0xcd5e0000, 0xe1a70000, 0x635c8000, 0xa8e1c000, 0x98be2000, 0x00b73000, 0x44b4a800, 0xfed5c400, 0x25803200, 0x19401b00, 0xd3e02980, 0xb4102140, 0x82681360, 0x8f741950, 0xcede0f78, 0xbde72744, 0x5d3cb27a, 0x69b1dfcd },
+    { 0x80000000, 0x40000000, 0x60000000, 0xd0000000, 0xf8000000, 0x34000000, 0x1a000000, 0xff000000, 0xf3800000, 0x93400000, 0x2da00000, 0x3e700000, 0x3d480000, 0x88cc0000, 0x52b20000, 0x8d910000, 0xce358000, 0x750cc000, 0x94922000, 0x84a11000, 0x5cdd9800, 0xd8b0f400, 0xeae81e00, 0xd9bc1d00, 0x047a1e80, 0x721d0bc0, 0x532782e0, 0x0dede9d0, 0x8e6fade8, 0x1521e05c, 0x44dd8bb2, 0x7cb0e2e3 },
+    { 0x80000000, 0xc0000000, 0x60000000, 0x10000000, 0x28000000, 0xfc000000, 0xb2000000, 0x5b000000, 0x3f800000, 0x7f400000, 0x89e00000, 0x22700000, 0xb3680000, 0xa3a40000, 0xdd360000, 0xfaad0000, 0xe1a38000, 0x7e6ec000, 0x71562000, 0xc09d3000, 0x36ab9800, 0xcbfac400, 0x81682a00, 0x38a40f00, 0x82b63480, 0x95ed12c0, 0x404385e0, 0xa01ee0d0, 0x703e2ef8, 0x38392e5c, 0xd41dbb3a, 0x4e17f339 },
+    { 0x80000000, 0x40000000, 0x60000000, 0x30000000, 0x08000000, 0x4c000000, 0xf6000000, 0x7f000000, 0x76800000, 0x19400000, 0x11a00000, 0x7bf00000, 0x8af80000, 0xa7540000, 0x42ae0000, 0xcb170000, 0xe4a58000, 0x8c124000, 0xd6562000, 0x2f431000, 0x4e8b9800, 0x5d454c00, 0xabd3a200, 0xf2e14300, 0x83058580, 0xc8e243c0, 0x4a2e27a0, 0xa1570950, 0x1585a3e8, 0xa1a25e3c, 0x338e209e, 0xa6a73345 },
+    { 0x80000000, 0x40000000, 0xa0000000, 0x70000000, 0xb8000000, 0x7c000000, 0x4a000000, 0xf3000000, 0x90800000, 0x81400000, 0x5fa00000, 0xfb900000, 0x5dd80000, 0x8cec0000, 0x5b360000, 0xc4b10000, 0xdf338000, 0x52974000, 0x166e2000, 0x891d1000, 0x7ba5a800, 0x1db65c00, 0x2c858e00, 0x2b664f00, 0x7cfd9a80, 0xa31a70c0, 0x18938220, 0xe5077350, 0x19b62368, 0xfaf11124, 0x4213a7d6, 0xd7477cab },
+    { 0x80000000, 0x40000000, 0xa0000000, 0xb0000000, 0x88000000, 0xd4000000, 0xea000000, 0xb7000000, 0xf5800000, 0xa5400000, 0xfea00000, 0x7e900000, 0x3eb80000, 0x9ef40000, 0x2e820000, 0xa6d90000, 0x729d8000, 0x98c9c000, 0x2fba2000, 0xda6d1000, 0x7f3fa800, 0x81c0ec00, 0xff3f8200, 0xc1c0e500, 0x5f3fb280, 0x71c0d1c0, 0xd73f9760, 0xa5c0e050, 0x3d3faf28, 0x12c0fb64, 0xc8bfa24e, 0xb780ea2d },
+    { 0x80000000, 0x40000000, 0x20000000, 0x50000000, 0x08000000, 0x34000000, 0x1a000000, 0xd1000000, 0xac800000, 0x57400000, 0x43a00000, 0x18d00000, 0x0d480000, 0xb2b40000, 0xe4620000, 0x52010000, 0xc5668000, 0xe6e94000, 0x8e0a2000, 0xdb251000, 0x55ec8800, 0x9f8c5400, 0x06c6a200, 0xbe395d00, 0xa3422e80, 0x39913040, 0xb98ea120, 0xf98d4cd0, 0xd9a03468, 0x89d02f74, 0x81c826f2, 0xb5f4193d },
+    { 0x80000000, 0x40000000, 0x60000000, 0xf0000000, 0x08000000, 0xe4000000, 0xe6000000, 0x07000000, 0x10800000, 0x7d400000, 0x5da00000, 0x08f00000, 0x21180000, 0x37940000, 0xfdfa0000, 0xd8ef0000, 0xb9258000, 0x2be14000, 0xf7c22000, 0xddcb1000, 0x48e79800, 0x412a7c00, 0xc7a5a200, 0xf5a16900, 0x3ce20180, 0x5f7b2dc0, 0x2cdf9e20, 0xe70e5a50, 0xa0e78ce8, 0x152a6afc, 0x49a58de6, 0xe6a17f75 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0xb0000000, 0x38000000, 0xac000000, 0xa2000000, 0xcf000000, 0x57800000, 0x2fc00000, 0x63a00000, 0x51b00000, 0x16e80000, 0xd5740000, 0xf4e20000, 0xfa130000, 0x33448000, 0x5dc74000, 0xc4c4a000, 0x02077000, 0xbf64a800, 0x4fb75c00, 0x338ca600, 0xf9c37700, 0x32ee8e80, 0xe31044c0, 0x358a1b60, 0xc0a70f30, 0x8406a388, 0x46646b5c, 0xd9680e32, 0x26b40201 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0x10000000, 0x78000000, 0x6c000000, 0x7e000000, 0xff000000, 0x18800000, 0xc0c00000, 0x7ca00000, 0x5ab00000, 0xd9b80000, 0xc7040000, 0x94f20000, 0x8eed0000, 0xebe28000, 0x5676c000, 0x0b62a000, 0x3ab6f000, 0x29c2a800, 0x8f06f400, 0x90fab600, 0xe4c2ef00, 0x06a8a980, 0xcf9fd0c0, 0x2c722fa0, 0x9e2d20f0, 0xcf429088, 0x70c6c65c, 0xd4da8ee6, 0x6eb2c39d },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0x30000000, 0xd8000000, 0xf4000000, 0xd2000000, 0xab000000, 0x98800000, 0x90c00000, 0xeca00000, 0x82f00000, 0xe7e80000, 0x2a040000, 0xaf3e0000, 0x32b70000, 0xfff28000, 0x7e46c000, 0x4d72a000, 0x4186f000, 0x93528800, 0x3cb6fc00, 0x0a9abe00, 0x5b82c100, 0xe46c8a80, 0xfa01ebc0, 0x27682ca0, 0x8ec40ff0, 0x319e3788, 0x2b471f4c, 0x589aa672, 0x3082d9cd },
+    { 0x80000000, 0x40000000, 0xa0000000, 0x30000000, 0x08000000, 0x0c000000, 0x72000000, 0xf9000000, 0x4a800000, 0x86c00000, 0x14e00000, 0x7db00000, 0x0f280000, 0x8dec0000, 0xe70a0000, 0x11830000, 0xad578000, 0xecdec000, 0x99b7a000, 0xe16ed000, 0x3e9f8800, 0x5082dc00, 0xa3958a00, 0xb401df00, 0x36421680, 0x271f2140, 0xf195a420, 0x3d01d0f0, 0xd4c22918, 0x9ddf139c, 0x9f75a0d2, 0xb5b1efe7 },
+    { 0x80000000, 0x40000000, 0x60000000, 0x50000000, 0x28000000, 0xe4000000, 0x1e000000, 0x0d000000, 0x4f800000, 0x03c00000, 0xb9e00000, 0xcad00000, 0xd8780000, 0xbc2c0000, 0xe27e0000, 0x8f410000, 0x90ef8000, 0xbb1c4000, 0xe68fa000, 0x320c5000, 0xe717b800, 0x14f04400, 0xf511b200, 0xc39d7d00, 0x99803580, 0xfac03e40, 0xa0600660, 0x70102eb0, 0x18183018, 0x9c3c0804, 0xd2660c06, 0xf77d1e0f },
+    { 0x80000000, 0x40000000, 0x20000000, 0xb0000000, 0x38000000, 0x2c000000, 0xd2000000, 0x8d000000, 0x70800000, 0x14c00000, 0xb2e00000, 0x51f00000, 0xf6280000, 0x0b740000, 0x23c20000, 0x8b7b0000, 0x63858000, 0xab51c000, 0xd3e5a000, 0x9361d000, 0xffada800, 0x4125fc00, 0x72a7a600, 0x31daf700, 0x66481280, 0x83441440, 0x378a2ea0, 0x753f0170, 0x3c8f8a18, 0x56aef90c, 0xb78a1992, 0x353f20d1 },
+    { 0x80000000, 0xc0000000, 0x60000000, 0x50000000, 0xd8000000, 0xec000000, 0xf2000000, 0x65000000, 0x87800000, 0x05c00000, 0x48a00000, 0xcb100000, 0x58f80000, 0xb3340000, 0x84d20000, 0xc9130000, 0xd5f58000, 0x50944000, 0x470da000, 0xfaa07000, 0x0e5fb800, 0xef736400, 0x3e8a0e00, 0xf8371f00, 0x1c5f9280, 0x1a737640, 0x010a0b60, 0x41f71330, 0x7eff9748, 0x58637ef4, 0x2c7233f6, 0x92031479 },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0x90000000, 0x58000000, 0xc4000000, 0x66000000, 0x3b000000, 0x39800000, 0xd7c00000, 0x10a00000, 0xbb700000, 0xf9f80000, 0x77f40000, 0x80a60000, 0xe30d0000, 0x3db48000, 0x11c64000, 0xbbcca000, 0xdaf27000, 0xea4a8800, 0x014f5400, 0x00a61e00, 0x230d2500, 0x9db4a780, 0x81c65bc0, 0xe3cca1e0, 0x1ef27a30, 0x8c4a9bc8, 0x3a4f41ec, 0x39262a36, 0xf4cd23d1 },
+    { 0x80000000, 0x40000000, 0xe0000000, 0x10000000, 0xb8000000, 0xb4000000, 0xfa000000, 0x47000000, 0xd1800000, 0x1fc00000, 0xe2e00000, 0x94100000, 0x4a580000, 0x0f240000, 0xcd8e0000, 0xe9bb0000, 0xebe48000, 0xf8a64000, 0xc35ca000, 0x23925000, 0xa48a9800, 0xd50d5400, 0x3ae03600, 0x70103900, 0xe8582880, 0xec2438c0, 0x5e0e24e0, 0x057b3b30, 0x2284b258, 0x34767334, 0xba64be4e, 0xa766713d },
+    { 0x80000000, 0x40000000, 0x60000000, 0x50000000, 0xb8000000, 0x14000000, 0xd2000000, 0x6d000000, 0x25800000, 0x73c00000, 0x54e00000, 0x38500000, 0x54380000, 0xb2440000, 0x3d7e0000, 0x9dbf0000, 0x67958000, 0x86ad4000, 0x554da000, 0x71b95000, 0xc18bb800, 0x69824400, 0xa5801600, 0x33c00100, 0x34e00280, 0x68500a40, 0xec3813e0, 0xa64402b0, 0xef7e28d8, 0xf0bf09a4, 0x42158956, 0xf56d7e75 },
+    { 0x80000000, 0x40000000, 0xe0000000, 0xf0000000, 0x38000000, 0x2c000000, 0x86000000, 0x79000000, 0xe2800000, 0xd8c00000, 0xafe00000, 0xc0100000, 0xa0280000, 0x10140000, 0xc8720000, 0x14490000, 0xaa698000, 0xff0ec000, 0x9ba1a000, 0x3a0ad000, 0x777b9800, 0x6f97ec00, 0x60001600, 0xb0002700, 0xd8001780, 0xdc002940, 0xbe001720, 0x55002370, 0x648032d8, 0xa1c01874, 0x4d603b52, 0x18d00231 },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0x30000000, 0x48000000, 0x34000000, 0x3e000000, 0x1b000000, 0xe0800000, 0xe2c00000, 0xd3a00000, 0xc6500000, 0xa7080000, 0x0acc0000, 0xf7e60000, 0x60010000, 0xf0188000, 0xa80ac000, 0x0430a000, 0x7656f000, 0x2f7e9800, 0xdecbfc00, 0xf9880a00, 0x330c3100, 0x24c62580, 0x749107c0, 0xccb0a5a0, 0x5096f370, 0x6adea348, 0x079bffe4, 0xc8003d0a, 0xf4003797 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0xf0000000, 0x98000000, 0x9c000000, 0x4e000000, 0x59000000, 0x07800000, 0xddc00000, 0xdea00000, 0x1a300000, 0x23080000, 0x34a40000, 0xa13a0000, 0x8bc50000, 0xdb958000, 0x73d04000, 0x57bda000, 0x75847000, 0xfaafa800, 0x38154c00, 0xac280e00, 0xf6542b00, 0x35123d80, 0xd1910d40, 0x1887b460, 0x97414630, 0x9eba05c8, 0xfa0517bc, 0xf335b68a, 0x5ce040d5 },
+    { 0x80000000, 0x40000000, 0x20000000, 0x10000000, 0x08000000, 0x84000000, 0x92000000, 0x91000000, 0xbd800000, 0x8cc00000, 0x61600000, 0xc5b00000, 0x30d80000, 0x6f6c0000, 0x4af60000, 0x0a530000, 0x5d2d8000, 0x8bc04000, 0x9fdba000, 0x45935000, 0x70f62800, 0x4f531400, 0x5aad8a00, 0x02006500, 0xd93b8680, 0x19e35540, 0x0ece23e0, 0xf84f1370, 0xfc63bd38, 0x2e4f775c, 0x9f5812ee, 0x32ac3ff7 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0xf0000000, 0x78000000, 0xac000000, 0x3a000000, 0x0d000000, 0xf1800000, 0x6cc00000, 0xf5200000, 0x9df00000, 0x76a80000, 0x08640000, 0x141a0000, 0xb6230000, 0xc75f8000, 0x84944000, 0x3145a000, 0xa3b77000, 0x659a2800, 0x1ae30c00, 0x127f9600, 0xe9645700, 0x3fedb080, 0x07d35840, 0x4b801ae0, 0xa1c01470, 0x24a01728, 0x01302b4c, 0xfb883062, 0x39940d25 },
+    { 0x80000000, 0x40000000, 0xe0000000, 0x30000000, 0x98000000, 0x6c000000, 0xaa000000, 0x83000000, 0xd7800000, 0xc0c00000, 0xa1600000, 0x30d00000, 0x99280000, 0x8cf40000, 0x9b4a0000, 0xfbdb0000, 0x8ae88000, 0x12644000, 0x7f42a000, 0x35af5000, 0x87e21800, 0x28ef1c00, 0xb5429e00, 0xc6af5700, 0x28622c80, 0xb42f2bc0, 0x2622a760, 0x197f5cf0, 0xccca1bb8, 0x7b1b3704, 0xcb889c92, 0x12b443c9 },
+    { 0x80000000, 0xc0000000, 0x60000000, 0x30000000, 0x28000000, 0x8c000000, 0x2e000000, 0xc3000000, 0xae800000, 0x79c00000, 0x9d200000, 0xe5d00000, 0x0b680000, 0xd2ec0000, 0x1fa20000, 0xe2690000, 0x4d328000, 0x3dd8c000, 0xcf30a000, 0x40a1f000, 0xdaca3800, 0x03853c00, 0xb4109200, 0x1a71ef00, 0x19222180, 0xd7a923c0, 0x9e12b820, 0x2b08e2b0, 0x42d8a6e8, 0x678df404, 0x76481612, 0xc73c010f },
+    { 0x80000000, 0xc0000000, 0x60000000, 0x70000000, 0x48000000, 0x6c000000, 0x4e000000, 0x3b000000, 0x94800000, 0xc1c00000, 0xbe200000, 0xb3500000, 0x98880000, 0xffdc0000, 0xcd320000, 0x4bc10000, 0x17728000, 0x7aabc000, 0xeac8a000, 0x12b6f000, 0x56883800, 0x04dc2c00, 0x39b20a00, 0xfa010700, 0xe1528180, 0xa5fbd5c0, 0x3c4096a0, 0xd66aceb0, 0x0f3a32a8, 0x8edd30a4, 0x90e083aa, 0x33fad423 },
+    { 0x80000000, 0x40000000, 0x60000000, 0x90000000, 0x58000000, 0x44000000, 0x1a000000, 0xf1000000, 0x4e800000, 0xf5c00000, 0x32600000, 0x3d100000, 0x28f80000, 0xcaa40000, 0xcfee0000, 0x337f0000, 0xbbad8000, 0xc14bc000, 0xa6bba000, 0x1990d000, 0xa4783800, 0xca643400, 0xc90e0e00, 0x9aaf3500, 0xb7b59080, 0x873fed40, 0x69cdb520, 0x2c5bd130, 0xb643a738, 0x0734c634, 0x299628a6, 0x4c1b18ed },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xc8000000, 0xe4000000, 0x42000000, 0xbd000000, 0x6a800000, 0x05c00000, 0x2a200000, 0x89100000, 0xf0880000, 0x64dc0000, 0x2eb60000, 0x97830000, 0x4f578000, 0x3fe7c000, 0x9b69a000, 0x55b8f000, 0x32081800, 0xb51c0c00, 0x6e960a00, 0xb7930500, 0x5f5fa280, 0x07fbd640, 0xb77faa20, 0xf3ebde30, 0xcd778828, 0x62f7ef34, 0x01e19caa, 0x9864ce73 },
+    { 0x80000000, 0x40000000, 0xe0000000, 0x10000000, 0x48000000, 0xdc000000, 0x92000000, 0x53000000, 0x6c800000, 0x85c00000, 0x36600000, 0xe5500000, 0xc9f80000, 0xac6c0000, 0x8a6a0000, 0x27570000, 0x32e88000, 0x0cfbc000, 0xd5faa000, 0x9e00d000, 0x29181800, 0x13fc1400, 0x23722a00, 0x74ab3300, 0xf19ab680, 0x6850e3c0, 0x6c601fa0, 0x2a5025b0, 0xd7782eb8, 0x6aac1c24, 0x988a2de6, 0x9bc7254f },
+    { 0x80000000, 0xc0000000, 0x60000000, 0xd0000000, 0x98000000, 0x6c000000, 0x2e000000, 0x71000000, 0x7c800000, 0xebc00000, 0xd2200000, 0x67500000, 0xd1d80000, 0xf1640000, 0xbc9a0000, 0x8bd10000, 0x02678000, 0xff1ac000, 0xbda5a000, 0xdf6ff000, 0xcdf83800, 0xf7340400, 0xe9c23e00, 0x2d752f00, 0xdaddad80, 0x0e9bc740, 0x3c9a34a0, 0x4bd116b0, 0x6267b3a8, 0x2f1ad724, 0x25a586fe, 0xb36fce8d },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0x30000000, 0xb8000000, 0xac000000, 0x06000000, 0xfd000000, 0xef800000, 0xf8c00000, 0x8c200000, 0xf6300000, 0xe5480000, 0x73c40000, 0x46ca0000, 0xdd750000, 0x1fcd8000, 0xe0814000, 0x106fa000, 0x48007000, 0xb4200800, 0x9a303c00, 0x43480600, 0xbec42700, 0x114a2f80, 0x89b51440, 0x95edba60, 0xebb14170, 0x1aa7b8e8, 0xc30473bc, 0x7eca125a, 0xb1751d7d },
+    { 0x80000000, 0x40000000, 0xa0000000, 0x50000000, 0x58000000, 0x14000000, 0x5a000000, 0x75000000, 0x6c800000, 0x87c00000, 0xdc600000, 0xf6700000, 0xcb780000, 0x4b840000, 0xd2660000, 0x79070000, 0x82c78000, 0xf8e4c000, 0x9db9a000, 0x0917d000, 0xcae00800, 0x14b00400, 0x83983e00, 0x7e341100, 0xc77e0080, 0xa5f31840, 0xad598da0, 0x38a7fcb0, 0x7df80c38, 0xf9440c6c, 0xc2862dc6, 0x58b73b7d },
+    { 0x80000000, 0xc0000000, 0x60000000, 0x70000000, 0xe8000000, 0x94000000, 0x42000000, 0x7b000000, 0x49800000, 0x3cc00000, 0x90200000, 0x58500000, 0x1c080000, 0xa64c0000, 0xd13e0000, 0xa6eb0000, 0x375c8000, 0xd7f94000, 0x81caa000, 0x78ce7000, 0x2a003800, 0x2f002c00, 0x6b802200, 0x37c03900, 0x31a02a80, 0xf0903bc0, 0xce2802e0, 0x851c11f0, 0x84b63668, 0x3c671924, 0x7642a30a, 0x29427f87 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0xf0000000, 0x28000000, 0x14000000, 0x4a000000, 0xe3000000, 0x6f800000, 0x72c00000, 0x70200000, 0xe8300000, 0x34080000, 0xba3c0000, 0xcb0a0000, 0x7b850000, 0x38d28000, 0x9318c000, 0x87abe000, 0x46d4b000, 0xca000800, 0x23000c00, 0x4f800200, 0x82c00f00, 0x58200280, 0xfc300140, 0x7e0804a0, 0x593c0e30, 0xa48a06f8, 0x0945072c, 0x48f28702, 0x7b28ce83 },
+    { 0x80000000, 0x40000000, 0xe0000000, 0x50000000, 0x28000000, 0x9c000000, 0x7e000000, 0xff000000, 0x43800000, 0x79c00000, 0xb8200000, 0x14100000, 0x52380000, 0xf9140000, 0x088a0000, 0xd8670000, 0x40ff8000, 0x108fc000, 0x7c78e000, 0x6ad27000, 0x5d800800, 0x96c00400, 0x33a00e00, 0xa1d00500, 0xbc180280, 0x8e0409c0, 0x673207e0, 0xa7b30ff0, 0xb3d58438, 0xa538c79c, 0xd69f6b82, 0x9759b141 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0x70000000, 0x48000000, 0x1c000000, 0xae000000, 0xf9000000, 0x6c800000, 0x95c00000, 0x7c200000, 0x3e300000, 0xe1080000, 0x489c0000, 0x6fd20000, 0x37270000, 0x059b8000, 0xe1764000, 0xcde72000, 0xb8277000, 0x94200800, 0x92300c00, 0x27080200, 0xdd9c0700, 0xe5520480, 0x47e701c0, 0xbb3b8ae0, 0xb3864f90, 0x3c4f26c8, 0x5b4b795c, 0x66da0fc2, 0xd3bb0fe3 },
+    { 0x80000000, 0x40000000, 0x60000000, 0xd0000000, 0x48000000, 0xbc000000, 0x0e000000, 0xe1000000, 0xb5800000, 0x3dc00000, 0x8c200000, 0xd6100000, 0x75180000, 0xd7b40000, 0x9ad20000, 0x648f0000, 0x50538000, 0x25c04000, 0x38296000, 0x04157000, 0x4a200800, 0xcb100400, 0xae980600, 0xdb740d00, 0xeb720480, 0x335f0bc0, 0xa76b80e0, 0xc5644e10, 0x62636b58, 0x8aee73dc, 0x0c8180c2, 0x5c4f4961 },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0xd0000000, 0x98000000, 0x34000000, 0x12000000, 0x43000000, 0x04800000, 0xb8400000, 0x46200000, 0x41300000, 0x3fb80000, 0x58f40000, 0x74460000, 0x701d0000, 0x680c8000, 0x9c1cc000, 0x6e132000, 0xfd051000, 0x61980800, 0xedc40c00, 0xb9fe0e00, 0xbbe90d00, 0x80ca8980, 0x6041c340, 0x523fa120, 0x6329d430, 0x34b32848, 0xf0751784, 0xea000262, 0x67000513 },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0x50000000, 0x98000000, 0xec000000, 0x0e000000, 0x29000000, 0x9f800000, 0xa9400000, 0x52200000, 0x8f300000, 0x32a80000, 0x1cd40000, 0xa8460000, 0x89ab0000, 0xac5b8000, 0x63964000, 0x5f65e000, 0x673f5000, 0xd6880800, 0xc6e40c00, 0x336e0a00, 0xa93f0500, 0x5fbd8980, 0x094d4ec0, 0x023660e0, 0x170d1290, 0xdea3e1f8, 0x12d45694, 0x81738722, 0x160241f3 },
+    { 0x80000000, 0x40000000, 0xa0000000, 0x30000000, 0xf8000000, 0xfc000000, 0x1e000000, 0x2b000000, 0x67800000, 0xc5400000, 0xab200000, 0x27900000, 0x65680000, 0x9b2c0000, 0xdfae0000, 0x99570000, 0x852b8000, 0xf4a4c000, 0xfecee000, 0x405ad000, 0x5fae0800, 0xd9570400, 0x252b8a00, 0xc4a4c300, 0x06ceef80, 0xbc5adfc0, 0x41ae09e0, 0xf25706b0, 0x42ab8c78, 0x01e4cf54, 0xadeee532, 0x9bcaddb9 },
+    { 0x80000000, 0x40000000, 0xe0000000, 0x90000000, 0x68000000, 0x9c000000, 0x06000000, 0x2f000000, 0xf8800000, 0x2a400000, 0x7f200000, 0x30900000, 0xc6780000, 0x81040000, 0xeb8a0000, 0xa4df0000, 0x82458000, 0x4321c000, 0x46b12000, 0x11571000, 0x8d8a0800, 0x5bdf0400, 0xf2c58e00, 0x6561c900, 0x57912680, 0x92c719c0, 0xb5720860, 0xdf9b06f0, 0x9eef8188, 0xdb6ecba4, 0x6c8ca172, 0x6072dac9 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0x70000000, 0xa8000000, 0x44000000, 0xc2000000, 0x13000000, 0xcf800000, 0xe2400000, 0x71200000, 0x6cb00000, 0xa5c80000, 0xa77c0000, 0x77ba0000, 0x9e690000, 0x0f048000, 0x2182c000, 0x5740e000, 0x1fa51000, 0xfa720800, 0xbd150c00, 0x9abe8200, 0xdcebc700, 0x3fc46a80, 0x9867d440, 0x1e12e420, 0xdd001d30, 0x0a8486f8, 0x24c2c524, 0xa3e0ef92, 0xb655158b },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0x10000000, 0x18000000, 0x7c000000, 0x8e000000, 0x6f000000, 0x52800000, 0x1fc00000, 0x59200000, 0x71b00000, 0x2b780000, 0x5de40000, 0x90160000, 0xd8170000, 0x9c1f8000, 0x9e19c000, 0x770da000, 0x2ebb7000, 0x91ee0800, 0x36330c00, 0x23298e00, 0x34bec100, 0x04ea2180, 0xe186b7c0, 0xf355a0e0, 0xc1ef7af0, 0x0e000328, 0xaf000cfc, 0xb2800a12, 0x0fc001db },
+    { 0x80000000, 0x40000000, 0xa0000000, 0xb0000000, 0x08000000, 0xf4000000, 0xa6000000, 0x77000000, 0x65800000, 0xd3c00000, 0x45200000, 0xe4900000, 0xd9680000, 0xbf4c0000, 0x28720000, 0x5de50000, 0x361d8000, 0x8f0bc000, 0x39a26000, 0x31ce7000, 0x9c3a0800, 0x02390400, 0xc9078a00, 0x5ea2cb00, 0xec4de080, 0xb3e0bf40, 0x1525e260, 0xfcacb370, 0x9557e458, 0xe549b23c, 0x0d4a66d2, 0xe9427e09 },
+    { 0x80000000, 0xc0000000, 0x60000000, 0xd0000000, 0x48000000, 0xf4000000, 0x26000000, 0x61000000, 0x17800000, 0x08c00000, 0xbb200000, 0x04b00000, 0xe8580000, 0x5d540000, 0x1cc20000, 0x8d350000, 0x4d958000, 0xdbe64000, 0x3bbee000, 0x32d4b000, 0xb83a0800, 0xcc110c00, 0x2a2f8600, 0x2b374d00, 0xecb16480, 0xac53ff40, 0xe3536a60, 0xc1d6fa10, 0x489eef78, 0x0264b18c, 0x16620132, 0x20450e0b },
+    { 0x80000000, 0x40000000, 0xe0000000, 0x70000000, 0x78000000, 0x74000000, 0x7e000000, 0x5f000000, 0xd0800000, 0x75400000, 0x7d200000, 0x2d900000, 0x18f80000, 0x85fc0000, 0xd86e0000, 0xb8950000, 0x496b8000, 0xef0dc000, 0x08bb2000, 0x9179d000, 0x0b360800, 0x7eb90400, 0xc25d8e00, 0xd1b4c700, 0x2ae6a780, 0x30cd1740, 0x59d0afe0, 0x3a7411f0, 0xe58d2b08, 0xb4c0d454, 0x1feb8652, 0xf14dc699 },
+    { 0x80000000, 0xc0000000, 0x20000000, 0x90000000, 0xc8000000, 0x24000000, 0x8e000000, 0x39000000, 0x6a800000, 0x60400000, 0x5aa00000, 0xf8700000, 0x96a80000, 0xc2540000, 0xe99a0000, 0xb5dd0000, 0x6d798000, 0xb6334000, 0xa5332000, 0xb8b35000, 0xab798800, 0x6b334c00, 0x61b32200, 0x71f35900, 0x53598480, 0xd7034e40, 0x23bb2ae0, 0x72d75a90, 0x46eb8228, 0xc0ca4844, 0xfdf8af4a, 0x89491517 },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0xd0000000, 0xf8000000, 0xbc000000, 0xca000000, 0x39000000, 0x13800000, 0x55400000, 0xbba00000, 0xd1700000, 0x6d880000, 0xf2440000, 0xbf360000, 0x08ab0000, 0x9be48000, 0x5b754000, 0x34986000, 0x91ec1000, 0xc2648800, 0xf7354c00, 0x3cb86a00, 0xc5dc1d00, 0xec4c8780, 0x680147c0, 0x240666a0, 0x06331e90, 0xdb1e06b8, 0x6e9f0294, 0x30da8d1a, 0x1dda4387 },
+    { 0x80000000, 0x40000000, 0x60000000, 0x30000000, 0xf8000000, 0xe4000000, 0xfa000000, 0xad000000, 0xb6800000, 0x89c00000, 0x92a00000, 0x53d00000, 0x6fb80000, 0x2d5c0000, 0xfa460000, 0xa1c50000, 0xfea88000, 0xd5d64000, 0xec992000, 0x34d23000, 0x8c088800, 0xf6064400, 0x1b212600, 0xcd8e3300, 0x744e8780, 0x1ec34a40, 0xa909a9a0, 0x3c9879d0, 0xbcf7ace8, 0xf00172dc, 0xd819288a, 0xb41238ed },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0x10000000, 0x68000000, 0xe4000000, 0x86000000, 0x9d000000, 0xe1800000, 0xb0c00000, 0xeda00000, 0x12f00000, 0x16980000, 0x7e740000, 0x2fc20000, 0xc72d0000, 0x56b38000, 0x5e624000, 0xdfe7e000, 0xbf387000, 0xda938800, 0x3c524c00, 0xc4dfee00, 0xc3bc7100, 0x8bc98e80, 0x610b4240, 0x3bae6660, 0xc7f338d0, 0xe31de098, 0x3091794c, 0xd37a00ba, 0x566905ff },
+    { 0x80000000, 0x40000000, 0x20000000, 0x70000000, 0xa8000000, 0x34000000, 0xd2000000, 0x59000000, 0xd6800000, 0xf1400000, 0x9aa00000, 0x8f500000, 0xada80000, 0x96cc0000, 0xa9420000, 0x46a10000, 0x49468000, 0x56af4000, 0xb1672000, 0xbaa51000, 0xff668800, 0x05bf4400, 0xa2ef2200, 0x7b791700, 0x1fac8280, 0x9fc24740, 0xa7e3af20, 0x2beb5290, 0x35e72fe8, 0x52e51854, 0x93468e8a, 0x0baf4e65 },
+    { 0x80000000, 0x40000000, 0xa0000000, 0x90000000, 0x88000000, 0xcc000000, 0x5a000000, 0x77000000, 0x4e800000, 0x23400000, 0xd4a00000, 0xb4500000, 0xaa080000, 0x8f340000, 0x3a8a0000, 0xad570000, 0xbd948000, 0x1bfec000, 0xeacd2000, 0x41411000, 0x379c8800, 0x44cac400, 0xf8472a00, 0xb0161900, 0x58080080, 0xe43408c0, 0x060a0fa0, 0xa5170e70, 0xf5b48c68, 0x37eecef4, 0x80e528ea, 0x2e651c35 },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0x70000000, 0x68000000, 0xb4000000, 0xb6000000, 0x09000000, 0x40800000, 0xb9400000, 0x3ea00000, 0x54700000, 0x30180000, 0x482c0000, 0x24220000, 0xae310000, 0xd5378000, 0x42af4000, 0x067da000, 0x770c1000, 0xadaf8800, 0xb7c34c00, 0x22ffae00, 0x404d1700, 0xd6000e80, 0xb9000740, 0xc8800560, 0x7d400790, 0xe0a00288, 0xe97000d4, 0xc698088a, 0xf86c05d7 },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0x10000000, 0xb8000000, 0xe4000000, 0x86000000, 0x8d000000, 0x4b800000, 0x8ec00000, 0x79a00000, 0x1df00000, 0xab180000, 0xf6b40000, 0x8d560000, 0xbb5d0000, 0xbe5f8000, 0x59f24000, 0x1d1f6000, 0x33a2f000, 0x8ae78800, 0xefb64c00, 0x28d16e00, 0x048bf100, 0xfe4e0380, 0x79e90240, 0xed098660, 0x9baf49d0, 0xd6c0ef38, 0x8d90b6ac, 0x23d8e7fa, 0xc224b50f },
+    { 0x80000000, 0x40000000, 0x60000000, 0xb0000000, 0x88000000, 0xbc000000, 0xba000000, 0x6b000000, 0xbb800000, 0x27400000, 0x30a00000, 0x6cd00000, 0xfff80000, 0x505c0000, 0xa10a0000, 0x788b0000, 0xf0f88000, 0x95dbc000, 0x037d6000, 0x2eba9000, 0x59f28800, 0x1150c400, 0x2985e600, 0x60615b00, 0x690fe080, 0xa4aa5fc0, 0xfad765a0, 0x76e199b0, 0x04f20d38, 0xb3d706b4, 0x0272862a, 0xc610c0bd },
+    { 0x80000000, 0xc0000000, 0x60000000, 0x50000000, 0x58000000, 0x54000000, 0x56000000, 0x33000000, 0x54800000, 0xe4c00000, 0x17a00000, 0x18700000, 0xcf780000, 0x05c40000, 0xbe1e0000, 0xaf290000, 0x6e8f8000, 0x85dbc000, 0x7e23a000, 0xcf057000, 0x3e918800, 0xddf2cc00, 0x2a2c2600, 0x991eb500, 0x0d922d80, 0x8947b940, 0xcee5ab60, 0x8e987a30, 0x15f80ec8, 0x4604020c, 0xcb3e079a, 0x309902f7 },
+    { 0x80000000, 0x40000000, 0xa0000000, 0x30000000, 0x78000000, 0xdc000000, 0xca000000, 0x43000000, 0xe3800000, 0x9c400000, 0xb8a00000, 0x73d00000, 0x06c80000, 0x1c7c0000, 0xf8860000, 0xd3c30000, 0x36e88000, 0x6445c000, 0x24bb6000, 0x19c65000, 0x75ee8800, 0x87c6c400, 0xb8f3ea00, 0xa1539300, 0x061def80, 0x813c99c0, 0xa4bb6ea0, 0x59c65330, 0xd5ee8bb8, 0xb7c6c304, 0xc0f3eaaa, 0x7d539dcd },
+    { 0x80000000, 0xc0000000, 0xa0000000, 0x90000000, 0x08000000, 0x5c000000, 0x3a000000, 0x2f000000, 0xac800000, 0x94c00000, 0x5fa00000, 0xc2700000, 0x44480000, 0xa1740000, 0x1afa0000, 0xe68b0000, 0x43f08000, 0x9732c000, 0xa8a4a000, 0x5add7000, 0x86aa8800, 0x73c9cc00, 0x0f1c2a00, 0xfc9bb900, 0x3cf42880, 0x939fb9c0, 0xf04621a0, 0x3760b7f0, 0x37cca848, 0xa119798c, 0x15b884da, 0x1546ce17 },
+    { 0x80000000, 0xc0000000, 0xe0000000, 0x70000000, 0x28000000, 0xc4000000, 0x3a000000, 0x9b000000, 0xa1800000, 0x93400000, 0xa0a00000, 0xf9f00000, 0x2a580000, 0x560c0000, 0xa5020000, 0xe0950000, 0xd9d88000, 0xba7dc000, 0x0e07e000, 0x49049000, 0x1e828800, 0x78e4cc00, 0x80dd6e00, 0x3cec5700, 0x7addea80, 0x47dd9040, 0xab7805a0, 0xfcbc02b0, 0xcffa0698, 0x3f690274, 0x7e828b2a, 0xc8e4ca6f },
+    { 0x80000000, 0xc0000000, 0x60000000, 0x70000000, 0x28000000, 0xa4000000, 0xfe000000, 0x3d000000, 0x82800000, 0xb3400000, 0x05a00000, 0x42f00000, 0x41780000, 0xa28c0000, 0x63620000, 0x3d8d0000, 0xbed98000, 0x33544000, 0xc5ba2000, 0x22fe1000, 0x31638800, 0x8aa54c00, 0xc779a600, 0xc3ab5700, 0x83e22a80, 0xb1c21640, 0x76d981e0, 0x275448d0, 0x73ba2ca8, 0xcbfe1674, 0x65e3853a, 0xa0e541bf },
+};
diff --git a/code/projects/sobol_matrices.h b/code/projects/sobol_matrices.h
new file mode 100644
index 0000000000000000000000000000000000000000..53aa319ea875004e099b59b79ac239beb80cc66d
--- /dev/null
+++ b/code/projects/sobol_matrices.h
@@ -0,0 +1,78 @@
+
+#pragma once
+
+#include <cassert>
+#include <cstdint>
+#include <array>
+
+
+unsigned sobol_sample( const std::array<unsigned, 32>& m, unsigned n )
+{
+    unsigned x= 0;
+    for(unsigned i= 0; n; i++, n>>= 1)
+    {
+        if(n & 1)
+            x ^= m[i];
+    }
+    
+    return x;
+}
+
+unsigned graycode( const unsigned i )
+{
+    return i ^ (i >> 1);
+}
+unsigned trailing_zeroes( const unsigned i )
+{
+    assert(i > 0);
+    return __builtin_ctz(i);
+}
+
+unsigned sobol_sample_graycode( const std::array<unsigned, 32>& m, unsigned n, const unsigned prev )
+{
+    assert(n > 0);
+    unsigned g= trailing_zeroes(graycode(n-1) ^ graycode(n));
+    return prev ^ m[g];
+}
+
+
+//~ constexpr unsigned sobol_matrices_size= 16;
+constexpr unsigned sobol_matrices_size= 128;
+extern std::array<unsigned, 32> sobol_matrices[sobol_matrices_size];
+
+unsigned sobol_sample( const unsigned d, const unsigned index )
+{
+    assert(d < sobol_matrices_size);
+    return sobol_sample(sobol_matrices[d], index);
+}
+
+float sobol_sample_float( const unsigned d, const unsigned index )
+{
+    assert(d < sobol_matrices_size);
+    return uint_to_float( sobol_sample(d, index) );
+}
+
+double sobol_sample_double( const unsigned d, const unsigned index )
+{
+    assert(d < sobol_matrices_size);
+    return uint_to_double( sobol_sample(d, index) );
+}
+
+unsigned sobol_sample( const unsigned d, const unsigned index, const unsigned scramble )
+{
+    assert(d < sobol_matrices_size);
+    return sobol_sample(sobol_matrices[d], index) ^ scramble;
+}
+
+float sobol_sample_float( const unsigned d, const unsigned index, const unsigned scramble )
+{
+    assert(d < sobol_matrices_size);
+    return uint_to_float( sobol_sample(d, index, scramble) );
+}
+
+double sobol_sample_double( const unsigned d, const unsigned index, const unsigned scramble )
+{
+    assert(d < sobol_matrices_size);
+    return uint_to_double( sobol_sample(d, index, scramble) );
+}
+
diff --git a/code/scripts/ao.txt b/code/scripts/ao.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f6159f9ce1b67cc5f83dbf5980d64db248fdd0a8
--- /dev/null
+++ b/code/scripts/ao.txt
@@ -0,0 +1,81 @@
+scene="emission.glb"
+prefix="emission"
+mkdir $prefix
+
+
+#~ bin/ao $scene --prefix $prefix/ref -s 16384 
+ref=$prefix/ref-16384.pfm
+
+#~ return 
+
+rm $prefix/test*.pfm $prefix/test*.png
+
+
+#~ samples=""
+samples="1 2 4 8 16 32 64 128 256"
+for spp in $samples
+do
+#~ bin/ao $scene --prefix $prefix/ao-rng -s $spp
+#~ bin/ao $scene --prefix $prefix/ao-owen4 -s $spp
+#~ bin/ao $scene --prefix $prefix/ao-owen -s $spp
+#~ bin/ao $scene --prefix $prefix/ao-sobol -s $spp
+#~ bin/ao $scene --prefix $prefix/ao-sobolg -s $spp
+
+bin/ao $scene --prefix $prefix/test -s $spp
+
+done
+
+#~ return
+
+## erreurs 
+bin/errors	$ref \
+	--line 1 --title "sobol" $prefix/ao-sobol-*.pfm \
+	--line 2 --title "owen" $prefix/ao-owen-*.pfm \
+	--line 3 --title "rng" $prefix/ao-rng-*.pfm
+	
+
+## filtrer avec oidn a installer a cote...
+
+samples=""
+#~ samples="0001 0002 0004 0008 0016 0032 0064 0128 0256"
+for spp in $samples
+do
+../../oidn/build/oidnDenoise -o $prefix/denoised-$spp.pfm --filter RT --quality high --type float --hdr $prefix/test-$spp.pfm --alb $prefix/test-albedo-$spp.pfm --nrm $prefix/test-normals-$spp.pfm 
+
+done
+
+bin/errors	$ref \
+	--line 1 --title "sobol" $prefix/mf-sobol-????.pfm \
+	--line 2 --title "owen" $prefix/mf-owen4-????.pfm \
+	--line 3 --title "rng" $prefix/mf-rng-????.pfm
+	
+## visualize mse with gnuplot
+gnuplot <<EOF
+set term pdfcairo enhanced size 10cm,10cm
+set term pdfcairo font "Arial,14"
+# set term pdfcairo linewidth 2
+set output "${prefix}/mse.pdf"
+set size square
+set logscale xy
+set format y "10^{%L}"
+set xtics 4
+set grid
+set style line 11 lc rgb '#808080' lt 1
+set border 3 back ls 11
+set tics nomirror
+
+# parula palette
+set style line 1 lt 1  lw 1.5 lc rgb '#0072bd' # blue
+set style line 2 lt 1  lw 1.5 lc rgb '#d95319' # orange
+set style line 3 lt 1  lw 1.5 lc rgb '#edb120' # yellow
+set style line 4 lt 1  lw 1.5 lc rgb '#7e2f8e' # purple
+set style line 5 lt 1  lw 1.5 lc rgb '#77ac30' # green
+set style line 6 lt 1  lw 1.5 lc rgb '#4dbeee' # light-blue
+set style line 7 lt 1  lw 1.5 lc rgb '#a2142f' # red
+
+plot \
+	1 / (x**0.5) w lines ls 11 dt 2 t "",\
+    "./${prefix}/mse_rng.txt" u 1:2 w linespoints ls 1 t "RNG", \
+    "./${prefix}/mse_sobol.txt" u 1:2 w linespoints ls 2 t "Sobol+RDS", \
+    "./${prefix}/mse_owen.txt" u 1:2 w linespoints ls 3 t "Sobol+Owen"
+EOF