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( {} );
$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.
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) );
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)
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.
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'.
You can't change/delete global variables without using the 'location hack'.
Friday, November 19, 2010
Thursday, November 18, 2010
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.
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
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'.
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
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.
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.
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).
(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)
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.
(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.
$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.
$::{'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.
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).
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)
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.)
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).
@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.
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.
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.
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();
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.
- 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.)
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() ) .
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.
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.
Both indexes are 0-based btw.
Tuesday, July 13, 2010
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.
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
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
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).
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:
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.
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
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.
$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.
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).
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
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.
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")
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 .
To add after the last row, use index >= .Count .
Tuesday, April 27, 2010
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.
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;
}
}
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.
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.
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();
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.
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
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[].
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
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.
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.
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)
(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.
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).
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");
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.
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.
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
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.
(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 }
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
gci | select-object length
Thursday, March 4, 2010
Tuesday, March 2, 2010
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
}
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
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:
/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.
/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.
/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.
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
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.
$^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
for /f "tokens=5" %g in ('7z l archive.7z') do del %g
Friday, January 29, 2010
Friday, January 22, 2010
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
Subscribe to:
Comments (Atom)
Followers
Blog Archive
-
▼
2010
(89)
-
►
April
(18)
- .NET timers
- DataRow Field
- Insert into DataRowCollection
- .NET collections
- C# constructors
- C# properties
- .NET treeview
- C# foreach
- .NET treenode key
- rank()
- C# shell command
- C# window interaction
- VNC
- C# index out of bounds
- C# command line arguments
- C# string indexes
- C# implicit conversion
- C# and static-ness
-
►
April
(18)