Assumptions:
NFA is the address that the next instruction will be compiled at
JC is a conditional jump
JP is an unconditional jump
All jump operands are absolute and take up 1 address cell
poke n, x = place x in address n
CASE..OF..ENDOF..ENDCASE can have unconditionally executed code anywhere inside the CASE but outside any OF clauses
IF
compile "JC 0" ; jump past the if clause
push NFA-1 ; address of the JC operand
ELSE ; may not be present
compile "JP 0" ; jump past the else clause
pop JC_ADDR
poke JC_ADDR, NFA ; fill in the JC operand of the IF code
push NFA-1 ; address of the JC operand
ENDIF
pop J_ADDR
poke J_ADDR, NFA ; fill in the JP operand of the ELSE code (or the JC of the IF if there was no ELSE clause)
--
BEGIN
push NFA ; to be used by REPEAT
WHILE
compile "JC 0" ; jump past the end of the loop
push NFA-1 ; address of the JC operand
REPEAT
pop JC_OUT_ADDR
pop JC_TOP_ADDR
compile "JP JC_TOP_ADDR" ; jump back to the BEGIN
poke JC_OUT_ADDR, NFA ; fill in the JC operand of the jump in WHILE
--
CASE
push 0 ; count of OF clauses
OF ; there can be any number of these
compile "JC 0" ; jump past this OF clause
pop COUNT ; temp store of count
push NFA-1 ; address of the JC operand
push COUNT ; restore count to top of stack
ENDOF ; one of these for each OF
compile "JP 0"
pop COUNT ; pop current OF clause count
++COUNT ; increase by exactly 1
pop JC_ADDR
poke JC_ADDR, NFA ; fill in the JC operand of the jump in the OF
push NFA-1 ; address of the JP operand we compiled just now
push COUNT ; put the (incremented) count back on the stack
ENDCASE
pop COUNT
for (I = 1; I <= COUNT; ++I) {
pop JP_ADDR
poke JP_ADDR, NFA ; fill in the JP operand of the jump in each ENDOF
}
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 )
Saturday, December 29, 2012
Saturday, December 22, 2012
Perl closures
Remember a variable must be declared with my (not local) to retain its value in a closure.
Technique for handlers (or 'how to supply a reference to an instance method'):
set_callback( \&method )
will not work inside an object because at the time the callback is run, Perl doesn't know what object the method belongs to. Instead I use
$copyinst = $inst;
set_callback( sub { &method($copyinst, @_); } )
where $inst is the instance variable (I'm never sure whether the copy is necessary or not). method will now be called properly, and like all methods will have the instance as the first argument, followed by whatever arguments the caller supplies.
There's supposed to be another way round this but I've never been able to make that work.
Technique for handlers (or 'how to supply a reference to an instance method'):
set_callback( \&method )
will not work inside an object because at the time the callback is run, Perl doesn't know what object the method belongs to. Instead I use
$copyinst = $inst;
set_callback( sub { &method($copyinst, @_); } )
where $inst is the instance variable (I'm never sure whether the copy is necessary or not). method will now be called properly, and like all methods will have the instance as the first argument, followed by whatever arguments the caller supplies.
There's supposed to be another way round this but I've never been able to make that work.
Day for a given declination of the Sun

\frac{365 \cdot cos^{-1}(\frac{\delta}{-23.45})}{360}
(365 * acos(declination/-23.45)) / 360
An approximation in days from the winter solstice in any year. Good enough for calculating on which days of the year, say, the sun sets at 8pm. Not good enough for eclipses.
NB that acos has two results, one positive and one negative, or to put it another way, the Sun has the same declination on two days each year (eg Mar 21 and Sep 21).
Calculators and programming languages will only return one result (the positive one, ie the day in the first half of the year) - to get the other one, substitute -1*acos(declination/-23.45) in the formula.
(People have asked me to say when the winter solstice is. I assume it's Dec 21, using any more accuracy together with this approximation formula seems pointless). (People have also been asking me to say what I mean by 'An approximation in days from the winter solstice in any year'. Well, if you put a declination (eg -23.45) into the formula above, and get the result 0, then the answer is '0 days from Dec 21' or 'Dec 21'. If the result was 1, then the answer is '1 days from Dec 21' or 'Dec 22', and so on and so forth.)
Copy constructor
If you don't define a copy constructor - a Thing(const Thing &t)() constructor - the compiler will generate a default one which just copies all the members bit-for-bit.
This is bad because the copy constructor is used, not just for stuff like
Thing t1 = Thing(t0);
but also for initialising arguments to functions, so if you have
void f(Thing a) { ... }
Thing t;
f(t);
the copy constructor will be used when a is created. And if it's the default one, all a's members will be literally and exactly the same as t's, even if their pointers. Particularly bad news if your destructor deletes those pointers - because at the end of f(), ~Thing will be called on a, and the referents of a's pointers are the same as the referents of t's pointers, so when f() has returned, t will have lost those referents. So, in short, if you want to pass your class to functions, make a copy constructor for it.
This is bad because the copy constructor is used, not just for stuff like
Thing t1 = Thing(t0);
but also for initialising arguments to functions, so if you have
void f(Thing a) { ... }
Thing t;
f(t);
the copy constructor will be used when a is created. And if it's the default one, all a's members will be literally and exactly the same as t's, even if their pointers. Particularly bad news if your destructor deletes those pointers - because at the end of f(), ~Thing will be called on a, and the referents of a's pointers are the same as the referents of t's pointers, so when f() has returned, t will have lost those referents. So, in short, if you want to pass your class to functions, make a copy constructor for it.
sqlite output formats
I hadn't previously noticed that sqlite has output formats other than line and column. In particular there are also the csv and tcl modes.
The difference between csv and tcl modes appears to be that in tcl all items are quoted, and newline is represented as \n, whereas in csv mode items are not always quoted and newline is represented as a newline.
I can't work out the exact rules it uses for quoting in csv mode, it appears to be that an item is quoted if it contains a newline or a separator, and sometimes even if it doesn't contain either of those.
Unfortunately, it doesn't seem possible to tcl mode from the command line, even if you use a script to construct a multi-line command line with the .mode tcl separated from the SQL by a newline. This makes them considerably less useful.
You can however specify -csv on the command line (contrary to my previous assertion). You have to be prepared to parse fields with an embedded newline, but it can be done.
Friday, December 14, 2012
Syntax for parseability
Fascinating - VB, which doesn't require brackets round the expression following 'if', won't allow you to create a subroutine or function called 'then'.
This is presumably because it can't, like the C family, use the trailing ) to tell where the expression ends, and wants to assume that 'then' on the end of a line that began 'if' always delimits it. Btw I see you can't have a variable called 'if' in C.
And Perl throws a syntax error at "$a--5", you have to put "$a- -5". Fascinating.
Even more fascinatingly, mingw C won't accept a--5. I've been expecting far too much of my own expression evaluators.
Thursday, November 22, 2012
Perl one-liners
Reverse order of lines:
pclip | perl -ne "chop; unshift (@a,$_); END { print join(qq/\n/,@a)}"
Friday, November 16, 2012
Perl :: and class methods
If you call an instance method as a static method - ie if you usually use it thus
$dalek->say("Exterminate");
and call it thus
Dalek::say("Exterminate");
then the method will NOT get the class name as its first argument, as I always assumed it would. It will only have the arguments explicitly supplied, which will probably mean it won't work, because in our example "Exterminate" will end up in the $inst or $self position in say.
To get the expected result, put
Dalek->say("Exterminate");
which I didn't think was allowed. This will supply "Dalek" as $_[0] as expected.
Or you could put
Dalek::say("Dalek", "Exterminate");
which I think is not as clear. Actually, I now realise Perl doesn't recognise any difference between instance and static methods. What I should be saying above is that Dalek::say("Exterminate") means simply 'say("Exterminate") using the say subroutine in package Dalek', whereas $dalek->say("Exterminate") means 'Check that $dalek is a reference to something blessed, and if it is, call say with the name of the class it was blessed into as the first argument, and "Exterminate" as the second.
And for completeness, presumably the other example above Dalek->say("Exterminate") means 'Enquote the bareword to the left of ->, that gives us "Dalek", now call Dalek::say with "Dalek" as first argument and "Exterminate" as second.
$dalek->say("Exterminate");
and call it thus
Dalek::say("Exterminate");
then the method will NOT get the class name as its first argument, as I always assumed it would. It will only have the arguments explicitly supplied, which will probably mean it won't work, because in our example "Exterminate" will end up in the $inst or $self position in say.
To get the expected result, put
Dalek->say("Exterminate");
which I didn't think was allowed. This will supply "Dalek" as $_[0] as expected.
Or you could put
Dalek::say("Dalek", "Exterminate");
which I think is not as clear. Actually, I now realise Perl doesn't recognise any difference between instance and static methods. What I should be saying above is that Dalek::say("Exterminate") means simply 'say("Exterminate") using the say subroutine in package Dalek', whereas $dalek->say("Exterminate") means 'Check that $dalek is a reference to something blessed, and if it is, call say with the name of the class it was blessed into as the first argument, and "Exterminate" as the second.
And for completeness, presumably the other example above Dalek->say("Exterminate") means 'Enquote the bareword to the left of ->, that gives us "Dalek", now call Dalek::say with "Dalek" as first argument and "Exterminate" as second.
Perl import and BEGIN
NB that code in a BEGIN block in a module runs before the call to import which is triggered by use-ing the module
import btw is a method like any other, the first argument will be the module name and subsequent arguments will be any strings that you placed after it. Eg with
use Extract "nodb";
the two arguments to Extract::import will be "Extract" and "nodb".
Tuesday, October 16, 2012
m// notes and easy mistakes
m// returns true or false in scalar context, not a character position or a match count!
In array context you get an array of matching strings - even if there is only 1 match, it's an array of 1 element.
m//g is different - it has state, and in scalar context will return true or false as many times as there are matches. Obviously it will only do this if invoked multiple times, eg in a while loop. In array context you get an array (obviously) as above.
Tuesday, September 11, 2012
Ad hoc join switching not workable - removed
Apologies for the misleading post beginning 'I tried writing a query with a switchable ad hoc join...' that appeared here earlier, the issue was actually caused by an incompletely specified join in the second branch.
Wednesday, September 5, 2012
Removing Flash malware
Installing Flash has also put an update checking malware app onto my PC. Working towards eliminating this - using procexp on the nag screen I found it was running as "C:\WINDOWS\system32\Macromed\Flash\FlashUtil32_11_3_300_265_Plugin.exe", command line "C:\WINDOWS\system32\Macromed\Flash\FlashUtil32_11_3_300_265_Plugin.exe" -update plugin".
Deleting ..plugin.exe looks like it might, well, delete the browser plugin, so instead I've deleted C:\WINDOWS\system32\Macromed\Flash\FlashPlayerUpdateService.exe, will see if that works.
I can't work out how the malware is running, despite its name it isn't installed as a service so far as I can see.
The above entry was made on Aug 29th - since then the malware has somehow reinstalled itself. Deleted it again.
Deleting ..plugin.exe looks like it might, well, delete the browser plugin, so instead I've deleted C:\WINDOWS\system32\Macromed\Flash\FlashPlayerUpdateService.exe, will see if that works.
I can't work out how the malware is running, despite its name it isn't installed as a service so far as I can see.
The above entry was made on Aug 29th - since then the malware has somehow reinstalled itself. Deleted it again.
Friday, July 13, 2012
Windows API AllocConsole
To use AllocConsole you must include the following
#define _WIN32_WINNT 0x0501
Presumably this has to come before any #includes of Windows header files, because it's setting some kind of 'minimum version' for those files to take note of.
#define _WIN32_WINNT 0x0501
Presumably this has to come before any #includes of Windows header files, because it's setting some kind of 'minimum version' for those files to take note of.
Friday, June 22, 2012
Last index of array
The equivalent to
$#array (which finds the last index of @array)
for an array reference $rArray is
$#{$rArray}
(note the second dollar sign)
And note that it is not
$#{ @{$rArray} }
where you're putting an array into a context where a reference to an array is expected. Beware, this fails without giving a warning.
$#array (which finds the last index of @array)
for an array reference $rArray is
$#{$rArray}
(note the second dollar sign)
And note that it is not
$#{ @{$rArray} }
where you're putting an array into a context where a reference to an array is expected. Beware, this fails without giving a warning.
Wednesday, June 20, 2012
XPath
/ absolute path separator - /AAA/BBB selects BBB (not AAA)
// relative path separator - //AAA/BBB selects BBB (not AAA)
( ie, / means what it does in file paths, whereas // means sort of /.*/ with any number of hierarchy levels intervening )
( Starting the path with "/" means the path starts at the root node of the document. Even if you supplied a different node to document.evaluate as the context node, / still has this meaning. To search under a context node, which is usually why you supplied one in the first place, start the path with .// , ie "at any position among the descendants of the context node")
.. as in file paths - //AAA/BBB/.. selects AAA (not BBB)
* all matching elements (at one level only)
[n] nth element at that level (1+) - also last()
[otherelement] select elements that have otherelement as a child
@attr select an attribute (not the tag it belongs to)
[@attr] select an element that has an attribute
attr can be *. not() negates, so [not(@*)] = an element without any attrs
[@attr='...'] select an element that has attr set to a given value
[expression] eg saying name()='BBB' is the same as //BBB
text() select all text node children - can be subscripted etc (use a predicate with string(.) or string() to select on the content of the text, eg [contains(string(.),'dog')]
Axes:
/AAA = /child::AAA (ie, child:: is the default axis)
/AAA/BBB = /child::AAA/child::BBB
//descendant::* = all elements below the specified level
//parent::* = all parents
//parent::DDD = all DDDs which are parents
ancestor::
following-sibling::, preceding-sibling::
//A/B/following-sibling:: = all following siblings of a B which has an A parent
following::, preceding::
descendant-of-self::, ancestor-of-self:: ('and' not 'or')
self::
Other functions:
normalize_space() = ltrim(rtrim())
starts_with(name(), 'BBB')
contains(name(), 'x')
string-length() remember < and > represented as entities
floor(), ceiling()
Beware using unfamiliar functions looked up on net, they may be from XPath 2 which browsers don't implement. Useful list of functions which do work in XPath 1 here (Appendix C) http://www.w3.org/TR/xpath-functions/#xpath1-compatibility
Other operators
div, mod
String value: I'm being told that nodes have a string-value, which for purposes of parsing HTML is all the text in themselves and their descendant nodes. This means that . in an XPath expression represents the text in a node, so you can specify things like //span[contains(.,'Dalek')] to pull out all spans containing the string "Dalek".
// relative path separator - //AAA/BBB selects BBB (not AAA)
( ie, / means what it does in file paths, whereas // means sort of /.*/ with any number of hierarchy levels intervening )
( Starting the path with "/" means the path starts at the root node of the document. Even if you supplied a different node to document.evaluate as the context node, / still has this meaning. To search under a context node, which is usually why you supplied one in the first place, start the path with .// , ie "at any position among the descendants of the context node")
.. as in file paths - //AAA/BBB/.. selects AAA (not BBB)
* all matching elements (at one level only)
[n] nth element at that level (1+) - also last()
[otherelement] select elements that have otherelement as a child
@attr select an attribute (not the tag it belongs to)
[@attr] select an element that has an attribute
attr can be *. not() negates, so [not(@*)] = an element without any attrs
[@attr='...'] select an element that has attr set to a given value
[expression] eg saying name()='BBB' is the same as //BBB
text() select all text node children - can be subscripted etc (use a predicate with string(.) or string() to select on the content of the text, eg [contains(string(.),'dog')]
Axes:
/AAA = /child::AAA (ie, child:: is the default axis)
/AAA/BBB = /child::AAA/child::BBB
//descendant::* = all elements below the specified level
//parent::* = all parents
//parent::DDD = all DDDs which are parents
ancestor::
following-sibling::, preceding-sibling::
//A/B/following-sibling:: = all following siblings of a B which has an A parent
following::, preceding::
descendant-of-self::, ancestor-of-self:: ('and' not 'or')
self::
Other functions:
normalize_space() = ltrim(rtrim())
starts_with(name(), 'BBB')
contains(name(), 'x')
string-length() remember < and > represented as entities
floor(), ceiling()
Beware using unfamiliar functions looked up on net, they may be from XPath 2 which browsers don't implement. Useful list of functions which do work in XPath 1 here (Appendix C) http://www.w3.org/TR/xpath-functions/#xpath1-compatibility
Other operators
div, mod
String value: I'm being told that nodes have a string-value, which for purposes of parsing HTML is all the text in themselves and their descendant nodes. This means that . in an XPath expression represents the text in a node, so you can specify things like //span[contains(.,'Dalek')] to pull out all spans containing the string "Dalek".
Saturday, June 16, 2012
DOM basics & gotchas
Get element attributes with .getAttribute(attrname). Element tag names in .tagName - in upper case seemingly. (tagName is a property of Element btw, not HTMLElement or Node. But className is a property of HTMLElement, presumably because HTML elements are expected to have 'class' whereas SGML ones aren't, necessarily. Not that this matters in practical terms.)
You can supply an XPath evaluation with a context node by supplying that node in the contextnode parameter. That node will then be the one represented by "." in the XPath expression.
NodeList is returned by childNodes and the getElementsBy... methods among others. It takes .item() or [] and has .length . If there are no nodes to return, you get an empty NodeList (not null).
You can supply an XPath evaluation with a context node by supplying that node in the contextnode parameter. That node will then be the one represented by "." in the XPath expression.
NodeList is returned by childNodes and the getElementsBy... methods among others. It takes .item() or [] and has .length . If there are no nodes to return, you get an empty NodeList (not null).
Friday, June 15, 2012
Scheduled task issues
Don't forget that if the command in a scheduled task contains redirections, or is an internal command, it needs "cmd /c" in front of it. This is a nasty one as it doesn't show up when you test from the command line (because you're inside cmd there...)
Thursday, June 14, 2012
Firefox and the DOM
Firefox is very conscientious about whitespace - it often (if not always) creates a separate text node for whitespace, rather than ignoring it. It's as if its rule is 'not even whitespace must be thrown away'.
This means that you cannot assume that, for example, a TR node's nextSibling will be the next TR in the table. It may well be a whitespace text node - one which will be invisible when you inspect the structure, too. So if your scripts don't find the siblings they expect, put in a loop to seek the next non-text node sibling (or parent, or child etc etc).
Monday, June 11, 2012
on v. where
It seems that the functional difference between specifying a predicate in 'join..on' and specifying it in 'where' is that, if the predicate only involves a field from one table (eg tax_year <= 2005), then with 'join...on' it's applied to the table before the join is made, and with 'where' it's applied to the rows that result from the join.
So I suppose the most efficient place for this kind of predicate is in 'join...on'.
So I suppose the most efficient place for this kind of predicate is in 'join...on'.
Friday, June 8, 2012
Shield anchors
When I'm drilling holes for shield anchors for things that bolt into concrete floors or paving, there's usually at least two holes to drill, and every hole after the first tends to get gritty concrete dust down it, which makes the bolts seize up in the threads.
A bit of blue tack or chewing gum stuck over the top of each hole keeps the dust out effectively. (Don't resume chewing the gum after use).
A bit of blue tack or chewing gum stuck over the top of each hole keeps the dust out effectively. (Don't resume chewing the gum after use).
Saturday, June 2, 2012
Javascript variable initialisation
Don't expect to ++ on a variable if you haven't set it to contain a number. Even if it has been declared, it is not initialised to 0 or even to an undefined numeric value.
Similarly, you can't set properties on a new variable unless it's been initialised to {}, and you can't set array index values unless it's been initialised to [].
Similarly, you can't set properties on a new variable unless it's been initialised to {}, and you can't set array index values unless it's been initialised to [].
Friday, June 1, 2012
Javascript null, undefined, false etc etc
What counts as false
When Javascript is casting to a boolean, eg in an if statement, it treats as false the following values:
null
undefined
""
0 (or any number equivalent to 0 eg -0, 0.0 etc, or a string that represents such a number)
NaN
So !value will be true if value is any of the above.
What can't take a property setting or index
It's an error to try to set or get a property (with .) or an index (with []) on a null or undefined value.
When Javascript is casting to a boolean, eg in an if statement, it treats as false the following values:
null
undefined
""
0 (or any number equivalent to 0 eg -0, 0.0 etc, or a string that represents such a number)
NaN
So !value will be true if value is any of the above.
What can't take a property setting or index
It's an error to try to set or get a property (with .) or an index (with []) on a null or undefined value.
Tuesday, May 29, 2012
Javascript regular expressions
Do capturing thus
r = /score=(\d\d)/;
a = r.exec("players=2;score=98;duration=2:09:03");
// a[0] is the whole match (score=98)
// a[1] is capture group 1 (98) like $1 in Perl
// if there are more groups, they are in subsequent array items
w3schools says exec returns the matched text, but I always get an array as described above.
If you define the regexp as global (/g) then you pick up successive matches in the string thusly
while (a = r.exec(string)) { ... }
(the regexp object must I suppose have state so that it can remember how far it's got through string on each iteration.)
The /.../ regexp syntax is part of the JS standard and perfectly respectable. Using it creates a RegExp object, of which exec() is one of the methods.
r = /score=(\d\d)/;
a = r.exec("players=2;score=98;duration=2:09:03");
// a[0] is the whole match (score=98)
// a[1] is capture group 1 (98) like $1 in Perl
// if there are more groups, they are in subsequent array items
w3schools says exec returns the matched text, but I always get an array as described above.
If you define the regexp as global (/g) then you pick up successive matches in the string thusly
while (a = r.exec(string)) { ... }
(the regexp object must I suppose have state so that it can remember how far it's got through string on each iteration.)
The /.../ regexp syntax is part of the JS standard and perfectly respectable. Using it creates a RegExp object, of which exec() is one of the methods.
Monday, May 21, 2012
tar invocation
I find the best way to marshal tar options is to remember that 'f' indicates which tar file you want to use, and putting that as the last option immediately before the filename. So
tar -cvf a.tar
to create and
tar -xvf a.tar
to extract. And similarly tar -tf a.tar to list.
tar -cvf a.tar
to create and
tar -xvf a.tar
to extract. And similarly tar -tf a.tar to list.
Saturday, May 19, 2012
Perl one-liners
HTML links to BB links
HTML B and I to BB B and I
s/<a href="(.*?)">(.*?)<\/a>/\[url=$1\]$2\[\/url\]/g
HTML B and I to BB B and I
s/<([bi])>(.*?)<\/[bi]>/\[$1\]$2\[\/$1\]/g
Wednesday, May 16, 2012
XPath evaluate results
If you use XPathResult.FIRST_ORDERED_NODE_TYPE as the result type with evaluate, you don't get back the same kind of node set that you do with UNORDERED_NODE_SNAPSHOT_TYPE. You don't use snapshotItem etc with it, instead use singleNodeValue to get the one node in the set. I think you get null back if there are no nodes.
Good description here http://www.wrox.com/WileyCDA/Section/id-291861.html
Good description here http://www.wrox.com/WileyCDA/Section/id-291861.html
Tuesday, May 15, 2012
Greasemonkey script commands
Suppose you have registered a script command which runs a function in your script. You load a page on which your script is included, and then you can use the menu option to run that function as many times as you like.
But Firefox won't load a fresh copy of your script if you change it in between uses of the menu option, even if you're using one of the ways of editing the script from the browser (eg right-clicking the script name on the Greasemonkey menu).
It seems it only loads the script when you reload the page it's included on.
But Firefox won't load a fresh copy of your script if you change it in between uses of the menu option, even if you're using one of the ways of editing the script from the browser (eg right-clicking the script name on the Greasemonkey menu).
It seems it only loads the script when you reload the page it's included on.
Greasemonkey script won't run
If your script isn't running at all - so you aren't even seeing an alert or GM_log message you've included -
1. Check that it's included on the page (will appear on the Greasemonkey menu with a tick)
2. Check - in the Error Console with 'All' or 'Errors' selected - that there isn't a Javascript syntax error in it.
I've been caught time and time again by this, having set the console to 'Messages' only and not looking at the Errors.
1. Check that it's included on the page (will appear on the Greasemonkey menu with a tick)
2. Check - in the Error Console with 'All' or 'Errors' selected - that there isn't a Javascript syntax error in it.
I've been caught time and time again by this, having set the console to 'Messages' only and not looking at the Errors.
Thursday, May 10, 2012
Greasemonkey metadata
It seems that in later versions, if you have metadata like
// @name OWA Lite refresher // @description // @include // @include https://email.dugeenswork.co.uk/owathe first, blank @include will cause the second one to be ignored, as if the blank one means 'don't include this script anywhere regardless of what I subsequently specify'. Yes I agree you wouldn't deliberately put metadata like that in in the first place.
Thursday, May 3, 2012
Google + operator
Google's stupid decision to start replacing your search terms with ones that produced more hits for their advertisers, and to abolish the + operator and start ignoring quoted terms to stop you evading it, can be evaded by using 'verbatim' mode (aka 'actually search for what I fucking told you in the first place' mode).
The pertinent bit of the URL is &tbs=li:1
eg if you're looking specifically for people who've mixed up Pavel Chekov and Chekhov the playwright
http://www.google.com/search?q=chekov+playwright&tbs=li:1
Even Instant Search was less annoying than this. And at least Instant is client-side and can be easily evaded with Greasemonkey. Google have made the mistake here of ignoring the number one principle of computing, which is that computers should do exactly what they're told, even if it's to start a global thermonuclear war.
Perhaps there's been a backlash - I notice that in certain circumstances + is now working again, eg searching for 'proprietry' gets you 'proprietary', but '+proprietry' actually performs the search you require.
The pertinent bit of the URL is &tbs=li:1
eg if you're looking specifically for people who've mixed up Pavel Chekov and Chekhov the playwright
http://www.google.com/search?q=chekov+playwright&tbs=li:1
Even Instant Search was less annoying than this. And at least Instant is client-side and can be easily evaded with Greasemonkey. Google have made the mistake here of ignoring the number one principle of computing, which is that computers should do exactly what they're told, even if it's to start a global thermonuclear war.
Perhaps there's been a backlash - I notice that in certain circumstances + is now working again, eg searching for 'proprietry' gets you 'proprietary', but '+proprietry' actually performs the search you require.
Friday, April 27, 2012
wordpress.com traps
Don't try editing CSS on a wordpress.com blog. It will let you edit and preview it, but you can't save it unless you pay for an upgrade. That's a cheap trick in my opinion.
Friday, April 13, 2012
Ranking window functions
The differences are
rank() gives two equal firsts a rank of 1, and the next rank given is 3 (mathematician's rank).
dense_rank() does likewise except that the next rank given is 2 (sportsperson's rank).
row_number() gives every row a different rank, even if the values being sorted on are equal.
rank() gives two equal firsts a rank of 1, and the next rank given is 3 (mathematician's rank).
dense_rank() does likewise except that the next rank given is 2 (sportsperson's rank).
row_number() gives every row a different rank, even if the values being sorted on are equal.
Thursday, April 5, 2012
polipo forbidden regex
polipo expects POSIX regular expressions in its forbiddenFile.
POSIX regex syntax does not have lookaheads or any of those forms that start with (? . Sadly this means that you can't use them to forbid 'all except /regex/', ie to allow URLs rather than forbid others.
Good general regex syntax comparison chart here: http://www.greenend.org.uk/rjk/tech/regexp.html
POSIX regex syntax does not have lookaheads or any of those forms that start with (? . Sadly this means that you can't use them to forbid 'all except /regex/', ie to allow URLs rather than forbid others.
Good general regex syntax comparison chart here: http://www.greenend.org.uk/rjk/tech/regexp.html
netcat
The difference between 'listen' and 'listen harder' is that nc -l will exit once any connection that has been made to it closes. nc -L will continue to listen after that, accepting other connections.
if you do
nc server port < file
the sending nc won't close after the file has been sent. It will only close if you give it a timeout
nc -w 3 server port < file
if you do
nc server port < file
the sending nc won't close after the file has been sent. It will only close if you give it a timeout
nc -w 3 server port < file
Wednesday, April 4, 2012
Tunnelling to polipo
This is the usual situation where I'm tunnelling from 127.0.0.2:anyport at home, through an SSH server on gateway.dugeenswork.co.uk to remotepc.dugeenswork.co.uk:desiredport, where something running on my remotepc is listening on desiredport (like a SSH server or Remote Desktop).
What I can't do is get this to work when Polipo is running on remotepc and listening on 8123. It'll happily serve requests coming from the session on remotepc, but it refuses all connections coming through the tunnel.
Oddly, when I set netcat to run on remotepc and listen on 8123, with
nc -L -p 8123
it happily communicated through the tunnel. Using the -v option showed me that requests coming through that way showed as coming from gateway's IP address, which was educational as up to now I thought they showed as coming from localhost.
So I thought putting gateway's IP address in allowedClients would fix this - it didn't.
Btw polipo won't read a config file (other than the default in /etc) unless you tell it to with -c.
While I'm on, the polipo local web server doesn't work through the tunnel either. It makes Firefox go into a spin loop allocating memory. nc reported '127.0.0.2: inverse host lookup failed: h_errno 11004: NO_DATA' when tried on this one.
Aha, I've worked out where I was going wrong. It isn't enough to set allowedClients, you also have to set proxyPort to 0.0.0.0 to allow external connections - like this one from the gateway.
This makes the proxy happily deal with requests from the tunnel, and the local web server works too.
Not really happy about that IP-based setup though, I might try the chain tunnelling method with a SSH server on remotepc, so that polipo thinks the requests are coming from remotepc (ie localhost hopefully).
What I can't do is get this to work when Polipo is running on remotepc and listening on 8123. It'll happily serve requests coming from the session on remotepc, but it refuses all connections coming through the tunnel.
Oddly, when I set netcat to run on remotepc and listen on 8123, with
nc -L -p 8123
it happily communicated through the tunnel. Using the -v option showed me that requests coming through that way showed as coming from gateway's IP address, which was educational as up to now I thought they showed as coming from localhost.
So I thought putting gateway's IP address in allowedClients would fix this - it didn't.
Btw polipo won't read a config file (other than the default in /etc) unless you tell it to with -c.
While I'm on, the polipo local web server doesn't work through the tunnel either. It makes Firefox go into a spin loop allocating memory. nc reported '127.0.0.2: inverse host lookup failed: h_errno 11004: NO_DATA' when tried on this one.
Aha, I've worked out where I was going wrong. It isn't enough to set allowedClients, you also have to set proxyPort to 0.0.0.0 to allow external connections - like this one from the gateway.
This makes the proxy happily deal with requests from the tunnel, and the local web server works too.
Not really happy about that IP-based setup though, I might try the chain tunnelling method with a SSH server on remotepc, so that polipo thinks the requests are coming from remotepc (ie localhost hopefully).
Tuesday, April 3, 2012
Reindexing dokuwikistick
Suppose you want to take the pages from a DokuWiki wiki and view them using DokuwikiStick.
Firstly, the default admin password for dokuwiki on a stick appears to be 'admin'. It says that in the documentation but I didn't read it.
Secondly, if all you do is copy the files from the pages directory of the original wiki and paste them into the DWS one, you can access them only by typing their names as part of the DokuWiki URL. Eg 'http://localhost:8800/thepage'.
If you want to use them with the search function in the usual way, you have to rebuild the index. In theory you can do this with the searchindex plugin - in practice it doesn't work and you probably won't even be able to download it.
So it has to be done manually by running bin/indexer.php (not to be confused with lib/exe/indexer.php).
DWS does not come with a command line version of PHP - it'd be nice if you could get MicroApache to run this script - so if you haven't got PHP you'll have to download it from php.net . At least it doesn't require installation, just unzip the downloaded file into a directory of your choice and run the script with it:
the-php-directory\php the-dokuwiki-path\bin\indexer.php
It reassuringly reports the page files as it indexes them, and when it's finished your DWS will finally recognise the existence of the pages.
DWS is a handy app to have but they really do need to sort out this reindexing thing, it shouldn't take hours of poking round the net and a 14M PHP download to get it done.
Firstly, the default admin password for dokuwiki on a stick appears to be 'admin'. It says that in the documentation but I didn't read it.
Secondly, if all you do is copy the files from the pages directory of the original wiki and paste them into the DWS one, you can access them only by typing their names as part of the DokuWiki URL. Eg 'http://localhost:8800/thepage'.
If you want to use them with the search function in the usual way, you have to rebuild the index. In theory you can do this with the searchindex plugin - in practice it doesn't work and you probably won't even be able to download it.
So it has to be done manually by running bin/indexer.php (not to be confused with lib/exe/indexer.php).
DWS does not come with a command line version of PHP - it'd be nice if you could get MicroApache to run this script - so if you haven't got PHP you'll have to download it from php.net . At least it doesn't require installation, just unzip the downloaded file into a directory of your choice and run the script with it:
the-php-directory\php the-dokuwiki-path\bin\indexer.php
It reassuringly reports the page files as it indexes them, and when it's finished your DWS will finally recognise the existence of the pages.
DWS is a handy app to have but they really do need to sort out this reindexing thing, it shouldn't take hours of poking round the net and a 14M PHP download to get it done.
Friday, March 30, 2012
Perl use
use takes effect as soon as it is compiled - even before BEGIN, or more precisely, before any BEGIN blocks that are read after it, because use is effectively inside its own BEGIN block.
And as the documentation points out (I now notice) this is why you can't skip a use by putting it in the false branch of an if. There is a use if pragma for this purpose instead. Or you could use require.
I shall be thinking of use as a compiler directive from now on.
And as the documentation points out (I now notice) this is why you can't skip a use by putting it in the false branch of an if. There is a use if pragma for this purpose instead. Or you could use require.
I shall be thinking of use as a compiler directive from now on.
Tuesday, March 27, 2012
Perl file::find
wanted
When you give File::Find a subroutine reference, the 'wanted' subroutine will find $_ set to the file base name - it will not find element 0 of @_ set to the file base name. Element 0 of @_ appears to be a reference to a hash whose keys resemble the File::Find variables (so it's probably a reference to a File::Find object).
So I should have
sub process {
local ($file) = ($_);
...
not
sub process {
local ($file) = (@_);
...
as I normally would.
preprocess
The 'preprocess' sub does get passed arguments in @_ - an array of strings representing the directory's contents. The strings don't have the directory path prefixed.
If a name isn't included in the list you return from preprocess, not only does it not get passed to wanted, it doesn't get searched (if it's a directory) either.
When you give File::Find a subroutine reference, the 'wanted' subroutine will find $_ set to the file base name - it will not find element 0 of @_ set to the file base name. Element 0 of @_ appears to be a reference to a hash whose keys resemble the File::Find variables (so it's probably a reference to a File::Find object).
So I should have
sub process {
local ($file) = ($_);
...
not
sub process {
local ($file) = (@_);
...
as I normally would.
preprocess
The 'preprocess' sub does get passed arguments in @_ - an array of strings representing the directory's contents. The strings don't have the directory path prefixed.
If a name isn't included in the list you return from preprocess, not only does it not get passed to wanted, it doesn't get searched (if it's a directory) either.
Thursday, March 15, 2012
Cuisenaire tower
Wet dinnertimes always finished before we could finish building our Cuisenaire towers, so we never got to find out how tall the complete tower would be. The towers were built by laying two parallel rods E-W, then two more across them N-S, and so on upwards, starting with the longest rods.
Using the rod quantities from the modern 'International' set (sadly the rods, 35 years on, are now plastic rather than wood)
In practice it would have been impossible to make many stable layers with the shorter rods (4cm downwards) so the maximum practical height would have been about 50cm.
The theoretical maximum using the 2-per-layer system would have been 99cm; one 1cm block on top would have reached the 100cm level, and I suppose under laboratory conditions the other 105 1cm blocks could have been stacked on top to reach 205cm.
Using the rod quantities from the modern 'International' set (sadly the rods, 35 years on, are now plastic rather than wood)
Rod colour Rod length (cm) Rods Layers Total height reached (cm)
Orange 10 10 5 5
Blue 9 12 6 11
Brown 8 12 6 17
Black 7 14 7 24
Dk green 6 16 8 32
Yellow 5 20 10 42
Purple 4 28 14 56
Lt green 3 36 18 74
Red 2 50 25 99
White 1 106 53 *
In practice it would have been impossible to make many stable layers with the shorter rods (4cm downwards) so the maximum practical height would have been about 50cm.
The theoretical maximum using the 2-per-layer system would have been 99cm; one 1cm block on top would have reached the 100cm level, and I suppose under laboratory conditions the other 105 1cm blocks could have been stacked on top to reach 205cm.
Monday, March 12, 2012
Sunday, March 11, 2012
Modify searches via Firefox search bar
Information: Firefox provides a Search Bar to allow quick searches. But you can't easily edit the search engine parameters.
Intention: To edit the Google search in the Search Bar to use 'verbatim' mode (aka 'work properly' mode).
Method: The account here (under 'How do I customise a search engine in 30 seconds') is correct. But an additional step is required: Firefox secretly caches the Search Bar configuration in two files in the profile directory, search.json and search.sqlite. Changes made to (eg) google.xml in the searchplugins directory are not picked up if they don't match these two files.
The solution is to (with Firefox closed) delete search.json and search.sqlite. Firefox will rebuild them, incorporating your changes, next time it starts.
Incidentally, to achieve the original intention the addition to google.xml is
<Param name="tbs" value="li:1"/>
(apologies for the misleading original title of this post) Btw, here's a precised copy of 'How do I customise a search engine in 30 seconds' in case it gets DMCAed by the Nazis:
Intention: To edit the Google search in the Search Bar to use 'verbatim' mode (aka 'work properly' mode).
Method: The account here (under 'How do I customise a search engine in 30 seconds') is correct. But an additional step is required: Firefox secretly caches the Search Bar configuration in two files in the profile directory, search.json and search.sqlite. Changes made to (eg) google.xml in the searchplugins directory are not picked up if they don't match these two files.
The solution is to (with Firefox closed) delete search.json and search.sqlite. Firefox will rebuild them, incorporating your changes, next time it starts.
Incidentally, to achieve the original intention the addition to google.xml is
<Param name="tbs" value="li:1"/>
(apologies for the misleading original title of this post) Btw, here's a precised copy of 'How do I customise a search engine in 30 seconds' in case it gets DMCAed by the Nazis:
Open the searchplugins folder located inside the Firefox installation directory. Open the file google.src with a text editor like notepad and make a simple change in the following lineWith Firefox Portable you'll find the searchplugins directory in ....FirefoxPortable\App\Firefox\browser , and the profile directory in ....FirefoxPortable\Data .
action="http://www.google.com/search"
change this to..
action="http://www.google.co.in/search" or
action="http://www.google.es/search"
Thursday, March 8, 2012
Perl::Tk tabbing
This is the encapsulation I've been using to fix the incredibly annoying broken tabbing feature on Tk Text boxes. NB it doesn't work on multiline Texts but then I've not so far wanted tab-to-next field behaviour on those.
I call it when I've created and packed my Texts:
enable_tab($textcontrol, $control_to_tab_to);
sub enable_tab {
my ($control, $nextcontrol) = @_;
# NB closure below - when the code runs, $control and $nextcontrol will have
# the values they do in this context here.
$control->bind("<Tab>" =>
sub {
$nextcontrol->focus();
$control->break();
} );
# make sure our new binding has priority
my @tags = $control->bindtags;
($tags[0], $tags[1]) = ($tags[1], $tags[0]);
$control->bindtags([@tags]);
}
I call it when I've created and packed my Texts:
enable_tab($textcontrol, $control_to_tab_to);
Unxutils tar
GNU tar helpfully ignores a leading slash in archived file paths - so \data\pages\t1.txt will be extracted into .\data\pages\t1.txt - unless -P is used to explicitly disable this.
Unxutils tar, although it has some other GNU tar features, doesn't have this one.
Unxutils tar, although it has some other GNU tar features, doesn't have this one.
Tuesday, March 6, 2012
Perl map and grep
map evaluates an expression (or block) for each member of a list in turn.
Each evaluation 'sees' $_ as set to the current list member.
The results of the applications are accumulated in a list, which map returns.
Eg
join(",", map $_ . " => " . $h{$_}, keys %h )
shows the members of a hash (map returns a list of strings which join agglutinates into a string).
In my experience the arguments to map should be left unparenthesised.
grep on the other hand evaluates the block/expression for each member of the list; the return value of grep is a list of the elements from LIST for which the block/expression returned a true value. (Or a count of those elements, in scalar context).
These two statements have the same result:
@out = grep {EXPR} @in;
@out = map { EXPR ? $_ : () } @in;
And a rough SQL metaphor:
map: select expr(item) from list
grep: select item from list where expr(item)=1
Each evaluation 'sees' $_ as set to the current list member.
The results of the applications are accumulated in a list, which map returns.
Eg
join(",", map $_ . " => " . $h{$_}, keys %h )
shows the members of a hash (map returns a list of strings which join agglutinates into a string).
In my experience the arguments to map should be left unparenthesised.
grep on the other hand evaluates the block/expression for each member of the list; the return value of grep is a list of the elements from LIST for which the block/expression returned a true value. (Or a count of those elements, in scalar context).
These two statements have the same result:
@out = grep {EXPR} @in;
@out = map { EXPR ? $_ : () } @in;
And a rough SQL metaphor:
map: select expr(item) from list
grep: select item from list where expr(item)=1
Monday, February 27, 2012
ssh chain tunnelling
Suppose you have
- a local PC at which you are sitting
- a gateway server which allows ssh connections from outside the firewall
- a remote PC of your own, also behind the firewall, also running sshd
- a target server which your remote PC can connect to, but the gateway can't
and you want to connect from the local PC - which is outside the firewall - to a port (say 1433 for SQL Server) on the target server.
Firstly set up a tunnel to your remote PC
plink -v -N dugeen@gateway.dugeenswork.co.uk -L 127.0.0.2:3381:remotepc.dugeenswork.co.uk:22
And then tunnel through the first tunnel onto the target server
plink -N -v -P 3381 dugeen@127.0.0.2 -L 127.0.0.2:3382:target.dugeenswork.co.uk:1433
(NB that -P 3381 dugeen@127.0.0.2 is saying 'connect to ssh on 127.0.0.2:3381 as dugeen')
Port 3382 on your local PC (127.0.0.2:3382) is now connected to port 1433 on target.
NB that you run both commands on your local PC, you don't ssh to remotepc to issue the second command.
3381 and 3382 are arbitrary choices, you can use any free ports on your local PC. And 1433 would be replaced by whatever port you were interested in on target.
- a local PC at which you are sitting
- a gateway server which allows ssh connections from outside the firewall
- a remote PC of your own, also behind the firewall, also running sshd
- a target server which your remote PC can connect to, but the gateway can't
and you want to connect from the local PC - which is outside the firewall - to a port (say 1433 for SQL Server) on the target server.
Firstly set up a tunnel to your remote PC
plink -v -N dugeen@gateway.dugeenswork.co.uk -L 127.0.0.2:3381:remotepc.dugeenswork.co.uk:22
And then tunnel through the first tunnel onto the target server
plink -N -v -P 3381 dugeen@127.0.0.2 -L 127.0.0.2:3382:target.dugeenswork.co.uk:1433
(NB that -P 3381 dugeen@127.0.0.2 is saying 'connect to ssh on 127.0.0.2:3381 as dugeen')
Port 3382 on your local PC (127.0.0.2:3382) is now connected to port 1433 on target.
NB that you run both commands on your local PC, you don't ssh to remotepc to issue the second command.
3381 and 3382 are arbitrary choices, you can use any free ports on your local PC. And 1433 would be replaced by whatever port you were interested in on target.
Friday, February 24, 2012
SQL Server functions
If a function returns a table you must grant SELECT permission on it, not EXECUTE.
If a function has a default parameter, caller cannot omit it from the parameter list, but must put the keyword default in its place. (Not terribly useful)
You can't join to a table-valued function, as you can only supply a function with constants or variables as parameters. (You can of course insert its result into a temp table or table variable, and then join to that).
If a function has a default parameter, caller cannot omit it from the parameter list, but must put the keyword default in its place. (Not terribly useful)
You can't join to a table-valued function, as you can only supply a function with constants or variables as parameters. (You can of course insert its result into a temp table or table variable, and then join to that).
Window functions in updates
Window functions aren't allowed in updates any more than other aggregates are.
Friday, February 17, 2012
Turn off OpenOffice Calc AutoCorrect
To get rid of all the autocorrect nonsense in OO Calc, use Tools/AutoCorrect/Options and untick everything.
These settings don't appear to be cross-OO, I think you have to do them individually for each app.
These settings don't appear to be cross-OO, I think you have to do them individually for each app.
Tuesday, February 14, 2012
Perl missing comma gotcha
Suppose you set up a window thusly
$self->{ww} = Win32::GUI::Window->new(
-name => 'Main',
-text => 'Vstatscheck',
-width => 100,
-height => 100 ,
-onTimer => sub { $self->cycle(@_); } # oops missed out the comma
-onTerminate => sub { $self->terminate(); }
);
the -onTerminate bit will be interpreted as a subtraction and neither your Timer or Terminate handlers will be properly set.
If, unlike me, you heed the advice to use the -w switch, you'll get a warning of this. Otherwise you won't. Foolishly perhaps I hardly ever use -w because I can't tell the useful warnings from the useless ones.
$self->{ww} = Win32::GUI::Window->new(
-name => 'Main',
-text => 'Vstatscheck',
-width => 100,
-height => 100 ,
-onTimer => sub { $self->cycle(@_); } # oops missed out the comma
-onTerminate => sub { $self->terminate(); }
);
the -onTerminate bit will be interpreted as a subtraction and neither your Timer or Terminate handlers will be properly set.
If, unlike me, you heed the advice to use the -w switch, you'll get a warning of this. Otherwise you won't. Foolishly perhaps I hardly ever use -w because I can't tell the useful warnings from the useless ones.
Perl Win32::GUI Terminate
Effect of returning different values from the onTerminate event handler of your main window:
-1 ('terminate message loop') - window closes, Win32::GUI::Dialog returns.
1 ('default action') - window closes, Win32::GUI::Dialog continues.
0 ('don't take default action') - window does not close, Win32::GUI::Dialog continues.
Is this different from Perl-Tk? A Tk MainWindow only closes from the X box if you write a WM_DELETE_WINDOW protocol handler which calls destroy(), but that destroy makes MainLoop terminate.
-1 ('terminate message loop') - window closes, Win32::GUI::Dialog returns.
1 ('default action') - window closes, Win32::GUI::Dialog continues.
0 ('don't take default action') - window does not close, Win32::GUI::Dialog continues.
Is this different from Perl-Tk? A Tk MainWindow only closes from the X box if you write a WM_DELETE_WINDOW protocol handler which calls destroy(), but that destroy makes MainLoop terminate.
Sunday, February 12, 2012
Perl::Tk hide window with withdraw
If you withdraw your MainWindow and then raise it again, you must apparently also deiconify it (like the concept of 'withdraw' includes 'minimise'):
$in->{window}->withdraw();
...
$in->{window}->deiconify();
$in->{window}->raise();
You may also need to update() it after the raise to get included widgets to show.
$in->{window}->withdraw();
...
$in->{window}->deiconify();
$in->{window}->raise();
You may also need to update() it after the raise to get included widgets to show.
Monday, February 6, 2012
Sockets with select
In the context of a single-threaded server such as you might construct in the absence of fork() on Win32, using mingw and winsock2.h; and suppose you only intend to cater for a single connection, so instead of having a sockets[] array for all the client sockets, you just have one int thesocket.
Do not do an FD_SET(thesocket, &read_fdset), when preparing to select, if thesocket is 0 (as it might be if you haven't had a connection yet or have closed one). This does not, as I expected, harmlessly AND 0 onto the fd_set, it appears to bugger it up completely so select() returns -1 without even waiting.
('Harmlessly AND 0' indeed. I was mixing up AND and OR there)
Also note that a single-threaded server that only expects one connection has to actively reject further connection attempts - you will find that FD_SET(serversocket, &read_fdset) is true after select() on every such attempt. To reject them, just closesocket() them.
Do not do an FD_SET(thesocket, &read_fdset), when preparing to select, if thesocket is 0 (as it might be if you haven't had a connection yet or have closed one). This does not, as I expected, harmlessly AND 0 onto the fd_set, it appears to bugger it up completely so select() returns -1 without even waiting.
('Harmlessly AND 0' indeed. I was mixing up AND and OR there)
Also note that a single-threaded server that only expects one connection has to actively reject further connection attempts - you will find that FD_SET(serversocket, &read_fdset) is true after select() on every such attempt. To reject them, just closesocket() them.
Saturday, February 4, 2012
Perl easy extensions
Inline::C doesn't seem to be workable on Win32 with ActiveState Perl unless you have the same C compiler that your Perl build was made with. It looks like if you want to use Inline with mingw, you have to build Perl with mingw.
Win32::API does work however, certainly with simple cases like
use Win32::API;
Win32::API->Import("kernel32", "int GetCurrentProcessId()");
Win32::API->Import("kernel32", "DWORD GetTickCount()");
$PID = GetCurrentProcessId();
print "pid=$PID tick=" . GetTickCount() . "\n";
Win32::API does work however, certainly with simple cases like
use Win32::API;
Win32::API->Import("kernel32", "int GetCurrentProcessId()");
Win32::API->Import("kernel32", "DWORD GetTickCount()");
$PID = GetCurrentProcessId();
print "pid=$PID tick=" . GetTickCount() . "\n";
Friday, February 3, 2012
Perl Win32::OLE
NB that OLE collections are indexed starting at 0.
Although Item may be referred to as a property in documentation, you access it like a method:
print $errorcollection->Item($n)->{Description};
Although Item may be referred to as a property in documentation, you access it like a method:
print $errorcollection->Item($n)->{Description};
OpenSSH with a domain
Suppose you want to get openssh working on a work machine that's part of a domain THEDOMAIN. You want to run ssh sessions using your usual username THEDOMAIN\dugeen.
Just do the 'domain' steps from the quick start guide:
mkgroup -d >> ..\etc\group
mkpasswd -d -u dugeen thedomain >> ..\etc\passwd
(mkgroup will take a while if THEDOMAIN has a large number of groups).
Then start the service and there you go.
One thing about ssh on windows in general - you won't get command line editing with the arrow keys unless your ssh client supports them itself.
I wonder if having all the groups from THEDOMAIN in etc\group is necessary?
Just do the 'domain' steps from the quick start guide:
mkgroup -d >> ..\etc\group
mkpasswd -d -u dugeen thedomain >> ..\etc\passwd
(mkgroup will take a while if THEDOMAIN has a large number of groups).
Then start the service and there you go.
One thing about ssh on windows in general - you won't get command line editing with the arrow keys unless your ssh client supports them itself.
I wonder if having all the groups from THEDOMAIN in etc\group is necessary?
SSH servers for Windows
Don't bother with freesshd, it only works if you can log in as literally 'Administrator'. You won't be able to install it if you use another account with admin rights, or if the name for Administrator in your locale is 'Administrateur' etc.
Saturday, January 28, 2012
Perl array insert
To insert an array @b before position n in an array a, use
splice(@a, n, 0, @b);
(ie 'replace 0 elements of @a, starting at offset n, with the elements of @b').
splice always puts into the list all the elements that it's given. If you tell it to replace fewer elements than it's given, the remaining elements are inserted. In this example, no elements are replaced and all elements are inserted.
splice(@a, n, 0, @b);
(ie 'replace 0 elements of @a, starting at offset n, with the elements of @b').
splice always puts into the list all the elements that it's given. If you tell it to replace fewer elements than it's given, the remaining elements are inserted. In this example, no elements are replaced and all elements are inserted.
Wednesday, January 25, 2012
SQL Server transactions
Three modes:
Autocommit = each statement is effectively its own transaction.
Implicit = transaction starts with the first DML statement and continues until you issue COMMIT or ROLLBACK. Another transaction starts at the next DML statement.
Explicit = you delimit transactions with BEGIN TRAN/COMMIT TRAN.
All connections start in autocommit mode.
Implicit mode is entered and left with SET IMPLICIT_TRANSACTIONS.
Explicit transactions are delimited by their BEGIN/COMMIT. When the transaction finishes, autocommit mode resumes.
Autocommit = each statement is effectively its own transaction.
Implicit = transaction starts with the first DML statement and continues until you issue COMMIT or ROLLBACK. Another transaction starts at the next DML statement.
Explicit = you delimit transactions with BEGIN TRAN/COMMIT TRAN.
All connections start in autocommit mode.
Implicit mode is entered and left with SET IMPLICIT_TRANSACTIONS.
Explicit transactions are delimited by their BEGIN/COMMIT. When the transaction finishes, autocommit mode resumes.
Tuesday, January 24, 2012
qx and stderr
There seems to be no problem getting stderr included in the result of qx() - just put 2>&1 on the end of the command just as you would at the prompt.
Thursday, January 5, 2012
Windows edit controls and text files
Windows edit controls represent newlines as \r\n.
Windows/DOS text files represent newlines as \r\n.
If you want to read text from a file into an edit control, make sure you open it in "b" mode (eg fp = fopen("\\config.sys", "rb");).
If b is not specified, the file is opened in text mode, which causes \r\n to be transformed into \n, and edit controls do not translate a single \n into a newline. They represent it as a blob instead.
Windows/DOS text files represent newlines as \r\n.
If you want to read text from a file into an edit control, make sure you open it in "b" mode (eg fp = fopen("\\config.sys", "rb");).
If b is not specified, the file is opened in text mode, which causes \r\n to be transformed into \n, and edit controls do not translate a single \n into a newline. They represent it as a blob instead.
Wednesday, January 4, 2012
std::vector
The things that you put in a vector must be "copyable and assignable", ie not arrays. The only way to have a vector of char arrays is to put the array in a struct.
Subscribe to:
Comments (Atom)
Followers
Blog Archive
-
▼
2012
(63)
-
►
February
(13)
- ssh chain tunnelling
- plink
- SQL Server functions
- Window functions in updates
- Turn off OpenOffice Calc AutoCorrect
- Perl missing comma gotcha
- Perl Win32::GUI Terminate
- Perl::Tk hide window with withdraw
- Sockets with select
- Perl easy extensions
- Perl Win32::OLE
- OpenSSH with a domain
- SSH servers for Windows
-
►
February
(13)