Esempio n. 1
0
        public void DownloadPackage(
            string packageId,
            IVersion version,
            string feedId,
            Uri feedUri,
            ICredentials feedCredentials,
            bool forcePackageDownload,
            int maxDownloadAttempts,
            TimeSpan downloadAttemptBackoff,
            out string downloadedTo,
            out string hash,
            out long size)
        {
            var cacheDirectory = PackageDownloaderUtils.GetPackageRoot(feedId);

            downloadedTo = null;
            if (!forcePackageDownload)
            {
                Log.Info("Attempting to get from cache");
                try
                {
                    downloadedTo = SourceFromCache(
                        packageId,
                        version,
                        cacheDirectory);
                }
                catch (Exception ex)
                {
                    Log.Info("SourceFromCache() failed");
                    Log.Info("Exception starts");
                    Log.Info(ex.ToString());
                    Log.Info(ex.StackTrace);
                    Log.Info("Exception ends");
                }
            }

            if (downloadedTo == null)
            {
                downloadedTo = DownloadPackage(
                    packageId,
                    version,
                    feedUri,
                    feedCredentials,
                    cacheDirectory,
                    maxDownloadAttempts,
                    downloadAttemptBackoff);
            }
            else
            {
                Log.VerboseFormat("Package was found in cache. No need to download. Using file: '{0}'", downloadedTo);
            }

            size = fileSystem.GetFileSize(downloadedTo);
            hash = downloadedTo
                   .Map(path => FunctionalExtensions.Using(
                            () => fileSystem.OpenFile(path, FileAccess.Read),
                            stream => HashCalculator.Hash(stream)));
        }
Esempio n. 2
0
        /// <summary>
        /// Actually download the maven file.
        /// </summary>
        /// <returns>The path to the downloaded file</returns>
        string DownloadArtifact(
            MavenPackageID mavenGavFirst,
            string packageId,
            IVersion version,
            Uri feedUri,
            ICredentials feedCredentials,
            string cacheDirectory,
            int maxDownloadAttempts,
            TimeSpan downloadAttemptBackoff,
            XmlDocument snapshotMetadata)
        {
            Guard.NotNull(mavenGavFirst, "mavenGavFirst can not be null");
            Guard.NotNullOrWhiteSpace(packageId, "packageId can not be null");
            Guard.NotNull(version, "version can not be null");
            Guard.NotNullOrWhiteSpace(cacheDirectory, "cacheDirectory can not be null");
            Guard.NotNull(feedUri, "feedUri can not be null");

            for (var retry = 0; retry < maxDownloadAttempts; ++retry)
            {
                try
                {
                    return(GetFilePathToDownloadPackageTo(
                               cacheDirectory,
                               packageId,
                               version.ToString(),
                               mavenGavFirst.Packaging)
                           .Tee(path => feedUri.ToString().TrimEnd('/')
                                .Map(uri => uri + (snapshotMetadata == null ?
                                                   mavenGavFirst.DefaultArtifactPath :
                                                   mavenGavFirst.SnapshotArtifactPath(MetadataParser.GetLatestSnapshotRelease(
                                                                                          snapshotMetadata,
                                                                                          mavenGavFirst.Packaging,
                                                                                          mavenGavFirst.Version))))
                                .Map(uri => FunctionalExtensions.Using(
                                         () => new WebClient(),
                                         client => client
                                         .Tee(c => c.Credentials = feedCredentials)
                                         .Tee(c => c.DownloadFile(uri, path))))
                                ));
                }
                catch
                {
                    Thread.Sleep(downloadAttemptBackoff);
                }
            }

            throw new MavenDownloadException("Failed to download the Maven artifact");
        }
Esempio n. 3
0
        /// <summary>
        /// Attempt to get the snapshot maven-metadata.xml file, which we will need to use to build up
        /// the filenames of snapshot versions.
        /// </summary>
        /// <returns>The snapshot maven-metadata.xml file if it exists, and a null result otherwise</returns>
        XmlDocument GetSnapshotMetadata(
            MavenPackageID mavenPackageID,
            Uri feedUri,
            ICredentials feedCredentials,
            int maxDownloadAttempts,
            TimeSpan downloadAttemptBackoff)
        {
            for (var retry = 0; retry < maxDownloadAttempts; ++retry)
            {
                try
                {
                    var metadataResponse = (feedUri.ToString().TrimEnd('/') + mavenPackageID.GroupVersionMetadataPath)
                                           .ToEnumerable()
                                           .Select(uri => WebRequest.Create(uri).Tee(request => request.Credentials = feedCredentials))
                                           .Select(request => request.GetResponse())
                                           .Select(response => response as HttpWebResponse)
                                           .First(response => response.IsSuccessStatusCode() || (int)response.StatusCode == 404);

                    if (metadataResponse.IsSuccessStatusCode())
                    {
                        return(FunctionalExtensions.Using(
                                   () => metadataResponse.GetResponseStream(),
                                   stream => new XmlDocument().Tee(doc => doc.Load(stream))));
                    }

                    return(null);
                }
                catch (WebException ex)
                {
                    if (ex.Response is HttpWebResponse response)
                    {
                        if ((int)(response.StatusCode) == 404)
                        {
                            return(null);
                        }
                    }

                    Thread.Sleep(downloadAttemptBackoff);
                }
                catch
                {
                    Thread.Sleep(downloadAttemptBackoff);
                }
            }

            throw new MavenDownloadException("Failed to download the Maven artifact");
        }
Esempio n. 4
0
            public static async Task Show()
            {
                var val = await ReadConsoleAsync("[CallsSequence]: Enter the number please")
                          .Bind(ParseOrZero)
                          .Map(r => r * 3)
                          .Map(s => s.ToString());

                Console.WriteLine("Method sequence result: " + val);

                var resFluent = await
                                from s in ReadConsoleAsync("[Extended]: Enter the number please")
                                from n in ParseOrZero(s)
                                from m3 in FunctionalExtensions.Async(n * 3)
                                select m3.ToString();

                Console.WriteLine("Fluent result: " + resFluent);
            }
Esempio n. 5
0
        public static Option <IntPtr> GetWindowHandleByProcessName(string processName)
        {
            var windowHandle = IntPtr.Zero;

            foreach (var pList in Process.GetProcesses())
            {
                if (pList.ProcessName.Equals(processName, StringComparison.CurrentCultureIgnoreCase))
                {
                    windowHandle = pList.MainWindowHandle;
                    break;
                }
            }
            if (windowHandle == IntPtr.Zero)
            {
                return(FunctionalExtensions.None());
            }
            return(FunctionalExtensions.Some(windowHandle));
        }
Esempio n. 6
0
        public static Option <IntPtr> GetWindowHandleByWindowTitle(string windowName)
        {
            var windowHandle = IntPtr.Zero;

            foreach (var pList in Process.GetProcesses())
            {
                if (pList.MainWindowTitle.Contains(windowName))
                {
                    windowHandle = pList.MainWindowHandle;
                    break;
                }
            }
            if (windowHandle == IntPtr.Zero)
            {
                return(FunctionalExtensions.None());
            }
            return(FunctionalExtensions.Some(windowHandle));
        }
Esempio n. 7
0
        public async Task <IActionResult> SendMessageWithUrlMarkdown(MessageUrlDto message)
        {
            if (!FunctionalExtensions.Check <MessageUrlDto>(message, x => x.ChatId != null || x.MessageText != null || x.URL != null))
            {
                return(BadRequest("All fields are necessary"));
            }
            try
            {
                Types.Message outMsg = await _botClient.SendTextMessageAsync(message.ChatId,
                                                                             message.MessageText,
                                                                             Types.Enums.ParseMode.Markdown,
                                                                             replyMarkup : new InlineKeyboardMarkup(InlineKeyboardButton.WithUrl(
                                                                                                                        "Action link", message.URL)));

                return(Ok(outMsg));
            }
            catch (ApiRequestException ex)
            {
                Console.WriteLine($"Error code:{ex.ErrorCode}");
                return(BadRequest(ex));
            }
        }
Esempio n. 8
0
        public async Task <IActionResult> SendMessage(MessageDto message)
        {
            if (!FunctionalExtensions.Check <MessageDto>(message, x => x.ChatId != null || x.MessageText != null || x.Sender != null))
            {
                return(BadRequest("All fields are necessary"));
            }
            try
            {
                Types.Message outMsg = await _botClient.SendTextMessageAsync(
                    chatId : message.ChatId,
                    text : $"{message.Sender} : {message.MessageText}",
                    parseMode : Types.Enums.ParseMode.Markdown
                    );

                return(Ok(outMsg));
            }
            catch (ApiRequestException ex)
            {
                Console.WriteLine($"Error code:{ex.ErrorCode}");
                return(BadRequest(ex));
            }
        }
Esempio n. 9
0
        public void AddDefaultMethodTranslators()
        {
            var lengthMethod = new GenericMethodCompiler(a => a[0].Member("length"));

            AddPropertyGetterTranslator(typeof(Array), nameof(Array.Length), lengthMethod);
            AddPropertyGetterTranslator(typeof(ICollection), nameof(ICollection.Count), lengthMethod);
            AddPropertyGetterTranslator(typeof(ICollection <>), nameof(ICollection.Count), lengthMethod);
            AddPropertyGetterTranslator(typeof(string), nameof(string.Length), lengthMethod);
            AddMethodTranslator(typeof(Enumerable), "Count", parameterCount: 1, translator: new GenericMethodCompiler(a => a[1].Member("length")));
            AddMethodTranslator(typeof(object), "ToString", new GenericMethodCompiler(
                                    a => new JsIdentifierExpression("String").Invoke(a[0]), (m, c, a) => ToStringCheck(c)), 0);
            AddMethodTranslator(typeof(Convert), "ToString", new GenericMethodCompiler(
                                    a => new JsIdentifierExpression("String").Invoke(a[1]), (m, c, a) => ToStringCheck(a[0])), 1, true);
            AddMethodTranslator(typeof(Enums), "GetNames", new EnumGetNamesMethodTranslator(), 0);

            JsExpression indexer(JsExpression[] args, MethodInfo method) =>
            BuildIndexer(args[0], args[1], method.DeclaringType.GetProperty("Item"));

            AddMethodTranslator(typeof(IList), "get_Item", new GenericMethodCompiler(indexer));
            AddMethodTranslator(typeof(IList <>), "get_Item", new GenericMethodCompiler(indexer));
            AddMethodTranslator(typeof(List <>), "get_Item", new GenericMethodCompiler(indexer));
            AddMethodTranslator(typeof(Enumerable).GetMethod("ElementAt", BindingFlags.Static | BindingFlags.Public), new GenericMethodCompiler((args, method) =>
                                                                                                                                                BuildIndexer(args[1], args[2], method)));
            AddPropertyGetterTranslator(typeof(Nullable <>), "Value", new GenericMethodCompiler((args, method) => args[0]));
            AddPropertyGetterTranslator(typeof(Nullable <>), "HasValue",
                                        new GenericMethodCompiler(args => new JsBinaryExpression(args[0], BinaryOperatorType.NotEqual, new JsLiteral(null))));
            //AddMethodTranslator(typeof(Enumerable), nameof(Enumerable.Count), lengthMethod, new[] { typeof(IEnumerable) });

            BindingApi.RegisterJavascriptTranslations(this);
            BindingPageInfo.RegisterJavascriptTranslations(this);
            BindingCollectionInfo.RegisterJavascriptTranslations(this);

            // string formatting
            var stringFormatTranslator = new GenericMethodCompiler(
                args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("format").Invoke(args[1], new JsArrayExpression(args.Skip(2)))
                );

            // TODO: string.Format could be two-way
            AddMethodTranslator(typeof(string).GetMethod("Format", new[] { typeof(string), typeof(object) }), stringFormatTranslator);
            AddMethodTranslator(typeof(string).GetMethod("Format", new[] { typeof(string), typeof(object), typeof(object) }), stringFormatTranslator);
            AddMethodTranslator(typeof(string).GetMethod("Format", new[] { typeof(string), typeof(object), typeof(object), typeof(object) }), stringFormatTranslator);
            AddMethodTranslator(typeof(string).GetMethod("Format", new[] { typeof(string), typeof(object[]) }), new GenericMethodCompiler(
                                    args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("format").Invoke(args[1], args[2])
                                    ));
            AddMethodTranslator(typeof(DateTime).GetMethod("ToString", Type.EmptyTypes), new GenericMethodCompiler(
                                    args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingDateToString")
                                    .WithAnnotation(new RequiredRuntimeResourcesBindingProperty(ImmutableArray.Create("globalize")))
                                    .Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance))
                                    ));
            AddMethodTranslator(typeof(DateTime).GetMethod("ToString", new[] { typeof(string) }), new GenericMethodCompiler(
                                    args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingDateToString")
                                    .WithAnnotation(new RequiredRuntimeResourcesBindingProperty(ImmutableArray.Create("globalize")))
                                    .Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance), args[1])
                                    ));
            AddMethodTranslator(typeof(DateTime?).GetMethod("ToString", Type.EmptyTypes), new GenericMethodCompiler(
                                    args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingDateToString")
                                    .WithAnnotation(new RequiredRuntimeResourcesBindingProperty(ImmutableArray.Create("globalize")))
                                    .Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance))
                                    ));

            foreach (var num in ReflectionUtils.NumericTypes.Except(new[] { typeof(char) }))
            {
                AddMethodTranslator(num.GetMethod("ToString", Type.EmptyTypes), new GenericMethodCompiler(
                                        args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingNumberToString")
                                        .WithAnnotation(new RequiredRuntimeResourcesBindingProperty(ImmutableArray.Create("globalize")))
                                        .Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance))
                                        .WithAnnotation(ResultIsObservableAnnotation.Instance)
                                        ));
                AddMethodTranslator(num.GetMethod("ToString", new[] { typeof(string) }), new GenericMethodCompiler(
                                        args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingNumberToString")
                                        .WithAnnotation(new RequiredRuntimeResourcesBindingProperty(ImmutableArray.Create("globalize")))
                                        .Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance), args[1])
                                        .WithAnnotation(ResultIsObservableAnnotation.Instance)
                                        ));
                AddMethodTranslator(typeof(Nullable <>).MakeGenericType(num).GetMethod("ToString", Type.EmptyTypes), new GenericMethodCompiler(
                                        args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingNumberToString")
                                        .WithAnnotation(new RequiredRuntimeResourcesBindingProperty(ImmutableArray.Create("globalize")))
                                        .Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance))
                                        .WithAnnotation(ResultIsObservableAnnotation.Instance)
                                        ));
            }

            AddPropertyGetterTranslator(typeof(Task <>), "Result", new GenericMethodCompiler(args => FunctionalExtensions.ApplyAction(args[0], a => a.RemoveAnnotations(typeof(ViewModelInfoAnnotation)))));

            AddMethodTranslator(typeof(DotvvmBindableObject).GetMethods(BindingFlags.Instance | BindingFlags.Public).Single(m => m.Name == "GetValue" && !m.ContainsGenericParameters), new GenericMethodCompiler(
                                    args => {
                var dotvvmproperty = ((DotvvmProperty)((JsLiteral)args[1]).Value);
                return(JavascriptTranslationVisitor.TranslateViewModelProperty(args[0], (MemberInfo)dotvvmproperty.PropertyInfo ?? dotvvmproperty.PropertyType.GetTypeInfo(), name: dotvvmproperty.Name));
            }
                                    ));
        }
Esempio n. 10
0
 private ResolvedBinding[] GetLiteralBindings(ResolvedContentNode node) =>
 (from c in node.Content.SelectRecursively(c => c.Content)
      where c.Metadata.Type == typeof(Literal)
  let text = FunctionalExtensions.GetValueOrDefault(c.Properties, Literal.TextProperty)
                 where text is ResolvedPropertyBinding
             select((ResolvedPropertyBinding)text).Binding).ToArray();
Esempio n. 11
0
        public void AddDefaultMethodTranslators()
        {
            var lengthMethod = new GenericMethodCompiler(a => a[0].Member("length"));

            AddPropertyGetterTranslator(typeof(Array), nameof(Array.Length), lengthMethod);
            AddPropertyGetterTranslator(typeof(ICollection), nameof(ICollection.Count), lengthMethod);
            AddPropertyGetterTranslator(typeof(ICollection <>), nameof(ICollection.Count), lengthMethod);
            AddPropertyGetterTranslator(typeof(string), nameof(string.Length), lengthMethod);
            AddMethodTranslator(typeof(Enumerable), "Count", parameterCount: 1, translator: new GenericMethodCompiler(a => a[1].Member("length")));
            AddMethodTranslator(typeof(object), "ToString", new GenericMethodCompiler(
                                    a => new JsIdentifierExpression("String").Invoke(a[0]), (m, c, a) => ToStringCheck(c)), 0);
            AddMethodTranslator(typeof(Convert), "ToString", new GenericMethodCompiler(
                                    a => new JsIdentifierExpression("String").Invoke(a[1]), (m, c, a) => ToStringCheck(a[0])), 1, true);

            JsExpression indexer(JsExpression[] args, MethodInfo method) =>
            BuildIndexer(args[0], args[1], method.DeclaringType.GetProperty("Item"));

            AddMethodTranslator(typeof(IList), "get_Item", new GenericMethodCompiler(indexer));
            AddMethodTranslator(typeof(IList <>), "get_Item", new GenericMethodCompiler(indexer));
            AddMethodTranslator(typeof(List <>), "get_Item", new GenericMethodCompiler(indexer));
            AddMethodTranslator(typeof(Enumerable).GetMethod("ElementAt", BindingFlags.Static | BindingFlags.Public), new GenericMethodCompiler((args, method) =>
                                                                                                                                                BuildIndexer(args[1], args[2], method)));
            AddPropertyGetterTranslator(typeof(Nullable <>), "Value", new GenericMethodCompiler((args, method) => args[0]));
            AddPropertyGetterTranslator(typeof(Nullable <>), "HasValue",
                                        new GenericMethodCompiler(args => new JsBinaryExpression(args[0], BinaryOperatorType.NotEqual, new JsLiteral(null))));
            //AddMethodTranslator(typeof(Enumerable), nameof(Enumerable.Count), lengthMethod, new[] { typeof(IEnumerable) });

            AddMethodTranslator(typeof(Api), nameof(Api.RefreshOnChange),
                                new GenericMethodCompiler(a =>
                                                          new JsIdentifierExpression("dotvvm").Member("apiRefreshOn").Invoke(
                                                              a[1].WithAnnotation(ShouldBeObservableAnnotation.Instance),
                                                              a[2].EnsureObservableWrapped())
                                                          .WithAnnotation(a[1].Annotation <ResultIsObservableAnnotation>())
                                                          .WithAnnotation(a[1].Annotation <ViewModelInfoAnnotation>())
                                                          .WithAnnotation(a[1].Annotation <MayBeNullAnnotation>())
                                                          ));
            AddMethodTranslator(typeof(Api), nameof(Api.RefreshOnEvent),
                                new GenericMethodCompiler(a =>
                                                          new JsIdentifierExpression("dotvvm").Member("apiRefreshOn").Invoke(
                                                              a[1].WithAnnotation(ShouldBeObservableAnnotation.Instance),
                                                              new JsIdentifierExpression("dotvvm").Member("eventHub").Member("get").Invoke(a[2]))
                                                          .WithAnnotation(a[1].Annotation <ResultIsObservableAnnotation>())
                                                          .WithAnnotation(a[1].Annotation <ViewModelInfoAnnotation>())
                                                          .WithAnnotation(a[1].Annotation <MayBeNullAnnotation>())
                                                          ));
            BindingPageInfo.RegisterJavascriptTranslations(this);
            BindingCollectionInfo.RegisterJavascriptTranslations(this);

            // string formatting
            var stringFormatTranslator = new GenericMethodCompiler(
                args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("format").Invoke(args[1], new JsArrayExpression(args.Skip(2)))
                );

            // TODO: string.Format could be two-way
            AddMethodTranslator(typeof(string).GetMethod("Format", new[] { typeof(string), typeof(object) }), stringFormatTranslator);
            AddMethodTranslator(typeof(string).GetMethod("Format", new[] { typeof(string), typeof(object), typeof(object) }), stringFormatTranslator);
            AddMethodTranslator(typeof(string).GetMethod("Format", new[] { typeof(string), typeof(object), typeof(object), typeof(object) }), stringFormatTranslator);
            AddMethodTranslator(typeof(string).GetMethod("Format", new[] { typeof(string), typeof(object[]) }), new GenericMethodCompiler(
                                    args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("format").Invoke(args[1], args[2])
                                    ));
            AddMethodTranslator(typeof(DateTime).GetMethod("ToString", Type.EmptyTypes), new GenericMethodCompiler(
                                    args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingDateToString").Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance))
                                    ));
            AddMethodTranslator(typeof(DateTime).GetMethod("ToString", new[] { typeof(string) }), new GenericMethodCompiler(
                                    args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingDateToString").Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance), args[1])
                                    ));
            AddMethodTranslator(typeof(DateTime?).GetMethod("ToString", Type.EmptyTypes), new GenericMethodCompiler(
                                    args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingDateToString").Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance))
                                    ));

            foreach (var num in ReflectionUtils.NumericTypes.Except(new[] { typeof(char) }))
            {
                AddMethodTranslator(num.GetMethod("ToString", Type.EmptyTypes), new GenericMethodCompiler(
                                        args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingNumberToString")
                                        .Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance))
                                        .WithAnnotation(ResultIsObservableAnnotation.Instance)
                                        ));
                AddMethodTranslator(num.GetMethod("ToString", new[] { typeof(string) }), new GenericMethodCompiler(
                                        args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingNumberToString")
                                        .Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance), args[1])
                                        .WithAnnotation(ResultIsObservableAnnotation.Instance)
                                        ));
                AddMethodTranslator(typeof(Nullable <>).MakeGenericType(num).GetMethod("ToString", Type.EmptyTypes), new GenericMethodCompiler(
                                        args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingNumberToString")
                                        .Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance))
                                        .WithAnnotation(ResultIsObservableAnnotation.Instance)
                                        ));
            }

            AddPropertyGetterTranslator(typeof(Task <>), "Result", new GenericMethodCompiler(args => FunctionalExtensions.ApplyAction(args[0], a => a.RemoveAnnotations(typeof(ViewModelInfoAnnotation)))));
        }
Esempio n. 12
0
        private void SpendingsChartAddTodayIndicator()
        {
            // Retrieve last spline lines collection
            var splines = FunctionalExtensions.ToList <ChartSeriesPanel>(FindChildren <ChartSeriesPanel>(this.SpendingsChart));
            var currentSpendingSpline = splines.Last();

            // Retrieve last path from the collection
            var paths = currentSpendingSpline.Children.OfType <Path>();
            var todaysSpendingPath = paths.LastOrDefault();

            // Attach to path data property changed callback
            todaysSpendingPath?.RegisterPropertyChangedCallback(Path.DataProperty, (o, dp) =>
            {
                const int ellipseSize   = 6;
                const int ellipseRadius = ellipseSize / 2;

                // Retrieve new data as path geometry
                var pathGeometry = todaysSpendingPath.Data as PathGeometry;
                if (pathGeometry == null)
                {
                    return;
                }

                // Retrieve last segment
                if (!(pathGeometry.Figures?.Any() ?? false) ||
                    !(pathGeometry.Figures[0].Segments?.Any() ?? false))
                {
                    return;
                }
                var segment = pathGeometry.Figures[0].Segments[0] as BezierSegment;
                if (segment == null)
                {
                    return;
                }

                // Calculate position from last point of curve and subtract radius of ellipse
                var positionX = segment.Point3.X - ellipseRadius;
                var positionY = segment.Point3.Y - ellipseRadius;

                // Instantiate new ellipse for indicating path end
                var ellipse = new Ellipse
                {
                    Fill            = new SolidColorBrush(Colors.DimGray),
                    Width           = ellipseSize,
                    Height          = ellipseSize,
                    RenderTransform = new ScaleTransform
                    {
                        CenterX = ellipseRadius,
                        CenterY = ellipseRadius
                    }
                };

                // Position ellipse on the chart
                Canvas.SetTop(ellipse, positionY);
                Canvas.SetLeft(ellipse, positionX);

                // Remove previously added ellipses
                var previouslyAdded    = currentSpendingSpline.Children.OfType <Ellipse>().ToList();
                var wasEllipseAnimated = previouslyAdded.Any();
                foreach (var oldEllipse in previouslyAdded)
                {
                    currentSpendingSpline.Children.Remove(oldEllipse);
                }

                // Add ellipse to the chart
                currentSpendingSpline.Children.Add(ellipse);

                // Assing animation target and animate
                if (!wasEllipseAnimated)
                {
                    this.BoundEasingStoryboard.Stop();
                    Storyboard.SetTarget(this.BoundEasingStoryboard, ellipse);
                    this.BoundEasingStoryboard.Begin();
                }
            });
        }