feat: generate faust C code and Nim wrapper with faustpp
Signed-off-by: Christopher Arndt <chris@chrisarndt.de>
This commit is contained in:
		
							parent
							
								
									aa3bae40fb
								
							
						
					
					
						commit
						9b33bf10bf
					
				| @ -84,7 +84,7 @@ below. | |||||||
| 
 | 
 | ||||||
|    See the definition of the `build_ex` task in the |    See the definition of the `build_ex` task in the | ||||||
|    [nymph.nimble](./nymph.nimble#L67) file on how to create a nimble task |    [nymph.nimble](./nymph.nimble#L67) file on how to create a nimble task | ||||||
|     to simplify compilation. |    to simplify compilation and additional compiler args you might want to use. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ## Dependencies | ## Dependencies | ||||||
|  | |||||||
| @ -1,31 +1,38 @@ | |||||||
| /* ------------------------------------------------------------
 |  | ||||||
| author: "Christopher Arndt" |  | ||||||
| copyright: "Christopher Arndt, 2024" |  | ||||||
| license: "MIT" |  | ||||||
| name: "FaustLPF" |  | ||||||
| version: "0.1.0" |  | ||||||
| Code generated with Faust 2.74.6 (https://faust.grame.fr)
 |  | ||||||
| Compilation options: -a ./examples/minarch.h -lang c -rui -ct 1 -cn faustlpf -es 1 -mcd 16 -mdd 1024 -mdy 33 -single -ftz 0 -vec -lv 0 -vs 32 |  | ||||||
| ------------------------------------------------------------ */ |  | ||||||
| 
 | 
 | ||||||
| #ifndef  __faustlpf_H__ | //------------------------------------------------------------------------------
 | ||||||
| #define  __faustlpf_H__ | // This file was generated using the Faust compiler (https://faust.grame.fr),
 | ||||||
| 
 | // and the Faust post-processor (https://github.com/SpotlightKid/faustpp).
 | ||||||
| /******************* BEGIN minarch.h ****************/ | //
 | ||||||
| 
 | // Source: lpf.dsp
 | ||||||
| /************************************************************************
 | // Name: FaustLPF
 | ||||||
|  FAUST Architecture File for generating a very minimal C interface | // Author: Christopher Arndt
 | ||||||
|  ************************************************************************/ | // Copyright: Christopher Arndt, 2024
 | ||||||
| 
 | // License: MIT
 | ||||||
| #include "faust/gui/CInterface.h" | // Version: 0.1.0
 | ||||||
| 
 | // FAUST version: 2.75.10
 | ||||||
| /******************************************************************************
 | // FAUST compilation options: -a /home/chris/tmp/tmp9v2ck7tz.c -lang c -rui -ct 1 -fm def -cn faustlpf -es 1 -mcd 16 -mdd 1024 -mdy 33 -single -ftz 0 -vec -lv 0 -vs 32
 | ||||||
|  VECTOR INTRINSICS | //------------------------------------------------------------------------------
 | ||||||
| *******************************************************************************/ |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /**************************BEGIN USER SECTION **************************/ |  | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | #include "faustlpf.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | //------------------------------------------------------------------------------
 | ||||||
|  | // Begin the Faust code section
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #if defined(__GNUC__) | ||||||
|  | #   pragma GCC diagnostic push | ||||||
|  | #   pragma GCC diagnostic ignored "-Wunused-parameter" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | // START INTRINSICS
 | ||||||
|  | // END INTRINSICS
 | ||||||
|  | // START CLASS CODE
 | ||||||
| #ifndef FAUSTFLOAT | #ifndef FAUSTFLOAT | ||||||
| #define FAUSTFLOAT float | #define FAUSTFLOAT float | ||||||
| #endif  | #endif  | ||||||
| @ -41,6 +48,7 @@ extern "C" { | |||||||
| #define RESTRICT __restrict__ | #define RESTRICT __restrict__ | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #include "faust/dsp/fastmath.cpp" | ||||||
| #include <math.h> | #include <math.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| @ -58,16 +66,7 @@ static float faustlpf_faustpower2_f(float value) { | |||||||
| #define exp10 __exp10 | #define exp10 __exp10 | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| typedef struct { | 
 | ||||||
| 	int fSampleRate; |  | ||||||
| 	float fConst0; |  | ||||||
| 	float fConst1; |  | ||||||
| 	float fConst2; |  | ||||||
| 	FAUSTFLOAT fHslider0; |  | ||||||
| 	float fRec1_perm[4]; |  | ||||||
| 	float fConst3; |  | ||||||
| 	float fRec0_perm[4]; |  | ||||||
| } faustlpf; |  | ||||||
| 
 | 
 | ||||||
| faustlpf* newfaustlpf() {  | faustlpf* newfaustlpf() {  | ||||||
| 	faustlpf* dsp = (faustlpf*)calloc(1, sizeof(faustlpf)); | 	faustlpf* dsp = (faustlpf*)calloc(1, sizeof(faustlpf)); | ||||||
| @ -80,7 +79,7 @@ void deletefaustlpf(faustlpf* dsp) { | |||||||
| 
 | 
 | ||||||
| void metadatafaustlpf(MetaGlue* m) {  | void metadatafaustlpf(MetaGlue* m) {  | ||||||
| 	m->declare(m->metaInterface, "author", "Christopher Arndt"); | 	m->declare(m->metaInterface, "author", "Christopher Arndt"); | ||||||
| 	m->declare(m->metaInterface, "compile_options", "-a ./examples/minarch.h -lang c -rui -ct 1 -cn faustlpf -es 1 -mcd 16 -mdd 1024 -mdy 33 -single -ftz 0 -vec -lv 0 -vs 32"); | 	m->declare(m->metaInterface, "compile_options", "-a /home/chris/tmp/tmp9v2ck7tz.c -lang c -rui -ct 1 -fm def -cn faustlpf -es 1 -mcd 16 -mdd 1024 -mdy 33 -single -ftz 0 -vec -lv 0 -vs 32"); | ||||||
| 	m->declare(m->metaInterface, "copyright", "Christopher Arndt, 2024"); | 	m->declare(m->metaInterface, "copyright", "Christopher Arndt, 2024"); | ||||||
| 	m->declare(m->metaInterface, "filename", "lpf.dsp"); | 	m->declare(m->metaInterface, "filename", "lpf.dsp"); | ||||||
| 	m->declare(m->metaInterface, "filters.lib/fir:author", "Julius O. Smith III"); | 	m->declare(m->metaInterface, "filters.lib/fir:author", "Julius O. Smith III"); | ||||||
| @ -112,7 +111,7 @@ void metadatafaustlpf(MetaGlue* m) { | |||||||
| 	m->declare(m->metaInterface, "platform.lib/name", "Generic Platform Library"); | 	m->declare(m->metaInterface, "platform.lib/name", "Generic Platform Library"); | ||||||
| 	m->declare(m->metaInterface, "platform.lib/version", "1.3.0"); | 	m->declare(m->metaInterface, "platform.lib/version", "1.3.0"); | ||||||
| 	m->declare(m->metaInterface, "signals.lib/name", "Faust Signal Routing Library"); | 	m->declare(m->metaInterface, "signals.lib/name", "Faust Signal Routing Library"); | ||||||
| 	m->declare(m->metaInterface, "signals.lib/version", "1.5.0"); | 	m->declare(m->metaInterface, "signals.lib/version", "1.6.0"); | ||||||
| 	m->declare(m->metaInterface, "version", "0.1.0"); | 	m->declare(m->metaInterface, "version", "0.1.0"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -230,7 +229,7 @@ void computefaustlpf(faustlpf* dsp, int count, FAUSTFLOAT** RESTRICT inputs, FAU | |||||||
| 		{ | 		{ | ||||||
| 			int i; | 			int i; | ||||||
| 			for (i = 0; i < vsize; i = i + 1) { | 			for (i = 0; i < vsize; i = i + 1) { | ||||||
| 				fZec0[i] = tanf(dsp->fConst3 * fRec1[i]); | 				fZec0[i] = fast_tanf(dsp->fConst3 * fRec1[i]); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		/* Vectorizable loop 2 */ | 		/* Vectorizable loop 2 */ | ||||||
| @ -322,7 +321,7 @@ void computefaustlpf(faustlpf* dsp, int count, FAUSTFLOAT** RESTRICT inputs, FAU | |||||||
| 		{ | 		{ | ||||||
| 			int i; | 			int i; | ||||||
| 			for (i = 0; i < vsize; i = i + 1) { | 			for (i = 0; i < vsize; i = i + 1) { | ||||||
| 				fZec0[i] = tanf(dsp->fConst3 * fRec1[i]); | 				fZec0[i] = fast_tanf(dsp->fConst3 * fRec1[i]); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		/* Vectorizable loop 2 */ | 		/* Vectorizable loop 2 */ | ||||||
| @ -383,7 +382,15 @@ void computefaustlpf(faustlpf* dsp, int count, FAUSTFLOAT** RESTRICT inputs, FAU | |||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | // END CLASS CODE
 | ||||||
| 
 | 
 | ||||||
| /***************************END USER SECTION ***************************/ |  | ||||||
| 
 | 
 | ||||||
|  | #if defined(__GNUC__) | ||||||
|  | #   pragma GCC diagnostic pop | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | //------------------------------------------------------------------------------
 | ||||||
|  | // End the Faust code section
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
							
								
								
									
										200
									
								
								examples/faustlpf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								examples/faustlpf.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,200 @@ | |||||||
|  | #ifndef  __faustlpf_H__ | ||||||
|  | #define  __faustlpf_H__ | ||||||
|  | 
 | ||||||
|  | #ifndef FAUSTFLOAT | ||||||
|  | #define FAUSTFLOAT float | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef FAUSTCLASS | ||||||
|  | #define FAUSTCLASS faustlpf | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if defined(_WIN32) | ||||||
|  | #define RESTRICT __restrict | ||||||
|  | #else | ||||||
|  | #define RESTRICT __restrict__ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include "faust/gui/CInterface.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  | 	int fSampleRate; | ||||||
|  | 	float fConst0; | ||||||
|  | 	float fConst1; | ||||||
|  | 	float fConst2; | ||||||
|  | 	FAUSTFLOAT fHslider0; | ||||||
|  | 	float fRec1_perm[4]; | ||||||
|  | 	float fConst3; | ||||||
|  | 	float fRec0_perm[4]; | ||||||
|  | } faustlpf; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | faustlpf* newfaustlpf(); | ||||||
|  | void deletefaustlpf(faustlpf* dsp); | ||||||
|  | void metadatafaustlpf(MetaGlue* m); | ||||||
|  | int getSampleRatefaustlpf(faustlpf* RESTRICT dsp); | ||||||
|  | int getNumInputsfaustlpf(faustlpf* RESTRICT dsp); | ||||||
|  | int getNumOutputsfaustlpf(faustlpf* RESTRICT dsp); | ||||||
|  | void classInitfaustlpf(int sample_rate); | ||||||
|  | void instanceResetUserInterfacefaustlpf(faustlpf* dsp); | ||||||
|  | void instanceClearfaustlpf(faustlpf* dsp); | ||||||
|  | void instanceConstantsfaustlpf(faustlpf* dsp, int sample_rate); | ||||||
|  | void instanceInitfaustlpf(faustlpf* dsp, int sample_rate); | ||||||
|  | void initfaustlpf(faustlpf* dsp, int sample_rate); | ||||||
|  | void buildUserInterfacefaustlpf(faustlpf* dsp, UIGlue* ui_interface); | ||||||
|  | void computefaustlpf(faustlpf* dsp, int count, FAUSTFLOAT** RESTRICT inputs, FAUSTFLOAT** RESTRICT outputs); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | int parameter_group(unsigned index) { | ||||||
|  |     switch (index) { | ||||||
|  |      | ||||||
|  |     case 0: | ||||||
|  |         return 0; | ||||||
|  |      | ||||||
|  |     default: | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char *parameter_label(unsigned index) { | ||||||
|  |     switch (index) { | ||||||
|  |      | ||||||
|  |     case 0: | ||||||
|  |         return "Cutoff"; | ||||||
|  |      | ||||||
|  |     default: | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char *parameter_short_label(unsigned index) { | ||||||
|  |     switch (index) { | ||||||
|  |      | ||||||
|  |     case 0: | ||||||
|  |         return "Cutoff"; | ||||||
|  |      | ||||||
|  |     default: | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char *parameter_style(unsigned index) { | ||||||
|  |     switch (index) { | ||||||
|  |      | ||||||
|  |     case 0: { | ||||||
|  |         return "knob"; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     default: | ||||||
|  |         return ""; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char *parameter_symbol(unsigned index) { | ||||||
|  |     switch (index) { | ||||||
|  |      | ||||||
|  |     case 0: | ||||||
|  |         return "cutoff"; | ||||||
|  |      | ||||||
|  |     default: | ||||||
|  |         return ""; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char *parameter_unit(unsigned index) { | ||||||
|  |     switch (index) { | ||||||
|  |      | ||||||
|  |     case 0: | ||||||
|  |         return "Hz"; | ||||||
|  |      | ||||||
|  |     default: | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | bool parameter_is_trigger(unsigned index) { | ||||||
|  |     switch (index) { | ||||||
|  |      | ||||||
|  |     default: | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool parameter_is_boolean(unsigned index) { | ||||||
|  |     switch (index) { | ||||||
|  |      | ||||||
|  |     default: | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool parameter_is_enum(unsigned index) { | ||||||
|  |     switch (index) { | ||||||
|  |      | ||||||
|  |     default: | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool parameter_is_integer(unsigned index) { | ||||||
|  |     switch (index) { | ||||||
|  |      | ||||||
|  |     default: | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool parameter_is_logarithmic(unsigned index) { | ||||||
|  |     switch (index) { | ||||||
|  |      | ||||||
|  |     case 0: | ||||||
|  |         return true; | ||||||
|  |      | ||||||
|  |     default: | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float get_parameter(faustlpf* dsp, unsigned index) { | ||||||
|  |     switch (index) { | ||||||
|  |      | ||||||
|  |     case 0: | ||||||
|  |         return dsp->fHslider0; | ||||||
|  |      | ||||||
|  |     default: | ||||||
|  |         (void)dsp; | ||||||
|  |         return 0.0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void set_parameter(faustlpf* dsp, unsigned index, float value) { | ||||||
|  |     switch (index) { | ||||||
|  |      | ||||||
|  |     case 0: | ||||||
|  |         dsp->fHslider0 = value; | ||||||
|  |         break; | ||||||
|  |      | ||||||
|  |     default: | ||||||
|  |         (void)dsp; | ||||||
|  |         (void)value; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | float get_cutoff(faustlpf* dsp) { | ||||||
|  |     return dsp->fHslider0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void set_cutoff(faustlpf* dsp, float value) { | ||||||
|  |     dsp->fHslider0 = value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #endif  /* __faustlpf_H__ */ | ||||||
							
								
								
									
										33
									
								
								examples/faustlpf.nim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								examples/faustlpf.nim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | |||||||
|  | {.compile: "faustlpf.c".} | ||||||
|  | 
 | ||||||
|  | type | ||||||
|  |     faustlpf* = object | ||||||
|  |     SampleBuffer* = UncheckedArray[cfloat] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | proc newfaustlpf*(): ptr faustlpf {.importc.} | ||||||
|  | proc deletefaustlpf*(dsp: ptr faustlpf) {.importc.} | ||||||
|  | proc initfaustlpf*(dsp: ptr faustlpf, sample_rate: cint) {.importc.} | ||||||
|  | proc instanceClearfaustlpf*(dsp: ptr faustlpf) {.importc.} | ||||||
|  | proc computefaustlpf*(dsp: ptr faustlpf, count: cint, inputs, outputs: ptr ptr SampleBuffer) {.importc.} | ||||||
|  | 
 | ||||||
|  | proc parameter_group*(index: cuint): cint {.importc} | ||||||
|  | proc parameter_is_boolean*(index: cuint): bool {.importc} | ||||||
|  | proc parameter_is_enum*(index: cuint): bool {.importc} | ||||||
|  | proc parameter_is_integer*(index: cuint): bool {.importc} | ||||||
|  | proc parameter_is_logarithmic*(index: cuint): bool {.importc} | ||||||
|  | proc parameter_is_trigger*(index: cuint): bool {.importc} | ||||||
|  | proc parameter_label*(index: cuint): cstring {.importc} | ||||||
|  | proc parameter_short_label*(index: cuint): cstring {.importc} | ||||||
|  | proc parameter_style*(index: cuint): cstring {.importc} | ||||||
|  | proc parameter_symbol*(index: cuint): cstring {.importc} | ||||||
|  | proc parameter_unit*(index: cuint): cstring {.importc} | ||||||
|  | 
 | ||||||
|  | proc get_parameter*(dsp: ptr faustlpf, index: cuint): cfloat {.importc} | ||||||
|  | proc set_parameter*(dsp: ptr faustlpf, index: cuint, value: cfloat) {.importc} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | proc get_cutoff*(dsp: ptr faustlpf): cfloat {.importc} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | proc set_cutoff*(dsp: ptr faustlpf, value: cfloat) {.importc} | ||||||
| @ -1,37 +1,21 @@ | |||||||
| ## A FAUST standard library 2-pole lowpass filter LV2 plugin | ## A FAUST standard library 2-pole lowpass filter LV2 plugin | ||||||
| 
 | 
 | ||||||
| import nymph | import nymph | ||||||
| 
 | import faustlpf | ||||||
| {.emit: """#include "lpf.h"""".} |  | ||||||
| 
 | 
 | ||||||
| const | const | ||||||
|     PluginUri = "urn:nymph:examples:faustlpf" |     PluginUri = "urn:nymph:examples:faustlpf" | ||||||
| 
 | 
 | ||||||
| type | type | ||||||
|     faustlpf {.importc, header: "lpf.h".} = object |  | ||||||
|         # struct field representing the value of the FAUST UI element, |  | ||||||
|         # which controls the filter cutoff frequency |  | ||||||
|         fHslider0: cfloat |  | ||||||
| 
 |  | ||||||
|     PluginPort {.pure.} = enum |     PluginPort {.pure.} = enum | ||||||
|         Input, Output, Frequency |         Input, Output, Frequency | ||||||
| 
 | 
 | ||||||
|     SampleBuffer = UncheckedArray[cfloat] |  | ||||||
| 
 |  | ||||||
|     FaustLPFPlugin = object |     FaustLPFPlugin = object | ||||||
|         input: ptr SampleBuffer |         input: ptr SampleBuffer | ||||||
|         output: ptr SampleBuffer |         output: ptr SampleBuffer | ||||||
|         freq: ptr cfloat |         freq: ptr cfloat | ||||||
|         flt: ptr faustlpf |         flt: ptr faustlpf | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # wrap only those functions from the C code, which we actually need |  | ||||||
| proc newfaustlpf(): ptr faustlpf {.importc.} |  | ||||||
| proc deletefaustlpf(dsp: ptr faustlpf) {.importc.} |  | ||||||
| proc initfaustlpf(dsp: ptr faustlpf, sample_rate: cint) {.importc.} |  | ||||||
| proc instanceClearfaustlpf(dsp: ptr faustlpf) {.importc.} |  | ||||||
| proc computefaustlpf(dsp: ptr faustlpf, count: cint, inputs, outputs: ptr ptr SampleBuffer) {.importc.} |  | ||||||
| 
 |  | ||||||
| proc NimMain() {.cdecl, importc.} | proc NimMain() {.cdecl, importc.} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -66,7 +50,7 @@ proc activate(instance: Lv2Handle) {.cdecl.} = | |||||||
| 
 | 
 | ||||||
| proc run(instance: Lv2Handle; nSamples: cuint) {.cdecl.} = | proc run(instance: Lv2Handle; nSamples: cuint) {.cdecl.} = | ||||||
|     let plug = cast[ptr FaustLPFPlugin](instance) |     let plug = cast[ptr FaustLPFPlugin](instance) | ||||||
|     plug.flt.fHslider0 = plug.freq[] |     set_cutoff(plug.flt, plug.freq[]) | ||||||
|     computefaustlpf(plug.flt, nSamples.cint, addr plug.input, addr plug.output) |     computefaustlpf(plug.flt, nSamples.cint, addr plug.input, addr plug.output) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user