Toolbar is an ItemsControl and does not have click event handler to indicate which button is clicked. Here Hit Testing is used to figure that out: Note that we need to use Preview to Tunneling Event Handler void tbr_PreviewMouseDown(object sender, MouseButtonEventArgs e) { ToolBar tbr = sender as ToolBar; Point pt=e.GetPosition(tbr); object btnClicked=null; UIElement element = tbr.InputHitTest(pt) as UIElement; while (element != null) { if (element == tbr) return; btnClicked = tbr.ItemContainerGenerator.ItemFromContainer(element); if (!btnClicked.Equals(DependencyProperty.UnsetValue)) break; element = (UIElement)VisualTreeHelper.GetParent(element); } if (btnClicked != null) Console.WriteLine((btnClicked as Button).Content); else Console.WriteLine("no item found"); }
Blog Archive
-
▼
2012
(34)
-
►
July
(9)
- Parallel.For vs. Synchronization using ManualReset...
- Implement Asyn WCF using Task in .Net 4.0
- High Performance WPF/WCF
- WPF Prism MVVM using Unity and Mef
- Trading Signals from EMA and RSI
- Interesting javascript code
- State Machine Desing Pattern
- IoC inject data into DropDownListFor
- Using AutoFac IocContainer to inject Log4Net into ...
-
►
July
(9)
Sunday, September 9, 2012
Hit Test Toolbar to find button
Saturday, August 25, 2012
WCF Duplex Client as Observer
Setup Rx observer over the wire requires WCF Duplex callback: (1) ServiceContract need to define IObserverCallback, instead of subscrbe method lamda. (2) Subscribe and unsubscrib() should be one-way to avoid potential blocking (3) If Session is required then Subscribe/Unsubscrib need to be initiating/terminating (4) Note that IO.Subcribe is non-blocking (v.s. deprecated ForEach) and its only purpose is to set up OnNext on Service side which call Client Side OnNext. (5) Service Instancing Context must be PerSession or Single. PerCall cannot do Unsubscribe since state variable bool stopIO is not maintained. On the other hand, Single => Unsubscribe will stop all Sessions. (6) Threading Issues: WCF service as Single-Thread by default,So reentry will cause deadlock and therefore disallowed ( e.g calling Callback during Service Operation). So mark Service Behavior ConcurrencyMode Reentrant/Mutiple (7) netTcp Binding is Duplex (its name did not say Dual) (8) Update Svc Reference on Client will trigger WCF host for WCF Lib project to run for debugging/testing. (9) Client side Auto Gen Service Reference will force Service Constructor taking in InstanceContext, which in term require Callback contract implemntation. Service Side uses OperationContext.Current.GetCallbackChannel<IObservserCallback>(); (10) Note that Callback contract name on client is IService1Callback <> IObservserCallback service side Callback Contract Name. (11) CPU <10% when run test with 1ms data push, no network travel. (12) To signal Complete on an IO, use TakeWhile and check a non-blocking State Variable like stopIO=true. Contract and Service Definition [ServiceContract(CallbackContract = typeof(IObservserCallback),SessionMode= SessionMode.Required)] public interface IService1 { [OperationContract(IsOneWay=true, IsInitiating=true)] void Subscribe(); [OperationContract(IsOneWay = true,IsTerminating=true)] void Unsubscribe(); } public interface IObservserCallback { [OperationContract] void OnNext(CompositeType data); } [DataContract] public class CompositeType { double _value = 30.45; string _Name = "Name1"; [DataMember] public double Value { get { return _value; } set { _value = value; } } [DataMember] public string Name { get { return _Name; } set { _Name = value; } } } Service // [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,ConcurrencyMode=ConcurrencyMode.Reentrant)] public class Service1 : IService1 { bool stopIO; //Session State public void Subscribe() { stopIO = false; IObservserCallback client = OperationContext.Current.GetCallbackChannel<IObservserCallback>(); var IO = Observable.Interval(TimeSpan.FromMilliseconds(1)).TakeWhile(x => { return !stopIO; }); IO.Subscribe(x => // This is non-blocking { if(client!=null) client.OnNext(new CompositeType() { Name ="Name"+ x.ToString(), Value=(new Random()).NextDouble()*30 }); }); } public void Unsubscribe() { stopIO = true; } } Client side Subscription and Observer class Program { static void Main(string[] args) { ServiceReference1.Service1Client c = new ServiceReference1.Service1Client(new InstanceContext(new callbackObserver())); c.Subscribe(); Console.WriteLine("Wait for Data. To stop IO, hit return"); Console.ReadLine(); c.Unsubscribe(); Console.ReadLine(); } } class callbackObserver : ConsoleApplication1.ServiceReference1.IService1Callback { public void OnNext(CompositeType data) { Console.WriteLine("Data: " + data.Name +" "+data.Value.ToString()); } }
Friday, August 17, 2012
Drag Canvas around using Rx
WPF UI can be Drag around using mouseMove stream Buffer of two element calculation of Delta: (1) Observe 3 streams: mouseDown, mouseUp, mouseMove. The first two are point event and need duration to join to mouseMove. (2) The duration is skip until mouseDown take until mouseUp (3) Delta is the difference between two mouseMove sampling inside Buffer(2,2). Note that Buffer(count, skip) skip=count is standard, skip>count skip and skip<count is overlapping. Buffer means pile up multiple point into one tally public MainWindow() { InitializeComponent(); var mouseDown = from evt in Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(h => cv.MouseDown += h, h => cv.MouseDown -= h) select evt.EventArgs.GetPosition(this); var mouseUp = from evt in Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(h => MouseUp += h, h => MouseUp -= h) select evt.EventArgs.GetPosition(this); var mouseMove = from evt in Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>(h => MouseMove += h, h => MouseMove -= h) select evt.EventArgs.GetPosition(this); var q = Observable.Join( mouseDown, mouseMove.Buffer(2, 2), _ => mouseMove.SkipUntil(mouseDown).TakeUntil(mouseUp), _ => Observable.Empty<Unit>(), (d, consecPts) =>new Point(consecPts[1].X - consecPts[0].X, consecPts[1].Y - consecPts[0].Y)); q.Subscribe(delta => { Canvas.SetLeft(cv, Canvas.GetLeft(cv) + delta.X); Canvas.SetTop(cv, Canvas.GetTop(cv) + delta.Y); }); // Side Note: To allow resizing do the following and using Microsoft sample Resizing Adorner: // a = AdornerLayer.GetAdornerLayer(g); //g=Canvas for layout // a.Add(new ResizingAdorner(cv)); // cv= any UIElement inside g } // AdornerLayer adornerLayer; } public class ResizingAdorner : Adorner { Thumb topLeft, topRight, bottomLeft, bottomRight; VisualCollection visualChildren; public ResizingAdorner(UIElement adornedElement) : base(adornedElement) { visualChildren = new VisualCollection(this); BuildAdornerCorner(ref topLeft, Cursors.SizeNWSE); BuildAdornerCorner(ref topRight, Cursors.SizeNESW); BuildAdornerCorner(ref bottomLeft, Cursors.SizeNESW); BuildAdornerCorner(ref bottomRight, Cursors.SizeNWSE); bottomLeft.DragDelta += new DragDeltaEventHandler(HandleBottomLeft); bottomRight.DragDelta += new DragDeltaEventHandler(HandleBottomRight); topLeft.DragDelta += new DragDeltaEventHandler(HandleTopLeft); topRight.DragDelta += new DragDeltaEventHandler(HandleTopRight); } #region Handle Resizing from Thumb void HandleBottomRight(object sender, DragDeltaEventArgs args) { FrameworkElement adornedElement = this.AdornedElement as FrameworkElement; Thumb hitThumb = sender as Thumb; if (adornedElement == null || hitThumb == null) return; FrameworkElement parentElement = adornedElement.Parent as FrameworkElement; EnforceSize(adornedElement); adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width); adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height); } void HandleBottomLeft(object sender, DragDeltaEventArgs args) { FrameworkElement adornedElement = AdornedElement as FrameworkElement; Thumb hitThumb = sender as Thumb; if (adornedElement == null || hitThumb == null) return; // Ensure that the Width and Height are properly initialized after the resize. EnforceSize(adornedElement); adornedElement.Width = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width); adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height); } void HandleTopRight(object sender, DragDeltaEventArgs args) { FrameworkElement adornedElement = this.AdornedElement as FrameworkElement; Thumb hitThumb = sender as Thumb; if (adornedElement == null || hitThumb == null) return; FrameworkElement parentElement = adornedElement.Parent as FrameworkElement; EnforceSize(adornedElement); adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width); adornedElement.Height = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height); } void HandleTopLeft(object sender, DragDeltaEventArgs args) { FrameworkElement adornedElement = AdornedElement as FrameworkElement; Thumb hitThumb = sender as Thumb; if (adornedElement == null || hitThumb == null) return; EnforceSize(adornedElement); adornedElement.Width = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width); adornedElement.Height = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height); } #endregion // Arrange thumbs relative to Adorner Center protected override Size ArrangeOverride(Size finalSize) { double desiredWidth = AdornedElement.DesiredSize.Width; double desiredHeight = AdornedElement.DesiredSize.Height; double adornerWidth = this.DesiredSize.Width; double adornerHeight = this.DesiredSize.Height; topLeft.Arrange(new Rect(-adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight)); topRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight)); bottomLeft.Arrange(new Rect(-adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight)); bottomRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight)); return finalSize; } void BuildAdornerCorner(ref Thumb cornerThumb, Cursor customizedCursor) { if (cornerThumb != null) return; cornerThumb = new Thumb(); // Set some arbitrary visual characteristics. cornerThumb.Cursor = customizedCursor; cornerThumb.Height = cornerThumb.Width = 10; cornerThumb.Opacity = 0.40; cornerThumb.Background = new SolidColorBrush(Colors.MediumBlue); visualChildren.Add(cornerThumb); // Must add to the tree to arrange } void EnforceSize(FrameworkElement adornedElement) { if (adornedElement.Width.Equals(Double.NaN)) adornedElement.Width = adornedElement.DesiredSize.Width; if (adornedElement.Height.Equals(Double.NaN)) adornedElement.Height = adornedElement.DesiredSize.Height; FrameworkElement parent = adornedElement.Parent as FrameworkElement; if (parent != null) { adornedElement.MaxHeight = parent.ActualHeight; adornedElement.MaxWidth = parent.ActualWidth; } } protected override int VisualChildrenCount { get { return visualChildren.Count; } } protected override Visual GetVisualChild(int index) { return visualChildren[index]; } }
Saturday, August 11, 2012
Dualization
(1) Algebra notation indicates IO is dual of any subject =>func pattern, especially IEnumerable<T> (2) Monad has M, bind, return and in Continuation Monad CM<T> = (T ->() ) -> () return :: T -> CM<T> bind :: CM<T> -> (T -> CM<S>) -> CM<S> Daulality Code interface IEnumerable<out T> { IEnumerator<T> GetEnumerator(); } interface IEnumerator<out T>: IDisposable { bool MoveNext(); T Current { get; } } interface IObservable<out T> { IDisposable Subscribe(IObserver<T> observer); } interface IObserver<in T> { void OnCompleted(bool done); void OnError(Exception exception); T OnNext { set; } } Covariant vs. Contravariant A <: B A is subtype of B,for TypeContructor C C<A> <: C<B> (Covariant) C<B> <: C<A> (Contravariant) Reading = Covar = <out T> Writing = Contra = <in T> =pass args into array. interface IRequireContravariant<in T> { int Write(T t); } interface IRequireCovariant<out T>{ T Read(int t); } IE vs. IO (1) Concurrency: IE need to remove Concurrency and block MoveNext until Source ready for Next Value; IO need to add Concurrency to not block source push to target (2) Async Computation Model void Fib( int n, ACtion CB, Action Err, Action Cncl) IObserverFib(int n); (3) IE can sample source interactively while IO cannot push back high speed source. So IScheduler is define to have time specified: IScheduler { DateTimeOffset Now IDisposable Schedule (state, DateTimeOffset dueTime, Func action) IDisposable Schedule (..TimeSpan dueTime,..); IDisposable Schedule (TState state, Func action) // constant push }
Sunday, August 5, 2012
Prism Region Manager, Sevice Locator and Module
Some code to demo additional features of Prism (1) ServiceLocator.GetInstance = Container.Resolve and inject (2) Region Manager can define region for injecting UserControl (view) (3) Module execute injection of view (4) Adding Module to ModuleCatalog does injection of Region Manager App run bootstrapper public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { OtherBootstrapper b = new OtherBootstrapper(); b.Run(); } } Bootstrapper: Service Locator, ModuleCatalog public class OtherBootstrapper : UnityBootstrapper { protected override void InitializeShell() { (Application.Current.MainWindow = (Window)Shell).Show(); } protected override DependencyObject CreateShell() { //ServiceLocator replaced Container.Resolve return ServiceLocator.Current.GetInstance<ShellWin>(); // return Container.TryResolve<ShellWin>(); } protected override void ConfigureContainer() { // this will run default config such as EventAggregator, ServiceLocator and region manager base.ConfigureContainer(); } protected override void ConfigureModuleCatalog() { // amazingly, add ModuelInfo will do DI just like container.Resolve ModuleCatalog.AddModule(new ModuleInfo() { ModuleName = typeof(OtherFeatureModule).Name, ModuleType = typeof(OtherFeatureModule).AssemblyQualifiedName }); base.ConfigureModuleCatalog(); } } public class OtherFeatureModule : IModule { IRegionManager _mgr; // DI does happend when ModuleInfor Added to Catalog public OtherFeatureModule(IRegionManager mgr) { _mgr = mgr; } public void Initialize() { _mgr.Regions["mainReg"].Add(new uc1 ()); } } ShellWin.xaml --- Region added to RegionManager.Region Collection xmlns:ps="http://www.codeplex.com/CompositeWPF" <Grid> <ContentControl ps:RegionManager.RegionName="mainReg" /> </Grid>
Tuesday, July 31, 2012
Parallel.For vs. Synchronization using ManualResetEvent
For 100 threads Synchronization using primitives seems a bit fater, 14s vs. 17s (but for some reason WCF does not go parallel even after adjusted throtlelling=100 machine.config processModel min/max work/Id thread =100/200) class Program { private const int NUM = 100; static CountdownEvent cde = new CountdownEvent(NUM); static ManualResetEvent mre = new ManualResetEvent(false); static void Main(string[] args) { Stopwatch sw = new Stopwatch(); sw.Start(); PFor(); // SyncWithPrimitives(); sw.Stop(); Console.WriteLine(sw.ElapsedMilliseconds); Console.ReadKey(); } private static void PFor() { c.Open(); Parallel.For(0, NUM, new ParallelOptions() {MaxDegreeOfParallelism=NUM}, (i) => { c.GetData(1111); // Console.WriteLine(c.GetData(1111)); }); c.Close(); } #region Using Threading Primitives private static void SyncWithPrimitives() { Thread[] threads = new Thread[NUM]; for (int i = 0; i < NUM; i++) { threads[i] = new Thread(SetThread); threads[i].Start(); } cde.Wait(); c.Open(); mre.Set(); // all threads burst into calling WCF cde = new CountdownEvent(NUM); // count down to all finish calls to WCF cde.Wait(); c.Close(); } static ServiceReference1.Service1Client c = new ServiceReference1.Service1Client(); static void SetThread() { cde.Signal(); mre.WaitOne(); c.GetData(1111); // Console.WriteLine( c.GetData(1111)); cde.Signal(); // call finished } #endregion } WCF: [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] public class Service1 : IService1 { public string GetData(int value) { Random r = new Random(); Thread.Sleep(TimeSpan.FromSeconds(1)); return r.NextDouble().ToString(); }
Monday, July 30, 2012
Implement Asyn WCF using Task in .Net 4.0
In Fx 4.5 Task can be returned but in Fx 4.0, task can only be on Server: public interface IService1 { [OperationContract(AsyncPattern=true)] IAsyncResult BeginGetDataAsync(int value, AsyncCallback cb, object state); string EndGetDataAsync(IAsyncResult ar); } string GetData(int value) { Random r = new Random(); Thread.Sleep(TimeSpan.FromSeconds(3)); return r.NextDouble().ToString(); } public IAsyncResult BeginGetDataAsync(int value, AsyncCallback cb, object state) { var t = Task<string>.Factory.StartNew((s) => { return GetData(value); },state); // must pass state into Lambda return t.ContinueWith(res => cb(t)); } public string EndGetDataAsync(IAsyncResult ar) { return ((Task<string>)ar).Result; } Client --- need to add Servicew Ref with support of async WCF checked object state = ""; ServiceReference1.Service1Client c = new ServiceReference1.Service1Client(); int NUM = 10; Stopwatch sw= new Stopwatch(); sw.Start(); Parallel.For(0, NUM, (ls) => { //for (int i = 0; i < NUM; i++) //{ var t = Task<string>.Factory.FromAsync(c.BeginGetDataAsync, c.EndGetDataAsync, 10, state); string s = t.Result; Console.WriteLine(s); //} }); c.Close(); sw.Stop(); Console.WriteLine(sw.ElapsedMilliseconds); Console.ReadLine();
Wednesday, July 25, 2012
High Performance WPF/WCF
Serveral Keys for High Performance: (1) WPF need to use ThreadPool (Task/ParallelFor) to call WCP in the backgroud (2) Return data should be on Queues for Dispatcher Timer to pick up and update UI (3) WCF Instancing.Single and Concurrency.Multiple seems to have better network through-put than Single/Single ( Total B/Sec in Win8 Resource Monitor 220 vs 280, 20%+). But this not a serious performance Testing) (4) one thing for sure: when Task is removed, UI will be slugish. public delegate void OnHeartbeat(); public partial class MainWindow : Window { const int NUM = 5000; public event OnHeartbeat Heartbeat; DispatcherTimer t; DispatcherTimer t2; List<RealtimeData> dataList = new List<RealtimeData>(); Dictionary<int, Queue> qList = new Dictionary<int, Queue<string>>(); public MainWindow() { InitializeComponent(); t = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 0, 0, 1) }; t.Tick += new EventHandler(t_Tick); t2 = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 0, 0, 1) }; t2.Tick += new EventHandler(t_Tick2); AddGridCell(); t.Start(); t2.Start(); } void t_Tick(object sender, EventArgs e) { if (Heartbeat != null) Heartbeat(); } void t_Tick2(object sender, EventArgs e) { Task.Factory.StartNew(() => { Parallel.For(0, NUM, (ii) => // for (int ii = 0; ii < NUM; ii++) { try { ServiceReference1.Service1Client c = new ServiceReference1.Service1Client(); qList[ii].Enqueue(c.GetData(ii)); c.Close(); } catch (Exception ex) { EventLog.WriteEntry("Application", ex.Message + " " + ex.StackTrace); } }); // } }); } void AddGridCell() { for (int i = 0; i < NUM; i++) { qList.Add(i, new Queue ()); RealtimeData rtD = MakeDataItem(i); this.Heartbeat += rtD.UpdateData; dataList.Add(rtD); wrapPanel1.Children.Add(rtD); } } RealtimeData MakeDataItem(int i) { return new RealtimeData(qList[i]) { Width = 50, Height = 50, BorderBrush = new SolidColorBrush(Colors.Black), BorderThickness = new Thickness(2) }; } } public class RealtimeData : UserControl { Label lb = new Label(); Queue<string> _q; public RealtimeData(Queue<string> q) { _q = q; this.AddChild(lb); } public void UpdateData() { int i = _q.Count; if (_q.Count > 0) lb.Content =i.ToString()+" "+ _q.Dequeue(); } } // [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)] [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)] public class Service1 : IService1 { public string GetData(int value) { // Thread.SpinWait(300000); Random r = new Random(); return string.Format(r.NextDouble().ToString()); } }
Tuesday, July 17, 2012
WPF Prism MVVM using Unity and Mef
Summary: We need to Unity/Mef Bootstrap into Shell as Top Window, where two things happen: the normal WPF Window.Show() and enable Dependency Injection (DI) as early as possible using UnityContainer.Resolve<Shell> or CompositeContainer.GetExportTypes<>. Note that basic services like EventAggregator are constructed by Unity/Mef and will be passed along through Container/Aggregate Catalog. Note that WPF DataContext is set in ShellWindos Constructor for Unity and DInjected for Mef through [Import]. bootstrapper.cs #region Unity Bootstrapper class DemoUnityBootstrapper : UnityBootstrapper { protected override System.Windows.DependencyObject CreateShell() { return Container.Resolve<ShellWindow>(); // must be resolved by Container to do DI } protected override void InitializeShell() { (Application.Current.MainWindow =(Window) Shell).Show(); } } #endregion #region Mef Bootstrapping class DemoMefBootstrapper : MefBootstrapper { protected override System.Windows.DependencyObject CreateShell() { return new ShellWindow2(Container,AggregateCatalog); //avoid DI [Export] on ShellWindow2 } protected override void InitializeShell() { (Application.Current.MainWindow = (Window)Shell).Show(); } } #endregion App Startup protected override void OnStartup(StartupEventArgs e) { DemoUnityBootstrapper dub = new DemoUnityBootstrapper(); dub.Run(true); DemoMefBootstrapper dmb = new DemoMefBootstrapper(); dmb.Run(true); } Shell as Window public ShellWindow(IUnityContainer container) //DI { InitializeComponent(); // again, DI require Container.Resolve. var vm = container.Resolve<PrismDemo.MVVM.ViewModel>(); var view = container.Resolve<PrismDemo.MVVM.View>(); view.DataContext = vm; cc.Content = view; } public ShellWindow2(CompositionContainer c, AggregateCatalog a) //not DI { InitializeComponent(); a.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly())); IView v2 = c.GetExportedValue<IView>(); // invoke Import-Export matching on V cc.Content = v2; } View for Mef only, Unity has no code [Export(typeof(IView))] // for Container.GetExportpublic partial class View2 : UserControl , IView { public View2() { InitializeComponent(); } [Import] // Import will Match Export of VM2 public ViewModel2 ViewModel { set { this.DataContext = value; } } // declare which view is it for Modularity public string ViewName { get { return "View2"; } set { throw new NotImplementedException(); } } } Xaml <Grid> <StackPanel> <TextBlock Background="#FF15ABB7">MVVM View, Data binding</TextBlock> <TextBox Text="{Binding Path=SingleValue, Mode=TwoWay}" /> </StackPanel> </Grid> ViewMode public class ViewModel : INotifyPropertyChanged { IEventAggregator _eventAggregator; public ViewModel(IEventAggregator ea) //Unity Ctor DI { _eventAggregator = ea; } string _SingleValue="test"; public string SingleValue { get { return _SingleValue;} set { _SingleValue=value; PropertyChanged(this, new PropertyChangedEventArgs("SingleValue")); Debug.Assert(_eventAggregator != null); // test Event Aggregator get DInjected } } public event PropertyChangedEventHandler PropertyChanged; } [Export(typeof(ViewModel2))] public class ViewModel2 : NotificationObject { [Import] // Exported by Mef base Aggregate Catalog public IEventAggregator ea { get; set; } IEventAggregator propEa; [ImportingConstructor] public ViewModel2(IEventAggregator ea2) { propEa = ea2; } string _SingleValue = "test"; public string SingleValue { get { return _SingleValue; } set { _SingleValue = value; RaisePropertyChanged("SingleValue"); Debug.Assert(ea != null & propEa != null); // test Event Aggregator get DInjected as Ctor and Prop } } }
Saturday, July 14, 2012
Trading Signals from EMA and RSI
[hist_date, hist_high, hist_low, hist_open, hist_close, hist_vol] =get_hist_stock_data('AAPL','2012'); data=hist_close; [lead,lag]=movavg(data,5,20,'e'); s=zeros(size(data)); s(lead<=lag)=-1; s(lead>lag)=1; r=[0;s(1:end-1).*diff(data)]; R=cumsum(r); % ax(1) = subplot(2,1,1); % plot([data,lead,lag]); grid on % legend('Close','Lead','Lag','Location','Best') % title(['Data, Lead and Lag MA']) % ax(2) = subplot(2,1,2); % plot([s*50,cumsum(r)]); grid on % legend('signal long and short','Cumulative Return','Location','Best') % linkaxes(ax,'x') rsi=rsindex(data,14) s1=zeros(size(data)); s1(rsi>75)=-1; s1(rsi<25)=1; r1=[0;s1(1:end-1).*diff(data)]; R1=cumsum(r); ax(1) = subplot(2,1,1); plot([data]); grid on legend('Close','Location','Best') title(['Close']) ax(2) = subplot(2,1,2); plot([s1*25,R1]); grid on legend('RSI Signal long short,no action','Cumulative Return','Location','Best') linkaxes(ax,'x')
Interesting javascript code
Get Radio button value and update Telerik Paging for refresh presevation // F12 and debugger showed the structure $(document).ready(function() { var rb = $("input[id='rbfilterType']:radio:checked").attr('value'); $("a[href*='TheGrid-page']").each(function(i) { var h = this.href; this.href =replaceQueryString(this.href, "filterType",rb); } ); } ) function replaceQueryString(url, param, value) { var re = new RegExp("([?|&])" + param + "=.*?(&|$)", "i"); if (url.match(re)) return url.replace(re, '$1' + param + "=" + value + '$2'); else return url + '&' + param + "=" + value; } Using CSS Scrollbar to replace malfunction Teleric Scrollbar // find the inner table and add scrollbar heigth to hide v-bar $(document).ready(function() { var h = $("#grdTestList table").height(); var h1 = h + 45; $("#grdTestList").attr("style", "overflow:auto;height:"+h1+"px"); } ) Refreshing <input type="button" value="Close and Refresh" onclick="javascript:document.location.reload();" /> <input type="button" value="Close and Refresh" onclick="javascript:Window_onClose();" /> <script type="text/javascript"> function Window_onClose() { var window = $('#editDialog').data('tWindow'); window.close(); document.getElementById("submit").click(); } </script> Modify Telrik UI using jQuery $(document).ready(function() { var anof = $("a.fa:contains('Add new record')") anof.text("Add location"); var anofr = $("a.fra:contains('Add new record')") anofr.text("Add man"); anofr.mouseup(function(event) { setCookie("pos", event.pageY, 1); }); var pos = getCookie("pos"); if (!isNaN(pos)) scrollTo(0, pos); // maintain scroll position setCookie("pos", "", 0); var url = window.location.href; if (url.indexOf("grd-mode=edit", 0) <= 0) { // edit mode $("#save").click(function(e) { e.preventDefault(); }); } anof.click(function() { anof[0].href = removeParameter(anof[0].href, "grd-mode") }); anofr.click(function() { anofr[0].href = removeParameter(anofr[0].href, "grd-mode") }); } )
Friday, July 13, 2012
State Machine Desing Pattern
#region SM definition and setup public interface IState { void EventSink(string eventData); void GoToNextState(); } public class StateMachine { List_states ; public IState CurrentState { get; set; } public StateMachine() { _states = new List () { new State1(this), new State2(this)}; // omited Start and End State } public void SignalEvent(string infor) { if (infor == "Start") { CurrentState = (from _ in _states where _.GetType() == typeof(State1) select _).FirstOrDefault (); } CurrentState.EventSink(infor); } internal void MoveState(IState st) { if (st.GetType() == typeof(State1)) // State2 would have move to End State CurrentState = (from _ in _states where _.GetType() == typeof(State2) select _).FirstOrDefault (); } } #endregion #region Concrete States public class State1 : IState { StateMachine _sm; public State1(StateMachine sm) { _sm = sm; } public void EventSink(string eventData) { if (eventData == "RequiredInforType1Received") { Console.WriteLine("Processing Type1 Infor"); Console.WriteLine("Passed, move to state2"); GoToNextState(); } } public void GoToNextState() { _sm.MoveState(this); } } public class State2 : IState { StateMachine _sm; public State2(StateMachine sm) { _sm = sm; } public void EventSink(string eventData) { if (eventData == "RequiredInforType2Received") { Console.WriteLine("Processing Type2 Infor"); Console.WriteLine("Passed, move to end state"); GoToNextState(); } } public void GoToNextState() { _sm.MoveState(this); } } #endregion static void Main(string[] args) { StateMachine sm = new StateMachine(); sm.SignalEvent("Start"); sm.SignalEvent("RequiredInforType1Received"); sm.SignalEvent("RequiredInforType12Received"); Console.ReadKey(); }
Wednesday, July 4, 2012
IoC inject data into DropDownListFor
DropDownListFor(m=>m.Name, ViewData["TheList"] requires repeatedly build ViewData. AutoFac IoCContainer Dependency Injection Could be used to avoid duplicating these code: (1) We need to build Referenc List Types so we can resolve a Generic Type for IoC (i.e we cannot use Enum) (2) Dependency Inject will inject a Repository IReferenceListRepository (3) The generic Type SelectionListmust be able to render a list of SelectItem to feed into DropDownListFor base(LinqExpression, IEnumeralb) (4) DropDownListFor Extension can now build a generic type using type input param #region Reference List types public class USStatesRefList : ReferenceListType { } public class ApppealStatusesRefList : ReferenceListType { } public class EscalationToRefList : ReferenceListType { } public class ReferenceListType { public int Id { get; set; } public string Description { get; set; } public string ShortName { get; set; } } #endregion #region Ref Data Repository public interface IReferenceListRepository { IEnumerable<T> All<T>(); } public class ReferenceListRepository : IReferenceListRepository { public IEnumerable<T> All () { // TODO; Build List from Database or RavenDB if (typeof(T)==typeof(USStatesRefList)) { List<USStatesRefList> list= new List<USStatesRefList>() { new USStatesRefList() { Id=1, ShortName="MA", Description="MASS"}, new USStatesRefList() {Id=2, ShortName="NY",Description="Empire State"}}; return (IEnumerable <T> ) list.AsEnumerable(); } return default(IEnumerable<T>); } } #endregion #region Selection List -- can fill dropdown public class SelectionList<T> : IReferenceListRenderer where T : ReferenceListType { IEnumerable<T> _All { get; set; } // Repository get injected here public SelectionList(IReferenceListRepository repository) { _All = repository.All<T>(); } public List<SelectListItem> RenderList(IConvertible value) { return (from p in _All select new SelectListItem { Value = null, // p.Id.ToString(), DropDownList mal function if Value get set Text =p.ShortName,// string.Format("{0} ({1})", p.Description, p.Id), Selected =ValueEqual(p,value) }).ToList(); } public bool ValueEqual(ReferenceListType p, IConvertible value) { // For selection List, shortname matching ToString() is the only valid case return p.ShortName == Convert.ToString(value); } } public interface IReferenceListRenderer { List<SelectListItem> RenderList(IConvertible value); } #endregion #region Drop Down List without using ViewData public static class DropDownListExtensions { public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> h, Expression<Func<TModel, TProperty>> expression, Type listType) where TProperty : IConvertible { var property = expression.Compile()(h.ViewData.Model); var SelectionListT = typeof(SelectionList<>).MakeGenericType(listType); var listR = DependencyResolver.Current.GetService(SelectionListT) as IReferenceListRenderer; List<SelectListItem> list = listR.RenderList(property); return h.DropDownListFor(expression,list ); } } #endregion @Html.DropDownListFor(m => m.Name, typeof(USStatesRefList)); Boiler Template code to hook up IoC protected void Application_Start() { var builder = new ContainerBuilder(); builder.RegisterControllers(typeof(MvcApplication).Assembly);//Assembly.GetExecutingAssembly()); builder.RegisterModelBinders(Assembly.GetExecutingAssembly()); builder.RegisterModule(new ApplicationModule()); var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); public class ApplicationModule : Module { protected override void Load(ContainerBuilder builder) { // builder.RegisterInstance<ILog>(LogManager.GetLogger("TheInstance")); builder.RegisterType<ReferenceListRepository>().As<IReferenceListRepository>().InstancePerLifetimeScope(); builder.RegisterGeneric(typeof(SelectionList<>)).SingleInstance(); }
Monday, July 2, 2012
Using AutoFac IocContainer to inject Log4Net into MVC3
Nugget AutoFac, AutoFac.MVC3 and Log4Net into a MVC3 project Create a Module to register public class ApplicationModule : Module { protected override void Load(ContainerBuilder builder) { // builder.RegisterInstance(LogManager.GetLogger("TheInstance")); } protected override void AttachToComponentRegistration(Autofac.Core.IComponentRegistry componentRegistry, Autofac.Core.IComponentRegistration registration) { registration.Preparing += registration_Preparing; } static void registration_Preparing(object sender, Autofac.Core.PreparingEventArgs e) { var t = e.Component.Activator.LimitType; e.Parameters = e.Parameters.Union( new[] { new ResolvedParameter((p, i) => p.ParameterType == typeof(ILog), (p, i) => LogManager.GetLogger(t)) } ); } } Create Container, Register, Build and setResolver protected void Application_Start() { ... var builder = new ContainerBuilder(); builder.RegisterControllers(typeof(MvcApplication).Assembly);//Assembly.GetExecutingAssembly()); builder.RegisterModule(new ApplicationModule()); var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); } Inject into COnstructor public class HomeController : Controller { public HomeController(ILog log) {
Thursday, June 28, 2012
MVC3 Log4Net Async and Customized Logging
Setup log4net in Web.Config is straight forward. Need to write Extension of ILog adding Task for Non-blocking Database write. Web.Config <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler"/> </configSections> <log4net debug="false"> <appender name="AdoNetAppender_SqlServer" type="log4net.Appender.AdoNetAppender"> <bufferSize value="1" /> <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <!--<connectionString value="Data Source=Pentium22;Initial Catalog=db;Integrated Security=True" />--> <connectionString value="Data Source=Pentium22;Initial Catalog=db;User ID=sa;Password=xxxxxx;" /> <!--<commandText value="INSERT INTO LogMVC3 ([Date],[Thread],[Level],[Logger],[Message]) VALUES (@log_date, @thread, @log_level, @logger, @message)" />--> <commandText value="INSERT INTO LogMVC3A ([Date],[Message]) VALUES (@log_date, @message)" /> <parameter> <parameterName value="@log_date" /> <dbType value="DateTime" /> <layout type="log4net.Layout.PatternLayout" value="%date{yyyy'-'MM'-'dd HH':'mm':'ss'.'fff}" /> </parameter> <parameter> <parameterName value="@thread" /> <dbType value="String" /> <size value="255" /> <layout type="log4net.Layout.PatternLayout" value="%thread" /> </parameter> <parameter> <parameterName value="@log_level" /> <dbType value="String" /> <size value="50" /> <layout type="log4net.Layout.PatternLayout" value="%level" /> </parameter> <parameter> <parameterName value="@logger" /> <dbType value="String" /> <size value="255" /> <layout type="log4net.Layout.PatternLayout" value="%logger" /> </parameter> <parameter> <parameterName value="@message" /> <dbType value="String" /> <size value="4000" /> <layout type="log4net.Layout.PatternLayout" value="%message" /> </parameter> </appender> <root> <level value="All"/> <appender-ref ref="AdoNetAppender_SqlServer"/> </root> </log4net> Global.asax protected void Application_Start() { ... log4net.Config.XmlConfigurator.Configure(); } Note that for console app use [assembly: log4net.Config.XmlConfigurator(Watch = true)] Extension for ILog: public static class Class1 { public static void Info2(this ILog log, object Message) { Task.Factory.StartNew(() => { log.Info(Message); Thread.Sleep(5000); }); } } Logging anywhere w/o blocking: public static class Class1 { public static void Info2(this ILog log, object Message) { Task.Factory.StartNew(() => { log.Info(Message); Thread.Sleep(5000); }); } public static void Audit2(this ILog log, object auditData) { Task.Factory.StartNew(() => { AuditDataWrapper adw = new AuditDataWrapper() { AuditData = auditData }; log.Info(adw); Thread.Sleep(5000); }); } } public class AuditDataWrapper { public object AuditData { get; set; } } Note: root/level/value can be OFF FATAL ERROR WARN INFO DEBUG ALL bufferSize=1 means immediate write to DB, no delay/caching Reference: http://basquang.wordpress.com/2011/08/26/logging-using-log4net-in-asp-net-mvc-3/ Customization -AuditData Pattern Converter public class AuditDataPatternLayoutConverter : PatternLayoutConverter { protected override void Convert(System.IO.TextWriter writer, log4net.Core.LoggingEvent loggingEvent) { object obj = loggingEvent.MessageObject; Type t = obj.GetType(); if (loggingEvent.Level != log4net.Core.Level.Info || t != typeof(AuditDataWrapper)) return; AuditDataWrapper adw = obj as AuditDataWrapper; if (adw.AuditData==null) return; XmlSerializer ser = new XmlSerializer(adw.AuditData.GetType()); StringWriter sw = new StringWriter(); try { ser.Serialize(sw, adw.AuditData); sw.Flush(); writer.Write(sw.ToString()); } catch { string dump = DumpProperties(adw.AuditData, adw.AuditData.GetType()); writer.Write(dump); } } string DumpProperties(object obj, Type t) { PropertyInfo[] pi = t.GetProperties(); StringBuilder sb = new StringBuilder(); foreach (PropertyInfo p in pi) sb.Append(p.Name + " :" + p.GetValue(obj, null) + "\r\n"); return sb.ToString(); } } <parameter> <parameterName value="@auditdata" /> <dbType value="String" /> <size value="4000" /> <layout type="log4net.Layout.PatternLayout"> <converter> <name value="auditdata" /> <type value="MvcApplication3.AuditDataPatternLayoutConverter" /> </converter> <conversionPattern value="%auditdata" /> </layout> </parameter> // Can put in any type of data into Audit log.Audit2(new TestData() { Name = "John", Age = 90, id = WindowsIdentity.GetCurrent(), Children = new List<TestData>() { new TestData() { Name = "Doe", Age = 12 }, new TestData() { Name = "Mat", Age = 9 } } }); public class TestData { [System.Xml.Serialization.XmlIgnore] public WindowsIdentity id { get; set; } public string Name { get; set; } public int Age { get; set; } public List<TestData> Children { get; set; } } Customization -existing Log4Net converter <commandText value="INSERT INTO LogMVC3 ([Date],[Thread],[Level],[Logger],[Message],[StackTrace],[AuditData],[UserName]) VALUES (@log_date, @thread, @log_level, @logger,@Message, @stacktrace,@auditdata,@username)" /> <parameter> <parameterName value="@stacktrace" /> <dbType value="String" /> <size value="4000" /> <layout type="log4net.Layout.PatternLayout" value="%exception" /> </parameter> <parameter> <parameterName value="@username" /> <dbType value="String" /> <size value="4000" /> <layout type="log4net.Layout.PatternLayout" value="%username" /> </parameter> %appdomain %date %exception %file %identity //slow %level %line %location %logger %method %message %newline %timestamp %type %username //slow %utcdate These can be used to format message: <parameter> <parameterName value="@message" /> <dbType value="String" /> <size value="4000" /> <layout type="log4net.Layout.PatternLayout" value=" %timestamp [%thread] %-5level %logger{2} %ndc - %message%newline" /> </parameter>
Thursday, June 21, 2012
Asset Pricing Model for simulation
There are two type of Pricing Model: Stochastic for Growth, Factor for Mean Reversion. In both case mu for $ return or % return or factors can be observed and used in Simulation
% google get_hist_stock_data.m [hist_date, hist_high, hist_low, hist_open, hist_close, hist_vol] =get_hist_stock_data('AAPL','2010'); R_dollar=hist_close(2:end)-hist_close(1:end-1); R_pct=R_dollar./hist_close(1:end-1); % $ return Random Walk dT=1; %daily mu=mean(R_dollar); sigma=std(R_dollar); St=zeros(100,1); St(1)=560; for i=1:1:100 St(i+1)=St(i)+mu+sigma*sqrt(dT)*normrnd(0,1); end f1=figure(1); set(f1,'name','$ return Random Walk'); plot(0:100,St); % % return Ramdom Walk dT=1; %daily mu=mean(R_pct); sigma=std(R_pct); St=zeros(100,1); St(1)=560; for i=1:1:100 St(i+1)=St(i)*exp((mu-sigma^2/2)*dT+sigma*sqrt(dT)*normrnd(0,1)); end f2=figure(2); set(f2,'name','% return Random Walk'); plot(0:100,St); % % return Mean Reversion Factor Model dT=1; %daily mu=mean(R_dollar); sigma=std(R_dollar); St=zeros(100,1); St(1)=560; p=polyfit(hist_close(2:end),R_pct,1) % google get_hist_stock_data.m [hist_date, hist_high, hist_low, hist_open, hist_close, hist_vol] =get_hist_stock_data('USO','2010'); R_dollar=hist_close(2:end)-hist_close(1:end-1); R_pct=R_dollar./hist_close(1:end-1); days=100 % $ return Mean Reversion Factor Model dT=1; %daily mu=mean(hist_close); sigma=std(hist_close); St=zeros(days,1); St(1)=hist_close(end); b=regress(R_dollar,hist_close(2:end)); b k=-b; for i=1:1:days St(i+1)=St(i)+k*(mu-St(i))+sigma*normrnd(0,1); end f1=figure(1); set(f1,'name','$ return Mean Reversion Factor Model'); plot(0:days,St); % % return Mean Reversion Factor Model---see MR Factor Model
Sunday, June 17, 2012
WPF 3D Plot -- Multivariate Normal
Multivariate Normal distribution is represented by an array of 3d vector associated PDF: mu=[2 3 5]; sigma=[1,1.5,.5;1.5 3, 0.5;0.5,0.5,2]; %covariance r=mvnrnd(mu,sigma,100); p=mvnpdf(r,mu,sigma); [r,p] We can plot mvnrnd in WPF Helix 3D Viewbox using pdf as "Density Material" <Window> .... <ht:HelixViewport3D ItemsSource="{Binding Objects}" ShowCoordinateSystem="True" ShowCameraInfo="True" /> </Window> public ObservableCollection<Visual3D> Objects { get; set; } For some reason I have to build 3D plot by ThreadPool. Calling directly from ctor does not work. t = Task.Factory.StartNew(() => { }).ContinueWith((t0) => { if (Objects.Count == 0) Objects.Add(new DefaultLights()); Material m = GetData(); List<Point3DWithDensity> list = Data3D.GetSamplePoints(); maxDensity = (from _ in list select _.Density).Max(); minDensity = (from _ in list select _.Density).Min(); foreach( var v in list) { BoxVisual3D sp = new BoxVisual3D() { Center = v.Point3D, Height = v.Density, Width = v.Density, Length = v.Density, Material = GetDensityMaterial(v.Density, v.Point3D) }; // SphereVisual3D sp = new SphereVisual3D { Center = v.Point3D, Radius = v.Density, Material = GetDensityMaterial(v.Density, v.Point3D) }; Objects.Add(sp); } }, TaskScheduler.FromCurrentSynchronizationContext()); double maxDensity; double minDensity; private Material GetDensityMaterial(double d, Point3D p) { DiffuseMaterial m = new DiffuseMaterial(); int i = (int)Math.Round(((maxDensity - d) * 1.0 + (d - minDensity) * 10) / (maxDensity - minDensity)); SolidColorBrush scb = new SolidColorBrush(GetColor(i)); VisualBrush vb = new VisualBrush(); TextBlock tb = new TextBlock { Text = "(" + p.X.ToString() + "," + p.Y.ToString() + "," + p.Z.ToString() + ")", Background = scb }; vb.Visual = tb; m.Brush = vb; return m; } public class Data3D { public static List<Point3DWithDensity> GetSamplePoints() { #region Raw Data string rawDataFromMATLAB = @" 2.3631 4.9997 4.8456 0.0129 .................. 1.9576 3.5687 1.9473 0.0040 2.7463 3.6281 4.7240 0.0300"; #endregion List<Point3DWithDensity> list = new List<Point3DWithDensity>(); string[] pointData = ReplaceMultipleSpace(rawDataFromMATLAB).Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); foreach (string s in pointData) { string[] xyz= s.Trim().Split(' '); list.Add(new Point3DWithDensity() { Point3D = new Point3D() { X = Convert.ToDouble(xyz[0].Trim()), Y = Convert.ToDouble(xyz[1].Trim()), Z = Convert.ToDouble(xyz[2].Trim()) }, Density=Convert.ToDouble(xyz[3].Trim()) }); } return list; } static string ReplaceMultipleSpace(string s) { RegexOptions options = RegexOptions.None; Regex regex = new Regex(@"[ ]{2,}", options); return regex.Replace(s, @" "); } } public class Point3DWithDensity { public Point3D Point3D { get; set; } public double Density { get; set; } } public static Color GetColor(int value) { int startIndex = (value / 10) * 10; int endIndex = startIndex + 10; Color startColor = Colors.Red; Color endColor = Colors.Blue; float weight = (value - startIndex) / (float)(endIndex - startIndex); return Color.FromArgb(255, (byte)Math.Round(startColor.R * (1 - weight) + endColor.R * weight), (byte)Math.Round(startColor.G * (1 - weight) + endColor.G * weight), (byte)Math.Round(startColor.B * (1 - weight) + endColor.B * weight)); }
Thursday, June 14, 2012
WPF Primitive Element could still uses Sofware Rendering
The following simple Animation strangely still uses swIRT shown in Perforator.
It turns out that WPF Rendering pipe need to rasterize DrawingBrush in software and hand over to GPU. And the only solution is to use RenderingOption,CachingHint on DrawingBrush <Window x:Class="WpfApplication5.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <DrawingBrush x:Key="MyBlueGridBrushResource" Viewport="0,0,10,10" ViewportUnits="Absolute" TileMode="Tile" RenderOptions.CachingHint="Cache" RenderOptions.CacheInvalidationThresholdMaximum="1000" RenderOptions.CacheInvalidationThresholdMinimum="0.5"> <DrawingBrush.Drawing> <DrawingGroup> <DrawingGroup.Children> <GeometryDrawing Brush="White"> <GeometryDrawing.Geometry> <RectangleGeometry Rect="0,0,1,1" /> </GeometryDrawing.Geometry> </GeometryDrawing> </DrawingGroup.Children> </DrawingGroup> </DrawingBrush.Drawing> </DrawingBrush> </Window.Resources> <DockPanel Margin="10"> <Canvas Width="250" Height="250" Background="{StaticResource MyBlueGridBrushResource}"> <Rectangle Height="50" Width="50" Fill="#CCCCCCFF" Stroke="Blue" StrokeThickness="2" Canvas.Left="100" Canvas.Top="100"> <Rectangle.RenderTransform> <ScaleTransform x:Name="MyAnimatedScaleTransform" CenterX="25" CenterY="25" ScaleX="1" ScaleY="1" /> </Rectangle.RenderTransform> </Rectangle> <Rectangle Height="50" Width="50" Stroke="#99000000" StrokeDashArray="4,1" StrokeThickness="2" Canvas.Left="100" Canvas.Top="100" /> </Canvas> <DockPanel HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="10"> <Button Name="startButton" Margin="0,0,2,0">Start</Button> <DockPanel.Triggers> <EventTrigger SourceName="startButton" RoutedEvent="Button.Click"> <BeginStoryboard Name="myBeginStoryboard"> <Storyboard> <DoubleAnimation Storyboard.TargetName="MyAnimatedScaleTransform" Storyboard.TargetProperty="ScaleX" From="0" To="5" Duration="0:0:2" /> <DoubleAnimation Storyboard.TargetName="MyAnimatedScaleTransform" Storyboard.TargetProperty="ScaleY" From="0" To="5" Duration="0:0:2" /> </Storyboard> </BeginStoryboard> </EventTrigger> </DockPanel.Triggers> </DockPanel> </DockPanel> </Window>
Sunday, June 3, 2012
AppFabric 1.1 host WCF multi-binding and Json Data
We can configure WCF services with Multiple EndPoints. To return Json, the following steps are needed: (1) Change OperationContract using WebGet, Json and UriTemplate --- note that input can only be string [WebGet(ResponseFormat=WebMessageFormat.Json, UriTemplate="Data/{value}")] [OperationContract] ListGetData(string value); (2) App.Config ==> Edit WCF config ==> Add webHttpBinding with Binding Behavior wedHttp <services> <service name="WcfServiceLibrary1.Service1"> ... <endpoint address="jsonTest" behaviorConfiguration="NewBehavior0" binding="webHttpBinding" bindingConfiguration="" contract="WcfServiceLibrary1.IService1" /> ... <behaviors> <endpointBehaviors> <behavior name="NewBehavior0"> <webHttp /> </behavior> </endpointBehaviors> (3) Publish to AppFabric Site/App considering the following details: (3.1) Make sure WebDeploy (MSDeploy,VS2010SP1) update installed so that AppFabric has deploy menu and VS2010 WCF App has Package/publish tab (3.2) Note that We are using WCF Lib not app so publish to AppFabric rather than using package. (3.3) Edit binding to default WebSite to have net.tcp binding infor 808:* and net.pipe etc and create an App "mb" with "http,net.tcp,net.pipe" as enabled protocols. (3.4) Browse the app to get base address like http://localhost/mb/WcfServiceLibrary1.Service1.svc test http://[baseAddress]/jsonTest/Data/0 should get to Json Data (save to disk) (3.5) make sure net.tcp port and address match 808:* and uses App "mb" and use a WPF client to add Service Reference for testing. and we should see client config has all protocols.
Saturday, June 2, 2012
Style Trigger and DataTrigger
To style a simple Lisbox, we can trigger change of property by either looking at other property or data loaded <Style TargetType="{x:Type ListBoxItem}" > <Style.Triggers> <Trigger Property="IsSelected" Value="true"> <Setter Property="Foreground" Value="Red" /> </Trigger> <DataTrigger Binding="{Binding Path=Name}" Value="User 3"> <Setter Property="BorderBrush" Value="Black" /> <Setter Property="BorderThickness" Value="1" /> ... list.Add(new User(){ Name="User 1"}); list.Add(new User() { Name = "User 2" }); listBox1.ItemsSource = list;
Thursday, May 31, 2012
Monday, May 28, 2012
WPF 3 D Coordinate System with A Camera: Example
Then we can map 2D Texture to 3D using MeshGeometry3D <Viewport3D> <Viewport3D.Camera> <PerspectiveCamera Position="-20,46,0" UpDirection="0,0,1" LookDirection="4,-10,0" NearPlaneDistance="0"/> ...... <GeometryModel3D.Geometry> <MeshGeometry3D Positions="-10,-10,-10 10,-10,-10 10,10,-10 -10,10,-10 -10,-10,10 -10,10,10" TriangleIndices="0 2 3 0 1 2 0 4 3 4 5 3" TextureCoordinates="0,0 0,1 1,1 1,0" />
Saturday, May 26, 2012
Future Pricing and MR factor model
MATLAB code [hist_date, hist_high, hist_low, hist_open, hist_close, hist_vol] =get_hist_stock_data('SPX','2006'); Data=hist_close; [n,nn] = size(Data); R_dollar=hist_close(2:end)-hist_close(1:end-1); R_pct=R_dollar./hist_close(1:end-1); [b_int,nn,nn,nn,stats] = regress(R_pct,[ones(n-1,1),Data(1:(n-1),1)]); intercept = b_int(1); slope = b_int(2); if (slope > 0) error('Cannot use geometric mean reversion: pct chg=k*(mu-s)+sigma*dW requiring k>0)'); end sigma = sqrt(stats(4)); k = -slope; mu = -intercept/slope; days=20; dT = 1; St=zeros(days,1); St(1)=hist_close(end); for i=1:1:days St(i+1)=St(i)+(k*(mu-St(i))+sigma*normrnd(0,1))*St(i); end % future price dS/S = dLn(F(t))/dt *dt + signma*dW or % Ft-1=Ft*exp(-dS/S+signma*dW) Ft=zeros(days,1); Ft(end)=St(end); for i=days:-1:2 chg =(St(i+1)-St(i))/St(i); Ft(i-1)=Ft(i)*exp(-chg+sigma*normrnd(0,1)); end f1=figure(1); set(f1,'name','%-Return Mean Reversion Factor Model'); p=plot(0:days,St); set(p,'color','red'); hold on; p=plot(1:days,Ft); hold off;
Friday, May 25, 2012
Sunday, April 22, 2012
Visitor Design Pattern
(1) IAccept will Accept any IVisitor, which include all object types in signature. (2) All participating object types implement IAccept with boiler template code visit(this) (3) Visitors are responsible to implement how to visit a type. Benefit: Ensure new visitor must know how to visit all types, and these types does not need to change to allow new visitors. #region IAccept Universal Visitor public interface IVisitor { // List the universe of objects void Visit(Swap sw); void Visit(Option o); void Visit(Bond b); } public interface IAccept { void Accept(IVisitor visitor); } #endregion #region Universal objects Accept any Visitor(this) --boiler template code public class Swap : IAccept { public void Accept(IVisitor visitor) { visitor.Visit(this); } } public class Option : IAccept { public void Accept(IVisitor visitor) { visitor.Visit(this); } } public class Bond : IAccept { public void Accept(IVisitor visitor) { visitor.Visit(this); } } #endregion #region Risk Visitor -- must know how to visitor any objects public class RiskVisitor : IVisitor { public void Visit(Swap sw) { Console.WriteLine("Special works related to Risk of SWAP"); } public void Visit(Option o) { Console.WriteLine("Special works related to Risk of Option"); } public void Visit(Bond b) { Console.WriteLine("Special works related to Risk of Bond"); } } #endregion #region Pricing Visitor -- must know how to visitor any objects public class PricingVisitor : IVisitor { public void Visit(Swap sw) { Console.WriteLine("Special works related to Pricing of SWAP"); } public void Visit(Option o) { Console.WriteLine("Special works related to Pricing of Option"); } public void Visit(Bond b) { Console.WriteLine("Special works related to Pricing of Bond"); } } #endregion // (1) each visitor visit object RiskVisitor rv = new RiskVisitor(); rv.Visit(new Swap()); rv.Visit(new Option()); PricingVisitor pv = new PricingVisitor(); pv.Visit(new Swap()); pv.Visit(new Option()); // (2) each object accept any visitor Swap sw = new Swap(); sw.Accept(new RiskVisitor()); Console.ReadLine();
Saturday, April 21, 2012
WPF Breadcrumb markup
<ListBox Padding="0" DockPanel.Dock="Left" VerticalAlignment="Center" x:Name="lbBreadCrumb" MinWidth="300" Background="Transparent" BorderThickness="0" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Hidden" SelectionChanged="ListBox_SelectionChanged"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <StackPanel Margin="8,0,0,0" Orientation="Horizontal"></StackPanel> </ItemsPanelTemplate> </ListBox.ItemsPanel> <ListBox.ItemContainerStyle> <Style TargetType="{x:Type ListBoxItem}"> <Setter Property="Background" Value="LightGray"/> <Setter Property="BorderBrush" Value="LightGray"/> <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/> <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/> <Setter Property="Padding" Value="0"/> <Setter Property="SnapsToDevicePixels" Value="true"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ListBoxItem"> <DockPanel LastChildFill="True" Margin="-8,0,0,0"> <Path x:Name="ArrowTip" DockPanel.Dock="Left" Stroke="LightGray" Fill="LightGray" Data="F1 M 112,144L 104,144L 112,160L 104,176L 112,176" Stretch="Fill" Height="32" Width="12" /> <Path x:Name="Arrow" DockPanel.Dock="Right" Stroke="LightGray" Fill="LightGray" Data="F1 M 168,144L 176,160L 168,176" Stretch="Fill" Height="32" Width="12" /> <Border Name="Border" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Background="{TemplateBinding Background}" BorderBrush="LightGray" Padding="{TemplateBinding Padding}" BorderThickness="0,1,0,1" VerticalAlignment="Center" Margin="-1,0,-1,0" > <ContentPresenter /> </Border> </DockPanel> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="true"> <Setter TargetName="Border" Property="Background" Value="Gray"/> <Setter TargetName="Arrow" Property="Fill" Value="Gray"/> <Setter TargetName="ArrowTip" Property="Fill" Value="Gray"/> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Foreground" Value="Red"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ListBox.ItemContainerStyle> <ListBox.ItemTemplate> <DataTemplate> <DataTemplate.Resources> <local:ContentToVisibilityConverter x:Key="c2vConverter" /> </DataTemplate.Resources> <DockPanel VerticalAlignment="Center" Height="30"> <Label DockPanel.Dock="Left" FontSize="8" Content="{Binding Name, FallbackValue=Tagname NA}" VerticalAlignment="Center" Name="lb"/> <Button Width="20" Height="20" Background="#FF1D5BBA" Margin="0" Style="{StaticResource GlassButton}" Visibility="{Binding ElementName=lb, Path=Content., Converter={StaticResource c2vConverter}}"> <Image Width="15" Height="15" Source="images\refresh.png" ToolTip="Refresh Dashboard" MouseLeftButtonDown="RefreshImage_MouseLeftButtonDown" /> </Button> </DockPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
Show WPF Form considering taskbar
// Considering space for Taskbar at the bottom. MONITORINFO monitorInfo = new MONITORINFO(); int MONITOR_DEFAULTTONEAREST = 0x00000001; System.IntPtr handle = (new WinInterop.WindowInteropHelper(this)).Handle; System.IntPtr monitor = MonitorFromWindow(handle, MONITOR_DEFAULTTONEAREST); GetMonitorInfo(monitor, monitorInfo); RECT rcWorkArea = monitorInfo.rcWork; RECT rcMonitorArea = monitorInfo.rcMonitor; M.Height = Math.Abs(rcWorkArea.bottom - rcWorkArea.top);// SystemParameters.MaximizedPrimaryScreenHeight - 20; M.Width = SystemParameters.MaximizedPrimaryScreenWidth - 15; M.Top = 0; M.Left = 0; #region Win32 API [DllImport("user32")] internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi); ////// /// [DllImport("User32")] internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags); #endregion
Saturday, March 24, 2012
Dynamic Programming Tree in MATLAB
function [x]=dynamicProgTree() % states --oil reserve x(1).rsrv=[600000]; x(2).rsrv=[500000 400000]; x(3).rsrv=[400000 300000 200000]; x(4).rsrv=[300000 200000 100000 0]; % Normal and Enhanced Pumping % Value Onward at t=4 is 0 due to lease expiration x(4).Vn=[0 0 0 0]; x(4).Ve=[0 0 0 0]; x(4).V=max(x(4).Vn,x(4).Ve); % Value % Onward=oilPrice*policy-multiplier*policy^1/reserve+discountedValueOnward for i=1:3 x(3).Vn(i)=40*100000- 1*100000^2/x(3).rsrv(i)+0.9*x(4).V(i); x(3).Ve(i)=40*200000- 20*200000^2/x(3).rsrv(i)+0.9*x(4).V(i+1); end % ValueOnward= Max (Norma, Enahnced) x(3).V=max(x(3).Vn,x(3).Ve); for i=1:2 x(2).Vn(i)=30*100000- 1*100000^2/x(2).rsrv(i)+0.9*x(3).V(i); x(2).Ve(i)=30*200000- 20*200000^2/x(2).rsrv(i)+0.9*x(3).V(i+1); end x(2).V=max(x(2).Vn,x(2).Ve); for i=1:1 x(1).Vn(i)=45*100000- 1*100000^2/x(1).rsrv(i)+0.9*x(2).V(i); x(1).Ve(i)=45*200000- 20*200000^2/x(1).rsrv(i)+0.9*x(2).V(i+1); end x(1).V=max(x(1).Vn,x(1).Ve); end
Wednesday, February 29, 2012
Deep Copy Helper
public static T DeepCopy<T>(T obj) { if (obj == null) throw new ArgumentNullException("Object cannot be null"); return (T)Process(obj); } static object Process(object obj) { if (obj == null) return null; Type type = obj.GetType(); if (type.IsValueType || type == typeof(string)) { return obj; } else if (type.IsArray) { Type elementType = Type.GetType( type.FullName.Replace("[]", string.Empty)); var array = obj as Array; Array copied = Array.CreateInstance(elementType, array.Length); for (int i = 0; i < array.Length; i++) { copied.SetValue(Process(array.GetValue(i)), i); } return Convert.ChangeType(copied, obj.GetType()); } else if (type.IsClass) { object toret = Activator.CreateInstance(obj.GetType()); //FieldInfo[] fields = type.GetFields(BindingFlags.Public | // BindingFlags.NonPublic | BindingFlags.Instance); FieldInfo[] fields = GetAllFields(type).ToArray(); foreach (FieldInfo field in fields) { object fieldValue = field.GetValue(obj); if (fieldValue == null) continue; field.SetValue(toret, Process(fieldValue)); } return toret; } else { return null; //throw new ArgumentException("Unknown type"); } } public static IEnumerable<FieldInfo> GetAllFields(Type t) { if (t == null) return Enumerable.Empty<FieldInfo>(); BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly; return t.GetFields(flags).Union(GetAllFields(t.BaseType)); } Note that If we restrict to Serializable then using Memory Stream can deep copy class Program { static void Main(string[] args) { Outside o = new Outside() { Data = new Inside() { Name = "n1", Price = 199 } }; Outside o_sc = o.ShadowCopy; o_sc.Data.Name = "Changed"; // change o as well since Shadow copy reference Outside o_dc = o.DeepCopy; o_dc.Data.Name = "Reset"; // not affect o } } [Serializable] public class Outside { public Inside Data { get; set; } public Outside ShadowCopy { get { return MemberwiseClone() as Outside ; } } public Outside DeepCopy { get { MemoryStream m = new MemoryStream(); BinaryFormatter b = new BinaryFormatter(); b.Serialize(m, this); m.Position = 0; return b.Deserialize(m) as Outside; } } } [Serializable] public class Inside { public string Name { get; set; } public double Price { get; set; } }
Sunday, February 19, 2012
HTML5 Canvas API
<canvas w h id="cv"/> var ctx=document.getElementById("cv").getContext('2d'); Path Drawing: ctx.beginPath(); ctx.moveTo(x,y); ctx.lineTo(x1,y1); ctx.closePath(); Fill ctx.fillRec(); ctx.fillStyle='rgba(0,0,0,0.2)'; alpha 0.2 for black. Mouse move vs. Touch move cv.onMouseMove= function Draw(e) {..} document.addEventListener('touchmove', function (e) { }); e.preventDefault(); not allow Ipad Giggle. e.targetTouches[0].pageX; ctx.transform (matrix+d); cx.scale(60%);
Tuesday, January 31, 2012
Correlated Action ComboBox Behavior
<UserControl xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:loc="clr-namespace:TestCorrTextBoxCustBehavior"> <ComboBox Height="23" HorizontalAlignment="Left" Margin="12,48,0,0" Name="cb1" VerticalAlignment="Top" Width="120" > <i:Interaction.Behaviors> <loc:CorrelatedActionComboBoxBehavior SourceRegularExpression="['Basket Swap'|'CDS']" SourceTriggerType="RegExpression" TargetControlId="lb1" TargetActionType="SetValue" TargetValue="2"/> </i:Interaction.Behaviors> <ComboBoxItem>1</ComboBoxItem> <ComboBoxItem>Basket Swap</ComboBoxItem> <ComboBoxItem>CDS</ComboBoxItem> </ComboBox> <TextBox Height="23" HorizontalAlignment="Left" Margin="268,48,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" /> <ListBox Name="lb1" Width="100" Height="200" Margin="355,91,48,20"> <ListBoxItem>1</ListBoxItem> <ListBoxItem>2</ListBoxItem> <ListBoxItem>3</ListBoxItem> </ListBox> public class CorrelatedActionComboBoxBehavior : Behavior</ComboBox> { public SourceTriggerType SourceTriggerType { get; set; } public string SourceRegularExpression { get; set; } public string TargetControlId { get; set; } public TargetActionType TargetActionType { get; set; } public string TargetValue { get; set; } protected override void OnAttached() { if (!(AssociatedObject is ComboBox)) return; object obj = AssociatedObject.Parent; Control mw = ((System.Windows.Controls.Panel)(obj)).Parent as Window; if (mw==null) mw = ((System.Windows.Controls.Panel)(obj)).Parent as Control; if (mw == null) return; AssociatedObject.DropDownClosed += (sender, e) => { ComboBox cb = AssociatedObject as ComboBox; if (SourceTriggerType == SourceTriggerType.RegExpression) { Regex r = new Regex(SourceRegularExpression); Control c = FindChild(mw, TargetControlId); c.IsEnabled = true; if (r.IsMatch(cb.Text) ) { if ( TargetActionType== TargetActionType.Disable ) c.IsEnabled = false; if (TargetActionType == TargetActionType.SetValue) { ListBox lb = c as ListBox; if (lb != null && TargetValue!="") SetListBoxValue(lb, TargetValue); } } } }; } private void SetListBoxValue(ListBox lb, string p) { for(int i=0;i< lb.Items.Count;i++) { if ((lb.Items[i] as ListBoxItem).Content.ToString() == p) lb.SelectedIndex = i; } } public static T FindChild (DependencyObject parent, string childName) where T : DependencyObject { // Confirm parent and childName are valid. if (parent == null) return null; T foundChild = null; int childrenCount = VisualTreeHelper.GetChildrenCount(parent); for (int i = 0; i < childrenCount; i++) { var child = VisualTreeHelper.GetChild(parent, i); // If the child is not of the request child type child T childType = child as T; if (childType == null) { // recursively drill down the tree foundChild = FindChild (child, childName); // If the child is found, break so we do not overwrite the found child. if (foundChild != null) break; } else if (!string.IsNullOrEmpty(childName)) { var frameworkElement = child as FrameworkElement; // If the child's name is set for search if (frameworkElement != null && frameworkElement.Name == childName) { // if the child's name is of the request name foundChild = (T)child; break; } } else { // child element found. foundChild = (T)child; break; } } return foundChild; } } public enum SourceTriggerType { RegExpression } public enum TargetActionType { Disable, SetValue }
Monday, January 30, 2012
WPF Custom Behavior
(1) Behavior is a gneric type <>, non-generic one has no public ctor (2) Need System.Interactivity.Dll from Blend SDK or MVVM light donwload <Window x:Class="TestCustomBehavior.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" xmlns:local="clr-namespace:TestCustomBehavior" > <Grid> <TextBlock Background="LightBlue" Height="23" HorizontalAlignment="Left" Margin="134,140,0,0" Name="textBlock1" Text="Drag Me Around" VerticalAlignment="Top" > <i:Interaction.Behaviors> <local:DragBehavior></local:DragBehavior> </i:Interaction.Behaviors> </TextBlock> </Grid> </Window> namespace TestCustomBehavior { public class DragBehavior : Behavior<UIElement> { Point startPosMouse, startPosElement; int i = 0; TranslateTransform trans = new TranslateTransform(); protected override void OnAttached() { Window parent = Application.Current.MainWindow; AssociatedObject.RenderTransform = trans; AssociatedObject.MouseLeftButtonDown += (sender, e) => { if (i == 0) { startPosElement = AssociatedObject.TranslatePoint(new Point(), parent); i = 1; } startPosMouse = e.GetPosition(parent); AssociatedObject.CaptureMouse(); }; AssociatedObject.MouseLeftButtonUp += (sender, e) => { AssociatedObject.ReleaseMouseCapture(); }; AssociatedObject.MouseMove += (sender, e) => { Vector diff = e.GetPosition(parent) - startPosElement; if (AssociatedObject.IsMouseCaptured) { trans.X= diff.X; trans.Y = diff.Y; } }; } } }
Sunday, January 29, 2012
WPF Printing using FixedDcoument
Print Preview Popup as FixedDocument (1) PageContent will has Compiler Error but can stil render with FixedPage---Known Defect of WPF. (2) Fixed document will has toolbar shown by WPF, no coded needed. So this is simplest printing <Window x:Class="TestWPFPrinting.PrintPreview" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="PrintPreview" Height="300" Width="300"> <FixedDocument Name="customerReport"> <PageContent> <FixedPage> <Label FontSize="20" Margin="100,20,0,0">REPORT</Label> <ListView BorderThickness="0" Margin="50,100,0,0" FontSize="14" Width="Auto" Height="Auto" ItemsSource="{Binding}"> <ListView.View> <GridView x:Name="gridReport"> <GridViewColumn Width="200" Header="FirstName" DisplayMemberBinding="{Binding Path=FirstName}"> <GridViewColumn.CellTemplate> <DataTemplate> <Label/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Width="200" Header="LastName" DisplayMemberBinding="{Binding Path=LastName}"> <GridViewColumn.CellTemplate> <DataTemplate> <Label/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> </GridView> </ListView.View> </ListView> </FixedPage> </PageContent> </FixedDocument> </Window> Bind to Data public partial class PrintPreview : Window { private List<Customer> _customers; public PrintPreview(List<Customer> customers) { InitializeComponent(); _customers = customers; // generate report this.DataContext = _customers; } } public class Customer { private string _firstName; private string _lastName; public string FirstName { get { return _firstName; } set { _firstName = value; } } public string LastName { get { return _lastName; } set { _lastName = value; } } } Main Form private void button1_Click(object sender, RoutedEventArgs e) { List<Customer> customers = new List<Customer>(); for (int i = 1; i <= 200; i++) { Customer customer = new Customer(); customer.FirstName = "FirstName " + i; customer.LastName = "LastName " + i; customers.Add(customer); } PrintPreview w = new PrintPreview(customers); w.Show();
Subscribe to:
Posts (Atom)