|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
#include <math.h>
|
|
Ivan Mahonin |
494577 |
#include <stdio.h>
|
|
Ivan Mahonin |
494577 |
#include <stdlib.h>
|
|
Ivan Mahonin |
494577 |
#include <string.h>
|
|
Ivan Mahonin |
494577 |
#include <helianthus.h>
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
#define COUNT 64
|
|
Ivan Mahonin |
494577 |
#define TEXCOUNT 512
|
|
Ivan Mahonin |
494577 |
#define FRAMECOUNT 512
|
|
Ivan Mahonin |
494577 |
#define W 512
|
|
Ivan Mahonin |
494577 |
#define H 512
|
|
Ivan Mahonin |
494577 |
#define STEP 0.05
|
|
Ivan Mahonin |
494577 |
#define EDGE 0
|
|
Ivan Mahonin |
494577 |
//#define SAVE "data/output/mosaic/frame%03d.png"
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
typedef struct {
|
|
Ivan Mahonin |
494577 |
int w, h;
|
|
Ivan Mahonin |
494577 |
unsigned char *pixels;
|
|
Ivan Mahonin |
494577 |
} Tex;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
typedef struct {
|
|
Ivan Mahonin |
494577 |
Tex *tex0;
|
|
Ivan Mahonin |
494577 |
Tex *tex1;
|
|
Ivan Mahonin |
494577 |
double alpha;
|
|
Ivan Mahonin |
494577 |
} Frame;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
typedef struct {
|
|
Ivan Mahonin |
494577 |
int x, y;
|
|
Ivan Mahonin |
494577 |
int l, t, w, h;
|
|
Ivan Mahonin |
494577 |
unsigned int color;
|
|
Ivan Mahonin |
494577 |
Frame frames[FRAMECOUNT];
|
|
Ivan Mahonin |
494577 |
} Point;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
typedef struct {
|
|
Ivan Mahonin |
494577 |
double k[3];
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
Point *point;
|
|
Ivan Mahonin |
494577 |
double weight;
|
|
Ivan Mahonin |
494577 |
double alpha;
|
|
Ivan Mahonin |
494577 |
double edge;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
Point *point2;
|
|
Ivan Mahonin |
494577 |
double weight2;
|
|
Ivan Mahonin |
494577 |
} Pixel;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
Point points[COUNT];
|
|
Ivan Mahonin |
494577 |
Pixel pixels[H][W];
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
Tex textures[TEXCOUNT];
|
|
Ivan Mahonin |
494577 |
int texturesCnt;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
unsigned char image[H][W][4];
|
|
Ivan Mahonin |
494577 |
Animation anim;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
int wrapX(int x)
|
|
Ivan Mahonin |
494577 |
{ return (x%W + W)%W; }
|
|
Ivan Mahonin |
494577 |
int wrapY(int y)
|
|
Ivan Mahonin |
494577 |
{ return (y%H + H)%H; }
|
|
Ivan Mahonin |
494577 |
Pixel* getPixel(int x, int y)
|
|
Ivan Mahonin |
494577 |
{ return &pixels[wrapY(y)][wrapX(x)]; }
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
int updatePixel(Pixel *p, int x, int y, int mode) {
|
|
Ivan Mahonin |
494577 |
Pixel *pp = getPixel(x, y);
|
|
Ivan Mahonin |
494577 |
double w = p->weight + p->k[mode] + pp->k[mode];
|
|
Ivan Mahonin |
494577 |
if (!pp->point || pp->weight > w) {
|
|
Ivan Mahonin |
494577 |
pp->point2 = pp->point = p->point;
|
|
Ivan Mahonin |
494577 |
pp->weight2 = pp->weight = w;
|
|
Ivan Mahonin |
494577 |
return 1;
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
return 0;
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
void updatePixel2(Pixel *p, int x, int y, int mode) {
|
|
Ivan Mahonin |
494577 |
Pixel *pp = getPixel(x, y);
|
|
Ivan Mahonin |
494577 |
if (p->point == pp->point) return;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
double w = pp->weight + pp->k[mode] + p->k[mode];
|
|
Ivan Mahonin |
494577 |
if (p->point2 == p->point || p->weight2 > w) {
|
|
Ivan Mahonin |
494577 |
p->point2 = pp->point;
|
|
Ivan Mahonin |
494577 |
p->weight2 = w;
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
void generateFrames(Frame *frames) {
|
|
Ivan Mahonin |
494577 |
int start;
|
|
Ivan Mahonin |
494577 |
int switches = 1 + rand()%10;
|
|
Ivan Mahonin |
494577 |
for(int i = 0; i < switches; ++i) {
|
|
Ivan Mahonin |
494577 |
start = rand()%FRAMECOUNT;
|
|
Ivan Mahonin |
494577 |
frames[start].tex1 = &textures[rand()%texturesCnt];
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
double alpha = 1;
|
|
Ivan Mahonin |
494577 |
Tex *t0 = frames[start].tex1, *t1 = t0;
|
|
Ivan Mahonin |
494577 |
for(int i = start; i < FRAMECOUNT*10; ++i) {
|
|
Ivan Mahonin |
494577 |
Frame *f = &frames[i%FRAMECOUNT];
|
|
Ivan Mahonin |
494577 |
if (alpha < 1) {
|
|
Ivan Mahonin |
494577 |
alpha += STEP;
|
|
Ivan Mahonin |
494577 |
if (alpha >= 1) {
|
|
Ivan Mahonin |
494577 |
alpha = 1;
|
|
Ivan Mahonin |
494577 |
t0 = t1;
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
} else
|
|
Ivan Mahonin |
494577 |
if (f->tex1 && f->tex1 != t1) {
|
|
Ivan Mahonin |
494577 |
t1 = f->tex1;
|
|
Ivan Mahonin |
494577 |
alpha = 0;
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
f->tex0 = t0;
|
|
Ivan Mahonin |
494577 |
f->tex1 = t1;
|
|
Ivan Mahonin |
494577 |
f->alpha = alpha;
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
//if (frames == points->frames)
|
|
Ivan Mahonin |
494577 |
// for(int i = 0; i < FRAMECOUNT; ++i)
|
|
Ivan Mahonin |
494577 |
// printf("%3d %3d %3d %f\n", i, frames[i].tex0 - textures, frames[i].tex1 - textures, frames[i].alpha);
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
Animation generateAnim(int frameId, const char *filename) {
|
|
Ivan Mahonin |
494577 |
// update image
|
|
Ivan Mahonin |
494577 |
Pixel *p = pixels[0];
|
|
Ivan Mahonin |
494577 |
unsigned char black[] = { 0, 0, 0, 255 };
|
|
Ivan Mahonin |
494577 |
//unsigned char white[] = { 255, 255, 255, 255 };
|
|
Ivan Mahonin |
494577 |
unsigned char *c = image[0][0];
|
|
Ivan Mahonin |
494577 |
for(int y = 0; y < H; ++y)
|
|
Ivan Mahonin |
494577 |
for(int x = 0; x < W; ++x, ++p) {
|
|
Ivan Mahonin |
494577 |
Frame *f0 = &p->point->frames[frameId];
|
|
Ivan Mahonin |
494577 |
Frame *f1 = &p->point2->frames[frameId];
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
Tex *t0 = f0->tex0;
|
|
Ivan Mahonin |
494577 |
Tex *t1 = f0->tex1;
|
|
Ivan Mahonin |
494577 |
Tex *t2 = f1->tex0;
|
|
Ivan Mahonin |
494577 |
Tex *t3 = f1->tex1;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
double a00 = 1 - f0->alpha;
|
|
Ivan Mahonin |
494577 |
double a01 = f0->alpha;
|
|
Ivan Mahonin |
494577 |
double a10 = 1 - f1->alpha;
|
|
Ivan Mahonin |
494577 |
double a11 = f1->alpha;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
if (t0 == t1) { a00 = 0; a01 = 1; }
|
|
Ivan Mahonin |
494577 |
if (t2 == t3) { a10 = 0; a11 = 1; }
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
double a0 = p->alpha*a00;
|
|
Ivan Mahonin |
494577 |
double a1 = p->alpha*a01;
|
|
Ivan Mahonin |
494577 |
double a2 = (1 - p->alpha)*a10;
|
|
Ivan Mahonin |
494577 |
double a3 = (1 - p->alpha)*a11;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
double k = 0;
|
|
Ivan Mahonin |
494577 |
if (t0 == t2) k += a00 < a10 ? a00 : a10;
|
|
Ivan Mahonin |
494577 |
if (t0 == t3) k += a00 < a11 ? a00 : a11;
|
|
Ivan Mahonin |
494577 |
if (t1 == t2) k += a01 < a10 ? a01 : a10;
|
|
Ivan Mahonin |
494577 |
if (t1 == t3) k += a01 < a11 ? a01 : a11;
|
|
Ivan Mahonin |
494577 |
double a4 = p->edge*(1 - k)*EDGE;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
unsigned char *c0 = t0->pixels + (y%t0->h*t0->w + x%t0->w)*4;
|
|
Ivan Mahonin |
494577 |
unsigned char *c1 = t1->pixels + (y%t1->h*t1->w + x%t1->w)*4;
|
|
Ivan Mahonin |
494577 |
unsigned char *c2 = t2->pixels + (y%t2->h*t2->w + x%t2->w)*4;
|
|
Ivan Mahonin |
494577 |
unsigned char *c3 = t3->pixels + (y%t3->h*t3->w + x%t3->w)*4;
|
|
Ivan Mahonin |
494577 |
unsigned char *c4 = black;
|
|
Ivan Mahonin |
494577 |
for(int i = 0; i < 4; ++i)
|
|
Ivan Mahonin |
494577 |
*c++ = (*c0++*a0 + *c1++*a1 + *c2++*a2 + *c3++*a3)*(1 - a4) + *c4++*a4;
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
if (filename) imageSave(filename, W, H, image);
|
|
Ivan Mahonin |
494577 |
return createAnimationFromImageEx(W, H, image, TRUE, TRUE, FALSE, FALSE);
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
void generate() {
|
|
Ivan Mahonin |
494577 |
// clear
|
|
Ivan Mahonin |
494577 |
memset(points, 0, sizeof(points));
|
|
Ivan Mahonin |
494577 |
memset(pixels, 0, sizeof(pixels));
|
|
Ivan Mahonin |
494577 |
memset(image, 0, sizeof(image));
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
// generate k
|
|
Ivan Mahonin |
494577 |
Pixel *p = pixels[0];
|
|
Ivan Mahonin |
494577 |
for(int y = 0; y < H; ++y)
|
|
Ivan Mahonin |
494577 |
for(int x = 0; x < W; ++x, ++p) {
|
|
Ivan Mahonin |
494577 |
p->k[0] = exp(randomFloat()-0.5)*4;
|
|
Ivan Mahonin |
494577 |
p->k[1] = exp(randomFloat()-0.5);
|
|
Ivan Mahonin |
494577 |
p->k[2] = (p->k[0] + p->k[1])*0.75;
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
// generate points
|
|
Ivan Mahonin |
494577 |
for(int i = 0; i < COUNT; ++i) {
|
|
Ivan Mahonin |
494577 |
Point *pt = &points[i];
|
|
Ivan Mahonin |
494577 |
pt->x = rand()%W;
|
|
Ivan Mahonin |
494577 |
pt->y = rand()%H;
|
|
Ivan Mahonin |
494577 |
pt->color = colorByHSV(randomFloat()*360, 1, 1);
|
|
Ivan Mahonin |
494577 |
generateFrames(pt->frames);
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
Pixel *p = getPixel(pt->x, pt->y);
|
|
Ivan Mahonin |
494577 |
p->point = p->point2 = pt;
|
|
Ivan Mahonin |
494577 |
p->weight = p->weight2 = randomFloat();
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
// expand points
|
|
Ivan Mahonin |
494577 |
int found = 1, i = 0;
|
|
Ivan Mahonin |
494577 |
while(found) {
|
|
Ivan Mahonin |
494577 |
found = 0;
|
|
Ivan Mahonin |
494577 |
Pixel *p = pixels[0];
|
|
Ivan Mahonin |
494577 |
for(int y = 0; y < H; ++y)
|
|
Ivan Mahonin |
494577 |
for(int x = 0; x < W; ++x, ++p) {
|
|
Ivan Mahonin |
494577 |
if (!p->point) continue;
|
|
Ivan Mahonin |
494577 |
if (updatePixel(p, x-1, y, 0)) found = 1;
|
|
Ivan Mahonin |
494577 |
if (updatePixel(p, x+1, y, 0)) found = 1;
|
|
Ivan Mahonin |
494577 |
if (updatePixel(p, x, y-1, 1)) found = 1;
|
|
Ivan Mahonin |
494577 |
if (updatePixel(p, x, y+1, 1)) found = 1;
|
|
Ivan Mahonin |
494577 |
if (updatePixel(p, x-1, y-1, 2)) found = 1;
|
|
Ivan Mahonin |
494577 |
if (updatePixel(p, x+1, y-1, 2)) found = 1;
|
|
Ivan Mahonin |
494577 |
if (updatePixel(p, x-1, y+1, 2)) found = 1;
|
|
Ivan Mahonin |
494577 |
if (updatePixel(p, x+1, y+1, 2)) found = 1;
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
printf("%d\n", i++); fflush(stdout);
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
// expand points2
|
|
Ivan Mahonin |
494577 |
p = pixels[0];
|
|
Ivan Mahonin |
494577 |
for(int y = 0; y < H; ++y)
|
|
Ivan Mahonin |
494577 |
for(int x = 0; x < W; ++x, ++p) {
|
|
Ivan Mahonin |
494577 |
updatePixel2(p, x-1, y, 0);
|
|
Ivan Mahonin |
494577 |
updatePixel2(p, x+1, y, 0);
|
|
Ivan Mahonin |
494577 |
updatePixel2(p, x, y-1, 1);
|
|
Ivan Mahonin |
494577 |
updatePixel2(p, x, y+1, 1);
|
|
Ivan Mahonin |
494577 |
updatePixel2(p, x-1, y-1, 2);
|
|
Ivan Mahonin |
494577 |
updatePixel2(p, x+1, y-1, 2);
|
|
Ivan Mahonin |
494577 |
updatePixel2(p, x-1, y+1, 2);
|
|
Ivan Mahonin |
494577 |
updatePixel2(p, x+1, y+1, 2);
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
double a = (p->weight2 - p->weight)*0.5 + 0.5;
|
|
Ivan Mahonin |
494577 |
if (a < 0) a = 0;
|
|
Ivan Mahonin |
494577 |
if (a > 1) a = 1;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
double edge = 1 - (p->weight2 - p->weight)/p->k[2]/8;
|
|
Ivan Mahonin |
494577 |
if (edge > 1) edge = 1;
|
|
Ivan Mahonin |
494577 |
if (edge < 0) edge = 0;
|
|
Ivan Mahonin |
494577 |
if (p->point == p->point2) edge = 0;
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
p->alpha = a;
|
|
Ivan Mahonin |
494577 |
p->edge = edge;
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
// generate animation
|
|
Ivan Mahonin |
494577 |
animationClear(anim);
|
|
Ivan Mahonin |
494577 |
for(int i = 0; i < FRAMECOUNT; ++i) {
|
|
Ivan Mahonin |
494577 |
#ifdef SAVE
|
|
Ivan Mahonin |
494577 |
char filename[1024] = {};
|
|
Ivan Mahonin |
494577 |
sprintf(filename, SAVE, i);
|
|
Ivan Mahonin |
494577 |
printf("generate: %s\n", filename); fflush(stdout);
|
|
Ivan Mahonin |
494577 |
animationInsert(anim, i, generateAnim(i, filename));
|
|
Ivan Mahonin |
494577 |
#else
|
|
Ivan Mahonin |
494577 |
printf("generate frame %d\n", i); fflush(stdout);
|
|
Ivan Mahonin |
494577 |
animationInsert(anim, i, generateAnim(i, NULL));
|
|
Ivan Mahonin |
494577 |
#endif
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
animationSetFps(anim, 32);
|
|
Ivan Mahonin |
494577 |
animationSetLoop(anim, TRUE);
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
void loadTexture(const char *filename) {
|
|
Ivan Mahonin |
494577 |
printf("load texture: %s\n", filename);
|
|
Ivan Mahonin |
494577 |
Tex *t = &textures[texturesCnt];
|
|
Ivan Mahonin |
494577 |
if (imageLoad(filename, &t->w, &t->h, &t->pixels))
|
|
Ivan Mahonin |
494577 |
++texturesCnt;
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
void loadTextures(const char *dirname) {
|
|
Ivan Mahonin |
494577 |
Directory dir = openDirectoryEx(dirname, "", ".png", FALSE, TRUE, FALSE);
|
|
Ivan Mahonin |
494577 |
if (dir) {
|
|
Ivan Mahonin |
494577 |
for(int i = 0; i < directoryGetCount(dir); ++i)
|
|
Ivan Mahonin |
494577 |
loadTexture(directoryGetFull(dir, i));
|
|
Ivan Mahonin |
494577 |
closeDirectory(dir);
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
void init() {
|
|
Ivan Mahonin |
494577 |
anim = createAnimationEmpty();
|
|
Ivan Mahonin |
494577 |
loadTextures("data/textures");
|
|
Ivan Mahonin |
494577 |
generate();
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
void draw() {
|
|
Ivan Mahonin |
494577 |
double w = windowGetWidth();
|
|
Ivan Mahonin |
494577 |
double h = windowGetHeight();
|
|
Ivan Mahonin |
494577 |
double t = windowGetSeconds();
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
saveState();
|
|
Ivan Mahonin |
494577 |
//scale(w/W, h/H);
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
noStroke();
|
|
Ivan Mahonin |
494577 |
animationSetFrame(anim, ((int)(t*32))%FRAMECOUNT);
|
|
Ivan Mahonin |
494577 |
fillTexture(anim, 0, 0, W, H, TRUE);
|
|
Ivan Mahonin |
494577 |
rect(0, 0, w, h);
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
//stroke(COLOR_BLACK);
|
|
Ivan Mahonin |
494577 |
//for(int i = 0; i < COUNT; ++i)
|
|
Ivan Mahonin |
494577 |
// point(points[i].x, points[i].y);
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
restoreState();
|
|
Ivan Mahonin |
494577 |
}
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
|
|
Ivan Mahonin |
494577 |
int main() {
|
|
Ivan Mahonin |
494577 |
windowSetVariableFrameRate();
|
|
Ivan Mahonin |
494577 |
windowSetResizable(TRUE);
|
|
Ivan Mahonin |
494577 |
windowSetInit(&init);
|
|
Ivan Mahonin |
494577 |
windowSetDraw(&draw);
|
|
Ivan Mahonin |
494577 |
windowRun();
|
|
Ivan Mahonin |
494577 |
}
|