Release 0.3.8 of RcppGSL is now getting onto CRAN. The RcppGSL package provides an interface from R to the GNU GSL using the Rcpp package.
Peter Carbonetto let us know in issue #25 that the included example now showed linker errors on (everybody s favourite CRAN platform) Slowlaris. Kidding aside, the added compiler variety really has benefits because we were indeed missing a good handful or two of inline statements in the headers which our good friends g++ and clang++ apparently let us get away with. This has been fixed, and a little bit of the usual package polish and cleanup has been added; see the list of detailed changes below.
Special thanks also to CRAN for a super-smooth and fully automated processing of a package with both compiled code and two handful of reverse dependencies. Courtesy of CRANberries, a summary of changes to the most recent release is also available. More information is on the RcppGSL page. Questions, comments etc should go to the issue tickets at the GitHub repo. If you like this or other open-source work I do, you can now sponsor me at GitHub. For the first year, GitHub will match your contributions.Changes in version 0.3.8 (2020-06-21)
- A few missing
inlinestatements were added to the headers fixing a (genuine) error that was seen only on Solaris (Dirk).- The nice
colNormexample is now in a file by itself, the previous versions are off in a new filecolNorm_old.cpp(Dirk).- The README.me now sports two new badges (Dirk).
- Travis CI was updated to 'bionic' and R 4.0 (Dirk).
This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. Please report excessive re-aggregation in third-party for-profit settings.
cvProjectPoints2()
calls. So I decided to just write a small C++ shim to call the new version of
that function, expose that with =extern "C"= to the rest of my world, and I'd be
done. And normally I would be, but this is OpenCV we're talking about. I wrote
the shim, and it didn't work. The code built and ran, but the results were
wrong. After some pointless debugging, I boiled the problem down to this test
program:
#include <opencv2/calib3d.hpp> #include <stdio.h> int main(void) double fx = 1000.0; double fy = 1000.0; double cx = 1000.0; double cy = 1000.0; double _camera_matrix[] = fx, 0, cx, 0, fy, cy, 0, 0, 1 ; cv::Mat camera_matrix(3,3, CV_64FC1, _camera_matrix); double pp[3] = 1., 2., 10. ; double qq[2] = 444, 555 ; int N=1; cv::Mat object_points(N,3, CV_64FC1, pp); cv::Mat image_points (N,2, CV_64FC1, qq); // rvec,tvec double _zero3[3] = ; cv::Mat zero3(1,3,CV_64FC1, _zero3); cv::projectPoints( object_points, zero3,zero3, camera_matrix, cv::noArray(), image_points, cv::noArray(), 0.0); fprintf(stderr, "manually-projected no-distortion: %f %f\n", pp[0]/pp[2] * fx + cx, pp[1]/pp[2] * fy + cy); fprintf(stderr, "opencv says: %f %f\n", qq[0], qq[1]); return 0;
$ g++ -I/usr/include/opencv4 -o tst tst.cc -lopencv_calib3d -lopencv_core && ./tst manually-projected no-distortion: 1100.000000 1200.000000 opencv says: 444.000000 555.000000Well that's no good. The answer is wrong, but it looks like it didn't even write anything into the output array. Since this is supposed to be a thin shim to C code, I want this thing to be filling in C arrays, which is what I'm doing here:
double qq[2] = 444, 555 ; int N=1; cv::Mat image_points (N,2, CV_64FC1, qq);
cv::Mat, but the API wants cv::InputArray for some arguments and
cv::OutputArray for others. Clearly cv::Mat can be coerced into either of
those types (and that's what you're supposed to do), but the details are not
meant to be understood. You can read the snazzy C++-style documentation.
Clicking on "OutputArray" in the doxygen gets you here. Then I guess you're
supposed to click on "_OutputArray", and you get here. Understand what's going
on now? Me neither.
Stepping through the code revealed the problem. cv::projectPoints() looks like
this:
void cv::projectPoints( InputArray _opoints, InputArray _rvec, InputArray _tvec, InputArray _cameraMatrix, InputArray _distCoeffs, OutputArray _ipoints, OutputArray _jacobian, double aspectRatio ) .... _ipoints.create(npoints, 1, CV_MAKETYPE(depth, 2), -1, true); ....
OutputArray object. This object already had a buffer, and that's
where I was expecting the output to go. Instead it went to the brand-new buffer
I didn't want. Issues:
OutputArray object knows it already has a buffer, and they could just
use it instead of allocating a new one
static void cvProjectPoints2Internal( const CvMat* objectPoints, const CvMat* r_vec, const CvMat* t_vec, const CvMat* A, const CvMat* distCoeffs, CvMat* imagePoints, CvMat* dpdr CV_DEFAULT(NULL), CvMat* dpdt CV_DEFAULT(NULL), CvMat* dpdf CV_DEFAULT(NULL), CvMat* dpdc CV_DEFAULT(NULL), CvMat* dpdk CV_DEFAULT(NULL), CvMat* dpdo CV_DEFAULT(NULL), double aspectRatio CV_DEFAULT(0) ) ...
CvMat is still there. I
have no words.
Yes, this is a massive library, and maybe other parts of it indeed did make some
sort of non-token transition, but this thing is ridiculous. In the end, here's
the function I ended up with (licensed as OpenCV; see the comment)
// The implementation of project_opencv is based on opencv. The sources have // been heavily modified, but the opencv logic remains. This function is a // cut-down cvProjectPoints2Internal() to keep only the functionality I want and // to use my interfaces. Putting this here allows me to drop the C dependency on // opencv. Which is a good thing, since opencv dropped their C API // // from opencv-4.2.0+dfsg/modules/calib3d/src/calibration.cpp // // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2009, Willow Garage Inc., all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of the copyright holders may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of typedef union struct double x,y; ; double xy[2]; point2_t; typedef union struct double x,y,z; ; double xyz[3]; point3_t; void project_opencv( // outputs point2_t* q, point3_t* dq_dp, // may be NULL double* dq_dintrinsics_nocore, // may be NULL // inputs const point3_t* p, int N, const double* intrinsics, int Nintrinsics) const double fx = intrinsics[0]; const double fy = intrinsics[1]; const double cx = intrinsics[2]; const double cy = intrinsics[3]; double k[12] = ; for(int i=0; i<Nintrinsics-4; i++) k[i] = intrinsics[i+4]; for( int i = 0; i < N; i++ ) double z_recip = 1./p[i].z; double x = p[i].x * z_recip; double y = p[i].y * z_recip; double r2 = x*x + y*y; double r4 = r2*r2; double r6 = r4*r2; double a1 = 2*x*y; double a2 = r2 + 2*x*x; double a3 = r2 + 2*y*y; double cdist = 1 + k[0]*r2 + k[1]*r4 + k[4]*r6; double icdist2 = 1./(1 + k[5]*r2 + k[6]*r4 + k[7]*r6); double xd = x*cdist*icdist2 + k[2]*a1 + k[3]*a2 + k[8]*r2+k[9]*r4; double yd = y*cdist*icdist2 + k[2]*a3 + k[3]*a1 + k[10]*r2+k[11]*r4; q[i].x = xd*fx + cx; q[i].y = yd*fy + cy; if( dq_dp ) double dx_dp[] = z_recip, 0, -x*z_recip ; double dy_dp[] = 0, z_recip, -y*z_recip ; for( int j = 0; j < 3; j++ ) double dr2_dp = 2*x*dx_dp[j] + 2*y*dy_dp[j]; double dcdist_dp = k[0]*dr2_dp + 2*k[1]*r2*dr2_dp + 3*k[4]*r4*dr2_dp; double dicdist2_dp = -icdist2*icdist2*(k[5]*dr2_dp + 2*k[6]*r2*dr2_dp + 3*k[7]*r4*dr2_dp); double da1_dp = 2*(x*dy_dp[j] + y*dx_dp[j]); double dmx_dp = (dx_dp[j]*cdist*icdist2 + x*dcdist_dp*icdist2 + x*cdist*dicdist2_dp + k[2]*da1_dp + k[3]*(dr2_dp + 4*x*dx_dp[j]) + k[8]*dr2_dp + 2*r2*k[9]*dr2_dp); double dmy_dp = (dy_dp[j]*cdist*icdist2 + y*dcdist_dp*icdist2 + y*cdist*dicdist2_dp + k[2]*(dr2_dp + 4*y*dy_dp[j]) + k[3]*da1_dp + k[10]*dr2_dp + 2*r2*k[11]*dr2_dp); dq_dp[i*2 + 0].xyz[j] = fx*dmx_dp; dq_dp[i*2 + 1].xyz[j] = fy*dmy_dp; if( dq_dintrinsics_nocore ) dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 0) + 0] = fx*x*icdist2*r2; dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 1) + 0] = fy*(y*icdist2*r2); dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 0) + 1] = fx*x*icdist2*r4; dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 1) + 1] = fy*y*icdist2*r4; if( Nintrinsics-4 > 2 ) dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 0) + 2] = fx*a1; dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 1) + 2] = fy*a3; dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 0) + 3] = fx*a2; dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 1) + 3] = fy*a1; if( Nintrinsics-4 > 4 ) dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 0) + 4] = fx*x*icdist2*r6; dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 1) + 4] = fy*y*icdist2*r6; if( Nintrinsics-4 > 5 ) dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 0) + 5] = fx*x*cdist*(-icdist2)*icdist2*r2; dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 1) + 5] = fy*y*cdist*(-icdist2)*icdist2*r2; dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 0) + 6] = fx*x*cdist*(-icdist2)*icdist2*r4; dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 1) + 6] = fy*y*cdist*(-icdist2)*icdist2*r4; dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 0) + 7] = fx*x*cdist*(-icdist2)*icdist2*r6; dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 1) + 7] = fy*y*cdist*(-icdist2)*icdist2*r6; if( Nintrinsics-4 > 8 ) dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 0) + 8] = fx*r2; //s1 dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 1) + 8] = fy*0; //s1 dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 0) + 9] = fx*r4; //s2 dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 1) + 9] = fy*0; //s2 dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 0) + 10] = fx*0;//s3 dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 1) + 10] = fy*r2; //s3 dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 0) + 11] = fx*0;//s4 dq_dintrinsics_nocore[(Nintrinsics-4)*(2*i + 1) + 11] = fy*r4; //s4
There are 3 choices for the alternative java (providing /usr/bin/java). Selection Path Priority StatusIt was set to jre-7, but I guess this was from years ago when I ran OpenFire as XMPP server. If something is not working with Jitsi Meet, it helps to not watch the log files only, but also to open the Debug Console in your web browser. That way I catched some XMPP Failures and saw that it tries to connect to some components where the DNS records were missing:
------------------------------------------------------------
* 0 /usr/lib/jvm/java-11-openjdk-amd64/bin/java 1111 auto mode
1 /usr/lib/jvm/java-11-openjdk-amd64/bin/java 1111 manual mode
2 /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java 1081 manual mode
3 /usr/lib/jvm/jre-7-oracle-x64/bin/java 316 manual mode
meet IN A yourIPOf course you also need to add some config to your ejabberd.yml:
chat.meet IN A yourIP
focus.meet IN A yourIP
pubsub.meet IN A yourIP
host_config:There is more config that needs to be done, but one of the XMPP Failures I spotted from debug console in Firefox was that it tried to connect to conference.domain.net while I prefer to use chat.domain.net for its brevity. If you prefer conference instead of chat, then you shouldn't be affected by this. Just make just that your config is consistent with what Jitsi Meet wants to connect to. Maybe not all of the above lines are necessary, but this works for me. Jitsi config is like this for me with short domains (/etc/jitsi/meet/meet.domain.net-config.js):
domain.net:
auth_password_format: scram
meet.domain.net:
## Disable s2s to prevent spam
s2s_access: none
auth_method: anonymous
allow_multiple_connections: true
anonymous_protocol: both
modules:
mod_bosh:
mod_caps:
mod_carboncopy:
#mod_disco:
mod_stun_disco:
secret: "YOURSECRETTURNCREDENTIALS"
services:
-
host: yourIP # Your coturn's public address.
type: stun
transport: udp
-
host: yourIP # Your coturn's public address.
type: stun
transport: tcp
-
host: yourIP # Your coturn's public address.
type: turn
transport: udp
mod_muc:
access: all
access_create: local
access_persistent: local
access_admin: admin
host: "chat.@HOST@"
mod_muc_admin:
mod_ping:
mod_pubsub:
access_createnode: local
db_type: sql
host: "pubsub.@HOST@"
ignore_pep_from_offline: false
last_item_cache: true
max_items_node: 5000 # For Jappix this must be set to 1000000
plugins:
- "flat"
- "pep" # requires mod_caps
force_node_config:
"eu.siacs.conversations.axolotl.*":
access_model: open
## Avoid buggy clients to make their bookmarks public
"storage:bookmarks":
access_model: whitelist
var config = hosts:In the above config snippet one of the issues solved was to add the port to the bosh setting. Of course you can also take care that your bosh requests get forwarded by your webserver as reverse proxy. Using the port in the config might be a quick way to test whether or not your config is working. It's easier to solve one issue after the other and make one config change at a time instead of needing to make changes in several places. /etc/jitsi/jicofo/sip-communicator.properties:
domain: 'domain.net',
anonymousdomain: 'meet.domain.net',
authdomain: 'meet.domain.net',
focus: 'focus.meet.domain.net',
muc: 'chat.hookipa.net'
, bosh: '//meet.domain.net:5280/http-bind',
//websocket: 'wss://meet.domain.net/ws',
clientNode: 'http://jitsi.org/jitsimeet',
focusUserJid: 'focus@domain.net', useStunTurn: true, p2p:
// Enables peer to peer mode. When enabled the system will try to
// establish a direct connection when there are exactly 2 participants
// in the room. If that succeeds the conference will stop sending data
// through the JVB and use the peer to peer connection instead. When a
// 3rd participant joins the conference will be moved back to the JVB
// connection.
enabled: true, // Use XEP-0215 to fetch STUN and TURN servers.
useStunTurn: true, // The STUN servers that will be used in the peer to peer connections
stunServers: [
// urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' ,
// urls: 'stun:stun.l.google.com:19302' ,
// urls: 'stun:stun1.l.google.com:19302' ,
// urls: 'stun:stun2.l.google.com:19302' ,
urls: 'stun:turn.domain.net:5349' ,
urls: 'stun:turn.domain.net:3478'
], ....
org.jitsi.jicofo.auth.URL=XMPP:meet.domain.net/etc/jitsi/videobridge/sip-communicator.properties:
org.jitsi.jicofo.BRIDGE_MUC=jvbbrewery@chat.meet.domain.net
org.jitsi.videobridge.ENABLE_STATISTICS=trueSometimes there might be stupid errors like (in my case) wrong hostnames like "chat.meet..domain.net" (a double dot in the domain), but you can spot those easily in the debug console of your browser. There tons of config options where you can easily make mistakes, but watching your logs and your debug console should really help you in sorting out these kind of errors. The other URLs above are helpful as well and more elaborate then my few lines here. Especially Mike Kuketz has some advanced configuration tips like disabling third party requests with "disableThirdPartyRequests: true" or limiting the number of video streams and such. Hope this helps...
org.jitsi.videobridge.STATISTICS_TRANSPORT=muc
org.jitsi.videobridge.STATISTICS_INTERVAL=5000 org.jitsi.videobridge.xmpp.user.shard.HOSTNAME=localhost
org.jitsi.videobridge.xmpp.user.shard.DOMAIN=domain.net
org.jitsi.videobridge.xmpp.user.shard.USERNAME=jvb
org.jitsi.videobridge.xmpp.user.shard.PASSWORD=SECRET
org.jitsi.videobridge.xmpp.user.shard.MUC_JIDS=JvbBrewery@chat.meet.domain.net
org.jitsi.videobridge.xmpp.user.shard.MUC_NICKNAME=videobridge1 org.jitsi.videobridge.DISABLE_TCP_HARVESTER=true
org.jitsi.videobridge.TCP_HARVESTER_PORT=4443
org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS=yourIP
org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS=yourIP
org.ice4j.ice.harvest.DISABLE_AWS_HARVESTER=true
org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES=turn.domain.net:3478
org.ice4j.ice.harvest.ALLOWED_INTERFACES=eth0
designer library was
not being built.
The designer library is needed to build designer plugins, which allow loading,
dynamically at runtime, .ui interface files that use custom widgets.
The error the customer got at runtime is:
QFormBuilder was unable to create a custom widget of the class ' '; defaulting to base class 'QWidget'.
The library with the custom widget implementation was correctly linked, and
indeed the same custom widget was used by the application in other parts of its
interface not loaded via .ui files.
It turns out that it is not sufficient, and to load custom widgets
automatically, QUiLoader wants to read
their metadata from plugin libraries containing objects that implement the
QDesignerCustomWidgetInterface
interface.
Sadly, building such a library requires using QT += designer, and the
designer library, that was not being built by Qt5's build system. This looks
very much like a Qt5 bug.
A work around would be to subclass
QUiLoader extending
createWidget to teach it how to create the custom widgets we need.
Unfortunately, the customer has many custom widgets.
The investigation
To find out why designer was not being built, I added -d to the qmake
invocation at the end of qtbase/configure, and trawled through the 3.1G build
output.
The needle in the haystack seems to be here:
DEBUG 1: /home/build/armhf/qt-everywhere-src-5.15.0/qttools/src/designer/src/src.pro:18: SUBDIRS := uiplugin uitools lib components designer plugins DEBUG 1: /home/build/armhf/qt-everywhere-src-5.15.0/qttools/src/designer/src/src.pro:23: calling qtNomakeTools(lib components designer plugins)
qtNomakeTools seems to be intended to disable
building those components if QT_BUILD_PARTS doesn't contain tools. For
cross-building, QT_BUILD_PARTS is libs examples, so designer does not get
built.
However, designer contains the library part needed for
QDesignerCustomWidgetInterface
and that really needs to be built. I assume that part should really be built as
part of libs, not tools.
The fixes/workarounds
I tried removing designer from the qtNomakeTools invocation at
qttools/src/designer/src/src.pro:23, to see if
qttools/src/designer/src/designer/ would get built.
It did get built, but then build failed with designer/src/designer and
designer/src/uitools both claiming the designer plugin.
I tried editing qttools/src/designer/src/uitools/uitools.pro not to claim the
designer plugin when tools is not a build part.
I added the tweaks to the Qt5 build system as debian/patches.
2 hours of build time later...
make check is broken:
make[6]: Leaving directory '/home/build/armhf/qt-everywhere-src-5.15.0/qttools/src/designer/src/uitools' make[5]: *** No rule to make target 'sub-components-check', needed by 'sub-designer-check'. Stop.
make check doesn't do anything in this build, we can simply
override dh_auto_test to skip that step.
Finally, this patch builds a new executable, of an architecture that makes dh_shlibdeps struggle:
dpkg-shlibdeps: error: cannot find library libQt5DesignerComponentssystem.so.5 needed by debian/qtbase5system-armhf-dev/opt/qt5system-armhf/bin/designer (ELF format: 'elf32-little' abi: '0101002800000000'; RPATH: '') dpkg-shlibdeps: error: cannot find library libQt5Designersystem.so.5 needed by debian/qtbase5system-armhf-dev/opt/qt5system-armhf/bin/designer (ELF format: 'elf32-little' abi: '0101002800000000'; RPATH: '')
dh_shlibdeps on the designer executable.
The result is in the qt5custom git repository.
LWN published today yet another great piece of writing, Loaded terms
in free software. I am sorry, the
content will not be immediately available to anybody following at
home, as LWN is based on a subscription model But a week from now,
the article will be open for anybody to read. Or you can ask me (you
most likely can find my contact addresses, as they are basically
everywhere) for a subscriber link, I will happily provide it.
In consonance with the current mood that started with the killing of
George Floyd
and sparked worldwide revolts against police brutality, racism (mostly
related to police and law enforcement forces, but social as well) and
the like, the debate that already started some months ago in technical
communities has re-sparked:
We have many terms that come with long histories attached to them, and
we are usually oblivious to their obvious meaning. We? Yes, we, the
main users and creators of technology. I never felt using master and
slave to refer to different points of a protocol, bus, clock or
whatever (do refer to the Wikipedia article for a fuller
explanation)
had any negative connotations but then again, those terms have never
tainted my personal family. That is, I understand I speak from a
position of privilege.
A similar although less heated issue goes around the blacklist and
whitelist terms, or other uses that use white to refer to good,
law-abiding citizens, and black to refer to somewhat antisocial uses
(i.e. the white hat and black hat hackers).
For several years, this debate has been sparking and dying off. Some
important changes have been made Particularly, in 2017 the Internet
Software Consortium started recommending Primary and
Secondary,
Python dropped master/slave pairs after a quite thorough and deep
review throughout 2018, GitHub
changed the default branch from master to main earlier this
week. The
Internet Engineering Task Force has a draft (that lapsed and thus
sadly didn t become an RFC, but still, is archived), Terminology,
Power and Oppressive
Language
that lists suggested alternatives:
There are also many other relationships that can be used as metaphors, Eglash s research calls into question the accuracy of the master-slave metaphor. Fortunately, there are ample alternatives for the master-slave relationship. Several options are suggested here and should be chosen based on the pairing that is most clear in context:I ll add that I think we Spanish-speakers are not fully aware of the issue s importance, because the most common translation I have seen for master/slave is maestro/esclavo: Maestro is the word for teacher (although we do keep our slaves in place). But think whether it sounds any worse if you refer to device pairs, or members of a database high-availability cluster, or whatever as Amo and Esclavo. It does sound much worse I cannot add much of value to this debate. I am just happy issues like this are being recognized and dealt with. If the topic interests you, do refer to the LWN article! Some excrepts: I consider the following to be the core of Jonathan Corbet s writeup:
- Primary-secondary
- Leader-follower
- Active-standby
- Primary-replica
- Writer-reader
- Coordinator-worker
- Parent-helper
Recent events, though, have made it clear even to those of us who were happy to not question this view that the story of slavery and the wider racist systems around it is not yet finished. There are many people who are still living in the middle of it, and it is not a nice place to be. We are not so enlightened as we like to think we are. If there is no other lesson from the events of the last few weeks, we should certainly take to heart the point that we need to be listening to the people who have been saying, for many years, that they are still suffering. If there are people who are telling us that terms like slave or blacklist are a hurtful reminder of the inequities that persist in our society, we need to accept that as the truth and act upon it. Etymological discussions on what, say, master really means may be interesting, but they miss the point and are irrelevant to this discussion.Part of a comment by user yokem_55:
Often, it seems to me that the replacement words are much more descriptive and precise than the old language. Allowlist is far more obviously a list of explicitly authorized entities than whitelist . Mainline has a more obvious meaning of a core stream of development than master . The benefit of moving past this language is more than just changing cultural norms, it s better, more precise communication across the board.Another spot-on comment, by user alan:
From my perspective as a Black American male, I think that it s nice to see people willing to see and address racism in various spheres. I am concerned that some of these steps will be more performative than substantial. Terminology changes in software so as to be more welcoming is a nice thing. Ensuring that oppressed minorities have access to the tools and resources to help reduce inequity and ensuring equal protection under the laws is better. We ll get there one day I m sure. The current ask is much simpler, its just to stop randomly killing and terrorizing us. Please and thank you.So Maybe the protests of this year caught special notoriety because the society is reacting after (or during, for many of us) the lockdown. In any case, I hope for their success in changing the planet s culture of oppression.
Language is a tool of power
In school, we read the philologist diary of Victor Klemperer about the
changes in the German language during the Third Reich, LTI - Lingua Tertii Imperii, a book which makes it clear that the use of
language is political, creates realities, and has reverse repercussions on
concepts of an entire society. Language was one of the tools that supported Nazism in
insiduously pervading all parts of society.
Language shapes our concepts of society
Around the same time, a friend of mine proposed to read Egalia's daughters by Gerd Brantenberg, a book
in which gendered words were reversed: so that human becomes
huwim, for example. This book made me take notice of gendered concepts
that often go unnoticed.
Language shapes the way we think and feel
I spent a large part of my adult life in France, which confronted me with
the realization that a language provides its speakers with certain concepts. If
a concept does not exist in a language, people cannot easily feel or imagine
this concept either.
Back then (roughly 20 years ago), even though I was aware of gender inequality, I hated using
gender neutral language because in German and French it felt unnatural, and, or so
I thought, we were all alike. One day, at a party, we played a game that
consisted in guessing people's professions by asking them Yes/No questions.
Turns out that we were unable to guess that the woman we were talking with was
a doctor, because we could simply not imagine this profession for a
young woman. In French, docteur is male and almost nobody would use
the word doctoresse, ou femme docteur.
Unimaginable are also the concepts of words in German that have no
equivalent in French or vice versa:
You never change things by fighting the existing reality. To change something, build a new model that makes the existing model obsolete.A change in language is such a new model: it can make oppression and inequalities visible. Words do not only describe our world, they are a vehicle of ideas, and utopias. Analyzing and criticizing our use of language means paving the way for ideas and concepts of inclusion, equality, and unity. You might be guessing at where am I getting at with this Right: I am in favor of acknowledging past mistakes, and replacing oppressive metaphors in computing. As noted in the IETF draft about Terminology, Power and Oppressive Language, by Niels Ten Oever and Mallory Knodel, the metaphors "master/slave" and "blacklist/whitelist" associate "white with good and black with evil [which] is known as the 'bad is black effect'", all the while being technically inaccurate. I acknowledge that this will take time. There is a lot of work to do.
/etc/modprobe.d/blacklist-memstick.conf, all relevant BT modules were added to the blacklist, all this time.
rrs@lenovo:~$ cat /etc/modprobe.d/blacklist-memstick.conf
blacklist memstick
blacklist rtsx_usb_ms
# And bluetooth too
#blacklist btusb
#blacklist btrtl
#blacklist btbcm
#blacklist btintel
#blacklist bluetooth
21:21
Also to keep in mind is that the driver for my card gives a very misleading kernel message, which is one of the many reasons for this blog post, so that I don t forget it a couple of months later. The missing firmware error message is okay to ignore, as per this upstream comment.
Jun 14 17:17:08 lenovo kernel: usbcore: registered new interface driver btusb
Jun 14 17:17:08 lenovo systemd[1]: Mounted /boot/efi.
Jun 14 17:17:08 lenovo kernel: Bluetooth: hci0: RTL: examining hci_ver=06 hci_rev=000b lmp_ver=06 lmp_subver=8723
Jun 14 17:17:08 lenovo kernel: Bluetooth: hci0: RTL: rom_version status=0 version=1
Jun 14 17:17:08 lenovo kernel: Bluetooth: hci0: RTL: loading rtl_bt/rtl8723b_fw.bin
Jun 14 17:17:08 lenovo kernel: bluetooth hci0: firmware: direct-loading firmware rtl_bt/rtl8723b_fw.bin
Jun 14 17:17:08 lenovo kernel: Bluetooth: hci0: RTL: loading rtl_bt/rtl8723b_config.bin
Jun 14 17:17:08 lenovo kernel: bluetooth hci0: firmware: failed to load rtl_bt/rtl8723b_config.bin (-2)
Jun 14 17:17:08 lenovo kernel: firmware_class: See https://wiki.debian.org/Firmware for information about missing firmware
Jun 14 17:17:08 lenovo kernel: bluetooth hci0: Direct firmware load for rtl_bt/rtl8723b_config.bin failed with error -2
Jun 14 17:17:08 lenovo kernel: Bluetooth: hci0: RTL: cfg_sz -2, total sz 22496
This device s network + bt are on the same chip.
01:00.0 Network controller: Realtek Semiconductor Co., Ltd. RTL8723BE PCIe Wireless Network Adapter
And then, when the btusb module is initialed (along with the misleading driver message), you ll get the following in your USB device listing
Bus 002 Device 005: ID 0bda:b728 Realtek Semiconductor Corp. Bluetooth Radio
rrs@lenovo:~$ systemctl status bluetooth
bluetooth.service - Bluetooth service
Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2020-06-15 12:54:58 IST; 3s ago
Docs: man:bluetoothd(8)
Main PID: 310197 (bluetoothd)
Status: "Running"
Tasks: 1 (limit: 9424)
Memory: 1.3M
CGroup: /system.slice/bluetooth.service
310197 /usr/lib/bluetooth/bluetoothd
Jun 15 12:54:58 lenovo systemd[1]: Starting Bluetooth service...
Jun 15 12:54:58 lenovo bluetoothd[310197]: Bluetooth daemon 5.50
Jun 15 12:54:58 lenovo systemd[1]: Started Bluetooth service.
Jun 15 12:54:58 lenovo bluetoothd[310197]: Starting SDP server
Jun 15 12:54:58 lenovo bluetoothd[310197]: Bluetooth management interface 1.15 initialized
Jun 15 12:54:58 lenovo bluetoothd[310197]: Sap driver initialization failed.
Jun 15 12:54:58 lenovo bluetoothd[310197]: sap-server: Operation not permitted (1)
12:55
Next, then is to discover and connect to your device
rrs@lenovo:~$ bluetoothctl
Agent registered
[bluetooth]# devices
Device E6:3A:32:A4:31:8F MI Band 2
Device D4:B8:FF:43:AB:47 MI RC
Device 00:1E:3D:10:29:0F BD Remote Control
[CHG] Device 00:1E:3D:10:29:0F Connected: yes
[BD Remote Control]# info 00:1E:3D:10:29:0F
Device 00:1E:3D:10:29:0F (public)
Name: BD Remote Control
Alias: BD Remote Control
Class: 0x0000250c
Paired: no
Trusted: yes
Blocked: no
Connected: yes
LegacyPairing: no
UUID: Human Interface Device... (00001124-0000-1000-8000-00805f9b34fb)
UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb)
Modalias: usb:v054Cp0306d0100
[bluetooth]#
In case of the Sony BD Remote, there s no need to pair. In fact, trying to pair fails. It prompts for the PIN code, but neither 0000 or 1234 are accepted.
So, the working steps so far are to Trust the device and then Connect the device.
For the sake of future use, I also populated /etc/bluetooth/input.conf based on suggestions on the internet.
Note: The advertised keymappings in this config file do not work.
Note: I m only using it for the power saving measures in instructing the BT connection to sleep after 3 minutes.
rrs@priyasi:/tmp$ cat input.conf
# Configuration file for the input service
# This section contains options which are not specific to any
# particular interface
[General]
# Set idle timeout (in minutes) before the connection will
# be disconnect (defaults to 0 for no timeout)
IdleTimeout=3
# Enable HID protocol handling in userspace input profile
# Defaults to false (HIDP handled in HIDP kernel module)
#UserspaceHID=true
# Limit HID connections to bonded devices
# The HID Profile does not specify that devices must be bonded, however some
# platforms may want to make sure that input connections only come from bonded
# device connections. Several older mice have been known for not supporting
# pairing/encryption.
# Defaults to false to maximize device compatibility.
#ClassicBondedOnly=true
# LE upgrade security
# Enables upgrades of security automatically if required.
# Defaults to true to maximize device compatibility.
#LEAutoSecurity=true
#
#[00:1E:3D:10:29:0F]
[2c:33:7a:8e:d6:30]
[PS3 Remote Map]
# When the 'OverlayBuiltin' option is TRUE (the default), the keymap uses
# the built-in keymap as a starting point. When FALSE, an empty keymap is
# the starting point.
#OverlayBuiltin = TRUE
#buttoncode = keypress # Button label = action with default key mappings
#OverlayBuiltin = FALSE
0x16 = KEY_ESC # EJECT = exit
0x64 = KEY_MINUS # AUDIO = cycle audio tracks
0x65 = KEY_W # ANGLE = cycle zoom mode
0x63 = KEY_T # SUBTITLE = toggle subtitles
0x0f = KEY_DELETE # CLEAR = delete key
0x28 = KEY_F8 # /TIME = toggle through sleep
0x00 = KEY_1 # NUM-1
0x01 = KEY_2 # NUM-2
0x02 = KEY_3 # NUM-3
0x03 = KEY_4 # NUM-4
0x04 = KEY_5 # NUM-5
0x05 = KEY_6 # NUM-6
0x06 = KEY_7 # NUM-7
0x07 = KEY_8 # NUM-8
0x08 = KEY_9 # NUM-9
0x09 = KEY_0 # NUM-0
0x81 = KEY_F2 # RED = red
0x82 = KEY_F3 # GREEN = green
0x80 = KEY_F4 # BLUE = blue
0x83 = KEY_F5 # YELLOW = yellow
0x70 = KEY_I # DISPLAY = show information
0x1a = KEY_S # TOP MENU = show guide
0x40 = KEY_M # POP UP/MENU = menu
0x0e = KEY_ESC # RETURN = back/escape/cancel
0x5c = KEY_R # TRIANGLE/OPTIONS = cycle through recording options
0x5d = KEY_ESC # CIRCLE/BACK = back/escape/cancel
0x5f = KEY_A # SQUARE/VIEW = Adjust Playback timestretch
0x5e = KEY_ENTER # CROSS = select
0x54 = KEY_UP # UP = Up/Skip forward 10 minutes
0x56 = KEY_DOWN # DOWN = Down/Skip back 10 minutes
0x57 = KEY_LEFT # LEFT = Left/Skip back 5 seconds
0x55 = KEY_RIGHT # RIGHT = Right/Skip forward 30 seconds
0x0b = KEY_ENTER # ENTER = select
0x5a = KEY_F10 # L1 = volume down
0x58 = KEY_J # L2 = decrease the play speed
0x51 = KEY_HOME # L3 = commercial skip previous
0x5b = KEY_F11 # R1 = volume up
0x59 = KEY_U # R2 = increase the play speed
0x52 = KEY_END # R3 = commercial skip next
0x43 = KEY_F9 # PS button = mute
0x50 = KEY_M # SELECT = menu (as per PS convention)
0x53 = KEY_ENTER # START = select / Enter (matches terminology in mythwelcome)
0x30 = KEY_PAGEUP # PREV = jump back (default 10 minutes)
0x76 = KEY_J # INSTANT BACK (newer RCs only) = decrease the play speed
0x75 = KEY_U # INSTANT FORWARD (newer RCs only) = increase the play speed
0x31 = KEY_PAGEDOWN # NEXT = jump forward (default 10 minutes)
0x33 = KEY_COMMA # SCAN BACK = decrease scan forward speed / play
0x32 = KEY_P # PLAY = play/pause
0x34 = KEY_DOT # SCAN FORWARD decrease scan backard speed / increase playback speed; 3x, 5, 10, 20, 30, 60, 120, 180
0x60 = KEY_LEFT # FRAMEBACK = Left/Skip back 5 seconds/rewind one frame
0x39 = KEY_P # PAUSE = play/pause
0x38 = KEY_P # STOP = play/pause
0x61 = KEY_RIGHT # FRAMEFORWARD = Right/Skip forward 30 seconds/advance one frame
0xff = KEY_MAX
21:48
I have not spent much time finding out why not all the key presses work. Especially, given that most places on the internet mention these mappings. For me, some of the key scan codes aren t even reported. For keys like L1, L2, L3, R1, R2, R3, Next_Item, Prev_Item, they generate no codes in the kernel.
If anyone has suggestions, ideas or fixes, I d appreciate if you can drop a comment or email me privately.
But given my limited use to get a simple remote ready, to be usable with Kodi, I was apt with only some of the keys working.
btusb.enable_autosuspend=n, but that did not help in this case.
Given that this device is enumberated over the USB Bus, it probably needs this feature applied to the whole USB tree of the device s chain. Something to investigate over the weekend.
Jun 16 20:41:23 lenovo kernel: Bluetooth: hci0: ACL packet for unknown connection handle 7
Jun 16 20:41:43 lenovo kernel: Bluetooth: hci0: ACL packet for unknown connection handle 8
Jun 16 20:41:59 lenovo kernel: Bluetooth: hci0: ACL packet for unknown connection handle 9
Jun 16 20:42:18 lenovo kernel: input: BD Remote Control as /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:10/0005:054C:030>
Jun 16 20:42:18 lenovo kernel: sony 0005:054C:0306.0006: input,hidraw1: BLUETOOTH HID v1.00 Gamepad [BD Remote Control] on 2c:33:7a:8e:d6:30
Jun 16 20:51:59 lenovo kernel: input: BD Remote Control as /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:11/0005:054C:030>
Jun 16 20:51:59 lenovo kernel: sony 0005:054C:0306.0007: input,hidraw1: BLUETOOTH HID v1.00 Gamepad [BD Remote Control] on 2c:33:7a:8e:d6:30
Jun 16 21:05:55 lenovo rtkit-daemon[1723]: Supervising 3 threads of 1 processes of 1 users.
Jun 16 21:05:55 lenovo rtkit-daemon[1723]: Successfully made thread 32747 of process 1646 owned by '1000' RT at priority 5.
Jun 16 21:05:55 lenovo rtkit-daemon[1723]: Supervising 4 threads of 1 processes of 1 users.
Jun 16 21:05:56 lenovo kernel: Bluetooth: hci0: ACL packet for unknown connection handle 12
Jun 16 21:06:12 lenovo kernel: Bluetooth: hci0: ACL packet for unknown connection handle 1
Jun 16 21:06:34 lenovo kernel: Bluetooth: hci0: ACL packet for unknown connection handle 2
Jun 16 21:06:59 lenovo kernel: input: BD Remote Control as /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:3/0005:054C:0306>
Jun 16 21:06:59 lenovo kernel: sony 0005:054C:0306.0008: input,hidraw1: BLUETOOTH HID v1.00 Gamepad [BD Remote Control] on 2c:33:7a:8e:d6:30
rrs@lenovo:~/ps3pair$ kodi-ps3remote localhost 9777
usr/share/pixmaps/kodi//bluetooth.png
Traceback (most recent call last):
File "/usr/bin/kodi-ps3remote", line 220, in <module>
File "/usr/bin/kodi-ps3remote", line 208, in main
xbmc.connect(host, port)
packet = PacketHELO(self.name, self.icon_type, self.icon_file)
File "/usr/lib/python3/dist-packages/kodi/xbmcclient.py", line 285, in __init__
with open(icon_file, 'rb') as f:
11:16 => 1
This one was simple as it was just a broken path.
The second issue with the tool is a leftover from python2 to python3 conversion.
rrs@lenovo:/etc/bluetooth$ kodi-ps3remote localhost
/usr/share/pixmaps/kodi//bluetooth.png
Searching for BD Remote Control
(Hold Start + Enter on remote to make it discoverable)
Redmi (E8:5A:8B:73:57:44) in range
Living Room TV (E4:DB:6D:24:23:E9) in range
Could not find BD Remote Control. Trying again...
Searching for BD Remote Control
(Hold Start + Enter on remote to make it discoverable)
Living Room TV (E4:DB:6D:24:23:E9) in range
Redmi (E8:5A:8B:73:57:44) in range
Could not find BD Remote Control. Trying again...
Searching for BD Remote Control
(Hold Start + Enter on remote to make it discoverable)
BD Remote Control (00:1E:3D:10:29:0F) in range
Found BD Remote Control with address 00:1E:3D:10:29:0F
Attempting to pair with remote
Remote Paired.
Traceback (most recent call last):
File "/usr/bin/kodi-ps3remote", line 221, in <module>
main()
File "/usr/bin/kodi-ps3remote", line 212, in main
if process_keys(remote, xbmc):
File "/usr/bin/kodi-ps3remote", line 164, in process_keys
keycode = data.encode("hex")[10:12]
AttributeError: 'bytes' object has no attribute 'encode'
11:24 => 1
Fixing that too did not give me the desired result on using the BD Remote in the way I want. So eventually, I gave up and used Kodi s Keymap Editor instead.
With the current four-month release cycle, the next Rcpp release is due in July following the 1.0.4 release in March. Just prior to the 1.0.4 release I had asked this:
It would be particularly beneficial if those with unsual build dependencies tested it as we would increase overall coverage beyond what I get from testing against 1800+ CRAN packages. BioConductor would also be welcome.but only on the rcpp-devel list, and only about a good week prior to the release. I remain rather disappointed and disillusioned about what happened after 1.0.4 was released. Two PRs in that release were soon seen to have side effects on more marginal test systems, precisely what added testing could have revealed. An additional issue arose from changes in R s make system, which is harder to anticipate or test. Each and every infelicity was fixed within a day or so, and we always make candidate releases available the current Rcpp as of this writing is 1.0.4.12 meaning twelve microreleases were made since 1.0.4. And those microreleases are always available for normal download and
install.packages use via the Rcpp drat repository accessible to all. So it was truly troubling to see some, especially those with experience in setting up or running testing / ci platforms, pretend to be unable to access, install, and provide these for their own tests, or the tests of their users. It just doesn t pass a basic logic test: it takes a single call to install.packages(), or, even more easily, a single assignment of an auxiliary repo. All told this was a rather sad experience.
So let s try to not repeat this. If you, or maybe users of a build or ci system you maintain, rely on Rcpp, and especially if you do so on systems outside the standard CRAN grid of three OSs and the triplet of previous, current, next releases of R, then please help by testing. I maitain these release as a volunteer, unpaid at that, and I simply cannot expand to more systesm. We take reverse dependency check seriously (and I just run two taking about a day each) but if you insist on building on stranger hardware or much older releases it will be up to you to ensure Rcpp passes. We prep for CRAN, and try our best to pass at CRAN. For nearly a dozen years.
To install the current microrelease from the Rcpp drat repository, just do
That is all there is to it. You could even add the Rcpp drat repository to your repository list.
Rcpp has become successful because so many people help with suggestions, documentation, and code. It is used by (as of today) 1958 CRAN packages, 205 BioConductor packages, and downloaded around a million times per month. So if you can, please help now with some more testing.
If you like this or other open-source work I do, you can now sponsor me at GitHub. For the first year, GitHub will match your contributions.
This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. Please report excessive re-aggregation in third-party for-profit settings.
Could I be any more happier?Well, this time, my project is basically to write a linter (an extension to RuboCop). This tool is mostly to help the Debian Ruby team. And that is the best part, I love working in/for/with the Ruby team!
More details about the project can be found here, on the wiki.git ls-files in the gemspec files. This has been the most problematic thing for us.
Dir or Dir.glob, the best (closest) possible solution
(right now) is to use Rake::FileList which tries to respects the .gitignore file.:wq for today.
The next video in our T^4 series of video lightning talks with tips, tricks, tools, and toys (where we had seen the announcement, shells sessions one, two, and three, as well as byoby sessions one and two) is now up at YouTube. It covers session management for the wonderful byobu tool that is both a text-based window manager and a terminal multiplexer :
The slides are here. This repo at GitHub support the series: use it to open issues for comments, criticism, suggestions, or feedback. If you like this or other open-source work I do, you can now sponsor me at GitHub. For the first year, GitHub will match your contributions.
This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. Please report excessive re-aggregation in third-party for-profit settings.
Another maintenance RVowpalWabbit package update brings us to version 0.0.14. This time CRAN asked us to replace the (long obsoleted C-library) function ftime(). Along the way, we also updated links in the DESCRIPTION file to the (spiffy!!) new vowpalwabbit.org website, updated Travis use and fine-tuned some autoconf code in configure.ac.
There is a newer package rvw based on the excellent GSoC 2018 and beyond work by Ivan Pavlov (mentored by James and myself) so if you are into Vowpal Wabbit from R go check it out. It should go to CRAN eventually once we have better mechanisms to support external libraries.
CRANberries provides a summary of changes to the previous version. More information is on the RVowpalWabbit page. Issues and bugreports should go to the GitHub issue tracker.
If you like this or other open-source work I do, you can now sponsor me at GitHub. For the first year, GitHub will match your contributions.
This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. Please report excessive re-aggregation in third-party for-profit settings.
Some time has passed since the last updated of my KDE/Plasma packages. In the meantime KDE/frameworks 0.70 was uploaded to Debian/unstable, and everyone should have smoothly transitioned to the official packages by now.
In the same vein, some packages from the Plasma stack have been updated to 5.18.5 via the official channels, but some aren t here my repos still might be helpful. Finally, KDE/Apps are also in the process of finally being updated to 20.04.0/1 in Debian/unstable, but 20.04.2 was already released the other day, as well as Plasma 5.19 some days ago.
So here is the current status in the repositories I maintain on OBS:
/etc/apt/trusted.gpg.d/obs-npreining.asc.
As mentioned in the previous post, collaboration with the Debian Qt/KDE Team unfortunately turned out to be impossible, but I will keep updating the packages here, and try to keep compatibility with the Debian official packages, so that if finally there are updates they will take precedence over the packages from my repositories.
Enjoy.
Welcome to gambaru.de. Here is my monthly report (+ the first week in June) that covers what I have been doing for Debian. If you re interested in Java, Games and LTS topics, this might be interesting for you.
Debian Games


The sixth release of the binb package is now on CRAN. binb regroups four rather nice themes for writing LaTeX Beamer presentations much more easily in (R)Markdown. As a teaser, a quick demo combining all four themes follows; documentation and examples are in the package.
Via two contributed PRs, this releases adds titlepage support via the YAML header for Metropolis, and suppresses nags about the changed natbib default. A little polish on the README and Travis rounds everything off.
CRANberries provides a summary of changes to the previous version. For questions or comments, please use the issue tracker at GitHub. If you like this or other open-source work I do, you can now sponsor me at GitHub. For the first year, GitHub will match your contributions.Changes in binb version 0.0.6 (2020-06-10)
This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. Please report excessive re-aggregation in third-party for-profit settings.
I've written about what Template Haskell is, and given an example of what
it can be used for, it's time to explain why I
was looking at it in the context of my PhD work.
Encoding stream-processing programs
StrIoT is an experimental distributed stream-processing
system that myself and others are building in order to explore our research
questions. A user of StrIoT writes a stream-processing program, using a set
of 8 functional operators provided for the purpose. A simple example is
streamFn :: Stream Int -> Stream Int
streamFn = streamFilter (<15)
. streamFilter (>5)
. streamMap (*2)
Our system is distributed: we take a stream-processing program and
partition it into sub-programs, which are distributed to and run on separate
nodes (perhaps cloud instances, or embedded devices like Raspberry Pis etc.).
In order to do that, we need to be able to manipulate the stream-processing
program as data. We've initially opted for a graph data-structure, with the
vertices in the graph defined as
data StreamVertex = StreamVertex
vertexId :: Int
, operator :: StreamOperator
, parameters :: [String]
, intype :: String
, outtype :: String
deriving (Eq,Show)
A stream-processing program encoded this way, equivalent to the first example
path [ StreamVertex 0 Map ["(*2)"] "Int" "Int"
, StreamVertex 1 Filter ["(>5)"] "Int" "Int"
, StreamVertex 2 Filter ["(<15)"] "Int" "Int"
]
We can easily manipulate instances of such types, rewrite them, partition them
and generate code from them. Unfortunately, this is quite a departure from the
first simple code example from the perspective of a user writing their program.
Template Haskell gives us the ability to manipulate code as a data structure,
and also to inspect names to gather information about them (their type, etc.).
I started looking at TH to see if we could build something where the
user-supplied program was as close to that first case as possible.
TH limitations
There are two reasons that we can't easily manipulate a stream-processing
definition written as in the first example. The following expressions are
equivalent, in some sense, but are not equal, and so yield completely
different expression trees when quasi-quoted:
[ streamFilter (<15) . streamFilter (>5) . streamMap (*2) ]
\s -> streamFilter (<15) (streamFilter (>5) (streamMap (*2) s)) ]
[ streamMap (*2) >>> streamFilter (>5) >>> streamFilter (<15) ]
[ \s -> s & streamMap (*2) & streamFilter (>5) & streamFilter (<15) ]
[ streamFn ] -- a named expression, defined outside the quasi-quotes
In theory, reify can give you the definition of a function from its
name, but in practice it doesn't, because this was never implemented.
So at the very least we would need to insist that a user included the
entirety of a stream-processing program within quasi-quotes, and not
split it up into separate bits, with some bits defined outside the
quotes and references within (as in the last case above). We would
probably have to insist on a consistent approach for composing operators
together, such as always use (.) and never >>>, &, etc. which is
limiting.
Incremental approach
After a while ruminating on this, and before moving onto something else,
I thought I'd try approaching it from the other side. Could I introduce
some TH into the existing approach, and improve it? The first thing I've
tried is to change the parameters field to TH's ExpQ, meaning the
map instance example above would be
StreamVertex 0 Map [ [ (*2) ] ] "Int" "Int"
I worked this through. It's an incremental improvement ease and clarity
for the user writing a stream-processing program. It catches a class of
programming bugs that would otherwise slip through: the expressions in
the brackets have to be syntactically valid (although they aren't type
checked). Some of the StrIoT internals are also much improved,
particularly the logical operator. Here's an excerpt from a rewrite
rule that involves composing code embedded in strings, dealing with all
the escaping rules and hoping we've accounted for all possible incoming
expression encodings:
let f' = "(let f = ("++f++"); p = ("++p++"); g = ("++g++") in\
\ \\ (a,b) v -> (f a v, if p v a then g b v else b))"
a' = "("++a++","++b++")"
q' = "(let p = ("++p++"); q = ("++q++") in \\v (y,z) -> p v y && q v z)"
And the same section after, manipulating ExpQ types:
let f' = [ \ (a,b) v -> ($(f) a v, if $(p) v a then $(g) b v else b) ]
a' = [ ($(a), $(b)) ]
q' = [ \v (y,z) -> $(p) v y && $(q) v z ]
I think the code-generation part of StrIoT could be radically refactored
to take advantage of this change but I have not made huge inroads into that.
Next steps
This is, probably, where I am going to stop. This work is very interesting
to me but not the main thrust of my research. But incrementally improving
the representation gave me some ideas of what I could try next:
intype and outtype could be TH Types instead of Strings.
This would catch some simple problems like typos, etc., but we could
possibly go further, andparameters is a list, because the different stream operators have
different arities. streamFilter has one parameter (the filter
predicate), so the list should have one element in that case, but
streamExpand has none, so it should be empty.
We could collapse this to a single ExpQ, which encoded however
many parameters are necessary, either in an internal list, or parameters
expression was actually a call to the relevant operator with its
parameters supplied.data StreamVertex = StreamVertex
vertexId :: Int
, opAndParams :: ExpQ
deriving (Eq,Show)
Example instances might be
StreamVertex 0 [ streamMap (*2) ]
StreamVertex 1 [ streamExpand ]
StreamVertex 2 [ streamScan (\c _ -> c+1) 0 ]
The vertexId field is a bit of wart, but we require that due to
the graph data structure that we are using. A change there could
eliminate it, too. By this point we are not that far away from where
we started, and certainly much closer to the "pure" function application
in the very first example.
After that I got multiple questions about the setup, so I thought "Michael and Michael did posts about their setups, you could too!"
And well, here we are ;-)
desk
The desk is a Flexispot E5B frame with a 200 80 2.6cm oak table top.
The Flexispot E5 (the B stands for black) is a rather cheap (as in not expensive) standing desk frame. It has a retail price of 379 , but you can often get it as low as 299 on sale.
Add a nice table top from a local store (mine was like 99 ), a bit of wood oil and work and you get a nice standing desk for less than 500 .
The frame has three memory positions, but I only use two: one for sitting, one for standing, and a "change position" timer that I never used so far.
The table top has a bit of a swing when in standing position (mine is at 104cm according to the electronics in the table), but not enough to disturb typing on the keyboard or thinking. I certainly wouldn't place a sewing machine up there, but that was not a requirement anyways ;)
To compare: the IKEA Bekant table has a similar, maybe even slightly stronger swing.
chair
Speaking of IKEA The chair is an IKEA Volmar. They don't seem to sell it since mid 2019 anymore though, so no link here.
hardware
laptop
A Lenovo ThinkPad T480s, i7-8650U, 24GB RAM, running Fedora 32 Workstation. Just enough power while not too big and heavy. Full of stickers, because I stickers!
It's connected to a Lenovo ThinkPad Thunderbolt 3 Dock (Gen 1). After 2 years with that thing, I'm still not sure what to think about it, as I had various issues with it over the time:
Armadillo is a powerful and expressive C++ template library for linear algebra aiming towards a good balance between speed and ease of use with a syntax deliberately close to a Matlab. RcppArmadillo integrates this library with the R environment and language and is widely used by (currently) 727 other packages on CRAN.
Conrad recently released a new upstream version 9.900.1 of Armadillo which we packaged and tested as usual first as a release candidate build and then as the release. As usual, logs from reverse-depends runs are in the rcpp-logs repo.
Apart from the new upstream release, we updated Travis use, ornamented the README a little, and smoothed over a rough corner from the recent R 4.0.0 release. All changes in the new release are noted below.
Courtesy of CRANberries, there is a diffstat report relative to previous release. More detailed information is on the RcppArmadillo page. Questions, comments etc should go to the rcpp-devel mailing list off the R-Forge page. If you like this or other open-source work I do, you can now sponsor me at GitHub. For the first year, GitHub will match your contributions.Changes in RcppArmadillo version 0.9.900.1.0 (2020-06-08)
- Upgraded to Armadillo release 9.900.1 (Nocturnal Misbehaviour)
- faster
solve()for under/over-determined systems- faster
eig_gen()andeig_pair()for large matrices- expanded
eig_gen()andeig_pair()to optionally provide left and right eigenvectors- Switch Travis CI testing to R 4.0.0, use bionic as base distro and test R 3.6.3 and 4.0.0 in a matrix (Dirk in #298).
- Add two badges to README for indirect use and the CSDA paper.
- Adapt
RcppArmadillo.package.skeleton()to a change in R 4.0.0 affecting what it exports inNAMESPACE.
This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. Please report excessive re-aggregation in third-party for-profit settings.
Next.