/**
 *	SHADER ADDON
 * 	Featuring BlurShift, Sharpen, Noise, LumaSharpen, Vibrance, Contrast, Black Level
 *	Exterior/Interior separation ready, GUI-enabled
 *	By ZeroKing
 */

/**
 *	ENBSeries
 *	visit http://enbdev.com for updates
 *	Copyright (c) 2007-2014 Boris Vorontsov
 */ 
 
//--------------------------//
//   Internal parameters	// 
//     Can be modified		//
//--------------------------// 

//////////////////
//	 DEFINES	//
//////////////////
#define ESHARPENING
#define ESHARPENINGCOLOR
#define ECOLORSHIFT
#define SharpMethod 						4
#define NoiseMethod							0 

// Set your resolution here 
float2 fvTexelSize = float2(1.0 / 2400.0, 1.0 / 1350.0);

///////////////
//	CHOICES	 //
///////////////
bool   C_BLACKLEVEL <
	string UIName =  "Enable Black Level";
> = {false};

bool   C_CONTRASTCURVES <
	string UIName =  "Enable Contrast";
> = {false};

bool   C_VIBRANCE <
	string UIName =  "Enable Vibrance";
> = {false};
 
//////////////////////////////
//	BLUR-SHIFT AND SHARPEN	//
//////////////////////////////
#define BlurSamplingRange			BlurRange
#define SharpSamplingRange			SharpRange
#define SharpeningAmount			SharpAmount
#define ShiftSamplingRange			ShiftRange

float	BlurRange <
	string UIName="Blur Sampling Range";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=1.0;
> = {0.2};

float	SharpRange <
	string UIName="Sharp Sampling Range";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=1.0;
> = {0.8};

float	SharpAmount <
	string UIName="Sharpening Amount";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=5.0;
> = {1.0};
		
float	ShiftRange <
	string UIName="Shift Sampling Range";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=1.0;
> = {0.8};
		
//////////////
//	NOISE	//
//////////////
float	NoiseAmount <
	string UIName="Noise Amount";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=1.0;
> = {0.0};

float	NoiseFineness <
	string UIName="Noise Fineness";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=100.0;
> = {50};

//////////////////
//	CONTRAST	//
//////////////////
float	ContrastCurve <
	string UIName="Contrast";
	string UIWidget="Spinner";
	float UIMin=-1.0;
	float UIMax=1.0;
> = {0};

//////////////////
//	VIBRANCE	//
//////////////////
float	Vibrance <
	string UIName="Vibrance";
	string UIWidget="Spinner";
	float UIMin=-1.0;
	float UIMax=1.0;
> = {0};
	
////////////////////
//	LUMASHARPEN	  //
////////////////////
float	sharp_strength <
	string UIName="LumaSharpen Strength";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=5.0;
> = {0};	
	
float	sharp_clamp <
	string UIName="LumaSharpen Clamp";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=1.0;
> = {0};	

////////////////////
//	BLACK LEVELS  //
////////////////////
float	BlackPoint <
	string UIName="Black Level";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=255.0;
> = {16};	

float	WhitePoint <
	string UIName="White Level";
	string UIWidget="Spinner";
	float UIMin=0.0;
	float UIMax=255.0;
> = {235};	

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		
//--------------------------//
//   External parameters	// 
//     Do not modify		//
//--------------------------//

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Keyboard controlled temporary variables. 
// Press and hold key 1,2,3...8 together with PageUp or PageDown to modify. 
// By default all set to 1.0
float4	tempF1; 			//0,1,2,3
float4	tempF2; 			//5,6,7,8
float4	tempF3; 			//9,0
float4	Timer;				//x=generic timer in range 0..1, period of 16777216 ms (4.6 hours), w=frame time elapsed (in seconds)
float4	ScreenSize;			//x=Width, y=1/Width, z=ScreenScaleY, w=1/ScreenScaleY
float	ENightDayFactor;	//changes in range 0..1, 0 means that night time, 1 - day time
float	EInteriorFactor;	//changes 0 or 1. 0 means that exterior, 1 - interior
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////
//	TEXTURES	//
//////////////////
texture2D texColor;
texture2D texNoise;

///////////////////
//	 SAMPLERS	 //
///////////////////
sampler2D SamplerColor = sampler_state
{
	Texture   = <texColor>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = NONE;
	AddressU  = Clamp;
	AddressV  = Clamp;
	SRGBTexture=FALSE;
	MaxMipLevel=0;
	MipMapLodBias=0;
};

sampler2D SamplerNoise = sampler_state
{
	Texture   = <texNoise>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = NONE;
	AddressU  = Wrap;
	AddressV  = Wrap;
	SRGBTexture=FALSE;
	MaxMipLevel=0;
	MipMapLodBias=0;
};

//////////////////
//	 STRUCTS	//
//////////////////
struct VS_OUTPUT_POST
{
	float4 vpos  : POSITION;
	float2 txcoord : TEXCOORD0;
};

struct VS_INPUT_POST
{
	float3 pos  : POSITION;
	float2 txcoord : TEXCOORD0;
};

VS_OUTPUT_POST VS_PostProcess(VS_INPUT_POST IN)
{
	VS_OUTPUT_POST OUT;

	float4 pos=float4(IN.pos.x,IN.pos.y,IN.pos.z,1.0);

	OUT.vpos=pos;
	OUT.txcoord.xy=IN.txcoord.xy;

	return OUT;
}

//////////////////
//	 SHADERS	//
//////////////////
float4 PS_ProcessLumaSharpen(VS_OUTPUT_POST IN, float2 vPos : VPOS, float2 tex : TEXCOORD0) : COLOR
{
    float2 coord = IN.txcoord.xy;
       
	#define px fvTexelSize.x 		
	#define py fvTexelSize.y 
			
	// Bias value
	float offset_bias = 1.0;	
				
	#define sharp_strength_luma 				(CoefLuma * sharp_strength) 
	#define CoefLuma 							float4(0.2126, 0.7152, 0.0722, 0)  
 
    half4 ori = tex2D(SamplerColor, coord.xy);
 
    [branch] if (any(frac(ori.rgb)))
    {
		#if SharpMethod == 1
			// -- Gaussian filter --
			//   [ 2/9, 4/9,    ]     [ 1 , 2 ,   ]
			//   [ 4/9, 8/9, 4/9]  =  [ 2 , 4 , 2 ]
			//   [    , 2/9, 2/9]     [   , 2 , 1 ]
		   
			half4 blur_ori = tex2Dlod(SamplerColor, float4(tex,tex) + float4(-px,py,-px,py) / 3 * offset_bias); 	// North West
			blur_ori += tex2Dlod(SamplerColor, float4(tex,tex) + float4(px,-py,px,-py) / 3 * offset_bias);  		// South East
			
			//Divide by the number of texture fetches
			blur_ori /= 2; 
		#endif
 
		// -- Pattern 2 -- A 9 tap gaussian using 4+1 texture fetches.
		#if SharpMethod == 2
			// -- Gaussian filter --
			//   [ .25, .50, .25]     [ 1 , 2 , 1 ]
			//   [ .50,   1, .50]  =  [ 2 , 4 , 2 ]
			//   [ .25, .50, .25]     [ 1 , 2 , 1 ]
 
			half4 blur_ori = tex2Dlod(SamplerColor, float4(tex,tex) + float4(-px,py,-px,py) * 0.5 * offset_bias); 		// North West
			blur_ori += tex2Dlod(SamplerColor, float4(tex,tex) + float4(px,-py,px,-py) * 0.5 * offset_bias);  			// South East
 
			if (any((blur_ori.rgb / 2) - ori.rgb))
			{
				blur_ori += tex2Dlod(SamplerColor, float4(tex,tex) + float4(-px,-py,-px,-py) * 0.5 * offset_bias); 		// South West
				blur_ori += tex2Dlod(SamplerColor, float4(tex,tex) + float4(px,py,px,py) * 0.5 * offset_bias); 			// North East
				
				//Divide by the number of texture fetches
				blur_ori *= 0.25;;  
			}
	 
			//Divide by the number of texture fetches
			blur_ori *= 0.25;;  
		#endif
 
		// -- Pattern 3 -- An experimental 17 tap gaussian using 4+1 texture fetches.
		#if SharpMethod == 3 
			// -- Gaussian filter --
			//   [   , 4 , 6 ,   ,   ]
			//   [   ,16 ,24 ,16 , 4 ]
			//   [ 6 ,24 ,50 ,24 , 6 ]
			//   [ 4 ,16 ,24 ,16 ,   ]
			//   [   ,   , 6 , 4 ,   ]
 
			half4 blur_ori = tex2Dlod(SamplerColor, float4(tex,tex) + float4(-0.4*px,1.2*py,-0.4*px,1.2*py) * offset_bias); 	// North North West
			blur_ori += tex2Dlod(SamplerColor, float4(tex,tex) + float4(0.4*px,-1.2*py,0.4*px,-1.2*py) * offset_bias);  		// South South East
			blur_ori += tex2Dlod(SamplerColor, float4(tex,tex) + float4(1.2*px,0.4*py,0,0) * offset_bias); 						// East North East
			blur_ori += tex2Dlod(SamplerColor, float4(tex,tex) + float4(-1.2*px,-0.4*py,0,0) * offset_bias); 					// West South West
			blur_ori += ori; 	// Probably not needed. Only serves to lessen the effect.
	   
			blur_ori /= 5;  	//Divide by the number of texture fetches
		#endif
 
		// -- Pattern 4 -- A 9 tap high pass using 4+1 texture fetches.
		#if SharpMethod == 4 
			// -- Gaussian filter --
			//   [ .50, .50, .50]     [ 1 , 1 , 1 ]
			//   [ .50,    , .50]  =  [ 1 ,   , 1 ]
			//   [ .50, .50, .50]     [ 1 , 1 , 1 ]
 
			half4 blur_ori = tex2Dlod(SamplerColor, float4(tex,tex) + float4(0.5 * -px,py,0.5 * -px,py) * offset_bias);		// North North West
			blur_ori += tex2Dlod(SamplerColor, float4(tex,tex) + float4(0.5 * px,-py,0.5 * px,-py));  						// South South East
			blur_ori += tex2Dlod(SamplerColor, float4(tex,tex) + float4(-px,0.5 * -py,-px,0.5 * -py)); 						// West South West
			blur_ori += tex2Dlod(SamplerColor, float4(tex,tex) + float4(px,0.5 * py,px,0.5 * py) * offset_bias); 			// East North East
			blur_ori += (2 * ori); 	// Probably not needed. Only serves to lessen the effect.
        
			blur_ori /= 6;  		//Divide by the number of texture fetches
		#endif	
               
        // -- Calculate the sharpening -- 
        half sharp = ori - blur_ori;  
        // -- Adjust strength of the sharpening --
        sharp = dot(sharp, sharp_strength_luma); 
		// -- Clamping the maximum amount of sharpening to prevent halo artifacts --
        sharp = clamp(sharp, -sharp_clamp, sharp_clamp);  
		// -- Combining the values to get the final sharpened pixel   --
        half4 done = ori + sharp;     

        return done;
    }
    
	else
    {               
        return ori;
    }
}

float4 PS_ProcessBlur(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
	float4 res;
	float4 coord=0.0;

	coord.xy=IN.txcoord.xy;
	float4 origcolor;

	coord.w=0.0;

	origcolor=tex2Dlod(SamplerColor, coord);

	float2 offset[16]=
	{
		float2(1.0, 1.0),
		float2(-1.0, -1.0),
		float2(-1.0, 1.0),
		float2(1.0, -1.0),

		float2(1.0, 0.0),
		float2(-1.0, 0.0),
		float2(0.0, 1.0),
		float2(0.0, -1.0),

		float2(1.41, 0.0),
		float2(-1.41, 0.0),
		float2(0.0, 1.41),
		float2(0.0, -1.41),

		float2(1.41, 1.41),
		float2(-1.41, -1.41),
		float2(-1.41, 1.41),
		float2(1.41, -1.41)
	};
	int i=0;

	float4 tcol=origcolor;
	float invscreensize=1.0/ScreenSize;

	for (i=0; i<16; i++)
	{
		float2 tdir=offset[i].xy;
		coord.xy=IN.txcoord.xy+tdir.xy*invscreensize*BlurSamplingRange;
		float4 ct=tex2Dlod(SamplerColor, coord);

		tcol+=ct;
	}
	tcol*=0.05882353;

	res.xyz=tcol.xyz;
		
	res.w=1.0;
	return res;
}

float4 PS_ProcessSharpen(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{		
	float4 res;
	float4 coord=0.0;

	coord.xy=IN.txcoord.xy;
	float4 origcolor;

	coord.w=0.0;
	origcolor=tex2Dlod(SamplerColor, coord);

	float2 offset[8]=
	{
		float2(1.0, 1.0),
		float2(-1.0, -1.0),
		float2(-1.0, 1.0),
		float2(1.0, -1.0),

		float2(1.41, 0.0),
		float2(-1.41, 0.0),
		float2(0.0, 1.41),
		float2(0.0, -1.41)
	};
	int i=0;

	float4 tcol=origcolor;
	float invscreensize=1.0/ScreenSize;
	
	for (i=0; i<8; i++) 
	{
		float2 tdir=offset[i].xy;
		coord.xy=IN.txcoord.xy+tdir.xy*invscreensize*SharpSamplingRange;	
		float4 ct=tex2Dlod(SamplerColor, coord);
		tcol+=ct;
	}
	tcol*=0.1111; 

	//sharp
	#ifdef ESHARPENING
		#ifdef ESHARPENINGCOLOR
			//color
			res=origcolor*(1.0+((origcolor-tcol)*SharpeningAmount));
		#else
			//non color
			float difffact=dot((origcolor.xyz-tcol.xyz), 0.333);
			res=origcolor*(1.0+difffact*SharpeningAmount);
		#endif

		//less sharpening for bright pixels
		float rgray=origcolor.z; 	
		rgray=pow(rgray, 3.0);
		res=lerp(res, origcolor, saturate(rgray));
	#endif

	res.w=1.0;
	return res;
}

float4 PS_ProcessShift(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
	float4 res;
	float4 coord=0.0;

	coord.xy=IN.txcoord.xy;
	float4 origcolor;

	coord.w=0.0;

	origcolor=tex2Dlod(SamplerColor, coord);

	int i=0;

	#ifdef ECOLORSHIFT
		float4 tcol=origcolor;
		float2 invscreensize=1.0/ScreenSize.x;
		invscreensize.y=invscreensize.y/ScreenSize.z;

		coord.xy=IN.txcoord.xy;
		origcolor=tex2Dlod(SamplerColor, coord);
		res.y=origcolor.y;

		coord.xy=IN.txcoord.xy;
		coord.y-=invscreensize*ShiftSamplingRange;
		origcolor=tex2Dlod(SamplerColor, coord);
		res.x=origcolor.x;

		coord.xy=IN.txcoord.xy;
		coord.y+=invscreensize*ShiftSamplingRange;
		origcolor=tex2Dlod(SamplerColor, coord);
		res.z=origcolor.z;
	#endif

	res.w=1.0;
	return res;
}

float4 PS_ProcessContrast(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{	
	float4	res;
	float3	origcolor=tex2D(SamplerColor, IN.txcoord.xy);
	float3	lumCoeff = float3(0.212656, 0.715158, 0.072186);  	//Calculate luma with these values
	
	float luma = dot(lumCoeff, origcolor.rgb);
	float3 chroma = origcolor.rgb - luma;
	
	float Curves_contrast_blend = ContrastCurve;
	float PI = 3.1415926535897932384626433832795; 
	
	float x = luma; 											//If the curve should be applied to Luma
  
	x = x - 0.5;
	x = x / ((abs(x)*1.25) + 0.375 ) + 0.5;
	
	x = lerp(luma, x, Curves_contrast_blend);					//if the curve should be applied to both Luma and Chroma
		
	if (C_CONTRASTCURVES==true)
	{	
		res.rgb = x + chroma; 										//Blend by Curves_contrast
	}
	
	if (C_CONTRASTCURVES==false)
	{
		res.rgb = origcolor.rgb;
	}	
  
	res.w=1.0;
	return res;
}

float4 PS_ProcessVibrance(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{	
	float4	res;
	float3	origcolor = tex2D(SamplerColor, IN.txcoord.xy);
	float3	lumCoeff = float3(0.212656, 0.715158, 0.072186);  				//Calculate luma with these values
	
	float	max_color = max(origcolor.r, max(origcolor.g,origcolor.b)); 	//Find the strongest color
	float	min_color = min(origcolor.r, min(origcolor.g,origcolor.b)); 	//Find the weakest color

	float	color_saturation = max_color - min_color; 						//Saturation is the difference between min and max

	float	luma = dot(lumCoeff, origcolor.rgb); 							//Calculate luma (grey)

	if (C_VIBRANCE==true)
	{	
		res.rgb = lerp(luma, origcolor.rgb, (1.0 + (Vibrance * (1.0 - (sign(Vibrance) * color_saturation))))); 	//Extrapolate between luma and original by 1 + (1-saturation) - current
	}
	
	if (C_VIBRANCE==false)
	{
		res.rgb = origcolor.rgb;
	}	
	
	res.w=1.0;
	return res;
}

float4 PS_ProcessNoise(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
	float4 coord=0.0;
	 
	coord.xy=IN.txcoord.xy;
	coord.w=0.0; 
	
	#define noise_strength_luma 				(CoefLuma * NoiseAmount)  
	#define CoefLuma 							float4(0.2126, 0.7152, 0.0722, 0)
 
	float4 tcol=tex2Dlod(SamplerColor, coord); 
	float origgray=max(tcol.x, tcol.y);
	origgray=max(origgray, tcol.z);
	coord.xy=IN.txcoord.xy*NoiseFineness + frac(Timer.x * 100000.0 + Timer.x);
	float4 cnoi=tex2Dlod(SamplerNoise, coord);
 
	#if NoiseMethod == 1
		tcol=lerp(tcol, (cnoi.x+0.5)*tcol, noise_strength_luma*saturate(1.0-origgray*0.5));
	#endif
	
	#if NoiseMethod == 0
		tcol=lerp(tcol, (cnoi.x+0.5)*tcol, NoiseAmount*saturate(1.0-origgray*0.5));
	#endif
 
	tcol.w=1.0;
	return tcol;
} 

float4 PS_LevelsPass(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
	#define black_point_float ( BlackPoint / 255.0 )
	#define white_point_float ( 255.0 / (WhitePoint - BlackPoint))
	
	float4	res;
	float3	origcolor = tex2D(SamplerColor, IN.txcoord.xy);
	
	if (C_BLACKLEVEL==true)
	{	
		res.rgb = origcolor.rgb * white_point_float - (black_point_float *  white_point_float);
	}
	
	if (C_BLACKLEVEL==false)
	{
		res.rgb = origcolor.rgb;
	}	
	
	res.w=1.0;
	return res;
}

///////////////////////
//	  TECHNIQUES	 //
///////////////////////
technique PostProcess
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessNoise();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}

technique PostProcess2
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessBlur();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}

technique PostProcess3
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessSharpen();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}

technique PostProcess4
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessShift();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}	

technique PostProcess5
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessContrast();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}

technique PostProcess6
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessVibrance();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}

technique PostProcess7
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessLumaSharpen();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}
	
technique PostProcess8
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_LevelsPass();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}	