MozillaVsBrendanEich

Probabilistic Ruminations on the Mozilla Fiasco

I’m doubly unease : I don’t know how I feel about the whole Mozilla fiasco, and I hate that I don’t know how to feel about it.

I can’t talk for all gay people, but I struggle to find a balance between two biases. On one hand, obviously, there’s the tendency to take homophobia personally. But on the other hand, maybe surprisingly,  there is desensitization. After hearing about, witnessing, or experiencing a high enough number of nasty incidents, some involving maiming and death, and many involving loss of appreciable measures of wealth, prestige, sanity or health, one gets a bit… hardened.

My rule of the thumb says “switch sexual-orientation for race and adjust your outrage accordingly”. And I assure you that if I heard some CEO had paid a thousand bucks to bring back racially segregated marriages, my outrage would be clear-cut : I would call for that person’s head to roll.

So why do I hesitate (while feeling horrible for hesitating) in giving the same verdict for Brendan Eich ?

My hesitation does not come from the belief that opposing same-sex marriage is compatible with embracing LGBT people (as many marriage equality opponents would love us to believe). At least this, for me, is crystal clear : if you oppose same-sex marriage, you are asserting that in some sense same-sex relationships deserve less recognition than heterosexual ones. And that’s homophobia. If you do it for religious reasons, you do it for homophobic religious reasons. (And please, don’t even think of bringing up that stale “different but equal” bullshit : if you must be a bigot, own your bigotry.)

Neither I think that the correct frame of discussion is the one of free speech. Even if we agree in joining the acrobatic virtuosity of the US Supreme Court in stretching the definition of speech so to accept the act of financing a political movement as an act of speech, that frame still does not provide a convincing defense for Eich.

Yes, for me, freedom of speech is sacred, “I don’t agree with what you have to say, but I’ll defend to the death your right to say it”, etc., etc., et al. It implies the right to the free exercise of expressing one’s ideas, even when those ideas show one’s a complete jerk. But here’s the catch : it does not imply the right to some kind of magical protection from criticism and consequences from expressing ideas that show one’s a complete jerk. Take note of that disclaimer, kids, it’s important.

If we have to consider free speech the act of Eich donating money to prevent same-sex couples from acceding to the protections of civil marriage — with very unpleasant concrete, material consequences for those couples ; then we must,  as well, consider free speech people calling for Eich to get the hell out of Mozilla foundation, even if the concrete, material consequences for him are, well, unpleasant.

The usual oligophrenics are of course shouting “Gay Gestapo !”  I’ll only cursorily comment on the bad taste of this wording, by warning that anyone who dare to use it in my presence should expect in return an overly long unsolicited lecture about Paragraph 175. (I must also comment that when it is the turn of those hypocrites to call for people’s heads, they reserve for themselves metaphors conveying only righteousness, never censorship or violence).

So, if I am not willing to buy Eich’s antinomy that he opposes same-sex marriage all the while completely embracing LGBT people ; and if the problem here is not violating his freedom of speech ; then where does my hesitation come from ?

Let’s come back to my outrage-adjustment rule, i.e., be as outraged for an act of homophobia as you would for an equivalent act of racism. I think there are two difficulties here.

First, and obviously, not all acts of homophobia are equal, like not all acts of racism are equal. Paraphrasing the puppets of Avenue Q, everyone is a little bit homophobe, including you and me. Defending segregation is not the same as defending slavery. Opposing same-sex marriage is not the same as defending the criminalization of homosexuality. Things have gradations.

Second, and here’s the root of my discomfort : the status of what is socially acceptable or not in terms of homophobia is changing fast. This is good, of course, but it means we must be careful not to to make presentist/ethnocentric judgements. And cut some slack as different people adapt to the new mores faster than others.

If we are to judge people by their acts — and not simply judge the acts of people, and I mean if we are to jump into the exercise of estimating P(A, X), where N is the unobservable measure of a person’s niceness, A is her observable’s acts, and X is all other prior information ; then we must be very careful to ensure that X encodes the social mores of the space and time when the act was committed, and not the mores of our present space and time. Otherwise we will fall into the fallacies of presentism (time) or ethnocentrism (space). Thus, the relevant likelihood to estimate here is not P(Eich gave 1000 bucks to repeal same-sex marriage | Eich is a nice guy, California, 2014, X), but P(Eich gave 1000 bucks to repeal same-sex marriage | Eich is a nice guy, California, 2008, X) [that model assumes that niceness at his age is stationary].

Then there is forgiveness.  Societal views on homosexuality are (fortunately) evolving fast. Scant decades ago — less than my age — gay bashing in Brazil was a wholesome sport practiced by bored guys in look for a thrill. In many parts of the world it still is. Meanwhile, many countries now have hate-crime laws, non-discrimination acts, and civil same-sex marriages. In some places, the f- word has become as much as taboo as the n- word. Some people are having a hard time to adapt.

I’ll be the last one to defend the ridiculous non-sequitur that “tolerance implies tolerating the intolerant”. But, for me, accepting, provisionally and conditionally to further dialog, some intolerance is compelling in two senses : charitable and utilitarian. Charitable because no-one is perfect, everyone is little bit racist, everyone is a little bit homophobe, everyone is a jerk now and then, everyone says and does things that they will regret later, etc. The Golden Rule applies. Utilitarian because if we can engage with people and help them to cross the bridge to tolerance, in the end we gain more than if we alienate them to the fringes of radical intolerance.

So is my verdict that the boycott to Eich was wrong, and that we should had instead let him occupy the CEO position, all the while keeping the dialog with him ? It is not that simple. Unless I have missed something, Eich has never really solved the issue of whether or not he is against marriage equality today.

This is the point that really troubles be : I think that the likelihood P(Person is against same-sex marriage | Person is nice, California, TX) is becoming vanishingly small as time T progresses. However, anyone should have the right to hold — privately — any thought, even the most horrifying, even the most nauseating, without being subject to any sanctions whatsoever. If freedom of speech is sacred and untouchable, freedom of thought should be A(sacred,untouchable). As long as Eich keeps his thoughts private, for me, it makes no difference if he wants each and every LGBT person lining up to the gas chambers : thoughts are unobservable and people should not be judged by them.

But Eich has in the past acted on those thoughts. He has donated money to prevent LGBT people in California from marrying. He has donated money to Pat Buchanan’s and Ron Paul’s campaigns in the 1990s (ultimately it were those donations who gave him the coup de grâce). His poison was very much observable in the past.

Honestly, I’m glad his gone — but I’m still not sure it was the right decision to ask him to go. Which loss function should we had applied to his case ? I wish I knew.

* * *

In my first term as a Computer Sciences undergrad, my colleagues thought it would be hilarious if they changed the screen savers of all our lab computers to show in big blinking letters a phrase calling me a gay slur. This went on for weeks.

Today, it strikes me that my colleagues could decide it would be okay to play such a prank, and do it without any shame or fear of punishment ; that the faculty and  administration, aware of the deeds, could think it would be okay to do nothing about it ;  that I could think it would be okay to be mildly annoyed, shrug it off, and not lodge a formal complaint. All this happened less than 20 years ago : if it happened today, I am sure the case would make national press.

I don’t want to be draconian with Eich. If I held my alma mater and old classmates to my today’s standards, I would hate them all. And I don’t. I have scientific cooperations with my former professors. When my former classmates and I meet, we treat each other cordially. I have no means to inspect the inside of their minds to check if those people still bear animosity against gay people, but if they do, they hide it really well. If I have evolved so much in 17 years, shouldn’t I give them at least the benefit of the doubt ?

MozillaVsBrendanEichBut neither I want to be lax with Eich, lest my leniency become a betrayal of everything LGBT people have earned so arduously.

Featured image —  Money Crush by Rocky Lubbers,  Ideal Husbands by See-ming Lee.

Code Released for Visual Word Spatial Arrangement

Illustration reproduced from “Visual word spatial arrangement for image retrieval and classification”, Pattern Recognition, 2014.My former Ph.D. student Dr. Otávio Penatti (now working at Samsung Research Institute Brazil and cooperating with  RECOD in a number of projects) has released the source code for the technique implemented in our paper “Visual word spatial arrangement for image retrieval and classification”, recently published in the Pattern Recognition journal.

The code has been released under a copyleft GPLv3 license.

Program Committee Member at SISAP 2014

Similarity search is my favorite research subject. But it was only two years ago that I became aware of SISAP. I remember, at that point, that taking a look at the former editions, I got the impression SISAP was exactly the kind of event you would want to attend : small, cozy, and all the cool people were there.

So I didn’t hesitate to accept when my dear colleague Prof. Agma Traina, who’ll be Chair at the Program Committee this year, invited me as a member of the Committee. I hope I’ll be able to attend, but even if that doesn’t happen, I am glad to take some part at this interesting community.

The call for papers has already launched, with deadline for abstract submissions on May 12th. If you work on similarity search, related topics or applications, please consider sending a contribution. The event will take place in Los Cabos, Mexico, on October, 29–31.

Grant from Microsoft Azure

My team and I received a grant from Microsoft Azure for Research. Our proposal was named “Medical Image Classification for Computer Aided Diagnosis with Deep Learning and Jumbo Vectors”, with the following abstract :

Information retrieval and content-based image classification are progressing fast. A key application for those technologies is Computer-Aided Diagnosis (CAD), improving doctors’ ability to detect diseases and prevent their progression. Our aim is to advance the state of the art in disease screening based upon images, focusing on the early screening of melanoma. The techniques covered in this project are Deep Learning Architectures and Bag of Visual Words models, which show complementary advantages.

The grant provides us with Azure’s resources (storage, processing units, etc.) to run our techniques in that cloud-based environment.

We are much thankful to Microsoft Research for this opportunity.

Planning the Future of Technology for Education in Brazil

SAMSUNG has kindly invited me to their Workshop “Planning the Future of Technology for Education in Brazil”, next week, at the Joint SAMSUNG/UNICAMP Lab. Quoting them, “The event will discuss technological innovation to address pressing education issues. At SAMSUNG Research Institute Brazil, Advanced Technology Group, we are committed to exploring visions and technologies that will create a new reality for technology in education in Brazil. We aim to build up a research agenda that will influence the industrial, academic and solution developer communities.”

I currently coordinate, with my colleagues Prof. Alim Gonçalves and Prof. Renato Lopes, the EAE Group (Teaching and Learning Engineering) — a voluntary, informal and collegial group of professors who are trying to improve the teaching and learning experience of Science, Technology, Engineering, and Math at UNICAMP, especially for the undergraduates. You can find more about our activities in our Google Plus page and our YouTube Channel (both in Portuguese).

I am also researching, with Renato and our student Ms. Jomara Bindá, low-cost Personal Response Systems, aimed at classroom usage in disfavored communities, especially in rural schools, and those in poor urban neighborhoods.

My lab and I have a number of ongoing collaborative works with SAMSUNG, which is one of our main partners. I am very excited about the upcoming workshop.

Webdesign is hell

I am still in love with Syntax, the theme I’ve recently chosen for my blog and webpage, but the first rift appeared between us. The lovely minimalist menu icon (the same used by Chrome, a little square with three horizontal bars — you can check it on Syntax’s homepage) is apparently too subtle for some of my readers. I had to change it for something more… explicit.

A little CSS magic should be enough to change the abstract icon for a concrete “menu” tag written vertically :

@media screen and (min-width: 801px) {
  #toggle-nav:before {
    content: "menu";
    font-family: Merriweather, Georgia, "Times New Roman", serif;
    text-align: center;
    display: block;
    width: 4em;
    height: 2em;
    padding-top: 0.5em;
    -webkit-transform-origin: 0% 100%;
    -o-transform-origin: 0% 100%;
    transform-origin: 0% 100%;
    -webkit-transform: rotate(90deg);
    -o-transform: rotate(90deg);
    transform: rotate(90deg);
  }
}

@media screen and (max-width: 800px) {
  #toggle-nav:before {
    content : "menu";
    padding-top: 0.2em;
    padding-bottom: 0.6em;
  }
}

And indeed it works. Sort of.

Menu button wrongly rendered on Internet ExplorerGetting the rotation right was a nightmare, since different browsers require different names for the properties. My first attempt included the declaration writing-mode: tb-rl; because every CSS snippet for vertical text I’ve found on the web seemed to include it. And it worked all right. Well, except on Internet Explorer (isn’t that a surprise ?) on which it resulted on a double rotation.

The code snippet above contains three independent pieces of magic :

  • CSS media queries : the @media { } rule comprehends other CSS rules conditional to the page being rendered on specific media. In my example, the #toggle-nav:before rules are to be interpreted only if the page is rendered on a screen at specific widths ;
  • CSS :before pseudo-selector : the :before (and its counterpart :after) pseudo-selectors allow inserting new content inside the specified elements. In my example, new content will be inserted inside all elements with id toggle-nav, before any child elements already there (:after would insert new content after any child elements already there). The new content is textual (<tags> are interpreted as plain text), but its formatting may be specified by other declarations in the rule. In my example, I’m inserting the content “menu” and specifying some details about fonts, size, text alignment, padding, etc. ;
  • CSS transforms : the transform property allows specifying various geometric transformations, and the transform-origin property allows specifying the origin point (the “pivot”) of the transformation. In my example, I am asking for a 90 degrees clockwise rotation, around the left lower corner (0% horizontal, 100% vertical) of the element. Those properties sometimes require browser-dependent synonyms.

Now everything seems to work, at least on Safari (OS X), Firefox (OS X and Windows), IE (Windows), and Chrome (OS X). Of course, each combination of OS–browser renders the button in a slightly but irritatingly different way. I’ll attribute to wisdom and spiritual growth  — instead of jadedness and laziness — that I’ll simply throw up my hands, instead of spend a sleepless night trying to make it perfectly right.

More worrisome than slight rendering inconsistencies is the fact that the button is behaving erratically on Chrome for Windows in one of the computers I’ve tested : sometimes it responds, sometimes it freezes. But since it worked on all other computers, I’m brushing it off to the fact that this one computer also had 5 or 6 plugin toolbars installed. I know : blaming the environment is the classical debugger’s fallacy, but in this case it might be justifiable.

If you are trying to read this blog and can’t use the menus, or if the rendering is horrible in your device–OS–browser, please drop me a note.

Edit 5/mar : I’ve expanded the explanation of the code snippet above and adopted a more rigorous CSS nomenclature.

Calls for papers are spam

(First I must do my confession : as an event organizer I’ve been on the offending side of CFP writing more times than I cared to count. Last time was maybe past week. I deeply empathize with the anxiety of program chairs and organizing committees : folks, I’ve been there. No, I am there ! But let’s all agree that this madness must stop.)

I’ve debated with myself for a while, but I now reached my verdict : formulaic calls for papers are spam.

Deciding what is spam is complicated. I am adopting Paul Graham’s definition : unsolicited automated e-mail. I will not take the time to defend it, Graham already did it better than I would. It is not perfect1, but it works for the purposes of this discussion.

Unless your recipient has explicitly asked you to do it, do not send him/her formulaic calls for papers.

You may still send relevant2 formulaic CFPs for mailing lists that explictly accept them, for example, the Brazilian Computer Society mailing list. And for aggregator sites, for example, the WikiCFP.

You may still write a one-to-one message to a friend, or a colleague that you know personally. I am talking about something in the spirit of “Hi, how are you doing ? Last summer you’ve told me about your research on anti-gravity belts. I think that the attached call on flying devices from the Mad Science Society will interest you. Cheers  !”3. I am not talking about something in the spirit of a boilerplate message that you write and then cram your entire contact list in the BCC. That’s unsolicited automated e-mail, even if it’s you acting as the automaton.

* * *

No Junk MailNext time I receive your formulaic call for papers in one of my personal, whether professional or private, e-mail addresses, I will not click “archive”, I will not click “delete”. I will click “mark as spam” without a second thought.

You have been warned.

1 One problem with Graham’s definition is emergency messages. If a flight gets cancelled/modified, or if there is an extreme-weather alert, I argue that unsolicited automated e-mail alerting people of those events should be considered bacon. If you have concrete evidence that missing your CFP will cause people a hassle as big as missing a flight (or threaten their life), by all means, send them the message.

2 “Relevant” means that your call for papers’ and the mailing list’s interests intersect appreciably. If your call interests that community only very tangentially or indirectly, abstain. If you are in doubt, abstain.

3 If you write a robot4 to try to pass your formulaic CFP as a personal one-to-one message, know there’s a Circle of Hell just for people like you.

4 If your robot is AI-complete, and it/he/she knows personally the recipient, it/he/she may write a personal one-to-one message to your recipient.

New packaging ! Same content ! Same great price !

Choosing WordPress themes is worse than buying a new car. I love the clean austerity of TwentyTen, but for quite a while I have been finding it a little tired. It is twenty fourteen, after all !

Meanwhile, I must have examined dozens of themes only to find each one lacking in some aspect : layout, typography, navigation, color scheme, etc., etc.

Now there is Syntax. It has a clean design, marvelous navigation, beautiful typography, intelligent layout. And it is free !

Now, two little blemishes. First : I hate the underlining, and I would much prefer color decoration for the hyperlinks. But this is a problem from which TwentyTen already suffered. Second : The font is a tad too big for my tastes, especially when reading on a phone. It is true that it makes reading much easier, especially on my poor 35+ year old eyes. But forget about getting a large chunk of text at once on that small screen.

I’d really appreciate some feedback here. What do you think ? Do you love it ? Do you hate it ? Is the huge-ass font a deal-breaker ? Please, let-me know.

Update 12/02 : A few hours and a little money later I’ve solved (I think) all problems : a little CSS magic got rid of the underlines, and a font customization got me a reasonably sized Minion Pro on the body text (30 bucks a year for both). I’ve also re-enabled the mobile view, which is friendlier for the really itsy bitsy screens (but as far as beauty goes, is a train wreck on Android — hair raising horrible).

Must. Stop. Designing. Must. Go. Sleep. (I blame my colleagues at RECOD. They’ve asked me to design a new logo for — well, I am not allowed to tell you at this point. Typography is a drug, kids, just say no to kerning. This is your brain on Helvetica.)

GEB Seminar ; Her

The students of our IEEE CIS chapter, together with our Pos-graduate Student Association have kindly invited me for their first joint Seminar–Coffee. I’ll be talking about Hofstadter’s Gödel, Escher, Bach, and about the forthcoming course I am offering the postgraduates about the book. Here’s a translation of their invitation :

What is the link between Gödel, Escher and Bach and what do the three of them have to do with Artificial Intelligence ?

Those are the questions that motivate our first Seminar–Coffee. We will host Professor Dr. Eduardo Valle, who will talk to us about the course he will give this semester, “35 Years of Gödel, Escher, Bach : Commented and Extended Reading of a Masterpiece of Artificial Intelligence”.

If you are interested in themes related to A.I., or even if you are just curious about it, come spend some time with us. According to Prof. Valle, “this will be an intellectual adventure more engaging than you can imagine !”.

The seminar will take place at the Congregation Room of the School of Electrical and Computer Engineering (pointer “C” in this map), on Wednesday, February 26 at 17h30.

Besides this “must watch” content, we will offer sandwiches and soft drinks, so we can concurrently eat and philosophize.

N.B. : our room has capacity for about 60 people. Admission will be made on a first-come basis.

The talk and discussion will be in Portuguese.

* * *

I’m not very attuned to Hollywood, my source of mindless entertainment being (should I confess this ?) webcomics, short videoclips and UGC. Therefore I was taken by surprise by all the noise around “Her”, last year’s film by Spike Jonze about a man, an intelligent Operating System who identifies as a women, and a relationship they develop. The film has received a long list of accolades, and widespread critical acclaim.

The film themes are dear to me : the relationship of people with technology, the possibility of hard A.I. happening within our lifetimes, how A.I. would perceive itself and relate to us if it happened. And, of course, the singularity. The film also raises interesting questions about the construction of gender identities.

But I must confess that I was left cold by both of the trailers. Watching the eau de rose scenes they chose for the marketing, all I could think was, “Great : the manic pixie dream girl goes digital. How avant-garde.” Judging by the cover, the film does not dwell very much in any of the interesting issues it raises.

It is possible, however, that the trailers don’t do justice to Samantha’s role. According to TVTropes (my go to resource for criticism and analysis), the MPDG aspect is lampshaded, and then subverted. If it is really so, the movie becomes  more interesting. I am still a bit skeptical, but now there is a chance I might pick “Her” instead of “Frozen” in my next intercontinental flight.

(Okay. Really there isn’t that chance. But there is a chance I might pick “Her” after “Frozen” if I can’t sleep in my next intercontinental flight.)

Update 11/02 : Apparently my seminar will have a live webcast. Stay tuned for details !

Update 26/02 : The talk is available (in Portuguese).

Update 27/02 : The talk slides are available in PPTX (including the short movies) or in PDF (just the images). I’m making the presentation itself available under a CC-BY-SA 3.0 License — but be careful with the 3rd parties copyrights.

Macro Programming, Unit Testing

Macro programming is hell. Abuse the preprocessor and soon you’ll be joining the ranks of the fallen in the Turing tarpit.

The problem is compounded by the infamously unhelpful error messages of GCC. Today, I’ve spent a good part of an hour trying to decipher and debug this particularly mystifying one :

In file included from test_bitvector.c:14:0:
checkhelper.h:79:34: error: '#' is not followed by a macro parameter
 #define checkAssertXXInt(X, OP, Y) do { \
                                  ^

Check the source and see if you can find the problem. I’ll make your life really easy and promise you that the error is in this small snippet :

#define checkAssertXXInt(X, OP, Y) do { \
  unsigned __int128 _ck_x = (unsigned __int128) (X); \
  uintmax_t _ck_x_hi = (_ck_x >> 64); \
  uintmax_t _ck_x_lo = (_ck_x & 0xFFFFFFFFFFFFFFFF); \
  unsigned __int128 _ck_y = (unsigned __int128) (Y); \
  uintmax_t _ck_y_hi = (_ck_y >> 64); \
  uintmax_t _ck_y_lo = (_ck_y & 0xFFFFFFFFFFFFFFFF); \
  ck_assert_msg(_ck_x OP _ck_y, \
    "Assertion '%s' failed: '%s'==%jX.%016jX, '%s'==%jX.%016jX"#msg, #X#OP#Y, \
    #X, _ck_x_hi, _ck_x_lo, #Y, _ck_y_hi, _ck_y_lo); \
} while (0)

Found out ? No ? First hint : although GCC is technically right and there is a problem in the line shown, it would be much more helpful to show another (symmetrical) error.

Still nothing ? There is no shame : the macro parameter msg used with the # operator in line 87 was not declared in line 79.

Now imagine ferreting the little troll, among a flurry of cascading errors, from a 150-line source that includes 5 other headers. Maddening enough for a Pirsig treatise.

* * *

Ironically, the error occurred whilst I prepared a common header for my unit testing modules.

As a scientist who mostly writes hundred-line scripts, this is the very first time I am designing unit tests. I was worried that the learning curve for a testing library would be steep, and so I was immediately sold by the no-frills proposition of Check, a unit test framework for C. It comes complete with a tutorial that — frankly — if you are an academic programer like me, tells you everything you need to know. (Although I find the diff notation of the examples less friendly than it could be).

It took me half an hour to understand Check, and then I was joyously writing and running my tests. Of course, just as soon, I was already wondering how it could be perfected :

  1. Have the assertion helper macros (e.g., ck_assert_int_eq) allow the printing of extra info, like ck_assert_msg does ;
  2. Solve a small bug in the helper macros : they show the inspected expressions by embedding them directly in the printfed string. The problem : what happens when the expression has a modulo operator (%) ? Exactly ! Printf takes it as an escape character, and catastrophe ensues ;
  3. Have helper macros for the 128-bit integers that GCC offers as an extension to the standard integers of C ;
  4. Solve an slight aesthetical problem, since I much prefer camelCase for the helper functions than snake_case (But I reserve UGLY_UPPER_SNAKE_CASE for preprocessor macros with UGLY_SECONDARY_EFFECTS, which you MUST_REMEMBER, because THEY_BITE !) ;
  5. Include automatically the main() function — which is very much the same for every test. I took the opportunity to make it parse the command-line to set the verbosity of the output.

Below you’ll find the fruits of those amendments. Or if you prefer, here’s a link for the source repo. It is released under the same LGPL 2.1 license as Check. No warranties : if you choose to use it, and your computer turns into an Antikytherean device,  or your code opens a portal to Baator, I am not liable.

/*
 Name        : checkhelper.h -- Helper header for Check unit test library
 Contributor : Eduardo A. do Valle Jr., 2014-01-27
 License     : LGPL 2.1 --- see http://check.sourceforge.net/COPYING.LESSER
 */

#ifndef CHECK_HELPER_H_
#define CHECK_HELPER_H_

#include <assert.h>
#include <check.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/* --- Alternative macros for unit testing --- */

#define checkAbort ck_abort

#define checkAssert ck_assert

#define checkAbortInfo ck_abort_msg

#define checkAssertInfo ck_assert_msg

#define checkAssertInt(X, OP, Y) do { \
  intmax_t _ck_x = (X); \
  intmax_t _ck_y = (Y); \
  ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: '%s'==%jd, '%s'==%jd", #X#OP#Y, #X, _ck_x, #Y, _ck_y); \
} while (0)

#define checkAssertUInt(X, OP, Y) do { \
  uintmax_t _ck_x = (X); \
  uintmax_t _ck_y = (Y); \
  ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: '%s'==%ju, '%s'==%ju", #X#OP#Y, #X, _ck_x, #Y, _ck_y); \
} while (0)

#define checkAssertXInt(X, OP, Y) do { \
  uintmax_t _ck_x = (X); \
  uintmax_t _ck_y = (Y); \
  ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: '%s'==%jX, '%s'==%jX", #X#OP#Y, #X, _ck_x, #Y, _ck_y); \
} while (0)

#define checkAssertString(X, OP, Y) do { \
  const char* _ck_x = (X); \
  const char* _ck_y = (Y); \
  ck_assert_msg(0 OP strcmp(_ck_y, _ck_x), "Assertion '%s' failed: '%s'==\"%s\", '%s'==\"%s\"", #X#OP#Y, #X, _ck_x, #Y, _ck_y); \
} while (0)

#define checkAssertIntInfo(X, OP, Y, msg, ...) do { \
  intmax_t _ck_x = (X); \
  intmax_t _ck_y = (Y); \
  ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: '%s'==%jd, '%s'==%jd. "#msg, #X#OP#Y, #X, _ck_x, #Y, _ck_y, ## __VA_ARGS__); \
} while (0)

#define checkAssertUIntInfo(X, OP, Y, msg, ...) do { \
  uintmax_t _ck_x = (X); \
  uintmax_t _ck_y = (Y); \
  ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: '%s'==%ju, '%s'==%ju. "#msg, #X#OP#Y, #X, _ck_x, #Y, _ck_y, ## __VA_ARGS__); \
} while (0)

#define checkAssertXIntInfo(X, OP, Y, msg, ...) do { \
  uintmax_t _ck_x = (X); \
  uintmax_t _ck_y = (Y); \
  ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: '%s'==%jX, '%s'==%jX. "#msg, #X#OP#Y, #X, _ck_x, #Y, _ck_y, ## __VA_ARGS__); \
} while (0)

#define checkAssertStringInfo(X, OP, Y, msg, ...) do { \
  const char* _ck_x = (X); \
  const char* _ck_y = (Y); \
  ck_assert_msg(0 OP strcmp(_ck_y, _ck_x), \
    "Assertion '%s' failed: '%s'==\"%s\", '%s'==\"%s\". "#msg, #X#OP#Y, #X, _ck_x, #Y, _ck_y, ## __VA_ARGS__); \
} while (0)


#ifdef __SIZEOF_INT128__

    #define checkAssertXXInt(X, OP, Y) do { \
      unsigned __int128 _ck_x = (unsigned __int128) (X); \
      uintmax_t _ck_x_hi = (_ck_x >> 64); \
      uintmax_t _ck_x_lo = (_ck_x & 0xFFFFFFFFFFFFFFFF); \
      unsigned __int128 _ck_y = (unsigned __int128) (Y); \
      uintmax_t _ck_y_hi = (_ck_y >> 64); \
      uintmax_t _ck_y_lo = (_ck_y & 0xFFFFFFFFFFFFFFFF); \
      ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: '%s'==%jX.%016jX, '%s'==%jX.%016jX", #X#OP#Y, #X, _ck_x_hi, _ck_x_lo, #Y, _ck_y_hi, _ck_y_lo); \
    } while (0)

    #define checkAssertXXIntInfo(X, OP, Y, msg, ...) do { \
      unsigned __int128 _ck_x = (unsigned __int128) (X); \
      uintmax_t _ck_x_hi = (_ck_x >> 64); \
      uintmax_t _ck_x_lo = (_ck_x & 0xFFFFFFFFFFFFFFFF); \
      unsigned __int128 _ck_y = (unsigned __int128) (Y); \
      uintmax_t _ck_y_hi = (_ck_y >> 64); \
      uintmax_t _ck_y_lo = (_ck_y & 0xFFFFFFFFFFFFFFFF); \
      ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: '%s'==%jX.%016jX, '%s'==%jX.%016jX. "#msg, #X#OP#Y, #X, _ck_x_hi, _ck_x_lo, #Y, _ck_y_hi, _ck_y_lo, ## __VA_ARGS__); \
    } while (0)

#endif


/* --- Unless CHECK_HELPER_TEST_SUITE_NAME is defined with the name to use, testSuite() will be called to build the suite to run --- */

#ifndef CHECK_HELPER_TEST_SUITE_NAME
    #define CHECK_HELPER_TEST_SUITE_NAME testSuite
#endif


/* --- Unless CHECK_HELPER_MAIN_NAME is defined with the name to use, main() will be used --- */

#ifndef CHECK_HELPER_MAIN_NAME
    #define CHECK_HELPER_MAIN_NAME main
#endif


/* --- Provide a main() function by default, unless CHECK_HELPER_NO_MAIN is defined --- */

#ifndef CHECK_HELPER_NO_MAIN

    Suite * CHECK_HELPER_TEST_SUITE_NAME(void);  // declaration

    int CHECK_HELPER_MAIN_NAME(int argc, char **argv) {

        enum print_output mode = CK_NORMAL;

        if      (argc>1 && (strcmp(argv[1], "-v")==0 || strcmp(argv[1], "--verbose")==0)) {
            mode = CK_VERBOSE;
        }
        else if (argc>1 && (strcmp(argv[1], "-q")==0 || strcmp(argv[1], "--quiet")==0)) {
            mode = CK_SILENT;
        }
        else if (argc>1 && (strcmp(argv[1], "-m")==0 || strcmp(argv[1], "--minimal")==0)) {
            mode = CK_MINIMAL;
        }
        else if (argc>1 && (strcmp(argv[1], "-n")==0 || strcmp(argv[1], "--normal")==0)) {
            mode = CK_NORMAL;
        }
        else if (argc>1 && (strcmp(argv[1], "-e")==0 || strcmp(argv[1], "--environment")==0)) {
            mode = CK_ENV;
        }
        else if (argc>1) {
            #ifndef CHECK_HELPER_USAGE_STRING
            printf("usage: [test_executable] [verbosity flags: -(-q)uiet | -(-m)inimal | -(-n)ormal (default) | -(-v)erbose | -(-e)nvironment ]\n"
                   "       if -e or --environment get verbosity from environment variable CK_VERBOSITY (values: silent minimal normal verbose)\n");
            #else
            printf(CHECK_HELPER_USAGE_STRING);
            #endif
            return 1;
        }

        Suite *suite = CHECK_HELPER_TEST_SUITE_NAME();

        SRunner *suiteRunner = srunner_create(suite);
        srunner_run_all(suiteRunner, mode);
        int numberFailed = srunner_ntests_failed(suiteRunner);
        srunner_free(suiteRunner);

        return (numberFailed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
    }

#endif

#endif