20 December 2012
Fun with CQ5: 3
23 October 2012
Sad but probably true
19 October 2012
Spoiler alert: we drop the bomb
...we find it rather amusing that in the one movie where the AN/FSQ-7 would make perfect sense, you don't find the AN/FSQ-7.At least it was one the scientific systems, not one of IBM's business mainframes.
12 September 2012
Fun with CQ5: 2
So to render a menu, it's a typical coding pattern to walk a subtree of tags, and for each one, find its corresponding web page (Node) and render its hyperlink. The only tricky bit is that com.day.cq.tagging.Tag.find()
returns both Nodes that are explcitly marked with the specified tag as well as Nodes that are only subordinate to a Node that is assigned the tag. A lot of the time, you just want Nodes of the first kind.
We had been using a scheme that matched the Node's navigation title to the tag's title, but that pattern broke down when authors started designing menu items with duplicate names. (And there were other wrinkles.) So, after some desperate Friday afternoon whiteboard sketching, I realized that we could inquire of each candidate Node what tags were assigned to it explicitly, and test for an exact match of TagIDs
. And I cooked up the following method, stripped of exception handling, debugging logic, and a little project-specific stuff. The cq:tags
property is multi-valued, so there's a little more messy object navigation than you might expect.
import com.day.cq.tagging.Tag;
import java.util.Iterator;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.Value;
import org.apache.sling.api.resource.Resource;
* * *
/**
* Returns the node tagged with the specified tag; if there is more than one such node, returns
* one of them arbitrarily. The node must have the tag assigned directly to it as a property;
* nodes that are tagged by inheritance in the content tree are ignored.
* @param tag
* @return node: the node tagged with the specified tag, or null
*/
public static Node getMatchingNode(Tag tag) {
Node matchingNode = null;
Iterator<Resource> relatedNodes = tag.find();
outer:
while (relatedNodes.hasNext() && matchingNode == null) {
Node node = relatedNodes.next().adaptTo(Node.class);
PropertyIterator tagIds = node.getProperties("cq:tags");
while (tagIds.hasNext()) {
Property property = tagIds.nextProperty();
Value values[] = property.getValues();
for (Value value : values) {
String id = value.getString();
if (id.equals(tag.getTagID())) {
matchingNode = node;
break outer;
}
}
}
}
return matchingNode;
}
13 July 2012
So you think you understand optimization
Number of disk sector writes (especially for solid-state drives).* * *
Number of bytes of network traffic.
* * *
Number of taps/clicks it takes to accomplish a task.
01 July 2012
Show your stuff
I've been using Visual CV for some time now as my online shop window. I've never gotten a lead from it, as far as I know, but it's nice to have it there as a place that is completely focused on my professional work. There's more flexibility with links (I'm looking at you, LinkedIn), and with a little tweaking, you can use it to display code samples.
30 June 2012
Fermeture
22 June 2012
Happy birthday, Alan
In honor of Alan Turing's centenary, Charles Severance visits Bletchley Park where Turing contributed to codebreaking in World War II, building on work by the Polish Cypher Bureau. Bletchley Park displays powered-up replicas of the hybrid electronic/electromechanical BOMBE and Colossus devices from that period.
Meanwhile, the editors of Nature evaluate Turing's legacy with a series of articles.
15 June 2012
It's a conference, hon
14 June 2012
Let me get back to you
Blogger appears to have hosed up the formatting of posts that use <pre> and/or <code> tags. Good thing I have a little time to clean them up.
Decentralized
31 May 2012
Perl is still looking good to me
PHP is built to keep chugging along at all costs. When faced with either doing something nonsensical or aborting with an error, it will do something nonsensical. Anything is better than nothing.
28 May 2012
Up in the air
01 May 2012
Pragmatic Thinking and Learning
Along the way, he debunks certain received wisdom about continuing education and professional development: he calls the traditional four days in a remote classroom cramming the latest technology "sheep-dip" training; in his words, it's an "intensive, alien, and largely toxic experience" that wears off quickly.
The book is part of Thomas and Hunt's Pragmatic Bookshelf series (of which The Pragmatic Programmer is the flagship title), so the emphasis is on just-do-it practices. For taking notes, a cheap notebook and plain text files good enough; you don't need to invest in an expensive Moleskine or complicated note-taking app if that gets in the way of taking notes. (But if something works for you, go ahead.) The underlying principle: "Capture all ideas to get more of them."
Similarly, Hunt uses a good-enough approach to modeling how human cognition works, at least so far as we understand it today. Some might find his "dual CPU" model of the brain oversimplified and off-putting, but it's in the service of illustrating the neurological dichotomy that researchers are beginning to understand. Rather than the right brain/left brain terminology that has become popular, Hunt calls the two sides ℛ-mode and 𝖫-mode (I've attempted to capture Hunt's typography with Unicode). ℛ-mode, also called rich mode, is critical for intuition and creative problem solving, while 𝖫-mode (linear mode) "gives you the power to work through the details and make it happen." A personal example from ornithology: if rich mode is like using jizz for fast identification of a flying bird, linear mode is like walking through the plumage of the bird from top to toe, worrying about the difference between "rusty" and "rufous," in order to do a subspecies ID from field marks.
Hunt's approach to illustrations aligns with his pragmatism: his graphs and figures are hand drawn, and the more effective for it.
The book's strength is also its weakness, as several ideas (Myers-Briggs typology for all us INTJs, Vipassana meditation) that warrant an entire chapter are skimmed over in a page or two. However, the references are good, and as Hunt admits,
I've barely scratched the surface on a variety of really interesting topics, and researchers are discovering new things and disproving old ideas all the time. If anything I've suggested here doesn't work out for you, don't worry about it, and move on. There's plenty more to try. (p. 248)I found the book's heavy reliance on sidebars a smidge distracting, but that's probably just me: I feel like I don't know what to read next.
Hunt is a fan of mind maps, but I have found them to be less useful. A mind map to me is just writing your presentation's outline in a circle. On the other hand, I really like Hunt's idea of employer-facilitated study groups.
A final quibble with the graphic design: I like the readable, cushiony Bookman font that is used for body text. However, while the severely sans serif Avant Garde works well for headings and pull quotes, it's a legibility disaster to use it for URLs, as this book does in the footnotes.
30 April 2012
Fun with CQ5: 1
I wrapped this functionality into a workflow process step, but it ought to work perfectly well as part of a command-line program, too. The advantage of making it a process step is that you get a session established for you, and the navigation to the insert point has been taken care of. (I haven't yet explored developing for CQ5 with standalone programs).
I created a workflow model that uses this process step, then I created an instance of the model and ran it, specifying the English > Products > Triangle page from the Geometrixx web site as the payload.
Here's the code, sanitized to remove client names and a little condensed. I'm using version 5.4.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import org.apache.sling.jcr.resource.JcrResourceConstants;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.day.cq.workflow.WorkflowException;
import com.day.cq.workflow.WorkflowSession;
import com.day.cq.workflow.exec.WorkItem;
import com.day.cq.workflow.exec.WorkflowData;
import com.day.cq.workflow.exec.WorkflowProcess;
import com.day.cq.workflow.metadata.MetaDataMap;
import com.day.cq.wcm.api.NameConstants;
@Component
@Service
@Properties({
@Property(name = Constants.SERVICE_DESCRIPTION,
value = "Makes a new tree of nodes, subordinate to the payload node, from the content of a file."),
@Property(name = Constants.SERVICE_VENDOR, value = "Siteworx"),
@Property(name = "process.label", value = "Make new nodes from file")})
public class PageNodesFromFile implements WorkflowProcess {
private static final Logger log = LoggerFactory.getLogger(PageNodesFromFile.class);
private static final String TYPE_JCR_PATH = "JCR_PATH";
* * *
public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap args)
throws WorkflowException {
//get the payload
WorkflowData workflowData = workItem.getWorkflowData();
if (!workflowData.getPayloadType().equals(TYPE_JCR_PATH)) {
log.warn("unusable workflow payload type: " + workflowData.getPayloadType());
workflowSession.terminateWorkflow(workItem.getWorkflow());
return;
}
String payloadString = workflowData.getPayload().toString();
//get the file contents
String lipsum = null;
try {
BufferedReader is = new BufferedReader(new FileReader("e:\\Sandbox\\CQ5\\content.html"));
lipsum = readerToString(is);
}
catch (IOException e) {
log.error(e.toString(), e);
workflowSession.terminateWorkflow(workItem.getWorkflow());
return;
}
//set up some node info
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("d-MMM-yyyy-HH-mm-ss");
String newRootNodeName = "demo-page-" + simpleDateFormat.format(new Date());
SimpleDateFormat simpleDateFormatSpaces = new SimpleDateFormat("d MMM yyyy HH:mm:ss");
String newRootNodeTitle = "Demo page: " + simpleDateFormatSpaces.format(new Date());
//insert the nodes
try {
Node parentNode = (Node) workflowSession.getSession().getItem(payloadString);
Node pageNode = parentNode.addNode(newRootNodeName);
pageNode.setPrimaryType(NameConstants.NT_PAGE); //cq:Page
Node contentNode = pageNode.addNode(Node.JCR_CONTENT); //jcr:content
contentNode.setPrimaryType("cq:PageContent"); //or use MigrationConstants.TYPE_CQ_PAGE_CONTENT
//from com.day.cq.compat.migration
contentNode.setProperty(javax.jcr.Property.JCR_TITLE, newRootNodeTitle); //jcr:title
contentNode.setProperty(NameConstants.PN_TEMPLATE,
"/apps/geometrixx/templates/contentpage"); //cq:template
contentNode.setProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY,
"geometrixx/components/contentpage"); //sling:resourceType
Node parsysNode = contentNode.addNode("par");
parsysNode.setProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY,
"foundation/components/parsys");
Node textNode = parsysNode.addNode("text");
textNode.setProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY,
"foundation/components/text");
textNode.setProperty("text", lipsum);
textNode.setProperty("textIsRich", true);
workflowSession.getSession().save();
}
catch (RepositoryException e) {
log.error(e.toString(), e);
workflowSession.terminateWorkflow(workItem.getWorkflow());
return;
}
}
}
Here's the comp text in
e:\\Sandbox\\CQ5\\content.html
:
Veggies sunt bona vobis, proinde vos postulo esse magis earthnut pea catsear cress sea lettuce quandong scallion rock melon seakale jícama komatsuna onion.
Bush tomato garbanzo beetroot caulie plantain sorrel swiss chard summer purslane celtuce salad seakale rutabaga radicchio lettuce spring onion groundnut soko peanut. Tigernut bitterleaf bush tomato celery corn garbanzo bamboo shoot cauliflower komatsuna cress sweet pepper mustard squash. Celtuce parsley kakadu plum coriander peanut garlic radish water chestnut tomatillo yarrow parsnip.
Squash endive collard greens tigernut bamboo shoot okra melon turnip. Rock melon amaranth ricebean pea chickpea nori bitterleaf spring onion bush tomato aubergine beetroot lotus root earthnut pea artichoke eggplant collard greens chard water spinach. Prairie turnip napa cabbage lettuce bush tomato garlic chickweed wattle seed potato lotus root pea sprouts leek kakadu plum. Radish leek green bean epazote water chestnut bamboo shoot celtuce taro tomatillo horseradish lettuce spring onion. Mustard taro prairie turnip horseradish wattle seed kohlrabi rock melon yarrow broccoli rabe fennel spinach celery collard greens gourd turnip.
Here's what the Websites window looks like after execution:
Here's what the corresponding node looks like in CRXDE Lite:
And here's what the page looks like in the content finder:
Some notes about the demonstrator code:
- I like to use lorem ipsum-style text (I got this text from Veggie Ipsum) when I'm testing. It's always clear that you're using test data rather than a copy of something live. And in the unlikely event that your test data leaks into production, it's a lot less embarrassing to see "lorem ipsum" than "asdf jkl; asdf jkl;" or "yo mama" in 16-point type, in my opinion.
- I incorporated a timestamp into the name and title of the content page to be inserted. That way, you can run many code and test cycles without cleaning up your repository, and you know which test was the most recently run. Added bonus: no duplicate file names, no ambiguity.
- Adobe and Day have been inconsistent about providing constants for property values, node types, and suchlike. I used the constants that I could find, and used literal strings elsewhere.
- I did not fill in properties like the last-modified date. In code for production I would do so.
-
I found myself confused by
Node.setPrimaryType()
andNode.getPrimaryNodeType()
. The two methods are only rough complements; the setter takes a string but the getter returns a NodeType with various info inside it.
26 April 2012
Q and A
One of the features of a Stack Exchange site that makes it successful is the liberal awarding of brownie points to users who constructively participate in the site. Jeff Atwood and his team have figured out the alchemy that makes a community-managed site work.
At this point, the proposed site is in the stage of soliciting committers. Follow the link below and join us!
25 April 2012
!JOB ARSRCHAA,RPT/*.IVL;OUTCLASS=LP,1
19 April 2012
Doomed
It wasn’t until Windows NT 3.5.1 (and then Windows 95 later) that long file names were supported. Prior to this, there were a lot of limitations on what characters could be part of a filename or directory, one of those being a space.In fact, any space in a shell command execution was seen to be an argument. This made sense at the time so you could issue a command like this:
That, of course, would start Doom at episode 3. However, when Microsoft switched to Long File Names, it still had to support this type of invocation. So, the way the windows cmd.exe shell works is simple. You pass it a string like this:C:\DOOM\doom.exe -episode 3
And it will try to execute “C:\Program” as a file, passing it “Files\id Software\Doom\Doom.exe -nomusic” as argument to that executable. Of course, this program doesn’t exist, so it will then try to execute “C:\Program Files\id”, passing it “Software\Doom\Doom.exe -nomusic” as argument. If this doesn’t exist, it will try to execute “C:\Program Files\id Software\Doom\Doom.exe” passing in “-nomusic” as an argument. It would continue this way until a program existed and started, or until the path was depleted and no program was to be found.C:\Program Files\id Software\Doom\Doom.exe -nomusic
11 April 2012
Work in progress
That last (missing) piece -- training for teachers -- has long been something that gets overlooked when it comes to ed-tech initiatives no matter the location, Peru or the U.S. It is almost as if we believe we can simply parachute technology in to a classroom and expect everyone to just pick it up, understand it, use it, hack it, and prosper.ᔥ The Code Project
31 March 2012
Delayed mercury
30 March 2012
Enfranchised
29 March 2012
Still going
Benj Edwards reports for PCWorld on vintage systems that are still in production, running inventory, controlling aircraft systems, generating financial statements. The jewel of this (popup-heavy) report is an plugboard-programmed IBM 402 tabulator in service at a Texas industrial filter factory.
ᔥ Paul Ceruzzi and the IT History Society blog
22 February 2012
News item
18 February 2012
Home base
Back at Siteworx Reston after an extended stay onsite, and after a couple of moves and cubicle reconfigurations, here's what most of my work surface looks like now. Oh, and after receipt of peachy Valentine's Day flowers from Leta.
A really nice chair, a big Kensington trackball that they don't make anymore, a monitor and a half (the laptop), and a good-sized shelf for books above. Need to do something about that tangle of USB cables.
08 February 2012
Keep trying
Its limited battery life—a maximum of 2.5 hours, which falls to 1 hour and 20 minutes with video or other applications running—is disappointing for a device that is supposed to be used in villages where access to electricity is sporadic at best.
30 January 2012
Learning to COPE
26 January 2012
Had we but money enough and time
24 January 2012
No vanilla, just chocolate
18 January 2012
Good advice
Izzy Johnson of Girl Develop It:
I would advise anyone who wants to be involved in instruction that the first issue you have to address is never about the language. Not “What is a variable?” or “What does a for loop do?” The first issue you have to address is making sure each person in the room believes that they are capable of learning everything you are about to tell them. From your curriculum, to your slides, to your attitude–create a class that builds confidence at every step.
09 January 2012
Looking for an NB compiler
I decided to follow the single-letter style and called it C, leaving open the question whether the name represented a progression through the alphabet or through the letters in BCPL.Via The Code Project, in a paper from 1993, Dennis Ritchie describes the evolution of C from its predecessor languages.