text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.Versioning;

using NuGet;

using Duality.IO;
using Duality.Editor.Properties;
using Duality.Editor.Forms;
using Duality.Editor.PackageManagement.Internal;

namespace Duality.Editor.PackageManagement
{
	/// <summary>
	/// Allows to install, uninstall, update and query local and remote Duality packages.
	/// </summary>
	public class PackageManager
	{
		public const string DualityTag  = "Duality";
		public const string PluginTag   = "Plugin";
		public const string SampleTag   = "Sample";
		public const string CoreTag     = "Core";
		public const string EditorTag   = "Editor";
		public const string LauncherTag = "Launcher";

		/// <summary>
		/// A list of package names that are considered "core" Duality packages.
		/// If none of these show up anywhere in the deep dependency graph of a Duality package,
		/// it will be assumed that dependencies are simply not specified properly.
		/// </summary>
		private static readonly string[] DualityPackageNames = new string[]
		{
			"AdamsLair.Duality",
			"AdamsLair.Duality.Editor",
			"AdamsLair.Duality.Launcher"
		};

		private PackageSetup              setup        = new PackageSetup();
		private PackageManagerEnvironment env          = null;
		private PackageCache              cache        = null;

		private Dictionary<PackageName,bool>  licenseAccepted      = new Dictionary<PackageName,bool>();
		private List<PackageDependencyWalker> dependencyWalkerPool = new List<PackageDependencyWalker>();
		private object                        dependencyWalkerLock = new object();

		private NuGetTargetedPackageManager manager    = null;
		private NuGet.IPackageRepository   repository = null;
		private PackageManagerLogger       logger     = null;

		public event EventHandler<PackageLicenseAgreementEventArgs> PackageLicenseAcceptRequired = null;
		public event EventHandler<PackageEventArgs>                 PackageInstalled             = null;
		public event EventHandler<PackageEventArgs>                 PackageUninstalled           = null;

		/// <summary>
		/// [GET] Whether the local <see cref="PackageSetup"/> and the actually installed packages
		/// are currently out of sync.
		/// </summary>
		public bool IsPackageSyncRequired
		{
			get
			{
				IPackage[] allInstalledPackages = this.manager
					.LocalRepository
					.GetPackages()
					.ToArray();

				// Do we have installed packages that are not registered, i.e. need to be uninstalled?
				foreach (IPackage package in allInstalledPackages)
				{
					if (!IsDualityPackage(package)) continue;
					if (this.setup.GetPackage(package.Id, package.Version.Version) == null)
						return true;
				}

				// Do we have registered packages that are not installed or don't have a specific version?
				// Also, are any of them not actually installed yet?
				foreach (LocalPackage package in this.setup.Packages)
				{
					if (package.Id == null) return true;
					if (package.Version == null) return true;
					if (!allInstalledPackages.Any(n =>
						n.Id == package.Id &&
						n.Version == new SemanticVersion(package.Version)))
						return true;
				}

				return false;
			}
		}
		/// <summary>
		/// [GET] The local file system environment in which this <see cref="PackageManager"/> operates.
		/// </summary>
		public PackageManagerEnvironment LocalEnvironment
		{
			get { return this.env; }
		}
		/// <summary>
		/// [GET / SET] A data class representing the local package setup. Do not change these
		/// values manually, but use <see cref="PackageManager"/> API instead.
		/// </summary>
		public PackageSetup LocalSetup
		{
			get { return this.setup; }
		}

		public PackageManager() : this(new PackageManagerEnvironment(null)) { }
		public PackageManager(string rootPath) : this(new PackageManagerEnvironment(rootPath)) { }
		public PackageManager(PackageManagerEnvironment workEnvironment) : this(workEnvironment, null) { }
		public PackageManager(PackageManagerEnvironment workEnvironment, PackageSetup packageSetup)
		{
			// If no external package setup is provided, load it from the config file
			if (packageSetup == null)
			{
				string configFilePath = workEnvironment.ConfigFilePath;
				if (!File.Exists(configFilePath))
				{
					packageSetup = new PackageSetup();
					packageSetup.Save(configFilePath);
				}
				else
				{
					try
					{
						packageSetup = PackageSetup.Load(configFilePath);
					}
					catch (Exception e)
					{
						Logs.Editor.WriteError(
							"Failed to load PackageManager config file '{0}': {1}",
							configFilePath,
							LogFormat.Exception(e));
					}
				}
			}

			// Assign work environment and package setup to work with
			this.env = workEnvironment;
			this.setup = packageSetup;

			// Create internal package management objects
			IPackageRepository[] repositories = this.setup.RepositoryUrls
				.Select(x => this.CreateRepository(x))
				.Where(x => x != null)
				.ToArray();
			this.repository = new AggregateRepository(repositories);
			this.manager = new NuGetTargetedPackageManager(
				new FrameworkName(".NETFramework", new Version(4, 5, 2)),
				this.repository,
				this.env.RepositoryPath);
			this.manager.PackageInstalling += this.manager_PackageInstalling;
			this.manager.PackageInstalled += this.manager_PackageInstalled;
			this.manager.PackageUninstalled += this.manager_PackageUninstalled;
			this.cache = new PackageCache(
				this.repository,
				repositories.OfType<LocalPackageRepository>().Any() || repositories.OfType<LazyLocalPackageRepository>().Any());

			this.logger = new PackageManagerLogger();
			this.manager.Logger = this.logger;

			// Retrieve information about local packages
			this.RetrieveLocalPackageInfo();
		}

		/// <summary>
		/// Installs the specified package if it wasn't installed yet and synchronizes
		/// the registered Duality package version number with the one that is present
		/// in the local cache.
		/// </summary>
		/// <param name="localPackage"></param>
		public void VerifyPackage(LocalPackage localPackage)
		{
			Version oldPackageVersion = localPackage.Version;

			// Determine the exact version that will be installed
			PackageInfo packageInfo = this.GetPackage(localPackage.Name);
			if (packageInfo == null)
			{
				throw new Exception(string.Format(
					"Can't resolve version of package '{0}'. There seems to be no compatible version available.",
					localPackage.Id));
			}

			// Prepare a listener to determine whether we actually installed something
			EventHandler<PackageOperationEventArgs> installListener = null;
			bool packageInstalled = false;
			installListener = delegate(object sender, PackageOperationEventArgs args)
			{
				if (args.Package.Id == localPackage.Id)
				{
					packageInstalled = true;
				}
			};

			// Install the package. Won't do anything if the package is already installed.
			this.manager.PackageInstalled += installListener;
			this.InstallPackage(localPackage.Name, true);
			this.manager.PackageInstalled -= installListener;

			// If we didn't install anything, that package was already in the local repo.
			// Update the local setup to match its specific version.
			if (!packageInstalled && oldPackageVersion == null)
			{
				// Add the explicit version to the PackageConfig file
				this.setup.Packages.RemoveAll(p => p.Id == packageInfo.Id);
				this.setup.Packages.Add(new LocalPackage(packageInfo));
			}

			// In case we've just retrieved an explicit version for the first time, save the config file.
			if (oldPackageVersion == null)
			{
				this.setup.Save(this.env.ConfigFilePath);
			}
		}
		/// <summary>
		/// Uninstalls all Duality packages that are installed, but not registered. This
		/// usually happens when a user manually edits the package config file and either
		/// removes package entries explicitly, or changes their version numbers.
		///
		/// Due to the nature of this operation, it is possible that package dependencies
		/// are removed even though they might still be required by some installed packages.
		/// To make sure this state doesn't persist, it is recommended to perform a package
		/// verification step afterwards, which will re-install dependencies that might have
		/// been accidentally removed.
		/// </summary>
		public void UninstallNonRegisteredPackages()
		{
			IPackage[] allInstalledPackages = this.manager
				.LocalRepository
				.GetPackages()
				.ToArray();
			LocalPackage[] registeredPackages = this.setup.Packages
				.ToArray();

			foreach (IPackage package in allInstalledPackages)
			{
				// Skip non-Duality packages. They're not registered anyway and not expected to.
				if (!IsDualityPackage(package)) continue;

				// Skip packages that are registered in the exact same version
				bool isRegistered = registeredPackages.Any(p =>
					p.Id == package.Id &&
					p.Version == package.Version.Version);
				if (isRegistered) continue;

				// Uninstall all others with a force-uninstall. If we happen to remove
				// a package that is actually still needed, an additional package verification
				// step afterwards will fix this.
				this.UninstallPackage(
					new PackageName(package.Id, package.Version.Version),
					true);
			}
		}

		/// <summary>
		/// Installs the specified package.
		/// </summary>
		/// <param name="packageName"></param>
		public void InstallPackage(PackageName packageName)
		{
			this.InstallPackage(packageName, false);
		}
		private void InstallPackage(PackageName packageName, bool skipLicense)
		{
			NuGet.IPackage installPackage = this.cache.GetNuGetPackage(packageName);
			if (installPackage == null)
			{
				throw new InvalidOperationException(string.Format(
					"Unable to install package '{0}', because no matching package could be found.",
					packageName));
			}

			// Check license terms
			if (!skipLicense && !this.CheckDeepLicenseAgreements(installPackage))
			{
				return;
			}

			Logs.Editor.Write("Installing package '{0}'...", packageName);
			Logs.Editor.PushIndent();
			try
			{
				// Request NuGet to install the package
				this.manager.InstallPackage(installPackage, false, false);
			}
			finally
			{
				Logs.Editor.PopIndent();
			}
		}
		/// <summary>
		/// Uninstalls the specified package.
		/// </summary>
		/// <param name="packageName"></param>
		public void UninstallPackage(PackageName packageName)
		{
			this.UninstallPackage(packageName, false);
		}
		private void UninstallPackage(PackageName packageName, bool force)
		{
			Logs.Editor.Write("Uninstalling package '{0}'...", packageName);
			Logs.Editor.PushIndent();
			try
			{
				// Find the local package that we'll uninstall
				NuGet.IPackage uninstallPackage = this.manager.LocalRepository
					.FindPackagesById(packageName.Id)
					.FirstOrDefault(p => p.Version.Version == packageName.Version);
				if (uninstallPackage == null) return;

				// Find all dependencies of the package we want to uninstall
				PackageName uninstallPackageName = new PackageName(uninstallPackage.Id, uninstallPackage.Version.Version);
				PackageInfo uninstallPackageInfo = this.GetPackage(uninstallPackageName);
				List<PackageInfo> uninstallDependencies = new List<PackageInfo>();
				if (uninstallPackageInfo != null)
				{
					PackageDependencyWalker dependencyWalker = this.RentDependencyWalker();
					dependencyWalker.IgnorePackage("NETStandard.Library"); // Avoid dependency explosion, treat as opaque
					dependencyWalker.WalkGraph(uninstallPackageInfo);
					uninstallDependencies.AddRange(dependencyWalker.VisitedPackages);
					uninstallDependencies.RemoveAll(package => package.Id == uninstallPackageInfo.Id);
					this.ReturnDependencyWalker(ref dependencyWalker);
				}

				// Filter out all dependencies that are used by other Duality packages
				foreach (LocalPackage otherPackage in this.LocalSetup.Packages)
				{
					if (otherPackage.Id == uninstallPackage.Id) continue;

					PackageInfo otherPackageInfo = otherPackage.Info ?? this.GetPackage(otherPackage.Name);
					if (otherPackageInfo == null) continue;

					PackageDependencyWalker dependencyWalker = this.RentDependencyWalker();
					dependencyWalker.IgnorePackage(uninstallPackage.Id);
					dependencyWalker.IgnorePackage("NETStandard.Library"); // Avoid dependency explosion, treat as opaque
					dependencyWalker.WalkGraph(otherPackageInfo);
					foreach (PackageInfo dependency in dependencyWalker.VisitedPackages)
					{
						// Don't check versions, as dependencies are usually not resolved
						// with an exact version match.
						uninstallDependencies.RemoveAll(item => item.Id == dependency.Id);
					}
					this.ReturnDependencyWalker(ref dependencyWalker);
				}

				// Uninstall the package itself
				this.manager.UninstallPackage(
					uninstallPackage,
					force);

				// Uninstall its dependencies that are no longer used, in reverse dependency order
				// to avoid stumbling over dependencies that they might have between each other.
				this.OrderByDependencies(uninstallDependencies);
				uninstallDependencies.Reverse();
				foreach (PackageInfo package in uninstallDependencies)
				{
					List<NuGet.IPackage> matchingNuGetPackages = this.manager.LocalRepository
						.FindPackagesById(package.Id)
						.ToList();

					foreach (NuGet.IPackage nugetPackage in matchingNuGetPackages)
					{
						this.manager.UninstallPackage(nugetPackage, force, false);
					}
				}
			}
			finally
			{
				Logs.Editor.PopIndent();
			}
		}
		/// <summary>
		/// Determines whether the specified package can be uninstalled. Returns
		/// false when other packages still depend on it.
		/// </summary>
		/// <param name="package"></param>
		/// <returns></returns>
		[DebuggerNonUserCode]
		public bool CanUninstallPackage(PackageName packageName)
		{
			NuGet.IPackage uninstallPackage = this.manager.LocalRepository
				.FindPackagesById(packageName.Id)
				.FirstOrDefault(p => p.Version.Version == packageName.Version);
			if (uninstallPackage == null) return false;

			bool allowed = true;
			this.manager.WhatIf = true;
			this.manager.Logger = null;
			try
			{
				this.manager.UninstallPackage(
					uninstallPackage,
					false,
					true);
			}
			catch (Exception)
			{
				allowed = false;
			}
			this.manager.Logger = this.logger;
			this.manager.WhatIf = false;
			return allowed;
		}
		/// <summary>
		/// Updates the specified package to the latest available version.
		/// </summary>
		/// <param name="packageName"></param>
		public void UpdatePackage(PackageName packageName)
		{
			if (!this.manager.LocalRepository.FindPackagesById(packageName.Id).Any())
			{
				throw new InvalidOperationException(string.Format(
					"Can't update package '{0}', because it is not installed.",
					packageName));
			}

			NuGet.IPackage latestPackage = this.cache.GetNuGetPackage(packageName.VersionInvariant);
			if (latestPackage == null)
			{
				throw new InvalidOperationException(string.Format(
					"Unable to update package '{0}', because no matching package could be found.",
					packageName));
			}

			// Check license terms
			if (!this.CheckDeepLicenseAgreements(latestPackage))
			{
				return;
			}

			Logs.Editor.Write("Updating package '{0}'...", packageName);
			Logs.Editor.PushIndent();
			try
			{
				this.manager.UpdatePackage(latestPackage, true, false);
			}
			finally
			{
				Logs.Editor.PopIndent();
			}
		}

		/// <summary>
		/// Starts applying any pending package updates and returns true when it is required
		/// to shut down the current editor instance in order to complete them.
		/// </summary>
		/// <param name="restartEditor">
		/// Whether the current editor instance should be restarted after the update has been applied.
		/// </param>
		/// <returns></returns>
		public bool ApplyUpdate(bool restartEditor = true)
		{
			if (!File.Exists(this.env.UpdateFilePath)) return false;

			Logs.Editor.Write("Applying package update...");
			Logs.Editor.PushIndent();
			try
			{
				// Manually perform update operations on the updater itself
				try
				{
					Logs.Editor.Write("Preparing updater...");
					PackageUpdateSchedule schedule = this.PrepareUpdateSchedule();
					schedule.ApplyUpdaterChanges(this.env.UpdaterExecFilePath);
					this.SaveUpdateSchedule(schedule);
				}
				catch (Exception e)
				{
					Logs.Editor.WriteError(
						"Can't update '{0}', because an error occurred: {1}",
						this.env.UpdaterExecFilePath,
						LogFormat.Exception(e));
					return false;
				}

				// Run the updater application
				Logs.Editor.Write("Running updater...");
				Process.Start(this.env.UpdaterExecFilePath, string.Format("\"{0}\" \"{1}\" \"{2}\"",
					this.env.UpdateFilePath,
					restartEditor ? typeof(DualityEditorApp).Assembly.Location : "",
					restartEditor ? Environment.CurrentDirectory : ""));
			}
			finally
			{
				Logs.Editor.PopIndent();
			}

			return true;
		}

		/// <summary>
		/// Clears the internal cache for remote repository packages, allowing
		/// to retrieve updated information about the latest available packages
		/// and package versions.
		/// </summary>
		public void ClearCache()
		{
			this.cache.Clear();
		}
		/// <summary>
		/// Enumerates the latest versions of all available Duality packages from
		/// the remote repository.
		/// </summary>
		/// <returns></returns>
		public IEnumerable<PackageInfo> GetLatestDualityPackages()
		{
			return this.cache.GetLatestDualityPackages();
		}
		/// <summary>
		/// Retrieves detailed information about the specified package from the
		/// local or remote repository.
		/// </summary>
		/// <param name="name"></param>
		/// <returns></returns>
		public PackageInfo GetPackage(PackageName name)
		{
			return this.cache.GetPackage(name);
		}

		/// <summary>
		/// Enumerates all target packages for local installs that could be updated.
		/// </summary>
		/// <returns></returns>
		public IEnumerable<PackageInfo> GetUpdatablePackages()
		{
			List<PackageInfo> updatePackages = new List<PackageInfo>();
			LocalPackage[] targetPackages = this.setup.Packages.ToArray();
			for (int i = 0; i < targetPackages.Length; i++)
			{
				PackageInfo update = this.GetPackage(targetPackages[i].Name.VersionInvariant);
				if (update.Version <= targetPackages[i].Version) continue;
				updatePackages.Add(update);
			}
			return updatePackages;
		}
		/// <summary>
		/// Determines compatibility between the current package installs and the specified target package.
		/// Works for both updates and new installs.
		/// </summary>
		/// <param name="target"></param>
		/// <returns></returns>
		public PackageCompatibility GetCompatibilityLevel(PackageInfo target)
		{
			// If the target package is already installed in the matching version, assume compatibility
			if (this.setup.GetPackage(target.Id, target.Version) != null)
				return PackageCompatibility.Definite;

			// Determine all packages that might be updated or installed
			PackageDependencyWalker dependencyWalker = this.RentDependencyWalker();
			dependencyWalker.IgnorePackage("NETStandard.Library"); // Avoid dependency explosion, doesn't matter for Duality compatibility anyway
			dependencyWalker.WalkGraph(target);
			List<PackageInfo> touchedPackages = dependencyWalker.VisitedPackages.ToList();
			this.ReturnDependencyWalker(ref dependencyWalker);

			// Verify properly specified dependencies for Duality packages
			if (target.IsDualityPackage)
			{
				// If none of the targets deep dependencies is anyhow related to Duality, assume they're incomplete and potentially incompatible
				bool anyDualityDependency = false;
				foreach (PackageInfo package in touchedPackages)
				{
					if (DualityPackageNames.Any(name => string.Equals(name, package.Id)))
					{
						anyDualityDependency = true;
						break;
					}
				}
				if (!anyDualityDependency)
					return PackageCompatibility.None;
			}

			// Generate a mapping to already installed packages
			Dictionary<PackageInfo,LocalPackage> localMap = new Dictionary<PackageInfo,LocalPackage>();
			foreach (PackageInfo package in touchedPackages)
			{
				LocalPackage local = this.setup.GetPackage(package.Id);
				if (local == null) continue;

				localMap.Add(package, local);
			}

			// Determine the maximum version difference between target and installed
			PackageCompatibility compatibility = PackageCompatibility.Definite;
			foreach (var pair in localMap)
			{
				Version targetVersion = pair.Key.Version;
				Version localVersion = pair.Value.Version;

				if (localVersion.Major != targetVersion.Major)
					compatibility = compatibility.Combine(PackageCompatibility.Unlikely);
				else if (localVersion.Minor != targetVersion.Minor)
					compatibility = compatibility.Combine(PackageCompatibility.Likely);
			}

			return compatibility;
		}

		/// <summary>
		/// Sorts the specified list of packages according to their dependencies, guaranteeing that no package
		/// is listed before its dependencies. Use this to determine the order of batch updates and installs
		/// to prevent conflicts from having different versions of the same packages.
		/// </summary>
		public void OrderByDependencies(IList<PackageInfo> packages)
		{
			if (packages.Count < 2) return;

			// Determine the number of deep dependencies for each package
			PackageDependencyWalker dependencyWalker = this.RentDependencyWalker();
			dependencyWalker.IgnorePackage("NETStandard.Library"); // Avoid dependency explosion, treat as opaque
			dependencyWalker.WalkGraph(packages);

			// Sort packages according to their deep dependency counts
			packages.StableSort((a, b) =>
			{
				int countA = (a == null) ? 0 : dependencyWalker.GetDependencyCount(a.Name);
				int countB = (b == null) ? 0 : dependencyWalker.GetDependencyCount(b.Name);
				return countA - countB;
			});

			this.ReturnDependencyWalker(ref dependencyWalker);
		}
		/// <summary>
		/// Sorts the specified list of packages according to their dependencies, guaranteeing that no package
		/// is listed before its dependencies. Use this to determine the order of batch updates and installs
		/// to prevent conflicts from having different versions of the same packages.
		/// </summary>
		public void OrderByDependencies(IList<LocalPackage> packages)
		{
			// Map each list entry to its PackageInfo
			PackageInfo[] localInfo = packages
				.Select(p => p.Info ?? this.GetPackage(p.Name))
				.NotNull()
				.ToArray();

			// Sort the mapped list
			this.OrderByDependencies(localInfo);

			// Now sort the original list to match the sorted mapped list
			LocalPackage[] originalPackages = packages.ToArray();
			int nonSortedCount = 0;
			for (int i = 0; i < originalPackages.Length; i++)
			{
				LocalPackage localPackage = originalPackages[i];

				int newIndex = localInfo.IndexOfFirst(p => p.Id == localPackage.Id && p.Version == localPackage.Version);
				if (newIndex == -1)
					newIndex = localInfo.IndexOfFirst(p => p.Id == localPackage.Id);

				// Unresolved packages are always last in the sorted list
				if (newIndex == -1)
				{
					newIndex = packages.Count - nonSortedCount - 1;
					nonSortedCount++;
				}

				packages[newIndex] = localPackage;
			}
		}

		private void RetrieveLocalPackageInfo()
		{
			foreach (LocalPackage setupItem in this.setup.Packages)
			{
				if (setupItem.Version == null) continue;
				if (string.IsNullOrEmpty(setupItem.Id)) continue;

				foreach (NuGet.IPackage localPackage in this.manager.LocalRepository.FindPackagesById(setupItem.Id))
				{
					if (localPackage.Version.Version != setupItem.Version) continue;

					setupItem.Info = new PackageInfo(localPackage);
					break;
				}
			}
		}
		private IPackageRepository CreateRepository(string repositoryUrl)
		{
			if (string.IsNullOrWhiteSpace(repositoryUrl))
				return null;

			try
			{
				string schemeName = null;
				if (repositoryUrl.Contains(Uri.SchemeDelimiter))
				{
					schemeName = repositoryUrl.Split(new[] { Uri.SchemeDelimiter }, StringSplitOptions.RemoveEmptyEntries)[0];
				}

				if (schemeName != null && Uri.CheckSchemeName(schemeName))
					repositoryUrl = new Uri(repositoryUrl).AbsoluteUri;
				else
					repositoryUrl = Path.GetFullPath(Path.Combine(this.env.RootPath, repositoryUrl));
			}
			catch (UriFormatException)
			{
				Logs.Editor.WriteError("NuGet repository URI '{0}' has an incorrect format and will be skipped.", repositoryUrl);
				return null;
			}

			return PackageRepositoryFactory.Default.CreateRepository(repositoryUrl);
		}

		/// <summary>
		/// Rents a pooled <see cref="PackageDependencyWalker"/> instance, or allocates a new one when required.
		/// Not returning a rented instance will harm efficiency, but not cause a leak.
		/// </summary>
		/// <returns></returns>
		private PackageDependencyWalker RentDependencyWalker()
		{
			lock (this.dependencyWalkerLock)
			{
				if (this.dependencyWalkerPool.Count == 0)
				{
					return new PackageDependencyWalker(this.GetPackage);
				}
				else
				{
					int lastWalkerIndex = this.dependencyWalkerPool.Count - 1;
					PackageDependencyWalker walker = this.dependencyWalkerPool[lastWalkerIndex];
					this.dependencyWalkerPool.RemoveAt(lastWalkerIndex);
					return walker;
				}
			}
		}
		/// <summary>
		/// Returns a previously rented <see cref="PackageDependencyWalker"/> instance, and nullifies the
		/// provided reference to it afterwards to avoid further use.
		/// </summary>
		/// <param name="walker"></param>
		private void ReturnDependencyWalker(ref PackageDependencyWalker walker)
		{
			walker.Clear();
			lock (this.dependencyWalkerLock)
			{
				this.dependencyWalkerPool.Add(walker);
				walker = null;
			}
		}

		private bool CheckDeepLicenseAgreements(NuGet.IPackage package)
		{
			PackageDependencyWalker dependencyWalker = this.RentDependencyWalker();
			dependencyWalker.IgnorePackage("NETStandard.Library"); // Avoid dependency explosion, doesn't require license acceptance anyway
			dependencyWalker.WalkGraph(new PackageName(package.Id, package.Version.Version));

			List<PackageInfo> packageGraph = dependencyWalker.VisitedPackages.ToList();
			List<NuGet.IPackage> installedPackages = this.manager.LocalRepository.GetPackages().ToList();

			this.ReturnDependencyWalker(ref dependencyWalker);

			foreach (PackageInfo visitedPackage in packageGraph)
			{
				// Skip the ones that are already installed
				if (installedPackages.Any(installed =>
					installed.Id == visitedPackage.Id &&
					installed.Version.Version >= visitedPackage.Version))
					continue;

				if (!this.CheckLicenseAgreement(visitedPackage))
					return false;
			}

			return true;
		}
		private bool CheckLicenseAgreement(PackageInfo package)
		{
			if (package.RequireLicenseAcceptance)
			{
				// On the very first install, do not display additional license agreement dialogs
				// because all the packages being installed are the default ones.
				if (this.setup.IsFirstInstall)
					return true;

				bool agreed;
				if (!this.licenseAccepted.TryGetValue(package.Name, out agreed) || !agreed)
				{
					PackageLicenseAgreementEventArgs args = new PackageLicenseAgreementEventArgs(
						package.Name,
						package.LicenseUrl,
						package.RequireLicenseAcceptance);

					if (this.PackageLicenseAcceptRequired != null)
						this.PackageLicenseAcceptRequired(this, args);
					else
						DisplayDefaultLicenseAcceptDialog(args);

					agreed = args.IsLicenseAccepted;
					this.licenseAccepted[package.Name] = agreed;
				}

				if (!agreed)
				{
					return false;
				}
			}

			return true;
		}

		private PackageUpdateSchedule PrepareUpdateSchedule()
		{
			// Load existing update schedule in order to extend it
			string updateFilePath = this.env.UpdateFilePath;
			PackageUpdateSchedule updateSchedule = null;
			if (File.Exists(updateFilePath))
			{
				try
				{
					updateSchedule = PackageUpdateSchedule.Load(updateFilePath);
				}
				catch (Exception exception)
				{
					updateSchedule = null;
					Logs.Editor.WriteError("Error parsing existing package update schedule '{0}': {1}",
						Path.GetFileName(updateFilePath),
						LogFormat.Exception(exception));
				}
			}

			// If none existed yet, create a fresh update schedule
			if (updateSchedule == null)
				updateSchedule = new PackageUpdateSchedule();

			return updateSchedule;
		}
		private void SaveUpdateSchedule(PackageUpdateSchedule schedule)
		{
			string updateFilePath = this.env.UpdateFilePath;
			schedule.Save(updateFilePath);
		}

		private Dictionary<string,string> CreateFileMapping(NuGet.IPackage package)
		{
			Dictionary<string,string> fileMapping = new Dictionary<string,string>();

			bool isDualityPackage = IsDualityPackage(package);
			bool isPluginPackage = isDualityPackage && package.Tags.Contains(PluginTag);

			string folderFriendlyPackageName = package.Id;
			string binaryBaseDir = this.env.TargetPluginPath;
			string contentBaseDir = this.env.TargetDataPath;
			string sourceBaseDir = Path.Combine(this.env.TargetSourcePath, folderFriendlyPackageName);
			if (!isPluginPackage || !isDualityPackage)
			{
				binaryBaseDir = this.env.RootPath;
				contentBaseDir = this.env.RootPath;
			}

			List<IPackageFile> applicableFiles = new List<IPackageFile>();
			try
			{
				// Separate package files in to framework-dependent lib files and framework-independent
				// non-lib files. Those include content and source files, but also any other folder structure
				// that isn't specifically a lib binary.
				List<IPackageFile> files = package.GetFiles().ToList();
				List<IPackageFile> libFiles = new List<IPackageFile>();
				List<IPackageFile> nonLibFiles = new List<IPackageFile>();
				foreach (IPackageFile file in files)
				{
					string path = file.Path.Replace('/', '\\');
					bool isLibFile = path.StartsWith("lib\\");
					if (isLibFile)
						libFiles.Add(file);
					else
						nonLibFiles.Add(file);
				}
				List<IPackageFile> applicableLibFiles = new List<IPackageFile>();

				// Determine which frameworks are available in this package.
				// Note that due to the NuGet version we're using, .NETStandard target frameworks
				// are unknown and will be returned as "Unsupported, Version 0.0".
				List<FrameworkName> availableFrameworks = libFiles.Select(f => f.TargetFramework).Distinct().ToList();

				// Select the closest matching framework this package has and use all of its files,
				// and none of the others
				FrameworkName matchingFramework = SelectBestFrameworkMatch(availableFrameworks);
				applicableLibFiles.AddRange(libFiles.Where(f => f.TargetFramework == matchingFramework));

				// Check if we have files without a target framework that do not have an equivalent
				// in the files from the selected match. To support legacy packages, we'll use them
				// as a fallback. Packages that do this are for example AdamsLair.OpenTK, AdamsLair.WinForms
				// and others which have a set of explicit root files and a subset of implicit framework files.
				if (matchingFramework != null)
				{
					List<IPackageFile> rootFiles = libFiles.Where(f => f.TargetFramework == null).ToList();
					foreach (IPackageFile file in rootFiles)
					{
						string fileName = Path.GetFileName(file.Path);
						bool hasOverride = applicableLibFiles.Any(f => Path.GetFileName(f.Path) == fileName);
						if (!hasOverride)
						{
							applicableLibFiles.Add(file);
						}
					}
				}

				// Non-lib files (content, source) are treated differently and used as-is, since they are
				// not dependent on any target framework and just carried over.
				applicableFiles.AddRange(applicableLibFiles);
				applicableFiles.AddRange(nonLibFiles);
			}
			catch (DirectoryNotFoundException)
			{
				// We'll run into this exception when uninstalling a package without any files.
				return fileMapping;
			}

			foreach (IPackageFile f in applicableFiles)
			{
				// Determine where the file needs to go
				string targetPath = f.EffectivePath;
				string baseDir = f.Path;
				while (baseDir.Contains(Path.DirectorySeparatorChar) || baseDir.Contains(Path.AltDirectorySeparatorChar))
				{
					baseDir = Path.GetDirectoryName(baseDir);
				}
				if (string.Equals(baseDir, "lib", StringComparison.InvariantCultureIgnoreCase))
					targetPath = Path.Combine(binaryBaseDir, targetPath);
				else if (string.Equals(baseDir, "content", StringComparison.InvariantCultureIgnoreCase))
					targetPath = Path.Combine(contentBaseDir, targetPath);
				else if (string.Equals(baseDir, "source", StringComparison.InvariantCultureIgnoreCase))
				{
					if (targetPath.StartsWith("source") && targetPath.Length > "source".Length)
						targetPath = targetPath.Remove(0, "source".Length + 1);
					targetPath = Path.Combine(sourceBaseDir, targetPath);
				}
				else
					continue;

				// Add a file mapping entry linking target path to package path
				if (fileMapping.ContainsKey(targetPath)) continue;
				fileMapping[targetPath] = f.Path;
			}

			return fileMapping;
		}

		private void OnPackageInstalled(PackageEventArgs args)
		{
			if (this.PackageInstalled != null)
				this.PackageInstalled(this, args);
		}
		private void OnPackageUninstalled(PackageEventArgs args)
		{
			if (this.PackageUninstalled != null)
				this.PackageUninstalled(this, args);
		}

		private void manager_PackageUninstalled(object sender, PackageOperationEventArgs e)
		{
			Logs.Editor.Write("Integrating uninstall of package '{0} {1}'...", e.Package.Id, e.Package.Version);

			// Determine all files that are referenced by a package, and the ones referenced by this one
			IEnumerable<string> localFiles = this.CreateFileMapping(e.Package).Select(p => p.Key);

			// Schedule files for removal
			PackageUpdateSchedule updateSchedule = this.PrepareUpdateSchedule();
			foreach (string packageFile in localFiles)
			{
				// Don't remove any file that is still referenced by a local package
				bool stillInUse = false;
				foreach (NuGet.IPackage localNugetPackage in this.manager.LocalRepository.GetPackages())
				{
					Dictionary<string,string> localMapping = this.CreateFileMapping(localNugetPackage);
					if (localMapping.Any(p => PathHelper.Equals(p.Key, packageFile)))
					{
						stillInUse = true;
						break;
					}
				}
				if (stillInUse) continue;

				// Append the scheduled operation to the updater config file.
				updateSchedule.AppendDeleteFile(packageFile);
				if (Path.GetExtension(packageFile) == ".csproj")
				{
					updateSchedule.AppendSeparateProject(
						packageFile,
						this.env.TargetSolutionPathRelative);
				}
			}
			this.SaveUpdateSchedule(updateSchedule);

			// Update local package configuration file
			PackageName packageName = new PackageName(e.Package.Id, e.Package.Version.Version);
			this.setup.Packages.RemoveAll(p => p.Name == packageName);
			this.setup.Save(this.env.ConfigFilePath);

			this.OnPackageUninstalled(new PackageEventArgs(new PackageName(e.Package.Id, e.Package.Version.Version)));
		}
		private void manager_PackageInstalling(object sender, PackageOperationEventArgs e)
		{
			// Duality does, by design, not support multiple versions of the same package to be
			// installed at the same time. Enforce this constraint by double-checking every install
			// for already installed versions of the same package.
			List<NuGet.IPackage> previousPackages = this.manager.LocalRepository
				.FindPackagesById(e.Package.Id)
				.ToList();
			foreach (NuGet.IPackage package in previousPackages)
			{
				// Installing a newer version? Make sure to uninstall any older versions of it.
				if (package.Version < e.Package.Version)
				{
					this.manager.UninstallPackage(
						package,
						true,
						false);
				}
				// Installing an older version? Cancel the operation. We'll prefer the newer
				// version and if a downgrade is really desired, it should be done by explicitly
				// uninstalling the newer package first.
				else if (package.Version > e.Package.Version)
				{
					e.Cancel = true;
			}
		}
		}
		private void manager_PackageInstalled(object sender, PackageOperationEventArgs e)
		{
			Logs.Editor.Write("Integrating install of package '{0} {1}'...", e.Package.Id, e.Package.Version);

			// Update package entries from local config
			PackageInfo packageInfo = this.GetPackage(new PackageName(e.Package.Id, e.Package.Version.Version));
			if (packageInfo.IsDualityPackage)
			{
				this.setup.Packages.RemoveAll(p => p.Id == e.Package.Id);
				this.setup.Packages.Add(new LocalPackage(packageInfo));
				this.setup.Save(this.env.ConfigFilePath);
			}

			// Schedule files for updating / copying
			PackageUpdateSchedule updateSchedule = this.PrepareUpdateSchedule();
			Dictionary<string,string> fileMapping = this.CreateFileMapping(e.Package);
			foreach (var pair in fileMapping)
			{
				// Don't overwrite files from a newer version of this package with their old one (think of dependencies)
				bool isOldVersion = false;
				foreach (NuGet.IPackage localNugetPackage in this.manager.LocalRepository.GetPackages())
				{
					if (localNugetPackage.Id != e.Package.Id) continue;

					Dictionary<string,string> localMapping = this.CreateFileMapping(localNugetPackage);
					if (localMapping.Any(p => string.Equals(p.Value, pair.Value, StringComparison.InvariantCultureIgnoreCase)))
					{
						if (localNugetPackage.Version > e.Package.Version)
						{
							isOldVersion = true;
							break;
						}
					}
				}
				if (isOldVersion) continue;

				// Append the scheduled operation to the updater config file.
				updateSchedule.AppendCopyFile(Path.Combine(e.InstallPath, pair.Value), pair.Key);
				if (Path.GetExtension(pair.Key) == ".csproj")
				{
					updateSchedule.AppendIntegrateProject(
						pair.Key,
						this.env.TargetSolutionPathRelative,
						this.env.TargetPluginPathRelative);
				}
			}
			this.SaveUpdateSchedule(updateSchedule);

			this.OnPackageInstalled(new PackageEventArgs(new PackageName(e.Package.Id, e.Package.Version.Version)));
		}

		private static bool IsDualityPackage(NuGet.IPackage package)
		{
			return
				package.Tags != null &&
				package.Tags.Contains(DualityTag);
		}
		private static void DisplayDefaultLicenseAcceptDialog(PackageLicenseAgreementEventArgs args)
		{
			LicenseAcceptDialog licenseDialog = new LicenseAcceptDialog
			{
				DescriptionText = string.Format(GeneralRes.LicenseAcceptDialog_PackageDesc, args.PackageName),
				LicenseUrl = args.LicenseUrl
			};

			Form invokeForm = DualityEditorApp.MainForm ?? Application.OpenForms.OfType<Form>().FirstOrDefault();
			DialogResult result = invokeForm.InvokeEx(main => licenseDialog.ShowDialog());
			if (result == DialogResult.OK)
			{
				args.AcceptLicense();
			}
		}

		/// <summary>
		/// From the given list of target frameworks, this methods selects the one that best matches
		/// the one we want for installed packages.
		/// </summary>
		/// <param name="frameworks"></param>
		/// <returns></returns>
		internal static FrameworkName SelectBestFrameworkMatch(List<FrameworkName> frameworks)
		{
			int highestScore = -1;
			FrameworkName bestMatch = null;
			foreach (FrameworkName framework in frameworks)
			{
				int score = GetFrameworkMatchScore(framework);
				if (score > highestScore)
				{
					highestScore = score;
					bestMatch = framework;
				}
			}
			return bestMatch;
		}
		/// <summary>
		/// Determines a score value for the given target framework representing how well it
		/// matches the one we want for installed packages.
		/// </summary>
		/// <param name="framework"></param>
		/// <returns></returns>
		private static int GetFrameworkMatchScore(FrameworkName framework)
		{
			// A null framework is a valid value, as it represents NuGet package files
			// that are not associated with any specific target framework. For legacy
			// reasons, we score them slightly higher than defined, but completely unknown
			// frameworks.
			if (framework == null) return 1;

			// Since the context of our package selection is editor and desktop deployment
			// we'll prefer .NET Framework 4.5 binaries over others.
			switch (framework.Identifier)
			{
				case ".NETPortable":
					if (framework.Profile == "net45+win8+wpa81") // Profile 111
						return 50;
					else if (framework.Profile.Contains("net45"))
						return 49;
					else if (framework.Profile.Contains("net40"))
						return 48;
					else
						return 40;
				case ".NETFramework":
					if (framework.Version == new Version(4, 5))
						return 100;
					else if (framework.Version < new Version(4, 5))
						return 90;
					else
						return 80;
				default:
					return 0;
			}
		}
	}
}

redpajama_set_name: RedPajamaGithub


text:
How To Bet On The Grand National 2022 – The Ultimate Guide
By Dean Ryan |
Sep 28th, 2022 08:53 AM | 13 mins
Welcome to the Bookmakers betting guide to the 2022 Grand National. This article will detail how to bet, when to bet and what you might want to bet on for the 2022 Aintree Grand National, which takes place on the Saturday the 9th April 2022 at 17:15.
The Grand National is truly the race that the world stops to watch, and each year it attracts a global audience as a flagship event in the UK horse racing calendar. The Grand National is famous for being one of the richest handicap prizes in world horse racing, and its iconic fences capture the true essence of jump racing for purists and new fans alike. The race always has a story to tell from small trainer success, to champion jockey stardom, and the horses themselves are nearing the peak or ends of their respective careers that have all led to one race in Liverpool at the famous Aintree racecourse on the second weekend in April.
Whether you are taking in your first Grand National or you're a veteran of the horse racing game, this ultimate Grand National betting guide will give you all you need to know before the off.
Best Horse Racing Bets
When is the Aintree 2022 Grand National?
The Grand National will take place at Aintree on the 9th April 2022 at 17:15. This time slot has been a topic of discussion for some time and aims to give it pride of place among a busy Saturday television audience for Premier League Soccer and other prime-time Saturday events, while giving people who like to place a wager plenty of time to visit the horse racing betting sites.
The Aintree Grand National meeting starts on the Thursday 7th April and lasts for three days in total, with 21 races and 10 Grade 1 contests across the three days. It provides a perfect chance for those that won at the Cheltenham Festival to double up or those that missed out narrowly to take revenge. The gap between the two meetings is often just enough to consider racing at both meetings ideal, and while Fairyhouse and Punchestown still have their big meetings ahead, it takes precedence for many as the place to go with the very best national hunt horses in the UK, Ireland and even France.
How To Place A Bet On The Grand National
There are several ways to bet on the Grand National the most common traditionally has been to venture to your nearest high street bookmaker and place the bet in cash with the friendly staff at the counter. That has become old hat these days, though, with online betting options and massive choice across UK betting sites, Ireland betting sites and, of course, those such as USA sports betting sites.
Bookmakers are keen to take your business, and therefore the markets have become seriously competitive with enhancements and betting offers around the Grand National. Traditionally, a field of this size with 40 runners would have been a perfect race for each way bettors to find a horse at a big price and hope they can come home to win or place in the first four. However, it Is common place now to see up to 6 and 7 places paid on each way bets for the Grand National rather than the first four home, and that makes it far more enjoyable for betting on the race and getting a return for your wager even if you aren't troubling the judge in the finish.
Often, you will find a special sign up offer available if placing your first bet with the best horse racing betting sites on the Grand National itself. Sign up offers and welcome bonuses vary, but Grand National day is special, and you will see the usual bonuses increased around the Aintree meeting that allow you to get more for your spend and or money back for losers or free bets on offer to get involved.
Different Types Of Grand National Bet
Win Single – A bet on a horse to win. One selection and one outcome with this bet. An example would be a £10 bet placed to win on Tiger Roll, and should the horse win, you will be paid at the odds it returns at, the starting price. So, if Tiger Roll was 4/1 and won, you would get £40 back plus your £10 stake and a total of £50 returned for a £10 wager.
Each Way Single – A bet on a horse to win and a bet on the horse to place – known as each way. Be sure to know that this is actually two bets on the same horse. With the Tiger Roll example at 4/1 and using the same stake you would select £5 each way and that would cost a total of £10 stake. £5 to win and £5 to place. If Tiger Roll was to win you would get £20 for the win and your £5 stake back for the win part of the bet. The place part of the bet would also win but usually the place terms mean this is at ¼ of the odds you have taken, so 4/1 becomes 1/1 and the place part would return £5 for the place and £5 for the stake returned. A total of £35 back for the £10 staked. The insurance element here is that if Tiger Roll hadn't won but had placed then you would get back the place part of the bet and a total of £10 returned means you had lost nothing on the wager. Horses at bigger prices would make the place part of an each way bet more attractive. If Tiger Roll was 20/1 and had placed, you would lose the win part of your each way bet, but the place part would be settled at 5/1 and return £25 plus your £5 stake and a total of £30 back means a profit of £20 on a £10 bet would be yours.
Forecast – Selecting two horses in the race to finish first and second. It's hard to land this given the size of the field and the nature of the Grand National, of course, but it's hugely rewarding if you can get it right. You can do a reverse forecast, which is two bets covering the two horses to finish first and second in any order or a straight forecast where you select the winner and second correctly. Last year's forecast dividend in the Grand National paid a whopping £882.66 for a £1 stake and the Exacta even more at £2,053.30 for correctly predicting well fancied Minella Times, ridden by Rachael Blackmore would win and that 100/1 outsider Balko De Flos would be second!
Tricast – Similar to a forecast as you are predicting the horses to finish in the first two, but with a tricast you are also selecting a horse to finish third, so it becomes even harder! The tricast last year at Aintree for the Grand National paid £8,593.94 for a £1 stake, while the trifecta returned a remarkable £35,431.20 with some horse racing betting sites for correctly selecting the first three home.
The Tote Markets are the pooled betting option on UK racing, and the pools for the Grand National are often the biggest of the year and many online betting sites for horse racing will give you direct access to the pools via their websites. This allows you to bet against thousands of others at the course and around the UK and Ireland in a collective market. Here, the money wagered into the pool determines the prices. The favourite and shortest-priced horse will be the most backed, and the prices increase as the horses below are less backed to form a perfect book of odds and betting opinion.
Last year, Minella Times returned an 11/1 winner and paid an exact match on the Tote at £12 return for a £1 stake, but often an outsider with the Tote is a much larger price than with the bookmakers. However, they are strict with the place terms, so you will not likely see a return on an each-way bet with the Tote if your horse narrowly misses out on the traditional first four places, whereas an online bookmaker can pay each way bets up to six, seven and even eight places if you shop around.
Choosing a Grand National Betting Site and Offer
The best horse racing betting sites will cover several aspects of the race in great detail that make betting on the event simple and hopefully rewarding. You will likely receive an enhanced welcome offer where a £10 stake might be matched with a free bet to the same value or a deposit bonus that allows you to deposit £10 but bet with £50 or £60 for the day itself across all the races. Some will offer money back or free bets in return for bad luck like a faller or finishing second, and it pays to check out all the operators here on Bookmakers.com to be sure you are getting the best value for your betting on the Grand National.
Check out the best online bookmakers that you have access to with our betting offers page, but we suggest you consider the following before signing up by clicking one of our links and securing your Grand National offer and registering for a new online account.
- The type of sign up bonus or welcome offer
- Betting terms on the race, enhanced place terms especially
- Money back concessions around fallers or narrow losers
- Access to the Tote pools for exotic bets like Forecasts, Tricasts and more
- Enhanced odds or odds boosts for the horse you want to bet on
- Bet and watch the race via your phone if on the move with live streaming
We make sure to list these bookmakers at the top of our best online horse racing betting sites to make it easier for you, and the chance of you falling foul and not getting what you need are slim based on these recommendations.
How to Bet on the Grand National Online
It's simple to bet on the Grand National online and save the walk on the high street to place a bet in the betting shops. It also saves you the walk back to beat the queues and collect any winnings should you be lucky in this year's race. Opening a new betting account online is a simple exercise and similar to any ecommerce account or transaction you may have completed online in recent times. Be sure to have a few items to hand to complete the standard customer requirements. The steps vary a little but usually take the following process.
- Choose an online bookmaker that suits you from our recommended horse racing betting sites here
- Provide your name and address
- Choose a username and password
- Select a deposit method, debit card, e-wallet or bank transfer etc
- Make a qualifying deposit – often the minimum will be £10 or currency equivalent
- Choose your horse for the race
- Select a bet type, win or each way
- Choose the stake you wish to bet
- Receive a bet receipt to confirm you are in the race
Some sites will require an upload of photographic identification like a driving licence or a passport, which can be done directly with your phone or tablet, or sent in to their customer service team by email. Also, an address verification such as a recent utility bill to confirm your residence may be required. This will ensure there are no delays with withdrawals or future deposits and allow for a seamless interaction that you would expect in the normal course of setting up an account with a company online.
Your account balance will update immediately upon placing a bet and then again once the result is known to reflect any winnings that are due.
How to Withdraw Your Grand National Winnings
If you are lucky enough to place a winning bet on the Grand National this year, your online betting account balance will reflect those winnings with an updated balance. You can access your balance by choosing the account option and then selecting withdrawal. You will be able to withdraw all or some of the balance using the same payment method you used to fund your account and make your initial deposit. Many of the best betting sites for horse racing will process a withdrawal instantly, or within a matter of hours, but some may take a working day or two to conclude. This is a seamless process and works very similarly to any usual online transaction you will have had in recent times.
Last 10 Grand National Winners
Knowing what has gone before in the Grand National can be a good guide to what is yet to come. The winners' age, the weight they carried and the successful trainers and jockeys involved are always a good starting point to picking the next winner of the Grand National. Here are the last 10 results from Aintree for the Grand Nationals gone by.
Year | Horse | Weight | Trainer | Jockey | Starting Price
2021 | Minella Times | 10-03 | Henry de Bromhead | Rachael Blackmore | 11/1
2019 | Tiger Roll | 11-05 | Gordon Elliott | Davy Russell | 4/1
2018 | Tiger Roll | 10-13 | Gordon Elliott | Davy Russell | 14/1
2017 | One For Arthur | 10-11 | Lucinda Russell | Derek Fox | 14/1
2016 | Rule The World | 10-07 | Mouse Morris | David Mullins | 33/1
2015 | Many Clouds | 11-09 | Oliver Sherwood | Leighton Aspell | 25/1
2014 | Pineau De Re | 10-06 | Dr Richard Newland | Leighton Aspell | 25/1
2013 | Auroras Encore | 10-03 | Mrs S Smith | Ryan Mania | 66/1
2012 | Neptune Collonges | 11-06 | Paul Nicholls | Daryl Jacob | 33/1
2011 | Ballabriggs | 11-00 | Donald McCain | Jason Maguire | 14/1
Grand National Betting Trends
Many versions of Grand National trends have been successfully used to identify a short list for the winner of the great race. When you are staring at a Grand National race card with 40 runners, it is hard to narrow it down to just a few without some helpful hints as to what it might take to win the race or finish in the money. Based on decades of past results you want to concentrate on the following trends when selecting a Grand National winner.
- Aged between 8 and 10 years old
- Previously run ten times over fences or more
- Previously won a race over a distance of 3m or more
- Currently rated between 148 and 160 by the handicapper
- Have run at Aintree before in any race
- Had raced within the last 60 days
- Had previously been placed in a Graded race
This should help to create a Grand National shortlist from the 40 runners down to a list of single figures or so. Then you can check recent form, jockey bookings and trainer records to find the best horse to bet on at the Grand National or two or three!
Biggest Priced Grand National Winners
In recent times, Mon Mome's success in the 2009 Grand National at 100/1 for trainer Venetia Williams and jockey Liam Treadwell was a standout for big-priced winners in the Grand National. The nine-year-old actually fitted many of the trends required to win the race but was unfancied by the punters that year and returned a three-figure price and caused an almighty shock. Foinavon, who now has a fence named after him on the Aintree Grand National course was also a 100/1 winner in 1967, but they are few and far between. The lottery aspect of the race is still true to this day with the test of stamina and jumping not a simple one for even the best horses and jockeys to navigate. Winners at 66/1, 50/1, 40/1 and 33/1 are commonplace, and horses finishing in the places at these odds happen almost without fail every single year. Don't be put off by a big price, if the horse fits some of the trends mentioned above and is a big price that is usually a better bet than most will find.
Grand National Betting Lingo
Don't be put off by horse racing lingo in the run up to the Grand National and when betting on the race. The terms may sound complicated but are basically just slang for common things, and some are detailed below.
Jolly – the race favourite with the punters.
In The Money – the horse has finished in the places, rewarding each-way backers.
The Elbow – the part of the track after the last fence in the Grand National when the horses must turn slightly right to meet the straight to the finishing post. Shaped a little like an elbow.
Backed Off The Boards – a horse is being heavily supported with bets in the betting market and is clearly fancied to do well.
Pulled Up – the jockey decided to stop his horse from completing the race, possibly due to an injury or being too tired to finish or a long way back from the front and without a chance of winning.
Held Up – letting the race develop in front of him rather than mixing it with the pace setters.
The Melling Road – literally a road that crosses a part of the course that horses run across during the race.
Becher's Brook – a famous fence that takes a lot of jumping on the way round in the Grand National.
The Chair – another famous fence that must be negotiated during the Grand National.
Foinavon – a famous fence at the National where plenty of horses fell and allowed the 100/1 big outsider Foinavon to come through and win the race having been out the back for a long way.
Drifter – the price on this horse is getting bigger before the race, which can mean that it is not fancied and perhaps will perform below par.
Steamer – the opposite of a drifter, this suggests a horse is being well backed and fancied to perform better than expected by the betting public.
Tip – a suggested horse from someone who claims to know a lot about the race, otherwise known as a tipster.
Grand National Entries, Runners and Riders
The current entries for the Grand National are known weeks in advance, along with the weights, numbers and colours they will carry in the race.
The 2022 Grand National entries, along with their race number, weight, trainer and odds, at the time of writing are:
Chris's Dream | 11-10 | Henry De Bromhead | 33/1
Minella Times | 11-09 | Henry de Bromhead | 20/1
Delta Work | 11-08 | Gordon Elliott | 8/1
Easysland | 11-07 | Jonjo O'Neill | 50/1
Any Second Now | 11-07 | Ted Walsh | 9/1
Run Wild Fred | 11-07 | Gordon Elliott | 22/1
Lostintranslation | 11-05 | Colin Tizzard | 66/1
Brahma Bull | 11-05 | Willie Mullins | 80/1
Battleoverdoyen | 11-05 | Gordon Elliott | 100/1
Burrows Saint | 11-04 | Willie Mullins | 18/1
Mount Ida | 11-04 | Gordon Elliott | 20/1
Longhouse Poet | 11-03 | Martin Brassil | 22/1
Fiddlerontheroof | 11-03 | Colin Tizzard | 14/1
Two For Gold | 11-02 | Kim Bailey | 40/1
Santini | 11-01 | Polly Gundry | 50/1
Samcro | 11-00 | Gordon Elliott | 66/1
Chatham Street Lad | 11-00 | Michael Winters | 50/1
Farclas | 11-00 | Gordon Elliott | 22/1
Escaria Ten | 11-00 | Gordon Elliott | 10/1
Good Boy Bobby | 10-12 | Nigel Twiston-Davies | 33/1
Lord du Mesnil | 10-12 | Richard Hobson | 100/1
Coko Beach | 10-12 | Gordon Elliott | 50/1
De Rasher Counter | 10-11 | Emma Lavelle | 40/1
Caribean Boy | 10-11 | Nicky Henderson | 50/1
Court Maid | 10-11 | Tom Mullins | 66/1
Kildisart | 10-10 | Ben Pauling | 33/1
Discorama | 10-10 | Paul Nolan | 28/1
Top Ville Ben | 10-10 | Philip Kirby | 50/1
Enjoy d'Allen | 10-10 | Ciaran Murphy | 12/1
Anibale Fly | 10-10 | Tony Martin | 40/1
Dingo Dollar | 10-10 | Sandy Thomson | 50/1
Freewheelin Dylan | 10-09 | Dermot McLoughlin | 50/1
Class Conti | 10-09 | Willie Mullins | 150/1
Noble Yeats | 10-09 | Emmet Mullins | 28/1
Mighty Thunder | 10-09 | Lucinda Russell | 33/1
Cloth Cap | 10-09 | Jonjo O'Neill | 28/1
Snow Leopardess | 10-08 | Charlie Longsdon | 12/1
Agusta Gold | 10-08 | Willie Mullins | 66/1
Phoenix Way | 10-08 | Harry Fry | 33/1
Deise Aba | 10-07 | Philip Hobbs | 66/1
Fun Ways to Pick a Grand National Winner
There are several ways to get involved with the Grand National without placing an actual bet. Sweepstakes and lucky dips have become hugely popular mechanics for having an interest in the race with colleagues, friends and family. A sweepstake involves putting all the race-horse names in a hat and taking turns to draw out a name in return for a small payment, and the one who selects the winner takes the pot! Also known as a lucky dip and is just like a raffle, with the emphasis very much on luck of the draw!
Many people rely on superstitions to pick a Grand National winner, such as picking the horse with the same number as their birthday or perhaps the door on their house. The names can also be the method, an uncle or grandmother that shares a name with a horse can be popular. With previous winners like One For Arthur, Monty's Pass and Bobbyjo costing the bookies more than might have been had the names not been so popular with the once a year bettors.
Who is the Favourite for the Grand National?
The favourite for the 2022 Grand National is currently Delta Work for trainer Gordon Elliott and the Gigginstown House Stud, owned by Michael O'Leary of Ryanair fame. Delta Work recently won at the Cheltenham Festival beating a two-time Grand National winner Tiger Roll in the process and since that success has seen his odds of winning this year's Grand National tumble into a general price of 8/1. Any Second Now varies between 8-1 and 10-1 with some of the best horse racing betting sites at the moment, and Escaria Ten, which is also trained in Ireland, is next in the current Grand National betting markets at 10/1. These prices will change in the lead up to race day on the 9th of April but backing them now might secure you some early value and is known as placing an antepost bet. If choosing to do so some bookmakers will allow you to do this with a non-runner no bet concession, that means should your selection miss the race for any reason you will get your stake back.
Who Won the 2021 Grand National?
The 2021 Grand National was won by Minella Times at a price of 11/1. Trained by Henry De Bromhead in Ireland, owned by famous racing legend JP McManus and ridden by Rachael Blackmore, it will go down in the history books for several reasons. There were no crowds at Aintree that day due to the COVID-19 pandemic and restrictions on large gatherings, but it was the first time a female jockey had ridden the winner of the famous race. Despite several near misses in the past, Rachael Blackmore delivered for the women in the weighing room to banish the stat to the annuls forever more with a perfect ride and success aboard Minella Times. The win capped a wonderful season in the saddle, which saw her also win the top rider's award at the Cheltenham Festival with Honeysuckle taking the Champion Hurdle.
What Horse Does Rachael Blackmore Ride in the Grand National?
Jockey bookings are not yet confirmed for the Grand National and can change up to 48 hours before the race itself to allow for non-runners, injuries and decisions to be made as to the best chances the trainer and connections feel their horses have as the race approaches. However, Rachael Blackmore will likely partner Minella Times again after being successful on the horse 12 months ago in the same race, but she will have other options from the Henry De Bromhead yard with Chris's Dream and potentially Plan Of Attack and Poker Party all still entered, though the latter will have to rely on withdrawals to make the starting line. Perhaps other yards will vie for her to be on board their horse. Whatever Rachael decides to ride will no doubt be popular with the punters and a poor result for the bookmakers should she win again.
Grand National Betting Tips
Check out our best bets for horse racing each and every day on Bookmakers.com, and we will be sure to have the Grand National covered in detail on Saturday 9th April 2022. Many newspapers and online publications will have dedicated sections for the race with previews, tips and analysis, and here at Bookmakers.com we make sure to use the very best in expert opinion and advice when it comes to betting on the great race and all the supporting action from Aintree at this year's Grand National meeting.
Best Soccer Bets
Best US Sports Picks
Grand National FAQs
Can you bet on the Grand National?
The Grand National is a huge event for bettors around the world, whether they are accessing UK betting sites or even USA sports betting sites. Wagers can be placed weeks in advance of the event with antepost selections, while thousands will wait until the day.
The favourite for the race at the time of writing is Delta Work after his impressive win over Tiger Roll in the Cross Country Chase at the Cheltenham Festival. While he is the current favourite, others such as Any Second Now and Escaria Ten are also being well backed in advance of the race.
Which horse has won the most Grand Nationals?
Red Rum is the only horse to have won the Grand National an incredible three times, winning in 1973, 1974 and 1977. Many would have hoped Tiger Roll might have been entered to try to equal Red Rum's record, having won the race in 2018 and 2019, but it wasn't to be.
Where can I bet on the Grand National?
You can bet on the Grand National in person at betting shops, at the course if you're lucky enough to watch the race or by visiting any number of sports betting sites around the world. Bookmakers.com lists all the most-trusted operators in the world and also the best betting offers people can find.
@Onthenoseinfo
Dean is respected tipster, journalist and broadcaster on sports - mainly horse racing. Having featured across radio, TV and podcasts, his betting knowledge is developed over decades in the gambling industry across a number of different publications and platforms. You will usually find him on social media discussing Tottenham Hotspur or the Cheltenham Festival.
Festival Focus With Tom Lee & David Mullins
Dean Ryan | Jan 31st, 2023 10:19 AM

redpajama_set_name: RedPajamaCommonCrawl


text:
Men's hoops looks to sweep Washington schools
(Photo: BOB DREBIN/isiphotos.com)
By Teddy Solomon on January 8, 2021
Good teams play through adversity, and Stanford (7-3, 3-1 Pac-12) is trying to prove just that as it takes on Washington State (9-1, 2-1 Pac-12) on Saturday.
Stanford's recent obstacles have included injuries to key players. Senior guard Daejon Davis hasn't played since Dec. 19 due to a lower leg injury, and his status has since been considered "day-to-day." Junior guard Bryce Wills went down on Monday with a knee injury, and he is currently "week-to-week," with a seemingly more uncertain return than that of Davis. One or both of Davis and Wills could very possibly be out for Saturday's matchup.
Davis and Wills have made a name for themselves as a defensive duo, arguably the best in the Pac-12. They have also both been vital on the offensive end, averaging 13.8 and 9.3 points per game, respectively, with Davis leading the Cardinal in assists.
Another hurdle Stanford has been forced to jump is a lack of true "home" games. Due to Santa Clara County's restrictive COVID-19 guidelines, the Cardinal has yet to compete on the Farm this season. Saturday's matchup will be no exception, as it will be played in Santa Cruz at Kaiser Permanente Arena in what is effectively a neutral court game. It will be Stanford's fourth game at the home court of the NBA G League's Santa Cruz Warriors.
Despite these challenges, Stanford has persevered, albeit against low-level Pac-12 competition, thus far. In the Cardinal's recent matchup against Washington (1-8, 0-4 Pac-12), Stanford secured a 16-point victory in the absence of Davis and Wills. The freshmen were among the most important players of the game, with guard Michael O'Connell embracing his starting role and scoring 11 points, and forward Ziaire Williams delivering the second triple-double in program history.
Junior forward Jaiden Delaire, who has missed key games due to back spasms, was spectacular on Thursday. In 24 minutes, he tied a career-high 21 points and secured nine rebounds. At 6-foot-9, Delaire adds important size and rebounding ability for the Cardinal, and his success will be essential moving forward.
Washington State enters Saturday's game with something to prove. Despite holding an impressive 9-1 record, the Cougars are still overlooked by many. As of Jan. 8, the team sits at 114th in KenPom, emphasizing its weak strength of schedule. Many continue to believe that Washington State belongs in the bottom of the conference with teams like Oregon State, Cal and Washington.
The Cougars' strongest win is likely their recent road win against Cal — which is currently in last place in the Pac-12 — but Washington State has shown glimpses of brilliance throughout the season. Against Arizona, the Cougars gave Wildcats head coach Sean Miller and his squad all they could handle, forcing double overtime as a distinct underdog. Though Washington State failed to come out on top, the Cougars looked as good as anyone in the conference in moments of that game.
While the Cougars lack flashy wins, their freshmen have stepped up, their senior leadership has outperformed and the team's coaching is near impeccable.
After losing star guard C.J. Elleby from last season, Washington State knew it had to rely heavily on its top-35 recruiting class. Freshmen like center Efe Abogidi and forward Andrej Jakimovski have proven to be vital parts of the core Cougar lineup.
In the senior leadership position is guard Isaac Bonton, who has proven to be a dangerous scorer, averaging 17.7 points per contest. In conference play, Bonton has demonstrated that he can compete with power-five players, scoring an impressive 25 points against Arizona and 22 against Cal.
At the helm of this Washington State team is head coach Kyle Smith, who has continued to show that he is one of the best coaches in the Pac-12. Before coming to Washington State, Smith rebuilt the basketball program at the University of San Francisco, and in Pullman, he is seemingly replicating that success. Smith and his staff's analytical approach and top-notch recruiting creates unprecedented achievement for struggling programs.
Keys for success
For Washington State, the first key is free-throw shooting. In the double overtime loss to Arizona, the Cougars shot 19-of-37 from the charity stripe. In contrast, Washington State shot 18-of-23 from the line in its road win over Cal. Free throws make-or-break games, and for the Cougars, it could be the difference maker against a beaten up Stanford squad.
The second key for Washington State is points off of turnovers. With Wills very likely out of Saturday's matchup and Davis possibly out as well, Stanford will be operating with an extremely youthful backcourt. Against Washington on Thursday, the Cardinal turned the ball over 22 times, with seven coming from Williams. If the Cougars can capitalize on Stanford's inexperience and recklessness with the ball, an upset victory will be well within reach.
For Stanford, the first key is freshman contribution. With one or both star upperclassman guards likely out, freshman guards O'Connell and Noah Taitz will have to step up on both ends of the floor. Even in the frontcourt, it will be important for freshman forwards Brandon Angel and Max Murrell to supplement senior forward Oscar da Silva and Delaire's work.
The second key for the Cardinal is to limit turnovers. As of Jan. 6, Stanford was 281st in the nation in turnovers per game, and that ranking got worse with the 22 turnovers against Washington and will continue to get worse without Wills and Davis handling the ball. Williams especially, who averages 3.4 turnovers per game, needs to manage the ball better. If Stanford wants to win against top-notch teams, it needs to limit points off turnovers and have more effective offensive possessions.
Tip-off is scheduled for 2 p.m. PT on Saturday.
Contact Teddy Solomon at tedsol 'at' stanford.edu.
Teddy Solomon


text:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Phocalstream_Shared.Data.Model.External
{
    public enum DMDataType
    {
        [Description("County")]
        COUNTY,
        [Description("State")]
        STATE,
        [Description("US")]
        US,
        [Description("All")]
        ALL
    }
}


Located in North Guilford, CT at the junction of routes 77 and 80, Dudley Farm was in the same family for about 350 years. In 1991 David Dudley willed the farm to the North Guilford Volunteer Fire Department who has worked to help create a private, nonprofit foundation to oversee the 10-acre farm, farmhouse and barn buildings as a working farm.
Various events are held throughout the year including blacksmithing demonstrations, sheep shearing, wool spinning, crafters, quilters, archeological digs, and music jams.
Directions: From I-95, Exit 58, bottom of exit turn left (if northbound) or right (if southbound). Follow Route 77 north for 3 miles; at route 80, proceed straight, Dudley Farm is on your right.
Joseph Dudley 1643-1712 & Ann Robinson - In 1690 Joseph received a land grant of 200-acres.
William Dudley 1684-1761 & Ruth Strong (1st wife) - William was probably the first to farm the land known as "Dudley Farm".
Nathaniel Chidsey "Nathan" Dudley 1821-1912 & Sophronia Annis Rossiter - Nathan built the present house being restored as part of the Dudley Farm in 1844 and twice additions were built to accommodate his growing family and their parents. His three closest neighbors were his brothers Erastus, Luther and Ebenezer, whose houses still stand as of 1997.
David Munger Dudley 1909-1991 - was unmarried and the last owner of Dudley Farm.
As of 1997, efforts are under way by the Dudley foundation to restore the historic Dudley Farm in Guilford, Connecticut into a 19th-century working environment as a living museum. In 1690 Joseph received a land grant of 200-acres. Since that date more than 300 years ago, one or more members of the Dudley family has continually occupied it. David left an estate worth more than $500,000 to the North Guilford Congregational Church and the North Guilford Volunteer Fire Department. The Fire Company decided it wanted the house rather than the cash and worked out a distribution with the church; thus began the idea for the restoration.
A first look at the house after David's death found a house virtually unchanged since its original construction. The walls had one coat of paint, floors were painted up to where the rugs would have been, newspapers from 1961 covered some of the furniture, the barn had a thriving colony of about 6,000 bats.
The house was built by Nathaniel Dudley in 1844 and twice additions were built to accommodate his growing family and their parents.
2000 ... Ed and Linda Dolby traveled from Texas to attend the 2nd annual reunion of the Descendants of William Dudley which was held on September 12th at The Dudley Farm in Guilford, Connecticut. Those in attendance were treated to a wonderful meal roasted outdoors with all the trimmings and had an update on the farm by Curator Jim Powers (who also led us on a trip to the cemetery to view our Dudley ancestrial gravestones). Al Dudley had copies of the Descendants of William Dudley on hand for those who wished to purchased a copy. Also taking place at the farm were 2 different musical jams going on, ladies hooking rugs, and a farmers market. A major highlight was meeting new cousins and discovering how many other lines we had in common. The day was a huge success and one we will remember for quite awhile.
1999 ... A successful reunion of the Descendants of William Dudley was held August 14 and 15, 1999 at The Dudley Farm in Guilford, Connecticut. A family association was formed and is now accepting memberships in the William Dudley Family Association. For more information on the 2000 Dudley Reunion or joining the Association, please email Dudley Family Association. Note that the Association is not part of the Dudley Farm.


Download in Original Size (1022x1817, 183.11 KB) or select from the list of ready-made resolutions.
Download in Original Size (1920x1080, 1272.99 KB) or select from the list of ready-made resolutions.
Download in Original Size (500x313, 309.41 KB) or select from the list of ready-made resolutions.
Download in Original Size (800x500, 66.13 KB) or select from the list of ready-made resolutions.
Download in Original Size (1920x1280, 447.04 KB) or select from the list of ready-made resolutions.
Download in Original Size (1440x909, 268.68 KB) or select from the list of ready-made resolutions.
Download in Original Size (3840x2160, 2904.32 KB) or select from the list of ready-made resolutions.
Download in Original Size (640x960, 450.12 KB) or select from the list of ready-made resolutions.
Download in Original Size (1068x1900, 2197 KB) or select from the list of ready-made resolutions.
Download in Original Size (520x347, 94.38 KB) or select from the list of ready-made resolutions.


text:
Q: Display array of values in field Kendo Grid I need to display array of values inside a single field in kendo grid. Is it possible to do this
Scenario : For some columns in each row of the grid I'm getting a list of values per row and need to display them comma separated. So given values ['a','b'] I need to display in the column as a,b

A: In the column definition, define a template that users jQuery.join method.
Example: If the field is Cities (the array), it would be something like:
{ field: "Cities", width: 300, template: "#= Cities.join(', ') #" }

redpajama_set_name: RedPajamaStackExchange


text:
Hamline alumnus takes a stand-up
Comedian Nate Nickel navigates the world of stand-up in the Twin Cities.
Payton Mansfield
Payton Mansfield, Reporter
As the latest winner of Acme Comedy's "Funniest Person in the Twin Cities" contest, Hamline Alumnus Nate Nickel has certainly been making a name for himself.
Nickel graduated from Hamline in 2014 with a double major in Psychology and English and a concentration in creative writing. It's safe to say he's been putting his creative writing skills to good use, as a stand-up comedian, writing and delivering his own ruthless one-liners.
"I have longer jokes, but one-liners are what I'm best at," Nickel says. "Unless you're really good, a show of just one-liners can get old really quick."
The venue, Acme Comedy Club, has featured names like Emo Phillips, Miranda Sings, and Colin Jost. Nickel is just one of many rising comics that performs at the hotspot on a weekly basis. Monday nights are free to the public and allow for newcomers to sign up and give stand-up a shot. When Nickel's not at Acme, he is signing up to perform, "Everywhere I can, everyday. Or every night, for that matter."
Surprisingly enough, comedy wasn't always an aspiration for the 25-year-old.
Hailing from the small town of Northfield, Minnesota, young Nickel had dreams of being, "probably a jedi." His teenage years were driven by a passion for music and playing instruments, drumming in particular.
After college graduation, Nickel went back to his hometown with hopes of using his degree to become a therapist. Unfortunately, he found his career options to be sparse. He spent post-graduation working, recovering from tendonitis and watching Netflix specials.
One day, he got inspired to attend his first open mic, and kept it hidden from his family. He didn't tell them until he started to find some success.
"It was my dirty little secret," he says.
Two years later, Nickel is shamelessly dedicated to climbing the ladder of stand-up. He studies his favorite comedians and will drop everything to scribble down a joke that comes to mind, even during family gatherings.
"When I find something I like, I really like it," he says. "I just go super hard at it."
When I ask how to handle a difficult audience, Nickel says, "Eat sh*t, basically. Tough it out."
He explains that trying to revive a dull crowd is a "huge mistake" for any comedian and that it's best to just go with the script. Nickel has also dealt with his fair share of hecklers and people confronting him post-show.
"It's usually the same group of people," he says.
He believes comedy is a unique profession in that it often instigates the most hatred out of people.
"You have to have a high tolerance for failure," he says. Amateur comedians need thick skin if they expect to succeed, and must be prepared to work hard.
"Sign up and show up."
For the night's performance, Nickel puts aside his friendliness and makes the most of his seven-minute act with no remorse.
With his own Facebook page, and dreams of one day having his own Netflix special, Nickel is determined to make his way through the world, one punchline at a time.
Archives Select Month January 2023 December 2022 November 2022 October 2022 September 2022 May 2022 April 2022 March 2022 February 2022 December 2021 November 2021 October 2021 September 2021 August 2021 May 2021 April 2021 March 2021 February 2021 November 2020 October 2020 September 2020 July 2020 June 2020 May 2020 April 2020 March 2020 February 2020 December 2019 November 2019 October 2019 September 2019 May 2019 April 2019 March 2019 February 2019 December 2018 November 2018 October 2018 September 2018 May 2018 April 2018 March 2018 February 2018 December 2017 November 2017 October 2017 September 2017 April 2017 March 2017 February 2017 December 2016 November 2016 October 2016 September 2016 May 2016 April 2016 March 2016 February 2016 December 2015 November 2015 October 2015 September 2015 August 2015 July 2015 May 2015 April 2015 March 2015 February 2015 December 2014 November 2014 October 2014 September 2014 May 2014 April 2014 March 2014 February 2014 December 2013 November 2013 October 2013 September 2013 May 2013 April 2013 March 2013 February 2013 December 2012 November 2012 October 2012 December 2011 May 2011 November 2010
Review of Everything Everywhere All at Once
A midsummer night's dream in late April
Hmong Night Market showcases Diversity
Oscar's night: Where to begin?
The language of music
All The Oracle Picks Reader Picks Sort: Newest


text:
Laika the space dog.
Scientific work on the Moon.
Space exploration is a term which describes searching outer space. There are many reasons for space exploration. The most important reasons are for scientific research and the interest of humans to learn more about outer space. For centuries, humans had dreamt of reaching outer space. Better rockets made it possible in the 20th century. On October 4, 1957, the former Soviet Union launched the Sputnik 1, which was the first artificial satellite. This started the Space Race and people later went into orbit and Americans visited the Moon in Project Apollo.
Many space probes have gone to various planets and other places in the solar system to send back information about them. When people first went to space they didn't know how the effects of microgravity would have on humans so they sent animals instead. But in 1961 the soviets launched the first human into space, Yuri Gagarin.
Astronomy[change | change source]
Main article: Astronomy
The first telescope was probably invented in 1608 by Hans Lippershey. The Orbiting Astronomical Observatory 2 was the first space telescope launched on December 7, 1968.[1] As of February 2, 2019, about 3,891 exoplanets are discovered. The Milky Way galaxy has more than 100–400 billion stars[2] and more than 100 billion planets.[3] There are about 2 trillion galaxies in the observable universe.[4][5]
Interstellar travel
Soyuz
Saturn V
Exploration of Mars
Exploration of Neptune
Wikimedia Commons has media related to Space exploration.
↑ Joseph A. Angelo (2014). Spacecraft for Astronomy. Infobase Publishing. p. 20. ISBN 978-1-4381-0896-4.
↑ "How Many Stars in the Milky Way?". NASA Blueshift. Archived from the original on January 25, 2016.
↑ Staff (January 2, 2013). "100 Billion Alien Planets Fill Our Milky Way Galaxy: Study". Space.com. Archived from the original on January 3, 2013. Retrieved January 3, 2013.
↑ Conselice, Christopher J.; et al. (2016). "The Evolution of Galaxy Number Density at z < 8 and Its Implications". The Astrophysical Journal. 830 (2): 83. arXiv:1607.03909v2. Bibcode:2016ApJ...830...83C. doi:10.3847/0004-637X/830/2/83. S2CID 17424588.
↑ Fountain, Henry (17 October 2016). "Two Trillion Galaxies, at the Very Least". New York Times. Retrieved 17 October 2016.
This short article about science can be made longer. You can help Wikipedia by adding to it.
Retrieved from "https://simple.wikipedia.org/w/index.php?title=Space_exploration&oldid=8647389"
Science stubs


text:
MainAll NewsInside IsraelHigh Court Again Orders Demolition of Homes
High Court Again Orders Demolition of Homes
As residents of Beit El rallied Sunday night, the High Court reiterated demands to demolish the Draynoff Houses.
Yaakov Levi, 26/07/15 22:13
Beit El homes slated for demolition
Aryeh Minkoff
As residents of Beit El and supporters of the community rallied Sunday night, demanding that the government follow through on its plan to ensure that the Draynoff Houses in the community are left standing, the High Court yet again sought to put a halt to plans to prevent the demolition of the homes. The court issued an injunction against any construction work that would result from the removal of objections to the project by a planning council.
Supporters had hoped that the change could lead to a new legal status for the buildings. Previously, the High Court had ordered the buildings to be demolished because they were built without approval of planning councils. The decision last week was set to pave the way for the issuance of retroactive building permits for the project.
In the wake of a High Court decision that would have required the buildings to be demolished, the IDF Civil Administration last week authorized the building plan for the project, after a planning council removed its objections to the plan. With the authorization, the road is open to providing retroactive building permits for the project.
However, in order for the plan to take effect, it needs to be signed off on at the ministerial level. In addition, the Civil Administration decision, while providing for permits for planning and construction, would require the demolition of the existing buildings and the construction of new ones.
The rally Sunday is designed to pressure the government into accepting the plan and preserving the existing homes. If the relevant ministers do sign the plan, residents believe they will be able to get an injunction against the buildings' imminent demolition.
With the Court's demolition order renewed Sunday, that route may now be closed off. Supporters said that they would examine their options in the wake of the new decision.
Last week, senior rabbis in the Religious Zionist community called on the public to demonstrate on behalf of the residents of the "Draynoff Houses," supporting them in "their just struggle for their right to settle in the Land of Israel."
The rabbis, among them Rabbi Dov Lior, Rabbi Nachum Rabinowitz, Rabbi Shmuel Eliyahu, Rabbi Elyakim Levanon, Rabbi Shlomo Aviner, and others, issued a public letter calling for mass protests against the planned demolitions. "Especially at this time," their letter said, "when we commemorate a decade since the terrible removal of Jews from Gush Katif, and the government implements yet another building freeze in Judea and Samaria."
The government, reads the letter, "is under pressure from the nations of the world, and is ignoring our G-d given right to build in Judea and Samaria." The antidote, according to the rabbis, is pressure from the other side, demanding that Jews be allowed to settle anywhere they want on their land, the letter said.
Tags:High Court, Beit El, Draynoff Houses


attrici I think Tom should work with some day: Who would be the best?
Out of these superiore, in alto 10 Tom Hardy performances which one is your favorite?
My preferito Tom Hardy roles. Pick your favorite.
la scelta dei fan: te musn't be afraid to dream a little bigger darling.
Should Tom Hardy be the successivo James Bond?
la scelta dei fan: Yes, Tom Hardy would make an awesome James Bond!
Does anyone know what all of his tatoos are off o what they say?
Does anyone know where te can send fan mail to tom? An if he has an official site?
Of the roles TH has played, my preferito is the one in "the drop".
He is intelligent, understated, fiercely protective, and his Amore for the cucciolo was extraordinary.
When Bronson talked to Tom, he likened the actor to what icon?


I just turned 50. That's a blessing and a curse.
The blessing of making it to 50 is the wisdom that comes from remembering 50 years' worth of stuff. The curse is the burden of remembering 50 years' worth of stuff.
See, in some respects, ignorance is bliss. There is a certain contentment in not knowing what you don't know.
Take the state of radio, for example. It's the little story that tells the big story of life in these postmodern times.
If you don't know anything about what radio was, it's difficult to get all grief-stricken about what radio -- and by extension our society -- has become.
I have loved radio for as long as I can remember. When I was a little kid -- back when music came on records, sound got recorded on reel-to-reel tape and computers were the size of small rooms -- I used to trek up and down the dial of our big five-band transistor set, listening to all the world that would fit in (and squeeze through) a six-inch speaker.
I would listen to a wonderful world of music -- all kinds of music. I would listen to network broadcasts from New York . . . and the world. I would listen to, and wonder about, life in exotic places like . . . New Orleans. Nashville. Little Rock.
Little Rock? Little Rock. When you're 8 or 9 and growing up blue collar in Baton Rouge, exotic is a catch-as-catch-can affair.
Little Rock was the Mighty 1090, KAAY, with rock 'n' roll in the night. And as I was to learn through the magic of someone long ago hooking a reel-to-reel tape recorder up to an AM radio, Little Rock also was KARK. Or, as the announcers there said back in 1971, "Kay! A-R-K."
IF YOU'RE a lot younger than my 50 years, the above hour of KARK, circa May 19, 1971, must sound like a transmission from an alien culture. That's because it is.
In 1971, the mass media was just that. While in many respects, we were just as much a tribal society 40 years ago as we are today, all our various tribes were on a first-name basis. Even when we hated one another's guts.
Though alienation was a fact then just as it is today, alienation was not a business model for mass media. Though we often screamed at one another four decades past, radio and television by and large weren't about displacing light with heat. Or hot air.
Radio stations like KARK -- those one's parents were most likely to favor -- were all about being the voice of a community. Today, by contrast, the picked-over carcasses of stations like KARK (now KARN) are all about being the cynical voice of an outraged sociopolitical demographic, usually on the far right.
Today, if you don't want to listen to a single thing "The Other" has to say, you don't have to. You can get all your "news" from people who think just like you do. You can listen to radio stations that pull angry voices from the sky -- via satellite -- that tell you exactly what you want to hear.
YOU CAN wander across the AM dial in search of exotic voices from exotic places, only to find that everywhere is just like Nowhere . . . that nondescript backdrop for our unremarkable lives of quiet desperation. The voice from New Orleans is the voice from Omaha is the voice from Little Rock is the voice from the satellite.
The overwrought voice of outrage.
The voice that shouts but never sings.
A few years after the time of our 1971 archived transmission from an alien culture, Harry Chapin sang about a "bright good-morning voice who's heard but never seen." That guy got fired years ago.
Now there's Ryan, or Rush, or Glenn, or Laura, or Sean . . . or the conspiracy theorists selling doom late at night. They're not from around here.
THE BLESSING of my 50 years on this earth is I can remember a time when I had a working knowledge of subcultures not my own. When the snot-nosed kid that I used to be couldn't help but have broad familiarity with my parents' Squaresville landscape. With their history, their cultural underpinnings.
Memory also is the burden I bear. This curse is born of a half century of learning the hard way that "progress" oftentimes isn't -- that things don't always get better and better.
When I close my eyes and shut off the noise we can't ignore, I hear music. I hear exotic voices from magical places. I hear New Orleans. I hear Baton Rouge.
I hear 1971. It's right there . . . the troubled but magical world from when most of my life was ahead of me, not behind.
I hear it . . . I can almost touch it. My blessing.
I open my eyes, and now it's gone.


Stunning Cluster Pendant features Genuine Sleeping Beauty Turquoise, King's Manassa Turquoise, Red Coral, Purple Spiny Oyster Shell and Orange Spiny Oyster Shell set in Sterling Silver. Free 18" Sterling Silver Chain with Purchase of Pendant. Created by Navajo Artist Bea Tom. Signed by the artist.


It looks like some official press renders and the fill specifications for the new HTC U12+ have been leaked.
The handset will come with a 6 inch Super LCD display with a QHD+ resolution of 2880 x 1440 pixels and the device will feature a Qualcomm Snapdragon 845 processor.
Other specifications on the handset will include 6GB of RAM and a choice of either 64GB of 128GB of storage. The handset will also come with high end cameras, on the front there will be an 8 megapixel camera and on the back there will be a dual camera setup.
The dual cameras on the back will be made up of one 12 megapixel camera and one 16 megapixel camera. The handset will come with Android Oreo and will feature a 3500 mAh battery.


Celebrating Indianapolis, Indiana! This is the statue on top of the Soldiers and Sailors monument in the circle of downtown Indy. This print is sized 11x14" and is 3 colors hand screen printed on French Paper Co. 100 lb. Blacktop paper. Signed and numbered edition of 100.


text:
    <form accept-charset="UTF-8" role="form" name="namespacedAliasCreateForm" class="form-horizontal">

Not Available. Release planned nov 1'st 2014

FIMK Namespaced Aliases are scoped per account. This means you can use any alias you wish, even the same ones that someone else is using.

Namespaced Alias makes the blockchain more suitable for storing small pieces of data in decentralized storage.

 The aliases you register are stored either in plain text or encrypted and can thus be read by anyone or only be read through access to your account, or access details that you grant to a third party (setting a Namespaced Alias costs 0.1 FIM)

{{items.errorMessage | json}}

        Sender

          <input type="text" class="form-control" id="nsalias-sender" readonly ng-model="items.senderRS">

        Key

          <input type="text" class="form-control" id="nsalias-key" ng-model="items.key" name="key" required
                 ui-validate="{length : 'validateKeyLength($value)', chars: 'validateCharacters($value)'}" ui-validate-watch=" 'items.key' ">

        Value

          <textarea rows="4" class="form-control" id="nsalias-value" ng-model="items.value" name="value" required
                    ui-validate="{length : 'validateValueLength($value)'}"
                    ui-validate-watch=" 'items.value' "></textarea>

        Fee

          <input money precision="8" class="form-control" id="nsalias-fee-1" placeholder="Fee" name="fee" type="text"
              ng-model="items.feeNXT"
              ng-mouseenter="setTitle('Enter a fee')" ng-mouseleave="setTitle(null)">

        Deadline

          <input class="form-control" id="nsalias-deadline-1" placeholder="Deadline" name="deadline"
                type="text" ng-model="items.deadline"
                ng-mouseenter="setTitle('Set the deadline minimum 1 maximum 1440')" ng-mouseleave="setTitle(null)">

    </form>

        <button ng-click="close()" type="button" class="btn btn-block btn-primary" ng-disabled="!namespacedAliasCreateForm.$valid">Save</button>

        <button ng-click="dismiss()" type="button" class="btn btn-block btn-default" ng-disabled="sendSuccess">Cancel</button>


The sailing culture here has seen better days.
For at least the last two years, people in Newport Beach have struggled to sell their boats. Others lack the financial stability to buy one, and many in between just opt to not take theirs out on the water.
But with a deal struck between the organizers of the fledgling Border Run Yacht Race and the iconic Newport to Ensenada race to host contests on consecutive weekends, yachting might just get a strong gust of wind in its sails.
"We're fighting the economy," said Border Run co-founder Randy Reynolds. "We're going to promote the month of April as, 'If you can't sell it, sail it.'"
For the last two years, the Newport to Ensenada race has had to compete directly with the Border Run, a 70- to 90-mile race from Newport Harbor to San Diego that goes around Coronado Island.
The Border Run is an abbreviated version of the Ensenada race, which keeps sailors in American waters for almost the whole race.
The Newport to Ensenada race, which just celebrated its 63rd year, had slightly more than 200 participants this year, a far cry from years ago when 700 sailors would participate.
2009 when he was not allowed to participate in the Ensenada event and scheduled it for the same weekend.
"Our goal is to promote sailing and grow sailing on the coast like it used to be in the '70s and '80s," he said. "That was causing some conflict in the Newport Beach area"
That conflict made waves among local sailors, but both sides agreed to sit down and come to a solution for the sake of the sport, Border Run co-founder Bob Long said.
"We were able to get everybody together and basically say, 'Let's work together and come up with a series of races,'" Long said.
"I think it's going to help both races, hopefully pick up more boats, and Newport to Ensenada will hopefully pick up new boats," Reynolds said.
next year, when sailors start signing up.
both, it's really nothing bad for anybody."
"Now we can get back to sailing again," Reynolds said. "We're not looking back anymore. We're looking forward."
Ensenada race is scheduled for April 15.
For more information on the Border Run, visit XSRacing.org. For information on the Ensenada race, visit http://www.nosa.org.


AMCX Studio opened it's "doors" last November on Etsy but didn't pick up momentum until February of this year. I established an LLC for the business in April and have been working and evolving as a company. I am explored new avenues and I have a lot of great ideas for the direction of the company. As we are quickly approaching the one year mark, I have been thinking long and hard on how I want the second year to unfold. Although we can't ever predict the future, I still want to plan what I can and think of how I can set up the second year for more success.
I have been kicking around the idea of opening a stand-alone shop for some while now but always felt it was too far out of reach. AMCX Studio has operated largely on Etsy and Facebook and although I have been pretty happy with the results, I am hoping that the launch of our "own shop" will bring more success. I have recently installed WOO-Commerce and am looking at videos and tutorials to adding all of my listings from Etsy (and even more bonus goodies) to one central store located right here at AMCXstudio.com. You will be able to shop for everything from decals to graphics and even shirts!
With that said, please excuse the dust while I make adjustments the site to help accommodate this new chapter. I hope that you will check back often to see how things progress. As always check back for DIY videos, blogs, and more to help you grow your own business. I really do have big plans and I am working on implementing them every day.
Congratulations!!!! I can't wait to shop with AMCXstudios.com!!!