Before I spend a lot of time writing the only solution I can think of I was wondering if I'm doing it an inefficient way.
Once a support ticket is closed, a script is triggered, the script is passed an array of 'status-change-events' that happened from call open to close. So you might have 5 changes: new, open, active, stalled, resolved. Each one of these events has a timestamp associated with it.
What I need to do is calculate how much time the call was with us (new, open, active) and how much time it was with the customer (stalled). I also need to figure out how much of the 'us' time was within core hours 08:00 - 18:00 (and how many were non-core), and weekends/bank holidays count towards non-core hours.
My current idea is to for each status change, iterate over every second that occurred and check for core/non_core, and log it.
Here's some pseudo code:
time_since_last = ticket->creation_date
foreach events as event {
time_now = time_since_last
while (time_now < ticket->event_date) {
if ticket->status = stalled {
customer_fault_stalled++
} else {
work out if it was our fault or not
add to the appropriate counter etc
}
time_now++
}
}
Apologies if it's a little unclear, it's a fairly longwinded problem. Also I'm aware this may be slightly off of SO question guidelines, but I can't think of a better way of wording it and I need some advice before I spend days writing it this way.
I think you have the right idea, but recalculating the status of every ticket for every second of elapsed time will take a lot processing, and nothing will have changed for the vast majority of those one-second intervals
The way event simulations work, and the way I think you should write your application, is to create a list of all events where the status might change. So you will want to include all of the status change events for every ticket as well as the start and end of core time on all non-bank-holiday weekdays
That list of events is sorted by timestamp, after which you can just process each event as if your per-second counter has reached that time. The difference is that you no longer have to count through the many intervening seconds where nothing changes, and you should end up with a much more efficient application
I hope that's clear. You may find it easier to process each ticket separately, but the maximum gain will be achieved by processing all tickets simultaneously. You will still have a sorted sequence of events to process, but you will avoid having to reprocess the same core time start and end events over and over again
One more thing I noticed is that you can probably ignore any open status change events. I would guess that tickets either go from new to open and then active, or straight from new to resolved. So a switch between with your company and with the customer will never be made at an open event, and so they can be ignored. Please check this as I am only speaking from my intuition, and clearly know nothing about how your ticketing system has been designed
I would not iterate over the seconds. Depending on the cost of your calculations that could be quite costly. It would be better to calculate the borders between core/outside core.
use strict;
use warnings;
my $customer_time;
my $our_time_outside;
my $our_time_core;
foreach my $event ($ticket->events) {
my $current_ts = $event->start_ts;
while ($current_ts < $event->end_ts) {
if ($event->status eq 'stalled') {
$customer_time += $event->end_ts - $current_ts;
$current_ts = $event->end_ts;
}
elsif (is_core_hours($current_ts)) {
my $next_ts = min(end_of_core_hours($current_ts), $event->end_ts);
$our_time_core += $next_ts - $current_ts;
$current_ts = $next_ts;
}
else {
my $next_ts = min(start_of_core_hours($current_ts), $event->end_ts);
$our_time_outside += $next_ts - $current_ts;
$current_ts = $next_ts;
}
}
}
I can't see why you'd want to iterate over every second. That seems very wasteful.
Get a list of all of the events for a given ticket.
Add to the list any boundaries between core and non-core times.
Sort this list into chronological order.
For each consecutive pair of events in the list, subtract the later from the earlier to get a duration.
Add that duration to the appropriate bucket.
And the usual caveats for dealing with dates and times apply here:
Use a library (I recommend DateTime together with DateTime::Duration)
Convert all of your timestamps to UTC as soon as you get them. Only convert back to local time just before displaying them to the user.
Related
I need to use "Count Day" code for indicator.
It does work fine, but this indicator keeps previous day object till I restart MT4.
What is wrong below code?
if(day >= drowDays) {
break;}
Also you can see chart screenshot link.
You're not providing sufficient information to your problem :'(
With the limited info, what I can say is that you need to delete the graphical objects created for previous day.
Assuming your indicator will plot the latest line, then you MIGHT (again, this is a guess as there is not enough information of your code) be able to achieve it with the ObjectsDeleteAll() function at the start of your OnCalculate(). Obviously, this is not efficient, but is something you can think about.
I need to log trace events during boot so I configure an AutoLogger with all the required providers. But when my service/process starts I want to switch to real-time mode so that the file doesn't explode.
I'm using TraceEvent and I can't figure out how to do this move correctly and atomically.
The first thing I tried:
const int timeToWait = 5000;
using (var tes = new TraceEventSession("TEMPSESSIONNAME", #"c:\temp\TEMPSESSIONNAME.etl") { StopOnDispose = false })
{
tes.EnableProvider(ProviderExtensions.ProviderName<MicrosoftWindowsKernelProcess>());
Thread.Sleep(timeToWait);
}
using (var tes = new TraceEventSession("TEMPSESSIONNAME", TraceEventSessionOptions.Attach))
{
Thread.Sleep(timeToWait);
tes.SetFileName(null);
Thread.Sleep(timeToWait);
Console.WriteLine("Done");
}
Here I wanted to make that I can transfer the session to real-time mode. But instead, the file I got contained events from a 15s period instead of just 10s.
The same happens if I use new TraceEventSession("TEMPSESSIONNAME", #"c:\temp\TEMPSESSIONNAME.etl", TraceEventSessionOptions.Create) instead.
It seems that the following will cause the file to stop being written to:
using (var tes = new TraceEventSession("TEMPSESSIONNAME"))
{
tes.EnableProvider(ProviderExtensions.ProviderName<MicrosoftWindowsKernelProcess>());
Thread.Sleep(timeToWait);
}
But here I must reenable all the providers and according to the documentation "if the session already existed it is closed and reopened (thus orphans are cleaned up on next use)". I don't understand the last part about orphans. Obviously some events might occur in the time between closing, opening and subscribing on the events. Does this mean I will lose these events or will I get the later?
I also found the following in the documentation of the library:
In real time mode, events are buffered and there is at least a second or so delay (typically 3 sec) between the firing of the event and the reception by the session (to allow events to be delivered in efficient clumps of many events)
Does this make the above code alright (well, unless the improbable happens and for some reason my thread is delayed for more than a second between creating the real-time session and starting processing the events)?
I could close the session and create a new different one but then I think I'd miss some events. Or I could open a new session and then close the file-based one but then I might get duplicate events.
I couldn't find online any examples of moving from a file-based trace to a real-time trace.
I managed to contact the author of TraceEvent and this is the answer I got:
Re the exception of the 'auto-closing and restarting' feature, it is really questions about the OS (TraceEvent simply calls the underlying OS API). Just FYI, the deal about orphans is that it is EASY for your process to exit but leave a session going. This MAY be what you want, but often it is not, and so to make the common case 'just work' if you do Create (which is the default), it will close a session if it already existed (since you asked for a new one).
Experimentation of course is the touchstone of 'truth' but I would frankly expecting unusual combinations to just work is generally NOT true.
My recommendation is to keep it simple. You need to open a new session and close the original one. Yes, you will end up with duplicates, but you CAN filter them out (after all they are IDENTICAL timestamps).
The other possibility is use SetFileName in its intended way (from one file to another). This certainly solves your problem of file size growth, and often is a good way to deal with other scenarios (after all you can start up you processing and start deleting files even as new files are being generated).
I have the following auto-responder on my bot
on *:TEXT:*sparky*:*: { msg # $read(scripts/name-responses.txt) }
on *:ACTION:*sparky*:*: { msg # $read(scripts/name-responses.txt) }
I wanted to know how can I tell write a code, I'm guessing with an IF statement, that if a user types sparky more than twice that the user gets ignored for 120 seconds. This way, my bot doesn't flood the chat due to the auto-responder feature.
Any help would be appreciated!
I would recommend keeping track of all users that have used the command, and when they have last used it. This can easily be done by saving all data in an INI file.
You can save this information by using the writeini command. To write the data to this file, use something along the lines of the following:
writeini sparky.ini usage $nick $ctime
$ctime will evaluate to the number of seconds elapsed since 1970/01/01. This is generally the way to compare times of events.
Once a user triggers your script again, you can read the value from this INI file and compare it to the current time. If the difference between the times is less than 10 seconds (for example), it can send the command and then ignore them for 120 seconds. You would read the value of their last usage using:
$readini(sparky.ini, n, usage, $nick)
Your final script could look like something along the lines of the following script. I've moved the functionality to a separate alias (/triggerSparky <nick> <channel>) to avoid identical code in the on TEXT and on ACTION event listeners.
on *:TEXT:*sparky*:#: {
triggerSparky
}
on *:ACTION:*sparky*:#: {
triggerSparky
}
alias triggerSparky {
; Send the message
msg $chan $read(scripts/name-responses.txt, n)
if ($calc($ctime - $readini(sparky.ini, n, usage, $nick)) < 10) {
; This user has recently triggered this script (10 seconds ago), ignore him for 120 seconds
ignore -u120 $nick
remini sparky.ini usage $nick
}
else {
writeini sparky.ini usage %nick $ctime
}
}
Of course, a slightly easier way to achieve a similar result is by simply ignoring them for a predefined time without saving their data in an INI file. This would stop you from checking whether they have triggered twice recently, but it would be a good way to only allow them to trigger it once per two minutes, for example.
Guys help me to understand the timeouts usage. The documentation gives quite a couple of words about them:
popTimeout- Retrieves the previous timeout value from a stack, restores it as the current timeout value, and returns it.
pushTimeout - Stores the current timeout value on a stack and sets a new timeout value.
They also provide some code:
target = UIATarget.localTarget();
target.pushTimeout(2);
// attempt element access
target.popTimeout();
But I don't exactly understand how and when to use them. Can anybode give an example?
During automation testing, some elements might not become visible right away. so instruments uses a timeout (default 5 seconds) to wait for requested elements. They call this the grace period.
Sometimes the default grace period might not be what you need, so you can change the timeout to a shorter or longer value.
Using the pushTimeout and popTimeout makes sure that the previous grace period is restored after calling popTimeout, without the need to remember the previous grace period.
For example: in one of my tests, I don't want to wait for a popover to become active, but I just want to know if there is a popover active, and dismiss it if there is:
target.pushTimeout(0.0);
if ( target.isDeviceiPad() && ! isNull( popOver= app.mainWindow().popover() ) )
{
UIALogger.logDebug(" dismiss popup by tapping somewhere");
popOver.dismiss();
target.delay(0.2);
}
target.popTimeout();
BTW, the isNull() is a custom function I made, but you probably understand what is going on.
I have been using mach_absolute_time() for all my timing functions so far. calculating how long between frames etc.
I now want to get the exact time touch input events happen using event.timestamp in the touch callbacks.
the problem is these two seem to use completely different timers. sure, you can get them both in seconds, but their origins are different and seemingly random...
is there any way to sync the two different timers?
or is there anyway to get access to the same timer that the touch input uses to generate that timestamp property? otherwise its next to useless.
Had some trouble with this myself. There isn't a lot of good documentation, so I went with experimentation. Here's what I was able to determine:
mach_absolute_time depends on the processor of the device. It returns ticks since the device was last rebooted (otherwise known as uptime). In order to get it in a human readable form, you have to modify it by the result from mach_timebase_info (a ratio), which will return billionth of seconds (or nanoseconds). To make this more usable I use a function like the one below:
#include <mach/mach_time.h>
int getUptimeInMilliseconds()
{
static const int64_t kOneMillion = 1000 * 1000;
static mach_timebase_info_data_t s_timebase_info;
if (s_timebase_info.denom == 0) {
(void) mach_timebase_info(&s_timebase_info);
}
// mach_absolute_time() returns billionth of seconds,
// so divide by one million to get milliseconds
return (int)((mach_absolute_time() * s_timebase_info.numer) / (kOneMillion * s_timebase_info.denom));
}
Get the initial difference between two i.e
what is returned by mach_absolute_time() initally when your application starts and also get the event.timestamp initially at the same time...
store the difference... it would remain same through out the time your application runs.. so you can use this time difference to convert one to another...
How about CFAbsoluteTimeGetCurrent?