Preparing pdf-documents for the ebook reader

Briss

Getting the best resolution for pdf-documents on the an ebook reader like kindle isn’t always easy, but there’s a great program available for “trimming” your pdfs.

With the Java-based open-source software Briss, you can remove unnecessary margins by cropping the even and odd pages of a pdf-document. The end-result is a pdf-document that better utilize the screenspace of the kindle, and hence bigger fonts to read. Results may vary though as it seems the kindle software does a little bit of optimization itself.

Note: There’s no direct installer or execution but you can create a shortcut yourself for running the program using ‘java -jar briss-x.y.z.jar’, where x.y.z refer to your downloaded version. It’s also assumed that Java Runtime Environment (JRE) is installed on your system.

PDF Split and Merge

Jumping around pdf-documents on the Kindle can be a bit cumbersome. With PDF-SaM you can split up large documents into chapters etc. for quicker browsing. This tool is also based on Java and thus requires the Java JRE.

Links

Setting up an Ant build script for your Scala project

Introduction

This is a small writeup which gives one way of setting up a build system for your Scala project. Here Apache Ant is used for managing this process, where the whole configuration is contained within a single build.xml file placed in the project’s root directory. Execution is done from command line or within your IDE environment.

Prerequisites

Install and configure Scala:

  • Define and set the SCALA_HOME variable in the OS environment
  • Update the PATH variable in the OS environment to include SCALA_HOME\bin directory

Install and configure Ant:

  • Define and set the ANT_HOME variable in the OS environment
  • Update the PATH variable in the OS environment to include ANT_HOME\bin directory
  • Optional: If you encounter memory problems, define and set ANT_OPTS=-Xmx500M with JVM memory configuration in the OS environment

Install and configure Java:

  • Define and set the JAVA_HOME variable in the OS environment
  • Update the PATH variable in the OS environment to include JAVA_HOME\bin directory

Find a suitable file structure for the project:

project-name/
  build/
  lib/
  src/
  test/
  build.xml

The Ant build script

Order of Ant targets:

  • build <- package <- doc <- compile <- init
  • clean <- init

Configure project-name/build.xml:


 

  Project Build Script
 
  
  
 
  
    
  
 
  
    
 
    
    
      
    
    
      
    
 
    
    
    
    
    
    
    
    
    
    
    
    
 
    
      
       
    
 
    
      
      
      
    	
 
    
    
 
    
    
    
    
 
    
    
      
      
    
  
 
  
    
    
      
      
    
  
 
  
    
    
      
    
  
 
  
    
    
      
    
    
      
    
    
      
    
     
  

References

@tuple – experimenting with lisp-like syntax as XML replacement

Motivation

The following post describes an experimental format which has a lisp-like syntax, with hints of JSON, for storing tree-structured data as text. The main motivation was a need to have a less verbose alternative to XML, but still be readable and editable, support pattern matching and transformation, include common binary datatypes, and enable structural type checking.

The current specification might contain errors and is not yet completed. Rule-based transformations through pattern matching is still in early stage.

Current specification

(@text
  (#

  Quick overview
    @tuple is an experimental typed data format using s-expression-like syntax
    for storing tree-structured data. In addition to handling text there is also
    support for common binary datatypes. The data format also allows transformations
    with rules that pattern match on the tree structure.

    A tuple is given by (   ...  ) or its shorthand
    form (   ... ). The sequence of expressions allowed
    is dependent on the type.
 
    A typed tuple may be a @int, @float, @bool, @bytes, @rule, @text, @note or
    @tuple. A named or untyped tuple is implicitly typed as @tuple. A @note
    is used for documentation or ignoring embedded tuples, and may be
    discarded during parsing.

    Binary operators are defined for
      :  key-value pair in @tuple or @note
      == require rule in @rule
      -> replace rule in @rule
      => merge rule in @rule

    A @tuple may contain key-value pairs, @note, @rule, untyped and typed @text, and
    untyped and typed @tuple.

    The value in a key-value pair may contain untyped or typed @text, @int, @float,
    @bool, @bytes, @tuple. It may also contain a pattern matching variable.

    A document must start with a named @tuple or typed tuple, but cannot start with
    a @note.

  Syntax
    ()    encloses a named, unnamed or typed tuple
 
    (#    begins a text block (nested text blocks are allowed but
          unbalanced text blocks must use double-quotation instead)
    #)    ends a text block
    ""    encloses a text-string of escaped characters
    @text gives one or more text-blocks and text-strings
 
    :  a pair where left side is key and right side the value
    => rule that matches the left side and then merges it with the right side
    -> rule that matches the left side and then replace it with the right side
    == rule that matches left side and then require that the right side is present
    '' encloses a pattern matching variable that specify type or named reference
 
    @tuple  gives a sequence of typed or untyped @tuple, @text, @rule, or @note
    ()      gives a sequence of typed or untyped @tuple, @text, @rule, or @note
    (Name)  gives a sequence of typed or untyped @tuple, @text, @rule, or @note
    @note   gives a sequence of typed or untyped @tuple, @text, @rule, or @note
    @rule   gives a sequence of rules
    @bytes  gives a sequence of base64-encoded text containing unsigned bytes
    @int    gives a sequence of signed integers in :32 bit or :64 bit
    @float  gives a sequence of floating point numbers in :32 bit or :64 bit
    @value  gives a sequence of unbounded numeric values
    @bool   gives a sequence of true and false values
 
  Pattern matching
    * Application of pattern matching is handled in application code
    * Distinction between shallow and deep pattern matching
      (@note "a @rule:shallow pattern matches on child nodes of @tuple"
        (@rule:shallow (value: '@int') => (Data))
      )
      (@note "a @rule:deep pattern matches recursively on child nodes of @tuple and pairs"
        (@rule:deep (value: '@int') => (Data))
      )
      (@note "a @rule is implicitly typed as @rule:shallow"
        (@rule (value: '@int') => (Data))
      )
    * Pattern matching variables can be used to
      (@note "assign variable to the value of a pair"
        (Data value: 'pi')
      )
      (@note "replace a variable with an expression"
        (@rule:deep 'pi' -> (@float 3.14))
      )
      (@note "require the structure of a tuple"
        (@rule (Data) == (size: '@int'))
      )

  Examples
    (@note "named tuples"
       (Document title: "just another format" Document)
       (Dir name: "root" files: (
           (File name: "readme" data: (@bytes (#MTIz#)))
         )
       )
    )
    (@note "unnamed tuples"
       (title: "just another format")
       (name: "root" files: (
           (name: "readme" data: (@bytes (#MTIz#)))
         )
       )
    )
    (@note "typed tuples in key-value pairs"
       (Cell name: "a" value: (@int:32 42))
       (Screen fullscreen: (@bool false))
    )
    (@note "untyped tuples in key-value pairs"
       (Cell name: "b" value: 42)
       (Screen fullscreen: false)
    )
 
  Parsing syntax
    start            ::= tuple-named | tuple-typed | rule-typed | primitives-typed
 
    tuple            ::= tuple-named | tuple-untyped | tuple-typed
    tuple-typed      ::= typed
    tuple-untyped    ::= unnamed
    tuple-type       ::= '@tuple'
    tuple-named      ::= named
    tuple-seq        ::= {rule | note | text | pair | tuple, pad}

    unnamed    ::= '(' body ')'
    named  ::= '(' tag (pad body)? (pad tag)? ')'
    typed  ::= '(' tag (pad body)? (pad tag)? ')'
    name             ::= [a-zA-Z][-A-Za-z0-9]*
    pair             ::= name ':' pad pair-value
    pair-value       ::= values | variable | tuple
    values           ::= values-untyped | values-typed
    values-untyped   ::= value-untyped | bool-untyped | text-untyped
    values-typed     ::= bytes-typed | float-typed | int-typed
                       | bool-typed | text-typed | tuple

    rule             ::= rule-typed
    rule-typed       ::= typed
    rule-type        ::= '@rule' (':shallow' | ':deep')?
    rule-seq         ::= {rule-merge | rule-replace | rule-require | note, pad}
    rule-merge       ::= tuple pad '=>' pad tuple
    rule-replace     ::= (tuple pad '->' pad tuple)
                       | variable pad '->' pad (tuple | primitives)
    rule-require     ::= tuple pad '==' pad tuple
 
    variable         ::= ''' variable-type '''
    variable-type    ::= name | int-type | float-type | bool-type | bytes-type 
                       | text-type | tuple-type | note-type

    note             ::= note-typed
    note-typed       ::= typed
    note-type        ::= '@note'

    bytes            ::= bytes-typed
    bytes-typed      ::= typed
    bytes-untyped    ::= '(#' `all validated base64 text with whitespace trimmed` '#)'
    bytes-type       ::= '@bytes'

    value-untyped    ::= int-untyped | float-untyped

    int              ::= int-untyped | int-typed
    int-typed        ::= typed
    int-untyped      ::= `characters giving an integer of any size`
    int-type         ::= '@int' (':32' | ':64')?
    int-seq          ::= {int-untyped, pad}

    float            ::= float-untyped | float-typed
    float-typed      ::= typed
    float-untyped    ::= `characters giving a floating point of any size`
    float-type       ::= '@float' (':32' | ':64')?
    float-seq        ::= {float-untyped, pad}

    bool             ::= bool-untyped | bool-typed
    bool-typed       ::= typed
    bool-untyped     ::= 'true' | 'false'
    bool-type        ::= '@bool'
    bool-seq         ::= {bool-untyped, pad}

    text             ::= text-untyped | text-typed
    text-typed       ::= typed
    text-untyped     ::= text-string | text-block
    text-type        ::= '@text'
    text-seq         ::= {text-string | text-block, pad}
    text-string      ::= '"' `all validated text until unescaped double-quote` '"'
    text-block       ::= '(#' `all validated text until text-block is balanced` '#)'
 
    pad              ::= [/s]+
 
  How to handle text
    * Text-strings are escaped by replacing '\' with '\\' then '"' with '\"', and
      unescaped by replacing '\"' with '"' then '\\' with '\'.
    * Text-blocks are not escaped, but verified that they are balanced. If not they
      become text-strings. A text-block is balanced if all embedded '(#' is matched
      by a corresponding '#)'. A text-block cannot end with the '(' character.

  Examples of invalid expressions
    (@note "duplicate keys"
      (Data name: "A" name: "B")
    )
    (@note "named tuple not enclosed with parenthesis"
      Data
    )
    (@note "type not enclosed with parenthesis"
      @tuple
    )
    (@note "variable does not contain a valid type"
      value: '@byte'
    )
 
  Examples of valid expressions
    (@note "untyped @tuple"
      (label: "Kyrre")
    )
    (@note "untyped @text"
      "Some characters!"
    )
    (@note "boolean value is implicit typed as @bool"
      value: true
    )
    (@note "numeric value implicit typed as @value"
      width: 1024
    )
    (@note "integer value implicit typed as @int:64"
      value: (@int 4)
    )
    (@note "float value implicit typed as @float:64"
      value: (@float 3.14)
    )
  #)
@text)

An example

Data with redundant information stored in rules:

(@tuple

  (@note "Rules for naming all unnamed tuples and discarding notes and rules")
  (@rule:deep
    (name: '@text' type: '@text') => (Node)
    (from: '@tuple' to: '@tuple') => (Link)
    (inputs: (
        (@rule (name: '@text' type: '@text') => (Socket))
      )
    ) => ()
    (outputs: (
        (@rule (name: '@text' type: '@text') => (Socket))
      )
    ) => ()
    '@note' -> ()
    '@rule' -> ()
  )

  (@note "Rules for replacing variables with data")
  (@rule:deep
    'binary-data' -> (@bytes (#QUI9PQ==#))
    'instructions' -> "some data in text format"
  )

  (@note "The data to be transformed")
  (name: "Group1" type: "Group"
    nodes: (
      (name: "Source" type: "Value" value: 'binary-data'
        inputs: ((name: "In" type: "bytedata"))
        outputs: ((name: "Out" type: "bytedata"))
      )
      (name: "Transform" type: "Process" data: 'instructions'
        inputs: ((name: "In" type: "bytedata"))
        outputs: ((name: "Out" type: "bytedata"))
      )
      (name: "Target" type: "Value" value: ""
        inputs: ((name: "In" type: "bytedata"))
        outputs: ((name: "Out" type: "bytedata"))
      )
    )
    links: (
      (from: (node: "Source" socket: "Out") to: (node: "Transform" socket: "In"))
      (from: (node: "Transform" socket: "Out") to: (node: "Target" socket: "In"))
    )
  )

@tuple)

The resulting data after the rules of the tuple has been applied to itself:

(@tuple
  (Node name: "Group1" type: "Group"
    nodes: (
      (Node name: "Source" type: "Value" value: (@bytes (#QUI9PQ==#))
        inputs: ((Socket name: "In" type: "bytedata"))
        outputs: ((Socket name: "Out" type: "bytedata"))
      )
      (Node name: "Transform" type: "Process" data: "some data in text format"
        inputs: ((Socket name: "In" type: "bytedata"))
        outputs: ((Socket name: "Out" type: "bytedata"))
      )
      (Node name: "Target" type: "Value" value: "output"
        inputs: ((Socket name: "In" type: "bytedata"))
        outputs: ((Socket name: "Out" type: "bytedata"))
      )
    )

    links: (
      (Link from: (node: "Source" socket: "Out")
        to: (node: "Transform" socket: "In")
      )
      (Link from: (node: "Transform" socket: "Out")
        to: (node: "Target" socket: "In")
      )
    )
  )
@tuple)

Implementation

A basic implementation in Scala is available at bitbucket.org/trondolsen/tuples and also an api documentation.

Ideas for extensions

  • Chaining together separate files
  • Nesting separate files with pattern matching variables – like referencing large bytedata and instantiating tuples
  • Use separate files for validation, update and typing of data
  • Pattern matching bits, will maybe complicate the format too much

Trait-like CSS on HTML

Defining some CSS types

One way of structuring the CSS is to define some types over the CSS classes. What these types might be may be is open, but one instance might be Behaviour, Layout and Roles. The types are not used explicitly in the CSS, but are there to help organize and abstract the CSS classes.

On these types the following CSS classes can be defined:

  • Roles – sidebar, menu, toolbar, group, item, title, input, post, search, button
  • Behaviour – inactive, hidden, selectable, grabable, highlighted
  • Layout – flow{L,R}, break{,L,R}, padded{,L,R,T,B,V,H}, spaced{,L,R,T,B,V,H}

    where {} mean “choose from” and letters are abbreviations for Left, Right, Top, Bottom, Vertically, Horizontally

For Roles it is important to add classes that can be combined or nested. For instance, toolbar and menu might both contain item and group. Furthermore, a sidebar might contain a toolbar or menu. Experimenting and identifying such classes as Roles (or any types) can help simplify or find reoccuring structures in the CSS.

Tagging the HTML elements with CSS classes

Depending on the design of the HTML page, HTML elements may be tagged as you see fit with CSS classes. The variations of Roles is a result of how the HTML elements are nested. These elements can further be tagged with Behaviour and Layout classes.

Example:

Setting the appearance of composed CSS classes

The visual appearance of the HTML elements is specified by a set of selectors, each having a pattern to match and the corresponing CSS attributes to set.

Guidelines for writing the selectors:

  • More specific compositions of CSS classes override less specific
  • Selector A B specifies node B when nested inside A
  • Selector AB specifies node with A and B
  • Selector A>B specifies node B when child of A
  • Selector A+B specifies node B if after A
  • Selector A B, C+D specifies two selectors using the same attributes

Example:

.break { clear: both; }
.breakL { clear: left; }
.breakR { clear: right; }

.spaced { margin: 4px; }
.spacedL { margin-left: 4px; }
.spacedV { margin-top: 4px; margin-bottom: 4px; }
.spacedH { margin-left: 4px; margin-right: 4px; }

.menu {
  background-color: #404040;
}

.menu .title {
  color: #a0a0a0;
  font-weight: bold;
}

.menu .item {
  color: #a0a0a0;
}

/* Here .item.selectable is node with both */
.menu .item.selectable#hover {
  color: #f0f0f0;
}

References

Reminders on Scala syntax

Reminders

The companion object (both for own code and Scala’s API)

// The class definition with primary constructor
class Node protected (val a: String, private var b: String) {
  // imports definitions in companion object
  import Node._ 

  // attributes and primary constructor code
  var busy = false

  // methods
  override def toString() = "A"
}

// Companion object comes after the class/trait definition
object Node {
  // apply and unapply methods for object pattern matching (like case classes)
  // and object construction
  apply(arg: String): A = new A("a", arg)

  // static methods and variables
}

val node = Node("test","me")

Setter and getter functions are defined implicitly for val, var and referenced arguments in primary constructor. To set these manually

class A {
  private[this] var v: Int = 0 // avoids implicit setters and getters
  def value(): Int = v
  def value_=(t: Int): Unit = { v = t } // setters returns Unit
}

Adding indexing operators

// Here T give the type parameter for the class
class A[T] (size: Int) {
  private val array = new Array[T](size)
  def apply(index: Int): T = { /** get index value */ }
  def update(index: Int, value: T): Unit = { /** set index value*/ }
}

val a = new A[Int](100)
a(0) = 1
val n = a(0)

Binding a variable during pattern matching

str match {
  case bound @ "A match!" => println(bound)
  case _ => // no match
}

Defining an extractor for pattern matching (example lacks validation)

object Email {
  def apply(user: String, domain: String): String =
    user + "@" + domain

  def unapply(str: String): Option[(String,String)] = {
    str.split("@").toList match {
      case user :: domain :: Nil => Some(user,domain)
      case _ => None
    }
  }
}

"me@host.com" match {
  case Email(name,host) => println("Username is " + name)
  case _ => println("Invalid email address")
}

Imports can be grouped

import scala.collection.mutable.{Map,Stack,Queue}

Types can be aliased

type QMap = Map[Int,Queue[Int]]

Upper A <: T (A is a subtype of T) and lower A >: T (A is a supertype of T) bounded type parameters

class List[+A](elem: A, next: Option[List[A]]) {
  def prepend[B >: A](newElem: B): List[B] = new List(newElem, Some(this))
}
// scala> val l1 = new List(1.0, None)
// l1: List[Double] = List@1f49969
// scala> val l2 = new List(10,Some(l1))
// l2: List[AnyVal] = List@19bf996

def sort[T <: Ordered[T]](list: List[T]) { /** ... */ }

Writing () is optional with no arguments, and . is optional for methods with one argument

val b = new B
List(1,2,3) map (_ * 2)

The return keyword is optional (and curly braces on a single expression too)

def test() = "test"

The return type Unit is implicit when functions are declared without =

def printBig(str: String): Unit = {
  println(str.toUpperCase)
  () /** explicitly end the expression with the unit value */
}
def printBig(str: String) { println(str.toUpperCase) } /** same as previous */

References

Simple serialization with XML strings in Javascript

Introduction

Included in this post are some quick and simple functions for doing XML serialization in Javascript through strings. Reserved XML characters < > & ' " are escaped from input and if any invalid input are found an exception will be thrown.

List of XML utility functions:

  • toXmlHeader() – Creates the XML header.
  • toXmlElem(name: string, attributes: object) – Creates and closes an XML element.
  • toXmlElemOpen(name: string, attributes: object) – Creates and opens an XML element.
  • toXmlElemClose(name: string) – Closes an XML element.
  • toXmlText(text: string) – Creates XML text.

A serialization example

var xml = toXmlHeader();
xml += toXmlElemOpen("Library"); // No attributes given.

xml += toXmlElemOpen("Authors", {country: "Norway"});
xml += toXmlElem("Author", {name:"Petter Dass"});
xml += toXmlElemClose("Authors");

xml += toXmlElemOpen("Books"); // No attributes given.
xml += toXmlElem("Book", {title:"book1", author:"author1"});
xml += toXmlElemOpen("Book", {title:"book2", author:"author1"});
xml += toXmlText("Ach, So?");
xml += toXmlElemClose("Book");
xml += toXmlElem("Book", {title:"book3", author:"author2"});
xml += toXmlElem("Book"); // No attributes given.
xml += toXmlElemClose("Books");

xml += toXmlElemClose("Library");
alert(xml); // the complete xml is now contained inside the string.






Ach, So?

Sourcecode for the XML utility functions

function toXmlValid(str) {
  if (str === undefined || str === null || str.match === undefined || str.match(/<|>|&|'|"/) !== null) {
    throw("invalid string given");
  }

  return str;
}

function escapeXmlText(str) {
  if (str === undefined || str === null || str.replace === undefined) {
    throw("invalid string given");
  }

  // The order of replace is important because the & character is used in escaping.
  return str.replace(/&/g, "&").replace(/"/g, """).replace(//g, ">").replace(/'/g, "'");
}

function unescapeXmlText(str) {
  if (str === undefined || str === null || str.replace === undefined) {
    throw("invalid string given");
  }

  // The order of replace is important because the & character is used in unescaping.
  return str.replace(/</g, "<").replace(/>/g, ">").replace(/'/g, "'").replace(/"/g, "\"").replace(/&/g, "&");
}

function toXmlHeader() {
  return "";
}

function toXmlAttr(name, value) {
  return " " + toXmlValid(name) + "=\"" + escapeXmlText(value) + "\"";
}

function toXmlElem(tagName, attributes) {
  var str = "\n<" + toXmlValid(tagName);
	
  if (attributes !== undefined) {	
    for (var key in attributes) {
      if (attributes.hasOwnProperty(key) === true) {
        str += toXmlAttr(key, attributes[key]);
      }
    }
  }
	
  return str + "/>";
}

function toXmlElemOpen(tagName, attributes) {
  var str = "\n<" + toXmlValid(tagName);
	
  if (attributes !== undefined) {
    for (var key in attributes) {
      if (attributes.hasOwnProperty(key) === true) {
        str += toXmlAttr(key, attributes[key]);
      }
    }
  }
	
  return str + ">";
}

function toXmlElemClose(tagName) {
  return "";
}

function toXmlText(text) {
  return escapeXmlText(text);
}

References

Comparison against null and undefined in Javascript

Values in Javascript can come from

  • Object – object reference
  • String – immutable, 16-bit USC-2
  • Boolean – true, false
  • Number – only 64-bit floating point, IEEE 754 (double)
  • null – empty object reference
  • undefined – unassigned variables and function arguments, missing object properties

Boolean evaluation of values using == and != operators

Values that are interpreted as false:

  • false
  • null
  • undefined
  • "" – the empty string
  • 0 – the number 0
  • NaN – not a number, result of undefined math operation

All other values and objects are interpreted as true.

Working with comparison operators

The == and != operators will do implicit type conversion of it’s arguments to match their type.┬áSince the null and undefined values are both equal with these operators, errors can occur when a missing object property is used in a null-comparison.

By using the === and !== operators, no implicit type conversion will be done. The values null and undefined are not equal using these operators. These operators can be used to check against missing properties and unassigned arguments among other.

Notice: Be careful if updating your old javascript code with === and !== for null-comparison tests. It might be that an undefined-comparison should have been used instead (or both). Failure to recognise these cases can introduce hard-to-catch errors.

References

Deep Pocket Layout – tree-based UI layout

Overall idea

The Deep Pocket Layout is a specialized tree data-structure for use in non-overlapping layout of widgets. This data-structure can be used for partitioning screen-space, like the quadtree or kd-tree data-structures, and uses the naming conventions of border layout. In usage, it functions as a tree of either vertically or horizontally linked partitions. Much like a combined border/horizontal/vertical layout.

This data-structure will be explained by example as a container widget, which is part of an inheritance hierarchy of widgets.

Introduction by example

The figure above shows the named “pockets” of the data structure. The outmost pockets are used for linking the Pocket Layout Widget (PW) together with other PWs. The center pocket can contain a PW (thus forming a tree) or a different kind of Widget (leaf node). The center pocket specifies the screen-space, while the border pockets acts as internal links to other PWs. When the left or right pockets are linked, they become part of a horizontal layout (top and bottom pockets must always be empty). Conversely, when the top or bottom pockets are linked, they become part of a vertical layout (left and right pockets must always be empty).

The first example below shows how a widget (of any kind) can be inserted by using the center pocket of the PW.

PWs can be arranged into either vertical and horizontal layouts. The figure below shows how a horizontal layout is started. Since P1 it the root of the tree, a new PW P3 is created, replacing the center pocket content of P1. Then P2 is linked with P3, starting a horizontal layout.

The figure below shows how a vertical layout is started. This example is identical to the previous one, but starting a vertical layout instead. (The root constraint for P1 still applies.)

The final example shows how to split a PW in a horizontal layout into a vertical. Here P3 is already part of a horizontal layout. A new PW is created and replaced with P3s center pocket. The vertical layout is then started by linking P6 with P7.

The final deep pocket layout of this example is visualized in the following figure.

Summary

Some features:

  • Enables combination of tree-based vertical/horizontal layouts.
  • Allows the user to insert/remove any PWs in the hierarchy from any depth, thus controlling the complete layout with drag-and-drop.
  • User control over screen space that is delegated within the tree hierarchy.
  • PW linked in either a horizontal or vertical layout can adjust neighboring PWs or delegate request to parent PW.

Implementation extensions:

  • The example used “share equally”, but custom ratios of the linked PWs can be handled by the parent PW.
  • Overlay of drag-and-drop targets when dragging is in progress.

Code documentation for Javascript and Actionscript 3

Prerequisites for Actionscript documentation

Prerequisites for Javascript documentation

Actionscript 3 Code Documentation

Example documentation:

/**
* class-description
*/
class-declaration
/**
* method-description
*
* @see method-name
* @param name description
* @return description
*/
method-declaration.
/** attribute-description */
attribute-declaration

Extracting the documentation from the sourcecode:

asdoc.exe -source-path /source/directory -doc-sources /source/directory -output /output/directory -window-title "Project Title"

Javascript Code Documentation

Example documentation:

/**
 * class-description
 *
 * @author author
 * @extends class-name
 * @see class-name
 * @version version
 * @constructor
 */
class-constructor-declaration.
/**
 * method-description
 *
 * @see class-name#method-name
 * @param {data-type} name description
 * @return description
 * @type data-type-of-return
 */
method-declaration.

Extracting the documentation from the sourcecode:

perl jsdoc.pl /source/directory --directory /output/directory --project-name "Project Title"

References for this post

Multiple Inheritance in Javascript

Notice

Javascript does not support multiple inheritance, so the given method will break the instanceof operator! Javascript checks inheritance by traversing the linked list prototype.__proto__ for occurences of the requested prototype. This means that one prototype can only contain one reference to another prototype and in effect only inherit from one prototype. By discarding support for the instanceof operator, multiple inheritance can be simulated.

A support function is available that provide similar functionality as the instanceof operator.

Description and implementation details

The function responsible for applying inheritance between classes works by copying all missing attributes/methods from parent class(es) to the inheritance class. In addition, metadata in the class constructors allows for isInstanceOf() comparisons to to made on objects.

/**
 * Check if object is instance of given class.
 *
 * @param {Object} object Object to check inheritance of.
 * @param {Function} classConstructor Constructor function to check inheritance against.
 * @return Boolean indicating success of comparison.
 * @type {Boolean}
 */
function isInstanceOf(object, classConstructor) {
  // Check for class metadata
  if (object.constructor.meta === undefined || classConstructor.meta === undefined) {
    return object instanceof classConstructor; // Use standard inheritance test
  }
 
  // Use inheritance metadata to perform instanceof comparison
  return object.constructor.meta.fromClasses[classConstructor.meta.index] !== undefined;
}
 
/**
 * Applies inheritance to a class (first argument) from classes (second, third, and
 * so on, arguments).
 *
 * Notes:
 *  - This WILL BREAK the instanceof operator! Use the isInstanceOf() function instead.
 *  - Parent classes must be fully declared before calling this function.
 *  - Multiple classes will be copied in sequence.
 *  - Properties that already exists in class will not be copied.
 */
function applyInheritance() {
  // Validate arguments
  if (arguments.length < 2) {
    throw new Error("No inheritance classes given");
  }
 
  var toClass = arguments[0];
  var fromClasses = Array.prototype.slice.call(arguments, 1, arguments.length);

  // Check if class referencer has been created
  if (applyInheritance.allClasses === undefined) {
    applyInheritance.allClasses = [];
  }
 
  // Check for inheritance metadata in toClass
  if (toClass.meta === undefined) {
    toClass.meta = {
      index: applyInheritance.allClasses.length,
      fromClasses : [],
      toClasses: []
    };
    toClass.meta.fromClasses[toClass.meta.index] = true; // class links to itself
    applyInheritance.allClasses.push(toClass);
  }
 
  // Apply inheritance fromClasses
  var fromClass = null;
  for (var i = 0; i < fromClasses.length; i++) {
    fromClass = fromClasses[i];
		
    // Check for inheritance metadata in fromClass
    if (fromClass.meta === undefined) {
      fromClass.meta = {
        index: applyInheritance.allClasses.length,
        fromClasses: [],
        toClasses: []
      };
      fromClasses[i].meta.fromClasses[fromClass.meta.index] = true; // class links to itself
      applyInheritance.allClasses.push(fromClass);
    }
 
    // Link toClass and fromClass
    toClass.meta.fromClasses[fromClass.meta.index] = true;
    fromClass.meta.toClasses[toClass.meta.index] = true;
 
    // Copy prototype fromClass toClass
    for (var property in fromClass.prototype) {
      if (toClass.prototype.hasOwnProperty(property) === false) {
        // Copy missing property from the parent class to the inheritance class
        toClass.prototype[property] = fromClass.prototype[property];
      }
    }
  }
}

Multiple inheritance example:

function Animal(name) {
   // Attributes
   this.name = name;
}

Animal.prototype.makeSound = function (soundOutput) {
   soundOutput.playSound("Unknown");
};

Animal.prototype.getHierarchy = function () {
   return "Animal";
};

function Petable(personality) {
   // Attributes
   this.personality = personality;
}

Petable.prototype.isCompatible = function (personality) {
   return this.personality == personality;
};

function Dog(name, personality, breed) {
   // Call parent constructors
   Animal.call(this, name);
   Petable.call(this, personality);

   // Attributes
   this.breed = breed;
}
// Apply inheritance to Dog from Animal and Petable
applyInheritance(Dog, Animal, Petable);

An example of how to override a method of a parent class:

Dog.prototype.makeSound = function (soundOutput) {
   soundOutput.playSound("Bark");
};

An example of how an overidden method can delegate to it's parent method:

Dog.prototype.getHierarchy = function () {
   // returns "Animal.Dog"
   return Animal.prototype.getHierarchy.apply(this, arguments) + ".Dog";
};

An example of how to call a parent method:

Dog.prototype.isOwner = function (name, personality) {
   if (this.name != name) {
      return false;
   }

   return Petable.prototype.isCompatible.call(this, personality);
};

Notes on calling function objects

References