Mirth String Handling - mirth

I'm using the code below to try and strip the file extension off the incoming file and replace it with "ACK";
Can't use .lastIndexOf as it's not available in Rhino.
var _filename = String(sourceMap.get('originalFilename'));
pos = -1;
var search = ".";
for(var i = 0; i < _filename.length - search.length; i++) {
if (_filename.substr(i, search.length) == search) {
pos = i;
}
}
logger.info('_pos:' + _pos);
Every time I get a pos value of -1
i.e. Last full stop position not found.
BUT if I hardcode the filename in as "2020049.259317052.HC.P.F3M147-G" it works perfectly.
Is it something to do with the sourceMap.get('originalFilename') supplying a non-string or different
character set ?

This was tested on mirth 3.5. Rhino does, in fact, have String.prototype.lastIndexOf for all mirth versions going back to at least mirth 3.0. You were correctly converting the java string from the sourceMap to a javascript string, however, it is not necessary in this case.
Java strings share String.prototype methods as long as there is not a conflict in method name. Java strings themselves have a lastIndexOf method, so that is the one being called in my answer. The java string is able to then borrow the slice method from javascript seamlessly. The javascript method returns a javascript string.
If for some reason the filename starts with a . and doesn't contain any others, this won't leave you with a blank filename.
var filename = $('originalFilename');
var index = filename.lastIndexOf('.');
if (index > 0) filename = filename.slice(0, index);
logger.info('filename: ' + filename);
That being said, I'm not sure why your original code wasn't working. When I replaced the first line with
var originalFilename = new java.lang.String('2020049.259317052.HC.P.F3M147-G');
var _filename = String(originalFilename);
It gave me the correct pos value of 22.

New Answer
After reviewing and testing what agermano said he is correct.
In your sample code you are setting pos = i but logging _pos
New answer var newFilename = _filename.slice(0, _filename.lastIndexOf('.'))
Older Answer
First, you are mixing JavaScript types and Java types.
var _filename = String(sourceMap.get('originalFilename'));
Instead, do
var _filename = '' + sourceMap.get('originalFilename');
This will cause a type conversion from Java String to JS string.
Secondly, there is an easier way to do what you are trying to do.
var _filenameArr = ('' + sourceMap.get('originalFilename')).split('.');
_filenameArr.pop() // throw away last item
var _filename = _filenameArr.join('.') // rejoin the array with out the last item
logger.info('_filename:' + _filename)

Related

How to convert Date and Time with mailmerge google slides from sheets as it is in cell

I have created a table with which I can record our check in times of our employees with the help of a generated Qr code in each line.The data in the table is generated as slides and converted into pdf. For this I use a script that I got to work with your help and it works. Here I would like to thank you especially #tanaike.
My problem is that the date and time are not copied to the slides to be generated as indicated in the cell but completely with Central European time and I added in the script to look in column if its empty to generate the slide. If it's not empty don't do anything. As I said everything is working except this two things.
I must confess I did not try to correct it somehow because I had already shot the script and I made some here despair. It would be really great if you write me the solutions and I can take them over. I will share the spreadsheet with you and the screenshot with ae and time. Thanks for your time and effort to help people like us; we are really trying.
As another approach, when I saw your question, I thought that if your Spreadsheet has the correct date values you expect, and in your script, you are retrieving the values using getValues, getValues is replaced with getDisplayValues(), it might be your expected result.
When I saw your provided sample Spreadsheet, I found your current script, when your script is modified, how about the following modification?
From:
var sheetContents = dataRange.getValues();
To:
sheetContents = dataRange.getDisplayValues();
Note:
When I saw your sample Spreadsheet, it seems that the column of the date has mixed values of both the string value and the date object. So, if you want to use the values as the date object using getValues, please be careful about this.
Reference:
getDisplayValues()
Added:
About your 2nd question of I mean that when a slide has been generated, the script saves the link from the slide in column D if the word YES is in column L. How do I make the script create the slide if there is JA in the column L and there is no link in column D. is a link in column D, the script should not generate a slide again. Thus, the script should only generate a slide if column D is empty and at the same time the word JA is in column L., when I proposed to modify from if (row[2] === "" && row[11] === "JA") { to if (row[3] == "" && ["JA", "YES"].includes(row[11])) {, you say as follows.
If ichanged as you descripted if (row[3] == "" && ["JA", "YES"].includes(row[11])) { i got this error. Syntax error: Unexpected token 'else' Line: 21 File: Code.gs
In this case, I'm worried that you might correctly reflect my proposed script. Because when I tested it, no error occurs. So, just in case, I add the modified script from your provided Spreadsheet as follows. Please test this.
Modified script:
function mailMergeSlidesFromSheets() {
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getDataRange();
sheetContents = dataRange.getDisplayValues(); // Modified
sheetContents.shift();
var updatedContents = [];
var check = 0;
sheetContents.forEach(function (row) {
if (row[3] == "" && ["JA", "YES"].includes(row[11])) { // Modified
check++;
var slides = createSlidesFromRow(row);
var slidesId = slides.getId();
var slidesUrl = `https://docs.google.com/presentation/d/${slidesId}/edit`;
updatedContents.push([slidesUrl]);
slides.saveAndClose();
var pdf = UrlFetchApp.fetch(`https://docs.google.com/feeds/download/presentations/Export?exportFormat=pdf&id=${slidesId}`, { headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() } }).getBlob().setName(slides.getName() + ".pdf");
DriveApp.getFolderById("1tRC505IWtTj8nnPB7XyydvTtCJmOb6Ek").createFile(pdf);
// Or DriveApp.getFolderById("###folderId###").createFile(pdf);
} else {
updatedContents.push([row[3]]);
}
});
if (check == 0) return;
sheet.getRange(2, 4, updatedContents.length).setValues(updatedContents);
}
function todaysDateAndTime() {
const dt = Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"MM:dd:yyyy");
const tm = Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"HH:mm:ss");
Logger.log(dt);
Logger.log(tm);
}

String transformation for subject course code for Dart/Flutter

For interaction with an API, I need to pass the course code in <string><space><number> format. For example, MCTE 2333, CCUB 3621, BTE 1021.
Yes, the text part can be 3 or 4 letters.
Most users enter the code without the space, eg: MCTE2333. But that causes error to the API. So how can I add a space between string and numbers so that it follows the correct format.
You can achieve the desired behaviour by using regular expressions:
void main() {
String a = "MCTE2333";
String aStr = a.replaceAll(RegExp(r'[^0-9]'), ''); //extract the number
String bStr = a.replaceAll(RegExp(r'[^A-Za-z]'), ''); //extract the character
print("$bStr $aStr"); //MCTE 2333
}
Note: This will produce the same result, regardless of how many whitespaces your user enters between the characters and numbers.
Try this.You have to give two texfields. One is for name i.e; MCTE and one is for numbers i.e; 1021. (for this textfield you have to change keyboard type only number).
After that you can join those string with space between them and send to your DB.
It's just like hack but it will work.
Scrolling down the course codes list, I noticed some unusual formatting.
Example: TQB 1001E, TQB 1001E etc. (With extra letter at the end)
So, this special format doesn't work with #Jahidul Islam's answer. However, inspired by his answer, I manage to come up with this logic:
var code = "TQB2001M";
var i = course.indexOf(RegExp(r'[^A-Za-z]')); // get the index
var j = course.substring(0, i); // extract the first half
var k = course.substring(i).trim(); // extract the others
var formatted = '$j $k'.toUpperCase(); // combine & capitalize
print(formatted); // TQB 1011M
Works with other formats too. Check out the DartPad here.
Here is the entire logic you need (also works for multiple whitespaces!):
void main() {
String courseCode= "MMM 111";
String parsedCourseCode = "";
if (courseCode.contains(" ")) {
final ensureSingleWhitespace = RegExp(r"(?! )\s+| \s+");
parsedCourseCode = courseCode.split(ensureSingleWhitespace).join(" ");
} else {
final r1 = RegExp(r'[0-9]', caseSensitive: false);
final r2 = RegExp(r'[a-z]', caseSensitive: false);
final letters = courseCode.split(r1);
final numbers = courseCode.split(r2);
parsedCourseCode = "${letters[0].trim()} ${numbers.last}";
}
print(parsedCourseCode);
}
Play around with the input value (courseCode) to test it - also use dart pad if you want. You just have to add this logic to your input value, before submitting / handling the input form of your user :)

vscode API: get Position of last character of line

Following up on this still unanswered question regarding VS Code Extensions with the VS Code API. I didn't answer it because it specifically asked for a solution using the with method of the Position object. I couldn't make that work, nor was I able to loop through the object to get the last character. Trying to manipulate the selection with vscode.commands.executeCommand didn't work either, because vscode.window.activeTextEditor doesn't appear to reflect the actual selection in the window as soon as the Execution Development Host starts running. The only solution I could find was the hoop-jumping exercise below, which gets the first character of one line and the first character of the next line, sets a Range, gets the text of that Range, then reduces the length of that text string by 1 to get the last character of the previous line.
function getCursorPosition() {
const position = editor.selection.active;
curPos = selection.start;
return curPos;
}
curPos = getCursorPosition();
var curLineStart = new vscode.Position(curPos.line, 0);
var nextLineStart = new vscode.Position(curPos.line + 1, 0);
var rangeWithFirstCharOfNextLine = new vscode.Range( curLineStart, nextLineStart);
var contentWithFirstCharOfNextLine = editor.document.getText(rangeWithFirstCharOfNextLine);
var firstLineLength = contentWithFirstCharOfNextLine.length - 1;
var curLinePos = new vscode.Position(curPos.line, firstLineLength);
var curLineEndPos = curLinePos.character;
console.log('curLineEndPos :>> ' + curLineEndPos);
I'm obviously missing something - it can't be impossible to get the last character of a line using the VSCode API without mickey-mousing the thing like this. So the question is simply, what is the right way to do this?
Once you have the cursor Position the TextDocument.lineAt() function returns a TextLine. From which you can get its range and that range.end.character will give you the character number of the last character. - not including the linebreak which if you want to include that see TextLine.rangeIncludingLineBreak().
const editor = vscode.window.activeTextEditor;
const document = editor.document;
const cursorPos = editor.selection.active;
document.lineAt(cursorPos).range.end.character;
Note (from [TextDocument.lineAt documentation][1] ):
Returns a text line denoted by the position. Note that the returned
object is not live and changes to the document are not reflected.

how to Papa.unparse a huge JSON object

I'm using Papa.unparse() to convert a JSON object to csv then downloading the file. The method fails with:
"allocation size overflow papaparse.min.js:6:1580"
This happens in firefox when there's > than 500,000 items to unparse in the JSON array.
The Papa.parse() method allows you to stream data from a file. Is there any similar approach you can take for Papa.unparse()?
You don't need PapaParse to do this.
The allocation size overflow problem is from converting your 500,000 rows into 500,000 strings and concatenating them together to form one massive string to create the CSV file with. JavaScript creates a new String when you concatenate one or more together, and eventually you run out of memory and crash.
The solution is to use TextEncoder to encode your strings into utf-8 (or whatever you need) ArrayBuffers, push each one into a giant array, and then use that array to create your file.
Here's some rough code for how you might do that:
var textEncoder = new TextEncoder("utf-8");
var headers = ["header1","header2","header3"];
var row1 = ["column1-1","column1-2","column1-3"];
var row2 = ["column2-1","column-2-2","column2-3"];
var data = [headers,row1,row2];
var arrayBuffers = [];
var csvString = '';
var encodedString = null;
var file = null;
for(var x=0;x<data.length;x++){
csvString = data[x].join(",").concat('\r\n');
encodedString = textEncoder.encode(csvString);
arrayBuffers.push(encodedString);
}
file = new File(arrayBuffers,"yourCsvFile.csv",{ type: "text/csv" });
I use text-encoding for a TextEncoder polyfill, and presumably if you're trying to Papa.unparse you've got FileAPI already.

What is the better way to do the below program(c#3.0)

Consider the below program
private static bool CheckFactorPresent(List<FactorReturn> factorReturnCol)
{
bool IsPresent = true;
StringBuilder sb = new StringBuilder();
//Get the exposure names from Exposure list.
//Since this will remain same , so it has been done outside the loop
List<string> lstExposureName = (from item in Exposures
select item.ExposureName).ToList<string>();
foreach (FactorReturn fr in factorReturnCol)
{
//Build the factor names from the ReturnCollection dictionary
List<string> lstFactorNames = fr.ReturnCollection.Keys.ToList<string>();
//Check if all the Factor Names are present in ExposureName list
List<string> result = lstFactorNames.Except(lstExposureName).ToList();
if (result.Count() > 0)
{
result.ForEach(i =>
{
IsPresent = false;
sb.AppendLine("Factor" + i + "is not present for week no: " + fr.WeekNo.ToString());
});
}
}
return IsPresent;
}
Basically I am checking if all the FactorNames[lstFactorNames] are present in
ExposureNames[lstExposureName] list by using lstFactorNames.Except(lstExposureName).
And then by using the Count() function(if count() > 0), I am writing the error
messages to the String Builder(sb)
I am sure that someone can definitely write a better implementation than the one presented.
And I am looking forward for the same to learn something new from that program.
I am using c#3.0 and dotnet framework 3.5
Thanks
Save for some naming convention issues, I'd say that looks fine (for what I can figure out without seeing the rest of the code, or the purpose in the effort. The naming conventions though, need some work. A sporadic mix of ntnHungarian, PascalCase, camelCase, and abbrv is a little disorienting. Try just naming your local variables camelCase exclusively and things will look a lot better. Best of luck to you - things are looking good so far!
- EDIT -
Also, you can clean up the iteration at the end by just running a simple foreach:
...
foreach (var except in result)
{
isPresent = false;
builder.AppendFormat("Factor{0} is not present for week no: {1}\r\n", except, fr.WeekNo);
}
...