Anti-nuisance lawsuit warning: The purpose of these notes is to remind me, Zoegond, of stuff or to help me work stuff out. They may contain mistakes.

Quick

  • ($a, $b....) = unpack("A2A7...", $packed)
  • push( array, list )

Tuesday, December 21, 2010

LWP::UserAgent

A UserAgent will not handle cookies unless you tell it to, by assigning it an empty cookie jar:

$Ua->cookie_jar( {} );

Perl HTML parsing - text nodes

As far as I can see, text nodes are accessed via the HTML::Element content_list method: this returns a list of child nodes. The members of this list are either HTML::Element object references, or strings of text.

HTML::Element also has as_text which returns all text under a node.

Monday, December 20, 2010

Perl HTML parsing - look_down

look_down is a method of HTML::Element.

If an attr_value parameter is a qr() then it is supposed to do a regexp match for you, but I couldn't make this work. I had to use

$link = $root->look_down( _tag => 'a', sub { $_[0]->attr('title') =~ qr(^Cool); } );

instead of

$link = $root->look_down( _tag => 'a', title => qr(^Cool) );

Thursday, December 16, 2010

Perl bitwise operators

Beware - Perl is not SQL, and == has higher precedence than &, so if you have this

if ($flags & 3 == 3)

you are not performing a useful test. Parenthesise

if ( ($flags & 3) == 3)

Thursday, November 25, 2010

Exporting OpenOffice Base query results

It seems the only way to do this is

1. Select the query name in the list of queries, and Copy
2. Paste into a new Calc spreadsheet

You cannot paste into Excel this way, and you cannot copy from the query results grid like you'd expect. Even if you select all on the results grid by clicking at top left, and Copy, only one cell gets copied to the clipboard.

NB that if you have put a filter on the query, although it will show in data table view, it will not be applied to the export.

I don't know why 'free' has to mean 'bizarre'. I'd expect copying the query name to copy the SQL source, not the output.

Tuesday, November 23, 2010

Greasemonkey sandbox

You do need to pay attention to all that 'sandbox' stuff as it means some actions which you might expect to be able to do are not allowed:

You can't change/delete global variables
without using the 'location hack'.

Friday, November 19, 2010

IFRAME

An event listener in the parent document, or the parent window, is not triggered by events in a child iframe.

Thursday, November 18, 2010

C# String

If you index into a string

s[i]

what you get is a char, not a 1-character string.

Wednesday, November 17, 2010

getElementsBy...

Element only has the getElementsByTagName[NS]() methods, not the other getElementsBy... ones.

Javascript array/object

You can't use .length to get the property count of an Object. It only works for genuine arrays.

JScript

Most of the time with JScript you are working with Windows objects and concepts rather than Javascript ones. Particularly note that you have to use the VB 'Collection' syntax, eg

WScript.Arguments.Item(0)

not

WScript.Arguments.Item[0]


(the latter will silently fail).

Yes, you can say

WScript.Arguments(0)

but that's just too unJavascriptish for me, I prefer to spell it out at length.

Monday, November 15, 2010

iframe

iframe elements have a .contentWindow - but this property doesn't have a value until the iframe has been placed in the document. Once it has, you refer to

ifr.contentWindow.document.body

to get stuff done.

Getting elements

getElementsByTagName returns a NodeList, which has .length and can be indexed into with [], or item() if you prefer.

XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE returns (an object) which has .snapshotLength and has to be indexed with snapshotItem(). The types of the objects returned by snapshotItem() depend on what tags they represent, eg HTMLLIElement, HTMLBodyElement; but these objects are all descendants of HTMLElement, Element and Node, so they can be supplied as the context node to another invocation of document.evaluate.

Insofar as JS has a type hierarchy, then a specific HTML element type, eg HTMLDivElement, 'is' a HTMLElement and a HTMLElement is an Element, and an Element is a Node.

NB that getElementById is so spelt (singular) and returns an Element, not a NodeList with 1 item. It genuinely expects there to be only one element with a given 'id'.

Friday, November 12, 2010

IFRAME

If you have an iframe element its document is accessible via the contentDocument property.

textContent

textContent appears to be a perfectly pukka, DOM-specified way of getting the text of all the text nodes under an element (ie including text from child elements).

It's node.textContent btw.

It can be set as well as read - but will destroy all child nodes in the process of replacing them with one big text node.

bookmarklets

The reason bookmarklet links in web pages have void() round them is that void is a JS keyword which evaluates its argument and doesn't return anything (or returns undefined according to who you believe). If this is not used, the browser will replace the document in which the javascript: link was evaluated, with the result of the evaluation, which is generally not what you want.

NB that while javascript: URLs can contain whole chunks of code, void expects an expression, not a block or series of statements. So code of any complexity inside void needs to be inside an anonymous function evaluation.

While I'm on, the anonymous function syntax is thus

(function () { code; more code; })()

From the inside out, you have a block of code in {}, which is being used to construct a function with no arguments - function () - and that function definition has ( ) round it, and then it is being evaluated with no arguments, hence the trailing ().

Btw Firefox will take quite a lot of text in a javascript: URL. You can paste it in from a file with line breaks etc and FF doesn't care.

However, using a drop-line comment // seems to give it a headache. It probably thinks you're trying to say javascript://blah .

C-style block comments seem fine though.

Wednesday, November 10, 2010

Document

The Document class is designed to model HTML and XML documents. Stuff specific to HTML ones is modelled in the HTMLDocument interface.

(Interface is in the usual modern sense of a set of methods, properties etc which a class can implement, without having to be a subclass of anything).

Friday, November 5, 2010

Eyepieces

F = focal length of main (objective) lens/mirror
D = aperture thereof
f = focal length of eyepiece

magnification M = F/f

focal ratio = F/D (this is the quantity photographers quote as f/10 etc))

exit pupil = f / (F/D) = fD / f

actual field of view = (apparent field of view) / M

(eg if eyepiece has an apparent field of 55 deg, and its focal length gives it a magnification of 40x with your telescope, actual field of view - ie the size of the bit of sky you can see - is 55/40 = 1.38 deg, or well over 2 Moon-widths)

Monday, November 1, 2010

Text nodes

The text in a text node is in its data property.

(data is actually CharacterData.data. You can also use nodeValue, which is Node.nodeValue).

Element.textContent is the amalgamated text of all the text nodes under an element, at all levels.

Node.TEXT_NODE will show up as 3 in Firefox from javascript: , but appears to be undefined in Greasemonkey context.

Wednesday, October 20, 2010

\b in regular expressions

You cannot match a string, which starts with a non-word character, at a word boundary.

$staff = "Elgin \@Stevens BOSS"; # Elgin @Stevens BOSS

s/\b\@Stevens/Dr Stevens/;

Nothing happens because \b is defined as a change from \W to \w, which by definition cannot occur between space and @, because @ is \W.

Friday, October 15, 2010

Perl typeglobs and symbol table

*a represents the symbol table entry for a, ie a hidden binary structure that, when it's prefixed with $, @ etc, or used in filehandle context etc, the appropriate element is selected and used.

$::{'a'} does basically the same thing.

You can do a dereference on $::{'a'}, or indeed in this situation

$a = 9; *b = *a; print ${*b};

though I don't know whether this works because typeglobs and references are really interchangeable or whether some kind of soft dereferencing is happening automatically to make this work.

(The Perl 4 programming book says that %_main holds the symbol table for package main, but this doesn't seem to work now. Presumably $:: replaced it.)

Advanced Perl Programming says that assigning a reference to a typeglob

$a = 9; *b = \$a;

will change only the appropriate part of *b to a reference to $a. Ie after the above example, $b will be 9 but @b, %b etc will be unaffected.

The suggestion in APP is the sub-elements inside a typeglob are references, which is why the above would work, but it doesn't say that explicitly.

Tuesday, October 12, 2010

Google obfuscation

The key to Google's new obfuscation is the Search button - when this is clicked, the search request and all subsequent search requests return JSON which is, I think, then formed into a new results page, rather than fetching a new URL. This means that any Greasemonkey script won't get to run on the new results.

The key then is to make all searches avoid the Search button, by putting different code of our own behind it and also behind the paging buttons.

Tuesday, October 5, 2010

Javascript this

this refers to the 'owner' of the function in which it occurs.

In the page context this is the window or global object, in a property context it is the object (the object whose property it is).

NB that inline HTML property definitions, eg <element onclick="func()"> are in the page context (probably not what you want if func refers to this).

Thursday, September 23, 2010

RAISERROR

raiserror( { msg_id | msg_string }, severity, state)

msg_id typically >=50000
severity 0..16
state 0..255 (location identifier)

Thursday, September 16, 2010

Perl package 'constants'

If you use variables as 'constants', and you want to use them in a package, they should be defined in a BEGIN block inside the package, which (I think) is run as soon as the package is parsed by Perl.

package Map;
{
use Carp;

local ($s);

BEGIN {
$s = sqrt(2);
}
}

I think this is the same problem I recently came across here - if you define your 'constants' in the outermost scope of the package, you won't find them set when your script runs. It seems like they get re-initialised to undef at some point after they're defined.

(Btw in modern versions of Perl the 'use constant' pragma is a much better way of defining constants.)

Tuesday, August 31, 2010

Array slices

NB the syntax for slices is

@a[1,2]

If you use $a[1,2] you'll just get $a[1] (-w gives a 'Multidimensional syntax not supported' warning).

Further note that @a[m,n] just returns elements m and n, not all elements from m to n. Use m..n for the latter (note that, as with all Perl ranges, both ends of the range must be specified).

Thursday, August 26, 2010

Perl, the clipboard and \n

If you copy stuff onto the clipboard, and then run Perl on the data (perhaps using pclip) you'll find that each line ends with 0D 0A (shown as \cM\cJ in the debugger).

chop (and chomp) only remove the 0A, not the 0D. Similarly, split(/\n/) splits on the 0A and leaves you with an array of strings each ending in 0D.

Perl's treatment of \n is very confusing, I thought that "\n" in Perl meant 0A or 0D 0A according to which platform you were on, but apparently not.

I just do another chop to get the 0D off each line - chomp does not appear to regard 0D as \n, and won't remove it.

Tuesday, August 3, 2010

.NET text file read

TextReader inpf;
inpf = new StreamReader("file");
inl = inpf.ReadLine(); // null if none left
inpf.Close();

You can also create a FileStream (as this allows Seek) and then construct a StreamReader from the FileStream (FileStream doesn't have ReadLine).

NB that the string returned by ReadLine does not have a newline on the end.

.NET text file write

Quick text file open and write:

TextWriter outf;
outf = new StreamWriter("file");
outf.WriteLine("Hello");
outf.Close();

It's possible to have the StreamWriter creation in one branch, and

outf = Console.Out;

in another, so program can be switched between stdout and file write.

Monday, August 2, 2010

C# structs

Not quite like C structs:

struct DayAnalysis { public DateTime date; public int minutes; public string lasttime;
public int ndays; public int sminutes; };
DayAnalysis DayAna = new DayAnalysis();

Friday, July 30, 2010

mingw and gcc

If you want to use API calls you need to do two things:

- include the right header file so C/C++ knows the function prototypes for the calls, and the types and structures that they use as parameters
- link in the right library file (.a files in .\lib), which I'm guessing contains the object code that actually implements the calls. There appears to be a 1:1 .a file/.dll file correspondence.

Eg to use GetDeviceCaps in gdi32.dll, you need to include wingdi.h and link to libgdi32.a by adding -lgdi32 to your gcc invocation.

If you're just calling stuff from user32.dll (definitions in windows.h) you don't seem to need to say -luser32. Looking into this further with the very helpful -v compiler switch, I see that gcc links to the following libraries by default

-lmingw32 -lgcc -lmoldname -lmingwex -lmsvcrt -luser32 -lkernel32 -ladvapi32 -lshell32 -lmingw32 -lgcc -lmoldname -lmingwex -lmsvcrt

Indeed I see that it does this for the simplest hello.c program, even without windows.h being included. That's not a complaint, I just want to know how it is.

mingw linking

Suppose mygdiprog.cpp includes wingdi.h and uses various API calls implemented via gdi32.dll

g++ -lgdi32 mygdiprog.cpp

will throw up errors for the API calls along the lines of 'undefined reference to GetDeviceCaps@8''.

You must place -lgdi32 (which means 'link in stuff from lib\libgdi32.a') after the source file name

g++ mygdiprog.cpp -lgdi32

(This is why -mwindows makes it work, because -mwindows adds a load of -l options, and it puts them in the right place on the command line.)

Tuesday, July 27, 2010

Javascript Date

Javascript Dates appear to adjust themselves automatically for (US) daylight savings time. Eg

dateInTheDSTPeriod - dateBeforeTheDSTPeriod

will not be a round number of days if both dates represent midnight (because Javascript thinks that by 'midnight' on dateInTheDSTPeriod you mean 0000 BST, 2300 GMT).

Often with astronomy you mean 0000 GMT in the above example, and your date calculations will be an hour off. Get round this by using the ..UTC... versions of all relevant Date methods.

Incidentally, you can add n days to a Date by doing setDate(d.getDate() + n) . I don't know if there's any limit to n but it certainly works up to 366 days.

(Yes, getDate means 'getDayOfMonth', so we are adding n days to the day of month).

NBB A Date is an object: if you assign d2=d1, d2 is the same object as d1, and if d1's properties change, so will d2's, and vice versa. Bit annoyed with myself for not realising that tbh.
The way to shallow copy is d2 = new Date( d1.valueOf() ) .

Monday, July 19, 2010

.CUE files and burnatonce

To start referring to a new source file, simply add another FILE line. Track numbering should continue in sequence (not start again from 01).

Don't forget that for after each FILE line, you probably want a track with INDEX 01 00:00:00 . It's easy to miss it out and start with the position of the 2nd track.

The time fields are mm:ss:cc (cc being hundredths, not 'frames').

burnatonce seems to expect TITLE lines - with the title in quotes - both for tracks and the disc as a whole. Specify "" if necessary.

burnatonce doesn't object to the omission of AUDIO after TRACK nn.

burnatonce will not process files with tabs. Use spaces to indent.

burnatonce uses the actual size of the audio files specified, if your CUE file mistakenly contains a track that starts beyond the end of the file then that track is ignored.

burnatonce occasionally thinks a file is slightly longer than it is - seems to happen when the file is a fraction of a second shorter than an integer number of minutes, eg 26:59.68 . It will then put up an "0 MB to be written to disc" message box when Write is clicked. If you answer OK the log will contain a complaint that it's trying to go past the end of the file. The way to fix this is to right-click the last track of the offending file in Audio Mastering, choose Properties and make the length slightly shorter - 0.01 second is often enough, but if it isn't, try slightly larger reductions till burnatonce accepts it.

Javascript substring

String.substring(n1, n2) is not like typical substring functions - firstly, n2 is a character index, not a length, and secondly, it's the index of the first character not to include in the substring.

Both indexes are 0-based btw.

Tuesday, July 13, 2010

In the context of Google Spreadsheet timed triggers, the active sheet is the one that the script is part of. It doesn't matter whether it's open at the time the trigger runs.

Friday, July 9, 2010

Javascript reminders

Array length is in length (not Length or Count) and it is a property, not a method.

for (v in a) { } loops through the property names of a - if a is an array, each value of v is an element index, eg 0,1,2... , because array elements are basically object properties.

If you want the element values, which is what you'd expect coming from Perl, say, use a numeric loop, or this construction

for (v in a) { do_something( a[v] ); }

String indexing starts at character position 0.

Thursday, July 8, 2010

Getting rid of the Title in Sharepoint lists

1. Go into (list)/General Settings/Advanced Settings
2. Set 'Allow management of content types?' to Yes
3. Back on the Customise page, a Content Types list is now visible. Click on the Item item.
4. Click on Title
5. Set Column Settings to Hidden.
6. Go back to Go into Customise/General Settings/Advanced Settings and set ''Allow management of content types?' back to No
7. Title will now not appear when list items are edited.
8. But it will still show on the Default View until you modify the latter to hide it.
9. You will probably also want to add the 'Edit' dummy column to the default view in column 1, if like me you're used to clicking Title to edit list items.
10. You can also add the 'ID' column to the default view if you aren't using your own unique identifier.

http://social.technet.microsoft.com/Forums/en/sharepointgeneral/thread/89042dd1-1960-4eaa-91c6-8a6d0ddab1a3, scroll down to JadeSerys' post

Friday, July 2, 2010

.NET system tray icons

//in form definition
NotifyIcon tray = new NotifyIcon();

//in constructor (after InitializeComponent [sic])
tray.Icon = new Icon("myiconfileinexecdir.ico");

//when you want to show it
tray.Visible = true;
tray.Text = "This text appears as a tooltip when mouse hovers over icon";

//hide it again
tray.Visible = false;

//to accept clicks on the icon
//
tray.Click += new System.EventHandler(tray_Click);
...
void tray_Click(object sender, System.EventArgs e) {
...
}

//to make the icon disappear immediately the form closes, set tray.Icon to null on closure

Thursday, July 1, 2010

sqlite dates

To get sqlite to parse a date string, including 'now', you have to use date() or datetime(). There is no automatic conversion.

sqlite is very particular about dates. This will work

date('1963-11-23')

but this won't

date('1963/11/23')

Also NB that datetime('10:21:00') will not default to today's date, but to Jan 1 2000.

And further NB that to subtract (etc) dates you must use julianday() to convert them to numeric values. Your difference will thus be in fractional days.

Incidentally they are proper Julian Day numbers which is handy for astronomy.


So let's be clear, datetime() converts a string to a standard format datetime representation string. It is these strings that are stored in datetime type fields.

Conversely, julianday() converts these strings into serial date numbers (specifically Julian Day numbers).

Wednesday, June 30, 2010

WF list/combo value and representation

If your list/combobox just has strings as items, you can get the selected value with .Text . But this restricts you to displaying and storing the same item (ie you can't have 'International Electromatics' in the display and be storing 'IE' behind the scenes).

To do the latter you need to define a class which defines methods for getting the value (IE) and the representation (International Electromatics) of its instances. Then you set the DataSource of the control to be an ArrayList of these objects. Finally you set the DisplayMember and ValueMember properties of the control to the names of the the class methods.

Now, the control's SelectedValue property will be the ValueMember of the object that is currently selected. NB that SelectedValue appears to return an object which you must cast to a string, not a string per se.

Fragmentary example:

ArrayList Availabletests = new ArrayList();
...
Availabletests.Add( new UnitTest( 1, "tryparse datetime(p)" ) );
Tests.DataSource = Availabletests;
Tests.DisplayMember = "Representation";
Tests.ValueMember = "Value";
...
Output.Text = Tests.SelectedValue.ToString();
...

public class UnitTest {
/*protected*/ private int number;
/*protected*/ private string description;

public UnitTest (int num, string desc) {
this.number = num;
this.description = desc;
}

public string Value {
get { return number.ToString(); }
}

public string Representation {
get { return number.ToString() + ": " + description; }
}

}


Properly explained example with US states in ListControl.DataSource

As always with .NET there's a lot of typing but I admit this is a nice flexible, modular way to go about it.

Thursday, June 17, 2010

null and not in

a not in (...) will exclude null values of a. Probably not what you want.

Thursday, May 27, 2010

m// in loop

If you loop over m//g, you get one iteration for each match.

$daleks = "Red Dalek Black Dalek Gold Dalek";
while ($daleks =~ /(\w+)\s+Dalek\b/g) {
if (++$count == 3) {
print "The third Dalek is a $1 Dalek.\n";
}
}

NB that $1 always refers to the current match here.

Apparently you shouldn't use 'last' to get out of a loop like this. Don't know why yet.

SQL window functions again

You can think of

window_function() over (partition by A,B,C [order by C,D,E])

as

'Within each group of records with a common A+B+C, return window_function [as if the rows were ordered by C,D,E] but don't group or sort the actual result rows in those ways'

I always mistakenly start by thinking that there is one window function result per A+B+C combination. There is not, there is one result per original query row.

In particular, the order by C,D,E here is an ordering of the original query rows within each group.

Wednesday, May 26, 2010

SQL window functions

Maybe these are easier to understand if you consider the degenerate case where no partition is specified - then the whole table is one partition:

select seqnum, count(*) over () from doctor

gives you count(*) repeated on each row, a bit like Sybase used to do if you missed out the group by.

select seqnum, row_number() over (order by seqnum) from doctor

gives you the sort order number for each row when sorted by seqnum

Similarly, window aggregation functions work without an order by:

select seqnum, count(*) over (partition by doctor_seqnum) from episode

gives (repeated for each episode for a particular Doctor) the number of episodes featuring that Doctor. (You couldn't do row_number() here because it requires a sort).

Thursday, May 13, 2010

POP3 (via C# .NET)

POP3 server responses end in "\r\n". Remember that "\n" in C# is just an 0A like in C, not an 0D 0A like in Perl. Check for this sequence at the end of the byte array you read from the SslStream - don't use the 'wait for a count of 0 bytes to be returned' method in a loop, as you will get a never-ending network wait with that.

Sending TOP m n elicits 3 server responses:
1. +OK
2. The headers, blank line and top n lines, all together
3. A full stop

Friday, April 30, 2010

.NET timers

To use a timer:

using System.Timers;
...
// NB put this next declaration at class level,
// not in a method where 'tick' will be
// garbage collected before it can fire
System.Timers.Timer tick;

...
tick = new System.Timers.Timer(10000);
// include the next line if you want event handler to interact with controls
// (eg setting text)
tick.SynchronizingObject = this;
tick.Elapsed += new ElapsedEventHandler(this.tickElapsed);
tick.Enabled = true;
...
void tickElapsed(object source, ElapsedEventArgs e)
{
...
}

If your timer is failing to eg set text on a control, check that you included the SynchronizingObject set.

Thursday, April 29, 2010

DataRow Field

DataRow.Field is both an instance method and a static method. Either way, the reason it keeps not compiling is that it's some kind of template which you have to supply with a type name, eg

therow.Field<string>("fieldname")

Wednesday, April 28, 2010

Insert into DataRowCollection

DataRowCollection.InsertAt(...) appears to do an insert-before, ie InsertAt(row, 0) results in /row/ being added at index 0.

To add after the last row, use index >= .Count .

Tuesday, April 27, 2010

.NET collections

.NET collections have 0-based indexing.

Saturday, April 24, 2010

C# constructors

One version of an overloaded constructor can call another thusly:

public class Doctor {

public Doctor(int incarnation) {
...
}

public Doctor(): this(1) {
...
}

}

ie Doctor() makes a call Doctor(1) - this happens before the body of Doctor() executes.

The colon syntax is the same as used for calling a base class constructor in an inheriting class.

C# properties

You can't have just a get or set accessor with auto properties (because without an underlying variable there's no way to perform the opposite operation even inside the class). But this is acceptable:

public int Regenerations { get; protected set; }

Btw, the expanded syntax is eg

public int Incarnation {
get { return _incarnation; }
set {
if (value == 4) DonScarf();
_incarnation = value;
}
}

Wednesday, April 21, 2010

.NET treeview

TreeView.Nodes works just like TreeNode.Nodes, ie it only returns its own immediate children (the top-level nodes).

C# foreach

The data type in foreach isn't just a shortcut, you have to use it:

foreach (int i in intarray)

It won't compile if you predeclare int i and just use (i in intarray) in the loop expression.

.NET treenode key

The reason a Treenode doesn't have a Key property as such is that the key (such as you can set with some of the Add methods) is also the Treenode's Name property. Apparently.

Tuesday, April 20, 2010

rank()

rank() over (partition by X... order by Y....) produces, for each row, its rank when all the rows are subdivided according to (basically, grouped by) fields X... and sorted within each subdivision by fields Y...

So if with this query

select story_name, episode, rating from episode

Space Museum,1,4
Space Museum,2,3
Space Museum,3,2
Space Museum,4,2
Castrovalva,1,3
Castrovalva,2,2
Castrovalva,3,4
Castrovalva,4,4

you wanted the episodes of each story to be ranked in order of rating, you'd specify

select story_name, episode, rating, rank() over (partition by story_name, episode order by rating desc) from episode

and get

Space Museum,1,4,1
Space Museum,2,3,2
Space Museum,3,2,3
Space Museum,4,2,3
Castrovalva,3,4,1
Castrovalva,4,4,1
Castrovalva,2,2,3
Castrovalva,1,3,4

NB that you get a sportsman's rank, not a mathematician's (two equal firsts get 1, not 2).

NB2 that you don't seem to have to specify all the candidate fields for partition, as you would with group by.

Monday, April 19, 2010

C# shell command

stdout capture example:

Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = @"/c reg query HKEY_CURRENT_USER\Software\Crapware\UniCrap /s";
p.Start();
string output = p.StandardOutput.ReadToEnd();

C# window interaction

The easiest way to do the window activation/control stuff that AutoIt and VB can is to add a reference to the Microsoft.VisualBasic assembly to your project.

You can then have code like

Microsoft.VisualBasic.Interaction.AppActivate("Calculator");

- SendKeys is already available in System.Windows.Forms, but there's no simple way in there to activate a window so as to send keys to it.

- SendKeys.Send won't work from a form constructor, there'll be a run-time error. Put it in the form Load event handler or anywhere 'later' - looks like the form has to be running and handling messages before it can send keys.

Sunday, April 18, 2010

VNC

NB that when running a listening viewer on your machine, you should have allowed incoming access to port 5500. There needs to be incoming access in at least one direction...

Wednesday, April 14, 2010

C# index out of bounds

Don't be lulled into a false sense of security by C#'s habit of throwing exception dialogues for file not found, etc. You can't always expect one - an array index out of bounds will still give you an old-fashioned crash, for example.

C# command line arguments

Windows app - the array returned by Environment.GetCommandLineArgs has the executable filename as element 0, ie it is CommandLine split up into an array.

BUT

Console app - args[0] is the first argument, not the executable name. So args[] is like Perl's @ARGV, and different from Environment.GetCommandLineArgs and from C's argv[].

Thursday, April 8, 2010

C# string indexes

First character of a string has index 0.

Monday, April 5, 2010

C# implicit conversion

Even in this scenario where b and c are both byte variables

c = b + 64;

C# converts the result of the calculation to int, and then complains that you're assigning int to byte. Casting 64 to (byte) doesn't help either, you have to say

c = (byte) (b + 64);

ffs.

Thursday, April 1, 2010

C# and static-ness

Deductively - in a console app, Program.Main is defined as static (presumably for a good reason) and if Main is static (= a class method, remember) then presumably all the other methods should be too.

And you can't refer to a non-static (instance) variable from a static method, because 'Object reference required' and /this/ isn't allowed in static methods.

So all the Program-level variables should be static.

Tuesday, March 30, 2010

Array declaration and initialisation

byte[] inbf = new byte[1024];

(Remember C# rarely lets you declare a variable without initialising it)

Monday, March 22, 2010

Path closing and filling

The area enclosed by an SVG path is filled in if the /fill/ attribute is anything other than "none".

Whether the path is closed or not (with z) does not affect filling, it only affects the strokes.

Thursday, March 11, 2010

SVG text

Experiments show that a line of SVG text has four strata or horizontal layers of equal height:

TOP QUARTER only used by descenders from the line above

UPPER CAPITAL QUARTER only used by upper parts of capitals, and ascenders

UPPER MINISCULE QUARTER midparts of capitals, and upper part of x-height

LOWER QUARTER lowest part of x-height

-------------

DESCENDER QUARTER (overlaps TOP QUARTER of line below
)


That's to say, if you specify your text to have font-size 6 then the space occupied by the four quarters will be 6 units, with each quarter taking up 1.5 units. Similarly you should use 6 as the dy when placing tspans to do multiple lines of text.

(It seems that while Arial follows this pattern, other fonts may not, any unfamiliar font should be experimentally displayed first for measurement).

Wednesday, March 10, 2010

StringBuilder

The way to replace the contents of a StringBuilder seems to be

sb.Length = 0;
sb.Append("New stuff");

string comparison

s1 == s2

is the same as saying

s1.Equals(s2)

and neither of them is a C++ 'is it exactly the same object' trap.

There is also Compare but I'm not clear as to the difference.

string concatenation

Concatenate strings with + . If you're doing this in a loop, you should be using a StringBuilder not a String (StringBuilder.append).

However, an expression like

s1 + s2 + s3 + s4

is apparently optimised by the compiler so that it is not done as three separate string copies.

Tuesday, March 9, 2010

exists

If you do a check like

if (exists($h->{a}{b}{c})) ...

$h->{a}{b}{c} won't be created as part of the check, but $h->{a} and $h->{a}{b} will. Beware!

Property calls on command results

To get a property of the object returned by a command, do thusly

(get-date).tofiletime()

NB that

(get-date).tofiletime

will get you the 'tofiletime' member itself, a bit like a function pointer in C and probably not what you want.

where-object

where-object takes a bit of code as a parameter. Context seems to be that $_ is the object. Alpha comparison operators are used.

gci | where-object { $_.length -lt 500 }

select-object

Despite its name select-object determines which properties ('columns') of the object are to be displayed.

gci | select-object length

Thursday, March 4, 2010

Perl filehandle manoeuvre

sub_me(*FH);

#

sub sub_me
{
local (*FHANDLE) = @_;

while (<FHANDLE>)
{
}
}

Tuesday, March 2, 2010

SVG text

If you place text at x,y then that's where the bottom left-hand corner of the body-part of the text will go. The main part of the letters extends upwards from x,y.

Don't let this make you forget that in SVG the grid runs the other way, ie the positive y-direction is downwards.

Monday, March 1, 2010

Perl for loops

for($n = 0; $n<10; ++$n) {
}
print $n;

will print 10, not 9. $n is incremented the last time control returns to the for - ++$n happens before the $n<10 check, because the loop control statement means

1. If this is the first iteration, $n = 0
2. if $n < 10, execute the loop body...
3. .. then ++$n
4. goto 1

Friday, February 26, 2010

Perl regular expressions and interpolation

Q. How to use, in a s/// substitution, a string defined elsewhere in your program, or supplied by the user, and that contains variable substitions/grouping references?

A. Use double evaluation, and ensure the string has quotes actually in it, and (in the case of a string defined in the program) that any references to groups are escaped so that they aren't interpreted at compile time. Escaping group references should not be done in a user-supplied string, or a string read from a file etc.

(On the pattern side of the s///, you only need watch out for $, @ etc which might cause unwanted interpolation in your pattern).

$replace = '"\$1z"'; # check the quotes carefully! it's ' " blah " '
$text = "apple";
$pattern = "a(..)";
$text =~ s/$pattern/$replace/ee;
# or $text =~ s/$pattern/eval $replace/e;

# or
$replace = "\$1z";
$text = "apple";
$pattern = "a(..)";
$text =~ s/$pattern/qq("$replace")/ee;
# NOT $text =~ s/$pattern/"$replace"/ee;

Remember that in all these examples, the string the user types, or the string in the file etc, should not have interpolation escapes, eg user should type literally

"$1z"

(or, if the qq("") form is being used, just

$1z
)

As the internet points out

What is likely confusing is that both of these statements yield the same result:

$text2 =~ s/$match/$replace/;
$text2 =~ s/$match/$replace/e;

Thursday, February 18, 2010

Arcs

a rx ry x-axis-rotation large-arc-flag sweep-flag x y

/x-axis-rotation/ is (I think) the orientation of the minor (shorter) axis of the ellipse, measured clockwise with East being 0 deg. Obviously for an arc which is a portion of a circle, the rotation has no effect.

/large-arc-flag/ and /sweep-flag/ work together. To understand them you have to appreciate that there are always two possible circles or ellipses on whose circumference the start and end points can fall:
  • The circle where the shortest route from start to end is the anticlockwise one ('anticlockwise short')
  • The circle where the shortest route from start to end is the clockwise one ('clockwise short')

/large-arc-flag/ determines whether the longer, or the shorter path between the start and end points is used.

/sweep-flag/ determines which direction (0=negative/anticlockwise, 1=positive/clockwise) we move in round the circle when going from start to end.

Basically the combination of /large-arc-flag/ and /sweep-flag/ chooses between one of the possible circles and the other, and dictates whether we use the larger or smaller way round that circle.

That's to say, the combination 0 0 uses the same circle as 1 1 (anticlockwise short), and 0 1 uses the same circle as 1 0 (clockwise short) - and 0 1 and 1 1 take the long way round the chosen circle.

(Good diagram of this here)

NB that it is a lot easier to use the circle element instead of trying to draw a complete circle with arcs.

Wednesday, February 17, 2010

Spreadsheet lookups

In Excel, VLOOKUP(key, range, column-in-range, FALSE) looks in the leftmost column of /range/ for /key/, and if it finds it, returns the corresponding value in /column-in-range/, where the key column is number 1.

/range/ should not include the column header row if any. Also you probably should specify it as an absolute value eg $A$2:$B$10, if you intend to repeat your formula in a series of cells.

Monday, February 15, 2010

Attribute case

SVG is case-sensitive, and it appears to silently ignore attributes whose case is wrong. Eg in the marker tag, refx= is silently ignored, and only refX= will be acted on.

Markers

(For our purposes the 'vertex' is the point being marked - the line start, end or vertex depending on what kind of marker we are defining.)

markerwidth and markerheight give the actual size of the space that the marker is fitted into. The unit is (by default) the stroke-width of the line being marked. How this space is positioned relative to the vertex depends on the position of refx, refy relative to the viewbox origin - see below.

viewbox="minx miny width height" establishes a coordinate grid - the stuff you draw as the marker has its co-ordinates expressed in terms of the viewbox. Eg if box is "0 0 10 10" then you are saying 'Divide the marker space into a grid with width 10, height 10, and let its top left-hand corner have the co-ord 0,0.'

refx,refy establish the co-ords of the vertex in terms of the viewbox. Eg with refx="5" and refy="5", you are saying 'Let the vertex have the co-ords 5,5 in our system', which with the viewbox above would put the vertex in the middle.

(This is all a matter of convention: if the viewbox size, refx and refy, and the dimensions of the marker components are all increased by the same proportion, the result is exactly the same. The idea, I suppose, is that you can use whatever co-ord system you find most useful.)

Btw orient="auto" is not the default. You should specify "auto" if you want something like an arrowhead to point in the same direction that the line does.

Thursday, February 11, 2010

Perl debugger

The debugger does not seem to step through DESTROY destructors.

Wednesday, February 10, 2010

Perl file times

The conversion from file operator times to epoch times is

$^T - ((-M $file) * 86400)

(the result of -M has to be converted from days to seconds, then subtracted from Perl start time)

Consequently the current age of a file in seconds is

(-M $file) * 86400

That may seem obvious but I've got it the wrong way round more times than I care to remember.

Monday, February 1, 2010

Batch language archive cleanup

To delete from the current directory all files listed in an archive:

for /f "tokens=5" %g in ('7z l archive.7z') do del %g

Friday, January 29, 2010

file object

Files returned by get-childitem have a length, not a 'size'.

Friday, January 22, 2010

stuff

Attempting to stuff() to a start position beyond the end of a string results in null!

This does not happen merely when stuffing a multi-character string so as to produce a result longer than the original string. (Eg stuffing "xyz" into position 2 of "ab").

go

'go' is purely a batch delimiter. It just divides a load of SQL in the client up into 'batches' that get sent to the server one at a time.

select 9

go

select 8

go

is the exact equivalent of

connection.Execute("select 9")

connection.Execute("select 8")

mp3 data in filenames

To count songs by artist, from a file containing a list of filenames with format C:\blah\blah\bling\99 Artist - Song.mp3

get-content \0.txt

| foreach-object -process {

if ($_ -match "\\\d\d ([^\\]+) -") {$_ = $matches[1] }

else {$_ = "X"}; $_

| group-object

| sort-object -property count

}


  • the count property belongs to the objects that group-object produces
  • the -process part of foreach-object doesn't output anything by default, hence the trailing $_
  • $matches[n] == $n in Perl

Followers

Blog Archive