hamstergene

Eugene's blog

Hashtags in OS X Console App

| Comments

Just discovered a brilliant feature in OS X Console app: hashtags. A little button in the lower left of the window opens a panel that allows you to filter messages by process name or by “tags”, where the latter stand for simple hashtags like those in Twitter.

Ticking checkboxes on hashtags will restrict display to messages containing either of them:

Have each log message tagged with something like subsystem name or importance, and you will be able to quickly filter output by any of those aspects.

Here is the code that produced the messages above:

1
2
3
4
NSLog(@"Starting. #debug");
NSLog(@"Database initialized. #debug #database");
NSLog(@"Fetching data. #database");
NSLog(@"Quitting. #debug");

Manipulating OS X Login Items From Command Line

| Comments

I will leave this post as a reference for those who need their installer postflight scripts (and uninstallers) to manipulate login items in OS X.

Add login item

osascript -e 'tell application "System Events" to make login item at end with properties {path:"/path/to/itemname.app", hidden:true, name:"Customized Name"}'

The name property can be omitted.

The hidden property is useful for applications that do not have LSUIElement set, it causes them to start with all windows hidden (what Cmd+H shortcut does). Please be good to users and set it to true if you are adding non-LSUIElement app into login items.

NOTE: If path is symlink, OS X will resolve it, and you will not be able to delete the item later by that path. You can use name property to locate the item.

Delete login item

By path:

osascript -e 'tell application "System Events" to delete every login item whose path is "/path/to/itemname.app"'

By name:

osascript -e 'tell application "System Events" to delete every login item whose name is "Customized Name"'

The every login item may be changed to first login item or last login item if you are afraid of deleting too much.

Get list of all login items

osascript -e 'tell application "System Events" to get every login item'

Add whose property is ... clause to narrow down the search.

Prevent Mac Sleep When `make` Is Running

| Comments

OS X 10.8 “Mountain Lion” now includes a nice command /usr/bin/caffeinate which will prevent system from going to sleep while a program is running.

For example, if one morning you realize the build started yesterday isn't done yet, because the Mac was asleep, you might want to start using this:

~/.profile
1
alias make='caffeinate make'

My Shell Prompt

| Comments

This is my shell prompt. It automatically stretches to fill the width of the window, and uses colors to help the eye to separate commands from their output.

/etc/profile.d/prompt.sh
1
2
3
if [[ "$TERM" == xterm* ]]; then
    export PS1='\[\e[0;36m\n`/usr/bin/printf %${COLUMNS}s "+jobs:\j+    +\l+" | /usr/bin/tr " +" "- "`\r\u@\H:\[\e[0;32m\]\w\[ \]\n\[\e[1;33m\]  \$ \[\e[0m\]'
fi

C# Variable Arguments Flaw

| Comments

I've come across a corner case in C# syntax when variable arguments do not work as you'd intuitively expect:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Problem
{
    static void foo(params object[] ps)
    {
        System.Console.WriteLine("got {0} parameters", ps.Length);
    }

    public static void Main()
    {
        foo(null, null, null, null);
        foo(null, null, null);
        foo(null, null);
        foo(null); // <-------------- CRASH?!
        foo();
    }
}

When type of the only argument matches the type of arguments array, the parser treats it as an attempt to pass precomposed arguments array.

What they should do is to always treat one argument as one argument (logically), and require params modifier whenever the programmer wants to pass a precomposed array of arguments:

1
2
foo(null); // would pass one parameter: ps.Length == 1
foo(params null); // would pass the array: ps == null

That would fit very nice given ref and out already work this way.

Python uses exactly this approach (it does a lot of things right way, that's why I love it):

1
2
foo(args) # always treats args as one variable argument
foo(*args) # always treats args as array of variable arguments

How to Actually Fix FOV in Mass Effect

| Comments

Short story: the viewing angle (FOV) in Mass Effect games is too small, PC players are upset, but developers never cared.

Here is how to fix it in each of three Mass Effect games.

This article is how to actually fix it.

What is widely reposted between forums as FOV fix (by binding several FOV commands to keypad) is a bad solution. That command is a global override; each game mode requires a different FOV but that command forces the same one on them all, consequently messing those which are not designed for different FOV (like conversations and cutscenes). That is why they also need to bind a key to “FOV 0″ to temporarily turn off their “fix” every time a cutscene appears. When a cutscene ends, they have to press a key again; and so the player has frequently re-fix during play.

The fix in this article changes FOV permanently and without breaking anything.

Mass Effect 3

Note: you might be banned from multiplayer for changing Coalesced.bin.

  1. Use Gibbed Mass Effect 3 Coalesced.bin tool to unpack Coalesced.bin into separate .json. files.

  2. Open 06_bioinput.json in text editor and find the sfxgame.sfxgamemodedefault.bindings section.

  3. Append a comma after the last element (the one that binds Tab key), and add a binding for Period key as follows:

     "sfxgame.sfxgamemodedefault": {
      "bindings": [
      "( Name=\"LeftControl\", Command=\"Walking\" )",
     .............................................................
      "( Name=\"Tab\", Command=\"PC_PushToTalk\" )",
      "( Name=\"Period\", Command=\"set SFXGame.SFXCameraMode FOV 100\" )"
      ],
    
  4. If you've been using the bad FOV fix previously, revert SharedAim and RightMouseButton to their original values.

  5. Pack .json files back into new Coalesced.bin and replace the old one.

  6. See the end of this article about how to use it (hint: press Period . key).

Save a copy — in case game auto-update rewrites the file back to original one.

Mass Effect 2

  1. Get Notepad++ editor. Notepad, Wordpad, Word will not work, they will corrupt the file.

  2. Save a backup of MassEffect2\BioGame\Config\PC\Cooked\Coalesced.ini. Do it, because if you accidentally screw it up, the game will stop working.

  3. Open Coalesced.ini with Notepad++ and find [SFXGame.SFXGameModeDefault] section.

  4. Add binding for the Period key somewhere in that section:

     [SFXGame.SFXGameModeDefault]
     InputDelayStormExit=0.23
     InputDelayTightAimExit=0.1
     RadarMapDisplayTime=1.0
     Bindings=( Name="LeftControl", Command="Walking" )
     ......................................................................
     Bindings=( Name="LeftShift", Command="PC_EnterCommandMenu" )
     Bindings=( Name="Period", Command="set SFXGame.SFXCameraMode FOV 100" )
    
  5. (Optional) Also fix mouse acceleration. You'd be surprised how better will the aiming be. Search for these values in the file and make sure they are false:

     bEnableMouseSmoothing=false
     bUseMouseDampening=false
    

    That will require to lower sensitivity somewhat. I'm using this value:

     MouseSensitivity=0.15
    
  6. If you've been using the bad FOV fix previously, revert SharedAim and RightMouseButton to their original values.

  7. Download ME2IniFixer into the same folder and run it to fix the file. If the game started crashing on start, it means you have used a bad text editor, or did not apply ME2IniFixer. Restore Coalesced.ini from backup and retry.

  8. See the end of this article about how to use it (hint: press Period . key).

Save a copy of Coalesced.ini — in case game auto-update rewrites the file back to original one.

Mass Effect 1

For some reason I never wanted to fix FOV in ME1, probably because big camera distance kind of compensates low FOV. But people asked so here it is.

  1. Open Documents\BioWare\Mass Effect\Config\BIOInput.ini with any text editor.

  2. Locate [BIOC_Base.BioPlayerInput] section and add the Period binding into it:

     [BIOC_Base.BioPlayerInput]
     Bindings=(Name="Period",Command="set BioCameraBehaviorFollow CAMERA_FOV 100 | set BioCameraBehaviorZoom CAMERA_FOV 40")
    
  3. See the next chapter about how to use it (hint: press Period . key).

How to use it

Get to a stage when your Shepard can run around, and hit Period . key. You only need to do it once, then it works until you exit the game.

This fix sets FOV to 100. You can try other values, the good ones are in the range 80..120.

Theoretically the Unreal engine allows to set object properties on load using a config file and then no key binding would be needed. However it does not work with Mass Effect games. Probably because developers rewrite camera's FOV with the hardcoded value 75 after the config has been read.

Random Access in Strings Is a Myth

| Comments

Whenever a discussion of Unicode encodings comes up, someone eventually claims that UTF-32 has an advantage of random character access and character-by-character manipulation.

Guys, there is no such thing as random access to characters or character-by-character manipulation in real-life Unicode text.

UTF-32 gives random access to code points, which is entirely different thing than characters. Here are things that you might think are easier in UTF-32 than in UTF-8, but in fact they are not:

  • Manipulating case. You can not take a char at str[i], change it's case and put it back into str[i]. Some code points capitalize to several ones (the German letter ß is capitalized as "SS"; some ligatures like ff or fi do not have uppercase and become FF anf FI). The Greek letter Σ has two different lowercase forms: "ς" and "σ" depending on context.

  • Counting characters. Several code points may produce only one character (diacritics, devanagari scripts), and one code point should be treated as two (ligatures). One string can have two times more code points but be shorter than another. Unicode is ultimately variable-length thing.

  • Drawing or interaction. You can not draw code points individually for the same reasons. Mouse clicks on a displayed glyph may pick a range of code points, not just one index. Advancing text cursor in response to right arrow key is much more complicated than incrementing a position number.

  • Searching. Searching for even an ASCII character like 'e' by looking for its code point may falsely succeed when it's preceeded with a diacritic. And it will fail to find 'f' when it's composed into a ligature 'fl'.

  • Comparison. The only comparison you can do by looking at individually accessed code points is equivalent to memcmp. For example, in many lanaguages users want characters with diacritics to match precomposed equivalents.

  • Ordering and sorting. Even “plain” U.S. English text that you would hope to be restricted to ASCII will contain fancy characters (think Beyoncé) and therefore comparing code points will not give you proper alphabetic ordering.

The random access to code points, which makes UTF-8 and UTF-16 different from UTF-32, is rarely (if ever) useful. The random access to characters does not exist. Additionally, UTF-16 and UTF-32 have the disadvantages of wasted memory and endianess conversions.

I believe the only reason wchars are still alive are that Windows NT, Java, and the ICU library made the wrong call of picking UCS-2 once, and now they are stuck with backward compatibility. Thinking more of it, today a freshly designed system should have:

  • no [] operator for objects of String in the first place
  • String as a thin wrapper over u8/u16/u32 array to be able to take over any data without re-encoding
  • UTF-8 as the default choice

How to Install Xcode 3 on Mountain Lion

| Comments

Unlike with Mac OS X Lion, installing Xcode 3 on OS X Mountain Lion is not problem-free: the kernel extensions render the system unbootable and you will have to repair it. Also, Interface Builder plugins from iOS platform won't load, so you can't use iOS SDK with Xcode 3 anymore.

  1. Make sure you know how to boot into single-user mode (hit Cmd+S on boot).

  2. Save a repair script somewhere:

    /Users/my-user-name/repair-script
    1
    2
    3
    4
    
    fsck -fy
    mount -uw /
    rm -rf /System/Library/Extensions/AppleProfileFamily.kext
    rm -rf /System/Library/Extensions/CHUD*.kext
    

  3. If Xcode 3 is on a DMG, mount it.

  4. Open Terminal and cd to whereever the installation package is.

    1
    2
    3
    4
    5
    
    $ cd "/Volumes/Xcode and iOS SDK"
    $ ls -1
    About Xcode and iOS SDK.pdf
    Packages
    Xcode and iOS SDK.mpkg
    

  5. Run the installation package like this:

    1
    
    $ COMMAND_LINE_INSTALL=1 open "Xcode and iOS SDK.mpkg"
    

  6. Uncheck iOS SDK option, or the Interface Builder will not be able to start.

  7. You get kernel panic and your system won't boot anymore. Hooray. Turn the power off.

  8. Turn the power back on and hit Cmd+S once gray screen appears, then run the repair script:

    1
    2
    
    # . /Users/my-user-name/repair-script
    # exit
    

Done.

How to Install Xcode 3 on Lion

| Comments

Note: for OS X Mountain Lion, see How to install Xcode 3 on Mountain Lion.

  1. If Xcode 3 is on a DMG, mount it.

  2. Open Terminal and cd to whereever the installation package is.

    1
    2
    3
    4
    5
    
    $ cd "/Volumes/Xcode and iOS SDK"
    $ ls -1
    About Xcode and iOS SDK.pdf
    Packages
    Xcode and iOS SDK.mpkg
    

  3. Open the installation package like this:

    1
    
    $ COMMAND_LINE_INSTALL=1 open "Xcode and iOS SDK.mpkg"
    

  4. Even though the installer ends with “Install failed” message, everything is installed and works properly.

It works because the installation package does this check for whatever reason:

Xcode and iOS SDK.mpkg/Contents/iPhoneSDKSL.dist
1
2
3
4
5
6
7
8
9
10
function isDevToolsCompatible()
{
    if ( system.env.COMMAND_LINE_INSTALL == 1 ) { return true; }
    if( system.compareVersions(my.target.systemVersion.ProductVersion, '10.6.6') >= 0
        && system.compareVersions(my.target.systemVersion.ProductVersion, '10.7') < 0 ) {

            return true;
         }
    return false;
}

Note how they check for == 1 instead of != 0. Not good!

Hello, Octopress!

| Comments

So I finally had time to move for Octopress. Hope it will be better than anything before. Using Vim to edit posts in Markdown? Source code highlighting? Git deployment? No SQL? Transparent guts? Hell, yeah.