<commit_before>using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using CSScriptLibrary;
using Quartz;
using Quartz.Impl;

namespace Cronshop
{
    public class CronshopScheduler : IDisposable
    {
        private const string InternalScriptKey = "__InternalScript";
        private readonly IScriptCatalog _catalog;
        private readonly List<JobInfo> _jobs = new List<JobInfo>();
        private readonly ReadOnlyCollection<JobInfo> _readOnlyJobs;
        private readonly IScheduler _scheduler;

        static CronshopScheduler()
        {
            // for now -- this is less painful on temp files and file locks.
            CSScript.CacheEnabled = false;
            CSScript.GlobalSettings.InMemoryAsssembly = true;
        }

        public CronshopScheduler(IScriptCatalog catalog)
        {
            _catalog = catalog;
            _catalog.CatalogChanged += CatalogChanged;

            _readOnlyJobs = new ReadOnlyCollection<JobInfo>(_jobs);

            ISchedulerFactory factory = new StdSchedulerFactory();
            _scheduler = factory.GetScheduler();
            Scheduler.JobFactory = new SafeJobFactory();
            Scheduler.AddGlobalJobListener(new MainJobMonitor(_readOnlyJobs));

            LoadJobsFromCatalog();
        }

        public ReadOnlyCollection<JobInfo> Jobs
        {
            get { return _readOnlyJobs; }
        }

        protected internal IScheduler Scheduler
        {
            get { return _scheduler; }
        }

        #region IDisposable Members

        public void Dispose()
        {
            Stop();

            _catalog.CatalogChanged -= CatalogChanged;
        }

        #endregion

        private void CatalogChanged(object sender, CatalogChangedEventArgs e)
        {
            Console.WriteLine("event");

            foreach (var change in e.Changes)
            {
                Console.Write("change: " + change.Item1);
                Console.WriteLine(" -> " + change.Item2);
            }

            while (e.Changes.Count > 0)
            {
                var change = e.Changes.Dequeue();

                if (change.Item2 == CatalogChange.Deleted)
                {
                    UnscheduleScript(change.Item1);
                }
                else if (change.Item2 == CatalogChange.Created)
                {
                    ScheduleScript(change.Item1);
                }
                else if (change.Item2 == CatalogChange.Modified)
                {
                    UnscheduleScript(change.Item1);
                    ScheduleScript(change.Item1);
                }
            }
        }

        private void LoadJobsFromCatalog()
        {
            CronshopScript[] scripts = _catalog.Scripts.ToArray();

            foreach (CronshopScript script in scripts)
            {
                ScheduleScript(script);
            }
        }

        private void ScheduleScript(CronshopScript script)
        {
            Assembly assembly = SaveLoad(script);

            if (assembly == null)
            {
                return;
            }

            Console.WriteLine("ScheduleScript: " + script);

            // find implementations of CronshopJob
            IEnumerable<Type> types = assembly.GetTypes()
                .Where(t => typeof (CronshopJob).IsAssignableFrom(t));

            foreach (Type type in types)
            {
                JobConfigurator configurator;

                // create the instance to get the schedule
                using (var instance = (CronshopJob) Activator.CreateInstance(type))
                {
                    configurator = new JobConfigurator();
                    instance.Configure(configurator);
                }

                string name = script.FullPath;

                var detail = new JobDetail(name, null, type) {Durable = true};
                detail.JobDataMap[InternalScriptKey] = script;

                Scheduler.AddJob(detail, false);

                var triggers = new List<Trigger>();

                foreach (string cron in configurator.Crons)
                {
                    var trigger = new CronTrigger(name + "-" + Guid.NewGuid(), null, cron)
                                      {
                                          JobName = name,
                                          MisfireInstruction = MisfireInstruction.CronTrigger.DoNothing,
                                      };

                    triggers.Add(trigger);

                    Scheduler.ScheduleJob(trigger);
                }

                _jobs.Add(new JobInfo(script, detail, triggers));
            }
        }

        private static Assembly SaveLoad(CronshopScript script)
        {
            try
            {
                return CSScript.Load(script.FullPath);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

            return null;
        }

        private void UnscheduleScript(CronshopScript script)
        {
            bool success = Scheduler.DeleteJob(script.FullPath, null);
            Console.WriteLine("UnscheduleScript: " + script.FullPath + " = " + success);
        }

        public void Start()
        {
            Scheduler.Start();
        }

        public void Stop()
        {
            if (!Scheduler.IsShutdown)
            {
                Scheduler.Shutdown(true);
            }
        }

        public void InterruptJob(string jobName)
        {
            Scheduler.Interrupt(jobName, null);
        }

        public void Pause(string jobName = null)
        {
            if (jobName == null)
            {
                Scheduler.PauseAll();
            }
            else
            {
                Scheduler.PauseJob(jobName, null);
            }
        }

        public void Resume(string jobName = null)
        {
            if (jobName == null)
            {
                Scheduler.ResumeAll();
            }
            else
            {
                Scheduler.ResumeJob(jobName, null);<commit_msg>new stop behavior (now restartable)<commit_after>using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using CSScriptLibrary;
using Quartz;
using Quartz.Impl;

namespace Cronshop
{
    public class CronshopScheduler : IDisposable
    {
        private const string InternalScriptKey = "__InternalScript";
        private readonly IScriptCatalog _catalog;
        private readonly List<JobInfo> _jobs = new List<JobInfo>();
        private readonly ReadOnlyCollection<JobInfo> _readOnlyJobs;
        private readonly IScheduler _scheduler;

        static CronshopScheduler()
        {
            // for now -- this is less painful on temp files and file locks.
            CSScript.CacheEnabled = false;
            CSScript.GlobalSettings.InMemoryAsssembly = true;
        }

        public CronshopScheduler(IScriptCatalog catalog)
        {
            _catalog = catalog;
            _catalog.CatalogChanged += CatalogChanged;

            _readOnlyJobs = new ReadOnlyCollection<JobInfo>(_jobs);

            ISchedulerFactory factory = new StdSchedulerFactory();
            _scheduler = factory.GetScheduler();
            Scheduler.JobFactory = new SafeJobFactory();
            Scheduler.AddGlobalJobListener(new MainJobMonitor(_readOnlyJobs));

            LoadJobsFromCatalog();
        }

        public ReadOnlyCollection<JobInfo> Jobs
        {
            get { return _readOnlyJobs; }
        }

        protected internal IScheduler Scheduler
        {
            get { return _scheduler; }
        }

        #region IDisposable Members

        public void Dispose()
        {
            Scheduler.Shutdown(true);

            _catalog.CatalogChanged -= CatalogChanged;
        }

        #endregion

        private void CatalogChanged(object sender, CatalogChangedEventArgs e)
        {
            Console.WriteLine("event");

            foreach (var change in e.Changes)
            {
                Console.Write("change: " + change.Item1);
                Console.WriteLine(" -> " + change.Item2);
            }

            while (e.Changes.Count > 0)
            {
                var change = e.Changes.Dequeue();

                if (change.Item2 == CatalogChange.Deleted)
                {
                    UnscheduleScript(change.Item1);
                }
                else if (change.Item2 == CatalogChange.Created)
                {
                    ScheduleScript(change.Item1);
                }
                else if (change.Item2 == CatalogChange.Modified)
                {
                    UnscheduleScript(change.Item1);
                    ScheduleScript(change.Item1);
                }
            }
        }

        private void LoadJobsFromCatalog()
        {
            CronshopScript[] scripts = _catalog.Scripts.ToArray();

            foreach (CronshopScript script in scripts)
            {
                ScheduleScript(script);
            }
        }

        private void ScheduleScript(CronshopScript script)
        {
            Assembly assembly = SaveLoad(script);

            if (assembly == null)
            {
                return;
            }

            Console.WriteLine("ScheduleScript: " + script);

            // find implementations of CronshopJob
            IEnumerable<Type> types = assembly.GetTypes()
                .Where(t => typeof (CronshopJob).IsAssignableFrom(t));

            foreach (Type type in types)
            {
                JobConfigurator configurator;

                // create the instance to get the schedule
                using (var instance = (CronshopJob) Activator.CreateInstance(type))
                {
                    configurator = new JobConfigurator();
                    instance.Configure(configurator);
                }

                string name = script.FullPath;

                var detail = new JobDetail(name, null, type) {Durable = true};
                detail.JobDataMap[InternalScriptKey] = script;

                Scheduler.AddJob(detail, false);

                var triggers = new List<Trigger>();

                foreach (string cron in configurator.Crons)
                {
                    var trigger = new CronTrigger(name + "-" + Guid.NewGuid(), null, cron)
                                      {
                                          JobName = name,
                                          MisfireInstruction = MisfireInstruction.CronTrigger.DoNothing,
                                      };

                    triggers.Add(trigger);

                    Scheduler.ScheduleJob(trigger);
                }

                _jobs.Add(new JobInfo(script, detail, triggers));
            }
        }

        private static Assembly SaveLoad(CronshopScript script)
        {
            try
            {
                return CSScript.Load(script.FullPath);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

            return null;
        }

        private void UnscheduleScript(CronshopScript script)
        {
            bool success = Scheduler.DeleteJob(script.FullPath, null);
            Console.WriteLine("UnscheduleScript: " + script.FullPath + " = " + success);
        }

        public void Start()
        {
            Scheduler.Start();
        }

        public void Stop()
        {
            Scheduler.Standby();
        }

        public void InterruptJob(string jobName)
        {
            Scheduler.Interrupt(jobName, null);
        }

        public void Pause(string jobName = null)
        {
            if (jobName == null)
            {
                Scheduler.PauseAll();
            }
            else
            {
                Scheduler.PauseJob(jobName, null);
            }
        }

        public void Resume(string jobName = null)
        {
            if (jobName == null)
            {
                Scheduler.ResumeAll();
            }
            else
            {
                Scheduler.ResumeJob(jobName, null);
{'fraction_non_alphanumeric': 0.07842656198887799, 'fraction_numerical': 0.0016355904481517827, 'mean_word_length': 1.351278600269179, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2866822', 'n_tokens_mistral': 3026, 'n_tokens_neox': 2831, 'n_words': 619}