To create new wiki account, please join us on #znc at Libera.Chat and ask admins to create a wiki account for you. You can say thanks to spambots for this inconvenience.

Timestamps and Talk:Ideas: Difference between pages

From ZNC
(Difference between pages)
Jump to navigation Jump to search
>Gry
→‎WeeChat: new section
 
>Jpnurmi
m fix typo
 
Line 1: Line 1:
== Usage ==
== Uli's complaints (TODO: Better headline) ==
If you want real timestamps you should use these settings for your user:


TimestampFormat = [%H:%M:%S]
* The big rename (ZFoo): I never saw a project were this was a good idea. Of course I won't stop anyone to do this, but I won't encourage anyone either.
AppendTimestamp = false
** There's the initial hurdle, but in the end module developers will be happier with a beautiful and consistent API to develop with. [[User:Jpnurmi|J-P Nurmi]] ([[User talk:Jpnurmi|talk]]) 17:41, 6 March 2014 (CET)
PrependTimestamp = true
* Semantic versions: So the only difference to right now is that we get another .0 at the end of the version number? ZNC had a grand total of two bug fix releases in its history (I think) and those were for CVEs...
 
** Release early, release often. I'm sure your customers would appreciate. ;) Branching and semantic versioning in a nutshell; master branch for new features, X.Y branch for bug fixes (periodically merged to master). Bugfix releases tagged from X.Y branch, master forms the next X.Y.0 release (and eventually the next X.0). [[User:Jpnurmi|J-P Nurmi]] ([[User talk:Jpnurmi|talk]]) 17:41, 6 March 2014 (CET)
It currently supports Channel, Query, Wallops, Notice and Servernotices
* Binary compatibility: Just not possible. Basically every release would be a major release. Feel free to convince me otherwise, but "binary compatible" and "C++" mostly means "don't change anything".
 
** My suggestion is to keep it simple and provide binary compatibility only for bugfix releases. New feature development happens in master, not in the X.Y branch where bugfix releases come from. Even for master, my suggestion would be to keep old deprecated methods and types around instead of breaking source compatibility. [[User:Jpnurmi|J-P Nurmi]] ([[User talk:Jpnurmi|talk]]) 17:41, 6 March 2014 (CET)
== Format ==
* Message type: Since we don't promise API stability anyway, this can happen outside of ZNCv2 (aka "can be done right now, too")
 
** I'd like to kindly ask you to reconsider. ZNC has such a nice bunch of official and unofficial modules, it would be a pity to break them like that. Any module written for the 1.x series would ideally work with later 1.x releases. Write such intrusive ideas down or as TODO comments in the code. Once you have a reasonable set of changes in mind, start preparing for the next major release. Module developers know that something needs to be updated in order to support the new major version. If the changes are beneficial, module developers will surely follow. [[User:Jpnurmi|J-P Nurmi]] ([[User talk:Jpnurmi|talk]]) 17:41, 6 March 2014 (CET)
strftime arguments can be used for the timestamps, more details and arguments can be found at opengroup.org[http://opengroup.org/onlinepubs/007908799/xsh/strftime.html].
* Radically reduce the amount of module hooks: "Radically" means "4"? Also, what's the point? Most modules will check for the type of message as first thing anyway and e.g. immediately return for queries. So this just makes modules more complicated
 
** Sorry, I'm not familiar enough with the CModule API to understand which hook does what, but my first impression was - please make it simpler. :) Perhaps it would be easier to understand if the module API was structured after the categories? Furthermore, ideally the interface for ZNC app wouldn't be exposed for module developers. [[User:Jpnurmi|J-P Nurmi]] ([[User talk:Jpnurmi|talk]]) 17:41, 6 March 2014 (CET)
  %a the locale's abbreviated weekday name.  
* Project structure: Are you saying that modules must not link against symbols from the znc binary? We already have a libznc.dll for cygwin. It contains everything but main(). There just is no sane way to split things up currently, but feel free to proof me wrong.
  %A - the locale's full weekday name.
** The library is the part that we would retain backwards compatibility for. On the app side you may do anything you want since that wouldn't break modules. Modules shouldn't have access to application specific code. [[User:Jpnurmi|J-P Nurmi]] ([[User talk:Jpnurmi|talk]]) 17:41, 6 March 2014 (CET)
  %b - the locale's abbreviated month name.  
* Coding style: Hahaha. No.
  %B - the locale's full month name.
** Are you laughing at all the points or some specific of them? Regarding passing certain types always by reference or as pointers... alongside good naming, consistency is one of the most important factors for easy to memorize APIs. [[User:Jpnurmi|J-P Nurmi]] ([[User talk:Jpnurmi|talk]]) 17:41, 6 March 2014 (CET)
  %c - the locale's appropriate date and time representation.
[[User:Psychon|Psychon]] ([[User talk:Psychon|talk]]) 16:37, 6 March 2014 (CET)
  %C - the century number (the year divided by 100 and truncated to an integer) as a decimal number [00-99].
  %d - the day of the month as a decimal number [01,31].
  %D - same as %m/%d/%y.
  %e - the day of the month as a decimal number [1,31]; a single digit is preceded by a space.
  %h - same as %b.
  %H - the hour (24-hour clock) as a decimal number [00,23].
  %I - the hour (12-hour clock) as a decimal number [01,12].
  %j - the day of the year as a decimal number [001,366].
  %m - the month as a decimal number [01,12].
  %M - the minute as a decimal number [00,59].
  %n - a newline character.
  %p - the locale's equivalent of either a.m. or p.m.
  %r - the time in a.m. and p.m. notation; in the POSIX locale this is equivalent to %I:%M:%S %p.
  %R - the time in 24 hour notation (%H:%M).
  %S - the second as a decimal number [00,61].
  %t - a tab character.
  %T - the time (%H:%M:%S).
  %u - the weekday as a decimal number [1,7], with 1 representing Monday.  
  %U - the week number of the year (Sunday as the first day of the week) as a decimal number [00,53].
  %V - the week number of the year (Monday as the first day of the week) as a decimal number [01,53]. If the week containing 1 January has four or more
      days in the new year, then it is considered week 1. Otherwise, it is the last week of the previous year, and the next week is week 1.  
  %w - the weekday as a decimal number [0,6], with 0 representing Sunday.  
  %W - the week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday
      are considered to be in week 0.
  %x - the locale's appropriate date representation.
  %X - the locale's appropriate time representation.
  %y - the year without century as a decimal number [00,99].  
  %Y - the year with century as a decimal number.
  %Z - the timezone name or abbreviation, or by no bytes if no timezone information exists.
  %% - %.
 
== Scripts ==
=== KVIrc ===
This script '''requires''' these settings for your user:
 
TimestampFormat = {%H:%M:%S}
AppendTimestamp = false
PrependTimestamp = true
 
and here is it:
 
event(OnWallops,zncid)
{
%timefront = $str.lefttofirst($3,$char(32))
%timeappend = $str.rightfromlast($3,$char(32))
if($str.matchnocase(\{**\:**\:**\},%timefront))
{
%time = %timefront
%msg = $str.rightfromfirst($3,\})
#echo %timefront front
} else {
if($str.matchnocase(\{**\:**\:**\},%timeappend))
{
%time = %timeappend
%msg = $str.lefttofirst($3,\{)
#echo %timeappend append
}
}
if($str.matchnocase(\{**\:**\:**\},%time))
{
echo -n -i=$msgtype(Wallops) $k($option(uinttimestampforeground))%time$k WALLOPS von $0 \[$1\@$2\] $str.rightfromfirst($3,\})
}
halt
}
event(OnServerNotice,zncid)
{
%chan = $window.list(channel,$ic)
%con = $window.list(console,$ic)
%x = 0
while(%x < %chan[]#)
{
if($window.hasUserFocus(%chan[%x]))
{
%outchan = %con
#echo -w=%outchan $0 $3 %outchan
break;
} else {
%outchan = %con
}
if(%x < %chan[]#)
{
%x = $(%x + 1)
} else {
break;
}
}
%timefront = $str.lefttofirst($1,$char(32))
%timeappend = $str.rightfromlast($1,$char(32))
if($str.matchnocase(\{**\:**\:**\},%timefront))
{
%time = %timefront
%msg = $str.rightfromfirst($1,\})
#echo %timefront front
} else {
if($str.matchnocase(\{**\:**\:**\},%timeappend))
{
%time = %timeappend
%msg = $str.lefttofirst($1,\{)
#echo %timeappend append
}
}
if($str.matchnocase(\{**\:**\:**\},%time))
{
echo -n  -w=%con -i=$msgtype(ServerNotice) $k($option(uinttimestampforeground))%time$k [$0] $str.rightfromfirst($1,\})
halt
}
}
event(OnQueryNotice,zncid)
{
%chan = $window.list(channel,$ic)
%con = $window.list(console,$ic)
%x = 0
while(%x < %chan[]#)
{
if($window.hasUserFocus(%chan[%x]))
{
%outchan = %chan[%x]
#echo -w=%outchan $0 $3 %outchan
break;
} else {
%outchan = %con
}
if(%x < %chan[]#)
{
%x = $(%x + 1)
} else {
break;
}
}
%timefront = $str.lefttofirst($3,$char(32))
%timeappend = $str.rightfromlast($3,$char(32))
if($str.matchnocase(\{**\:**\:**\},%timefront))
{
%time = %timefront
%msg = $str.rightfromfirst($3,\})
#echo %timefront front
} else {
if($str.matchnocase(\{**\:**\:**\},%timeappend))
{
%time = %timeappend
%msg = $str.lefttofirst($3,\{)
#echo %timeappend append
}
}
if($str.matchnocase(\{**\:**\:**\},%time))
{
echo -n  -w=%outchan -i=$msgtype(QueryNotice) $k($option(uinttimestampforeground))%time$k *$0* $str.rightfromfirst($3,\})
halt
}
}
event(OnQueryMessage,zncid)
{
%timefront = $str.lefttofirst($3,$char(32))
%timeappend = $str.rightfromlast($3,$char(32))
if($str.matchnocase(\{**\:**\:**\},%timefront))
{
%time = %timefront
%msg = $str.rightfromfirst($3,\})
#echo %timefront front
} else {
if($str.matchnocase(\{**\:**\:**\},%timeappend))
{
%time = %timeappend
%msg = $str.lefttofirst($3,\{)
#echo %timeappend append
}
}
if($str.matchnocase(\{**\:**\:**\},%time))
{
echo -n -i=$msgtype(ChannelPrivateMessage) $k($option(uinttimestampforeground))%time$k $option(stringextendedprivmsgprefix)%status$0$option(stringextendedprivmsgpostfix)%msg
halt
}
}
event(OnChannelMessage,zncid)
{
if(%Win{$window} > 0)
{
%timefront = $str.lefttofirst($3,$char(32))
%timeappend = $str.rightfromlast($3,$char(32))
if(($option(boolshowchanneluserflaginprivmsgview)) && ($chan.ison($0)) && ($chan.isvoice($0)))%status = $chan.getflag($0)
if($str.matchnocase(\{**\:**\:**\},%timefront))
{
%time = %timefront
%msg = $str.rightfromfirst($3,\})
#echo %timefront front
} else {
if($str.matchnocase(\{**\:**\:**\},%timeappend))
{
%time = %timeappend
%msg = $str.lefttofirst($3,\{)
#echo %timeappend append
}
}
if($str.matchnocase(\{**\:**\:**\},%time))
{
                if($str.containsnocase(%msg,$me))
                          {
          echo -n -i=$msgtype(Highlight) $k($option(uinttimestampforeground))%time$k $option(stringextendedprivmsgprefix)%status$0$option(stringextendedprivmsgpostfix) %msg
          halt
                          }else{
                          echo -n -i=$msgtype(ChannelPrivateMessage) $k($option(uinttimestampforeground))%time$k $option(stringextendedprivmsgprefix)%status$0$option(stringextendedprivmsgpostfix) %msg
          halt
                          }
}
}
if($0 == "***")
{
if($3 == "Buffer Playback...")
{
%Win{$window} = 1
}
if($3 == "Playback Complete.")
{
%Win{$window} = 0
}
}
}
event(OnAction,zncid)
{
if(%Win{$window}  > 0)
{
%timefront = $str.lefttofirst($4,$char(32))
%timeappend = $str.rightfromlast($4,$char(32))
if($str.matchnocase(\{**\:**\:**\},%timefront))
{
%time = %timefront
%msg = $str.rightfromfirst($4,\})
#echo %timefront front
} else {
if($str.matchnocase(\{**\:**\:**\},%timeappend))
{
%time = %timeappend
%msg = $str.lefttofirst($4,\{)
#echo %timeappend append
}
}
if($chan.ison($0))%status = $chan.getflag($0)
if($str.matchnocase(\{**\:**\:**\},%time))
{
#%time = $date([H:M:S])
echo -n -i=$msgtype(Action) $k($option(uinttimestampforeground))%time$k $0 %msg
#echo $0 $3
halt
}
}
}
 
=== mIRC ===
This script '''requires''' these settings for your user:
 
TimestampFormat = [%H:%M:%S]
AppendTimestamp = false
PrependTimestamp = true
 
Otherwise you have to adjust the regex pattern in the script that grabs the timestamp.
 
It handles
* Channel messages
* Savebuff output
* Channel notices
* Channel actions
 
==== Configuration (optional) ====
If lines are too long to fit the window width they are wrapped so that the wrapped lines will line up after the nick. To disable that behavior, set <tt>%INDENT_LINES</tt> to <tt>$false</tt>.
 
Nicks will be prefixed with their mode identifier (so "nick" becomes "@nick" for example). To disable this behavior, set <tt>%PREFIX_NICKS</tt> to <tt>$false</tt>.
 
The beginning and end of buffer playback are marked with the default line separator by default. This can be changed to <tt>NORMAL</tt> to display the usual <tt>*** Buffer Playback.</tt> and <tt>*** Playback Complete</tt> messages or to <tt>NONE</tt> to not show any status message at all.
 
If you run into problems like all messages being displayed twice because of other <tt>ON TEXT</tt> processing scripts, try to set <tt>%EXTERNAL_RENDERER</tt> to <tt>$false</tt>.
 
The script also allows the use of spaces.dll to preserve consecutive spaces. To enable it just put <tt>spaces.dll</tt> (http://www.xise.nl/mirc/) into your <tt>Application Data</tt> folder and set <tt>%USE_SPACES_DLL</tt> to <tt>$true</tt>.
 
==== Script ====
Information about loading mIRC scripts can be found [http://chanops.org/faqs/clients/how-to-load-an-mirc-script-into-your-main-mirc-program.html here].
alias -l config {
  ; Mandatory settings
  var %TIMESTAMP_PATTERN = ^\[(\d\d:\d\d:\d\d)\].*$
  var %PLAYBACK_BEGIN    = Buffer Playback...
  var %PLAYBACK_END      = Playback Complete.
  var %VARIABLE_PREFIX  = gbuffer
  ; Optional settings
  ; Indent wrapped lines
  var %INDENT_LINES = $true
  ; Add the mode prefix to the nick (if possible)
  var %PREFIX_NICKS = $true
  ; Are there other ON TEXT processors in place?
  var %EXTERNAL_RENDERER = $false
  ; Possible values are NORMAL/LINESEP/NONE
  var %STATUS_DISPLAY = LINESEP
  ; Make use of space-preserving spaces.dll
  var %USE_SPACES_DLL = $true
  return $eval( $+( %, $1 ), 2 )
}
alias -l makeNick {
  var %nick = $nick( $1, $2 ).pnick
  if ( ( 0 == $len( %nick ) ) || ( $true != $config( PREFIX_NICKS ) ) ) %nick = $2
  return %nick
}
alias -l handleMessage {
  var %chan = $1
  var %nick = $2
  var %color = $3
  var %pattern = $4
  var %text = $5
  var %pnick = $makeNick( %chan, %nick )
  ; Buffered input
  if ( $true == $eval( $+( %, $config( VARIABLE_PREFIX ), ., $cid, ., %chan, ., playback ), 2 ) ) {
    noop $regex( %text, $config( TIMESTAMP_PATTERN ) ) )
    var %timestamp = $regml( 1 )
    var %params
    if ( $config( INDENT_LINES ) ) %params = $+( i, $calc( $len( %timestamp ) + $len( %pnick ) + 4 ) )
    if ( %nick != $me ) %params = $+( %params, lmr )
    if ( 0 != $len( %params ) ) %params = $+( -, %params )
    if ( %nick == $me ) {
      if ( $true == $config( USE_SPACES_DLL ) ) {
        var %result
        noop $regex( %text, ^.*? (.*)$ )
        noop $regsub( %pattern, &TEXT&, $regml( 1 ), %result )
        noop $regsub( %result , &NICK&, %pnick, %result )
        noop $dll( spaces.dll, echo, $color( own  ) %params $chan %timestamp %result )
      }
      else {
        echo $color( own ) %params $chan %timestamp $replacecs( %pattern, &NICK&, %pnick, &TEXT&, $gettok( %text, 2-, 32 ) )
      }
    }
    else {
      if ( $true == $config( USE_SPACES_DLL ) ) {
        var %result
        noop $regex( %text, ^.*? (.*)$ )
        noop $regsub( $regml( 1 ), /\\/g, \\\\, %result )
        noop $regsub( %pattern, &TEXT&, %result, %result )
        noop $regsub( %result , &NICK&, %pnick, %result )
        noop $dll( spaces.dll, echo, $color( %color ) %params $chan %timestamp %result )
      }
      else {
        echo $color( %color ) %params $chan %timestamp $replacecs( %pattern, &NICK&, %pnick, &TEXT&, $gettok( %text, 2-, 32 ) )
      }
    }
  }
  else {
    ; Current events (optional)
    if ( $true == $config( EXTERNAL_RENDERER ) ) return $false
    if ( $true == $config( USE_SPACES_DLL ) ) {
      var %result
      noop $regsub( %pattern, &NICK&, %pnick, %result )
      noop $regsub( %text, /\\/g, \\\\, %text )
      noop $regsub( %result, &TEXT&, %text, %result )
      noop $dll( spaces.dll, echo, $color( %color ) $+( -i, $calc( $len( $timestamp ) + $len( %pnick ) + 5 ), lmrt ) $chan %result )
    }
    else {
      echo $color( %color ) $+( -i, $calc( $len( $timestamp ) + $len( %pnick ) + 4 ), lmrt ) $chan $replacecs( %pattern, &NICK&, %pnick, &TEXT&, %text )
    }
  }
  return $true
}
on ^*:text:*:#:{
  ; Handle savebuff output
  if ( $nick == *savebuff ) {
    var %nick = $gettok( $2, 1, $asc( ! ) )
    var %timestamp = $asctime( $1, $timestampfmt )
    if ( $3 == MODE )    echo $color( mode ) $chan %timestamp * %nick sets mode: $4-
    elseif ( $3 == JOIN ) echo $color( join ) $chan %timestamp * %nick ( $+ $gettok( $2, 2, $asc( ! ) ) $+ ) has joined $chan
    elseif ( $3 == QUIT ) echo $color( quit ) $chan %timestamp * %nick ( $+ $gettok( $2, 2, $asc( ! ) ) $+ ) Quit ( $+ $4- $+ )
    elseif ( $3 == PART ) echo $color( part ) $chan %timestamp * %nick ( $+ $gettok( $2, 2, $asc( ! ) ) $+ ) has left $chan
    elseif ( $3 == NICK ) echo $color( nick ) $chan %timestamp * %nick is now known as $4
    elseif ( $3 == KICK ) echo $color( kick ) $chan %timestamp * $2 was kicked by $gettok( $4, 1, $asc( ! ) ) ( $+ $5- $+ )
    else                  echo $color( erro ) $chan *** UNHANDLED LINE < $+ $1- $+ >
  }
  ; Handle playback state notifications
  elseif ( $nick == *** ) {
    if ( $1- == $config( PLAYBACK_BEGIN ) ) {
      set -e $+( %, $config( VARIABLE_PREFIX ), ., $cid, ., $chan, ., playback ) $true
    }
    elseif ( $1- == $config( PLAYBACK_END ) ) {
      unset $eval( $+( %, $config( VARIABLE_PREFIX ), ., $cid, ., $chan, ., playback ), 1 )
    }
    if ( $config( STATUS_DISPLAY ) == NORMAL ) {
      echo $color( notice ) $chan *** $1-
    }
    elseif ( $config( STATUS_DISPLAY ) == LINESEP ) {
      linesep $chan
    }
  }
  ; Handle usual input
  else {
    var %pattern = ^:.*? :(.*)$
    noop $regex( $rawmsg, %pattern )
    if ( $false == $handleMessage( $chan, $nick, normal, <&NICK&> &TEXT&, $regml( 1 ) ) ) return
  }
  halt
}
on ^*:action:*:#:{
  ;noop $dll( spaces.dll, echo, $chan $rawmsg )
  var %pattern = ^:.*? :\x01ACTION (.*)\x01$
  noop $regex( $rawmsg, %pattern )
  if ( $true == $handleMessage( $chan, $nick, action, * &NICK& &TEXT&, $regml( 1 ) ) ) halt
}
on ^*:notice:*:#:{
  ;noop $dll( spaces.dll, echo, $chan $rawmsg )
  var %pattern = ^:.*? :(.*)$
  noop $regex( $rawmsg, %pattern )
  if ( $true == $handleMessage( $chan, $nick, notice, -&NICK&- &TEXT&, $regml( 1 ) ) ) halt
}
 
=== irssi ===
This script '''requires''' these settings for your user:
 
TimestampFormat = [%H:%M:%S]
AppendTimestamp = false
PrependTimestamp = true
 
Otherwise you have to adjust the regex pattern in the script that grabs the timestamp.
 
Download the script from: http://cba.si/stuff/znc_timestamp.pl
 
Put it into ~/.irssi/scripts, then '''/script load znc_timestamp''' .
 
=== WeeChat ===
* [http://www.weechat.org/files/scripts/unofficial/znc-playback.py znc-playback.py]

Revision as of 17:04, 6 March 2014

Uli's complaints (TODO: Better headline)

  • The big rename (ZFoo): I never saw a project were this was a good idea. Of course I won't stop anyone to do this, but I won't encourage anyone either.
    • There's the initial hurdle, but in the end module developers will be happier with a beautiful and consistent API to develop with. J-P Nurmi (talk) 17:41, 6 March 2014 (CET)
  • Semantic versions: So the only difference to right now is that we get another .0 at the end of the version number? ZNC had a grand total of two bug fix releases in its history (I think) and those were for CVEs...
    • Release early, release often. I'm sure your customers would appreciate. ;) Branching and semantic versioning in a nutshell; master branch for new features, X.Y branch for bug fixes (periodically merged to master). Bugfix releases tagged from X.Y branch, master forms the next X.Y.0 release (and eventually the next X.0). J-P Nurmi (talk) 17:41, 6 March 2014 (CET)
  • Binary compatibility: Just not possible. Basically every release would be a major release. Feel free to convince me otherwise, but "binary compatible" and "C++" mostly means "don't change anything".
    • My suggestion is to keep it simple and provide binary compatibility only for bugfix releases. New feature development happens in master, not in the X.Y branch where bugfix releases come from. Even for master, my suggestion would be to keep old deprecated methods and types around instead of breaking source compatibility. J-P Nurmi (talk) 17:41, 6 March 2014 (CET)
  • Message type: Since we don't promise API stability anyway, this can happen outside of ZNCv2 (aka "can be done right now, too")
    • I'd like to kindly ask you to reconsider. ZNC has such a nice bunch of official and unofficial modules, it would be a pity to break them like that. Any module written for the 1.x series would ideally work with later 1.x releases. Write such intrusive ideas down or as TODO comments in the code. Once you have a reasonable set of changes in mind, start preparing for the next major release. Module developers know that something needs to be updated in order to support the new major version. If the changes are beneficial, module developers will surely follow. J-P Nurmi (talk) 17:41, 6 March 2014 (CET)
  • Radically reduce the amount of module hooks: "Radically" means "4"? Also, what's the point? Most modules will check for the type of message as first thing anyway and e.g. immediately return for queries. So this just makes modules more complicated
    • Sorry, I'm not familiar enough with the CModule API to understand which hook does what, but my first impression was - please make it simpler. :) Perhaps it would be easier to understand if the module API was structured after the categories? Furthermore, ideally the interface for ZNC app wouldn't be exposed for module developers. J-P Nurmi (talk) 17:41, 6 March 2014 (CET)
  • Project structure: Are you saying that modules must not link against symbols from the znc binary? We already have a libznc.dll for cygwin. It contains everything but main(). There just is no sane way to split things up currently, but feel free to proof me wrong.
    • The library is the part that we would retain backwards compatibility for. On the app side you may do anything you want since that wouldn't break modules. Modules shouldn't have access to application specific code. J-P Nurmi (talk) 17:41, 6 March 2014 (CET)
  • Coding style: Hahaha. No.
    • Are you laughing at all the points or some specific of them? Regarding passing certain types always by reference or as pointers... alongside good naming, consistency is one of the most important factors for easy to memorize APIs. J-P Nurmi (talk) 17:41, 6 March 2014 (CET)

Psychon (talk) 16:37, 6 March 2014 (CET)