PHP: Simple directory recursion

Keep running into scenarios where I need to scan through a file system and it’s actually pretty simple if you just know what classes to use. So… note to self and others:

// This should return false if there is something you want excluded
function filter($file, $key, $iterator)
{
    $exclude = array('.git');
    return ! in_array($file->getFilename(), $exclude);
}

// Recursive directory iterator for current directory, ignoring dots
$it = new RecursiveDirectoryIterator('.', FilesystemIterator::SKIP_DOTS);
// Wrapped by a filtering iterator with our filter function
$it = new RecursiveCallbackFilterIterator($it, 'filter');
// Wrapped by an iterator which automatically traverses children for us
$it = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::SELF_FIRST);

// And then just loop :)
foreach($it as $file)
{
    echo str_repeat("\t", $it->getDepth())
        . $file->getRealPath()
        . PHP_EOL;
}

This skips the annoying dots, properly excludes directories you don’t want and pretty much works the way it should.

XSLT: Load XML or other text from external sources

Just discovered you can pull in external XML and other kinds of text directly through standard XSLT 2.0 methods. So here’s a note to self on how.

Documentation

Example usage

<!-- Single string URI -->
<copy-of select="doc('http://www.w3schools.com/xml/note.xml')"/>

<!-- One or more URI from items, in this case a variable -->
<variable name="uri" select="'http://www.w3schools.com/xml/note.xml'"/>
<copy-of select="document($uri)"/>

<!-- Unparsed text, in this case escaped HTML -->
<copy-of select="unparsed-text('http://example.com')"/>

Unix: Remove lines from a file based on regular expression

Just a note to self. Useful for trimming away useless information from a log file for example.

# Output result
$ sed "/pattern/d" file.log

# Overwrite file
$ sed "/pattern/d" file.log > file.log

# Inplace deletion (requires GNU sed)
$ sed -i "/pattern/d" file.log

In the pattern, things like capturing groups and alternations needs to be escaped with a slash, \. If you have RegexBuddy you can use the GNU BRE flavor to help you construct the pattern.

Source: StackOverflow

Solaris utilization

Commands for checking various utilization on Solaris. Notes to self, based on this, this, and this. The sar command depends on regular collection of data by sa1 and sa2 commands. See bottom of post for how to set that up.

  • top (various)
  • vmstat (various)
  • mpstat (per CPU)
  • sar (see below)

Sar switches

-u  CPU utilization
-a  File access
-d  Disk activity
-b  Buffer activity
-c  System call statistics
-g  Page-out and memory
-r  Unused memory
-k  Kernel memory allocation
-m  Interprocess communication
-p  Page-in activity
-q  Queue activity
-v  System table activity
-w  Swapping activity
-y  Terminal activity
-A  Overall system performance

For what output means, see this page.

Real-time gathering

You can add interval and count to the vmstat, sar and mpstat commands to collect statistics real-time. For example

# Collect CPU usage in 10 second intervals, 60 times
$ sar -u 10 60
# Collect CPU usage in 10 second intervals indefinitely
$ sar -u 10

Setup of sar

Some sar commands depends on sa1 and sa2 collecting data regularly. If not setup, you’ll get the following error when running various sar commands (XX=todays date).

$ sar
sar: can't open /var/adm/sa/saXX

To set it up you need to edit the crontab of the sys user.

$ su
su sys
EDITOR=vi
export EDITOR
♯ crontab -e

The sys crontab should already contain samples which you could just uncomment.

# System performance snapshot every hour
0 * * * 0-6 /usr/lib/sa/sa1
# System performance snapshot every 20 minutes, Monday through Friday between 8 and 17
20,40 8-17 * * 1-5 /usr/lib/sa/sa1
# ASCII report at 6:05, Monday through Friday
5 18 * * 1-5 /usr/lib/sa/sa2 -s 8:00 -e 18:01 -i 1200 -A

Following is a more straight forward version.

# System performance snapshot every 15 minutes
0,15,30,45 * * * 0-6 /usr/lib/sa/sa1
# ASCII report every day at 23:55
55 23 * * 0-6 /usr/lib/sa/sa2 -A

After editing, save the file and data should start being collected.

XSLT: Pull duplicate namespace declarations up towards root node

Sometimes XML becomes a bit weird with namespace declarations all over the place. This XSLT cleans that up. Stumbled upon in a StackOverflow answer I don’t find anymore and put here so I know where to find it in the future.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="@* | text() | processing-instruction() | comment()">
        <xsl:copy/>
    </xsl:template>

    <xsl:template match="*">
        <xsl:copy copy-namespaces="no">
            <xsl:for-each-group group-by="local-name()" select="descendant-or-self::*/namespace::*">
                <xsl:copy-of select="."/>
            </xsl:for-each-group>
            <xsl:apply-templates select="@* , node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Example

Input

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
   <soap:Header>
      <wsa:MessageID soap:mustUnderstand="0">uuid:7fa12310-5db4-11e3-ae24-a3c913f2629d</wsa:MessageID>
      <wsa:To soap:mustUnderstand="0">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
   </soap:Header>
   <soap:Body>
      <ns1:getTicket xmlns:ns1="http://api.example.com/some-webservice">
         <cus:msisdn xmlns:cus="http://api.example.com/some-webservice" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">00000000</cus:msisdn>
         <cus:ticket xmlns:cus="http://api.example.com/some-webservice" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">171</cus:ticket>
      </ns1:getTicket>
   </soap:Body>
</soap:Envelope>

Output

<soap:Envelope xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
       xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
       xmlns:ns1="http://api.example.com/some-webservice"
       xmlns:cus="http://api.example.com/some-webservice"
       xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header>
        <wsa:MessageID soap:mustUnderstand="0">uuid:7fa12310-5db4-11e3-ae24-a3c913f2629d</wsa:MessageID>
        <wsa:To soap:mustUnderstand="0">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
    </soap:Header>
    <soap:Body>
        <ns1:getTicket>
            <cus:msisdn>00000000</cus:msisdn>
            <cus:ticket>171</cus:ticket>
        </ns1:getTicket>
    </soap:Body>
</soap:Envelope>

If anyone know how to adjust it to also merge the duplicated prefixes ns1 and cus, do let me know :)

Tractor speeds in Farming Simulator 2013

Nothing attached, full speed straight ahead on flat road, these are the speeds of all the tractors available in Farming Simulator 2013 including Official Expansion, Classics and Ursus.

Name

Top speed (mph)

kW
Deutz 7250 Agrotron TTV

37

194
Deutz Agrotron X 720

32

202
Case IH Puma 160

32

149
Deutz 6190 Agrotron TTV

32

142
Deutz Agrotron M 620

32

114
Ursus 15014

32

111
Deutz 430 Agrotron TTV

32

104
Huerlimann XL 130

32

104
Deutz Agrotron K 420

32

73
Case IH Magnum 340

26

286
Case IH Quadtrac 600

25

492
Case IH Steiger 600

25

492
Schlueter Super Trac 2500 VL

25

179
Buehrer 6135 A

25

100
Lamborghini R4.110 Italia

25

81
Ursus 11024

25

80
Lindner Geotrac 94

25

75
SAME Explorer3 105

25

75
Ursus 8014H

25

61
SAME Argon3 75

25

55
Kramer KL 600

20

45
Ursus C-330

20

22
Ursus 5044

20

37
Kramer KL 200

13

13
Ursus C-45

12

33
IH Farmall H

11

18

Tail less

I keep seeing people typing these lines in the console:

$ tail /path/to/some.log
$ tail -f /path/to/some.log

This is often a dumb thing to do. Why? Because you can’t really do anything with tail. What if you discovered you needed to look at something right above the lines you got printed out? Or what if you were -f’ing and something flew past you that you needed to investigate further? You’d have to leave tail and run it again with more lines or use a different tool instead. Not very practical.

What more people should do is to use less tail and more less :)

$ less /path/to/some.log

Things you can do with less

Key

Function

Up one line

Down one line
b

Up one page
space

Down one page
g

Beginning of file
G

End of file
F

Follow
ctrl + c

Stop follow
q

Quit
/

Search forward
?

Search backwards
n

Next search result
N

Previous search result

Much more flexible and handy than tail! Know your tools ;) Now back to work…

With a hint of Social Ineptitude