public static void Main(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            bool isFirstInstance;

            // Please use a unique name for the mutex to prevent conflicts with other programs
            using (Mutex mtx = new Mutex(true, "IntegratorEduTeacherNotify", out isFirstInstance)) {
                if (isFirstInstance)
                {
                    NotificationIcon notificationIcon = new NotificationIcon();
                    notificationIcon.notifyIcon.Visible = true;
                    Application.Run();
                    notificationIcon.notifyIcon.Dispose();
                }
                else
                {
                    MessageForm.ShowMessage("There is more than one user logged in. Please log off, go to the other then user off that user too, then log back in (until then, your board calibration and notifications may not work properly).", my_display_name_and_version);
                    // The application is already running
                    // TODO: Display message box or change focus to existing application instance
                }
            }             // releases the Mutex
        }
 private void iconDoubleClick(object sender, EventArgs e)
 {
     MessageForm.ShowMessage(my_about_string + status_string, "About " + my_display_name_and_version);
 }
        private void secondlyTimerTick(object sender, EventArgs e)
        {
            string my_error_string = "";

            if (secondlyTimer.Enabled)
            {
                any_disposable_timed_events_today = false;
                secondlyTimer.Enabled             = false;
                secondly_check_count++;
                if (daily_disposable_events_table != null)
                {
                    try {
                        my_error_string = "";
                        int Time_Column = daily_disposable_events_table.InternalColumnIndexOfI_AssumingNeedleIsLower("time");
                        if (Time_Column < 0)
                        {
                            my_error_string += "missing Time column ";
                        }
                        int Category_Column = daily_disposable_events_table.InternalColumnIndexOfI_AssumingNeedleIsLower("category");
                        if (Category_Column < 0)
                        {
                            my_error_string += "missing Category column ";
                        }
                        int Description_Column = daily_disposable_events_table.InternalColumnIndexOfI_AssumingNeedleIsLower("description");
                        if (Description_Column < 0)
                        {
                            my_error_string += "missing Description column ";
                        }
                        int Days_Column = daily_disposable_events_table.InternalColumnIndexOfI_AssumingNeedleIsLower("days");
                        if (Days_Column < 0)
                        {
                            my_error_string += "missing Days column ";
                        }
                        if (string.IsNullOrEmpty(my_error_string))
                        {
                            DateTime temporary_last_daily_alert_time = DateTime.MinValue;
                            for (int row_index = 0; row_index < daily_disposable_events_table.Rows; row_index++)
                            {
                                string days_string = daily_disposable_events_table.GetForcedString(row_index, Days_Column);
                                if (!string.IsNullOrEmpty(days_string))
                                {
                                    string[] days_array             = days_string.Split(';');
                                    bool     this_event_fires_today = false;
                                    for (int relative_day_entry_index = 0; relative_day_entry_index < days_array.Length; relative_day_entry_index++)
                                    {
                                        if ((days_array[relative_day_entry_index].Length == 2 && DateTime.Now.ToString("dddd").ToLower().Substring(0, 2) == days_array[relative_day_entry_index].ToLower()) ||
                                            DateTime.Now.ToString("dddd").ToLower() == days_array[relative_day_entry_index].ToLower() ||
                                            DateTime.Now.ToString("ddd").ToLower() == days_array[relative_day_entry_index].ToLower()
                                            )
                                        {
                                            this_event_fires_today = true;
                                            break;
                                        }
                                        else
                                        {
                                            //Console.Error.WriteLine(days_array[relative_day_entry_index].ToLower()+" is not today ("+DateTime.Now.ToString("dddd").ToLower()+")");
                                        }
                                    }
                                    if (this_event_fires_today)
                                    {
                                        any_disposable_timed_events_today = true;
                                        string   category_string    = daily_disposable_events_table.GetForcedString(row_index, Category_Column);
                                        string   description_string = daily_disposable_events_table.GetForcedString(row_index, Description_Column);
                                        string   time_string        = daily_disposable_events_table.GetForcedString(row_index, Time_Column);
                                        DateTime thisDateTime       = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd ") + time_string);
                                        if (thisDateTime >= program_load_datetime
                                            //thisDateTime<=DateTime.Now
                                            //&& thisDateTime>last_daily_alert_not_including_before_loadtime_alerts_time
                                            && DateTime.Now.ToString("yyyy-MM-dd HH:mm") != last_daily_alert_not_including_before_loadtime_alerts_time.ToString("yyyy-MM-dd HH:mm") &&
                                            DateTime.Now.ToString("yyyy-MM-dd HH:mm") == thisDateTime.ToString("yyyy-MM-dd HH:mm")
                                            )
                                        {
                                            if (is_verbose)
                                            {
                                                Console.Error.WriteLine();
                                                Console.Error.WriteLine("Event instance DateTime:" + thisDateTime.ToString("yyyy-MM-dd HH:mm:ss"));
                                            }
                                            last_alert_string = "(invalid category '" + category_string + "')";
                                            string category_path         = Path.Combine(categories_path, category_string + ".yml");
                                            bool   is_good_ec            = false;
                                            string categories_to_string  = "";
                                            bool   is_ignored            = false;
                                            string category_string_lower = category_string.ToLower();
                                            if (locally_ignored_categories_list != null)
                                            {
                                                foreach (string ignore_ec_string in locally_ignored_categories_list)
                                                {
                                                    if (ignore_ec_string.ToLower() == category_string_lower)
                                                    {
                                                        is_ignored = true;
                                                    }
                                                }
                                            }
                                            //TODO: make this case insensitive:
                                            if (!is_ignored)
                                            {
                                                foreach (IEduEventCategory check_ec in recurring_event_categories)
                                                {
                                                    if (check_ec != null)
                                                    {
                                                        if (check_ec.name.ToLower() == category_string.ToLower())
                                                        {
                                                            categories_to_string += (string.IsNullOrEmpty(categories_to_string))?check_ec.name:categories_to_string + ", " + check_ec.name;
                                                            is_good_ec            = true;
                                                            last_alert_string     = "";
                                                            if (!string.IsNullOrEmpty(check_ec.sound_file_path))
                                                            {
                                                                soundplayer.SoundLocation = Path.Combine(data_path, check_ec.sound_file_path);
                                                                string alert_part_string = " Play(@\"" + soundplayer.SoundLocation.Replace("\"", "\\\"") + "\")";
                                                                last_alert_string += alert_part_string;
                                                                Console.Error.Write(alert_part_string);
                                                                soundplayer.Play();
                                                            }
                                                            if (!string.IsNullOrEmpty(check_ec.message_heading) || !string.IsNullOrEmpty(check_ec.message))
                                                            {
                                                                string msg     = (check_ec.message != null)?check_ec.message:"";
                                                                string caption = (check_ec.message_heading != null?check_ec.message_heading:"");
                                                                if (string.IsNullOrEmpty(caption))
                                                                {
                                                                    caption = my_display_name_and_version;
                                                                }
                                                                //else caption+=" via "+my_display_name;
                                                                last_alert_string += "; MessageForm (\"" + msg.Replace("\"", "\\\"") + "\", \"" + caption.Replace("\"", "\\\"") + "\")";

                                                                MessageForm.ShowMessage(msg, caption);
                                                            }
                                                            last_alert_string += " (" + thisDateTime.ToString("yyyy-MM-dd HH:mm") + ")";
                                                        }
                                                    }
                                                }
                                                if (!is_good_ec)
                                                {
                                                    last_alert_string = "(invalid category '" + category_string + "': not found among list [ " + categories_to_string + "])";
                                                }
                                            }
                                            else
                                            {
                                                last_alert_string = "";                     // in locally_ignored_categories_list
                                            }
                                            temporary_last_daily_alert_time = DateTime.Now; //Since using temporary value, will not prevent other event of same second but different category from firing?
                                        }                                                   //end if in range of last time and this time, and now is not same minute as last check, but event is same minute as now
                                        else
                                        {
                                            if (DateTime.Now.ToString("yyyy-MM-dd HH:mm") == thisDateTime.ToString("yyyy-MM-dd HH:mm"))
                                            {
                                                Console.Error.WriteLine("  ignoring event since:");
                                                Console.Error.WriteLine("    DateTime.Now: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm"));
                                                Console.Error.WriteLine("    event: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm"));
                                                Console.Error.WriteLine("    last alert: " + last_daily_alert_not_including_before_loadtime_alerts_time.ToString("yyyy-MM-dd HH:mm"));
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    my_error_string = events_file_path + " is missing Days for alert on line " + (row_index + 2).ToString() + " so it will never happen.";                           //+2 to convert to counting number AND add title row
                                }
                            }
                            if (temporary_last_daily_alert_time != DateTime.MinValue)
                            {
                                //for purpose of this, see comment on previous usage of temporary_last_daily_alert_time
                                last_daily_alert_not_including_before_loadtime_alerts_time = temporary_last_daily_alert_time;
                            }
                        }
                    }
                    catch (Exception exn) {
                        if (!string.IsNullOrEmpty(my_error_string))
                        {
                            my_error_string = my_error_string + " AND ";
                        }
                        my_error_string += "secondlyTimerTick could not finish because " + exn.ToString();
                    }
                }
                else
                {
                    my_error_string = "secondlyTimerTick found null daily_disposable_events_table.";
                }
                secondlyTimer.Enabled = true;
            }
            else
            {
                my_error_string = "secondly timer was already firing.";
            }
            if (!string.IsNullOrEmpty(my_error_string))
            {
                last_error_string = my_error_string;
            }
            updateStatus();
        }        //end secondlyTimerTick