<commit_before>﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.Win32;

namespace devcoach.Tools
{
  /// <summary>
  /// This is the class that implements the package exposed by this assembly.
  /// The minimum requirement for a class to be considered a valid package for Visual Studio
  /// is to implement the IVsPackage interface and register itself with the shell.
  /// This package uses the helper classes defined inside the Managed Package Framework (MPF)
  /// to do it: it derives from the Package class that provides the implementation of the 
  /// IVsPackage interface and uses the registration attributes defined in the framework to 
  /// register itself and its components with the shell.
  /// </summary>
  // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is
  // a package.
  [ProvideAutoLoad(UIContextGuids.SolutionExists)]
  [PackageRegistration(UseManagedResourcesOnly = true)]
  // This attribute is used to register the information needed to show this package
  // in the Help/About dialog of Visual Studio.
  [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
  // This attribute is needed to let the shell know that this package exposes some menus.
  [ProvideMenuResource("Menus.ctmenu", 1)]
  [Guid(GuidList.guidKarmaVsPkgString)]
  public sealed class KarmaVsPackage : Package
  {
    private static readonly object _s_applicationLock = new object();
    public static DTE2 Application { get; private set; }
    private static OutputWindow _outputWindow;
    private static OutputWindowPane _karmaOutputWindowPane;
    private static System.Diagnostics.Process _karmaProcess;
    private static System.Diagnostics.Process _webServerProcess;
    private static Events _events;
    private static DTEEvents _dteEvents;
    private static DocumentEvents _documentEvents;

    readonly Regex _outputDir =
        new Regex(
          @"\[[\d]{1,6}m{1}",
          RegexOptions.Compiled);

    readonly Regex _browserInfo =
        new Regex(
            @"[a-z|A-Z]{4,20}\s([\d]{1,5}\.{0,1})*\s\" +
            @"([a-z|A-Z|\s|\d]{4,20}\)(\:\s|\s|\]\:\s)",
            RegexOptions.Compiled);

    readonly Regex _details =
        new Regex(
          @"\[\d{1,2}[A-Z]{1}|\[\d{1,2}m{1}",
          RegexOptions.Compiled);

    #region Initialize()
    protected override void Initialize()
    {
      lock (_s_applicationLock)
      {
        Application = (DTE2)GetService(typeof(SDTE));
        _events = Application.Application.Events;
        _dteEvents = _events.DTEEvents;
        _documentEvents = _events.DocumentEvents;

        var win =
          Application.Windows.Item(EnvDTE.Constants.vsWindowKindOutput);
        _outputWindow = win.Object as OutputWindow;
        if (_outputWindow != null)
        {
          _karmaOutputWindowPane =
            _outputWindow.OutputWindowPanes.Add("Karma");
        }
        _dteEvents.OnBeginShutdown += ShutdownKarma;
        _events.SolutionEvents.Opened += SolutionEventsOpened;

      }

      base.Initialize();

      // Add our command handlers for menu (commands must exist in .vsct file)
      var mcs =
        GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
      if (null == mcs) return;

      // Create the command for the menu item.
      var menuCommandId1 =
        new CommandID(
          GuidList.guidToggleKarmaVsUnitCmdSet,
          (int)PkgCmdIDList.cmdidToggleKarmaVsUnit
        );
      var menuItem1 = new MenuCommand(KarmaVsUnit, menuCommandId1);
      mcs.AddCommand(menuItem1);

      // Create the command for the menu item.
      var menuCommandId2 =
        new CommandID(
          GuidList.guidToggleKarmaVsE2eCmdSet,
          (int)PkgCmdIDList.cmdidToggleKarmaVsE2e
        );
      var menuItem2 = new MenuCommand(KarmaVsE2e, menuCommandId2);
      mcs.AddCommand(menuItem2);
    }
    #endregion

    #region SolutionEventsOpened()
    private void SolutionEventsOpened()
    {
      RunKarmaVs();
    }
    #endregion

    #region RunKarmaVs()
    private void RunKarmaVs(string config = "unit")
    {
      _karmaOutputWindowPane.Clear();

      ShutdownKarma();

      var nodeFilePath = GetNodeJsPath();
      if (nodeFilePath == null)
      {
        _karmaOutputWindowPane.OutputString(
            "ERROR: Node not found. Download and " +
            "install from: http://www.nodejs.org");
        _karmaOutputWindowPane.OutputString(Environment.NewLine);
        return;
      }

      _karmaOutputWindowPane.OutputString(
          "INFO: Node installation found: " + nodeFilePath);
      _karmaOutputWindowPane.OutputString(Environment.NewLine);

      var karmaFilePath = GetKarmaPath();
      if (karmaFilePath == null)
      {
        _karmaOutputWindowPane.OutputString(
            "ERROR: Karma was not found. Run \"npm install -g karma\"...");
        _karmaOutputWindowPane.OutputString(Environment.NewLine);
        return;
      }

      _karmaOutputWindowPane.OutputString(
          "INFO: Karma installation found: " + karmaFilePath);
      _karmaOutputWindowPane.OutputString(Environment.NewLine);

      var chromePath = GetChromePath();
      if (chromePath != null)
      {
        _karmaOutputWindowPane.OutputString(
            "INFO: Found Google Chrome : " + chromePath);
        _karmaOutputWindowPane.OutputString(Environment.NewLine);
        Environment.SetEnvironmentVariable("CHROME_BIN", chromePath);
      }

      var mozillaPath = GetMozillaPath();
      if (mozillaPath != null)
      {
        _karmaOutputWindowPane.OutputString(
            "INFO: Found Mozilla Firefox: " + mozillaPath);
        _karmaOutputWindowPane.OutputString(Environment.NewLine);
        Environment.SetEnvironmentVariable("FIREFOX_BIN", mozillaPath);
      }

      if (Application.Solution.Projects.Count < 1)
      {
        _karmaOutputWindowPane.OutputString("ERROR: No projects loaded");
        _karmaOutputWindowPane.OutputString(Environment.NewLine);
        return;
      }


      var projects = GetProjects().
        ToDictionary(project => project.Name, project => project);

      const string webApplication = "{349C5851-65DF-11DA-9384-00065B846F21}";
      const string webSite = "{E24C65DC-7377-472B-9ABA-BC803B73C61A}";

      Project karmaProject = null;
      string karmaConfigFilePath = null;
      string projectDir = null;
      foreach (var project in projects.Values)
      {
        try
        {
          var projectGuids = project.GetProjectTypeGuids(GetService);

          _karmaOutputWindowPane.OutputString(
              "DEBUG: project '" + project.Name + "' found; GUIDs: " + projectGuids);

          if (projectGuids.Contains(webApplication) ||
              projectGuids.Contains(webSite))
          {
            _karmaOutputWindowPane.OutputString(
                "INFO: Web project found: " + project.Name);
            _karmaOutputWindowPane.OutputString(Environment.NewLine);

            projectDir =
                Path.GetDirectoryName(project.FileName);

            karmaConfigFilePath =
                Path.Combine(projectDir, "karma." + config + ".conf.js");

            if (File.Exists(karmaConfigFilePath))
            {
              _karmaOutputWindowPane.OutputString(
                  "INFO: Configuration found: " + karmaConfigFilePath);
              _karmaOutputWindowPane.OutputString(Environment.NewLine);
              karmaProject = project;
              break;<commit_msg>Fix allowing multiple projects with the same name<commit_after>﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.Win32;

namespace devcoach.Tools
{
  /// <summary>
  /// This is the class that implements the package exposed by this assembly.
  /// The minimum requirement for a class to be considered a valid package for Visual Studio
  /// is to implement the IVsPackage interface and register itself with the shell.
  /// This package uses the helper classes defined inside the Managed Package Framework (MPF)
  /// to do it: it derives from the Package class that provides the implementation of the 
  /// IVsPackage interface and uses the registration attributes defined in the framework to 
  /// register itself and its components with the shell.
  /// </summary>
  // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is
  // a package.
  [ProvideAutoLoad(UIContextGuids.SolutionExists)]
  [PackageRegistration(UseManagedResourcesOnly = true)]
  // This attribute is used to register the information needed to show this package
  // in the Help/About dialog of Visual Studio.
  [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
  // This attribute is needed to let the shell know that this package exposes some menus.
  [ProvideMenuResource("Menus.ctmenu", 1)]
  [Guid(GuidList.guidKarmaVsPkgString)]
  public sealed class KarmaVsPackage : Package
  {
    private static readonly object _s_applicationLock = new object();
    public static DTE2 Application { get; private set; }
    private static OutputWindow _outputWindow;
    private static OutputWindowPane _karmaOutputWindowPane;
    private static System.Diagnostics.Process _karmaProcess;
    private static System.Diagnostics.Process _webServerProcess;
    private static Events _events;
    private static DTEEvents _dteEvents;
    private static DocumentEvents _documentEvents;

    readonly Regex _outputDir =
        new Regex(
          @"\[[\d]{1,6}m{1}",
          RegexOptions.Compiled);

    readonly Regex _browserInfo =
        new Regex(
            @"[a-z|A-Z]{4,20}\s([\d]{1,5}\.{0,1})*\s\" +
            @"([a-z|A-Z|\s|\d]{4,20}\)(\:\s|\s|\]\:\s)",
            RegexOptions.Compiled);

    readonly Regex _details =
        new Regex(
          @"\[\d{1,2}[A-Z]{1}|\[\d{1,2}m{1}",
          RegexOptions.Compiled);

    #region Initialize()
    protected override void Initialize()
    {
      lock (_s_applicationLock)
      {
        Application = (DTE2)GetService(typeof(SDTE));
        _events = Application.Application.Events;
        _dteEvents = _events.DTEEvents;
        _documentEvents = _events.DocumentEvents;

        var win =
          Application.Windows.Item(EnvDTE.Constants.vsWindowKindOutput);
        _outputWindow = win.Object as OutputWindow;
        if (_outputWindow != null)
        {
          _karmaOutputWindowPane =
            _outputWindow.OutputWindowPanes.Add("Karma");
        }
        _dteEvents.OnBeginShutdown += ShutdownKarma;
        _events.SolutionEvents.Opened += SolutionEventsOpened;

      }

      base.Initialize();

      // Add our command handlers for menu (commands must exist in .vsct file)
      var mcs =
        GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
      if (null == mcs) return;

      // Create the command for the menu item.
      var menuCommandId1 =
        new CommandID(
          GuidList.guidToggleKarmaVsUnitCmdSet,
          (int)PkgCmdIDList.cmdidToggleKarmaVsUnit
        );
      var menuItem1 = new MenuCommand(KarmaVsUnit, menuCommandId1);
      mcs.AddCommand(menuItem1);

      // Create the command for the menu item.
      var menuCommandId2 =
        new CommandID(
          GuidList.guidToggleKarmaVsE2eCmdSet,
          (int)PkgCmdIDList.cmdidToggleKarmaVsE2e
        );
      var menuItem2 = new MenuCommand(KarmaVsE2e, menuCommandId2);
      mcs.AddCommand(menuItem2);
    }
    #endregion

    #region SolutionEventsOpened()
    private void SolutionEventsOpened()
    {
      RunKarmaVs();
    }
    #endregion

    #region RunKarmaVs()
    private void RunKarmaVs(string config = "unit")
    {
      _karmaOutputWindowPane.Clear();

      ShutdownKarma();

      var nodeFilePath = GetNodeJsPath();
      if (nodeFilePath == null)
      {
        _karmaOutputWindowPane.OutputString(
            "ERROR: Node not found. Download and " +
            "install from: http://www.nodejs.org");
        _karmaOutputWindowPane.OutputString(Environment.NewLine);
        return;
      }

      _karmaOutputWindowPane.OutputString(
          "INFO: Node installation found: " + nodeFilePath);
      _karmaOutputWindowPane.OutputString(Environment.NewLine);

      var karmaFilePath = GetKarmaPath();
      if (karmaFilePath == null)
      {
        _karmaOutputWindowPane.OutputString(
            "ERROR: Karma was not found. Run \"npm install -g karma\"...");
        _karmaOutputWindowPane.OutputString(Environment.NewLine);
        return;
      }

      _karmaOutputWindowPane.OutputString(
          "INFO: Karma installation found: " + karmaFilePath);
      _karmaOutputWindowPane.OutputString(Environment.NewLine);

      var chromePath = GetChromePath();
      if (chromePath != null)
      {
        _karmaOutputWindowPane.OutputString(
            "INFO: Found Google Chrome : " + chromePath);
        _karmaOutputWindowPane.OutputString(Environment.NewLine);
        Environment.SetEnvironmentVariable("CHROME_BIN", chromePath);
      }

      var mozillaPath = GetMozillaPath();
      if (mozillaPath != null)
      {
        _karmaOutputWindowPane.OutputString(
            "INFO: Found Mozilla Firefox: " + mozillaPath);
        _karmaOutputWindowPane.OutputString(Environment.NewLine);
        Environment.SetEnvironmentVariable("FIREFOX_BIN", mozillaPath);
      }

      if (Application.Solution.Projects.Count < 1)
      {
        _karmaOutputWindowPane.OutputString("ERROR: No projects loaded");
        _karmaOutputWindowPane.OutputString(Environment.NewLine);
        return;
      }


      var projects = GetProjects();

      const string webApplication = "{349C5851-65DF-11DA-9384-00065B846F21}";
      const string webSite = "{E24C65DC-7377-472B-9ABA-BC803B73C61A}";

      Project karmaProject = null;
      string karmaConfigFilePath = null;
      string projectDir = null;
      foreach (var project in projects)
      {
        try
        {
          var projectGuids = project.GetProjectTypeGuids(GetService);

          _karmaOutputWindowPane.OutputString(
              "DEBUG: project '" + project.Name + "' found; GUIDs: " + projectGuids);

          if (projectGuids.Contains(webApplication) ||
              projectGuids.Contains(webSite))
          {
            _karmaOutputWindowPane.OutputString(
                "INFO: Web project found: " + project.Name);
            _karmaOutputWindowPane.OutputString(Environment.NewLine);

            projectDir =
                Path.GetDirectoryName(project.FileName);

            karmaConfigFilePath =
                Path.Combine(projectDir, "karma." + config + ".conf.js");

            if (File.Exists(karmaConfigFilePath))
            {
              _karmaOutputWindowPane.OutputString(
                  "INFO: Configuration found: " + karmaConfigFilePath);
              _karmaOutputWindowPane.OutputString(Environment.NewLine);
              karmaProject = project;
              break;
{'fraction_non_alphanumeric': 0.09364548494983277, 'fraction_numerical': 0.011962953434525341, 'mean_word_length': 2.736842105263158, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6587140', 'n_tokens_mistral': 4509, 'n_tokens_neox': 4265, 'n_words': 1032}