Thursday, December 23, 2010

Kindergarden science - Paper Cogs

Cogs are a corner stone of mechanics. Although they are rather simple to make they tend to have a low tolerance to faults. The key to getting something that works in the end is to measure them as precise as possible at the start.


Stage 0) Adult prep
You can look below to construct the cog pattern from scratch or you can print out 2 patterns and paste it on to the cardboard.

Stage 1) Create some interest
Ask your kid about a clock(one with the cogs showing is best) how it turns and works and show her pictures of the insides. Ask her if she wants to make some cogs.

Stage 2) Gather materials
Get the cardboard with the cog patterns on it. Get scissors tape and a sharp pencil or Japanese chopsticks.

Stage 3) Cut it out.
Cut the cogs out. Don't worry to much about being too precise, just get them to follow the lines. My daughter was able to cut it quite neatly when I showed her to cut straight lines, even despite the cardboard thickness. Also clip the points of the teeth so they are flat (the points are weak and will easily get jammed). Cut a long strip of cardboard as the backing to the cogs. Then the adult should cut 2 cardboard pins(shown on the pattern) from the left over cardboard.

Stage 4) Assemble.
Place the two cogs on the backing board. The teeth should inter-mesh with about 1-2mm of gap between the two cogs. Then with Japanese chopsticks or a sharp pencil punch a hole in the middle of the cog and though the backing board. Push in the cardboard pins and fold them over on the backside and tap them to the backing board.

Stage 5) Test
Spin the cogs and check that they work correctly. Draw arrows to show (and discuss) how the cogs turn around.

What they learn
  • Basics of mechanical devices
  • Basics of rotational dynamics

Appendix
How to construct the Cog pattern from scratch.

0.1) First create a compass. Tape 3 sharpened pencils together in a triangle with of the 2 leads about 5cm apart.
0.2) Get some thick cardboard, thicker is better.
0.3) Draw a circle with the compass.
0.4) Then rule a straight line through the center of the circle, using the edge of the ruler to measure the 90 degrees draw a second line through the center to form a +.
0.5) Where each of lines touch the circle place the compass point and draw a lines marking the circle both above and below. These marks are exactly +/- 60degrees from the line. Once finish you will have marks on the circle at every 30 degree(including the + lines). There should be a total of 8 points marked and 4 points where the lines cut for a total of 12.
0.6) Now take the compass again an draw a circle around to of the neighboring marks. The two new circles will cross at 2 points, 1 the center of you main circle and another point outside of the circle. Draw a straight line through the 2 points where they cross. This forms the 15degree mark on the circle.
0.7) With the ruler place the corner of it on the 15 degree line facing into the main circles middle, and with the sides touching the marks on the outer circle. Trace its edge.
0.8) repeat for other 11 marks.
0.9) repeat for another cog.

Sounds complex but its quite simple to do.

Wednesday, December 22, 2010

Kindergarden science - Shaky leg robot

The Shaky leg robot is a simple device that uses mechanical vibration to draw random lines and patterns.


Stage 1) adult prep
Scavenge a battery container, switch and motor from a broken toy or device. wire them together and check the the switch correctly operates the motor. tape the motor to battery pack so the shaft extends out. tape the switch so is faces in the same direction but on a neighboring face of battery case.

Stage 2) build interest
Discuss robots and what the are with you kid. Ask if she wants to make one.

Stage 3) gather materials.
Get an old box with about 15cm square of thick cardboard.
Get the scissors, tape and 4 crayons


Stage4) build it - child
Cut about a 3 cm line straight in about 3cm fold the edges up and tape the overlapping 3 cms to the next edge. this forms a kind of strong small shoe box top.
tape the motor to the inside of box lid with the drive shaft out.
tape the four crayons/texters to the four box lid corners so they point in the same direction as the motors drive shaft and extend as far as possible.
then tape the weight to the motor with a long piece of tape

Stage 5) turn it on and test - done by child
Stand the entire device on a sheet of paper so the the points of the crayons are touching the paper. and turn it on.

The weight should swing around between the crayon legs causing the whole thing to shake and rotate drawing lines in the paper.

Have your kid change the length of the tape between the weight and motor and crayon leg length and see what happens to the drawing. Ask which is better and why

What they learn
  • basic engineering; prototyping and refinement
  • structure and stability (odd sized legs)
  • the basics of mechanical vibrations what the are and why they exist
Refer: http://www.newscientist.com/article/dn19501-homebrew-technology-meet-new-scientists-junk-robot.html

Saturday, December 18, 2010

Bad system design -- Overspecification of Data.

The key principles behind Architecture and technical drawing rules can and do apply to computer science and programing. One key item is "Over-specification". It is one of the main items that I find in;
  • Poorly written or adhoc designed software
  • In software that has been in long term maintenance without purging rewrites
  • or in software produced by coders under constant(and often pointless) deadlines.

Here is what it is and why its evil.

Consider a Line with a point on it. Here are 2 classes defining it.

struct Good
{
  int length;
  int pointFromLeft;
};

struct Bad
{
  int length;
  int pointFromLeft;
  int pointFromRight;
};

So why is the Bad struct a no-no. Simple!. There is an implicate relationship between the data entries. "length = pointFromLeft + pointFromRight". If something updates the length and forgets to update one of the pointForm entries, then you end up with the data in an invalid state. This will later cause computation errors and finding the cause of the incorrect data is often quite difficult, because the code with will often look legitimate..

Furthermore the problem often isn't so simple to see/fix either. Consider this set of classes defining the same thing.

class GoodLineWithPoint
{
private:
  GoodPoint* point;
  int length;
};

class GoodPoint
}
private:
  int pointFromLeft;
}

class BadLineWithPoint
{
private:
  BadPoint* point;
  int length;
};

class BadPoint
}
private:
  int pointFromLeft;
  int pointFromRight;
}

In this case someone may have added the pointFromRight member so that they can "cache" the result. In reality the parent class GoodLineWithPoint should be the one that is dealt with however a function call might be passing GoodPoint to save the additional pointer deference. And once this is established in an API or lib it becomes quite difficult to fix cleanly.

Svn commit all the readme's that where have modified.

Most of the time I'm working on multiple projects at the same time. This means many svn working directories. And sometimes its essential to commit a similar file across all working dirs. Here is quick commandline to get it done (for README files).

find ./ | grep README | grep -v svn | sed "s/^/svn status /" | sh | sed "s/^M *\(.*\)/svn commit \1 -m 'updating project readme'/"

open office from the command line

You probably want to alias this but sometimes its convenient to boot up open officce from the command line.

openoffice.org3 -writer <filename>

Friday, November 26, 2010

Factory with registerable and configurable units..

One of the most common patterns used in software a factory. The ideal factory has sub units that can register with the main factory using one or more keywords.

The holy grail implementation is the self-registering factory, where the mere definition of the class causes it to register with the Factory. This is not really not really possible in C++ due to the limited RTT typing and introspection of the language. However you can do some 1 liner tricks to get the item to install at startup, such as static/local variables, or an instance function.

Below is a Factory that utilizes its registration to store the keyword, Type and some construction parameters for a factory. Thus allowing repeated of the same type with customized default parameters.

A brief class overview is
Class/TypeDescription
KeyThe description/tag/id for the factory
RegItemBaseThe Factory Registration generic entry
BaseThe Factory output class
RegFactoryThe Factory
RegItemAn item to register with the factory, without any parameters
RegItemParamAn item to register with the factory, without a single parameter
AThe First demo class
BThe Second demo class

#include <iostream>
#include <map>

using namespace std;

/*****************************************************
 *          Factory with registering methods
 *****************************************************/

typedef string Key;

class Base;

class RegItemBase
{
public:
    RegItemBase(Key _key) :
        key(_key)
    {}

    virtual Base* construct()   const = 0;
    virtual void      print()   const = 0;
    virtual const Key keyword() const { return key; }

private:
    Key key;
};
typedef map<Key,RegItemBase*> KeyRegItemMap;

class Base
{
public:
    virtual const RegItemBase* getReg() const = 0;
    virtual const Key keyword() const { return getReg()->keyword(); }
    virtual void      print()   const { cout << keyword() << endl; }
    virtual void      bark()    const { cout << "...." << endl; }
};


class RegFactory
{
public:
    static RegFactory* getInstance() 
    {
        static RegFactory* instance = new RegFactory();
        return instance;
    }

    void add(RegItemBase* item) 
    {
        items[item->keyword()] = item;
    }
    
    Base* construct(Key key) 
    {
        KeyRegItemMap::const_iterator bit = items.find(key);
        if(bit != items.end())
            return bit->second->construct();
        return NULL;
    }
        
    void listAll() 
    {
        cout << "Registered items:"  << endl;

        KeyRegItemMap::const_iterator bit;
        for(bit = items.begin();
            bit != items.end();
            bit++)
        {
            cout << " " << bit->second->keyword() << endl;
        }

        cout << "Registered items DONE"  << endl;
    }

protected:
    RegFactory() {}

private:        
    KeyRegItemMap items;
};


template <class TempType>
class RegItem : public RegItemBase
{
public:
    typedef TempType Type;

    RegItem(const Key _key) :
        RegItemBase(_key)
    {
        cout << "Registering key: " << _key << endl;
        RegFactory::getInstance()->add(this);
    }

    virtual Base* construct()   const { return new Type(); }
    virtual void print()        const { cout << keyword() << endl; }
};

template <class TempType>
class RegItemParam : public RegItemBase
{
public:
    typedef TempType Type;

    RegItemParam(const Key _key, string _param) :
        RegItemBase(_key),
        param(_param)
    {
        cout << "Registering key: " << _key << endl;
        RegFactory::getInstance()->add(this);
    }

    virtual Base* construct()   const { return new Type(param); }
    virtual void print()        const { cout << keyword() << endl; }
private:
    string param;
};

/*****************************************************
 *             Specific Classes to register
 *****************************************************/

class A : public Base
{
public:
    static RegItemBase* reg()
    {
        static RegItemBase* regItem = (RegItemBase*)new RegItem<A>("A");
        return regItem;
    }
    virtual RegItemBase* getReg() const { return A::reg(); }

    virtual void      bark()    const { cout << "ruff" << endl; }
protected:
    friend class RegItem<A>;
    A() {}
};

class B: public Base
{
public:
    static RegItemBase* reg()
    {
        static RegItemBase* regItem  = (RegItemBase*)new RegItemParam<B>("B", "red");
        static RegItemBase* regItem2 = (RegItemBase*)new RegItemParam<B>("C", "green");
        return regItem;
    }
    virtual RegItemBase* getReg() const { return B::reg(); }

    virtual void      bark()    const { cout << "woof " << param << endl; }
protected:
    friend class RegItemParam<B>;
    B(string _param) : param(_param) {}

    string param;
};

int main()
{
    //setup regs...
    A::reg();
    B::reg();

    //list types..
    RegFactory::getInstance()->listAll();

    Base* a = RegFactory::getInstance()->construct("A");
    a->print();
    a->bark();

    Base* b = RegFactory::getInstance()->construct("B");
    b->print();
    b->bark();

    Base* c = RegFactory::getInstance()->construct("C");
    c->print();
    c->bark();
}

http://accu.org/index.php/journals/597

Saturday, November 13, 2010

Adding a syntax higher to your blog

Recently went through the effort of adding syntax highlighting to this blog. Its a worth while and somewhat easy process.. There can be a bit of leg work to up date existing posts but its worth the effort.

  1. Copy the below code;

    <!--SYNTAX HIGHLIGHTER BEGINS-->
    <link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' rel='stylesheet' type='text/css'/>
    <link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeRDark.css' rel='stylesheet' type='text/css'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushBash.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPython.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushRuby.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushVb.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPerl.js' type='text/javascript'/>
    <script language='javascript'>
    SyntaxHighlighter.brushes.Clojure = function()
    {
            // Contributed by Travis Whitton
    
            var funcs = &#39;:arglists :doc :file :line :macro :name :ns :private :tag :test new add-hook alias alter and apply assert class cond conj count def defmacro defn defun defstruct deref do doall dorun doseq dosync eval filter finally find first fn gen-class gensym if import inc keys let list loop map ns or print println quote rand recur reduce ref repeat require rest send seq set setq sort str struct sync take test throw trampoline try type use var vec when while&#39;;
    
            this.regexList = [
                    { regex: new RegExp(&#39;;[^\]]+$&#39;, &#39;gm&#39;),                           css: &#39;comments&#39; },
      { regex: SyntaxHighlighter.regexLib.multiLineDoubleQuotedString, css: &#39;string&#39; },
                    { regex: /\[|\]/g,                                               css: &#39;keyword&#39; },
      { regex: /&#39;[a-z][A-Za-z0-9_]*/g,                                 css: &#39;color1&#39; }, // symbols
      { regex: /:[a-z][A-Za-z0-9_]*/g,                                 css: &#39;color2&#39; }, // keywords
      { regex: new RegExp(this.getKeywords(funcs), &#39;gmi&#39;),             css: &#39;functions&#39; }
                ];
     
     this.forHtmlScript(SyntaxHighlighter.regexLib.aspScriptTags);
    }
    
    SyntaxHighlighter.brushes.Clojure.prototype     = new SyntaxHighlighter.Highlighter(); 
    SyntaxHighlighter.brushes.Clojure.aliases       = [&#39;clojure&#39;, &#39;Clojure&#39;, &#39;clj&#39;, &#39;lisp&#39;];
    </script>
    <script language='javascript'>
    SyntaxHighlighter.config.bloggerMode = true;
    SyntaxHighlighter.config.clipboardSwf = &#39;http://alexgorbatchev.com/pub/sh/current/scripts/clipboard.swf&#39;;
    SyntaxHighlighter.config.strings.expandSource = &#39;show source&#39;;
    SyntaxHighlighter.config.strings.viewSource = &#39;view source&#39;;
    SyntaxHighlighter.all();
    </script>
    <!--SYNTAX HIGHLIGHTER ENDS-->
    
  2. Note that i have a custom hightlighter in this set for lisp (emacs configs etc)
  3. Go to Blogger Dashboard > Layout > Edit HTML.
  4. Press CTRL+F to find the code </html>.
  5. Add the code to the location before the final </b:section-contents>. This depends highly on what blogger template you have, so you may need to experiment with it a bit. You want to add the syntax highlighter to the end of the page because if the 3rd party site providing javascript is down or under heavy load your blog wont load its content.
  6. You can alter the Color Theme from "shThemeRDark.css" with different ones as explained here
    http://alexgorbatchev.com/SyntaxHighlighter/manual/themes/

  7. Then to highlight a section of code add the following around it in the blogger edit/new posts screen.
    <pre class="brush:cpp">
    //code here
    </pre>
    
    The item after the "brush:" is altered to match your code syntax. The possibles are listed here; http://alexgorbatchev.com/SyntaxHighlighter/manual/brushes/. Of course you need to check that you have installed the brush to get the highlight working.


  8. Other Refs;
http://www.cyberack.com/2007/07/adding-syntax-highlighter-to-blogger.html

sygnery - ubunutu mouse/keyboard sharing with a Mac-- bootup

Find, download and install the sygnery client(mAC) and server for the respective machine

Note that the machine names will need to be replace with whatever yours are mine are:
mac-mini.local
ubuntu-desktop

################### CLIENT (MAC OSX) #####################
For the mac client. (IE not using the mac mouse or keyboard)
mkdir ~/LoginItems
cat > ~/LoginItems/start_synergy.command 
/Applications/synergy/synergyc -f 

Then in Settings -> Accounts -> select the user -> login items
Add the .command file as a terminal shell script.


################### SERVER (UBUNTU) #####################

For the ubutu server. (IE not using the ubuntus mouse or keyboard, on a remote)

vi .synergy.conf

Add the lines
section: screens
ubuntu-desktop:
mac-mini.local:
super = alt
alt = super
end
section: links
ubuntu-desktop:
right = mac-mini.local
mac-mini.local:
left = ubuntu-desktop
end

Assuming your a bash user
vi .bashrc

Add the lines
sysergys_exec=`ps -A | grep synergys`
if [ "$sysergys_exec" = "" ]
then
synergys 
fi

Then restart(only really need to logout/login) and see what happens.

You could run the server globally from your xwindows config or even from start up but i prefer to have it in my bash where i can get at it and modify it easier.

switching users with sudo

sudo -u otheruser /bin/bash

Monday, November 1, 2010

Perl file search, loc, action

Find a file with the text and take the action on it. (in this case do a clearcase checkout)

find ./ | xargs perl -ne 'print "cleartool co -nc $ARGV\n" if m/endl/' | uniq | sh

Perl sed replacement

Gezz.. who let the squirrels into the server room.. there is nutty #$%& everywhere.. so now I have no sed go figure..

ls | xargs perl -ne 'print "$ARGV:$. $_" if m/endl/'

endl vs "\n"

Someone recently asked my why I used endl lines in place of "\n" must say I forgot that they are different. The key point is; Endl Forces a flush of the data stream as well as adding a new line. Where as "\n" is just a "raw" end of line.

A raw "\n" is used when you just need a new line and you dont care either way. IE User logs, data file writing, etc.

The idea usage of endl line is that the buffer is cleared in a timely fashion out the the user or stream. This is needed when the buffering may cause the unacceptable drag out of the final piece of data. IE networks, user prompts, etc

The other point to remember is that endl isn't always compatible with other libraries. For example boost lamba functions and Qt streams dont always react well to endl.

Of course unless your dumping thousands of lines here u shouldn't really have anywaycare.

Friday, October 29, 2010

Perl World clock

Heres another hacked up script that gives the time locally on the system(mine is NYT), the time in japan and the number of seconds fro NYT midnight..

Try running it(called datetime.pl) with these commands lines:
./datetime.pl 
./datetime.pl "7:00"
./datetime.pl "+ 1 day + 1 hours"
./datetime.pl "-10 seconds"

#!/usr/bin/env perl

use strict;
use Date::Manip;

sub string2date
{
    my ($str) = @_;
    return int(UnixDate($str, "%s")); 
}

sub date2string
{
    my ($time) = @_;
    return UnixDate("epoch $time", "%m/%d/%y %H:%M:%S"); 
}

sub date2timezone
{
    my ($time, $tz) = @_;

    return UnixDate(Date_ConvTZ(ParseDate("epoch $time"), '', $tz), '%m/%d/%y %H:%M:%S');
}

sub date2midnightSec
{
    my ($time) = @_;
    my @a = localtime($time); 
    return 3600*@a[2] + 60*@a[1] + @a[0];
}

my $intime = $ARGV[0];
$intime = 'now' unless defined $intime;

my $rawInTime  = string2date($intime);
print "NYT: " . date2string($rawInTime) . "\n";
print "JST: " .  date2timezone($rawInTime, "JST") . "\n";
print "Midnight Seconds: " .  date2midnightSec($rawInTime) . "\n";

hacky crontab replacement in perl

I love system admins. I have been one my self. All that power at the tips of my fingers, and a manager with a big club behind me, waiting to play wack a mole with my fingers if i mees up. Of course system admins can tell a coder that he doesn't have access to cron.... but guess what: cron was written by programmers soo.... hack yourself up a 30 min crontab system in perl and chuckle in your sleep.

Heres my hacked up mess for the day.

#!/usr/bin/env perl

use strict;
use Date::Manip;

#For the valid formats look at 
#http://search.cpan.org/~muir/Time-modules-2003.0211/lib/Time/ParseDate.pm

my $period = 10;
my @tasks = (
             { time => "09:00:00", label => "morning", cmd  => "echo 'good morning'"},
             { time => "01:34:00", label => "Hi", cmd  => "echo 'good morning'"},
             { step => "+ 1 minutes", label => "5 mins", cmd  => "echo '5 mins'"},
             { step => "+ 10 seconds", label => "10 seconsd", cmd  => "echo '5 mins'"}
             
             );

sub string2date
{
    my ($str) = @_;
    return int(UnixDate($str, "%s")); 
}

sub secsDiff
{
    my ($str) = @_;
    return string2date($str) - string2date("now");
}

sub update_firetime
{
    my ($task, $now) = @_;
    my $new = $now;
    if(defined $task->{time})
    {
        $new = string2date($task->{time});
        $new += secsDiff("+ 1 day") if $new < $now;
    }
    elsif(defined $task->{step})
    {
        $new  = $now;
        $new += secsDiff($task->{step}) while $new <= $now;
    }
    $task->{fire_time} = $new;

}

sub boot
{
    my $now = string2date("now");    
    update_firetime($_, $now)
        foreach (@tasks);
}

sub execute
{
    my ($task) = @_;

    my $pid = fork();
    if((defined $pid) && ($pid == 0)) 
    {
        if(defined $task->{xterm} && $task->{xterm} == 1)
        {
            #boot and leave an xt
            my $label   = $task->{label};
            my $cmd     = $task->{cmd};
            my $sys_cmd = "xterm -xrm 'XTerm*foreground: red3' -xrm 'XTerm*background: black' -title 'CRONTAB:$label' -e sh -c \"$cmd; ksh\" &";
            
            system($sys_cmd);
        }
        else
        {
            #just execute it..
            system($task->{cmd});
        }
        exit(0);
    }
}

sub cron_core
{
    while(1)
    {
        my $now = string2date("now");
        foreach my $task (@tasks)
        {
            if($now > $task->{fire_time})
            {
                print "fire! $task->{label}\n";
                execute($task);
                update_firetime($task, $now) 
            }
        }
        #cron loop an launch
        
        print("sleeping.....\n");
        sleep($period);
    }
}

print "Operating with an accuracy of +/-$period seconds\n";

boot();
cron_core();

Monday, October 25, 2010

Checking the version of a ksh

The system admins at my office are crazy they just replaced sh with ksh... evil little monsters... Here how to pull the ksh version

ksh
set -o vi

Now type esc and then Ctrl-V. The version of ksh will appear on the prompt. Something like "Version M-11/16/88f"

Yes its insane but so is ksh...

Friday, October 22, 2010

Profiling perl

The main problem with perl scripts is that they get hacked too much and this generally results in them either breaking or ending up doing useless things... DProf is the older perl profiling lib, and can easily be booted from the command line via a direct call to perl with the debug option. Basically it requires no mod of your existing script(assuming the script is the standard #!/usr/bin/env perl type).

perl -d:DProf <script_file>
dprofpp

It produces a file called "tmon.out" that is processed with "dprofpp" into a human readable form. After that point its up to you to find and kill the pointless junk.

Kindergarden science - Biology

My young daughter has reached 4 years old and I have decided its time to get her started with some basic science. Everyone knows about the classic carrot-top in a dish experiment. So here is the recipe for it;

Stage0) Adult basics.
  • Young kids learn alot by mimicry
    • How you act and react will directly teach them. More than what you say about it
    • They will learn good scientific procedure if you show them it rather than tell them it
  • Young kids have an very short attention span about 15mins max.
    • Experiments need to have simple easy to understand objectives
    • You must prep the materials before hand or the child might wander off or lose interest before its ready.
    • Experiments need to be piece wise if they are long, take a break if its too long and rekindle your kids interest
    • Experiments need to have a fascinating or intriguing result.
    • Sometimes things go wrong or you get stuck it is best to get the kid of on a side project while you sort it out or risk them becoming confused and frustrated as you do.
  • You dont want kids handling dangerous stuff, but you want the child to learn enough practical caution
    • For example using scissors is ok, but using them badly or in a way not intended will teach your kid to do the same.
    • With chemistry experiments think food science, if it cant be eaten or goes boom then its most likely not suitable for a young kid.

Stage 1) Create some interest (And adult prep)
Take a carrot, and cut of the top(about 1 cm thick) and take it to your kid. Ask her what it is what she thinks about it. Ask her where it came from and how it grew up to be a carrot. Explain to her the that the carrot is still alive even now and we can make it grew again. Ask her if she believes it. Ask her if she wants to see it happen.

Stage 2) Prep the experiment(done by your kid)
Gather the materials, A plastic container, cup of water, the carrot top, and a piece of paper(the less the bleach and artificial coloring the better)

Stage 3) Experiment(done by the child)
Place the paper in the container, add the carrot on top, poor on the water(about 1/3 of the carrot should be underwater) and place near a sunny window. Go play elsewhere

Stage 4) Measure and discuss(done by the child)
Come back every day with a log book, ruler and pencil. Ask her about what has changed and measure how long the new green sprouts and roots are. Write it down in the log book. Then after a week create a graph and play connect the dots with her.

Stage 5) End the Experiment(done by the child)
After a while this will start to get monotonous and the fascination will end, it is best not to kill your kids enthusiasm by over doing it. My daughter choose to end this experiment by feeding the new carrot sprouts to a rabbit.

To sum it up you have exposed your child to;
  • Basic experimental procedure
  • Measurement and logging of results
  • Basic charting
  • Basic biology; What are Roots, What are Leaves, What are Stems
  • Basic biology; Planets grow slowly and fresh veggies are alive
http://www.dummies.com/how-to/content/plant-biology-roots-shoots-stems-and-leaves.html

Thursday, October 21, 2010

Stream wrappers for cerr and cout

Its always convient to have a quick wrapper class at your finger tips to turn on or off all output from you system in one foul swoop. Here is a class that adds a layer of indirection to output and allows you to go into a "testing" mode where all output is suppressed

//compile with g++

#include <iostream>
#include <sstream>
#include <string>

using namespace std;

class Streams 
{
public:
static Streams& instance()
    {
        static Streams* self = NULL;
        if(self == NULL)
        {
            self = new Streams();
        }
        return *self;
    }

    static inline std::ostream& out() { return *(instance().out_); }
    static inline std::ostream& err() { return *(instance().err_); }

    void setNormal()
    {
        out_ = &std::cout;
        err_ = &std::cerr;
    }

    void setRedirected()
    {
        if(test)
        {
            delete test;
        }
        test = new std::ostringstream();
        out_ =  test;
        err_ =  test;
    }

private:
    Streams() { test = NULL; setNormal(); }
    ~Streams() { if(test) delete test; }

    std::ostream* test;
    std::ostream* out_;
    std::ostream* err_;
};

int main()
{
    Streams::out() << "bah bah bah" << endl;
    Streams::err() << "err erh ber" << endl;

    Streams::instance().setRedirected();

    Streams::out() << "bah bah bah" << endl;
    Streams::err() << "err erh ber" << endl;
}

Wednesday, October 20, 2010

Object Anti-patterns

Object design patterns are great but there are many pit falls from over engineering a system or creating designs that become menaces, They have become know as the Anti-patterns.

Im currently trying to explain why a class that lists its objective as "This can either be seconds-from midnight. Or a time_t with a date." is a very bad idea.

I dont understand why people dont get it. Its basically a "Staralised schema" IE one object trying to be both things at the same time... and violates the "Single Responsibility principle"

UPDATE:
I have tried exploring the issues that occur with the implementation of an operator+ for this dual purpose class with them but they seem tied to the idea that what is in disk MUST be represented as is in memory.

I have also explain that when the class is viewed in isolate it loses the format information related to the time. This is because the Time classes main use is as an aggregate data-member and the aggregator classes type gives an implicit indication of what the Aggregatees time format is... I have even shown them code that proves the point and exposes many of the problems. To all this effort they have responded with "well maybe you should write/use a whole new time class for that"..

The main reason why I am fighting this so hard boils down the fact that these guys control QA in the system, and unless I can change there minds the problem will remain and other coders will continue to created hacks that avoid issues. These hacks then have a knock on effect(violation of Encapsulation principle) and become maintenance nightmares later...

Refer:
http://www.worldlingo.com/ma/enwiki/en/Anti-pattern

http://en.wikipedia.org/wiki/Single_responsibility_principle

Friday, October 15, 2010

bitsets

The STLs Bitsets are a great way to get flexible and expandable masking and flag logic without using using uints. They print nicely, mask correctly and are very readable compared to inline masking logic.

//complie with g++
#include <iostream>
#include <bitset>

using namespace std;

int main()
{
    const int count=50;
    bitset<count> bits;
    uint32_t      mask;

    bits = 0;
    mask = 0;

    cout << "All off" << endl;
    cout << bits << endl;
    cout << hex << mask << endl;

    //setting
    for(int i=0; i<count; i+=3)
    {
        bits[i] = true;        
        mask |= 1<<i;
    }

    cout << "Every 3rd on" << endl;
    cout << bits << endl;
    cout << hex << mask << endl;

    //masking test
    cout << "Self invert with ^" << endl;
    cout << (bits ^ bits) << endl;
    cout << hex << (mask ^ mask) << endl;

    cout << "Self mask with &" << endl;
    cout << (bits & bits) << endl;
    cout << hex << (mask & mask) << endl;

    //turn on all
    bits = 0; bits.flip();
    mask = -1;

    cout << "All on" << endl;
    cout << bits << endl;
    cout << hex << mask << endl;

    bits = -1; bits.flip();

    cout << "when bits are: " << bits << endl;
    cout << "check any on:  " << (bits != 0) << endl;
    cout << "check any off: " << (~bits != 0) << endl;

    bits = 0;

    cout << "when bits are: " << bits << endl;
    cout << "check any on:  " << (bits != 0) << endl;
    cout << "check any off: " << (~bits != 0) << endl;

    bits.flip();

    cout << "when bits are: " << bits << endl;
    cout << "check any on:  " << (bits != 0) << endl;
    cout << "check any off: " << (~bits != 0) << endl;

    return 0;
}

This outputs the following
All off
00000000000000000000000000000000000000000000000000
0
Every 3rd on
01001001001001001001001001001001001001001001001001
4925b6db
Self invert with ^
00000000000000000000000000000000000000000000000000
0
Self mask with &
01001001001001001001001001001001001001001001001001
4925b6db
All on
11111111111111111111111111111111111111111111111111
ffffffff
when bits are: 11111111111111111100000000000000000000000000000000
check any on:  1
check any off: 1
when bits are: 00000000000000000000000000000000000000000000000000
check any on:  0
check any off: 1
when bits are: 11111111111111111111111111111111111111111111111111
check any on:  1
check any off: 0

Thursday, October 14, 2010

Sum compiler typenotall error

The piece of crud excuse for a compiler has the most meaningless errors ever. "typenotall" means that something BEFORE your type/class (ie the prior line) is missing/wrong like a ";"

Thursday, October 7, 2010

Google Goggles

Well it looks like google has released an image search this stuff is seriously non-trival so anything is better than nothing!

http://www.google.com/mobile/goggles/#text

Get it for the iphone at:
http://itunes.apple.com/us/app/google-mobile-app/id284815942?mt=8

Wednesday, October 6, 2010

A hacky way to get your class streaming out

Needing a quick way to seem to contents of a classes.. dump it into cout with a overloaded operator<< and an existing print function of some kind with very little fuss..

//complie with g++
#include <iostream>
#include <sstream>

using namespace std;

class A  {
public:
    A(): str1("Hi"), str2("There") {}
 
    string print()
    {
 ostringstream out;
 out << " str1: " << str1 << endl;
 out << " str2: " << str2 << endl;
 return out.str();
    }

private:
    string str1;
    string str2;
};

ostream& operator<<(ostream& out, A& val)
{
    out << val.print();
    return out;
}

int main()
{
    A test;
    cout << test << endl;
    return 0;
}

Monday, October 4, 2010

supressing purecov messages for untested functions

Add the "purecov: begin inspected" blocks around the untestable/difficult to test code.

/* purecov: begin inspected */
void Timer::tickTock()
{
}
/* purecov: end inspected */

Determine the arch type of the executable

file <exe_name>

Sunday, October 3, 2010

Sudo trick to get a root like shell

Here is the command to get a su like shell from sudo

sudo -i

Friday, October 1, 2010

Ksh completion

Here is kshs way of getting file completion. (just another useless fact)

Keystoke Action
ESC ESC tab complete
ESC = list possible completions
ESC * expand all possible completions into command line

Thursday, September 30, 2010

WinXP multiple taskbars with little pain

I dont have admin rights on my work machine but needed a multi screen toolbar app now winXP. "multimon" seemed to install without an issue and worked well. It doesnt seem to need to mess with the OS to run.

http://www.mediachance.com/free/multimon.htm

Update:
A great alt key alternative is Vista Switcher(also works on XP) This app gives you a preview of the widow and allows you to filter based on monitor with ctrl+alt+tab

http://www.ntwind.com/software/vistaswitcher.html

Wednesday, September 29, 2010

C Bit packing and structs

Bit packing of a struct is achieved with the ":" after the member of the struct this little item is great for working with binary images of data however it can lead to surprises. Always keep in mind the compiled result will mask and shift every thing you place in the struct.

#include <stdint.h>
#include <iostream>

using namespace std;

typedef struct {
    uint8_t a :6;
    uint8_t b :1;
    uint8_t c :1;
} Test1;

typedef struct {
    uint8_t a;
    uint8_t b;
    uint8_t c;
} Test2;

typedef union {
    struct {
 uint8_t a :6;
 uint8_t b :1;
 uint8_t c :1;
    } bits;
    uint8_t full;
} Test3;

int main()
{
    Test3 test3;
    
    cout << sizeof(Test1) << endl;
    cout << sizeof(Test2) << endl;
    cout << sizeof(Test3) << endl;
    
    test3.bits.a = 0;
    test3.bits.b = 0;
    test3.bits.c = 0;
    
    cout << "Test3 inited:" << endl 
  << (int)test3.bits.a << endl
  << (int)test3.bits.b << endl
  << (int)test3.full   << endl;
    
    test3.bits.a = 0xff;
    
    cout << "Test3.bits.a loaded with 255:" << endl 
  << (int)test3.bits.a << endl
  << (int)test3.bits.b << endl
  << (int)test3.full   << endl;
    
    test3.bits.a = 0x0;
    test3.bits.b = 0xff;
    
    cout << "Test3.bits.b loaded with 255:" << endl 
  << (int)test3.bits.a << endl
  << (int)test3.bits.b << endl
  << (int)test3.full   << endl;
}

The output looks like this (depending on machine endianness)
1
3
1
Test3 inited:
0
0
0
Test3.bits.a loaded with 255:
63
0
252
Test3.bits.b loaded with 255:
0
1
2

A perl implementation of find

Recently working on a system which has a busted find command need a fix.. it is about 300% slower than the real thing so use it when needed only

#!/usr/bin/env perl

use strict;
use warnings;
use Cwd;

my $start=$ARGV[0];

sub find
{
    my ($dirname) = @_;
    my $dh;
    opendir($dh, $dirname) or die "Couldn't open dir '$dirname': $!";
    my @files = readdir($dh);
    closedir($dh);

    #print files...
    foreach my $file (@files) 
    {
 if(
    ($file) &&
    ($file !~ /^\.$/) &&
    ($file !~ /^\.\.$/)
    )
 {
     my $path = "$dirname/$file";
     print "$path\n";
     if(-d "$path")
     { 
  find("$path"); 
     }
 }
    }
}

$start = "." unless $start;

find($start);

Friday, September 24, 2010

Friends and Inhertance

In C++ there is a common gotcha with friends and inheritance.

The rules are summarized as
  1. Friend access is one way.
  2. Friends of a friend have no access.
  3. Children of a friend have no access.
  4. Children of a parent with a friend will allow the friend to access them like the parent.

    IE friend access of a derived class is limited to interface present on the original base class only. Virtual functions will operate as normal if they are accessible.

Example code;

#include <iostream>

using namespace std;

class FriendOfFriendA;
class FriendA;


class A{    
public:
    A() : stuff(8) {}

    int get(){return stuff;}
    
protected:
    virtual int vget(){return stuff;}
    int stuff;

    friend class FriendA;
};

class KidA : public A {
public:
    KidA() : A(), kidStuff(9) { stuff = 16; }

protected:
    int kidGet(){return kidStuff;}
    virtual int vget(){return kidStuff;}
    int kidStuff;
};

class FriendA{
public:
    int getA(A& a){return a.stuff;}
    int getKidA(KidA& a){return a.stuff;}
    //int getKidAstuff(KidA a){return a.kidStuff;}  //BAD only a's stuff is a friend
    //int getKidAstuff(KidA a){return a.kidGet();}  //BAD only a's stuff is a friend

    int getVirtualA(A* a){return a->vget();}

    friend class FriendOfFriendA;

    static int pubStaticGetA(A& a) { return a.stuff; }
private:
    static int privStaticGetA(A& a) { return a.stuff; }
};

class FriendOfFriendA{
public:
    //int getADDirect(A& a){return a.stuff;}   //BAD no freind of a friend access
    int getAIndirect(A& a){return FriendA::pubStaticGetA(a);}
    int getADoubleIndirect(A& a){return FriendA::privStaticGetA(a);}
};

class FriendAKid : public FriendA{
public:
    //int getADDirect(A& a){return a.stuff;} //BAD no child of a friend access
    int getADIndirect(A& a){return getA(a);}
};


int main()
{
    A    a;
    KidA kidA;

    FriendA         friendA;
    FriendAKid      friendAKid;
    FriendOfFriendA friendOfFriendA;

    cout << "friendA.getA(a) : " << friendA.getA(a) << endl;
    cout << "friendA::pubStaticGetA(a) : " << FriendA::pubStaticGetA(a) << endl;

    cout << "friendA.getVirtualA(a) : " << friendA.getVirtualA(&a) << endl;
    cout << "friendA.getVirtualA(kidA) : " << friendA.getVirtualA(&kidA) << endl;
   
    cout << "friendA.getKidA(kidA) : " << friendA.getKidA(kidA) << endl;
    
    //cout << "friendOfFriendA.getADDirect(a) : " << friendOfFriendA.getADDirect(a) << endl;
    cout << "friendOfFriendA.getAIndirect(a) : " << friendOfFriendA.getAIndirect(a) << endl;
    cout << "friendOfFriendA.getADoubleIndirect(a) : " << friendOfFriendA.getADoubleIndirect(a) << endl;
    
    cout << "friendAKid.getADIndirect(a) : " << friendAKid.getADIndirect(a) << endl;
}

This produces this result:
friendA.getA(a) : 8
friendA::pubStaticGetA(a) : 8
friendA.getVirtualA(a) : 8
friendA.getVirtualA(kidA) : 9
friendA.getKidA(kidA) : 16
friendOfFriendA.getAIndirect(a) : 8
friendOfFriendA.getADoubleIndirect(a) : 8
friendAKid.getADIndirect(a) : 8

Tuesday, September 21, 2010

Adjusting emacs tabs in namespaces only

Dealing with a large project with lots of c++ namespaces and scoping; Here is how to kill the indents from the namespace regions in emacs

;; Basic indentation
(setq c-basic-offset 4)

(defun my-c-setup ()
  (c-set-offset 'innamespace 0))
(add-hook 'c++-mode-hook 'my-c-setup)

To find out your current syntax state hit \C-c\C-s (crtl-c ctrl-s)


Refer:
http://www.emacswiki.org/emacs/IndentingC
http://google-styleguide.googlecode.com/svn/trunk/google-c-style.el

Thursday, September 16, 2010

sh simple counted command line loops

For repeated predictable execution of times

i=64; while [ $i -ne 0 ]; do  echo $i; i=`expr $i - 1`; done

Portable script shebang

Let say you need a script to execute on multiple systems but the admins and OS's all have there own idea on where things belong. Here is a quick way to get the script to locate the interpreter 99% of the time

#!/usr/bin/env perl

Tuesday, September 14, 2010

Quick and dirty hex converter

void convertHex()
{
    string exchangeHex = "0123";
    int exchange;

    //exchangeHex
    std::stringstream ss;
    ss << std::hex << exchangeHex;
    ss >> exchange;
 
    cout << exchange << endl;
}

Tuesday, September 7, 2010

Googles got a bouncy logo

UPDATE: Rob Hawkes has recreated it in html5 here;

http://rawkes.com/experiments/google-bouncing-balls-canvas/

And Mark Brenig-Jones has mod'ed it slightly
http://dotty-dots.appspot.com/?h=40526f624861776b6573

http://rawkes.com/blog/2010/09/07/recreating-googles-bouncing-balls-logo-in-html5-canvas



ORIGINAL POST:
http://www.google.fr/

probably just for today..

a fatal relocation error

A fatal relocation error:

This error means that you have included a dynamic library in your build but at run time the library that it uses is mismatched. This can happened if you rebuilt the lib after the exe, or failed to move the new lib into place etc.

Monday, September 6, 2010

xterm colors and settings

Edit ~/.Xresources and add the following

xterm*foreground: white
xterm*background: black

Then execute this command
xrdb ~/.Xresources
Then open a new terminal to test.

Here is a more complex version of it
http://www.xfce.org/various/Xresources.txt

Wednesday, September 1, 2010

graphviz map of the linkage between .a files

This hacked up piece of perl script will generate a dot compatible piece of text that will display the mapping of the libs in a project.

#!/usr/bin/perl 

my $path = "path/to/libs"

# get the nm results for the system
@ret = `find $path | grep "\.a$" | xargs nm -A`;
#@ret = `cat data.tmp`;

# 0 = lib[object]
# 6 = DEF/UNDEF 
# ./path_to_lib.a[object_in_lib.o]: [152]   |             0|           0|FUNC |GLOB |0    |UNDEF  | func_name_in_obj

my $count = 20;

my %defs     = ();
my %connects = ();

# break appart the result and map what are uages of functions and what are definations

print " // mapping functions...\n";
foreach $line (@ret)
{
    chomp($line);
    @cols = split(/\|/, $line);

    $file  = $cols[0];
    $undef = $cols[6];
    $func  = $cols[7];

    # $file =~ s/:.*//;  # for in lib object inter-dependency...
    $file =~ s/\[.*//;    # for lib file inter-dependency...
    if( $undef =~ /UNDEF/ )
    {
 $connects{ $func }{ $file } = 1;
    }
    else
    {
 $defs{$func} = $file;
    }
}

# now merge the usage with the definition as the file linkage
my %map = ();

print " // merging func usage to definition...\n";
foreach $func (sort keys %connects)
{
    $files = $connects{$func};
    $def_file = $defs{$func};

    foreach $file (sort keys %$files)
    {
 $map{$def_file}{$file} = 1;
    }
}

my %node = ();
my $node_count = 0;

print " // generating node index...\n";
foreach $src_file (sort keys %map)
{
    unless( exists( $node{$src_file} ) )
    {
 $node{$src_file} = $node_count;
 $node_count = $node_count + 1;
    }

    $files = $map{$src_func};
    foreach $tar (sort keys %$files)
    {
 unless( exists( $node{$tar} ) )
 {
     $node{$tar} = $node_count;
     $node_count = $node_count + 1;
 }
    }
}

print " // generating dot file...\n";

print "digraph linkmapping {\n";
foreach $key (sort keys %node)
{
    $idx = $node{$key};
    print "    n$idx [label=\"$key\"];\n";
}

foreach $src_file (sort keys %map)
{
    $files = $map{$src_func};
    $src_node = $node{$src_file};

    foreach $tar (sort keys %$files)
    {
 $tar_node = $node{$tar};
 print "    n$tar_node -> n$src_node;\n";
    }
}
print "}";

Execute with the following (assuming you called the saved file "nm_deps.pl"
nm_deps.pl > map.dot
dot map.dot -Tpng -omap.png

count the occurace of words in a file

cat filename | tr '[:punct:]' ' ' | tr ' ' '\012' | sort | uniq -c | sort -n 

Thursday, July 15, 2010

SSL using website -- Setting up the server

First of all you need to realize that SSL doesn't work for name based virtual hosts so it needs to be an ip. Technically 1 SSL using host does work it does but the SSL cert is shared for all sites and this is a serious issue from a business/search engine/customer point of view.

  1. Check that you have completed the basic ssl module set up
    sudo a2enmod ssl
    

    And check that the server is listening on 443. either netstat antp for it or grep for the Listen line in the apache2 config files.
    Listen 443
    

  2. Choose a new ip address for the ssl version of the server. Lets say we pick the IP: 192.168.1.200. Once you have gotten the crt back from the provider move it into place and remember to chown and chmod it for root only

    Lets assume we placed it at; /etc/apache2/ss/www.mysite.com.crt


  3. Now to multi-home the server (ie give it the new ip address to play with). You do this by editing and appending the following to /etc/network/interfaces
    #this is mysite's ip for its ssl
    auto eth0:1
      iface eth0:1 inet static
      address 192.168.1.200
      netmask 255.255.255.0
      network 192.168.1.0
      broadcast 192.168.1.255

    Remember to update your DNS server if needed

  4. Then add a new virtual host for the SSL version of the site.

    <VirtualHost 192.168.1.200:443>
      ... COPY OF NON-SSL VERSIONS SETTINGS ...
    
      SSLEngine On
      SSLCertificateKeyFile   /etc/apache2/ssl/www.mysite.com.key
      SSLCertificateFile      /etc/apache2/ssl/www.mysite.com.crt
    </VirtualHost>
    
I may have missed a few things since my servers have been serving SSL for a long time now. Refer:
https://help.ubuntu.com/8.04/serverguide/C/httpd.html https://help.ubuntu.com/8.04/serverguide/C/certificates-and-security.html

SSL using website - Generating an SSL cert for apache2

  1. Generate a the ssl key pair
    openssl genrsa -out www.mysite.com.key 2048
    
    • using a pass-phrase is problematic since the apache2 server cant boot with the having the pass-phrase input.
    • if you need to use a passphrase then add on -des3 param
  2. Generate a code signing request (without a pass-phrase)
    openssl req -new -key www.mysite.com.key -out www.mysite.com.csr
    
    • do not enter an email address, challenge password or an optional company name when generating the CSR.
    • Enter the info which MATCHES THE WHOIS for the domain or your request is likely to get rejected.
      • Country Name:
      • State or Province: (the capitalized two letter code)
      • Locality or City: (without abbreviations)
      • Company: (without &, @, or any other symbol)
      • Organizational Unit: (optional; to skip hit enter)
      • Common Name: the host name ie "www.mysite.com" (make certain it matches the main one used by end customers, to avoid ssl mismatch warnings.)

  3. Send the code code signing request to the certificate authority and wait for them to send the signed certificate back (the crt file).
  4. The files should be stored at the following location with the following permissions/owner. Remember to do it or the key can be viewed and copied.
    /etc/apache2/ssl$ ls -al
    drwxr-xr-x 2 root root 4096 2010-01-08 16:38 .
    drwxr-xr-x 9 root root 4096 2010-01-08 09:42 ..
    -r-------- 1 root root 1354 2010-01-08 09:17 www.mysite.com.crt
    -r-------- 1 root root 1354 2010-01-08 09:17 www.mysite.com.csr
    -r-------- 1 root root 1675 2010-01-08 16:38 www.mysite.com.key
    
Refer https://knowledge.verisign.com/support/ssl-certificates-support/index?page=content&actp=CROSSLINK&id=AR198

rails - Forcing a certain encoding type for the page

response.headers["Content-Type"] = "text/html; charset=shift_jis"

tcpdump to debug the an encoding problem

This is kind of over kill but the HTTP headers plugin for firefox wasn't telling me the truth. I dev web apps using a locale apache2 server. And in this case I needed to deal out an sjis page, of course rails is utf-8 inside and somewhere/somehow the encoding is getting forced to utf8. So to get the truth tcpdump it.

sudo tcpdump -i lo  -Xx -s1500

After this I refreshed the page in question and read the log. Its was clear that rails is always writing utf-8 into the HTTP header which overrode the weaker meta tag setting I was trying to us.

fixing "svn: Malformed file" and other broken svn file problems...

This happens when you get to smart for yourself and alter the contents of the .svn dir accidentally...


To fix it;
Basically move the whole working dir over and recheck out and then restore the new/edited/deleted files. Sounds hard but it is quite easy(especially if you have had to do it a few times).... Run the following commands on the console. And note the commands with "| sh" allow you to first confirm the exact action before executing it so use it to double check before you make a total mess


#move broken trunk out of the way
mv trunk broken
mkdir trunk 
cd trunk
svn checkout https://server.svn/repos/project/trunk
cd ../broken

# make the new dirs -- confirm first...
find ./ -type d | grep -v svn | egrep "^./(app|test|lib|db)" | sed "s|\(.*\)|mkdir -p ../trunk/\1|"
find ./ -type d | grep -v svn | egrep "^./(app|test|lib|db)" | sed "s|\(.*\)|mkdir -p ../trunk/\1|" | sh

# move all the normal non-svn files that are relevant back in (im my case its a rails app) -- confirm first... find ./ -type f | grep -v svn | egrep "^./(app|test|lib|db)" | sed "s|\(.*\)|cp \1 ../trunk/\1|" find ./ -type f | grep -v svn | egrep "^./(app|test|lib|db)" | sed "s|\(.*\)|cp \1 ../trunk/\1|" | sh

# remove all deleted files. -- confirm first... svn status | grep "^D" | sed "s|^D *|svn del ../trunk/|" svn status | grep "^D" | sed "s|^D *|svn del ../trunk/|" | sh

rails - using truncate from a the lib dir ie a module

Here is how to get the helpers into the libs area, Sometimes the helpers use/set data on the controller etc so this doesn't work.

module MyModule
  include ActionView::Helpers::TextHelper
  module_function :truncate
end


Here is how to get it on the console
helper.truncate(string, :length => length)

Monday, July 12, 2010

A quick javascript console web page.

If you have problematic javascript on a website then its often a pain to locate the exact cause of the problem in the particular browser (excluding firefox due to firebug). This site gives you a nice in browser console to work out your issues on.

http://www.jconsole.com/

Hopefully some hack doesn't find it and use it for blackhat purposes that results in it getting taken down.

/proc/: The linux kernels live state

/proc/ is a virtual (ie in memory) part of the linux file-system that displays the current status and configuration of the kernel.

The amount of information about the system in this area is amazing.

For example try out these commands
cat /proc/cpuinfo
cat /proc/meminfo
cat /proc/version
cat /proc/uptime
cat /proc/loadavg
cat /proc/net/dev

When scripting you will probably want to use the info in a more digested form. The command for a script could be something like

cat cpuinfo  | grep vend |  cut -d' ' -f2

A useful debug trick is to determine what the environment settings where for a process after it has been started. To do so you would cat the processes environ file like so;

cat /proc/<process_id>/environ

The /proc/sys directory can also be used to alter certain files in a live system to adjust the kernel system wide. To tell which files can be altered just ls -al and look for the writable bit. Keep in mind that changes made in the area are temporary, and some changes can easily kill the system. To make the changes permanent the /etc/sysctl.conf needs to be edited.

Refer to
http://www.linuxjournal.com/article/8381

http://linuxhelp.blogspot.com/2005/04/proc-filesystem.html

crontab for every X minutes excluding a period Y hours

Crontab isnt really hard its just limited.

To execute for every 5 minutes except between 1:00 to 2:00
*/5 0-1,2-23 * * * /bin/hello.sh

If you need finer control than an hour you might need to consider using 2 lines;
*/5 0-1,2-23 * * * /bin/hello.sh
0,5,10,55 1-2 * * * /bin/hello.sh

mass replacement of text in files

UPDATE: Phil pointed out there was an easier way to get mass replacement of text, Kudos mate.
find ./ -type f | grep -v svn  | xargs perl -pi -e "s/partA/partB/g;s/partC/partD/g;s/partE/partF/g"

Here is a crazy bit of script that uses a pair of seds to replace a several pieces of text across all files in the directory and below.

#example script that converts the following
#  _address => _address1
#  _address_street => _address2
#  _address_building => _address3
find ./ -type f | grep -v svn | sed "s/\(.*\)/sed 's|_address_building|_address3|g' \1 > \1.script; mv \1.script \1/" | sh
find ./ -type f | grep -v svn | sed "s/\(.*\)/sed 's|_address_street|_address2|g' \1 > \1.script; mv \1.script \1/" | sh
find ./ -type f | grep -v svn | sed "s/\(.*\)/sed 's|_address|_address1|g' \1 > \1.script; mv \1.script \1/" | sh
find ./ -type f | grep -v svn | sed "s/\(.*\)/sed 's|_address12|_address2|g' \1 > \1.script; mv \1.script \1/" | sh
find ./ -type f | grep -v svn | sed "s/\(.*\)/sed 's|_address13|_address3|g' \1 > \1.script; mv \1.script \1/" | sh

Free OCR that is worth it

Wow OCR of Japanese text really is hard but this system just did a great job for me (>80% accurate). It worked best with large pictures

http://weocr.ocrgrid.org/cgi-bin/weocr/search.cgi?lang=jpn&fmt=html

PS i tried the iPhone version "C'est What!!" of the app it doesn't work so dont purchase it.

Monday, July 5, 2010

rails testing - undefined method `request='

Problem:
test_some_functional_test_case(SomeFunctionalControllerTest):
NoMethodError: undefined method `request=' for #<SomeMispeltFunctionalController:0x7f5b55bd0a58>

Solution:
Basically it means you haven't required the controllers file. Or you have a typo in the name that is instantiating the a non controller for the @controller variable in the test.

rails - DEFAULT_RAILS_LOGGER not working in libs

I just noticed that "DEFAULT_RAILS_LOGGER" is not working in libs on some of the newer rails versions.. The new alternative is "Rails.logger" it seems to work perfectly fine.

OWASP - Web site security documents of worth

The owasp site is a great resource for web site security guide lines

http://www.owasp.org/

http://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet

http://code.google.com/p/owasp-development-guide/wiki/WebAppSecDesignGuide_D6

Script injection attacks to be aware of

The following is an xss attack that few people release is possible;
<script>
alert('</script><script>alert(2);</script>');
alert('1');
</script>

How it works:
Its simple really the HTML parser of browsers first parse the HTML structure of the page, they have no knowledge of the structure of javascript and contents contained in the tag body. _ANY_ HTML tag, even one present in correctly escaped javascript takes precedence.

Saturday, July 3, 2010

Interview puzzle questions

This site has a good list of interview questions and puzzles;

http://www.mytechinterviews.com/category/puzzles

If I bother to work out a problem that is on that blog myself that ill still post it here but.. for now its a good resource for interview prep.

cleaning up locales in ubuntu

if you notice your ubuntu install wasting space in locales here is how to kill it quickly

sudo apt-get install localepurge
sudo localepurge

Rails DateTime converting into your time zone

Quick and dirty way to get a time into your locale

DateTime.parse(some_other_time_string).in_time_zone(::Time.zone)

Confirming and ip/email/web sites owner

Scammers will often try to make themselves look more presentable by hiring a web designer/programmer to make a professional site for them. Then they simply walk away with the code and content without paying and worst still use your work to scam a bigger fish, most likely with info in it that clearly identifies it as YOUR work.

Here are a couple of nslookup/dig/whois trace examples
nslookup 66.249.89.104
dig -x 66.249.89.104
dig 104.89.249.66.in-addr.arpa
whois  66.249.89.104

Normally you can trace digs actions to see what servers are being talked with however my DSL modems dns server doesnt seem to not support it. So I cant use it. Here it is anyway.
dig -x 66.249.89.104 +trace

Here is a manually worked trace
dig @a.root-servers.net 104.89.249.66.in-addr.arpa +norecurse
dig @V.ARIN.NET 104.89.249.66.in-addr.arpa +norecurse
dig @ns2.google.com 104.89.249.66.in-addr.arpa +norecurse
dig @ns1.google.com -x 66.249.89.104 +norecurse
For this trace the path ends at an SOA record

dig @a.root-servers.net www.google.com +norecurse
dig @g.gtld-servers.net  www.google.com  +norecurse
dig @ns1.google.com  www.google.com  +norecurse

Now what to do with that raw info. Here are some ways to figure out if its legit
  • Grab domain name with a dig or nslookup on the real ips/urls that find in the emails
  • Grab the who-is info off the urls and find the registered owners,
  • Check them against an scammer list like http://www.autosurfinfo.net/badiplist.html
Then Since your dealing with a company;
  • Google search the company and its affiliates, Using the info from the whois and what they claimed to be in there emails.
  • Then First confirm the basics about the company web site.
    • Confirm that your looking at the real companies site. Not some fake site that is trying to trick you into believing its part of the really company. ie microsoft.com vs microsoft.jack.com
    • Are they claiming to be a massive company and yet they have a website made by some crud web publishing.
    • Is the content all pictures or stolen text (possibly modified when taken from a 3rd party place)
    • Is the web site hosted in a free host somewhere
  • Then you want to look at the companies location and employer info;
    • Google map the location and look at the building with street view
    • Does it have the companies names/sign logo etc
    • Can the companies number of employees actually fit in the building/floor they claim to be on?
    • Does the office space even appear to be used?
    • Is the building/location appropriate for there type of business?
  • Then you want to look at the companies finance info;
    • How much operating cash do they have and how many employees, figure out the ratio of cash to employees then match that to what that employee would be payed yearly if the number is too far off then how are they paying employees?
    • Is size/wealth of company reflected in the web site. Why would a multi-million dollar company have a crub website?
    • And look over the products/services that they sell and search around for 3rd party info on
      it. Confirm that they really can make the cash they are talking about.

Rails - 422 error code

The Rail 422 error code is a bit of an odd ball.


Most likely cause of this is the CSRF is firing and killing whatever is posting to your site from outside in my case its PAYPAL posting an IPN request to a site im working on.

To fix it add this line of code to the controller


If entire controller can be posted to from out side then this is ok

skip_before_filter :verify_authenticity_token

If you need to open access to a single page then try this:
protect_from_forgery :execpt => :pages_that_are_posted_to_from_out_side

Monday, June 28, 2010

mysql - find grandparents/grandchildren

Another interesting set of queries are parent, grandparent queries.

To find all the grand children nodes do this.
select b.id, b.parent_id, a.parent_id from kids as a, kids as b where a.id = b.parent_id and a.parent_id is not null;

To find all the grand parents with more than 2 grand children do this.
select b.id, b.parent_id, a.parent_id from kids as a, kids as b where a.id = b.parent_id and a.parent_id is not null group by a.parent_id having count(a.parent_id) > 2;

To produce the full family tree of a grandchild node do this
select b.id, b.parent_id, a.parent_id from kids as a right outer join kids as b on a.id = b.parent_id;

To find all nodes whos grandparent(and possibly parent) is unknown do this;
select b.id, b.parent_id, a.parent_id from kids as a right outer join kids as b on a.id = b.parent_id where a.parent_id is null;

Here is my full test sql.. try it out
create table kids (id integer, parent_id integer);
describe kids;
insert into kids values (1,null);
insert into kids values (3,1);
insert into kids values (4,2);
insert into kids values (5,2);
insert into kids values (6,4);
insert into kids values (7,2);
insert into kids values (8,7);
insert into kids values (9,7);
insert into kids values (10,7);
insert into kids values (11,3);
select * from kids;
select b.id, b.parent_id, a.parent_id from kids as a, kids as b where a.id = b.parent_id and a.parent_id is not null;

select b.id, b.parent_id, a.parent_id from kids as a, kids as b where a.id = b.parent_id and a.parent_id is not null group by a.parent_id having count(a.parent_id) > 2;

select b.id, b.parent_id, a.parent_id from kids as a right outer join kids as b on a.id = b.parent_id;

select b.id, b.parent_id, a.parent_id from kids as a right outer join kids as b on a.id = b.parent_id where a.parent_id is null;

Saturday, June 26, 2010

My sql -- finding duplicates in a column

Here is how to find all entries that have duplicates in a mysql database


select email, count(email) from emails group by email having count(email) > 1;

So what is happening. To me it appears that the SQL boys have decided that selects can act in two independent ways:
1) "normal mode" - give me all the results
2) "aggregate mode" - give me groups of results represented by the first group member

It appears to me that this "aggregate mode" is triggered if either the "group by" or an aggregate function is present in the statement.

To be more specific;
1) When the "GROUP BY" is not present but an aggregate function is used then it is assumed that the data is one large group and only a single row is returned. This row appears to have the data from the first row of the normal select and the results of any aggregate function applied access the entire normal select results.
2) However if the "GROUP BY" is present then the functions operate on the individual groups. The resulting row(s) will use the normal selects first row for the normal data in the group and will apply any functions across the entire group.

This statement here will demonstrate the second rule in action more clearly.
select email, count(email), num, sum(num), avg(num), min(num), max(num) from emails group by email;

Here is the full test sql which brought me to my conclusions;
create table emails (email text, num integer);
describe emails;
insert into emails values("a@a.com", 1);
insert into emails values("b@a.com", 2);
insert into emails values("b@a.com", 3);
insert into emails values("c@a.com", 4);
insert into emails values("d@a.com", 5);
insert into emails values("d@a.com", 6);
insert into emails values("d@a.com", 7);
insert into emails values("b@a.com", 8);
select * from emails;
select distinct email from emails;
select email from emails group by email;
select email, count(email) from emails;
select email, count(email), num, sum(num), avg(num), min(num), max(num) from emails group by email;
select email, count(email) from emails group by email having count(email) > 1;

There are several functions that operate on the "group"
sum(), count(), avg(), min(), max(), etc

Refer here for more info;
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html

Mysql grant syntax

As unbelievable as it is I forget the grant syntax way to easily...

GRANT ALL ON database.* TO username@'localhost' IDENTIFIED BY 'password';

die hard 3 jug 5 jug problem

Question:
You have two jugs a 3 and 5 liter jug how do you get 4 liters in a jug.

Answer:
This is one of the more basic questions, but it still appears in job interviews. It is basically impossible not to get the answer correct.

1) First fill the 5 liter jug.
2) Poor water from the 5 liter into the 3 liter one until its full. That leaves 2 liters in the 5 liter,
3) Empty the 3 liter and transfer the 2 liters into it. This leaves 1 liter of space in the 3 liter jug.
4) Then fill the 5 liter jug
5) Then poor 1 liter out of the 5 liter into the 1 liter of empty space in the 3 liter jug.

Done the 5 liter jug has 4 liters in it

c++: Basic Traits

Traits:
In C++ "traits" are basically a group of template classes that provide miscellaneous information about another type or data structure.

'Think of a trait as a small object whose main purpose is to carry information used by another object or algorithm to determine "policy" or "implementation details".'
- Bjarne Stroustrup

Traits are very common in C++. One of the more common ones is the string class its self. The string class uses traits to provide information about internationalization and character encoding. Often they are visible in the code and debugger output as a template parameter that has a default initialization via a second template.

In other cases the use of traits is more normal as in the the class "std::numeric_limits" and the other members of the limits.h header.

Boost also offers many interesting and helpful traits classes as an example here is the "is_void" traits class.

template< typename T > 
struct is_void{ 
  static const bool value = false;
};

template<> 
struct is_void< void >{ 
  static const bool value = true; 
};


As you can see this trait template's sole purpose to is provide information about what the input parameter type was. This is only really useful in a parts of the code which the programmer doesn't know what the input type was: Hence inside another template.

For more info refer to:
http://www.cantrip.org/traits.html
http://www.cplusplus.com/reference/std/limits/numeric_limits/

The truth about what movitates people

http://www.youtube.com/watch?v=u6XAPnuFjJc

Wednesday, June 23, 2010

Three coworkers sharing average salaries

Question:
Three coworkers would like to know their average salary. How can they do it, without disclosing their own salaries?

The key is to scramble the sum with unknown/unshared data. The scramble must be reversible and when reversing it must not effect the sum.

Answer on the web:
So each person adds a random number(Rn) plus there salary(Sn) to the sum(Sum) and hands it to the next one. And then in the second round they each deduce there random number

(round 1)
Sum0 = S1 + R1
Sum1 = S1 + S2 + R1 + R2
Sum2 = S1 + S2 + S3 + R1 + R2 + R3

(round 2)
Sum3 = S1 + S2 + S3 + R2 + R3
Sum4 = S1 + S2 + S3 + R3
Sum5 = S1 + S2 + S3

And final they divide by the number of people
Average(6) = (S1 + S2 + S3)/3

Here is the proof:
For person 1
Starts with:
R1
S1
Sum0 = S1 + R1
Sum2 = S1 + S2 + S3 + R1 + R2 + R3
Sum3 = S1 + S2 + S3 + R2 + R3
Sum5 = S1 + S2 + S3

Can calc
R2 + R3 = Sum3 - Sum5

So he finally knows
R1
S1
R2 + R3
S2 + S3 

For person 2
He starts with:
R2
S2
Sum0 = S1 + R1
Sum1 = S1 + S2 + R1 + R2
Sum3 = S1 + S2 + S3 + R2 + R3
Sum4 = S1 + S2 + S3 + R3
Sum5 = S1 + S2 + S3

He can calc:
R3 = Sum4 - Sum5

He finally knows knows
R2
R3
S2
S1 + R1
S1 + S3

For person 3
He Starts with:
R3
S3
Sum1 = S1 + S2 + R1 + R2
Sum2 = S1 + S2 + S3 + R1 + R2 + R3
Sum4 = S1 + S2 + S3 + R3
Sum5 = S1 + S2 + S3

He can calc:
S1 + S2 = Sum5 - S2
R1 + R2 = Sum2 - S1 + S2 

He finally knows:
R3
S3
S1 + S2
R1 + R2

Here is a much stronger answer
It requires an 2 or more arbitrators in the system, At the end of each Sum stage the summer chooses a random arbitrator who then adds his own random value to the sum.
Once Sum5 stage is complete the arbitrators each in turn recieve the sum and deduct out the total of the random numbers they added in. As a result the computation becomes

(round 1)
Sum0 = S1 + R1 + A0
Sum1 = S1 + S2 + R1 + R2 + A0 + A1
Sum2 = S1 + S2 + S3 + R1 + R2 + R3 + A0 + A1 + A2

(round 2)
Sum3 = S1 + S2 + S3 + R2 + R3 + A0 + A1 + A2 + A3
Sum4 = S1 + S2 + S3 + R3 + A0 + A1 + A2 + A3 + A4
Sum5 = S1 + S2 + S3 + A0 + A1 + A2 + A3 + A4 + A5

Sum6 =  S1 + S2 + S3 + A0 + A2 + A4
Sum7 =  S1 + S2 + S3

Hence its much more harder to break

Nuggets in packs of 6, 9 and 20.

Question:
At a fast food restaurant you can buy chicken nuggets in packs of 6, 9 or 20. Is there such a number N, that for all numbers greater than it, it is possible to buy any number of chicken nuggets?

Answer:
Keep in mind the key fact we need to prove that numbers are not possible. The equation we have is 6x + 9y + 20z = n. The minimum step we can take is 6 so lets work from there.
If we assume y and z are 0 then the equation becomes 6x = n. Hence the possible numbers become

 1  2  3  4  5  x
 7  8  9 10 11  x
13 14 15 16 17  x 
19 20 21 22 23  x 

If we assume y=1, z=0 then the equation becomes 9 + 6x = n. Hence the possible numbers become

 1  2  3  4  5  x
 7  8  x 10 11  x
13 14  x 16 17  x 
19 20  x 22 23  x 

Any further 9s will take us back to the same used columns so more 9s is pointless that leaves 20. If we assume y=0, z=1 then the equation becomes 20 + 6x = n

 1  2  3  4  5  x
 7  8  x 10 11  x
13 14  x 16 17  x
19  x  x 22 23  x
25  x  x 28 29  x
31  x  x 34 35  x
37  x  x 40 41  x
43  x  x 46 47  x

If we assume y=1, z=1 then the equation becomes 20 + 9 + 6x = 29 + 6n = n

 1  2  3  4  5  x
 7  8  x 10 11  x
13 14  x 16 17  x
19  x  x 22 23  x
25  x  x 28  x  x
31  x  x 34  x  x
37  x  x 40  x  x
43  x  x 46  x  x

If we go y=2,z=1 now then it becomes 38 + 6n which is already taken. So we try another 20 If we assume y=0, z=2 then the equation becomes 40 + 6x = n

 1  2  3  4  5  x
 7  8  x 10 11  x
13 14  x 16 17  x
19  x  x 22 23  x
25  x  x 28  x  x
31  x  x 34  x  x
37  x  x  x  x  x
43  x  x  x  x  x
 x  x  x  x  x  x

If we assume y=1, z=2 then the equation becomes 40 + 9 + 6x = 49 + 6x = n

Hence N = 43.

fork: basic child processes - creating, waiting for and ending children

Here is basic example program demonstrating the use of forks and child processes.

The key points are;
  • Children processes are created with a call to fork, Fork returns:
    • A number less than 0(the Error code) on an error.
    • A number equal to 0 in the thread.
    • A number greater than to 0(the childs pid) in the main process.
  • A call to getpid() will return the pid of the child or parent process.

  • Keep in might the differences between a thread and process. The fundamental difference is that a thread shares all regions of memory except the stack where as a process shares none. In general memory is copied over the the child process as needed by the kernel.

//complie with; g++ fork.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <time.h>

struct BaseA
{
 pid_t pid;
 int number;
};

//The thread core...
void child_worker(BaseA* data)
{
 data->pid = getpid();

 for(int i = 0; i < 10; i++)
   {
     printf("Child %d @ %d \n", data->pid, data->number++);
     sleep(rand()%3000/1000);
   }

 printf("Child %d DONE!\n", data->pid);
 exit(0);
}

int main()
{
 srand(time(NULL));

 pid_t childPid;
 BaseA data;

 //setup the process
 data.number = 1;

 // create the threads
 childPid = fork();
 if (childPid >= 0) // fork ok
    if (childPid == 0) // Am I the kid
       child_worker(&data);
 childPid = fork();
 if (childPid >= 0) // fork ok
    if (childPid == 0) // Am I the kid
       child_worker(&data);

 //wait for all kids to complete
 wait(NULL);
 wait(NULL);

 printf("Parent %d DONE!\n", data.number);

 exit(0);
}

Tuesday, June 22, 2010

pthread: basic threading - creating, waiting for and ending threads

Here is basic example program demonstrating threads using the posfix threads library.

The key points are;
  • Threads are created with a call to pthread_create, the parameters are:
    • The threads handle, consider it to be the equivalent of a file handle.
    • The threads attributes. Normally the defaults are sufficient so use NULL, otherwise you might end up having to allocate the stack for it too.
    • The function pointer to the threads "main", if this routine exits or returns it will implicitly end the thread just like the pthread_exit call.
    • And a generic chunk of memory that is passed to the threads "main".
  • pthread_join; this takes the threads handle and simply blocks until it gets the signal that the thread has ended. The second parameter is a pointer to the location of where to store the pointer for the threads exit.. gezz look at the function definition its more easy to understand than a written description of it.
  • pthread_exit: This is the thread equivalent of exit but it can return a pointer to a complex piece of data.

And here is the sample code its really simple and just a brush up on threads for now
//complie with; g++ thread.cpp -lpthread
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

struct BaseA
{
 pthread_t handler; //the handle to the thread.. a little dangerous!
 int number;
};

//The thread core...
void* thread_worker( void *ptr )
{
 BaseA *data = (BaseA*)ptr;

 for(int i = 0; i < 10; i++)
   {
     printf("Thread %d @ %d \n", data->number, i);
     sleep(rand()%3000/1000);
   }

 printf("Thread %d DONE!\n", data->number);
 pthread_exit(NULL);
}

int main()
{
 srand(time(NULL));

 BaseA data[2];

 //setup the threads
 data[0].number = 1;
 data[1].number = 2;

 // create the threads
 pthread_create (&data[0].handler, NULL, &thread_worker, (void *) &data[0]);
 pthread_create (&data[1].handler, NULL, &thread_worker, (void *) &data[1]);

 //wait for all kids to complete
 pthread_join(data[0].handler, NULL);
 pthread_join(data[1].handler, NULL);

 exit(0);
}

strace - Debugging a live misbehaving process.

Often when a server is live you dont have the luxury of installing a debug-able version and stepping through its code when the problem appears. Other times you need to get a hold on whatever is killing a program that you never even wrote.

Enter "strace" this tool watches the system calls of a process and dumps it to your console for analysis. strace is not for the faint at heart. You need to know about how shells operate, how dynamic linked libraries are loaded and based and how kernel system calls pass in and out of system. On the flip side if you have never seen it before its a real eye opener. The average programmer most likely just doesn't realize how involved the kernel is with your little program.

To execute it on a program from scratch
strace -v <filename>
Note the "-v" gives you information about the environment variables that are passed from the shell to the new process.

To attach to a live process (you'll need to match the processes privilege level or better)
strace -p <process_id>

Here are some more resources on it:
http://www.redhat.com/magazine/010aug05/features/strace/
http://linux.die.net/man/1/strace

ok and here is an strace of ls in an empty directory so you can clearly see that simple isnt really that simple! (PS I seem to have a problem with my locales is polluting the result)
~/tmp> strace ls ./

execve("/bin/ls", ["ls", "./"], [/* 42 vars */]) = 0
brk(0)                                  = 0x61a000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7da0f51000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7da0f4f000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/home/ashley/obj-mail-release-NDEBUG/dist/bin/tls/x86_64/librt.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/home/ashley/obj-mail-release-NDEBUG/dist/bin/tls/x86_64", 0x7fff25ef42d0) = -1 ENOENT (No such file or directory)
open("/home/ashley/obj-mail-release-NDEBUG/dist/bin/tls/librt.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/home/ashley/obj-mail-release-NDEBUG/dist/bin/tls", 0x7fff25ef42d0) = -1 ENOENT (No such file or directory)
open("/home/ashley/obj-mail-release-NDEBUG/dist/bin/x86_64/librt.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/home/ashley/obj-mail-release-NDEBUG/dist/bin/x86_64", 0x7fff25ef42d0) = -1 ENOENT (No such file or directory)
open("/home/ashley/obj-mail-release-NDEBUG/dist/bin/librt.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/home/ashley/obj-mail-release-NDEBUG/dist/bin", 0x7fff25ef42d0) = -1 ENOENT (No such file or directory)
open("/home/ashley/obj-mail-debug/dist/lib/tls/x86_64/librt.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/home/ashley/obj-mail-debug/dist/lib/tls/x86_64", 0x7fff25ef42d0) = -1 ENOENT (No such file or directory)
open("/home/ashley/obj-mail-debug/dist/lib/tls/librt.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/home/ashley/obj-mail-debug/dist/lib/tls", 0x7fff25ef42d0) = -1 ENOENT (No such file or directory)
open("/home/ashley/obj-mail-debug/dist/lib/x86_64/librt.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/home/ashley/obj-mail-debug/dist/lib/x86_64", 0x7fff25ef42d0) = -1 ENOENT (No such file or directory)
open("/home/ashley/obj-mail-debug/dist/lib/librt.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/home/ashley/obj-mail-debug/dist/lib", 0x7fff25ef42d0) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=102124, ...}) = 0
mmap(NULL, 102124, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7da0f36000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/librt.so.1", O_RDONLY)       = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240#\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=35784, ...}) = 0
mmap(NULL, 2132968, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7da0b2c000
mprotect(0x7f7da0b34000, 2093056, PROT_NONE) = 0
mmap(0x7f7da0d33000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x7000) = 0x7f7da0d33000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/libselinux.so.1", O_RDONLY)  = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240Q\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=109368, ...}) = 0
mmap(NULL, 2209176, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7da0910000
mprotect(0x7f7da0929000, 2097152, PROT_NONE) = 0
mmap(0x7f7da0b29000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19000) = 0x7f7da0b29000
mmap(0x7f7da0b2b000, 1432, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7da0b2b000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/libacl.so.1", O_RDONLY)      = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220\33\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=27600, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7da0f35000
mmap(NULL, 2122744, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7da0709000
mprotect(0x7f7da070f000, 2097152, PROT_NONE) = 0
mmap(0x7f7da090f000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6000) = 0x7f7da090f000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/libc.so.6", O_RDONLY)        = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\342"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1436976, ...}) = 0
mmap(NULL, 3543672, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7da03a7000
mprotect(0x7f7da04ff000, 2097152, PROT_NONE) = 0
mmap(0x7f7da06ff000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x158000) = 0x7f7da06ff000
mmap(0x7f7da0704000, 17016, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7da0704000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/libpthread.so.0", O_RDONLY)  = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260W\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=130224, ...}) = 0
mmap(NULL, 2208624, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7da018b000
mprotect(0x7f7da01a1000, 2097152, PROT_NONE) = 0
mmap(0x7f7da03a1000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16000) = 0x7f7da03a1000
mmap(0x7f7da03a3000, 13168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7da03a3000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/libdl.so.2", O_RDONLY)       = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 \16\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=14624, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7da0f34000
mmap(NULL, 2109728, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d9ff87000
mprotect(0x7f7d9ff89000, 2097152, PROT_NONE) = 0
mmap(0x7f7da0189000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7f7da0189000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/libattr.so.1", O_RDONLY)     = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000\21\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=16128, ...}) = 0
mmap(NULL, 2111240, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d9fd83000
mprotect(0x7f7d9fd87000, 2093056, PROT_NONE) = 0
mmap(0x7f7d9ff86000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7f7d9ff86000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7da0f33000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7da0f32000
arch_prctl(ARCH_SET_FS, 0x7f7da0f32780) = 0
mprotect(0x7f7da06ff000, 12288, PROT_READ) = 0
munmap(0x7f7da0f36000, 102124)          = 0
set_tid_address(0x7f7da0f32810)         = 15691
set_robust_list(0x7f7da0f32820, 0x18)   = 0
futex(0x7fff25ef4e0c, 0x81 /* FUTEX_??? */, 1) = 0
rt_sigaction(SIGRTMIN, {0x7f7da01902d0, [], SA_RESTORER|SA_SIGINFO, 0x7f7da01997d0}, NULL, 8) = 0
rt_sigaction(SIGRT_1, {0x7f7da0190350, [], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x7f7da01997d0}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM_INFINITY}) = 0
brk(0)                                  = 0x61a000
brk(0x63b000)                           = 0x63b000
open("/etc/selinux/config", O_RDONLY)   = -1 ENOENT (No such file or directory)
statfs("/selinux", 0x7fff25ef3d30)      = -1 ENOENT (No such file or directory)
open("/proc/mounts", O_RDONLY)          = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7da0f4e000
read(3, "rootfs / rootfs rw 0 0\nnone /sys"..., 1024) = 1024
read(3, "server1/public /home/ashley/file"..., 1024) = 537
read(3, "", 1024)                       = 0
close(3)                                = 0
munmap(0x7f7da0f4e000, 4096)            = 0
open("/usr/lib/locale/locale-archive", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/locale.alias", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2586, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7da0f4e000
read(3, "# Locale name alias data base.\n#"..., 4096) = 2586
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7f7da0f4e000, 4096)            = 0
open("/usr/lib/locale/en_US.UTF-8/LC_IDENTIFICATION", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_IDENTIFICATION", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=373, ...}) = 0
mmap(NULL, 373, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7da0f4e000
close(3)                                = 0
open("/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=25700, ...}) = 0
mmap(NULL, 25700, PROT_READ, MAP_SHARED, 3, 0) = 0x7f7da0f47000
close(3)                                = 0
futex(0x7f7da0703f40, 0x81 /* FUTEX_??? */, 2147483647) = 0
open("/usr/lib/locale/en_US.UTF-8/LC_MEASUREMENT", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_MEASUREMENT", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=23, ...}) = 0
mmap(NULL, 23, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7da0f46000
close(3)                                = 0
open("/usr/lib/locale/en_US.UTF-8/LC_TELEPHONE", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_TELEPHONE", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=59, ...}) = 0
mmap(NULL, 59, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7da0f45000
close(3)                                = 0
open("/usr/lib/locale/en_US.UTF-8/LC_ADDRESS", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_ADDRESS", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=155, ...}) = 0
mmap(NULL, 155, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7da0f44000
close(3)                                = 0
open("/usr/lib/locale/en_US.UTF-8/LC_NAME", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_NAME", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=77, ...}) = 0
mmap(NULL, 77, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7da0f43000
close(3)                                = 0
open("/usr/lib/locale/en_US.UTF-8/LC_PAPER", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_PAPER", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=34, ...}) = 0
mmap(NULL, 34, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7da0f42000
close(3)                                = 0
open("/usr/lib/locale/en_US.UTF-8/LC_MESSAGES", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_MESSAGES", O_RDONLY) = 3
fstat(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
close(3)                                = 0
open("/usr/lib/locale/en_US.utf8/LC_MESSAGES/SYS_LC_MESSAGES", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=52, ...}) = 0
mmap(NULL, 52, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7da0f41000
close(3)                                = 0
open("/usr/lib/locale/en_US.UTF-8/LC_MONETARY", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_MONETARY", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=286, ...}) = 0
mmap(NULL, 286, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7da0f40000
close(3)                                = 0
open("/usr/lib/locale/en_US.UTF-8/LC_COLLATE", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_COLLATE", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=921214, ...}) = 0
mmap(NULL, 921214, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7da0e51000
close(3)                                = 0
open("/usr/lib/locale/en_US.UTF-8/LC_TIME", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_TIME", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2451, ...}) = 0
mmap(NULL, 2451, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7da0f3f000
close(3)                                = 0
open("/usr/lib/locale/en_US.UTF-8/LC_NUMERIC", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_NUMERIC", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=54, ...}) = 0
mmap(NULL, 54, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7da0f3e000
close(3)                                = 0
open("/usr/lib/locale/en_US.UTF-8/LC_CTYPE", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_CTYPE", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=254076, ...}) = 0
mmap(NULL, 254076, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7da0e12000
close(3)                                = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=46, ws_col=156, ws_xpixel=0, ws_ypixel=0}) = 0
stat("./", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open("./", O_RDONLY|O_NONBLOCK|O_DIRECTORY|0x80000) = 3
fstat(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
fcntl(3, F_GETFD)                       = 0x1 (flags FD_CLOEXEC)
getdents(3, /* 2 entries */, 4096)      = 48
getdents(3, /* 0 entries */, 4096)      = 0
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
Process 15691 detached