using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;

using Renderer;
using SharpMath;
using UIUtility;

namespace TestGraphQuery
{
	public partial class GraphForm : Form
	{
		#region CONSTANTS

		const uint	MAX_QUERY_SOURCES = 64;

		#endregion

		#region NESTED TYPES

		[System.Runtime.InteropServices.StructLayout( System.Runtime.InteropServices.LayoutKind.Sequential )]
		private struct CB_Main {
			public uint			_nodesCount;
			public uint			_sourcesCount;
			public uint			_resX;
			public uint			_resY;

			public float2		_cameraCenter;
			public float2		_cameraSize;

			public float		_diffusionCoefficient;
			public uint			_sourceIndex;
			public uint			_hoveredNodeIndex;
			public uint			_renderFlags;

			public float		_barycentricDistanceTolerance;
			public float		_barycentricBias;
		}

		[System.Runtime.InteropServices.StructLayout( System.Runtime.InteropServices.LayoutKind.Sequential )]
		private struct CB_Text {
			public float2		_position;
			public float2		_right;
			public float2		_up;
		}

		[System.Runtime.InteropServices.StructLayout( System.Runtime.InteropServices.LayoutKind.Sequential )]
		private struct SB_NodeInfo {
			public float2		m_position;
			public uint			m_flags;
			public uint			m_linkOffset;
			public uint			m_linksCount;
		}

		[System.Runtime.InteropServices.StructLayout( System.Runtime.InteropServices.LayoutKind.Sequential )]
		private struct SB_Letter {
			public uint			m_letterIndex;
			public float		m_offset;
			public float		m_ratio;
		}

		#endregion

		#region FIELDS

		Device		m_device = new Device();

		private ConstantBuffer<CB_Main>			m_CB_Main = null;
		private ConstantBuffer<CB_Text>			m_CB_Text = null;

		private ComputeShader					m_compute_HeatDiffusion = null;
		private ComputeShader					m_compute_SplatHeatSources = null;

		private Shader							m_shader_RenderGraphNode = null;
		private Shader							m_shader_RenderGraphLink = null;
		private Shader							m_shader_RenderText = null;

		private StructuredBuffer<SB_NodeInfo>	m_SB_Nodes = null;
		private StructuredBuffer<uint>			m_SB_LinkSources = null;
		private StructuredBuffer<uint>			m_SB_LinkTargets = null;

		// Heatwave simulation
		private StructuredBuffer<uint>			m_SB_SourceIndices = null;
		private StructuredBuffer<float>			m_SB_HeatSource = null;
		private StructuredBuffer<float>			m_SB_HeatTarget = null;

		private bool							m_barycentricsDirty = true;
		private StructuredBuffer<float>			m_SB_HeatBarycentrics = null;

		private bool							m_sumDirty = true;
		private StructuredBuffer<float>			m_SB_HeatSum = null;

		// Text display
		private int[]							m_char2Index = new int[512];
		private Rectangle[]						m_fontRectangles = null;
 		private Texture2D						m_tex_FontAtlas = null;
 		private Texture2D						m_tex_FontRectangle = null;
		private StructuredBuffer<SB_Letter>		m_SB_Text = null;

		// Graph
		private ProtoParser.Graph				m_graph = null;
		private uint							m_nodesCount = 0;
		private uint							m_totalLinksCount = 0;
		private Dictionary< ProtoParser.Neuron, uint >	m_neuron2ID = null;

		private Texture2D						m_tex_FalseColors0 = null;
		private Texture2D						m_tex_FalseColors1 = null;

		#endregion

		#region METHODS

		public GraphForm() {
// UnitTestPacking();

			InitializeComponent();
		}

		protected override void OnLoad( EventArgs e ) {
			base.OnLoad( e );

			try {
				m_device.Init( panelOutput.Handle, false, true );
			}
			catch ( Exception _e ) {
				m_device = null;
				MessageBox.Show( "Failed to initialize DX device!\n\n" + _e.Message, "Heat Wave Test", MessageBoxButtons.OK, MessageBoxIcon.Error );
				return;
			}

			//////////////////////////////////////////////////////////////////////////
			m_CB_Main = new ConstantBuffer<CB_Main>( m_device, 0 );
			m_CB_Text = new ConstantBuffer<CB_Text>( m_device, 2 );

			m_compute_HeatDiffusion = new ComputeShader( m_device, new FileInfo( "./Shaders/HeatDiffusion.hlsl" ), "CS" );
			m_compute_SplatHeatSources = new ComputeShader( m_device, new FileInfo( "./Shaders/HeatDiffusion.hlsl" ), "CS2" );

			m_shader_RenderGraphNode = new Shader( m_device, new FileInfo( "./Shaders/RenderGraph.hlsl" ), VERTEX_FORMAT.Pt4, "VS", null, "PS" );
			m_shader_RenderGraphLink = new Shader( m_device, new FileInfo( "./Shaders/RenderGraph.hlsl" ), VERTEX_FORMAT.Pt4, "VS2", null, "PS2" );
			m_shader_RenderText = new Shader( m_device, new FileInfo( "./Shaders/RenderText.hlsl" ), VERTEX_FORMAT.Pt4, "VS", null, "PS"  );

			//////////////////////////////////////////////////////////////////////////
			// Load the graph we need to run
			m_graph = new ProtoParser.Graph();

			// Load graph
			using ( FileStream S = new FileInfo( "./Graphs/Birds.graph" ).OpenRead() )
				using ( BinaryReader R = new BinaryReader( S ) )
					m_graph.Read( R );

			// Load graph node positions (simulated and saved by the TestGraphViz project)
			float2[]	graphNodePositions = null;
			using ( FileStream S = new FileInfo( "./Graphs/Birds.graphpos" ).OpenRead() )
				using ( BinaryReader R = new BinaryReader( S ) ) {
					float2	BBoxMin = new float2( R.ReadSingle(), R.ReadSingle() );
					float2	BBoxMax = new float2( R.ReadSingle(), R.ReadSingle() );

					m_CB_Main.m._cameraCenter = 0.5f * (BBoxMin + BBoxMax);
					m_CB_Main.m._cameraSize = BBoxMax - BBoxMin;

					int	nodesCount = R.ReadInt32();
					if ( nodesCount != m_graph.NeuronsCount )
						throw new Exception( "Graph nodes count mismatch!" );

					graphNodePositions = new float2[nodesCount];
					for ( int i=0; i < nodesCount; i++ ) {
						graphNodePositions[i].Set( R.ReadSingle(), R.ReadSingle() );
					}
				}

			ProtoParser.Neuron[]	neurons = m_graph.Neurons;
			m_nodesCount = (uint) neurons.Length;

			// Build node info
			m_SB_Nodes = new StructuredBuffer<SB_NodeInfo>( m_device, m_nodesCount, true );

			m_neuron2ID = new Dictionary<ProtoParser.Neuron, uint>( neurons.Length );

			for ( int neuronIndex=0; neuronIndex < m_nodesCount; neuronIndex++ ) {
				ProtoParser.Neuron	N = neurons[neuronIndex];
				m_neuron2ID[N] = (uint) neuronIndex;

				uint	linksCount = (uint) (N.ParentsCount + N.ChildrenCount + N.FeaturesCount);
				m_SB_Nodes.m[neuronIndex].m_position = graphNodePositions[neuronIndex];
				m_SB_Nodes.m[neuronIndex].m_linkOffset = m_totalLinksCount;
				m_SB_Nodes.m[neuronIndex].m_linksCount = linksCount;
				m_SB_Nodes.m[neuronIndex].m_flags = 0U;

				m_totalLinksCount += linksCount;
			}

			m_SB_Nodes.Write();

			// Build node links
			m_SB_LinkTargets = new StructuredBuffer<uint>( m_device, m_totalLinksCount, true );
			m_SB_LinkSources = new StructuredBuffer<uint>( m_device, m_totalLinksCount, true );
			m_totalLinksCount = 0;
			for ( int neuronIndex=0; neuronIndex < m_nodesCount; neuronIndex++ ) {
				ProtoParser.Neuron	N = neurons[neuronIndex];
				foreach ( ProtoParser.Neuron O in N.Parents ) {
					m_SB_LinkSources.m[m_totalLinksCount] = (uint) neuronIndex;
					m_SB_LinkTargets.m[m_totalLinksCount++] = m_neuron2ID[O];
				}
				foreach ( ProtoParser.Neuron O in N.Children ) {
					m_SB_LinkSources.m[m_totalLinksCount] = (uint) neuronIndex;
					m_SB_LinkTargets.m[m_totalLinksCount++] = m_neuron2ID[O];
				}
				foreach ( ProtoParser.Neuron O in N.Features ) {
					m_SB_LinkSources.m[m_totalLinksCount] = (uint) neuronIndex;
					m_SB_LinkTargets.m[m_totalLinksCount++] = m_neuron2ID[O];
				}
			}
			m_SB_LinkTargets.Write();
			m_SB_LinkSources.Write();

			// Build heat buffers
			uint	elementsCount = m_nodesCount * MAX_QUERY_SOURCES;
			m_SB_SourceIndices = new StructuredBuffer<uint>( m_device, MAX_QUERY_SOURCES, true );
			m_SB_HeatSource = new StructuredBuffer<float>( m_device, elementsCount, true );
			m_SB_HeatTarget = new StructuredBuffer<float>( m_device, elementsCount, true );

			m_SB_HeatBarycentrics = new StructuredBuffer<float>( m_device, elementsCount, true );
			m_SB_HeatSum = new StructuredBuffer<float>( m_device, m_nodesCount, true );

			// Setup initial CB
			m_CB_Main.m._nodesCount = m_nodesCount;
			m_CB_Main.m._sourcesCount = 0;
			m_CB_Main.m._resX = (uint) panelOutput.Width;
			m_CB_Main.m._resY = (uint) panelOutput.Height;
			m_CB_Main.m._diffusionCoefficient = 1.0f;
			m_CB_Main.m._hoveredNodeIndex = ~0U;
			m_CB_Main.m._renderFlags = 0U;
			m_CB_Main.UpdateData();

			// Load false colors
			m_tex_FalseColors0 = LoadFalseColors( new FileInfo( "../../Images/Gradients/Magma.png" ) );
			m_tex_FalseColors1 = LoadFalseColors( new FileInfo( "../../Images/Gradients/Viridis.png" ) );

			// Prepare font atlas
			m_SB_Text = new StructuredBuffer<SB_Letter>( m_device, 1024U, true );
			BuildFont();

			Application.Idle += Application_Idle;
		}

		void Application_Idle( object sender, EventArgs e ) {
			if ( m_device == null )
				return;

			m_CB_Main.m._sourceIndex = (uint) integerTrackbarControlShowQuerySourceIndex.Value;
			m_CB_Main.m._renderFlags = 0U;
			m_CB_Main.m._renderFlags |= radioButtonShowBarycentrics.Checked ? 0x1U : 0U;
			m_CB_Main.m._renderFlags |= radioButtonShowResultsBarycentric.Checked ? 0x2U : 0U;
			m_CB_Main.m._renderFlags |= radioButtonShowResultsSum.Checked ? 0x4U : 0U;
			m_CB_Main.m._renderFlags |= checkBoxShowLog.Checked ? 0x10U : 0U;
			m_CB_Main.m._barycentricDistanceTolerance = floatTrackbarControlResultsTolerance.Value;
			m_CB_Main.m._barycentricBias = floatTrackbarControlBarycentricBias.Value;
			m_CB_Main.m._diffusionCoefficient = floatTrackbarControlDiffusionConstant.Value;
			m_CB_Main.UpdateData();

			//////////////////////////////////////////////////////////////////////////
			// Simulate heat wave
			if ( checkBoxRun.Checked && m_queryNodes.Length > 0 && m_compute_HeatDiffusion.Use() ) {

				m_SB_HeatSource.SetInput( 0 );
				m_SB_HeatTarget.SetOutput( 0 );

				m_SB_Nodes.SetInput( 1 );
				m_SB_LinkTargets.SetInput( 2 );

				m_SB_SourceIndices.SetInput( 3 );

				// Simulate heat propagation
				m_compute_HeatDiffusion.Dispatch( (m_nodesCount + 63) >> 6, (uint) m_queryNodes.Length, 1 );

				// Splat heat sources
				m_compute_SplatHeatSources.Use();
				m_compute_SplatHeatSources.Dispatch( ((uint) m_queryNodes.Length + 63) >> 6, 1, 1 );

				// Swap source & target
				StructuredBuffer<float>	temp = m_SB_HeatTarget;
				m_SB_HeatTarget = m_SB_HeatSource;
				m_SB_HeatSource = temp;

				m_barycentricsDirty = true;
				m_sumDirty = true;
			}

			//////////////////////////////////////////////////////////////////////////
			// Render
			m_device.Clear( float4.Zero );
			m_device.ClearDepthStencil( m_device.DefaultDepthStencil, 1.0f, 0, true, false );

			m_SB_Nodes.SetInput( 0 );
			m_SB_LinkTargets.SetInput( 1 );
			m_SB_LinkSources.SetInput( 2 );

			m_SB_HeatSource.SetInput( 3 );
			if ( radioButtonShowTemperature.Checked ) {
				m_tex_FalseColors0.Set( 5 );
			} else if ( radioButtonShowBarycentrics.Checked ) {
				GetBarycentricsBuffer().SetInput( 4 );
				m_tex_FalseColors1.Set( 5 );
			} else if ( radioButtonShowResultsBarycentric.Checked ) {
				GetBarycentricsBuffer().SetInput( 4 );
			} else if ( radioButtonShowResultsSum.Checked ) {
				GetSumBuffer().SetInput( 4 );
				m_tex_FalseColors0.Set( 5 );
			}

			if ( m_shader_RenderGraphLink.Use() ) {
				m_device.SetRenderStates( RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.READ_WRITE_DEPTH_LESS, BLEND_STATE.DISABLED );
				m_device.SetRenderTarget( m_device.DefaultTarget, m_device.DefaultDepthStencil );

				m_device.ScreenQuad.RenderInstanced( m_shader_RenderGraphLink, m_totalLinksCount );
			}

			if ( m_shader_RenderGraphNode.Use() ) {
				m_device.SetRenderStates( RASTERIZER_STATE.NOCHANGE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.NOCHANGE );
				m_device.SetRenderTarget( m_device.DefaultTarget, null );

				m_device.ScreenQuad.RenderInstanced( m_shader_RenderGraphNode, m_nodesCount );
			}

			//////////////////////////////////////////////////////////////////////////
			// Draw some text
			if ( m_displayText != null && m_displayText.Length > 0 && m_shader_RenderText.Use() ) {
				m_device.SetRenderStates( RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.DISABLED );
				m_device.SetRenderTarget( m_device.DefaultTarget, null );

				m_tex_FontAtlas.SetPS( 0 );
				m_tex_FontRectangle.SetVS( 1 );

				// Fill text letters
				int	totalWidth = 0;
				int	totalHeight = (int) m_tex_FontAtlas.Height;
				for ( int i=0; i < m_displayText.Length; i++ ) {
					int			letterIndex = m_char2Index[(int) m_displayText[i]];
					Rectangle	rect = m_fontRectangles[letterIndex];
					m_SB_Text.m[i].m_letterIndex = (uint) letterIndex;
					m_SB_Text.m[i].m_offset = totalWidth;
					m_SB_Text.m[i].m_ratio = rect.Width;
					totalWidth += rect.Width;
				}
					// Normalize
				float	norm = 1.0f / totalWidth;
				for ( int i=0; i < m_displayText.Length; i++ ) {
					m_SB_Text.m[i].m_offset *= norm;
					m_SB_Text.m[i].m_ratio *= norm;
				}
				m_SB_Text.Write();
				m_SB_Text.SetInput( 2 );

				// Setup text rectangle
				const float	textHeight_pixels = 20.0f;	// What we want the text size to be on screen
				float		textWidth_pixels = totalWidth * textHeight_pixels / totalHeight;

				float2		textSize_proj = new float2( 2.0f * textWidth_pixels / panelOutput.Width, 2.0f * textHeight_pixels / panelOutput.Height );

				float2		selectedNodePosition_proj = new float2(  2.0f * (m_selectedNodePosition.x - m_CB_Main.m._cameraCenter.x) / m_CB_Main.m._cameraSize.x,
																	-2.0f * (m_selectedNodePosition.y - m_CB_Main.m._cameraCenter.y) / m_CB_Main.m._cameraSize.y );
				m_CB_Text.m._position.Set( selectedNodePosition_proj.x - 0.5f * textSize_proj.x, selectedNodePosition_proj.y + 1.0f * textSize_proj.y );	// Horizontal centering on node position, vertical offset so it's above
				m_CB_Text.m._right.Set( textSize_proj.x, 0.0f );
				m_CB_Text.m._up.Set( 0.0f, textSize_proj.y );
				m_CB_Text.UpdateData();

				m_device.ScreenQuad.RenderInstanced( m_shader_RenderText, (uint) m_displayText.Length );
			}

			m_device.Present( false );
		}

		#region Normalized Results Space Computation

		float	ComputeLogHeat( float _heat ) {
//return _heat;
//			return 1 + Mathf.Log( Math.Max( 1e-18f, _heat ) );
			return Mathf.Sqrt( -Mathf.Log( Math.Max( 1e-18f, _heat ) ) );	// Following Varadhan
		}

		StructuredBuffer<float>			GetBarycentricsBuffer() {
			if ( !m_barycentricsDirty || m_queryNodes.Length < 2 )
				return m_SB_HeatBarycentrics;

			// Read back simulation & transform into computable log heat
			m_SB_HeatSource.Read();
			for ( int nodeIndex=0; nodeIndex < m_SB_HeatSource.m.Length; nodeIndex++ )
				m_SB_HeatSource.m[nodeIndex] = ComputeLogHeat( m_SB_HeatSource.m[nodeIndex] );

			// Build a matrix of mutual heat values for each simulation at the position of each source
			int			sourcesCount = m_queryNodes.Length;
			Matrix		mutualHeat = new Matrix( sourcesCount );
			for ( int source0=0; source0 < sourcesCount; source0++ ) {
				int	sourceHeatOffset0 = (int) m_nodesCount * source0;

				for ( int source1=0; source1 < sourcesCount; source1++ ) {
					int		sourceNodeIndex = (int) m_neuron2ID[m_queryNodes[source1]];
					float	heat = m_SB_HeatSource.m[sourceHeatOffset0 + sourceNodeIndex];	// Here we read the temperature of source 1 in the simulation space of source 0
					mutualHeat[source1,source0] = heat;
				}
			}

			// Invert so we get the matrix that will help us compute barycentric coordinates
			Matrix		barycentric = mutualHeat.Invert();
//Matrix	test = mutualHeat * barycentric;

			// Apply transform to the fields
			double[]	sourceHeatVector = new double[sourcesCount];
			double[]	barycentricsVector = new double[sourcesCount];
			for ( int nodeIndex=0; nodeIndex < (int) m_nodesCount; nodeIndex++ ) {
				// Build source vector
				for ( int sourceIndex=0; sourceIndex < sourcesCount; sourceIndex++ ) {
					sourceHeatVector[sourceIndex] = m_SB_HeatSource.m[(int) m_nodesCount * sourceIndex + nodeIndex];
				}

				// Transform into barycentrics
				Matrix.Mul( sourceHeatVector, barycentric, barycentricsVector );

				// Write back
				for ( int sourceIndex=0; sourceIndex < sourcesCount; sourceIndex++ ) {
					m_SB_HeatBarycentrics.m[(int) m_nodesCount * sourceIndex + nodeIndex] = (float) barycentricsVector[sourceIndex];
				}
			}

			// Write results
			m_SB_HeatBarycentrics.Write();

			m_barycentricsDirty = false;

			return m_SB_HeatBarycentrics;
		}

		StructuredBuffer<float>			GetSumBuffer() {
			if ( !m_sumDirty || m_queryNodes.Length < 2 )
				return m_SB_HeatSum;

			// Read back simulation & accumulate into each node
			m_SB_HeatSource.Read();

			// Build a matrix of mutual heat values for each simulation at the position of each source
			int		sourcesCount = m_queryNodes.Length;
			float	maxHeat = 0.0f;
			for ( int nodeIndex=0; nodeIndex < m_nodesCount; nodeIndex++ ) {
				float	sumHeat = 0.0f;
				for ( int sourceIndex=0; sourceIndex < sourcesCount; sourceIndex++ )
					sumHeat += m_SB_HeatSource.m[m_nodesCount * sourceIndex + nodeIndex];

				m_SB_HeatSum.m[nodeIndex] = sumHeat;
				maxHeat = Mathf.Max( maxHeat, sumHeat );
			}

			// Normalize
			for ( int nodeIndex=0; nodeIndex < m_nodesCount; nodeIndex++ ) {
				m_SB_HeatSum.m[nodeIndex] = m_SB_HeatSum.m[nodeIndex] / maxHeat;
			}

			// Write results
			m_SB_HeatSum.Write();

			m_sumDirty = false;

			return m_SB_HeatSum;
		}

		#endregion

		#region Junk

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
		protected override void Dispose( bool disposing ) {
			if ( disposing && (components != null) ) {
				components.Dispose();

				m_tex_FontRectangle.Dispose();
				m_tex_FontAtlas.Dispose();
				m_SB_Text.Dispose();

				m_SB_HeatSum.Dispose();
				m_SB_HeatBarycentrics.Dispose();
				m_SB_HeatTarget.Dispose();
				m_SB_HeatSource.Dispose();

				m_tex_FalseColors1.Dispose();
  				m_tex_FalseColors0.Dispose();

				m_SB_SourceIndices.Dispose();

				m_SB_LinkTargets.Dispose();
				m_SB_LinkSources.Dispose();
				m_SB_Nodes.Dispose();

				m_shader_RenderText.Dispose();
				m_shader_RenderGraphLink.Dispose();
				m_shader_RenderGraphNode.Dispose();

				m_compute_HeatDiffusion.Dispose();

				m_CB_Text.Dispose();
				m_CB_Main.Dispose();

				Device	temp = m_device;
				m_device = null;
				temp.Dispose();
			}
			base.Dispose( disposing );
		}

		void	BuildFont() {
			string	charSet = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~éèêëôöàçÔÖÂÊÉœûüù";

			m_fontRectangles = new Rectangle[charSet.Length];
			for ( int charIndex=0; charIndex < charSet.Length; charIndex++ ) {
				char	C = charSet[charIndex];
				int		index = (int) C;
				m_char2Index[index] = charIndex;
			}

			// Load atlas & rectangles
			using ( ImageUtility.ImageFile file = new ImageUtility.ImageFile( new FileInfo( "Atlas.png" ) ) ) {
				ImageUtility.ImageFile file2 = new ImageUtility.ImageFile( file, ImageUtility.PIXEL_FORMAT.RGBA8 );
				using ( ImageUtility.ImagesMatrix M = new ImageUtility.ImagesMatrix( file2, ImageUtility.ImagesMatrix.IMAGE_TYPE.sRGB ) ) {
					m_tex_FontAtlas = new Texture2D( m_device, M, ImageUtility.COMPONENT_FORMAT.UNORM_sRGB );
				}
			}

			using ( FileStream S = new FileInfo( "Atlas.rect" ).OpenRead() )
				using ( BinaryReader R = new BinaryReader( S ) ) {

					// Read both CPU and GPU versions
					float	recW = 1.0f / m_tex_FontAtlas.Width;
					float	recH = 1.0f / m_tex_FontAtlas.Height;
					using ( PixelsBuffer content = new PixelsBuffer( (uint) (16 * m_fontRectangles.Length) ) ) {
						using ( BinaryWriter W = content.OpenStreamWrite() ) {
							for ( int i=0; i < m_fontRectangles.Length; i++ ) {
								m_fontRectangles[i].X = R.ReadInt32();
								m_fontRectangles[i].Y = R.ReadInt32();
								m_fontRectangles[i].Width = R.ReadInt32();
								m_fontRectangles[i].Height = R.ReadInt32();

								W.Write( recW * (float) m_fontRectangles[i].X );
								W.Write( recH * (float) m_fontRectangles[i].Y );
								W.Write( recW * (float) m_fontRectangles[i].Width );
								W.Write( recH * (float) m_fontRectangles[i].Height );
							}
						}

						m_tex_FontRectangle = new Texture2D( m_device, (uint) m_fontRectangles.Length, 1, 1, 1, ImageUtility.PIXEL_FORMAT.RGBA32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, false, new PixelsBuffer[] { content } );
					}
				}

		}

		Texture2D	LoadFalseColors( FileInfo _fileName ) {
			using ( ImageUtility.ImageFile sourceImage = new ImageUtility.ImageFile( _fileName, ImageUtility.ImageFile.FILE_FORMAT.PNG ) ) {
				ImageUtility.ImageFile convertedImage = new ImageUtility.ImageFile();
				convertedImage.ConvertFrom( sourceImage, ImageUtility.PIXEL_FORMAT.BGRA8 );
				using ( ImageUtility.ImagesMatrix image = new ImageUtility.ImagesMatrix( convertedImage, ImageUtility.ImagesMatrix.IMAGE_TYPE.sRGB ) )
					return new Texture2D( m_device, image, ImageUtility.COMPONENT_FORMAT.UNORM_sRGB );
			}
		}

		#endregion

		#region Pack/Unpack unit testing

		void	UnitTestPacking() {
			for ( ushort i=0; i < 4096; i++ ) {
				for ( ushort j=i; j < 4096; j++ ) {
					uint	V = Pack2( i, j );
					ushort	i2, j2;
					Unpack2( V, out i2, out j2 );
					if ( i2 != i || j2 != j )
						throw new Exception( "Rha mé !" );
				}
			}

			for ( ushort i=0; i < 4096; i++ ) {
				for ( ushort j=i; j < 4096; j++ ) {
					uint	V = Pack( i, j );
					ushort	i2, j2;
					Unpack( V, out i2, out j2 );
					if ( i2 != i || j2 != j )
						throw new Exception( "Rha mé !" );
				}
			}
		}

uint	BitsCount( ushort _value ) {
	uint	count = 0;
	ushort	mask = (ushort) 0x8000U;
	for ( ; count < 16 && (_value & mask) == 0; count++, mask>>=1 );
	return 15 - count;
}
uint	Pack( ushort _a, ushort _b ) {
	uint	bitsCount = 1 + BitsCount( _a );
	uint	result = bitsCount << (32-4);
	if ( bitsCount > 0 )
		result |= (uint) (_a << (12 - (int) bitsCount));
	if ( bitsCount < 12 )
		result |= (uint) ((_b - _a) & (0x0FFFU >> (int) bitsCount));
	return result;
}
void	Unpack( uint _value, out ushort _a, out ushort _b ) {
	uint	bitsCount = _value >> (32-4);
	_a = (ushort) (bitsCount > 0 ? (_value >> (12 - (int) bitsCount)) : 0U);
	_b = (ushort) (bitsCount < 12 ? (_value & (0x0FFFU >> (int) bitsCount)) : 0);
	_b += _a;
}

uint	maxTotalBitsCount = 0;
ushort	maxA, maxB;
uint	Pack2( ushort _a, ushort _b ) {
	_b -= _a;
	uint	bitsCount0 = 1 + BitsCount( _a );
	uint	bitsCount1 = 1 + BitsCount( _b );
//	uint	result = (bitsCount0 << (32-4)) | (bitsCount1 << (32-8));
	uint	result = bitsCount0 << (32-4);
			result |= _a;
			result |= (uint) _b << (int) bitsCount0;

// Check max count
if ( bitsCount0 + bitsCount1 > maxTotalBitsCount ) {
	maxTotalBitsCount = bitsCount0 + bitsCount1;
	maxA = _a;
	maxB = _b;
}

	return result;
}
void	Unpack2( uint _value, out ushort _a, out ushort _b ) {
	uint	bitsCount = _value >> (32-4);
	_a = (ushort) (_value & (0x0FFFU >> (int) (12 - bitsCount)));
	_b = (ushort) (_value >> (int) bitsCount);
	_b += _a;
}

		#endregion

		#endregion

		#region EVENT HANDLERS

		private void buttonReload_Click( object sender, EventArgs e ) {
			m_device.ReloadModifiedShaders();
		}

		private void buttonReset_Click( object sender, EventArgs e ) {
			Array.Clear( m_SB_HeatSource.m, 0, m_SB_HeatSource.m.Length );
			m_SB_HeatSource.Write();
			m_barycentricsDirty = true;
			m_sumDirty = true;
		}

		float[]	m_resultScores = new float[0];
		int[]	m_resultNodeIndices = new int[0];

		float	ComputeResult( uint _nodeIndex ) {
			int		sourcesCount = m_queryNodes.Length;

			float	bias = floatTrackbarControlBarycentricBias.Value;
			int		biasSourceTarget = integerTrackbarControlShowQuerySourceIndex.Value;

			float	isoBarycentricCenter0 = (1.0f - bias) / (sourcesCount - bias);	// The ideal center is a vector with all components equal to this value
			float	isoBarycentricCenter1 = Mathf.Lerp( isoBarycentricCenter0, 1.0f, bias );

			float	sqDistance = 0.0f;
			for ( int sourceIndex=0; sourceIndex < sourcesCount; sourceIndex++ ) {
				float	barycentric = m_SB_HeatBarycentrics.m[m_nodesCount * sourceIndex + _nodeIndex];
				float	delta = barycentric - (sourceIndex == biasSourceTarget ? isoBarycentricCenter1 : isoBarycentricCenter0);
				sqDistance += delta * delta;
			}

			return Mathf.Sqrt( sqDistance );
		}

		private void buttonGrabResults_Click( object sender, EventArgs e ) {
			int	sourcesCount = m_queryNodes.Length;
			if ( sourcesCount == 0 ) {
				textBoxSearchResults.Text = "No results.";
				return;
			}

			// Compute barycentrics needed for results
			if ( radioButtonShowResultsBarycentric.Checked ) {
				GetBarycentricsBuffer().Read();

				// Compute node scores
				float	bias = floatTrackbarControlBarycentricBias.Value;
				int		biasSourceTarget = integerTrackbarControlShowQuerySourceIndex.Value;

				float	isoBarycentricCenter0 = (1.0f - bias) / (sourcesCount - bias);	// The ideal center is a vector with all components equal to this value
				float	isoBarycentricCenter1 = Mathf.Lerp( isoBarycentricCenter0, 1.0f, bias );

				m_resultScores = new float[m_nodesCount];
				m_resultNodeIndices = new int[m_nodesCount];
				for ( int nodeIndex=0; nodeIndex < m_nodesCount; nodeIndex++ ) {

					float	sqDistance = 0.0f;
					for ( int sourceIndex=0; sourceIndex < sourcesCount; sourceIndex++ ) {
						float	barycentric = m_SB_HeatBarycentrics.m[m_nodesCount * sourceIndex + nodeIndex];
						float	delta = barycentric - (sourceIndex == biasSourceTarget ? isoBarycentricCenter1 : isoBarycentricCenter0);
						sqDistance += delta * delta;
					}

					m_resultScores[nodeIndex] = Mathf.Sqrt( sqDistance );
					m_resultNodeIndices[nodeIndex] = nodeIndex;
				}
			} else {
				GetSumBuffer().Read();

				// Compute node scores
				m_resultScores = new float[m_nodesCount];
				m_resultNodeIndices = new int[m_nodesCount];
				for ( int nodeIndex=0; nodeIndex < m_nodesCount; nodeIndex++ ) {
					m_resultScores[nodeIndex] = 1.0f - m_SB_HeatSum.m[nodeIndex];	// Lowest scores are better!
					m_resultNodeIndices[nodeIndex] = nodeIndex;
				}
			}

//Il faut aussi isoler les résultats du type qu'on veut !

			// Dump results
			string	results = "";

			if ( Selection.Length > 0 ) {
				// Show selected nodes first
				results += "Results for selection:\r\n";
				foreach ( ProtoParser.Neuron selectedNode in Selection ) {
					float	score = m_resultScores[m_neuron2ID[selectedNode]];
					results += selectedNode + (selectedNode.m_value is ProtoParser.NeuronValue ? "( " + ((selectedNode.m_value as ProtoParser.NeuronValue).m_valueMean != null ? (selectedNode.m_value as ProtoParser.NeuronValue).m_valueMean : "<null>") + " )" : "") + " - " + score.ToString( "G4" ) + "\r\n";
				}

				results += "\r\n";
			}

			// Sort scores & dump the N first
			Array.Sort( m_resultScores, m_resultNodeIndices );

			for ( int i=0; i < integerTrackbarControlSignificantResultsCount.Value; i++ ) {
				float				score = m_resultScores[i];
				ProtoParser.Neuron	N = m_graph.Neurons[m_resultNodeIndices[i]];
				results += N + (N.m_value is ProtoParser.NeuronValue ? "( " + ((N.m_value as ProtoParser.NeuronValue).m_valueMean != null ? (N.m_value as ProtoParser.NeuronValue).m_valueMean : "<null>") + " )" : "") + " - " + score.ToString( "G4" ) + "\r\n";
			}
			textBoxSearchResults.Text = results;
		}

		private void panelOutput_MouseDown( object sender, MouseEventArgs e ) {
// 			if ( e.Button == MouseButtons.Middle ) {
// 				// Add a new hotspot
// 				AddHotSpot( new Point( e.X * GRAPH_SIZE / panelOutput.Width, e.Y * GRAPH_SIZE / panelOutput.Height ) );
//
// 				// Authorize source plotting ONLY when we successfully registered a new point
// 				m_plotSource = true;
// 			}
		}

		#region Hovering

		float2	Client2Pos( Point _clientPos ) {
			return new float2(	m_CB_Main.m._cameraCenter.x + ((float) _clientPos.X / panelOutput.Width - 0.5f) * m_CB_Main.m._cameraSize.x,
								m_CB_Main.m._cameraCenter.y - (0.5f - (float) _clientPos.Y / panelOutput.Height) * m_CB_Main.m._cameraSize.y );
		}

		string	m_displayText = null;
		float2	m_selectedNodePosition;
		private void panelOutput_MouseMove( object sender, MouseEventArgs e ) {
			// Transform mouse position into node space
			float2	mousePosition = Client2Pos( e.Location );
			float	nodeRadius = 0.01f * 0.5f * (m_CB_Main.m._cameraSize.x + m_CB_Main.m._cameraSize.y);	// Radius adapts to camera size
			float	sqNodeRadius = nodeRadius * nodeRadius;

			// Identify any node under the mouse
			m_SB_Nodes.Read();

			m_displayText = null;
			m_CB_Main.m._hoveredNodeIndex = ~0U;
			for ( int nodeIndex=0; nodeIndex < m_nodesCount; nodeIndex++ ) {
				float2	nodePosition = m_SB_Nodes.m[nodeIndex].m_position;
				float2	delta = nodePosition - mousePosition;
				float	sqDistance = delta.Dot( delta );
				if ( sqDistance > sqNodeRadius )
					continue;

				// Found it!
				ProtoParser.Neuron	selectedNeuron = m_graph[nodeIndex];
				if ( selectedNeuron.m_name != null )
					m_displayText = selectedNeuron.m_name;
				else
					m_displayText = "*" + selectedNeuron.Parents[0].m_name;

				if ( selectedNeuron.m_value is ProtoParser.NeuronValue ) {
					// Show value
					m_displayText += "( ";
					m_displayText += (selectedNeuron.m_value as ProtoParser.NeuronValue).m_valueMean != null ? (selectedNeuron.m_value as ProtoParser.NeuronValue).m_valueMean : "<null>";
					m_displayText += " )";
				}

				// Show value
				if ( radioButtonShowTemperature.Checked ) {
					m_SB_HeatSource.Read();
					float	heat = m_SB_HeatSource.m[m_nodesCount * integerTrackbarControlShowQuerySourceIndex.Value + m_neuron2ID[selectedNeuron]];
					m_displayText += " = " + heat.ToString( "G4" );
				} else if ( radioButtonShowBarycentrics.Checked ) {
					GetBarycentricsBuffer();
					float	heat = m_SB_HeatBarycentrics.m[m_nodesCount * integerTrackbarControlShowQuerySourceIndex.Value + m_neuron2ID[selectedNeuron]];
					m_displayText += " = " + heat.ToString( "G4" );
				} else if ( radioButtonShowResultsBarycentric.Checked ) {
					GetBarycentricsBuffer();
					float	heat = ComputeResult( m_neuron2ID[selectedNeuron] );
					m_displayText += " = " + heat.ToString( "G4" );
				} else if ( radioButtonShowResultsSum.Checked ) {
					float	heatSum = GetSumBuffer().m[m_neuron2ID[selectedNeuron]];
					m_displayText += " = " + heatSum.ToString( "G4" );
				}

				m_selectedNodePosition = nodePosition;

				m_CB_Main.m._hoveredNodeIndex = (uint) nodeIndex;
				break;
			}

			m_CB_Main.UpdateData();
		}

		#endregion

		#region Query/Selection Input

		ProtoParser.Neuron[]	m_queryNodes = new ProtoParser.Neuron[0];
		ProtoParser.Neuron[]	QueryNodes {
			get { return m_queryNodes; }
			set {
				if ( value == null )
					value = new ProtoParser.Neuron[0];

				m_queryNodes = value;

				// Update the amount of sources in the main CB
				m_CB_Main.m._sourcesCount = (uint) m_queryNodes.Length;
				m_CB_Main.UpdateData();

				// Set the source indices for the splatting shader
				for ( int i=0; i < m_queryNodes.Length; i++ ) {
					uint	neuronID = m_neuron2ID[m_queryNodes[i]];
					m_SB_SourceIndices.m[i] = neuronID;
				}
				m_SB_SourceIndices.Write();

				// Reset simulation
				buttonReset_Click( null, EventArgs.Empty );

				// Update UI
				if ( m_queryNodes.Length > 1 ) {
					integerTrackbarControlShowQuerySourceIndex.Enabled = true;
					integerTrackbarControlShowQuerySourceIndex.RangeMax = m_queryNodes.Length - 1;
					integerTrackbarControlShowQuerySourceIndex.VisibleRangeMax = m_queryNodes.Length - 1;
					integerTrackbarControlShowQuerySourceIndex.Value = Math.Min( integerTrackbarControlShowQuerySourceIndex.RangeMax-1, integerTrackbarControlShowQuerySourceIndex.Value );
				} else {
					integerTrackbarControlShowQuerySourceIndex.Enabled = false;
					integerTrackbarControlShowQuerySourceIndex.Value = 0;
					integerTrackbarControlShowQuerySourceIndex.RangeMax = 1;
					integerTrackbarControlShowQuerySourceIndex.VisibleRangeMax = 1;
				}
			}
		}

		private void textBoxSearch_TextChanged( object sender, EventArgs e ) {
			try {
				string[]	queries = textBoxSearch.Text.Split( '\n' );

				if ( queries.Length > 0 ) {
					string	message = "";

					List<ProtoParser.Neuron>	queryNodes = new List<ProtoParser.Neuron>();
					foreach ( string query in queries ) {
						try {
							ProtoParser.Neuron	N = ProcessQuery( query );
							if ( N == null )
								continue;

							queryNodes.Add( N );

							message += "OK: " + N + "\r\n";
						} catch ( Exception _e ) {
							message += "Error on \"" + query + "\": " + _e.Message + "\r\n";
						}
					}

					QueryNodes = queryNodes.ToArray();

					message += "Total queries: " + queryNodes.Count + "\r\n";

					textBoxProcessedQuery.Text = message;

				} else {
					textBoxProcessedQuery.Text = "No query source.";
				}

			} catch ( Exception _e ) {
				QueryNodes = null;
				textBoxProcessedQuery.Text = "Error during search: " + _e.Message;
			}
		}

		ProtoParser.Neuron[]	m_selection = new ProtoParser.Neuron[0];
		ProtoParser.Neuron[]	Selection {
			get { return m_selection; }
			set {
				if ( value == null )
					value = new ProtoParser.Neuron[0];

				m_selection = value;

				// Update selected flags
				for ( int nodeIndex=0; nodeIndex < (int) m_nodesCount; nodeIndex++ )
					m_SB_Nodes.m[nodeIndex].m_flags = 0x0U;

				for ( int i=0; i < m_nodesCount; i++ )
					m_SB_Nodes.m[i].m_flags = 0U;

				foreach ( ProtoParser.Neuron selectedNeuron in m_selection ) {
					// Select neuron
					m_SB_Nodes.m[m_neuron2ID[selectedNeuron]].m_flags |= 1U;

					// Select parents
					ProtoParser.Neuron parent = selectedNeuron;
					while ( parent.ParentsCount > 0 ) {
						parent = parent.Parents[0];
						m_SB_Nodes.m[m_neuron2ID[parent]].m_flags |= 2U;
					}
				}

				m_SB_Nodes.Write();
			}
		}

		private void textBoxSelection_TextChanged( object sender, EventArgs e ) {
			try {
				string[]	queries = textBoxSelection.Text.Split( '\n', ',', ' ', ';' );

				if ( queries.Length > 0 ) {
					string	message = "";

					List<ProtoParser.Neuron>	selectedNodes = new List<ProtoParser.Neuron>();
					for ( int i=0; i < queries.Length; i++ ) {
						string	query = queries[i].Trim();
						if ( query.StartsWith( "\"" ) ) {
//							query = query.Remove( 0, 1 );	// Remove "
							while ( !query.EndsWith( "\"" ) && i < queries.Length-1 ) {
								query += " " + queries[++i];
								query = query.Trim();
							}
// 							if ( query.Length > 0 )
// 								query = query.Remove( query.Length-1, 1 );	// Remove last "
						}

						try {
							ProtoParser.Neuron	N = ProcessQuery( query );
							if ( N == null )
								continue;

							selectedNodes.Add( N );

							message += "OK: " + N + "\r\n";
						} catch ( Exception _e ) {
							message += "Error on \"" + query + "\": " + _e.Message + "\r\n";
						}
					}

					Selection = selectedNodes.ToArray();

					message += "Total selection: " + selectedNodes.Count + "\r\n";

					textBoxProcessedSelection.Text = message;

				} else {
					textBoxProcessedSelection.Text = "Empty.";
				}

			} catch ( Exception _e ) {
				Selection = null;
				textBoxProcessedSelection.Text = "Error during selection: " + _e.Message;
			}
		}

		ProtoParser.Neuron	ProcessQuery( string _query ) {
			_query = _query.Trim();

			ProtoParser.Neuron	single = m_graph.FindNeuron( _query );
			return single;
		}

		#endregion

		private void buttonSave_Click( object sender, EventArgs e ) {
// 			if ( saveFileDialog1.ShowDialog( this ) != DialogResult.OK )
// 				return;
//
// 			using ( FileStream S = new FileInfo( saveFileDialog1.FileName ).Create() )
// 				using ( BinaryWriter W = new BinaryWriter( S ) ) {
// 					// Write bounding box
// 					W.Write( m_CB_Main.m._cameraCenter.x - 0.5f * m_CB_Main.m._cameraSize.x );
// 					W.Write( m_CB_Main.m._cameraCenter.y - 0.5f * m_CB_Main.m._cameraSize.y );
// 					W.Write( m_CB_Main.m._cameraCenter.x + 0.5f * m_CB_Main.m._cameraSize.x );
// 					W.Write( m_CB_Main.m._cameraCenter.y + 0.5f * m_CB_Main.m._cameraSize.y );
//
// 					// Write nodes count
// 					W.Write( m_SB_NodeSims[0].m.Length );
//
// 					// Write node positions
// 					m_SB_NodeSims[0].Read();
//
// 					for ( int i=0; i < m_SB_NodeSims[0].m.Length; i++ ) {
// 						W.Write( m_SB_NodeSims[0].m[i].m_position.x );
// 						W.Write( m_SB_NodeSims[0].m[i].m_position.y );
// 					}
// 				}
		}

		#endregion
	}
}


CAG to submit report on Orissa NREGA by October

Bhubaneswar, September 16 ( Odisha.in ) Union minister for Rural Development Raghuvansh Prasad Singh Monday said that the allegation regarding irregularities of Rs 500 crore in different projects under the National Rural Employment Guarantee Scheme (NREGS) is being probed into by the Comptroller and Accountant General (CAG) and action would be taken after receiving the CAG’s report.

Singh revealed this in a press conference at the State secretariat on Monday evening. He said that though the matter has already been referred to the CAG for audit and the report was expected in August, the CAG expressed it’s inability to complete the audit within such a short period for which the time has been extended to October.

Singh was in Bhuabneswar to attend the two-day all India meeting to review the ongoing implementation of National Rural Employment Guarantee Scheme (NREGS) on Monday at the Secretariat.

A Delhi-based NGO has brought allegation against the Orissa Government and stated that most of the works under the NREGS were not satisfactory.

Union Minister of State for Rural Development Chandrasekhar Sahu and Secretary of Ministry of Rural Development Subas Pani attended the meeting. Secretaries of Rural Development and Panchayat Raj of 10 States also participated in the discussions.

Sing also said the NREGS scheme is being implemented in Orissa’s 24 of 30 districts. The rest six districts would be included during the next phase, he told media persons.


DigPro LED mini studio i-photo Light box Product Photography

DigPro Continuous LED Lighting mini studio i-photo box. We will try our best to solve any problem. 24 hours a Day, 7 Days a week. The item "DigPro LED mini studio i-photo Light box Product Photography" is in sale since Saturday, January 23, 2016. This item is in the category "Cameras & Photo\Lighting & Studio\Continuous Lighting\Lighting Kits". The seller is "apdigi" and is located in default. This item can be shipped worldwide.


Q:

Conway's Game of Life not counting neighbors correctly

I am doing the standard Conway's Game of Life program using Python. I am having an issue when trying to count neighbors as I iterate through the array. I created print statements that print the succession of the if statement, as well as the value of count for each statement.
Here is my code: ( I have the questions inside the # throughout the code)
import random

numrows = 10
numcols = 10
def rnd():
    rn = random.randint(0,1)
    return rn

def initial():
    grid = []
    count = 0
    for x in range(numrows):
        grid.append([])
        for y in range(numcols):
            rand=random.randrange(1,3)
            if(rand == 1):
                grid[x].append('O')
            else:
                grid[x].append('-')
    for x in grid:
        print(*x, sep=' ',end="\n") #this prints the random 2d array

    print("")
    print("")

    answer = 'y'
    newgrid = []
    count = 0

    while(answer == 'y'): # I believe I am going through, checking neighbors
                          # and moving onto the next index inside these for
                          #loops below
        for r in range(0,numrows):
            grid.append([])
            for c in range(0,numcols):

                if(r-1 > -1 and c-1 > -1): #I use this to check out of bound
                    if(newgrid[r-1][c-1] == 'O'):#if top left location is O
                        count = count + 1        #should get count += 1
                    else:
                        count = count
                print("top left check complete")
                print(count)
                if(r-1 > -1):
                    if(newgrid[r-1][c] == 'O'):
                        count = count + 1
                    else:
                        count = count
                print("top mid check complete")
                print(count)
                if(r-1 > -1 and c+1 < numcols):
                    if(newgrid[r-1][c+1] == 'O'):
                        count = count + 1
                    else:
                        count = count
                print("top right check complete")
                print(count)
                if(c-1 > -1 and r-1 > -1):
                    if(newgrid[r][c-1] == 'O'):
                        count = count + 1
                    else:
                        count = count
                print("mid left check complete")
                print(count)
                if(r-1 > -1 and c+1 < numcols):
                    if(newgrid[r][c+1] == 'O'):
                        count = count + 1
                    else:
                        count = count
                print("mid right check complete")
                print(count)
                if(r+1 < numrows and c-1 > -1):
                    if(newgrid[r+1][c-1] == 'O'):
                        count = count + 1
                    else:
                        count = count
                print("bot left check complete")
                print(count)
                if(r+1 < numrows and c-1 > -1):
                    if(newgrid[r+1][c] == 'O'):
                        count = count + 1
                    else:
                        count = count
                print("bot mid check complete")
                print(count)
                if(r+1 < numrows and c+1 < numcols):
                    if(newgrid[r+1][c+1] == 'O'):
                        count = count + 1
                    else:
                        count = count
                print("bot right check complete")
                print(count)

# I am not sure about the formatting of the code below, how do I know that
# the newgrid[r][c] location is changing? should it be according to the for-
# loop above? Or should it get it's own? If so, how could I construct it as
# to not interfere with the other loops and items of them?

            if(newgrid[r][c] == '-' and count == 3):
                newgrid[r][c] ='O'

            elif(newgrid[r][c] == 'O' and count < 2):
                newgrid[r][c] = '-'

            elif(newgrid[r][c] == 'O' and (count == 2 or count == 3)):
                newgrid[r][c] = 'O'

            elif(newgrid[r][c] == 'O' and count > 3):
                newgrid[r][c] = '-'

# I'm also confused how to go about printing out the 'new' grid after each
# element has been evaluated and changed. I do however know that after the
# new grid prints, that I need to assign it to the old grid, so that it can
# be the 'new' default grid. How do I do this?

        for z in newgrid:
            print(*z, sep=' ',end="\n")

        answer = input("Continue? y or n( lower case only): ")

        newgrid = grid

        if(answer != 'y'):
            print(" Hope you had a great life! Goodbye!")

initial()

Here is the current output and error message:

>>> initial()
 - O - - O - - O - -
 - O - - O - - - O O
 - O - - O - O O - O
 O - - O - - O O O O
 O - O O - - - O O -
 O - O - O - O - O -
 O - O O O O - - O -
 - - - - O O O - - O
 O O - O - - O - - -
 - - O O O - O - - -
top left check complete
0
top mid check complete
0
top right check complete
0
mid left check complete
0
mid right check complete
0
bot left check complete
0
bot mid check complete
0
Traceback (most recent call last):
 File "<pyshell#68>", line 1, in <module>
  initial()
 File "C:\Users\Ted\Desktop\combined.py", line 86, in initial
  if(newgrid[r+1][c+1] == 'O'):
 IndexError: list index out of range

As I iterate through the random array to see what the neighbors are, it seems to be fine up until it moves over to [0][1] while checking the bot right neighbor.
Also, the mid right neighbor should + 1 to count as it is alive. However, even with succession of the if statement, count remains 0?
Question 1: How can I possibly know that my if conditions witll suffice for every instance of [r][c] for all sides of the array?
Question 2: Is my current method of checking out of bounds the best for my situation? Is there a way to make a "check all for out of bounds" before I even check the value?
I am at my wit's end at this point. Thanks in advance for the time taken to help answer my questions

A:

You are getting that index error because your newgrid only contains a single empty row. And your testing for neighbours in newgrid instead of in grid (as Blckknght mentions in the comments). I've made a few repairs, but there's a lot more that can be done to improve this code. It looks like it's working now, but it's hard to tell when you're working with random Life forms. :) I suggest giving your program some way of using known Life patterns like blinkers and gliders to see that they behave correctly.
The simplest way to ensure that newgrid is valid is to copy it from grid. If we just do newgrid = grid that simply makes newgrid another name for the grid object. To copy a list of lists properly we need to make copies of each of the internal lists. My new code does that with the copy_grid function.
I've fixed a couple of minor bugs that you had in the if tests in the section that counts neighbours, and I've simplified the logic that updates a cell from its neighbour count. I've also condensed the code that makes a random grid, and I've added a simple function that can read a Life pattern from a string and build a grid from it. This lets us test the code with a Glider. I've also added a function that makes an empty grid. The program doesn't currently use that function although I used it during my tests, and I guess it's a useful example. :)
import random

# Set a seed so that we get the same random numbers each time we run the program
# This makes it easier to test the program during development
random.seed(42)

numrows = 10
numcols = 10

glider = '''\
----------
--O-------
---O------
-OOO------
----------
----------
----------
----------
----------
----------
'''

# Make an empty grid
def empty_grid():
    return [['-' for y in range(numcols)]
        for x in range(numrows)]

# Make a random grid
def random_grid():
    return [[random.choice('O-') for y in range(numcols)]
        for x in range(numrows)]

# Make a grid from a pattern string
def pattern_grid(pattern):
    return [list(row) for row in pattern.splitlines()]

# Copy a grid, properly!
def copy_grid(grid):
    return [row[:] for row in grid]

# Print a grid
def show_grid(grid):
    for row in grid:
        print(*row)
    print()

def run(grid):
    show_grid(grid)

    # Copy the grid to newgrid.
    newgrid = copy_grid(grid)
    while True:
        for r in range(numrows):
            for c in range(numcols):
                # Count the neighbours, making sure that they are in bounds
                count = 0
                # Above this row
                if(r-1 > -1 and c-1 > -1):
                    if(grid[r-1][c-1] == 'O'):
                        count += 1
                if(r-1 > -1):
                    if(grid[r-1][c] == 'O'):
                        count += 1
                if(r-1 > -1 and c+1 < numcols):
                    if(grid[r-1][c+1] == 'O'):
                        count += 1

                # On this row
                if(c-1 > -1):
                    if(grid[r][c-1] == 'O'):
                        count += 1
                if(c+1 < numcols):
                    if(grid[r][c+1] == 'O'):
                        count += 1

                # Below this row
                if(r+1 < numrows and c-1 > -1):
                    if(grid[r+1][c-1] == 'O'):
                        count += 1
                if(r+1 < numrows):
                    if(grid[r+1][c] == 'O'):
                        count += 1
                if(r+1 < numrows and c+1 < numcols):
                    if(grid[r+1][c+1] == 'O'):
                        count += 1

                # Update the cell in the new grid
                if grid[r][c] == '-':
                    if count == 3:
                        newgrid[r][c] ='O'
                else:
                    if count < 2 or count> 3:
                        newgrid[r][c] = '-'

        # Copy the newgrid to grid
        grid = copy_grid(newgrid)
        show_grid(grid)

        answer = input("Continue? [Y/n]: ")
        if not answer in 'yY':
            print(" Hope you had a great life! Goodbye!")
            break

#grid = random_grid()
grid = pattern_grid(glider)
run(grid)

This code does work correctly, but there is still plenty of room for improvement. For example, here's an improved version of run() that condenses the neighbour counting section by using a couple of loops.
def run(grid):
    show_grid(grid)

    # Copy the grid to newgrid.
    newgrid = copy_grid(grid)
    while True:
        for r in range(numrows):
            for c in range(numcols):
                # Count the neighbours, making sure that they are in bounds
                # This includes the cell itself in the count
                count = 0
                for y in range(max(0, r - 1), min(r + 2, numrows)):
                    for x in range(max(0, c - 1), min(c + 2, numcols)):
                        count += grid[y][x] == 'O'

                # Update the cell in the new grid
                if grid[r][c] == '-':
                    if count == 3:
                        newgrid[r][c] ='O'
                else:
                    # Remember, this count includes the cell itself
                    if count < 3 or count > 4:
                        newgrid[r][c] = '-'

        # Copy the newgrid to grid
        grid = copy_grid(newgrid)
        show_grid(grid)

        answer = input("Continue? [Y/n]: ")
        if not answer in 'yY':
            print(" Hope you had a great life! Goodbye!")
            break


Q:

angular2 subject not subscribing the change

I've two components and a shared service which is shared by the two components.
shared.service.ts
// ..... top level codes are skipped

private pickAnalysisForBubble = new Subject<any>();

  analysisForBubble$ = this.pickAnalysisForBubble.asObservable();

  mapToggleToPointOrBubble(value) {
    this.pickAnalysisForBubble.next(value);
  }

utility.component.ts
in view (utility.component.html), there are two radio button and one is pre-selected:
<input type="radio" name="rdbBubblePoint" class="rdbBubblePoint" value="Point" (change)="changeToPoint($event)"> Point

<input type="radio" name="rdbBubblePoint" class="rdbBubblePoint" value="Bubble" (change)="changeToPoint($event)" checked="checked"> Bubble

in component (utility.component.ts), there is a method to grab the click event: (I've imported the shared.service and added this as a provider.)
changeToPoint(event){
    # analysisInteraction is the shared service constructor
    this.analysisInteraction.mapToggleToPointOrBubble(event.target.value);
}

map.component.ts
I've imported the shared.service and added a constructor. Then in ngOnInit tried to subscribe the change, but this is not working.
# analysisInteraction is the shared service constructor
this.analysisInteraction.analysisForBubble$.subscribe(
        data => {
          this.DrawType = data;
          console.log("Drawtype fixed");
      });

I'm using subject to detect the change based on this tutorial. What I'm doing wrong?

A:

I guess that you don't share the same instance of the service. Do you specify the corresponding provider when bootstrapping your application or within the main component:
bootstrap(AppComponent, [ SharedService ]);

or
@Component({
  (...)
  providers: [ SharedService ]
})
export class AppComponent {
  (...)
}

If you specify it within providers attributes of sub-components, you aren't sure to share the same instance...
Edit
Because of hierarchical injectors, each component will have its own instance and not share the same one. Thus, the shared service should be added as a provider in main Component. Also, thee shared service should not be included in the provider of sub-components.


The Obama administration faced a backlash from congressional Democrats on Friday following revelations that the National Security Agency broke privacy rules and overstepped its authority thousands of times since 2008.

The details were reported late Thursday in The Washington Post, based on an audit and other secret documents provided by NSA leaker Edward Snowden. The report challenged claims by President Obama just last week that the NSA was not abusing its authority, and complicated his effort to reassure Americans and Congress that -- with a little more oversight and transparency -- the surveillance programs are nothing to be worried about.

House Democratic Leader Nancy Pelosi called the latest reports "extremely disturbing."

Rep. Mike Thompson, D-Calif., a member of the House Intelligence Committee, said: "Reports that the NSA repeatedly overstepped its legal boundaries, broke privacy regulations and attempted to shield required disclosure of violations are outrageous, inappropriate and must be addressed."

Senior lawmakers said they had been unaware of the audit until they read the news on Friday.

More On This...

Senate Judiciary Committee Chairman Patrick Leahy, D-Vt., said he planned to hold another hearing in the wake of the report.

"The American people rely on the intelligence community to provide forthright and complete information so that Congress and the courts can properly conduct oversight. I remain concerned that we are still not getting straightforward answers from the NSA," Leahy said in a statement. "I plan to hold another hearing on these matters in the Judiciary Committee and will continue to demand honest and forthright answers from the intelligence community."

Obama has repeatedly said that Congress was thoroughly briefed on the programs revealed by Snowden in June. The two that were described vacuum up vast amounts of metadata -- such as telephone numbers called and called from, the time and duration of calls -- from most Americans' phone records, and scoop up global Internet usage data.

Proposed legislation to dismantle the programs was narrowly defeated last month in the House, and at least 19 other pending bills are aimed at restraining NSA's powers or changing how the agency is regulated, according to a count kept by the ACLU. The July legislative effort brought together Libertarian-leaning conservatives and liberal Democrats who pressed for change against congressional leaders and lawmakers focused on security.

A week ago, Obama sought to soothe concerns by promising to consider reforms to NSA surveillance.

"It's not enough for me to have confidence in these programs," he said at a White House news conference. "The American people have to have confidence in them as well."

He announced changes such as convening an outside advisory panel to review U.S. surveillance powers, although it is unclear how that would differ from the existing U.S. Privacy and Civil Liberties Oversight Board, mandated by Congress to monitor surveillance and constitutional concerns.

Obama also said the NSA would hire a privacy officer -- though the NSA already has a compliance office. None of those measures would seem likely to stop the kind of inadvertent collection of information that was described in the NSA audit.

Most of the infractions revealed late Thursday involve unauthorized surveillance of Americans or foreign intelligence targets in the United States, both of which are restricted by law and executive order, according to the May 3, 2012 audit, and other top-secret documents.

The May audit counted 2,776 incidents in the preceding 12 months of unauthorized collection, storage, access to or distribution of legally protected communications. Most were reported to be unintended, and many involved failures to take sufficient care or violations of standard operating procedure. They ranged from significant violations of law to typographical errors that resulted in unintended interceptions of U.S. emails and telephone calls.

The most serious incidents included a violation of a court order and unauthorized use of data about more than 3,000 Americans and green-card holders.

Sen. Dianne Feinstein, D-Calif., chairwoman of the Senate Intelligence Committee, backed up the administration on its claims, releasing a lengthy statement on Friday afternoon claiming that most the compliance problems at the NSA happen when the agency inadvertently collects records on a non-American who enters the U.S., a point when the NSA is supposed to follow different procedures.

"The majority of these 'compliance incidents' are, therefore, unintentional and do not involve any inappropriate surveillance of Americans," she said. "As I have said previously, the committee has never identified an instance in which the NSA has intentionally abused its authority to conduct surveillance for inappropriate purposes."

Late Friday, the White House issued a statement saying, "the majority of the compliance incidents are unintentional. The documents demonstrate that the NSA is monitoring, detecting, addressing and reporting compliance incidents."

It directed questions to the National Security Council, and NSC spokeswoman Caitlin Hayden directed questions to the NSA.

NSA spokeswoman Vanee Vines said the number of incidents in the first quarter of 2012 was higher than normal, and that the number has ranged from 372 to 1,162 in the past three years, due to factors such as "implementation of new procedures or guidance with respect to our authorities that prompt a spike that requires `fine tuning,' changes to the technology or software in the targeted environment for which we had no prior knowledge, unforeseen shortcomings in our systems, new or expanded access, and `roaming' by foreign targets into the U.S., some of which NSA cannot anticipate in advance but each instance of which is reported as an incident."

"When NSA makes a mistake in carrying out its foreign intelligence mission, the agency reports the issue internally and to federal overseers -- and aggressively gets to the bottom of it," Vines said.

The Associated Press contributed to this report.


Not Activists or Victims, Terrorists!

“I know it when I see it” was the famous response by a U.S. Supreme Court justice to the vexed problem of defining pornography. Terrorism may be no less difficult to define, but the wanton killing of schoolchildren, of mourners at a funeral, or workers at their desks in skyscrapers surely fits the know-it-when-I-see-it definition.

The media, however, generally shies away from the word terrorist, preferring euphemisms. Take the assault that led to the deaths of some 400 people, many of them children, in Beslan, Russia, on September 3. Journalists have been deep into their thesauruses, finding at least twenty euphemisms for terrorists:

• Assailants  National Public Radio.

• Attackers  the Economist.

• Bombers  the Guardian

• Captors  the Associated Press.

• Commandos  Agence France-Presse refers to the terrorists both as “membres du commando” and “commando.”

• Criminals  the Times (London).

• Extremists  United Press International.

• Fighters  the Washington Post.

• Group  the Australian.

• Guerrillas: in a New York Post editorial.

• Gunmen  Reuters.

• Hostage-takers  the Los Angeles Times.

• Insurgents  in a New York Times headline.

• Kidnappers  the Observer (London).

• Militants  the Chicago Tribune.

• Perpetrators  the New York Times.

• Radicals  the BBC.

• Rebels  in a Sydney Morning Herald headline.

• Separatists  the Daily Telegraph.

And my favorite:

• Activists  the Pakistan Times.

The origins of this unwillingness to name terrorists seems to lie in the Arab-Israeli conflict, prompted by an odd combination of media sympathy for the Palestinians and intimidation by them. The sympathy is well known; the intimidation less so. Reuters's Nidal al-Mughrabi made the latter explicit in advice for fellow reporters in Gaza to avoid trouble, where one tip reads: “Never use the word terrorist or terrorism in describing Palestinian gunmen and militants; people consider them heroes of the conflict.”

The reluctance to call terrorists by their rightful name can reach absurd lengths of inaccuracy and apologetics. For example, National Public Radio's Morning Edition announced on April 1, 2004, that “Israeli troops have arrested 12 men they say were wanted militants.” But CAMERA, the Committee for Accuracy in Middle East Reporting in America, pointed out the inaccuracy here and NPR issued an on-air correction on April 26: “Israeli military officials were quoted as saying they had arrested 12 men who were 'wanted militants.' But the actual phrase used by the Israeli military was 'wanted terrorists.'”

(At least NPR corrected itself. When the Los Angeles Times made the same error in its April 24 issue, writing that “Israel staged a series of raids in the West Bank that the army described as hunts for wanted Palestinian militants,” its editors refused CAMERA's request for a correction on the grounds that its change in terminology did not occur in a direct quotation.)

Metro, a Dutch paper, ran a picture on May 3, 2004, of two gloved hands belonging to a person taking fingerprints off a dead terrorist. The caption read: “An Israeli police officer takes fingerprints of a dead Palestinian. He is one of the victims (slachtoffers) who fell in the Gaza strip yesterday.” One of the victims!

Euphemistic usage then spread from the Arab-Israeli conflict to other theaters. As terrorism picked up in Saudi Arabia such media as The Times (London) and the Associated Press began routinely using “militants” in reference to Saudi terrorists. Reuters uses it with reference to Kashmir and Algeria.

Thus has “militants” become the media's default term for terrorists.

These self-imposed language limitations sometimes cause journalists to tie themselves into knots. In reporting the murder of one of its own cameraman, the BBC  which normally avoids the word terrorist  found itself using that term. In another instance, the search engine on the BBC website includes the word terrorist, but the page linked to has had that word expurgated.

Politically-correct news organizations undermine their credibility with such subterfuges. How can one trust what one reads, hears, or sees when the self-evident fact of terrorism is being semi-denied?

Worse, the multiple euphemisms for terrorist obstruct a clear understanding of the violent threats confronting the civilized world. It is bad enough that only one of five articles discussing the Beslan atrocity mentions its Islamist origins; worse is the miasma of words that insulates the public from the evil of terrorism.

Daniel Pipes is director of the Middle East Forum and the author of several books, most recently Militant Islam Reaches America. You may visit his website by clicking here and purchase his books by clicking here.

Daniel Pipes is director of the Middle East Forum and the author of several books, including Militant Islam Reaches America and In the Path of God: Islam and Political Power (Transaction Publishers), from which this column derives.

Connect

Most Popular

CE Shop

This page is having a slideshow that uses Javascript. Your browser either doesn't support Javascript or you have it turned off. To see this page as it is meant to appear please use a Javascript enabled browser.


W. B. Young

William Brewitt Young (7 May 1916 - 25 April 2013)   was born in Ardrossan  and was a Scottish and East African rugby football player.

He was capped ten times for  between 1937–48 and three times for East Africa between 1949-50.  Along with Maurice Daly of  he is one of only two people to have been capped by a major rugby playing nation and by East Africa.

Along with W.C.W. Murdoch, he was one of only two Scottish players to be capped on either side of World War II, giving him one of the longest international careers on record.  John "Jack" Heaton and Thomas Arthur "Tommy" Kemp also achieved this feat for .

Personal life
Young was the son of Alexander Robert Young (born c1885 Govan, Lanarkshire Scotland) and Christina Leiper (born c1883 Lanark, Lanarkshire). He attended City of London School and studied medicine at St Catharine's College, Cambridge.  and became a doctor after he finished playing rugby.

References
 Bath, Richard (ed.) The Scotland Rugby Miscellany (Vision Sports Publishing Ltd, 2007 )
 Jones, J.R. Encyclopedia of Rugby Union Football (Robert Hale, London, 1976 )
 Massie, Allan A Portrait of Scottish Rugby (Polygon, Edinburgh; )

Category:1916 births
Category:2013 deaths
Category:Alumni of St Catharine's College, Cambridge
Category:Scottish rugby union players
Category:Scotland international rugby union players
Category:People educated at the City of London School
Category:People from Ardrossan


175 Mich. App. 269 (1989)
437 N.W.2d 367
MONUSKO
v.
POSTLE
Docket Nos. 95314, 95355.
Michigan Court of Appeals.
Decided February 23, 1989.
Levine, Benjamin, Tushman, Bratt, Jerris & Stein, P.C. (by Alvin L. Levine and Bruce L. Jerris), for plaintiffs.
Kohl, Secrest, Wardle, Lynch, Clark & Hampton (by Michael L. Updike), for defendants, appellants, and third-party plaintiffs Postle, Keith, Kutcipal, *271 Verburg, Kinne, and Burns Clinic Medical Center, P.C.
Menmuir, Zimmerman, Rollert & Kuhn (by R. Jay Hardin, Esq.), for Northern Michigan Hospitals, Inc.
Before: MacKENZIE, P.J., and SHEPHERD and M.E. DODGE,[*] JJ.
SHEPHERD, J.
These consolidated appeals come to us on denial of the defendants' motion for summary disposition as to Count I of plaintiffs' complaint. Count I seeks damages for plaintiff Andrea Monusko for a preconception tort. The issue is one of first impression in this jurisdiction. We affirm the decision of the trial court and conclude that such a cause of action exists on the facts of this case.
Andrea Monusko was born on February 10, 1980, in a severely impaired physical and mental condition, suffering from rubella syndrome. A complaint was filed on her behalf in 1985. The complaint sets forth three theories for recovery. We are here concerned with Count I, alleging what might best be termed a preconception tort. In passing, we note that a 1982 suit resulted in a settlement of the parents' claim for all past, present, and future medical and custodial expenses throughout Andrea's lifetime. The instant suit seeks recovery for plaintiff Andrea Monusko's pain and suffering, mental anguish, and emotional trauma.
Jill Rose Monusko began prenatal care and treatment at Burns Clinic on November 22, 1977, prior to the birth of her second child, Loretta Monusko. The individual defendant doctors provide *272 OB/GYN treatment at Burns Clinic. Mrs. Monusko received prenatal care through February of 1978. She was not tested for her rubella status at any of her visits.
On March 2, 1978, she was admitted to Northern Michigan Hospital, where Loretta was delivered by at least one of the Burns Clinic defendants. Mrs. Monusko was neither tested nor immunized during her stay in the hospital. She was neither tested nor immunized during her Burns Clinic visit. On March 22, 1979, Mrs. Monusko returned to the Burns Clinic to have her IUD removed. She indicated to the attending doctor that she wished to have a third child. She was neither tested nor immunized for rubella at that visit.
Mrs. Monusko subsequently became pregnant with Andrea, suffered from rubella, and Andrea suffered the resulting difficulties. Rubella (a form of measles) is a disease which, if contracted by a pregnant woman, can result in damage to her child.
Plaintiffs put forward the recommendation made by the American College of Obstetricians and Gynecologists which states that a rubella test should be given to the pregnant patient if her status is unknown. They further rely on the ACOG standard which states that the first postpartum examination is "an optimal time for review of family planning and for determining immunizations, including rubella." In essence, the complaint alleges a negligent failure to render appropriate prenatal care to Mrs. Monusko preceding the birth of her second child, Loretta, including failure to conduct appropriate lab examinations, including a rubella test, and failure to render appropriate postpartum intraconceptional and gynecological care to Mrs. Monusko following the birth of her second child, *273 including failing to perform tests to determine Mrs. Monusko's rubella immunity status and in failing to immunize her against rubella, all in contravention of the ACOG standards.
The hearing on the motion for summary disposition was held on June 19, 1986. The thrust of defendants' argument was that they owed no duty to a plaintiff not yet conceived. Defendants' motion was denied and they now appeal.
In reviewing a grant of summary disposition under MCR 2.116(C)(8), for failure to state a claim upon which relief can be granted, this Court is obligated to accept as true all well-pled facts and to determine whether the plaintiff's claim, on the pleadings, is so clearly unenforceable as a matter of law that no factual development can possibly justify a right to recovery. Abel v Eli Lilly & Co, 418 Mich 311, 323-324; 343 NW2d 164 (1984), cert den sub nom E R Squibb & Sons v Abel, 469 US 833; 105 S Ct 123; 83 L Ed 2d 65 (1984). A motion for summary disposition under MCR 2.116(C)(8) tests the genuineness of the claim by challenging the legal adequacy of the pleadings. Id.
The trial court, in its written opinion, stated the issue succinctly: "In general terms, the issue is whether or not a child, when born alive, has a cause of action for injury arising out of preconception negligent conduct." The issue has otherwise been stated: "Whether there was a duty under these circumstances to a plaintiff who was not in being at the time of a wrongful act." Renslow v Mennonite Hospital, 67 Ill 2d 348, 367; 367 NE2d 1250 (1977) (Dooley, J., concurring).
In the instant case we are confronted with the issue of duty. "Duty is essentially a question of whether the relationship between the actor and the injured person gives rise to any legal obligation on the actor's part for the benefit of the *274 injured person." Moning v Alfono, 400 Mich 425, 438-439; 254 NW2d 759 (1977). The question of duty depends in part on "forseeability  whether it is forseeable that the actor's conduct may create a risk of harm to the victim, and whether the result of that conduct and intervening causes were foreseeable." 400 Mich at 439.
Other jurisdictions have concluded that a doctor or hospital can have a duty to a not-yet-conceived plaintiff. In Renslow v Mennonite Hospital, supra, the plaintiff's mother was given a negligently administered blood transfusion some eight years prior to the plaintiff's birth. The plaintiff was born with brain and physical injuries caused by the transfusion of RH positive blood into the RH negative mother eight years prior. The Illinois Supreme Court concluded:
The cases allowing relief to an infant for injuries incurred in its previable state make it clear that a defendant may be held liable to a person whose existence was not apparent at the time of his act. We therefore find it illogical to bar relief for an act done prior to conception where the defendant would be liable for this same conduct had the child, unbeknownst to him, been conceived prior to his act. We believe that there is a right to be born free from prenatal injuries foreseeably caused by a breach of duty to the child's mother.
The extension of duty in such a case is further supported by sound policy considerations. Medical science has developed various techniques which can mitigate or, in some cases, totally alleviate a child's prenatal harm. In light of these substantial medical advances it seems to us that sound social policy requires the extension of duty in this case. [Renslow at 357-358.]
In Bergstresser v Mitchell, 577 F2d 22 (CA 8, 1978), the court held that under Missouri law a *275 child stated a cause of action against two doctors in a hospital for injuries allegedly sustained as the result of a negligently performed Caesarean section upon the child's mother several years prior to the child's birth. See also Jorgensen v Meade Johnson Laboratories, Inc, 483 F2d 237 (CA 10, 1973) (product liability case vacating district court dismissal and reinstating suit on behalf of children allegedly injured as the result of mother's birth control pill usage).
Defendants rely heavily on a New York case prohibiting recovery for an alleged preconception tort. In that case the plaintiff was born with brain damage allegedly the result of a perforated uterus the plaintiff's mother received during an abortion several years prior to the plaintiff's birth. Albala v City of New York, 54 NY2d 269; 429 NE2d 786 (1981). The court rejected the plaintiff's claim, principally on the basis of policy. Concluding that "foreseeability alone is not the hallmark of legal duty," the court ruled that it would require an extension of traditional tort concepts beyond manageable bounds to allow the plaintiff to go forward.
We cannot agree with that reasoning in the instant case. Here, plaintiffs have alleged that the failure of defendants to test Jill Rose Monusko for her rubella status and to immunize her against rubella prior to conception resulted in Andrea's injuries. The tests and immunization, relatively simple and straight-forward to administer, are designed specifically to alleviate the sort of injuries we have in this case. It is readily foreseeable that someone not immunized may catch rubella and, if pregnant, bear a child suffering from rubella syndrome. We conclude that plaintiffs have stated a cause of action in alleging that defendants' failure to administer the test and immunization specifically designed to prevent rubella *276 syndrome resulted in Andrea's being born with rubella syndrome. We hold that defendants owed a duty to Andrea, even though she was not conceived at the time of the alleged wrongful act.
Defendants make one further argument on the basis of a recent Supreme Court case. See Sizemore v Smock, 430 Mich 283; 422 NW2d 666 (1988). Defendants argue that any decision which would have the effect of expanding the class of potential plaintiffs should be left to the Legislature. In that case the Supreme Court stated that the common law of Michigan did not recognize an action by a parent for the loss of a child's society and companionship as a result of the negligent injury of the child. The Court concluded that any decision to extend claims for loss of consortium to include a negligent tortfeasor's liability for loss by a parent of a child's society and companionship should be determined by the Legislature. The Court stated: "Foreseeability of injury alone does not mandate recognition of a cause of action. Social policy must intervene at some point to limit the extent of one's liability." Sizemore at 293. The rationale behind the Court's decision to limit consortium liability rested in part on the "social consequences and economic burdens resulting to the public." Sizemore at 295.
We do not believe such reasoning controls the instant, limited facts. This case involves a plaintiff who, while not specifically contemplated, would have been the beneficiary of a test and immunization procedure specifically designed to alleviate the harm which resulted in this case. We note that when the Supreme Court concluded that it was necessary to recognize a common law negligence action for prenatal tortious conduct the Court sought guidance in the rulings of other jurisdictions, not from the Legislature. See Womack v *277 Buchhorn, 384 Mich 718; 187 NW2d 218 (1971). We believe our present holding, limited to the facts of this case, constitutes a recognition of a modest extension of the duty we ascribe to a physician against prenatal tortious conduct. We emphasize the direct connection between the test and immunization procedure and the harm in this case, and the fact that the test and the preconception immunization are specifically designed to prevent rubella syndrome in children that are not yet conceived. It is this central fact that distinguishes this case from Malik v William Beaumont Hospital, 168 Mich App 159; 423 NW2d 920 (1988), lv den 431 Mich 875 (1988), where it was held there is no duty to a third party who was not a patient at the time of the alleged medical malpractice. In Malik the treatment of the patient was not ordered for the benefit of her siblings and father who were the plaintiffs.
Affirmed.
M.E. DODGE, J., concurred.
MacKENZIE, P.J. (dissenting).
The question presented in this case is whether medical malpractice allegedly committed against the mother of a child not yet conceived gives rise to a negligence cause of action in favor of the child if, after conception, the malpractice committed against the mother causes injury to the child during gestation. More specifically, the issue is whether an obstetrician/gynecologist owes a duty to a yet-to-be-conceived child not to breach the duty of care he owes to the unconceived child's mother. I would answer in the negative.
"Duty" comprehends whether a defendant is under any obligation to the plaintiff to avoid negligent conduct. Moning v Alfono, 400 Mich 425, 437; *278 254 NW2d 759 (1977). It is essentially a question whether the relationship between the actor and the injured person is such that there arises a legal obligation on the actor's part for the benefit of the injured person. Moning, supra, pp 438-439. The question whether there is the requisite relationship giving rise to a duty depends in part on foreseeability  whether it is foreseeable that the actor's conduct may create a risk of harm to the victim. Moning, supra, p 439.
In this case, defendants' alleged wrongful conduct took place when they were treating the mother prior to the child's conception. Clearly, defendants owed a duty to the mother to treat her in accordance with professional standards. However, when defendants' alleged wrongful conduct took place, there was no relationship between defendants and the child upon which to predicate a duty owed to the child for the simple reason that the child did not exist. The majority appears to maintain that the child's conception was foreseeable and that this foreseeability gives rise to defendants' duty to the child. That reasoning is flawed. Under Moning, the question is whether it is foreseeable that the defendant's conduct may create a risk of harm to the plaintiff, not whether it is foreseeable that the plaintiff will exist. Under the majority's logic, all persons would be deemed to foresee, and thus owe a duty to, the future children of all other persons.
By not vaccinating the mother for rubella, the foreseeable risk of harm in this case was that the mother would contract the illness. The "victim" of defendants' conduct was the mother, not the yet-to-be-conceived child. Of course, it was possible that the mother would be pregnant when that risk turned into reality  pregnancy is almost always a possibility in a woman of childbearing years. That *279 possibility is not enough to create a legal duty in defendants to the gestating child, however. It was equally possible that the mother would contract rubella while not pregnant. The creation of a legal duty does not rise or fall on the serendipities of when the risk of harm materializes, but on the existence of a relationship between the actor and the plaintiff. Again, there was no such relationship in this case.
The majority's holding, that one may owe a duty to unconceived children, exposes to liability not only the medical profession but also parents-to-be and the general public for their conduct prior to a plaintiff's conception. Suppose, for example, that a thirteen-year-old boy becomes involved in drug abuse and ten years after stopping use of drugs fathers an infant with birth defects resulting from the earlier drug use. Under the majority's holding and Plumley v Klein, 388 Mich 1; 199 NW2d 169 (1972), abrogating parental immunity, the child might well be able to maintain an action against the father for injuries sustained as a result of the father's drug abuse ten years before conception. Or suppose that a thirteen-year-old girl is struck while crossing a street by a negligently driven automobile, sustaining fractures to her pelvis. At age thirty-three, she gives birth to an infant who sustains prenatal injuries from a malformation in the mother's pelvis caused by improper healing of the fractures. Under the majority's holding, it would be possible for the injured infant to maintain an action against the person who drove the automobile twenty years earlier. See Preconception tort  The need for a limitation, 44 Mo L R 143 (1979).
The majority's holding also creates the potential for exposure to liability well beyond the twenty-year period of the previous hypothetical. Suppose, *280 for example, that a hospital staff physician negligently administers medication to a four-year-old girl and the drug alters the girl's chromosome structure. At age thirty-five she gives birth to a daughter whose chromosome structure is damaged by the alteration in the mother's chromosomes, but the damage is undetected because no outward deformity appears. At age thirty-two, the daughter gives birth to a child suffering from a deformity resulting from the damage to the chromosome structures of the mother and grandmother. Under the majority holding, the deformed infant could quite possibly maintain an action against the hospital which two generations earlier provided the drug to the infant's grandmother. With the tolling of the statute of limitations for infancy, this cause of action would be maintainable eighty-one years after the offending drug was administered. See Preconception Tort, supra.
Yet another difficulty with the majority's holding is that it inherently creates for a woman's doctor a conflict of interest as between his patient and the patient's yet-to-be-conceived children. This conflict of interest problem was well-articulated by the majority in Albala v City of New York, 54 NY2d 269; 429 NE2d 786 (1981):
[I]t is worth noting that the recognition of a cause of action under the circumstances of this case would have the undesirable impact of encouraging the practice of "defensive medicine". A physician faced with the alternative of saving a patient's life by administering a treatment involving the possibility of adverse consequences to later conceived offspring of that patient would, if exposed to liability of the magnitude considered in this case, undoubtedly be inclined to advise against the treatment rather than risk the possibility of having to recompense a child born with a *281 handicap. Accordingly, society as a whole would bear the cost of our placing physicians in a direct conflict between their moral duty to patients and the proposed legal duty to those hypothetical future generations outside the immediate zone of danger. [54 NY2d 274.]
Finally, and perhaps more fundamentally, it appears to me that the cause of action plaintiffs are asserting is not a negligence claim, but one of medical malpractice. This Court has defined medical malpractice as
the failure of a member of the medical profession, employed to treat a case professionally, to fulfill the duty to exercise that degree of skill, care and diligence exercised by members of the same profession, practicing in the same or similar locality, in light of the present state of medical science. [Sexton v Petz, 170 Mich App 561, 565-566; 428 NW2d 715 (1988), quoting Adkins v Annapolis Hospital, 116 Mich App 558, 564; 323 NW2d 482 (1982), and Cotton v Kambly, 101 Mich App 537, 540-541; 300 NW2d 627 (1980), lv den 411 Mich 1033 (1981).]
Plaintiffs' reliance on the recommendations of the American College of Obstetricians and Gynecologists as an indicator of defendants' misfeasance strongly suggests a malpractice claim. Plaintiffs are alleging no more than that defendants failed to properly discharge their professional duties, which resulted in Andrea Monusko's injuries. See Sexton, supra. In medical malpractice cases, however, the physician's duty to render services within the applicable standard of care arises from the patient-physician relationship; the term "malpractice" denotes a breach of the duty owed by one rendering professional services to a person who has contracted for such services. See Malik v William Beaumont Hospital, 168 Mich *282 App 159, 168; 423 NW2d 920 (1988), citing Rogers v Horvath, 65 Mich App 644, 646-647; 237 NW2d 595 (1975), lv den 396 Mich 845 (1976). Here, a patient-physician relationship existed between the mother and defendants. The yet-to-be-conceived child in no sense contracted for defendants' rendition of preconception services to her future mother. Because the child seeks to recover for the injuries inflicted upon her which resulted from the alleged malpractice committed upon her mother when defendants failed to meet the professional standards of the American College of Obstetricians and Gynecologists, she has failed to state a cause of action. Compare Malik, supra.
The cause of action recognized by the majority requires the extension of traditional tort concepts beyond reasonable bounds. Defendants owed no duty to Andrea Monusko on these facts. Accordingly, I would reverse.
NOTES
[*]  Circuit judge, sitting on the Court of Appeals by assignment.