Davor Josipovic Just another WordPress blog – rather tryout

15/07/2012

Deus Ex: Human Revolution – some thoughts from a fan

Filed under: Gaming — Tags: , — Davor @ 20:36

I played the original twice. When I was 17, and later when I was about 22. I am not really into shooters – yes, I skipped the Invisible War – but this game is so much more. One gets immersed into the future as seen by its creator Warren Spector. To describe this “not the end of the world but you can see it from there”-feeling would take many pages. So I’ll keep it short. Beside the great gameplay, sound and story, Deus Ex confronts you with moral dilemmas and makes you think about human augmentation and just polity. Beside the entertainment value it also has some “educational” value.

So now we have a new prequel Deus Ex: HR. Usually I play a game 2-4 years after its release, when it’s close to bugfree and possibly improved by the mods. But after I saw the Deus Ex: HR trailer and the intro I just couldn’t resist… So here is what I liked and did not like about the game. It might contain spoilers.

The visuals are stunning and memorable. Some are simply jawdropping. The creativity involved in making the world look mystical, but at the same time futuristic and “Deus Ex” is really top notch. These artists definitely understand the original.

Just like the original, this Deus Ex has definitely a memorable soundtrack. Very futuristic and at the same time “Deus Ex”. The voice acting is also incredibly well done, for all the NPC, but especially the main character and main NPC’s.

Overall gameplay is good to very good/perfect. Although this game seems to be made for console, it plays very well on PC too. It simply feels right after you get used to the gameplay. It is also obvious that much time has been spent on making the gameplay flawless, and incorporating various ways for one to get to the objective.

The dialogues are much improved compared to the original. There is much more interaction and choice left to the player. The social interaction aug is also very well implemented. The thing that bothered me were the sometimes shallow facial expressions.

Story is OK for a Deus Ex game. Whereas the first Deus Ex dealt with the just governmental system, the subject of HR is more about the dangers of augmentation and human transcendence. From that perspective it seems that the end of HR was pushed to resemble the original Deus Ex ending where one could choose – and play God. I did miss some depth and consistency. The story seems artificially prolonged because the plot is too simple, and at times becomes boring. So although the plot of HR is good and has great potential, the presentation of it seems far less to me. I think I missed the message during my 60h play. The original did better here, although it didn’t had as much content – I think.

Quake-like boss fights? Well, I don’t think they have a place in a Deus Ex game. Also it is a pity that these bosses are completely void of personality – in contrast with the other NPC.

The skill system is removed, and now completely replaced with the augmentation system. I really liked the skill system: it gave one a certain level of specialization that is unrelated to augs. Like better aiming with weapons you specialize in, faster movement with heavy weapons, staying longer under water, some hacking skills, medical skills, etc. So, to me this was definitely a big loss. An unique playing experience could be highly increased with a skill system.

The augs now get unlocked with XP-points. Most are well designed and well implemented in the game. The fact that you already have them all removes the “wauw” effect of finding one though. Auto-recharging one battery is a good improvement from the previous series – now one can experiment without permanently using up the bio-energy. But recharging only one seems inconsistent: having two charged cells and taking one enemy down will “waste” this second cell, while doing the same with one cell will not – the empty cell will reload eventually.

The praxis packs (and other items) scattered through the game on sometimes strange locations… it could have been better. Same with the empty lockers…

I also missed a way to replay (or re-read) the conversations I had with people. Sometimes there is much information at once, and you don’t want to miss a thing… I though the original had a log for this.

The hacking is improved – resembles System Shock (?) – but is imbalanced in my opinion. With a few aug-points one can hack everything and get money and XP for free. One can misuse this eventually. On hardest settings I had eventually more than 40 stops! and viruses in my backpack, and gathered very much gold. Even the toughest terminals went down easily. Such hacking makes searching for passcodes completely irrelevant.

Hacked turrets and robots have no cameras. They could have them.

The stealth difficulty could be higher. The patrol routes could be extended, randomized, etc. Now the guards usually don’t go just far enough to see you. Also, the AI during alarm or hostile faze could be better. The guards don’t go too far in their search, and if they do, they sometimes go alone, which makes them easy to take down unnoticed. Guards also don’t notice when some of them are missing for a long time.

The third person view unlocked with the right mouse button is interesting but lacks explanation – certainly for a game that is trying to look as realistic as possible. How come Adam is able to have such a “field of view”?

At the same time there are much eBooks scattered through the world that refer to real-life happenings. It’s kind of strange… it doesn’t feel right.

The DLC – Missing Link – doesn’t run from the main game. This is a pity. The pre-order special text in the weapon descriptions I also found very bothering.

Replay value? Not so if you ask me. But hard to tell why though. Maybe because the game tries to be so realistic your every decision feels like it is definite. The game feels more like an onetime experience… which sticks!

So does it live up to the name? I think it does. To be honest: there are flaws. But the vocals and visuals are stunning. The experience is unique. The story is OK. The gameplay is quite ambitious, and speaking of value: it is definitely worth the money. I am happy that de developers also tried successfully new things and didn’t simply brought us the original in a new package – like with HL2 (!!). I think they should have gone even further – although this is always a big risk. Because of this, I find it not as “redefining” as the original was, but at the same time I cannot look past its aspirations. So, although there are definitely things that could have been better, these shortcomings don’t measure up against the love, care and attention for detail that have been put into this game.

10/07/2011

Select screen for XBMC without 3th party tools

Filed under: batch — Tags: , — Davor @ 20:43

This is usually done by changing the default display with some tool (DisplaySwitch.exe, UltraMon,…) Here we simply use XBMC’s advanced settings and a simple batch file which will allow to select the startup options (in this case the screen), copy the corresponding advancedsettings.xml to the \userdata\ folder and start XBMC on the correct screen with custom properties.
For this we use XBMC in portable mode (with command line option –p), but it could also work without. Make this folder structure in your XBMC directory:

portable_data\config\adv_settings

In adv_settings folder we put 2 files from which we will chose during startup:
Advancedsettings_monitor.xml:

<advancedsettings>
	<videoscreen>
        		<screenmode>WINDOW</screenmode>
	</videoscreen>
    	<window>
        		<height>720</height>
	        	<width>1280</width>
    	</window>
	<input>
        		<enablemouse>false</enablemouse>
	</input>
</advancedsettings>

Advancedsettings_tv.xml:

<advancedsettings>
	<videoscreen>
		<screenmode>10128000720050.00000</screenmode>
	</videoscreen>
</advancedsettings>

These values are taken from guisettings.xml in the \userdata\ folder. So it’s best you set up XBMC and take the settings you need from guisettings.xml and put them into advancedsettings.xml. Apparently, in my case 10128000720050.00000 corresponds to full screen on the TV.
Finally this simple batch file will let you choose between the two:

@set batch_path=%~dp0

:: Choose Monitor-------------------------------------
@choice /C 12 /M "Start on TV[1], Monitor[2]?" /N /T 3 /D 1
@goto ANSWER%ERRORLEVEL%
::----------------------------------------------------
 
:ANSWER0
:ANSWER255
@GOTO ERROR
 
:ANSWER1
@copy "%batch_path%adv_settings\advancedsettings_tv.xml" "%batch_path%..\userdata\advancedsettings.xml" /Y
@IF ERRORLEVEL 1 GOTO ERROR
@GOTO exit
 
:ANSWER2
@copy "%batch_path%adv_settings\advancedsettings_monitor.xml" "%batch_path%..\userdata\advancedsettings.xml" /Y
@IF ERRORLEVEL 1 GOTO ERROR
@GOTO exit
 
:ERROR
@echo "Wrong batch execution... check batch"
@pause
@GOTO QUIT
 
:EXIT
@start /D "%batch_path%..\..\" XBMC.exe -p
 
:QUIT

Now all you need to do is run the batch file, type 1 or 2 and XBMC will start on the correct screen. It is also obvious that these advanced settings allow much more customization than is shown here.

An other interesting way would be to use the API called SetwindowsPos… and even more interesting would be to expose the XMBC API to the command line prompt as suggested here.

26/11/2010

Google Analytics on-the-fly insertion with Apache

Filed under: php,Programming — Tags: , — Davor @ 22:46

I recently needed to insert the Google Analytics script on the fly on each html page that an Apache server was sending. Kirill Minkovich has made a good overview of the standard ways for doing so. Particularly the second and third solutions are interesting because they use the ext_filter_module which is meant for such things.

External filters are slow. Since Apache 2.2.7 there is a internal SUBSTITUTE filter.

AddOutputFilterByType SUBSTITUTE text/html
 
Substitute "s#<head(.*)>#<head$1>\
    <!-- Global site tag (gtag.js) - Google Analytics -->\
    <script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-19913980-1\"></script>\
    <script>\
       window.dataLayer = window.dataLayer || [];\
       function gtag(){dataLayer.push(arguments);}\
       gtag('js', new Date());\
       gtag('config', 'UA-XXXXXXX-X');\
    </script>#iq"

That’s it! Make sure that DEFLATE filter is not run before, otherwise the SUBSTITUTE filter will get a gzipped stream and thus will not be able to insert the code.

Note: Aaron Gloege also has a very interesting php-only solution for this problem, but I, IMHO, thought it a bit farfetched. Nonetheless, it is probably (much) faster than the one used below.

Here is a simpler version for the filter.google-analytics.php file:

<?php
$ga_script =
"<script type=\"text/javascript\">
 
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-XXXXXXXX-X']);
  _gaq.push(['_trackPageview']);
 
  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();
 
</script>";
 
$handle = fopen ("php://stdin","r");
// Will read the whole stream. 
// Use $sHtmlFile = fgets($handle); for testing purposes from command line.
$sHtmlFile = stream_get_contents($handle);
 
// We allow only one replacement before one of the 3 tags.
// From testing it appears that php PCRE engine replaces the
// first match from the stream. So the ga_script will probably
// be inserted before </head> as Google recommends.
$replacements;
$sHtmlFile = preg_replace(
	'/(<\/head>|<\/body>|<\/html>)/si',
	"$ga_script$1",
	$sHtmlFile,
	1,
	$replacements);
 
if ($replacements == 0)
{
	$sHtmlFile = $sHtmlFile . $ga_script;
}
 
echo $sHtmlFile;
?>

And of course, add the following to your apache.conf file:

LoadModule ext_filter_module modules/mod_ext_filter.so
ExtFilterDefine insert-google-analytics cmd="/bin/php /cgi-bin/filter.google-analytics.php" mode=output
AddOutputFilter insert-google-analytics htm html

24/11/2010

System-wide events and Qt

Filed under: C++,Programming,Qt — Tags: , , — Davor @ 23:02

Few days back I wanted to create a macro recorder for the desktop. I though I could do this from within the Qt framework which has a neat high-level platform-independent event system that I thought I could incorporate with widgets to make a nice user interface. Well, that’s what I though at least… Truth is, Qt doesn’t offer any means for catching system-wide events. Eventually, I managed to put together a little command line application that can record and replay/loop the mouse and keyboard input messages based on the Windows API. What you will read next is my explanation why catching system-wide events is impossible from within the Qt framework, what the Windows API offers for this purpose, and a proposal on how system-wide events could be incorporated in the Qt event system.

Background

Windows and Qt applications are event driven, which means that they wait for the system to pass events to them upon which they can act. Simply put, those events are passed as “messages” to application windows through a callback function named the “window procedure”.

For example, when a user moves a mouse, the mouse device driver places the recorded movement in the system’s message queue. The system then determines the destination window and “posts” this message to the correct “thread message queue” (i.e. the message queue of the thread which created the destination window). Our Qt application has only access to these messages from its thread message queue. These messages are called “spontaneous events” in the Qt documentation. (Note: there exist also “sent” messages which bypass the message queue, but which we do not consider here.)

Now as one can see, the system is very selective on which mouse and keyboard events our Qt application will get. For example, our window will not get any keyboard messages if it is not in focus, nor will it get any mouse events if the mouse is not inside the window borders. So how can we access those events from the Qt framework? To my knowledge Qt doesn’t offer any ready made functions for this, so we will have to find some other way: directly accessing the Windows API.

Hooks

The Windows API offers a mechanism called a “hook” which we can hook somewhere in the message-handling mechanism and which will intercept and reroute the messages to some “hook procedure” we define. We define a hook with the API SetWindowsHookEx procedure. This procedure allows us to specify the “hook type” which defines the kind of messages to be intercepted (like WH_MOUSE_LL, WH_KEYBOARD_LL, WH_SHELL), the “hook scope” which can be thread or global (i.e. system), and the hook procedure with the following predefined signature:

 LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam);

So to get you started here is a very basic application which uses the above described mechanism an which can be used as a starting point for building applications which are able to monitor system events.

#include <QtGui/QApplication>
#include <QDebug>
 
#include <windows.h>
 
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    // process event...
    qDebug() << nCode << wParam << lParam;
 
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
 
    if (SetWindowsHookEx(WH_KEYBOARD_LL, HookProc, qWinAppInst(), NULL) == 0)
        qDebug() << "Hook failed for application instance" << qWinAppInst() << "with error:" << GetLastError();
 
    return a.exec();
}

For more information, the following links might be interesting:

I’ve put together a little command line utility that is able to record and replay/loop the recording based on the above explanation. Sourcecode is available here. To record: “winrec -record /f “recording.txt””. To play: “winrec -play /f “recording.txt” /repeat 0″. To stop any of these, just press Crtl+Esc.

I think integration with an Qt would probably be straightforward when used with QAbstractEventDispatcher, although I didn’t have time to test it.

11/08/2010

“Undefined reference to vtable” for QObject-derived classes in the implementation (.cpp) file.

Filed under: Programming,Qt — Tags: , — Davor @ 18:14

“undefined reference to vtable” seems to be a common problem with Qt’s meta-object system in combination with GCC.

The main cause due to GCC is described here: http://gcc.gnu.org/faq.html#vtables

But with QObject it gets a bit more complex. When you use the macro Q_OBJECT, you define some virtual methods which might trigger the above GCC error under certain circumstances. So make sure your use of the Q_OBJECT macro fulfills the following requirements:

  1. Make sure the Q_OBJECT macro is present in the definition of all QObject-derived classes
  2. Make sure you define your QObject-derived classes in your header files ONLY
  3. Make sure all of your header files are listed in your .pro file in the HEADERS-list
  4. Run qmake every time you add Q_OBJECT to one of your classes or modify your .pro file

(Source: http://www.theirishpenguin.com/2007/07/01/qobject-qmake-and-sadness-undefined-reference-to-vtable/)

Not fulfilling point 2:
You get the “undefined reference to vtable” error if you put your QObject-derived class in the implementation file because moc will not “add” the implementation of the virtual functions to the cpp file. Apparently you can enforce this by adding “#include cpp_file_name.moc” to your “cpp_file_name.cpp” file. Moc will detect this and will generate a “cpp_file_name.moc” file.

29/06/2010

PostgreSQL table audit in plpgsql

Filed under: Postgres,Programming — Tags: , — Davor @ 15:27

I recently had to implement a logging system for our database. Googling resulted in a few interesting ways to do this. The best I have found so far is from Lorenzo Alberton. I recommend you glance through that, and also an extension/improvement of it by James Gardner.

Now, Lorenzo’s implementation has a few problems. Most notably: not all of us want to install Tcl. So, I have “rewritten” it in plpgsql. This is possible since in the meantime the EXECUTE command was extended with the USING clause.

Some extra features are added also:

  • Support for multi-field PK’s.
  • Logging of PK’s.
  • Changes are detected by default type operators instead of textbased operators.

Note: I am using a slightly different naming convention, so you should adjust the names before using it with extra functions from James.

Note2: This is still a (working) tryout. Comments on improvement are welcome.

Update: fnc_audit(…) is used by trg_audit()

CREATE OR REPLACE FUNCTION private.tfc_audit()
  RETURNS TRIGGER AS
$BODY$ 
 
/*!
 Dynamic query exectution through plpgsql EXECUTE command makes this function possible.
 Some complications which can araise using this command are described here:
  - http://archives.postgresql.org/pgsql-general/2008-05/msg00314.php
*/ 
 
DECLARE 
 
_PK_NAMES CONSTANT VARCHAR[] := ARRAY(SELECT a.attname AS pk_name FROM pg_class c, pg_attribute a, pg_index i
     WHERE c.oid = i.indrelid
     AND a.attrelid = i.indexrelid
     AND a.attisdropped = FALSE /* such column names are like "........pg.dropped.1........" and are invalid */
     AND a.attnum > 0 /* i.e is not a system column like OID: they have (arbitrary) negative numbers */ 
     AND i.indisprimary = TRUE /* is pk */
     AND c.oid = TG_RELID /* regclass takes current schema into consideration! */); 
 
_FIELD_NAMES CONSTANT VARCHAR[] := ARRAY(SELECT a.attname AS pk_name FROM pg_class c, pg_attribute a
     WHERE c.oid = a.attrelid
     AND a.attisdropped = FALSE /* such column names are like "........pg.dropped.1........" and are invalid */
     AND a.attnum > 0 /* i.e is not a system column like OID: they have (arbitrary) negative numbers */ 
     AND c.oid = TG_RELID ); /* regclass takes current schema into consideration! */ 
 
_PK_VALUES VARCHAR[]; 
 
BEGIN 
 
-- this function works only when marked as AFTER trigger!
PERFORM assert(TG_WHEN = 'AFTER', 'Wrong execution of fnc_audit(): should only be executed AFTER an event!');
-- this function works only when marked as FOR EACH ROW trigger!
PERFORM assert(TG_LEVEL = 'ROW', 'Wrong execution of fnc_audit(): should only be executed FOR EACH ROW!'); 
 
-- table sanity check
PERFORM assert(TG_TABLE_NAME IS NOT NULL, 'TG_TABLE_NAME IS NULL');
PERFORM assert(_PK_NAMES IS NOT NULL AND array_length(_PK_NAMES, 1) IS NOT NULL, 'Table ' || TG_TABLE_NAME || ' can not be logged: it has no PK!');  -- FOR-loop will otherwise throw "upper bound of FOR loop cannot be null" 
 
-- skip changes on audit_table: otherwise endless loop
IF TG_TABLE_NAME = 'tbl_audits' THEN
 RETURN NULL; -- result is ignored since this is an AFTER trigger
END IF; 
 
-- find PK value
FOR i IN 1 .. array_length(_PK_NAMES, 1)
LOOP
 DECLARE
  tmp text;
  tmp_record record;
 BEGIN
  CASE TG_OP
  WHEN 'UPDATE', 'INSERT' THEN tmp_record = NEW;
  WHEN 'DELETE' THEN tmp_record = OLD;
  END CASE; 
 
  EXECUTE 'SELECT $1.' || quote_ident(_PK_NAMES[i]) INTO STRICT tmp USING tmp_record;
  _PK_VALUES[i] := tmp;
 END;
END LOOP; 
 
-- PK values sanity check
PERFORM assert(_PK_VALUES IS NOT NULL AND array_length(_PK_VALUES, 1) IS NOT NULL, '_PK_VALUES IS NULL'); -- FOR-loop will otherwise throw "upper bound of FOR loop cannot be null"
PERFORM assert(array_length(_PK_VALUES, 1) = array_length(_PK_NAMES, 1), '_PK_VALUES count not equal to _PK_NAMES count in table ' || TG_TABLE_NAME); 
 
-- find fields to be logged
FOR i IN 1 .. array_length(_FIELD_NAMES, 1)
LOOP
 -- field_name sanity check
 PERFORM assert(_FIELD_NAMES[i] IS NOT NULL, '_FIELD_NAMES[' || i || '] IS NULL'); 
 
 DECLARE
  _field_name CONSTANT VARCHAR := quote_ident(_FIELD_NAMES[i]);
  _distinct BOOLEAN;
  _old text;
  _new text;
 BEGIN 
 
 CASE TG_OP --fall through is unfortunately not supported
  WHEN 'UPDATE' THEN
   -- compare the two fields according to the type-default functions.
   -- note that <> returns false on NULL input and IS DISTINCT FROM does not, but only if both inputs are NULL!
   EXECUTE 'SELECT $1.' || _field_name || ' IS DISTINCT FROM $2.' || _field_name || ';' INTO STRICT _distinct USING OLD, NEW;
   CONTINUE WHEN NOT _distinct; 
 
   EXECUTE 'SELECT $1.' || _field_name || ';' INTO STRICT _new USING NEW;
   EXECUTE 'SELECT $1.' || _field_name || ';' INTO STRICT _old USING OLD;
  WHEN 'INSERT' THEN
   EXECUTE 'SELECT $1.' || _field_name || ';' INTO STRICT _new USING NEW;
  WHEN 'DELETE' THEN
   EXECUTE 'SELECT $1.' || _field_name || ';' INTO STRICT _old USING OLD;
  ELSE
   RAISE EXCEPTION 'Unhandled TG_OP in fnc_audit(): %', TG_OP;
 END CASE; 
 
 CONTINUE WHEN _new IS NULL AND _old IS NULL; 
 
 PERFORM private.fnc_audit(statement_timestamp()::TIMESTAMP WITHOUT TIME zone, SESSION_USER::VARCHAR, TG_TABLE_NAME::VARCHAR, _field_name, _PK_NAMES, _PK_VALUES, TG_OP::private.table_audit_mod_type, _old, _new);
 
 END;
END LOOP; 
 
RETURN NULL; -- result is ignored since this is an AFTER trigger
END; 
 
$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;

A specific function for inserting into tbl_audits is used:

CREATE OR REPLACE FUNCTION private.fnc_audit(_audi_timestamp TIMESTAMP WITHOUT TIME zone, _audi_user name, _audi_table name, _audi_field name, _audi_pk_name CHARACTER VARYING[], _audi_pk_value CHARACTER VARYING[], _audi_mod_type private.table_audit_mod_type, _audi_value_old text, _audi_value_new text)
  RETURNS void AS
$BODY$
DECLARE
BEGIN 
 
INSERT INTO private.tbl_audits(audi_timestamp, audi_user, audi_table, audi_field, audi_pk_name, audi_pk_value, audi_mod_type, audi_value_old, audi_value_new)
 VALUES (_audi_timestamp, _audi_user, _audi_table, _audi_field, _audi_pk_name, _audi_pk_value, _audi_mod_type, _audi_value_old, _audi_value_new); 
 
END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE;

TG_OP is stored as an ENUM (= more efficient) so we need a new type:

CREATE TYPE private.table_audit_mod_type AS ENUM ('INSERT', 'UPDATE', 'DELETE', 'TRUNCATE');

Here is a very important helper function:

CREATE OR REPLACE FUNCTION assert(BOOLEAN, CHARACTER VARYING)
  RETURNS void AS
$BODY$
BEGIN
 IF NOT $1 OR $1 IS NULL THEN
   IF $2 IS NOT NULL THEN 
     RAISE EXCEPTION 'Assert failure: %', $2;
   END IF;
   RAISE NOTICE 'Assert. Message is null';
 END IF; 
END;$BODY$
  LANGUAGE 'plpgsql' VOLATILE;

And finaly the audit table:

CREATE TABLE private.tbl_audits
(
  audi_timestamp TIMESTAMP WITHOUT TIME zone NOT NULL,
  audi_user CHARACTER VARYING(30) NOT NULL,
  audi_table CHARACTER VARYING(45) NOT NULL,
  audi_field CHARACTER VARYING(30) NOT NULL,
  audi_pk_name CHARACTER VARYING(30)[] NOT NULL,
  audi_pk_value CHARACTER VARYING(60)[] NOT NULL,
  audi_mod_type private.table_audit_mod_type NOT NULL,
  audi_value_old text,
  audi_value_new text,
  CONSTRAINT tbl_audits_check_pk CHECK (array_length(audi_pk_name, 1) = array_length(audi_pk_value, 1))
);

A more storage-efficient way to store logged data would be to make an audi_changeset column which consists of an array of changed fieldnames, old values and new values for each PK during a statement execution. It would be equivalent to the following view:

CREATE OR REPLACE VIEW vew_audit_changesets AS
 SELECT tbl_audits.audi_timestamp, tbl_audits.audi_user, tbl_audits.audi_table, tbl_audits.audi_pk_name, tbl_audits.audi_pk_value, tbl_audits.audi_mod_type, ARRAY[array_agg(tbl_audits.audi_field), array_agg(tbl_audits.audi_value_old)::CHARACTER VARYING[], array_agg(tbl_audits.audi_value_new)::CHARACTER VARYING[]] AS audi_changeset
   FROM tbl_audits
  GROUP BY tbl_audits.audi_timestamp, tbl_audits.audi_user, tbl_audits.audi_table, tbl_audits.audi_pk_name, tbl_audits.audi_pk_value, tbl_audits.audi_mod_type;

fnc_audit() is easily adjustable to store logs to such a table. But I wonder whether this is worth the fuss? Most of the queries run on vew_audit_changesets would first require the “unnesting of array audi_changeset to sets” (i.e. a structure which resembles tbl_audits). Why? Because SQL is set-oriented, not array-oriented. In other words, it seems easy to convert from tbl_audits structure to vew_audit_changesets structure, but how does one go from vew_audit_changesets structure to tbl_audits structure, and is this conversion efficient? Is it worth to save logs in a vew_audit_changesets-like table?

01/06/2010

Restore last viewed page when opening pdf files in Acrobat

Filed under: Uncategorized — Tags: — Davor @ 19:07

A very nice feature of WinDjView is that on opening a document it by default goes to the page you viewed the last time before you closed it. Now, for those who read pdf files, one may wonder whether this feature is supported by Adobe Acrobat. And guess what: It is. Go to Edit->Preferences->Documents and select “Restore last view settings when reopening documents”.

As far as I am concerned, this feature should be on by default.

11/05/2010

IsDirty() class member for QDataWidgetMapper

Filed under: C++,Programming,Qt — Tags: , — Davor @ 15:57

Here is something I wanted to share. It’s a pity something similar isn’t implemented by the Trolls. But then again, it doesn’t require much coding either.

    bool isDirty() const {
        Q_ASSERT(orientation() == Qt::Horizontal);
        Q_ASSERT(rootIndex() == QModelIndex());
        for(int i = 0; i < model()->columnCount(); i++) {
            QWidget *mapWidget = mappedWidgetAt(i);
            if (mapWidget){
                QByteArray p = mappedPropertyName(mapWidget);
                QModelIndex idx = model()->index(currentIndex(), i);
                if (idx.data(Qt::EditRole) != mapWidget->property(p))
                    return true;
            }
        }
        return false;
    }

One use is to check whether an update is required before going to the next record…

PS Other way one could achieve the same thing by adjusting the source code because the “mappings”-container is in the private implementation of QDataWidgetMapper.

05/03/2010

A philosophical analysis of the corruption phenomenon

Filed under: Corruption,Philosophy — Tags: , — Davor @ 19:34

In this series of blogs you will find a short version of my Master dissertation titled “Een filosofische analyse van het corruptiefenomeen”, or in English: “A philosophical analysis of the corruption phenomenon”. It expounds on what I think is one of the biggest problems of the current corruption-discourse: the conception of corruption itself. Why? Because corruption today is a blown up phenomenon where all sorts of things are shuffled underneath. This is my premise. And the consequences of this are far-reaching.

So what to expect from reading through? In my thesis I used examples and thought-experiments as a guide for the conceptual analysis. I think the examples in themselves are informative, even though you might not agree with my conclusions. Another element is Searle’s conceptualization of institutions which is very informative and highly useful in the context of institutional corruption.

Note: The original summary (based on the thesis) is written in Dutch and can be found here. I didn’t have time to translate it all. Currently, only a short description of corruption and the main problem are translated. If you (or someone you know, like Google Translate) know Dutch you can read the Dutch summary or the thesis itself.

Corruption?

Corruption is an universal phenomenon, independent of social system, age, position or class. It is also a very old phenomenon. Already in writings dating from Babylonia, 2250 BC, one finds traces of corruption. (Wab08: 38-9, 160) But corruption probably never was a hot issue as it is today. (Jos09: 5) Burgeoning global media has undoubtedly contributed to this. But many developments in the last thirty years have contributed also. These include the major corruption scandals, the end of the cold war and some globalization trends.

All this fuss about corruption is not without a reason. (cf. Jos09: 56) Bribery is probably the most researched form of corruption. Its consequences are estimated in various studies that focus on local and global economies, political and social domains. It’s economic costs are staggering. As an example: World Bank (Mos97) estimated that about 5% of the value of imports in developing countries are bribes to officials. This results in some 50-80 billion dollar loss in economic growth per year. A common consequence of such form of corruption are “white elephant” projects. Such projects are very large, grease well, and are buried short after completion because they are completely unnecessary from the public perspective. As an example of scale, Moody-Stuart (Moo96) notes that projects under $2,000,000 rarely attract attention of senior officials. Bribery has also the tendency to opt for specific industries. There is for example evidence (Lam06: 32-3) that corruption reduces government spending on education, contrary to military and defense.

Corruption goes further than just the economic and political sphere. Wabanhu (Wab08) emphasizes on many occasions that corruption erodes patters of morality and civic virtue which comprise the foundations of ethics and which are necessary to maintain human rights and dignity of an equitable community. In short, corruption erodes the patterns that generally promote the good of a community.

Despite the fact that corruption is broadly considered a problem and has led to the emergence of various developments, ranging from protests and international treaties, to national and international organizations like Transparency International, it still remains a debatable subject. So what’s “wrong” with concept of corruption?

The problem: the premise

For one, the concept of corruption in contemporary literature is vague and hardly explored. Most authors start from a general understanding of corruption, supported by the common definitions. But it is precisely these often quoted definitions that give us a too narrow view on corruption. (Jos09: 23) And that’s not all: we haven’t even considered their diversity! Wabanhu (Wab08: 15) notes in this context that there are almost as many definitions of corruption as there are authors who write about it. Now, the consequences of this conceptual chaos are far-reaching. Consider the following questions:

  • What is corruption all those empirical studies are referring to? If the main subject of research is dubiously defined, what about the results and implications of such research? Do these implications have any scientific value? This question begs for a clear definition, which we will try to give.
  • What do we restrict with the so-called anti-corruption measures? This is a very important question because the corruption countermeasures are established on basis of a particular understanding of that which has to be restricted (i.e. corruption). We will explore this issue, it’s possibly undesirable consequences, and give examples.
  • Is the carrot and stick approach sufficient to combat corruption? Some say yes, some say no, based on their particular conception of corruption. We will explore the differences, and point where it possibly goes wrong.
  • And why fight corruption at all? This might sound funny, but there actually are authors who defend it. Well, assuming their arguments do have a rational ground, where exactly do they differ from the antagonists, and most importantly, what can we learn from these differences?

It is in large part due to this conceptual chaos that today such questions have no clear answer. So the question “what exactly is corruption?” becomes more and more pressing. For us this question represents the start of our paper where we try to build a conceptual framework that allows us to understand corruption.

For two, we all associate bribery, extortion, nepotism and fraud with corruption, but the problem is that this association is ambiguous. (Jos09: 19) For example, it does not necessarily follow from the fact that if person X bribes someone, person X is also corrupt. Likewise nepotic practices are not necessarily considered corrupt. Same applies to extortion and fraud. Conversely, it is not necessary that all forms of corruption take one of the preceding forms. Corruption may also have to do with commissioning, rewarding, influencing, etc. In short we can say that the four terms are neither sufficient nor necessary elements of corruption (i.e. we do not have a logical equivalence between them.) However, these elements certainly have their usefulness. In the first instance we note nepotism, bribery or such, and only in the second instance we speculate on whether or not it is corruption. In what follows we try to setup a normative framework for such speculation. And how exactly do we do that?

The method of analysis (Jos09: 22)

In a nutshell this is how we do it: We first look at the widespread corruption literature and the use of concept corruption in different contexts, namely the economic, legal, socio-cultural, managerial, political, public and moral. Accordingly, through thought experiments we distill a number of key elements. Them being: perversion, the institution, the corruptor and morality. Then we do the inverse: We try to underpin these key elements in the existing corroborated theories to get, in addition to the descriptive component, also a normative element. This will give us a conceptualization of corruption that can be used as an analytical instrument. By conceptualization we mean the exclusive and sufficient conditions which are both non-circular and informative. So let us start with the first element (to be continued…).

References

Bardhan, Pranab (1997). ‘Corruption and Development: A Review of Issues’, in Journal of Economic Literature, Vol. 35, Nr. 3, p1320-1346

Caiden, E. Gerald (1977). ‘Administrative Corruption’ in Public Administration Review, Vol. 37, Nr. 3, p301-309
———- (1981). ‘Public maladministration and bureaucratic corruption’ in Hong Kong Journal of Public Administration, Vol. 3, Nr. 1, p56-71

Gert, Bernard (2008). ‘The Definition of Morality’ in Stanford Encyclopedia of Philosophy

Jos09: http://davor.no-ip.com:1983/Philosophy/Papers/Master/Dissertation/Davor,%20HERZIENE%20EDITIE,%20Een%20filosofische%20analyse%20van%20het%20corruptiefenomeen,%202009,%20v1.2.pdf

Lambsdorff, Johann Graf (2006). ‘Causes and consequences of corruption: What do we know from a cross-section of countries’ in Susan Rose-Ackerman (ed.), International handbook on the economics of corruption (Cheltenham, Edward Elgar), p3-51

Mauss, Marcel (2002). The Gift, trans. Mary Douglas (London, Routledge) [Oorspronkelijke uitgave (1950): Essai sur le don]

Miller, Seumas (2001). Social Action: A Teleological Account (Cambridge, Cambridge university press)
———- e.a. (2005a). Corruption and Anti-Corruption: A Study in Applied Philosophy (New Jersey, Prentice Hall)
———- (2005b). ‘Corruption’, Stanford Encyclopedia of Philosophy
———- (2007a). ‘Social Institutions’ in Stanford Encyclopedia of Philosophy
———- (2007b). ‘Corruption, institutions and transcultural interaction’ in Helen James (ed.), Civil society, religion and global governance (London, Routledge), p130-146

Moody-Stuart, George (1996) “The Good Business Guide to Bribery: Grand Corruption in Third World Development” in Uganda International Conference on Good Governance in Africa (Mweya Lodge: The Inspectorate of Government, Government of Uganda)

Moss, Nicholas (1997). “Who Bribes Wins” in The European, 11 December 1997.

Searle, John R. (1995). The Construction of Social Reality (London, Allen Lane The penguin press)
———- (2005). ‘What is an institution?’ in Journal of Institutional Economics, Vol. 1, Nr. 1, p1-22

Smith, Barry & John Searle (2003). ‘An Illuminating Exchange: The Construction of Social Reality’ in American Journal of Economics and Sociology, Vol. 62, Nr. 1, p285-309

Thompson, Dennis F. (1995). Ethics in Congress: from individual to institutional corruption (Washington D.C., Brookings Institution)

Verhezen, Peter (2005). Gifts and Bribes: An Essay on the Limits of Reciprocity (Leuven, K.U.Leuven Hoger instituut voor wijsbegeerte)

Wabanhu, Emanuel (2008). Confronting Corporate Corruption: A Virtue Ethics Approach (Leuven, K.U.Leuven Faculteit Godgeleerdheid)

« Newer Posts

Powered by WordPress