From 85ade02cba79418755ec64a3848b73b9b107702d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 29 Aug 2021 09:17:31 -0400 Subject: [PATCH 01/10] Set shm->valid to false on disconnect. --- src/zm_monitor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index c1fadd6e1..a15d2c99d 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1063,6 +1063,7 @@ bool Monitor::disconnect() { return true; } + shared_data->valid = false; #if ZM_MEM_MAPPED msync(mem_ptr, mem_size, MS_ASYNC); munmap(mem_ptr, mem_size); From 199e86e92a2fb7f1f9ec51378ca2f95b18546031 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 29 Aug 2021 09:15:40 -0400 Subject: [PATCH 02/10] spacing --- src/zm_monitor.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index a15d2c99d..a42c0759c 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -204,7 +204,7 @@ bool Monitor::MonitorLink::connect() { shared_data = (SharedData *)mem_ptr; trigger_data = (TriggerData *)((char *)shared_data + sizeof(SharedData)); - if ( !shared_data->valid ) { + if (!shared_data->valid) { Debug(3, "Linked memory not initialised by capture daemon"); disconnect(); return false; @@ -220,23 +220,23 @@ bool Monitor::MonitorLink::connect() { } // end bool Monitor::MonitorLink::connect() bool Monitor::MonitorLink::disconnect() { - if ( connected ) { + if (connected) { connected = false; #if ZM_MEM_MAPPED - if ( mem_ptr > (void *)0 ) { - msync( mem_ptr, mem_size, MS_ASYNC ); - munmap( mem_ptr, mem_size ); + if (mem_ptr > (void *)0) { + msync(mem_ptr, mem_size, MS_ASYNC); + munmap(mem_ptr, mem_size); } - if ( map_fd >= 0 ) - close( map_fd ); + if (map_fd >= 0) + close(map_fd); map_fd = -1; #else // ZM_MEM_MAPPED struct shmid_ds shm_data; - if ( shmctl( shm_id, IPC_STAT, &shm_data ) < 0 ) { - Debug( 3, "Can't shmctl: %s", strerror(errno) ); - return( false ); + if (shmctl(shm_id, IPC_STAT, &shm_data) < 0) { + Debug(3, "Can't shmctl: %s", strerror(errno)); + return false; } shm_id = 0; @@ -252,7 +252,6 @@ bool Monitor::MonitorLink::disconnect() { Debug(3, "Can't shmdt: %s", strerror(errno)); return false; } - #endif // ZM_MEM_MAPPED mem_size = 0; mem_ptr = nullptr; @@ -899,7 +898,6 @@ std::shared_ptr Monitor::Load(unsigned int p_id, bool load_zones, Purpo } bool Monitor::connect() { - if (mem_ptr != nullptr) { Warning("Already connected. Please call disconnect first."); } @@ -1041,7 +1039,7 @@ bool Monitor::connect() { video_store_data->size = sizeof(VideoStoreData); usedsubpixorder = camera->SubpixelOrder(); // Used in CheckSignal shared_data->valid = true; - } else if ( !shared_data->valid ) { + } else if (!shared_data->valid) { Error("Shared data not initialised by capture daemon for monitor %s", name.c_str()); return false; } From 6a0e27db4cb2e54296ccfbad7adbbda40d6a8af8 Mon Sep 17 00:00:00 2001 From: gmanproxtreme <36477327+gmanproxtreme@users.noreply.github.com> Date: Fri, 27 Aug 2021 20:21:02 +1000 Subject: [PATCH 03/10] Updated WEB_TITLE section from ToDo. The Web_Title's use was unknown. I have seen the changed title appear on the login screen. Documentation updated to reflect this. --- docs/userguide/options/options_web.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/userguide/options/options_web.rst b/docs/userguide/options/options_web.rst index 6766a2248..7ae0ac628 100644 --- a/docs/userguide/options/options_web.rst +++ b/docs/userguide/options/options_web.rst @@ -5,10 +5,7 @@ This screen lets you customize several aspects of the web interface of ZoneMinde .. image:: images/Options_web.png -WEB_TITLE - - -.. todo :: - not quite sure what this does. Seems to change the "target" name - not sure what effect it is supposed to have. +WEB_TITLE - The actual text that is shown on the login screen. It is possible that it also appears in other areas. WEB_TITLE_PREFIX - If you have more than one installation of ZoneMinder it can be helpful to display different titles for each one. Changing this option allows you to customise the window titles to include further information to aid identification. @@ -48,4 +45,4 @@ WEB_USE_OBJECT_TAGS - There are two methods of including media content in web pa WEB_XFRAME_WARN - When creating a Web Site monitor, if the target web site has X-Frame-Options set to sameorigin in the header, the site will not display in ZoneMinder. This is a design feature in most modern browsers. When this condition occurs, ZoneMinder will write a warning to the log file. To get around this, one can install a browser plugin or extension to ignore X-Frame headers, and then the page will display properly. Once the plugin or extension has ben installed, the end user may choose to turn this warning off -WEB_FILTER_SOURCE - This option only affects monitors with a source type of Ffmpeg, Libvlc, or WebSite. This setting controls what information is displayed in the Source column on the console. Selecting 'None' will not filter anything. The entire source string will be displayed, which may contain sensitive information. Selecting 'NoCredentials' will strip out usernames and passwords from the string. If there are any port numbers in the string and they are common (80, 554, etc) then those will be removed as well. Selecting 'Hostname' will filter out all information except for the hostname or ip address. When in doubt, stay with the default 'Hostname'. This feature uses the php function 'url_parts' to identify the various pieces of the url. If the url in question is unusual or not standard in some way, then filtering may not produce the desired results. \ No newline at end of file +WEB_FILTER_SOURCE - This option only affects monitors with a source type of Ffmpeg, Libvlc, or WebSite. This setting controls what information is displayed in the Source column on the console. Selecting 'None' will not filter anything. The entire source string will be displayed, which may contain sensitive information. Selecting 'NoCredentials' will strip out usernames and passwords from the string. If there are any port numbers in the string and they are common (80, 554, etc) then those will be removed as well. Selecting 'Hostname' will filter out all information except for the hostname or ip address. When in doubt, stay with the default 'Hostname'. This feature uses the php function 'url_parts' to identify the various pieces of the url. If the url in question is unusual or not standard in some way, then filtering may not produce the desired results. From a258567c16af6a14eba84f2955701f1a80ca5fae Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Oct 2021 09:43:49 -0400 Subject: [PATCH 04/10] You cannot commit on error because it releases the locks. --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 48544a911..c786392ad 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -756,9 +756,9 @@ sub CopyTo { } # end sub CopyTo sub MoveTo { - my ( $self, $NewStorage ) = @_; + my ($self, $NewStorage) = @_; - if ( !$self->canEdit() ) { + if (!$self->canEdit()) { Warning('No permission to move event.'); return 'No permission to move event.'; } @@ -772,11 +772,9 @@ sub MoveTo { $$self{StorageId} = $$NewStorage{Id}; $self->Storage($NewStorage); $error .= $self->save(); - if ( $error ) { - $ZoneMinder::Database::dbh->commit(); + if ($error) { return $error; } - $ZoneMinder::Database::dbh->commit(); $self->delete_files($OldStorage); return $error; } # end sub MoveTo From 522f8dd5bab5ca455838d711f31425f8cd02e09d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Oct 2021 09:44:20 -0400 Subject: [PATCH 05/10] Do no commit on error as it releases locks. Add better storage loading error handling --- scripts/zmfilter.pl.in | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 1e62cb229..aa1371d99 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -358,25 +358,27 @@ sub checkFilter { } } # end if AutoDelete - if ( $filter->{AutoMove} ) { - my $NewStorage = new ZoneMinder::Storage($filter->{AutoMoveTo}); - Info("Moving event $Event->{Id} to datastore $filter->{AutoMoveTo}"); - $_ = $Event->MoveTo($NewStorage); - Error($_) if $_; + if ($filter->{AutoMove}) { + my $NewStorage = ZoneMinder::Storage->find_one(Id=>$filter->{AutoMoveTo}); + if ($NewStorage) { + Info("Moving event $Event->{Id} to datastore $filter->{AutoMoveTo}"); + $_ = $Event->MoveTo($NewStorage); + Error($_) if $_; + } else { + Error("No storage area found for move to operation. AutoMoveTo was $$filter{AutoMoveTo}"); + } } - if ( $filter->{AutoCopy} ) { + if ($filter->{AutoCopy}) { # Copy To is different from MoveTo in that it JUST copies the files # So we still need to update the Event object with the new SecondaryStorageId my $NewStorage = ZoneMinder::Storage->find_one(Id=>$filter->{AutoCopyTo}); if ( $NewStorage ) { Info("Copying event $Event->{Id} to datastore $filter->{AutoCopyTo}"); $_ = $Event->CopyTo($NewStorage); - if ( $_ ) { - $ZoneMinder::Database::dbh->commit(); + if ($_) { Error($_); } else { $Event->save({SecondaryStorageId=>$$NewStorage{Id}}); - $ZoneMinder::Database::dbh->commit(); } } else { Error("No storage area found for copy to operation. AutoCopyTo was $$filter{AutoCopyTo}"); From c600725a1ad3632482923b2e203c659f176cca5e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Oct 2021 16:40:21 -0400 Subject: [PATCH 06/10] Fix monitor type labels by adding an Unknown for entry 0. Implement Function_Strings. Fix decoding_enabled not being recalculated correctly because we havn't loaded savejpegs or videowriter yet. --- src/zm_monitor.cpp | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 20a2a4cda..545d173d5 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -92,6 +92,7 @@ std::string load_monitor_sql = "`SignalCheckPoints`, `SignalCheckColour`, `Importance`-1 FROM `Monitors`"; std::string CameraType_Strings[] = { + "Unknown", "Local", "Remote", "File", @@ -99,10 +100,21 @@ std::string CameraType_Strings[] = { "LibVLC", "NVSOCKET", "CURL", - "VNC", + "VNC" +}; + +std::string Function_Strings[] = { + "Unknown", + "None", + "Monitor", + "Modect", + "Record", + "Mocord", + "Nodect" }; std::string State_Strings[] = { + "Unknown", "IDLE", "PREALARM", "ALARM", @@ -483,16 +495,7 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) { function = (Function)atoi(dbrow[col]); col++; enabled = dbrow[col] ? atoi(dbrow[col]) : false; col++; decoding_enabled = dbrow[col] ? atoi(dbrow[col]) : false; col++; - decoding_enabled = !( - ( function == RECORD or function == NODECT ) - and - ( savejpegs == 0 ) - and - ( videowriter == PASSTHROUGH ) - and - !decoding_enabled - ); - Debug(1, "Decoding enabled: %d", decoding_enabled); + // See below after save_jpegs for a recalculation of decoding_enabled ReloadLinkedMonitors(dbrow[col]); col++; @@ -555,6 +558,17 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) { videowriter = (VideoWriter)atoi(dbrow[col]); col++; encoderparams = dbrow[col] ? dbrow[col] : ""; col++; + decoding_enabled = !( + ( function == RECORD or function == NODECT ) + and + ( savejpegs == 0 ) + and + ( videowriter == PASSTHROUGH ) + and + !decoding_enabled + ); + Debug(3, "Decoding enabled: %d function %d %s savejpegs %d videowriter %d", decoding_enabled, function, Function_Strings[function].c_str(), savejpegs, videowriter); + /*"`OutputCodec`, `Encoder`, `OutputContainer`, " */ output_codec = dbrow[col] ? atoi(dbrow[col]) : 0; col++; encoder = dbrow[col] ? dbrow[col] : ""; col++; From d4467dba36f9388b80f0ec42202dc34485506c37 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 20 Oct 2021 13:13:50 -0400 Subject: [PATCH 07/10] Fix logic ordering in 1.35.14 updated that moves columns from Monitors table to Monitor_Status --- db/zm_update-1.35.14.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/db/zm_update-1.35.14.sql b/db/zm_update-1.35.14.sql index daa8239ff..f3c8bf779 100644 --- a/db/zm_update-1.35.14.sql +++ b/db/zm_update-1.35.14.sql @@ -28,8 +28,8 @@ SET @s = (SELECT IF( AND table_name = 'Monitors' AND column_name = 'TotalEvents' ) > 0, -"SELECT 'Column TotalEvents is already removed from Monitors'", -"ALTER TABLE `Monitors` DROP `TotalEvents`" +"ALTER TABLE `Monitors` DROP `TotalEvents`", +"SELECT 'Column TotalEvents is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; @@ -50,8 +50,8 @@ SET @s = (SELECT IF( AND table_name = 'Monitors' AND column_name = 'TotalEventDiskSpace' ) > 0, -"SELECT 'Column TotalEventDiskSpace is already removed from Monitors'", -"ALTER TABLE `Monitors` DROP `TotalEventDiskSpace`" +"ALTER TABLE `Monitors` DROP `TotalEventDiskSpace`", +"SELECT 'Column TotalEventDiskSpace is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; From 22f398dd6fcc0bc2d8d1a39c6576085f2a67e40b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Oct 2021 16:55:20 -0400 Subject: [PATCH 08/10] set vertical-align:top on monitor edit labels --- web/skins/classic/css/base/views/monitor.css | 1 + 1 file changed, 1 insertion(+) diff --git a/web/skins/classic/css/base/views/monitor.css b/web/skins/classic/css/base/views/monitor.css index 7fca80aac..f827af5ca 100644 --- a/web/skins/classic/css/base/views/monitor.css +++ b/web/skins/classic/css/base/views/monitor.css @@ -50,6 +50,7 @@ select.chosen { } tr td:first-child { min-width: 300px; + vertical-align: top; } .OutputContainer { display: none; From 4b5bc09c41318929e5efd1511c5693260c2f79b4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Oct 2021 17:03:36 -0400 Subject: [PATCH 09/10] Merge new logic from master. We now delete a non-keyframe from head instead of waiting in capture. --- src/zm_packetqueue.cpp | 135 +++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 67 deletions(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index d57346a30..ceef421db 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -24,7 +24,6 @@ #include "zm_ffmpeg.h" #include "zm_packet.h" #include "zm_signal.h" -#include PacketQueue::PacketQueue(): video_stream_id(-1), @@ -87,61 +86,6 @@ bool PacketQueue::queuePacket(std::shared_ptr add_packet) { { std::unique_lock lck(mutex); - if (add_packet->packet.stream_index == video_stream_id) { - if ((max_video_packet_count > 0) and (packet_counts[video_stream_id] > max_video_packet_count)) { - Warning("You have set the max video packets in the queue to %u." - " The queue is full. Either Analysis is not keeping up or" - " your camera's keyframe interval is larger than this setting." - " We are dropping packets.", max_video_packet_count); - if (add_packet->keyframe) { - // Have a new keyframe, so delete everything - while ((*pktQueue.begin() != add_packet) and (packet_counts[video_stream_id] > max_video_packet_count)) { - std::shared_ptr zm_packet = *pktQueue.begin(); - ZMLockedPacket *lp = new ZMLockedPacket(zm_packet); - if (!lp->trylock()) { - Debug(1, "Found locked packet when trying to free up video packets. Can't continue"); - delete lp; - break; - } - delete lp; - - for ( - std::list::iterator iterators_it = iterators.begin(); - iterators_it != iterators.end(); - ++iterators_it - ) { - packetqueue_iterator *iterator_it = *iterators_it; - // Have to check each iterator and make sure it doesn't point to the packet we are about to delete - if ( *(*iterator_it) == zm_packet ) { - Debug(1, "Bumping IT because it is at the front that we are deleting"); - ++(*iterators_it); - } - } // end foreach iterator - - pktQueue.pop_front(); - packet_counts[zm_packet->packet.stream_index] -= 1; - Debug(1, - "Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%zu", - zm_packet->packet.stream_index, - zm_packet->image_index, - zm_packet->keyframe, - packet_counts[video_stream_id], - max_video_packet_count, - pktQueue.size()); - } // end while - } - } // end if too many video packets - if (max_video_packet_count > 0) { - while (packet_counts[video_stream_id] > max_video_packet_count) { - Error("Unable to free up older packets. Waiting."); - condition.notify_all(); - condition.wait(lck); - if (deleting or zm_terminate) - return false; - } - } - } // end if this packet is a video packet - pktQueue.push_back(add_packet); packet_counts[add_packet->packet.stream_index] += 1; Debug(2, "packet counts for %d is %d", @@ -149,25 +93,79 @@ bool PacketQueue::queuePacket(std::shared_ptr add_packet) { packet_counts[add_packet->packet.stream_index]); for ( - std::list::iterator iterators_it = iterators.begin(); + auto iterators_it = iterators.begin(); iterators_it != iterators.end(); ++iterators_it ) { packetqueue_iterator *iterator_it = *iterators_it; if (*iterator_it == pktQueue.end()) { - Debug(4, "pointing it %p to back", iterator_it); --(*iterator_it); - } else { - Debug(4, "it %p not at end", iterator_it); } } // end foreach iterator + + if ( + (add_packet->packet.stream_index == video_stream_id) + and + (max_video_packet_count > 0) + and + (packet_counts[video_stream_id] > max_video_packet_count) + ) { + Warning("You have set the max video packets in the queue to %u." + " The queue is full. Either Analysis is not keeping up or" + " your camera's keyframe interval is larger than this setting." + , max_video_packet_count); + + for ( + auto it = ++pktQueue.begin(); + it != pktQueue.end() and *it != add_packet; + ) { + std::shared_ptr zm_packet = *it; + + ZMLockedPacket *lp = new ZMLockedPacket(zm_packet); + if (!lp->trylock()) { + Debug(1, "Found locked packet when trying to free up video packets. Skipping to next one"); + delete lp; + ++it; + continue; + } + + for ( + auto iterators_it = iterators.begin(); + iterators_it != iterators.end(); + ++iterators_it + ) { + auto iterator_it = *iterators_it; + // Have to check each iterator and make sure it doesn't point to the packet we are about to delete + if ((*iterator_it!=pktQueue.end()) and (*(*iterator_it) == zm_packet)) { + Debug(1, "Bumping IT because it is at the front that we are deleting"); + ++(*iterator_it); + } + } // end foreach iterator + + it = pktQueue.erase(it); + packet_counts[zm_packet->packet.stream_index] -= 1; + Debug(1, + "Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%zu", + zm_packet->packet.stream_index, + zm_packet->image_index, + zm_packet->keyframe, + packet_counts[video_stream_id], + max_video_packet_count, + pktQueue.size()); + + delete lp; + + if (zm_packet->packet.stream_index == video_stream_id) + break; + } // end while + } // end if not able catch up } // end lock scope // We signal on every packet because someday we may analyze sound Debug(4, "packetqueue queuepacket, unlocked signalling"); condition.notify_all(); return true; -} // end bool PacketQueue::queuePacket(ZMPacket* zm_packet) +} // end bool PacketQueue::queuePacket(ZMPacket* zm_packet) void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { // Only do queueCleaning if we are adding a video keyframe, so that we guarantee that there is one. @@ -241,8 +239,8 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { return; } - packetqueue_iterator it = pktQueue.begin(); - packetqueue_iterator next_front = pktQueue.begin(); + auto it = pktQueue.begin(); + auto next_front = pktQueue.begin(); // First packet is special because we know it is a video keyframe and only need to check for lock std::shared_ptr zm_packet = *it; @@ -250,11 +248,10 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { return; } - Debug(1, "trying lock on first packet"); ZMLockedPacket *lp = new ZMLockedPacket(zm_packet); if (lp->trylock()) { int video_packets_to_delete = 0; // This is a count of how many packets we will delete so we know when to stop looking - Debug(1, "Have lock on first packet"); + Debug(4, "Have lock on first packet"); ++it; delete lp; @@ -269,10 +266,14 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { } delete lp; - if (is_there_an_iterator_pointing_to_packet(zm_packet) and (pktQueue.begin() == next_front)) { - Warning("Found iterator at beginning of queue. Some thread isn't keeping up"); +#if 0 + // There are no threads that follow analysis thread. So there cannot be an it pointing here + if (is_there_an_iterator_pointing_to_packet(zm_packet)) { + if (pktQueue.begin() == next_front) + Warning("Found iterator at beginning of queue. Some thread isn't keeping up"); break; } +#endif if (zm_packet->packet.stream_index == video_stream_id) { if (zm_packet->keyframe) { From 1ab58aabc6df8bc009f803d6876c30c40b652a28 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Oct 2021 17:05:06 -0400 Subject: [PATCH 10/10] Bump version to 1.36.10 --- distros/redhat/zoneminder.spec | 5 ++++- version | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 813c58519..58ca5dbf9 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -36,7 +36,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.36.9 +Version: 1.36.10 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons @@ -430,6 +430,9 @@ ln -sf %{_sysconfdir}/zm/www/zoneminder.nginx.conf %{_sysconfdir}/zm/www/zonemin %dir %attr(755,nginx,nginx) %{_localstatedir}/log/zoneminder %changelog +* Mon Oct 25 2021 Andrew Bauer - 1.36.10-1 +- 1.36.10 release + * Tue Oct 19 2021 Andrew Bauer - 1.36.9-1 - 1.36.9 release diff --git a/version b/version index 42bce65fd..da140cd3f 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.36.9 +1.36.10