// © Copyright 2023 timetravelbeard (contact: https://www.patreon.com/timetravelbeard , https://youtube.com/@timetravelbeard3588 , https://discord.gg/S6F4r6K5yU )

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//NOTE:  In case you don't know, copyright means all rights are reserved. You cannot modify, redistribute, or make derivative works of this. Do not steal any of this code or use "code snippets". 



vec3 ray_emit= vec3(0.0);
vec3 ray_emit2= vec3(0.0);

	#include "/settings_1.glsl"

//float skydist = far*2.9;

float ASSUMED_DEPTH2 =  ASSUMED_DEPTH ;

			
					#if NOISE_AMOUNT_IN_RAYS > 0 
				    //raypos+=noise_ray_amount;
			
						 float noise_ray_amount_specular =0.1*NOISE_AMOUNT_IN_RAYS* blueNoise()*clamp(1*1.0-smoothness,0.0,1.0);
						float noise_ray_amount_diffuse = 0.1*NOISE_AMOUNT_IN_RAYS*blueNoise();
								
				#else
					float noise_ray_amount_specular = 0.0;
float noise_ray_amount_diffuse = 0.0;
				#endif

#if KILL_SWITCH > 0

int Kill_switch_multiplier = (1.0/frameTime < KILL_SWITCH) ? 0 : 1;
//steps *=Kill_switch_multiplier;
#else
int Kill_switch_multiplier = 1;
#endif

vec3 diffuse_angle =  bumpy_orth.xyz;

 
				tangent = tangent *2-1;
			//	tangent2 = tangent2 *2-1;
				tangent.z*=-1;
		
				tangent2.xyz = normalize(cross(tangent.xyz,diffuse_angle.xyz));//*tangent.w);
				
		//		tangent2.z*=-1;
				
					#if CATCH_COLOR == 0
					int Steps_to_start = PBR_RAY_STEPS_SKY;
					#else
					int Steps_to_start = PBR_RAY_STEPS;
					#endif
				
			
int PBR_RAY_STEPS2 = Kill_switch_multiplier *  int( (float(Steps_to_start) * PATH_TRACING_RESOLUTION)) ;//((Steps_to_start>0)?1:0) );
PBR_RAY_STEPS2=(Steps_to_start>0&&PBR_RAY_STEPS2==0)?1:PBR_RAY_STEPS2;
//int PBR_RAY_STEPS2 = PBR_RAY_STEPS2;// * PATH_TRACING_RESOLUTION;// min(PBR_RAY_STEPS2 * PATH_TRACING_RESOLUTION,((PBR_RAY_STEPS2>0)?1:0) );
				
				
				#if SCREEN_TANGENT == 0
					tangent.xyz=vec3(1,0,0);
					tangent2.xyz=vec3(0,1,0);
					// diffuse_angle = vec3(0.0,0.0,-1.0); //bumpy_orth.xyz
					// reflected_angle_orth.xy/= texcoord.xy,-texture2D(colortex15,raypos.xy).z;
					//tangent.z*=-1;
				#endif
				reflected_angle_orth=normalize(reflected_angle_orth);
				
				//ray trace reflections
				bool rayhit = false;
				bool oob = false;
				vec3 reflection_rgb = vec3(0.0);
				vec3 raypos;// = vec3(texcoord.xy,texture2D(depthtex0,texcoord.xy).x);//+reflected_angle;
				vec3 rayspeed ;//= reflected_angle_orth*1.0/PBR_RAY_STEPS2;
				vec3 oobrgb=vec3(0.0);
				float fadesky_complete=0;
				
				 
				 raypos = vec3(texcoord.xy,texture2D(depthtex0,texcoord.xy).x);//+reflected_angle;
				 rayspeed = reflected_angle_orth*1.0/PBR_RAY_STEPS2;
				 oobrgb=vec3(0.0);
				//raypos+=rayspeed;
				
				int raystepss = 0;
				for(raystepss = 0;raystepss<0&&!oob&&!rayhit;raystepss++)
				{ 
				    
					raypos+=vec3(rayspeed.xy/abs(raypos.z),.015*rayspeed.z/abs(raypos.z));
					rayspeed*=1.05;
					//rayspeed=(reflected_angle_orth*.01)*(1+.1*raystepss);
					//rayspeed.xyz/=((1+raypos.z));
					oob = raypos.x<0 || raypos.x>1 || raypos.y<0 || raypos.y> 1 || raypos.z<0? true: false;
					oobrgb.g= raypos.y<0 || raypos.y>1 ? 1:0;
					oobrgb.r= raypos.x<0 || raypos.x>1 ? 1:0;
					oobrgb.b= raypos.z<0 || raypos.z>1 ? 1:0;
					rayhit = oob? false :(texture2D(depthtex0,raypos.xy).x) <  raypos.z ? true : false;
					//reflection_rgb = rayhit? rayhit
					//rayhit = oob? false : -texture2D(colortex15,raypos.xy).z <  raypos.z ? true : false;
				}
				float fadesky = oobrgb.r* (texcoord.x<.05?1-texcoord.x/.05: texcoord.x>.95?(texcoord.x-.95)/.05:0);
				//fade lower on screen, looking up is actually looking horizontally
				float looking_up=1-clamp(abs((distance(uppos,vec3(0.0,0.0,1.0))/(1*1.41))-1.0),0,1);
				fadesky = fadesky + looking_up* oobrgb.r*(1-raypos.y);//ffade sky lower on screen
				//fadesky = raypos.z<0? fadesky + looking_up*oobrgb.b*(1):fadesky;//ffade sky lower on screen
				fadesky = raypos.y<0?fadesky +looking_up*(1-raypos.y): fadesky;//ffade sky lower on screen
				
				fadesky =clamp(fadesky+ oobrgb.g* (texcoord.y<.05?1-texcoord.y/.05: texcoord.y>.95?(texcoord.y-.95)/.05:0) ,0.0,1.0);
				
				
				
				//raytrace reflections2
				 fadesky_complete=0;
				int numddiffrays=5;
				#if HALF_RAYS == 1
					sky_reflection = 0.0;
				#else
				vec3 reflection_color_total = vec3(0.0);
				
				//
				//ray cone setup
				#if CATCH_COLOR > 0
				 int w = RAY_NUM_W ;
				 int h = RAY_NUM_H ;
				#else
				 int w = SKY_RAY_NUM_W ;
				 int h = SKY_RAY_NUM_H ;
				 #endif 
				 
				 #if KILL_SWITCH > 0
w*=Kill_switch_multiplier;
h*=Kill_switch_multiplier;
#endif

				 
			     float iw = 1.0/w;
			     float ih = 1.0/h;
			     
			     vec3 t1,t2;
			     
			      #if RAY_FULLY_CONVERGE == 0
			      int ray_num= 4*w*h;
			      #else
			      int ray_num= 4*w*h+1;
				 #endif
				 int NUM_RAYS_SPECULAR = ray_num;
				 
				 	  #if CURVE_LENS == 0
		reflected_angle_orth = (vec3(reflected_angle_orth.xy-	curved_lens2.xy	 ,reflected_angle_orth.z));
				  #endif
				   #if CURVE_LENS == 0
				   reflected_angle_orth = reflect(eye_out,bumpy_orth); //bumpy_orth
				   #endif
				 
	vec3 goal = reflected_angle_orth.xyz; // or diffuse  normal
	
	float focus = mix(0.1,1.0,smoothness);;//or 0.1, etc
				
				//
				
		
				 
				 #include "/raycone.glsl"
				 
			rayhit = false;
				
				 raypos = vec3(texcoord.xy,-texture2D(colortex15,texcoord.xy).z);//+reflected_angle;
				
				 oobrgb=vec3(0.0);
				//raypos+=rayspeed;
				
				 oob = false;
				 raystepss = 0;
				 rayspeed=RAY_DIST*.25*normalize(rayspeed)/PBR_RAY_STEPS2;
				// raypos-=.5*vec3(rayspeed.xy/abs(raypos.z),rayspeed.z);
				 //raypos+=0.2*rayspeed*clamp(texture2D(noisetex, texcoord.xy).g,0.0,1.0);
			
				rayspeed.x*=.5;
					 #if NOISE_AMOUNT_IN_RAYS > 0 
				    raypos+=rayspeed*noise_ray_amount_specular;

				 #endif
				vec3 ray_color = vec3(0.0);
				
					//first step
				if(PBR_RAY_STEPS2<40)
				{ 
				    vec3 rayspeed2 = rayspeed * PBR_RAY_STEPS2/20;
					raypos+=vec3(rayspeed2.xy,rayspeed2.z*abs(raypos.z+1));
					//rayspeed*=1.05;
					//rayspeed=(reflected_angle_orth*.01)*(1+.1*raystepss);
					//rayspeed.xyz/=((1+raypos.z));
					oob = raypos.x<0 || raypos.x>1 || raypos.y<0 || raypos.y> 1 || raypos.z<0|| raypos.z>far? true: false;
					oobrgb.g= raypos.y<0 || raypos.y>1 ? 1:0;
					oobrgb.r= raypos.x<0 || raypos.x>1 ? 1:0;
					oobrgb.b= raypos.z<0 || raypos.z>far ? 1:0;
					// bgdepth = texture2D(depthtex0,raypos.xy).x;
					float bgdepth=-texture2D(colortex15,raypos.xy).z;
						#if ASSUMED_DEPTH_DYNAMIC == 1 
						ASSUMED_DEPTH2 = max(bgdepth,ASSUMED_DEPTH);
					#endif
					rayhit = oob? false :(bgdepth)+RAY_BIAS <  raypos.z && (bgdepth+ASSUMED_DEPTH2) >  raypos.z  ? true : false;
					//rayhit = oob? false : -texture2D(colortex15,raypos.xy).z <  raypos.z ? true : false;
				}
				
				
				for(raystepss = 0;raystepss<PBR_RAY_STEPS2&&!oob&&!rayhit;raystepss++)
				{ 
				    
					raypos+=vec3(rayspeed.xy,rayspeed.z*abs(raypos.z+1));
					rayspeed*=(1.0+ RAY_ACCELERATION);
					//rayspeed=(reflected_angle_orth*.01)*(1+.1*raystepss);
					//rayspeed.xyz/=((1+raypos.z));
					oob = raypos.x<0 || raypos.x>1 || raypos.y<0 || raypos.y> 1 || raypos.z<0|| raypos.z>far? true: false;
					oobrgb.g= raypos.y<0 || raypos.y>1 ? 1:0;
					oobrgb.r= raypos.x<0 || raypos.x>1 ? 1:0;
					oobrgb.b= raypos.z<0 || raypos.z>far ? 1:0;
					// bgdepth = texture2D(depthtex0,raypos.xy).x;
					float bgdepth=-texture2D(colortex15,raypos.xy).z;
						#if ASSUMED_DEPTH_DYNAMIC == 1 
						ASSUMED_DEPTH2 = max(bgdepth,ASSUMED_DEPTH);
					#endif
					rayhit = oob? false :(bgdepth)+RAY_BIAS <  raypos.z && (bgdepth+ASSUMED_DEPTH2) >  raypos.z  ? true : false;
					//rayhit = oob? false : -texture2D(colortex15,raypos.xy).z <  raypos.z ? true : false;
				}
				
					//
					
					
					
				#if CATCH_COLOR > 0
				
				
				if(rayhit)
				{
				
				int raylod = DIFFUSE_THE_RAYS_SPEC == 0 ? 0: int((1.0-smoothness)*(DIFFUSE_THE_RAYS_SPEC*raystepss*RAY_DIST)/PBR_RAY_STEPS2);
				
				//refine pos
				float reverse = -1.0;
				for(raystepss = 0;raystepss<REFINER_STEPS_RAY;raystepss++)
				{ 
				    rayspeed*=.5;
					raypos+=reverse*vec3(rayspeed.xy,rayspeed.z*abs(raypos.z+1));
					
					//rayspeed=(reflected_angle_orth*.01)*(1+.1*raystepss);
					//rayspeed.xyz/=((1+raypos.z));
					oob = raypos.x<0 || raypos.x>1 || raypos.y<0 || raypos.y> 1 || raypos.z<0|| raypos.z>far? true: false;
					oobrgb.g= raypos.y<0 || raypos.y>1 ? 1:0;
					oobrgb.r= raypos.x<0 || raypos.x>1 ? 1:0;
					oobrgb.b= raypos.z<0 || raypos.z>far ? 1:0;
					// bgdepth = texture2D(depthtex0,raypos.xy).x;
					float bgdepth=-texture2D(colortex15,raypos.xy).z;
						#if ASSUMED_DEPTH_DYNAMIC == 1 
						ASSUMED_DEPTH2 = max(bgdepth,ASSUMED_DEPTH);
					#endif
					reverse = oob? 1.0 :(bgdepth)+RAY_BIAS <  raypos.z && (bgdepth+ASSUMED_DEPTH2) >  raypos.z  ? -1.0 : 1.0;
					//rayhit = oob? false : -texture2D(colortex15,raypos.xy).z <  raypos.z ? true : false;
				}
				
				//
				
				#if CATCH_COLOR >1 
					ray_color =textureLod(colortex10,raypos.xy,raylod).rgb; // albedo2*(shadow_info.x ) ;
					#else
					ray_color =textureLod(colortex3,raypos.xy,raylod).rgb; // albedo2*(shadow_info.x ) ;
					#endif
					
					
					//ray_emit += albedo2*PBR_EMMISSIVE_STRENGTH*emmissiveness2;
					
				}
				#endif
				//
				reflection_color_total+=ray_color;
				
				
				 fadesky = oobrgb.r* (texcoord.x<.05?1-texcoord.x/.05: texcoord.x>.95?(texcoord.x-.95)/.05:0);
				 fadesky =clamp(fadesky+ oobrgb.g* (texcoord.y<.05?1-texcoord.y/.05: texcoord.y>.95?(texcoord.y-.95)/.05:0) ,0.0,1.0);
			    //
				 //fadesky = oobrgb.r* (texcoord.x<.05?1-texcoord.x/.05: texcoord.x>.95?(texcoord.x-.95)/.05:0);
				//fade lower on screen, looking up is actually looking horizontally
				float looking_up=1-clamp(abs((distance(uppos,vec3(0.0,0.0,1.0))/(1*1.41))-1.0),0,1);
				
				//debug
				looking_up=0.0;
				
				fadesky = fadesky + looking_up* oobrgb.r*(1-raypos.y);//ffade sky lower on screen
				//fadesky = raypos.z<0? fadesky + looking_up*oobrgb.b*(1):fadesky;//ffade sky lower on screen
				fadesky = raypos.y<0?fadesky +looking_up*(1-raypos.y): fadesky;//ffade sky lower on screen
				
				fadesky =clamp(fadesky+ oobrgb.g* (texcoord.y<.05?1-texcoord.y/.05: texcoord.y>.95?(texcoord.y-.95)/.05:0) ,0.0,1.0);
				
				
				//
				fadesky=rayhit?1.0:fadesky;
				 //fadesky=raypos.z>=skydist? 0.0:fadesky;
				
				
				 fadesky_complete+=fadesky;
				 
				  }  }//xy, wh
				 }//s
				 #if RAY_FULLY_CONVERGE == 1
				  }}
				  #endif
				 //per ray
				 
				 
				 #endif
				 reflection_color_total=reflection_color_total/(NUM_RAYS_SPECULAR);
				 ray_emit=ray_emit/(NUM_RAYS_SPECULAR);
				 fadesky_complete=clamp(fadesky_complete/(NUM_RAYS_SPECULAR),0.0,1.0);
					sky_light_cpf=sky_light_cpf*(1-fadesky_complete);
				//sky_light_cpf=rayhit?sky_light_cpf*0.0:sky_light_cpf*(1-fadesky);
				
				
				//raytrace ambient
				 fadesky_complete=0;
				 numddiffrays=5;
				 vec3 reflection_color_total2 = vec3(0.0);
				 
				 //
				//ray cone setup

			     
			     
			     
			      #if RAY_FULLY_CONVERGE == 0
			       ray_num= 4*w*h;
			      #else
			       ray_num= 4*w*h+1;
				 #endif
				 int NUM_RAYS_DIFFUSE = ray_num;
				 
	 goal = diffuse_angle.xyz; // or diffuse  normal
	
	 focus = 0.1;;//or 0.1, etc
				
				//
				
		
				 
				 #include "/raycone.glsl"
				 
				 
				
				 rayhit = false;
				
				 raypos = vec3(texcoord.xy,-texture2D(colortex15,texcoord.xy).z);//+reflected_angle;
				 
				 
			
				
				 oobrgb=vec3(0.0);
				//raypos+=rayspeed;
				 oob = false;
				 raystepss = 0;
				 #if HALF_RAYS == 1
					rayspeed= mix(rayspeed.xyz,reflected_angle_orth.xyz,smoothness);
				 #endif
				 
				 rayspeed=RAY_DIST*0.25*normalize(rayspeed)/PBR_RAY_STEPS2;
				 //raypos-=.5*vec3(rayspeed.xy/abs(raypos.z),rayspeed.z);
		
				 rayspeed.x*=.5;
				 
				 		 #if HALF_RAYS == 1
		
				    	 #if NOISE_AMOUNT_IN_RAYS > 0 
				    raypos+=rayspeed*noise_ray_amount_specular;

				 #endif
					
					
				#else
				 //just diffuse
					 #if NOISE_AMOUNT_IN_RAYS > 0 
				    raypos+=rayspeed*noise_ray_amount_diffuse;

				 #endif
				#endif
				 
				vec3 ray_color = vec3(0.0);
				
				//first step
				if(PBR_RAY_STEPS2<40)
				{ 
				    vec3 rayspeed2 = rayspeed * PBR_RAY_STEPS2/20;
					raypos+=vec3(rayspeed2.xy,rayspeed2.z*abs(raypos.z+1));
					//rayspeed*=1.05;
					//rayspeed=(reflected_angle_orth*.01)*(1+.1*raystepss);
					//rayspeed.xyz/=((1+raypos.z));
					oob = raypos.x<0 || raypos.x>1 || raypos.y<0 || raypos.y> 1 || raypos.z<0|| raypos.z>far? true: false;
					oobrgb.g= raypos.y<0 || raypos.y>1 ? 1:0;
					oobrgb.r= raypos.x<0 || raypos.x>1 ? 1:0;
					oobrgb.b= raypos.z<0 || raypos.z>far ? 1:0;
					// bgdepth = texture2D(depthtex0,raypos.xy).x;
					float bgdepth=-texture2D(colortex15,raypos.xy).z;
							#if ASSUMED_DEPTH_DYNAMIC == 1 
						ASSUMED_DEPTH2 = max(bgdepth,ASSUMED_DEPTH);
					#endif
					rayhit = oob? false :(bgdepth)+RAY_BIAS <  raypos.z && (bgdepth+ASSUMED_DEPTH2) >  raypos.z  ? true : false;
					//rayhit = oob? false : -texture2D(colortex15,raypos.xy).z <  raypos.z ? true : false;
				}
				
				for(raystepss = 0;raystepss<PBR_RAY_STEPS2&&!oob&&!rayhit;raystepss++)
				{ 
				    
					raypos+=vec3(rayspeed.xy,rayspeed.z*abs(raypos.z+1));
					rayspeed*=(1.0+ RAY_ACCELERATION);
					//rayspeed=(reflected_angle_orth*.01)*(1+.1*raystepss);
					//rayspeed.xyz/=((1+raypos.z));
					oob = raypos.x<0 || raypos.x>1 || raypos.y<0 || raypos.y> 1 || raypos.z<0? true: false;
					oobrgb.g= raypos.y<0 || raypos.y>1 ? 1:0;
					oobrgb.r= raypos.x<0 || raypos.x>1 ? 1:0;
					oobrgb.b= raypos.z<0 || raypos.z>1 ? 1:0;
					// bgdepth = texture2D(depthtex0,raypos.xy).x;
					float bgdepth=-texture2D(colortex15,raypos.xy).z;
						#if ASSUMED_DEPTH_DYNAMIC == 1 
						ASSUMED_DEPTH2 = max(bgdepth,ASSUMED_DEPTH);
					#endif
					rayhit = oob? false :(bgdepth)+RAY_BIAS <  raypos.z && (bgdepth+ASSUMED_DEPTH2) >  raypos.z  ? true : false;
					//rayhit = oob? false : -texture2D(colortex15,raypos.xy).z <  raypos.z ? true : false;
				}
				
				 int raylod = DIFFUSE_THE_RAYS == 0 ? 0: (DIFFUSE_THE_RAYS*raystepss*RAY_DIST)/PBR_RAY_STEPS2 ;
				
				 fadesky = oobrgb.r* (texcoord.x<.05?1-texcoord.x/.05: texcoord.x>.95?(texcoord.x-.95)/.05:0);
				 fadesky =clamp(fadesky+ oobrgb.g* (texcoord.y<.05?1-texcoord.y/.05: texcoord.y>.95?(texcoord.y-.95)/.05:0) ,0.0,1.0);
			     fadesky=rayhit?1.0:fadesky;
				// fadesky=raypos.z>=skydist? 0.0:fadesky;
				 fadesky_complete+=fadesky;
				 
				
				//
				#if CATCH_COLOR > 0
				if(rayhit)
				{
				//refine pos
				float reverse = -1.0;
				for(raystepss = 0;raystepss<REFINER_STEPS_RAY;raystepss++)
				{ 
				    rayspeed*=.5;
					raypos+=reverse*vec3(rayspeed.xy,rayspeed.z*abs(raypos.z+1));
					
					//rayspeed=(reflected_angle_orth*.01)*(1+.1*raystepss);
					//rayspeed.xyz/=((1+raypos.z));
					oob = raypos.x<0 || raypos.x>1 || raypos.y<0 || raypos.y> 1 || raypos.z<0|| raypos.z>far? true: false;
					oobrgb.g= raypos.y<0 || raypos.y>1 ? 1:0;
					oobrgb.r= raypos.x<0 || raypos.x>1 ? 1:0;
					oobrgb.b= raypos.z<0 || raypos.z>far ? 1:0;
					// bgdepth = texture2D(depthtex0,raypos.xy).x;
					float bgdepth=-texture2D(colortex15,raypos.xy).z;
						#if ASSUMED_DEPTH_DYNAMIC == 1 
						ASSUMED_DEPTH2 = max(bgdepth,ASSUMED_DEPTH);
					#endif
					reverse = oob? 1.0 :(bgdepth)+RAY_BIAS <  raypos.z && (bgdepth+ASSUMED_DEPTH2) >  raypos.z  ? -1.0 : 1.0;
					//rayhit = oob? false : -texture2D(colortex15,raypos.xy).z <  raypos.z ? true : false;
				}
				
				//
				#if CATCH_COLOR >1 
					ray_color =textureLod(colortex10,raypos.xy,raylod).rgb; // albedo2*(shadow_info.x ) ;
					#else
					ray_color =textureLod(colortex3,raypos.xy,raylod).rgb; // albedo2*(shadow_info.x ) ;
					#endif
					//ray_emit += albedo2*PBR_EMMISSIVE_STRENGTH*emmissiveness2;
					
				}
				#endif
				//
				
				reflection_color_total2+=ray_color;
				 
				  }  }//xy, wh
				 }//s
				  #if RAY_FULLY_CONVERGE == 1
				  }}
				  #endif
				 //per ray
				 
				 fadesky_complete=clamp(fadesky_complete/(NUM_RAYS_DIFFUSE),0.0,1.0);
				  ray_emit2=ray_emit2/(NUM_RAYS_DIFFUSE);
				 
					sky_light_diffuse=sky_light_diffuse*(1-fadesky_complete);
							//
				 reflection_color_total2=reflection_color_total2/(NUM_RAYS_DIFFUSE);
				 
				 
// © Copyright 2023 timetravelbeard (contact: https://www.patreon.com/timetravelbeard , https://youtube.com/@timetravelbeard3588 , https://discord.gg/S6F4r6K5yU )

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//NOTE:  In case you don't know, copyright means all rights are reserved. You cannot modify, redistribute, or make derivative works of this. Do not steal any of this code or use "code snippets". 

