DATA(maximum) = REDUCE #( INIT max = VALUE myType( )
FOR line IN myTable
NEXT max = COND #( WHEN line-myColumn > max THEN line-myColumn
ELSE max ) ).
[ABAP] OData – GET_STREAM implementation to return a PDF
METHOD /iwbep/if_mgw_appl_srv_runtime~get_stream.
* This method get's called when a media file is queried with $value. A binary stream will be returned.
TRY.
DATA(file_id) = VALUE zfile_id( it_key_tab[ name = 'file_id' ]-value ).
CATCH cx_sy_itab_line_not_found.
RETURN. " leave here when no file_id provided
ENDTRY.
DATA(ls_file) = get_file( file_id ) " read your file you want to return (if it's not yet a binary stream, convert it)
DATA(ls_stream) = VALUE ty_s_media_resource( value = ls_file-value
mime_type = ls_file-mimetype ). " in my case it's 'application/pdf'
" necessary to display the filename instead of $value in the viewer title
TRY.
" create pdf object
DATA(lo_fp) = cl_fp=>get_reference( ).
DATA(lo_pdfobj) = lo_fp->create_pdf_object( connection = 'ADC' ).
lo_pdfobj->set_document( pdfdata = ls_stream-value ).
" set title
lo_pdfobj->set_metadata( VALUE #( title = ls_file-filename ) ).
lo_pdfobj->execute( ).
" get pdf with title
lo_pdfobj->get_document( IMPORTING pdfdata = ls_stream-value ).
CATCH cx_fp_runtime_internal
cx_fp_runtime_system
cx_fp_runtime_usage INTO DATA(lo_fpex).
ENDTRY.
copy_data_to_ref( EXPORTING is_data = ls_stream
CHANGING cr_data = er_stream ).
" necessary for the pdf to be opened inline instead of a download (also sets the filename when downloaded)
/iwbep/if_mgw_conv_srv_runtime~set_header( VALUE #( name = 'content-disposition'
value = |inline; filename={ ls_file-filename }| ) ).
ENDMETHOD
Quick way to open a PDFViewer in your UI5 App:
const pdfViewer = new PDFViewer()
pdfViewer.setSource("/sap/opu/odata/ZMY_SEVICE" + my_path + "/$value") // my_path could be something like this "/PdfSet('file_id')"
pdfViewer.setTitle("My PDFViewer Title") // title of the popup, not the viewer
pdfViewer.open()
[ABAP] Create DATA-URL from xstring
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs
DATA lv_filetype TYPE char4.
DATA lv_content TYPE xstring.
" get your data, for example a jpg
" lv_filetype = 'jpg'
" lv_content = ....
DATA(mimetype) = /iwwrk/cl_mgw_workflow_rt_util=>get_mime_type_from_extension( lv_filetype ).
DATA(base64) = /iwwrk/cl_mgw_workflow_rt_util=>base64_encode( lv_content ).
DATA(lv_data_url) = |data:{ mimetype };base64,{ base64 }|.
[ABAP] OData – Filtering, Sorting, Paging
" Filter, Sort, Paging
/iwbep/cl_mgw_data_util=>filtering( EXPORTING it_select_options = it_filter_select_options
CHANGING ct_data = et_entityset ).
/iwbep/cl_mgw_data_util=>orderby( EXPORTING it_order = it_order
CHANGING ct_data = et_entityset ).
/iwbep/cl_mgw_data_util=>paging( EXPORTING is_paging = is_paging
CHANGING ct_data = et_entityset ).
[ABAP] Delete all rows from index
If you want to delete all lines from a certain index, e.g. 6, you can do the following:
DELETE lt_data FROM 6 TO lines( lt_data ).
As result, your table will only hold the first 5 rows.
[JavaScript] Create date object from date string dd.MM.yyyy
Using regex, you can simply reorder the parts of your date string to create a compatible ISO 8601 date string which is accepted by the new Date() constructor.
const date_string = "01.01.2022"
const oDate = new Date(date_string.replace(/(.*)\.(.*)\.(.*)/, '$3-$2-$1'))
console.log(oDate.toUTCString())
[SAPUI5] Get data of an Item of a List or Table
All options have in common that you first try to get the binding context from the list/table element via the event. Having the right context, you can either use the getProperty() function to get a specific property, or use the getObject() function to get all data.
onClick: function (oEvent) {
// Option 1
oEvent.getParameters().item.getBindingContext().getProperty("ID")
// Option 2
oEvent.getParameters().item.getBindingContext().getObject().ID
// Option 3
oEvent.getParameter("item").getBindingContext().getObject().ID
// Option 4
oEvent.getSource().getBindingContext().getObject().ID
}
Note: When using a List, it’s oEvent.getParameters().listItem instead of oEvent.getParameters().item.
Or you could also use the sPath property from the binding context and directly get the data from the model.
onClick: function (oEvent) {
// Option 5
const sPath = oEvent.getSource().getBindingContext().sPath
// 5a
this.getView().getModel().getProperty(sPath).ID
// 5b
this.getView().getModel().getProperty(sPath + "/ID")
}
[Linux Mint] Wemos D1 Mini (ESP8266) not recognized
I had a few D1 Minis lying around that I wanted to flash WLED onto. But when plugging into my main PC running Linux Mint 21, no device got recognized. The D1 Mini was just flashing its blue LED light 2 times and that was all. I had already checked before, whether the USB cable is also a Data Link cable, because now and then you accidentally grab a USB cable which is charging only.
Since I was pretty sure it wasn’t a hardware problem, I checked dmesg for any suspicious messages. I’m using an alias named klog to beautify the output.
sudo dmesg -t -L=never -l emerg,alert,crit,err,warn --human --nopager

And indeed there were some messages regarding USB.
usbfs: interface 0 claimed by ch341 while 'brltty' sets config #1
Since brltty is software for people with visual impairment, I don’t need it and therefore uninstalled it.
sudo apt remove brltty
sudo apt autoclean && sudo apt autoremove
And after removing brltty, my D1 Mini got recognized immediately. Fortunately, the solution was very simple. 🙂

Update 19.01.2024: If you receive Cannot open /dev/ttyUSB0: Permission denied errors, when writing to the esp, you have to add your user to the dialout group and re-login. (*)
sudo usermod -a -G dialout $USER
[Home Assistant] Notify Groups
Notify Groups are useful to send notifications to a group of devices or even to different channels like Home Assistant Companion App, Telegram, Signal etc.
https://www.home-assistant.io/integrations/group/#notify-groups
I’m using it to create a group of Android Devices I want to send notifications to via the Companion App.
# Notify Groups
notify:
- platform: group
name: "family"
services:
- service: mobile_app_mi_8
- service: mobile_app_redmi_note_8_pro
After that, go to Developer Tools and reload the Notify Services.

Now you should find a new notify service called “family” which can be used in automations.

[PDF.js] Set light and dark theme manually
The new PDF.js viewer design Photon supports a light and a dark mode. By default, the theme is set automatically. To overwrite this, you can set the viewerCssTheme property.
I’ve embedded my PDF viewer in an iFrame like this:
<iframe id="pdf-js-viewer" src="/pdf/web/viewer.html" title="webviewer" frameborder="0" width="100%" height="700" allowfullscreen="" webkitallowfullscreen=""/>
By setting the viewerCssTheme property, you are able to change the PDF viewer theme. It can be modified using the PDFViewerApplicationOptions.set() function and there are three possible values. The property has to be set before the Viewer is initialized. To archive this, you can listen to the event webviewerloaded (read more about it here). In my case, I also had to call _forceCssTheme() after that.
document.addEventListener("webviewerloaded", async () => {
let pdfViewerIFrame = document.getElementById("pdf-js-viewer")
// https://github.com/mozilla/pdf.js/blob/master/web/app_options.js
pdfViewerIFrame.contentWindow.PDFViewerApplicationOptions.set("viewerCssTheme", 1) // 0=automatic theme, 1=light theme, 2=dark theme
pdfViewerIFrame.contentWindow.PDFViewerApplication._forceCssTheme()
})
