From ff01f39c1e8c9b9549d884a0db1f9a74799cf37e Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Wed, 24 Aug 2016 09:43:05 -0400 Subject: [PATCH] Liberate current implementation of "Calc DSL" (Copyright headers will be added in the next commit; these are the original files, unaltered in any way.) The internal project name at LoVullo is simply "Calc DSL". This liberates the entire thing. If anything was missed, I'll be added later. To continue building at LoVullo with this move, symlinks are used for the transition; this is the exact code that is used in production. There is a lot here---over 25,000 lines. Much of it is in disarray from the environment surrounding its development, but it does work well for what it was intended to do. (LoVullo folks: fork point is 65723a0 in calcdsl.git.) --- Makefile.am | 4 +- README.md | 7 + doc/Makefile.am | 4 +- src/current/.gitignore | 1 + src/current/Makefile | 8 + src/current/c1map.xsl | 383 +++ src/current/c1map/c1nodes.xsl | 95 + src/current/c1map/render.xsl | 339 +++ src/current/c1map/transform.xsl | 53 + src/current/c1map/valparse.xsl | 130 + src/current/calc.xsd | 883 +++++++ src/current/compile.xsl | 101 + src/current/compiler/fragments.xsl | 137 ++ src/current/compiler/js-calc.xsl | 1141 +++++++++ src/current/compiler/js.xsl | 1908 +++++++++++++++ src/current/compiler/linker.xsl | 1442 +++++++++++ src/current/compiler/linker/log.xsl | 95 + src/current/compiler/map.xsl | 997 ++++++++ src/current/compiler/validate.xsl | 771 ++++++ src/current/compiler/validate/domain.xsl | 193 ++ src/current/compiler/validate/param.xsl | 103 + src/current/compiler/worksheet.xsl | 543 +++++ src/current/doc/.gitignore | 4 + src/current/doc/chapters/class.tex | 372 +++ src/current/doc/manual.sty | 30 + src/current/doc/manual.tex | 19 + src/current/dot.xsl | 65 + src/current/dot/attr-color.xsl | 72 + src/current/dot/attr-extern.xsl | 33 + src/current/dot/attr-keep.xsl | 33 + src/current/dot/attr-shape.xsl | 62 + src/current/dot/defnode-attr.xsl | 70 + src/current/dot/defnode.xsl | 107 + src/current/dot/depout.xsl | 212 ++ src/current/dot/pkg-exec.xsl | 99 + src/current/dot/pkg-obj.xsl | 49 + src/current/include/calc-display.xsl | 702 ++++++ src/current/include/depgen.xsl | 526 ++++ src/current/include/display.xsl | 551 +++++ src/current/include/dslc-base.xsl | 90 + src/current/include/entry-form.xsl | 323 +++ .../include/exslt/str.tokenize.template.xsl | 65 + src/current/include/orderizer.xsl | 268 ++ src/current/include/preproc/domain.xsl | 226 ++ src/current/include/preproc/eligclass.xsl | 261 ++ src/current/include/preproc/expand.xsl | 691 ++++++ src/current/include/preproc/macros.xsl | 456 ++++ src/current/include/preproc/package.xsl | 817 +++++++ src/current/include/preproc/path.xsl | 230 ++ src/current/include/preproc/symtable.xsl | 959 ++++++++ src/current/include/preproc/template.xsl | 1149 +++++++++ src/current/include/preprocess.xsl | 48 + src/current/include/symbol-map.xml | 80 + src/current/include/util.xsl | 186 ++ src/current/link.xsl | 8 + src/current/map.xsd | 412 ++++ src/current/pkg-dep.xsl | 56 + src/current/scripts/entry-form.js | 2164 +++++++++++++++++ src/current/src/.gitignore | 6 + src/current/src/Makefile | 18 + .../src/com/lovullo/dslc/DslCompiler.java | 303 +++ src/current/standalone.xsl | 226 ++ src/current/summary.css | 835 +++++++ src/current/summary.xsl | 2107 ++++++++++++++++ src/current/tools/csv2xml | 110 + src/current/tools/csvi | 124 + src/current/tools/csvm2csv | 112 + src/current/tools/gen-make | 96 + src/current/tools/lib/zipre.php | 124 + src/current/tools/tdat2xml | 274 +++ src/current/tools/zipre | 23 + src/current/worksheet.xsd | 34 + 72 files changed, 25223 insertions(+), 2 deletions(-) create mode 100644 src/current/.gitignore create mode 100644 src/current/Makefile create mode 100644 src/current/c1map.xsl create mode 100644 src/current/c1map/c1nodes.xsl create mode 100644 src/current/c1map/render.xsl create mode 100644 src/current/c1map/transform.xsl create mode 100644 src/current/c1map/valparse.xsl create mode 100644 src/current/calc.xsd create mode 100644 src/current/compile.xsl create mode 100644 src/current/compiler/fragments.xsl create mode 100644 src/current/compiler/js-calc.xsl create mode 100644 src/current/compiler/js.xsl create mode 100644 src/current/compiler/linker.xsl create mode 100644 src/current/compiler/linker/log.xsl create mode 100644 src/current/compiler/map.xsl create mode 100644 src/current/compiler/validate.xsl create mode 100644 src/current/compiler/validate/domain.xsl create mode 100644 src/current/compiler/validate/param.xsl create mode 100644 src/current/compiler/worksheet.xsl create mode 100644 src/current/doc/.gitignore create mode 100644 src/current/doc/chapters/class.tex create mode 100644 src/current/doc/manual.sty create mode 100644 src/current/doc/manual.tex create mode 100644 src/current/dot.xsl create mode 100644 src/current/dot/attr-color.xsl create mode 100644 src/current/dot/attr-extern.xsl create mode 100644 src/current/dot/attr-keep.xsl create mode 100644 src/current/dot/attr-shape.xsl create mode 100644 src/current/dot/defnode-attr.xsl create mode 100644 src/current/dot/defnode.xsl create mode 100644 src/current/dot/depout.xsl create mode 100644 src/current/dot/pkg-exec.xsl create mode 100644 src/current/dot/pkg-obj.xsl create mode 100644 src/current/include/calc-display.xsl create mode 100644 src/current/include/depgen.xsl create mode 100644 src/current/include/display.xsl create mode 100644 src/current/include/dslc-base.xsl create mode 100644 src/current/include/entry-form.xsl create mode 100644 src/current/include/exslt/str.tokenize.template.xsl create mode 100644 src/current/include/orderizer.xsl create mode 100644 src/current/include/preproc/domain.xsl create mode 100644 src/current/include/preproc/eligclass.xsl create mode 100644 src/current/include/preproc/expand.xsl create mode 100644 src/current/include/preproc/macros.xsl create mode 100644 src/current/include/preproc/package.xsl create mode 100644 src/current/include/preproc/path.xsl create mode 100644 src/current/include/preproc/symtable.xsl create mode 100644 src/current/include/preproc/template.xsl create mode 100644 src/current/include/preprocess.xsl create mode 100644 src/current/include/symbol-map.xml create mode 100644 src/current/include/util.xsl create mode 100644 src/current/link.xsl create mode 100644 src/current/map.xsd create mode 100644 src/current/pkg-dep.xsl create mode 100644 src/current/scripts/entry-form.js create mode 100644 src/current/src/.gitignore create mode 100644 src/current/src/Makefile create mode 100644 src/current/src/com/lovullo/dslc/DslCompiler.java create mode 100644 src/current/standalone.xsl create mode 100644 src/current/summary.css create mode 100644 src/current/summary.xsl create mode 100755 src/current/tools/csv2xml create mode 100755 src/current/tools/csvi create mode 100755 src/current/tools/csvm2csv create mode 100755 src/current/tools/gen-make create mode 100644 src/current/tools/lib/zipre.php create mode 100755 src/current/tools/tdat2xml create mode 100755 src/current/tools/zipre create mode 100644 src/current/worksheet.xsd diff --git a/Makefile.am b/Makefile.am index 90090f1b..e632d543 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,7 +22,9 @@ path_src = src path_test = test # all source files will be run through hoxsl; see `applies' target -apply_src := $(shell find "$(path_src)" "$(path_test)" -name '*.xsl') +apply_src := $(shell find "$(path_src)" "$(path_test)" \ + -name '*.xsl' \ + -a \! -path "$(path_src)"/current/\* ) apply_dest := $(apply_src:%.xsl=%.xsl.apply) # needed by test runner diff --git a/README.md b/README.md index 3a5dbdb4..6b562411 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,13 @@ TAME's core library, and [hoxsl](https://github.com/lovullo/hoxsl) was developed as a supporting library. +## "Current" +The current state of the project as used in production is found in +`src/current/`. The environment surrounding the development of this +project resulted in a bit of a mess, which is being refactored into +`src/` as it is touched. Documentation is virtually non-existent. + + ## License This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free diff --git a/doc/Makefile.am b/doc/Makefile.am index 6bd1f0c1..889824bc 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -21,7 +21,9 @@ path_src := ../src path_tools := ../tools -stylesheets := $(shell find "$(path_src)" -name '*.xsl') +stylesheets := $(shell find "$(path_src)" \ + -name '*.xsl' \ + -a \! -path "$(path_src)"/current/\* ) stexi := $(stylesheets:.xsl=.texi) info_TEXINFOS = tame.texi diff --git a/src/current/.gitignore b/src/current/.gitignore new file mode 100644 index 00000000..24600083 --- /dev/null +++ b/src/current/.gitignore @@ -0,0 +1 @@ +!Makefile diff --git a/src/current/Makefile b/src/current/Makefile new file mode 100644 index 00000000..dc6eb542 --- /dev/null +++ b/src/current/Makefile @@ -0,0 +1,8 @@ + +.PHONY: dslc clean + +dslc: + $(MAKE) -C src/ dslc + +clean: + $(MAKE) -C src/ clean diff --git a/src/current/c1map.xsl b/src/current/c1map.xsl new file mode 100644 index 00000000..660fdf75 --- /dev/null +++ b/src/current/c1map.xsl @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [c1map] + + + + + + fatal: c1-map node not found + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [c1map] - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + error: missing required template argument ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + error: cannot have @dict on static mapping ` + + ' + + + + + + + error: cannot have @default on static mapping ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [c1map] fatal: unexpected node + + : + + + + + + + + + + + + / + + + + diff --git a/src/current/c1map/c1nodes.xsl b/src/current/c1map/c1nodes.xsl new file mode 100644 index 00000000..da4470f2 --- /dev/null +++ b/src/current/c1map/c1nodes.xsl @@ -0,0 +1,95 @@ + + + + + + + + + + + + => + + + + + + + + + + array( + + ) + + + + + + + + => + + + + + , + + + + + + '[ + + ]' => + + , + + + + + + '[ + + ]' => + + , + + + + + + + + + diff --git a/src/current/c1map/render.xsl b/src/current/c1map/render.xsl new file mode 100644 index 00000000..c782a35a --- /dev/null +++ b/src/current/c1map/render.xsl @@ -0,0 +1,339 @@ + + + + + + + + + + <?php + + + + namespace lovullo\c1\interfaces\c1\contract\ + + ; + + + class + + { + + + public function compose( $contract ) { + + return array( + + + + + ); + + } + + + } + + ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' + + ' + + + + + $contract->checkDefaultValue( ' + + ', + + ) + + + + + null + + + + + + + + + + + + + + + $contract->getValueByContext( + + + + + + , ' + + + ' + + ) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $contract->getValue( ' + + ', $contract->getValueIndex( ' + + ' ) + + + , + + + + ) + + + + + + + + + + + + + + + error: variable not within scope: + + / + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $contract->iterateValues( ' + + ', + function( $contract ) { + return array( + + ); + } + ) + + + + + + + + ' + + + + + > + + + ' + + + + + + + + + , + + + + + + + ( ( + $contract->isTruthy( + + ) + ) ? + + + + : null ), + + + + + + [c1map] fatal: unexpected node during render: + + + + + diff --git a/src/current/c1map/transform.xsl b/src/current/c1map/transform.xsl new file mode 100644 index 00000000..87936486 --- /dev/null +++ b/src/current/c1map/transform.xsl @@ -0,0 +1,53 @@ + + + + + + + + + + ucwords(strtolower( + + )) + + + + + + + + + + + + + + + + error: unknown transformation ` + + ' for ` + + ' + + + + + + + internal error: unexpected node for transformation: + + + + + + diff --git a/src/current/c1map/valparse.xsl b/src/current/c1map/valparse.xsl new file mode 100644 index 00000000..8c4ab1ff --- /dev/null +++ b/src/current/c1map/valparse.xsl @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ' + + + ' . + + + + + + + + + + + + + ' + + ' + + + + + . ' + + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/calc.xsd b/src/current/calc.xsd new file mode 100644 index 00000000..0030aa73 --- /dev/null +++ b/src/current/calc.xsd @@ -0,0 +1,883 @@ + + + + + + + + + Generic name reference restriction, intended to be generic enough to + work with most systems (supporting both C-style and Lisp-style + identifiers). + + The systems that implement this schema should perform their own, more + strict, type checks. + + + + + + + + + + + + + + + Valid value for constants. + + + + + + + + + + + + + + + Documentation for a specific element. + + The documentation must not be sparse; please provide something + descriptive that will be useful to someone completely new to the code. + + + + + + + + + + + + + Single-character index variable + + + + + + + + + + + + + Symbol used to represent an entity when rendered. + + The string should consist of TeX/LaTeX commands and should produce a + single symbol. + + + + + + + + + + + + + + Abstract operator type used to classify elements as operators. + + Operators are portions of the calculation that perform a portion of + the calculation. For example, a summation would classify as an + operation (operator), but value-of would not (as it is only + representing a value, but not performing a calculation). + + + + + + + + + Elements/attributes common to all operator types (see the operator + element for a description on what qualifies as an operator). + + All operators may include child calculations. Furthermore, they may + be labeled and may have an identifier associated with their result. + + + + + + + + + + + + + Optional identifier with which the result of the calculation may be + referenced. + + + + + + + Optional description of a calculation. @label is used in place of + @desc to ensure that it is not confused with the otherwise required + @desc attribute. + + + + + + + @desc should be used to describe a value that is generated by a + calculation and should not otherwise be used (e.g. with + lv:sum/@generate) + + This is different from @label, which provides a high-level + description of what the equation is doing. @desc describes what the + generated value is. + + + + + + + Allows for the definition of an index variable which will be + defined for all children of the operation. + + + + + + + + + + Represents a summation (addition) of a set of values. + + If @of is used, the equation defined by child elements will be + iterated using an index on the set provided by @of. If no equation is + given, all elements in the set identified by @of will be summed. + + If @of is omitted, the result of each child element will be summed. + + This operator should also be used for subtraction by summing negative + values. + + + + + + + + + + Iterate over all values of this set. Must be a set. + + + + + + + + Optional name of a set to generate from this expressions. + + Generators are compatible only with @of and a sub-expression. + + + + + + + + Symbol to use when typesetting the generator + + + + + + + + Yield precision + + + + + + + + + + + + + Represents the product (multiplication) of a set of values. + + If @of is used, the equation defined by child elements will be + iterated using an index on the set provided by @of. If no equation is + given, all elements in the set identified by @of will be multiplied. + + If @of is omitted, the result of each child element will be + multiplied. + + While this operator may also be used for division by multiplying by + the inverse of a number (n^-1), a limited quotient operator is + provided for clarity and convenience. + + + + + + + + + + Iterate over all values of this set. Must be a set. + + + + + + + + Optional name of a set to generate from this expressions. + + Generators are compatible only with @of and a sub-expression. + + + + + + + + Symbol to use when typesetting the generator + + + + + + + + Dot product of any number of vectors + + + + + + + + Yield precision + + + + + + + + + + + + + Represents the quotient (division) of two values. + + This operator is to be thought of as a fraction: the numerator is + identified by the first child element and the denominator the second. + + While the summation operator may also be used for division by + multiplying by the inverse of a number (n^-1), this limited operator + is provided for clarity and convenience. + + + + + + + + + + + + + + + + Exponent; the first child node is the base, the second is the order. + + + + + + + + + + + + + + + Construct a list using the given element and an existing list + + This is analogous to lisp's cons; the first argument is the car and + the second is the cdr. + + + + + + + + + + + + + + + + + + + + Retrieve the first element of a list + + Analogous to lisp's car. + + + + + + + + + + + + + + + + + + + + Return the list without its first element + + If the list contains only one element, then an empty list will be + returned. Analogous to lisp's cdr. + + + + + + + + + + + + + + + + + + + + Retrieves the length of a vector + + + + + + + + + + + + + + + + + + + + + Denotes a function application. + + The result of the function identified by @name will be used in + place of the call. The application may optionally accept an + argument list (if the function accepts arguments). + + + + + + + + + + + + + + Name of the function to apply + + + + + + + + + + + + + + + + Represents an argument to be applied to a function. + + + + + + + + + + + Name of the parameter to apply to the function + + + + + + + + + + Recursively applies the current function. + + All arguments are copied to the argument list of the function application unless overridden. + + + + + + + + + + + + + + + + + + + + + + + Converts the given value to an integer, rounding up if necessary (e.g. 0.1 => 1) + + + + + + + + + + Value precision to consider for rounding. + + + + + + + + + + + + + Converts the given value to an integer, rounding down if necessary (e.g. 0.9 => 0) + + + + + + + + + + Value precision to consider for rounding. + + + + + + + + + + + + Creates a set out of its siblings + + + + + + + + + + + + + + + + Outputs the result of the contained expression to the console and + returns its value. + + + + + + + + + + + + + + + + + Defines a condition under which the expression will yield one if + true, otherwise will be strongly zero (zero even if + undefined) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + More flexible alternative to the @index attribute on elements; supports + calculations for determining the index + + + + + + + + + + + + + Returns the value associated with the given identifier. + + + + + + + + + + + + An identifier for which the value should be retrieved + + + + + + + Allows for the definition of an index variable which will be + defined for all children of the operation. + + + + + + + Optional description of a calculation. @label is used in place of + @desc to ensure that it is not confused with the otherwise required + @desc attribute. + + + + + + + + + + Returns @value. This element simply enforces documentation and prevents + the use of magic values. + + + + + + + + + + + + Value of constant (must be within the domain of its @type) + + + + + + + Type (domain) of the constant (inferred when not provided) + + + + + + + Description of the value explaining its intent + + + + + + + Optional description of a calculation. @label is used in place of + @desc to ensure that it is not confused with the otherwise required + @desc attribute. + + + + + + + + + + Represents a list of cases for a calculation. + + + + + + + + + + + + + + + + + Optional description of the case + + + + + + + + + + + + + + + + + + Optional description of the case + + + + + + + + + + + Optional description of the case set + + + + + + + + + + Declares variables visible within the let block. + + This exists as a means of assignment for re-using values. + + + + + + + + + Declares a list of values to define for this block + + + + + + + + + + Declares a value that will remain in scope for the let block + + + + + + + + + + + Variable name + + + + + + + + Variable datatype + + + + + + + + + Vector/matrix; if omitted, implicitly scalar. + + + + + + + + Describe the purpose of the value + + + + + + + + + + + + + + + + + + + + Represents every element that can be used to perform a calculation. + Implementors may use this group to accept any type of calculation. + + + + + + + + + + + + + + + + + + Root calculation node; this should be the entry point for any type of + calculation. This helps to ensure that certain nodes are only used at + the beginning of a calculation (such as cases). + + + + + + + + + + diff --git a/src/current/compile.xsl b/src/current/compile.xsl new file mode 100644 index 00000000..2e8d561f --- /dev/null +++ b/src/current/compile.xsl @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + !!! preprocessor error: + + + + + + + + + + + + + + + + + + + + + + + + + fatal: source file is invalid: unexpected node + + + + + diff --git a/src/current/compiler/fragments.xsl b/src/current/compiler/fragments.xsl new file mode 100644 index 00000000..8ea60245 --- /dev/null +++ b/src/current/compiler/fragments.xsl @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [jsc] fatal: unknown symbol type for ` + + ': + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/compiler/js-calc.xsl b/src/current/compiler/js-calc.xsl new file mode 100644 index 00000000..8594d4f7 --- /dev/null +++ b/src/current/compiler/js-calc.xsl @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + : + + + + + + + + + + yes + + + + + + + + ( function() { var result = + + + + + + ; + ( debug[' + + '] || ( debug[' + + '] = [] ) ).push( result ); + + return result; + } )() + + + + + + + + ( + + ) + + + + + ( + + ( + + ) + + + * ( + + + * + + + + + ) + ) + + + + + + + + + + + + + + + 8 + + + + + + + + + + + + + + + + + _$i$_ + + + + + + ( function() { + + + var sum = 0; + + + + + + + + + + + + + + + + + consts[' + + '] + + + + args[' + + '] + + + + + + + var G = []; + + + + for ( var + + in + + ) { + + var result = +(+( + + + + + + + + + + [ + + ] + + + )).toFixed( + + ); + + + + G.push( result ); + + + + sum + + = +result; + + + } + + + + args[' + + '] = G; + + + return sum; + } )() + + + + + + ( function() { + + + var _$dlen$ = longerOf( + + + , + + + + + + ); + + + var _$dsum$ = 0; + + + for ( var _$d$ = 0; _$d$ < _$dlen$; _$d$++ ) { + _$dsum$ += + + + + * + + + ( ( + + || [] )[ _$d$ ] || 0 ) + + ; + } + + return _$dsum$; + + } )() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * + + + + + + + + + + + + + + + + 8 + + + + + Math. + + ( +( + + ).toFixed( + + ) ) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( + + )[__$$i] + + + + + + + + + + + + + + || 0 + + + + + + + + + + + + || 0 + + + + + + + + + + + + + + consts[' + + '] + + + + + + + + + + + + + + + consts[' + + '] + + + + + + + + || 0 + + + + + + + + + + + + + + + + + + + + + + + args[' + + '] + + + + + + + + + + + + + + + + || 0 + + + + + + + + + + + + ( + + ||[]) + + [ + + + + + + + + + + + + + + + + + + + + args[' + + '] + + + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + [ + + ] + + + + + + + + + ( + + + + + || 0 ) + + + + + + + + + + + + + + + + + / + + + + + + + Math.pow( + + , + + ) + + + + + + + + + + + + + ( args + + + + + + + , + + + + + + + + + + + + + + + + + + ) + + + + * + + + + + + + + + ( function() { + + return ( + ( + + + ) + + + + ) ? 1 : 0; + } )() + + + + + + + + + == + != + > + < + >= + <= + + + + + + + + + + + + + + + + ( function() { + + + + + else + + + if ( + + + + * + + + + + ) { return + + + ; } + + + + + + + + else + + + + if ( true ) + + + + { return + + ; } + + + } )() || 0 + + + + + + + + + + + + + [ + + + , + + + + + ] + + + + + + + + + (function(){ + + var cdr = Array.prototype.slice.call( + + , 0); + cdr.unshift( + + ); + + return cdr; + })() + + + + + ( + + [0]||0) + + + + + .slice(1) + + + + + + ( + + .length || 0 ) + + + + + + + + + + + + + + + + + ( + + + = + + function( + + + + , + + + + + ) { + + + return + + ; + } ) + + + ( + + + , + + + + ( + + ) + + ) + + + + + + + + func_ + + + + + + (function(){ + var result = + + ; + + + console.log( + + ' + + ', + + + result ); + return result; + })() + + + + + + ( function () { + throw Error( "Unknown calculation: + + " ); + } )() + + + diff --git a/src/current/compiler/js.xsl b/src/current/compiler/js.xsl new file mode 100644 index 00000000..55ea0299 --- /dev/null +++ b/src/current/compiler/js.xsl @@ -0,0 +1,1908 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + ' + + ':' + + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/compiler/linker.xsl b/src/current/compiler/linker.xsl new file mode 100644 index 00000000..f6a04783 --- /dev/null +++ b/src/current/compiler/linker.xsl @@ -0,0 +1,1442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cannot link + + ; must link program + + + + + + + + + + + + + + + + + linking + + ... + + + + + + + + + building dependency tree... + + + + + + + + + + + + + + + + + + resolving dependency tree... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + l:mark-class found for non-existing symbol + + ; there is a bug in l:depgen-process-sym + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( + + ) + + p - + + s - + + r - + + [s:: + + ::s] [r:: + + ::r] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + unresolved extern + + (declared by ` + + ') + + + + + + + + + + + + + + + + + + + + + + + + could not resolve external symbol ` + + ' + + + + + + + + + + + + + ambiguous external symbol ` + + '; resolution failed (found + + + ; + + + + ); pulled in by: + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + symbol name is not unique: ` + + ' found in + + + + and + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + depends upon + + external + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + could not locate dependency list for + + / + + + + + + + + + + + + + + + + + + failed locating dependency symbol ` + + ' + from package + + + + + + + + + + + + + + + + internal error: unknown symbol for l:depgen-sym: + + + + + + + + + + + + + circular dependency + + ( + + ): + + + + - + + + + + + + + + + + + + + + + + + + compiling entry point... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + compiling exit... + + + + + + + + compilation complete. + + + + + + + + + + + + + + + + + + + + + fatal: missing exit fragment: + + + + + + + + + + + + + + + + + ** linking metadata... + + + + + + + + + + + + + + + + ** linking worksheet... + + + + + + + + + + + + + + + + ** linking classifier... + + + + + + + + + + + + + + + + + + + ** linking global params... + + + + + + + + + + + + + + + + + ** linking types... + + + + + + + + + + + + + + + + + ** linking functions... + + + + + + + + + + + + + + + + + ** linking rater... + + + + + + + + + + + + + + + + + + + + + + + + + + + linking + + ... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + missing object code for symbol + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + could not locate package for exit-fragment: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + generating input map... + + + + + + + + missing object code for input map head or tail + + + + + + + + + + + + + + + + + + + + + + + + generating return map... + + + + + + + + missing object code for return map head or tail + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + could not locate symbol dependencies: + + + + + + + + + + + + + + + + + + map + + + + is not a known + + field for + + ; ensure that it exists and is either used or has @keep set + + + + + + + + + + + + + + + diff --git a/src/current/compiler/linker/log.xsl b/src/current/compiler/linker/log.xsl new file mode 100644 index 00000000..9c8db608 --- /dev/null +++ b/src/current/compiler/linker/log.xsl @@ -0,0 +1,95 @@ + + + + + + + + + + + + [ + + ] + + + + + + + + + + + + + [ + + ] + + + + + + + + + + + + + [ + + ] warning: + + + + + + + + + + + + + + + [ + + ] error: + + + + + + + + + + + + + + + [ + + ] internal error: + + + + + + + + diff --git a/src/current/compiler/map.xsl b/src/current/compiler/map.xsl new file mode 100644 index 00000000..10d8c426 --- /dev/null +++ b/src/current/compiler/map.xsl @@ -0,0 +1,997 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (function(){ + + var result= + + + + + + + + + ; + + return (result === "") ? ' + + ' : result; + })() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/compiler/validate.xsl b/src/current/compiler/validate.xsl new file mode 100644 index 00000000..91cfd03a --- /dev/null +++ b/src/current/compiler/validate.xsl @@ -0,0 +1,771 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + [validate] prohibited; skipping + + + + ... + + + + + + [validate] validating + + + + ... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + for application of + + () + + + + + + + + + + + + + + + + + + + + + + + + + + + ` + + ' is unknown for classification + + + + + + + + + + + + + + + + + + + ` + + ' is unknown for classification + + + + + + + + + + + + + + + + + + + + + + + + + + + + is not used to classify + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + is + + + + undefined + + + + of type ' + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + internal warning: unresolved param + dimension: ` + + ' + + + + + + + Unexpected vector/matrix reference + + + + + (did you forget @index?) + + + + + + + + + + + + + + requires + + indexes (use c:index) unless being + passed as a function argument + + + + + + + + + + + + may only have + + index(s) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Argument ` + + ' is unknown for function ` + + ' + + + + + + + + + + + + + + + + + + + + + Expected type ' + + ' for + + , but found ' + + ' + + + + + + + + + + + + + + + unknown classification ' + + ' referenced by + + + + + + + + + + + + + missing or empty @yields; see document dump + + + + + + + + + + + + + Cannot create generator ' + + '; generating expressions must contain both @of + and a sub-expression. + + + + + + + + + + + + + + + @desc required when creating generator + + + + + + + + + + + + + + + / + + + + + + + + + [ + + ] + + + + + @yields= + + + + + @name= + + + + @label= + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/compiler/validate/domain.xsl b/src/current/compiler/validate/domain.xsl new file mode 100644 index 00000000..0d84a8cf --- /dev/null +++ b/src/current/compiler/validate/domain.xsl @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + internal error: no domain symbol provided; + caller: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + internal error: unexpected node for lvv:domain-chk: + + + + + + + + + + + + + + + + + + + + + + + + + + error: no domain found for + + / + + + + + + + + + diff --git a/src/current/compiler/validate/param.xsl b/src/current/compiler/validate/param.xsl new file mode 100644 index 00000000..1d18d7a8 --- /dev/null +++ b/src/current/compiler/validate/param.xsl @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + ' + + ' is undefined for param + + + + + + + + + + + + + + + + + + + + + + + + + + internal error: in limbo processing param ` + + ' @default + + + + + + + + param ` + + ' @default of ` + + ' is not within its domain of + + / + + + + + + + + + + + + + diff --git a/src/current/compiler/worksheet.xsl b/src/current/compiler/worksheet.xsl new file mode 100644 index 00000000..9149ddd4 --- /dev/null +++ b/src/current/compiler/worksheet.xsl @@ -0,0 +1,543 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/doc/.gitignore b/src/current/doc/.gitignore new file mode 100644 index 00000000..2fa45d09 --- /dev/null +++ b/src/current/doc/.gitignore @@ -0,0 +1,4 @@ +*.aux +*.pdf +*.log +*.toc diff --git a/src/current/doc/chapters/class.tex b/src/current/doc/chapters/class.tex new file mode 100644 index 00000000..82a2f624 --- /dev/null +++ b/src/current/doc/chapters/class.tex @@ -0,0 +1,372 @@ +\chapter{Classification System} +The classification system is one of the most powerful features of \lang, +allowing precise control over the classification and conditional processing of +large sets of data, whether it be external input or values generated from within +\lang\ itself. Virtually every conditional calculation is best represented +through use of the classification system. + + +\section{Classification Matcher} +Data classification is performed by the classification matcher (sometimes +referred to simply as the ``matcher''). Put simply, it is a function (defined by +\aref{cmatch}) that, given a vector of inputs, produces a boolean vector (which +may itself contain boolean vectors) determining if the given input conforms to a +set of stated rules. A set of rules operating on a set input vectors is +collectively known as a \term{classification}. The system that performs matching +based on classifications is referred to as a \term{classifier}. + +A single classification can be separated into a set of rules, often referred to +as \term{matches} within the context of \lang. A single rule attempts to match +on a vector of inputs.\footnote{Scalar inputs are a special condition defined in +\sref{cmatch-scalar}.} A simple example of such a match is shown in +\fref{cmatch-ex-single}. + +\begin{figure}[h] + $$ + I = \left[ + \begin{array}{c} + 1 \\ 3 \\ 4 \\ 1 + \end{array} + \right] + \qquad + M = \left[ + \begin{array}{c} + 1 \\ 4 + \end{array} + \right] + \quad + \to + \quad + R = \left[ + \begin{array}{c} + \top \\ \bot \\ \top \\ \top + \end{array} + \right]. + $$ + + \caption{A simple classification match $M$ on input $I$ and its result vector + $R$.} + \label{f:cmatch-ex-single} +\end{figure} + +In \fref{cmatch-ex-single}, the input vector $I$ is \term{matched} against the +rule $M$. The output is a boolean result vector $R$ which can be summarized with +the following rule: + +$$ + R_n = \exists m\in M(m = I_n). +$$ +\noindent +In other words, $R_n$ is $\top$ if $I_n\in M$ and is $\bot$ if $I_n\notin M$. +Under this definition, $M$ can be considered to be the \term{domain} under which +a given input $I_n$ is considered to be valid (a \term{match}). + +We say that a classification rule \term{matches} if \emph{any} input matches. +That is: + +$$ + \left[\textrm{The rule $M$ matches input $I$}\right] + \iff + \top\in R +$$ +\noindent +Another way to think of this concept is the reduction of the result vector $R$ +using a logical OR. Alternatively, one could assert that: + +$$ + \left[\textrm{The rule $M$ matches input $I$}\right] + \iff + \sum\limits_n R_n \geq 1, \qquad R \in \set{0,1}, +$$ +\noindent +if an implementation were willing to use the sets \boolset and \set{1,0} +interchangeably.\footnote{See \sref{cmatch-int}.} + +The following sections, however, serve to demonstrate that such a simple view of +the classification system, while useful for an introductory demonstration, is +not sufficient when considering the level of flexibility that is necessary to +handle more complicated data (in particular, when $I$ is a +matrix).\footnote{See $\Omega$-reductions, introduced in +\asref{cmatch}{omega-reduce}.} + +%TODO: More example sections + + +\subsection{Classification Match (cmatch) Algorithm} +\label{a:cmatch} + +The classification match (``cmatch'') algorithm is used to determine if a given +set of data matches a given set of classification criteria. + +Let $I$ be the vector of input values.\footnote{$I$ may be a matrix (a vector +of vectors).} Let $M$ be the vector of predicates to match against $I$ such +that a match will be considered successful if \emph{any} predicate is true. +Since $I$ shall always be a vector of values---even if the vector contains only +one element (see algorithm below for comments on scalar values)---$M$ should be +a vector of one element if the desire is to match against a scalar value (rather +than a vector of values). Let $c$ (clear) be a boolean value\footnote{$1$ or $0$ +when used within an integer context within the algorithm.} representing whether +the results of this operation should be logically AND'd together with the +prior cmatch result ($R'$ in the algorithm below); otherwise, the results will +be OR'd (see step \ref{a:cmatch-c} below). + +Let $A\!\left(M,I,c,R'\right)$ (the ``algorithm'') be defined as: + +\begin{enumerate} + \item + Let $R$ be the result vector. + + \item\label{a:cmatch-scalar} + If the given input vector $I$ is a scalar, it should be converted to a vector + of length 1 with the value of the single element being the original scalar + value of $I$---that is, let $s$ be the original scalar value of $I$; then: $I + = \left[ s \right]$. If $s$ is undefined, then an empty result vector should + be returned. + + \item\label{a:cmatch:input-vectorize} + Step \ref{a:cmatch-scalar} should also be done to the match vector $M$, + yielding $M = \left[ s \right]$ where $s$ is the original scalar $M$. If $s$ + is undefined, then it should be treated as if it were the integer + $0$.\footnote{Consistent with the behavior of the remainder of the DSL.} + + \item + Step \ref{a:cmatch-scalar} should also be done to the prior result vector + $R'$, yielding $R = \left[ s \right]$ where $s$ is the original scalar $R'$. + This situation may result from recursing at step \ref{a:cmatch-mrecurse} when + $R'_k$ is a scalar. If $s$ is undefined, then $R'$ should be initialized to an + empty vector, implying a fresh match (no prior results). + \goodbreak + + \item\label{a:cmatch-iter} + The length of the result vector $R$~($\#R$) shall be the larger of the length + of the input vector $I$~($\#I$) or the prior result vector $R'$~($\#R'$). + For each $I_k \in I$: + + \begin{enumerate} + \item\label{a:cmatch-mrecurse} + If $I_k$ is a vector, recurse, beginning at step 1. Let $r = + A(M_k,I_k,c,R'_k)$. + + \begin{align*} + u &= \left\{ + \begin{array}{ll} + \bot & \textrm{if }\#R' > 0, \\ + c & \textrm{otherwise.} + \end{array} + \right. \\ + % + R_k &= \left\{ + \begin{array}{ll} + r & \textrm{if $R'_k$ is a vector or undefined}, \\ + \Omega(r,u) & \textrm{otherwise}.\footnotemark + \end{array} + \right. + \end{align*} + + \footnotetext{\label{a:cmatch-order} If $R'_k$ is a scalar, we must ensure + consistency with step \ref{a:cmatch-c} to ensure that the algorithm is not + dependent on input or execution order. Note the use of $u$ in place of + $c$---this ensures that, if there are any $R'$, we are consistent with the + effects of step \ref{a:cmatch:fill} (but in reverse).} + + Continue with the next $I$ at step \ref{a:cmatch-iter}. + + \item + \label{a:cmatch:omega-reduce} + Otherwise, $I_k$ is a scalar. Let $t$ be a temporary (intermediate) scalar + such that $t = \exists m \in M m(I_k)$. + + \item\label{a:cmatch-c} + Let $v = \Omega\left(R'_k,c\right)$ and let + $$ + R_k = \left\{ + \begin{array}{ll} + v \wedge t & c = \top, \\ + v \vee t & c = \bot. + \end{array} + \right., + $$ + + where\footnote{$\Omega$ is simply the recursive reduction of a vector using + a logical OR. This function exists to resolve the situation where $R'_k$ is + a vector of values when $I_k$ is a scalar, which will occur when $M_k$ is + scalar for any $k$ during one application of the cmatch algorithm and $M_k$ + is a vector for another iteration, where $R'$ is the previous match using + scalars. Note also that $X$, according to the recursion rule, may only be + undefined on the first iteration (in effect initializing the value).} + + $$ + \Omega\left(X,u\right) = \left\{ + \begin{array}{ll} + u & \textrm{if X is undefined,} \\ + X & \textrm{if X is a scalar,} \\ + \exists x\in X \Omega(x,u) & \textrm{otherwise.} + \end{array} + \right. \> + \mbox{ + $X \in \left\{\textrm{undefined},\top,\bot\right\}$ + or a vector. + } + $$ + \end{enumerate} + + \item\label{a:cmatch:fill} + Let $v = \Omega\left(R'_k,c\right) \wedge \neg c$. If $\#R' > \#I$, + $$ + R_k = \left\{ + \begin{array}{ll} + v & \exists n\in I(n\textrm{ is a scalar}), \\ + \left[v\right] & \textrm{otherwise.}\footnotemark + \end{array} + \right. + k \in \left\{j : \#I \leq j < \#R' \right\}. + $$ + + \footnotetext{Note that step \ref{a:cmatch:fill} will produce results + inconsistent with the recursive step \ref{a:cmatch-mrecurse} if there exists + an $I_n$ that is a matrix; this algorithm is not designed to handle such + scenarios.} +\end{enumerate} + +Given a set of classification criteria $C$ such that $C_k = M$ for some integer +$k$ and some application of $A$, and a vectorized clear flag $c$ such that $c_k$ +is associated with $C_k$, the final result $F(\#C-1)$ shall be defined as + +$$ + F(k) = \left\{ + \begin{array}{ll} + A\left(C_k,I_k,c_k\right) & \textrm{k = 0,} \\ + A\bigl(C_k,I_k,c_k,F\!\left(k-1\right)\bigr) & \textrm{otherwise.} + \end{array} + \right. +$$ + +The order of recursion on $F$ need not be right-to-left; $A$ is defined such +that it will produce the same result when applied in any order. This is +necessary since the input may be provided in any order.\footnote{Ibid, +\ref{a:cmatch-order}.} + +\subsubsection{Boolean Classification Match} +\label{s:cmatch-boolean} +A scalar boolean classification match $b$ may be obtained simply as $b = +\Omega\left(F,\bot\right)$, where $F$ and $\Omega$ are defined in the algorithm +above. Consequently, note that an empty result set $F$ will be treated as +$\bot$, since index $0$ will be undefined. + +\subsubsection{Match Vector} +$M$ is defined to be a vector of predicates which serve to {\sl match} against a +vector of input values. Most frequently, predicates will likely be against scalar +values. In such a case, an implementation may choose to forego function +application for performance reasons and instead match directly against the +scalar value. However, this document will consider scalar matches in the context +of predicates as functions. As such, if $M$ is a matrix, then the results are +implementation-defined (since the value does not make sense within the algorithm +as defined). + +\subsubsection{Integer Results} +\label{s:cmatch-int} +$A$ defines $R$ to be a vector/matrix of boolean values. However, it may be +useful to use the cmatch results in calculations; as such, implementations that +make use of or produce cmatch results are required to do one or both of the +following where $b$ is a boolean scalar: + +\begin{enumerate} + \item + Implicitly consider $b$ to be $\textrm{int}\!\left(b\right)$ when used in + calculations, and/or + + \item + Perform the implicit conversion before $R$ is returned from $A$, +\end{enumerate} + +where the function {\sl int} is defined as + +$$ + \textrm{int}(b) = \left\{ + \begin{array}{ll} + 1 & \textrm{if }b = \top, \\ + 0 & \textrm{if }b = \bot. + \end{array} + \right.\qquad + b \in \left\{\top,\bot\right\}. +$$ + + +\subsection{Scalar Classification Matches} +\label{s:cmatch-scalar} +Implementations may find it convenient to support scalar inputs and scalar +classification matches to represent matching ``all'' indexes of a vector. +\aref{cmatch} defines both a classification match ($R$, and consequently $F$) +and an input ($I$) to be a vector, which is generally sufficient. However, in +the case where the number of indexes of the inputs and results of other matches +may be arbitrary, it may be useful to apply a certain classification across all +indexes, which cannot be done when $c = \top$ using \aref{cmatch}. + +The onus of such a feature is on the implementation---it should flag such input +($I$) as a scalar, which is necessary since $I$ is unconditionally converted to +a vector by step \asref{cmatch}{input-vectorize}. If an implementation decides +to support scalar classification matches, \emph{it must conform to this +section}. Let such a scalar flag be denoted $s_k \inbool$ respective to input +$I_k$. Handling of both $F$ and $I$ is discussed in the sections that follow. + +\subsubsection{Mixing Scalar And Vectorized Inputs} +\label{s:cmatch-scalar-mixed} +Under the condition that $\exists v\in s(v=\top)$, the compiler must: + +\begingroup + % this definition is local to this group + \def\siset{k \in\set{j : s_j = \top}} + + \begin{enumerate} + \item + Reorder inputs $I$ such that each scalar input $I_k, \siset$ be applied + after all non-scalar inputs have been matched using \aref{cmatch}. + \begin{enumerate} + \item + Consequently (and contrary to what was mentioned in \aref{cmatch}), + application order of $A$ with respect to inputs $I$ \emph{does} in fact + matter and implementations should ensure that this restriction holds + during runtime. + \end{enumerate} + + \item + Before application of a scalar input, the scalar $I_k$ should be vectorized + according to the following rule: + + $$ + I'_{k,l} = I_k, + \qquad \siset, + \; 0 \leq l < \#R', + $$ + + where $R'$ is the value immediately before the application of $I_k$ as + defined in \aref{cmatch}. + + \item + Application of \aref{cmatch} should then proceed as normal, using $I'$ in + place of $I$. + \end{enumerate} +\endgroup + +\subsubsection{Converting Vectorized Match To Scalar} +As defined by \aref{cmatch}, the result $R$ will always be a vector. An +implementation may \emph{only} convert a vectorized match to a scalar using the +method defined in this section under the condition that $\forall v\in +s(v=\top)$; otherwise, there will be a loss of data (due to the expansion rules +defined in \sref{cmatch-scalar-mixed}). The implementation also \emph{must not} +reduce the vectorized match to a scalar using $\Omega$. An implementation +\emph{may}, however, $\Omega$-reduce the match result $R$ into an +\emph{separate} value as mentioned in \sref{cmatch-boolean}. + +Under the condition that $\forall v\in s(v=\top)$, the system may post-process +$F$ (as defined in \aref{cmatch}) such that + +$$ + F' = F_0, +$$ + +and return $F'$ in place of $F$. + +Note also that $F'$ may be fed back into \aref{cmatch} as an input and that the +results will be consistent and well-defined according to +\sref{cmatch-scalar-mixed} (and, consequently, this section). diff --git a/src/current/doc/manual.sty b/src/current/doc/manual.sty new file mode 100644 index 00000000..b3524f49 --- /dev/null +++ b/src/current/doc/manual.sty @@ -0,0 +1,30 @@ +% manual style package + +% these margins ensure that the PDF can be easily scrolled vertically without +% worrying about alternating margins (good for viewing on screen, but not on +% paper) +\usepackage[margin=1.25in]{geometry} +\usepackage{amsmath} + +\setcounter{secnumdepth}{3} +\setcounter{tocdepth}{3} + +% no name yet +\def\lang{the DSL} + +\def\sref#1{Section \ref{s:#1}} +\def\fref#1{Figure \ref{f:#1}} +\def\aref#1{Algorithm \ref{a:#1}} +\def\asref#1#2{A\ref{a:#1}(\ref{a:#1:#2})} + +\def\set#1{% + \ifmmode% + \left\{#1\right\}% + \else + $\left\{#1\right\}$% + \fi% +} +\def\boolset{\set{\top,\bot}} +\def\inbool{\in\boolset} + +\def\term#1{{\sl #1}} diff --git a/src/current/doc/manual.tex b/src/current/doc/manual.tex new file mode 100644 index 00000000..9d1d80ec --- /dev/null +++ b/src/current/doc/manual.tex @@ -0,0 +1,19 @@ +\documentclass[10pt]{book} + +%%begin preamble + \usepackage{manual} + + \author{Mike Gerwitz\\LoVullo Associates} + \date{\today} +%%end preamble + +\begin{document} + +\title{Calc DSL: Design Specification and Programmer's Manual} +\maketitle + +\tableofcontents + +\include{chapters/class} + +\end{document} diff --git a/src/current/dot.xsl b/src/current/dot.xsl new file mode 100644 index 00000000..ed0bb39e --- /dev/null +++ b/src/current/dot.xsl @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + [dot] fatal: this is not an object/executable file: + no symbol dependencies found + + + + + + + /* dependency graph of + + */ + + digraph " + + " { + + graph [rankdir="LR", ranksep="2"]; + + + + + + } + + + + + diff --git a/src/current/dot/attr-color.xsl b/src/current/dot/attr-color.xsl new file mode 100644 index 00000000..4ef7c01d --- /dev/null +++ b/src/current/dot/attr-color.xsl @@ -0,0 +1,72 @@ + + + + + + + + + + #204a87 + + + + + + + #729fcf + + + + + + + #4e9a06 + + + + + + + #c4a000 + + + + + + + #888a85 + + + + + + + + + + diff --git a/src/current/dot/attr-extern.xsl b/src/current/dot/attr-extern.xsl new file mode 100644 index 00000000..318da4a6 --- /dev/null +++ b/src/current/dot/attr-extern.xsl @@ -0,0 +1,33 @@ + + + + + + + + + + dashed + + + + + + + + + + diff --git a/src/current/dot/attr-keep.xsl b/src/current/dot/attr-keep.xsl new file mode 100644 index 00000000..3a72af49 --- /dev/null +++ b/src/current/dot/attr-keep.xsl @@ -0,0 +1,33 @@ + + + + + + + + + + red + + + + + + + + + + diff --git a/src/current/dot/attr-shape.xsl b/src/current/dot/attr-shape.xsl new file mode 100644 index 00000000..f4bc289f --- /dev/null +++ b/src/current/dot/attr-shape.xsl @@ -0,0 +1,62 @@ + + + + + + + + + + box + + + + + + + octagon + + + + + + + component + + + + + + + note + + + + + + + + + + diff --git a/src/current/dot/defnode-attr.xsl b/src/current/dot/defnode-attr.xsl new file mode 100644 index 00000000..778835a0 --- /dev/null +++ b/src/current/dot/defnode-attr.xsl @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + /\n + + + + + + / + + + + + + + + + + + + + + + + + + , + + + + =" + + " + + + + diff --git a/src/current/dot/defnode.xsl b/src/current/dot/defnode.xsl new file mode 100644 index 00000000..c34c591b --- /dev/null +++ b/src/current/dot/defnode.xsl @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + " + + " [ + + + + + , + + + + href=" + + " + + ]; + + + + + + + + diff --git a/src/current/dot/depout.xsl b/src/current/dot/depout.xsl new file mode 100644 index 00000000..5b3dbdab --- /dev/null +++ b/src/current/dot/depout.xsl @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + [root=ctr,fontsize=24,style=bold,label="Yield"]; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + " + + " -> " + + " + + + [ + + ] + + + ; + + + + + + + + + error: what do I do!?: unexpected + + + + + + + + + + + + + diff --git a/src/current/dot/pkg-exec.xsl b/src/current/dot/pkg-exec.xsl new file mode 100644 index 00000000..1c934bfa --- /dev/null +++ b/src/current/dot/pkg-exec.xsl @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + error: cannot locate symbol dependencies for ` + + ' + + + + + + + + + diff --git a/src/current/dot/pkg-obj.xsl b/src/current/dot/pkg-obj.xsl new file mode 100644 index 00000000..d281cffd --- /dev/null +++ b/src/current/dot/pkg-obj.xsl @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/calc-display.xsl b/src/current/include/calc-display.xsl new file mode 100644 index 00000000..4f9f0fac --- /dev/null +++ b/src/current/include/calc-display.xsl @@ -0,0 +1,702 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \left( + + + + + + \right) + + + + + + + + + + + + + + + + + + + + + + k + + + + + + + + + + + + + + + + + + + + + + + + + =0 + + + + \sum \limits_{ + + } + + + + + ^{\grave\# + + } + + + + + + + + + + + + + + + + + + + + + + + ( + + + + + + \,\cdot\, + + + + + + \left( + + + + + + + \right) + + + + + ) + + + + + + + + + + + \frac{ + + + + }{ + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \left\l + + + + \right\r + + + + + + + + + + + + + + + + + + \left( + + + + + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + \right) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \left[ + + + + + \text{ and } + + + + + + + + + + + + \right] + + + + + + \begin{cases} + + \end{cases} + + + + \;\;\; + + + + + + + + + + + + + + & + + + + [ + + + + + + + \text{if } + + + + + + + + + + \text{otherwise} + + + + + + + ] + + + + ; \\ + + + + . + + + + + + + + + + + + + + + + + + = + \not=\; + \gt + \lt + \geq + \leq + + + + + + + + + + + + \left[ + + + , + + + + + \right]^T + + + + + \left[\begin{array}\\ + + + + \\ + + + + + & + + + { + + } + + + + \end{array}\right] + + + + + \#\left( + + \right) + + + + \textrm{cons}\left( + + , + + \right) + + + + \left( + + \right)_0 + + + + \textrm{cdr}\left( + + \right) + + + diff --git a/src/current/include/depgen.xsl b/src/current/include/depgen.xsl new file mode 100644 index 00000000..d897c27d --- /dev/null +++ b/src/current/include/depgen.xsl @@ -0,0 +1,526 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [depgen] *determining symbol dependencies... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [depgen] internal error: + could not locate dependency symbol ` + + ' in local symbol table; needed by + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \textrm{ + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _{ + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [depgen] error: unexpected symbol + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [depgen] warning: unknown symbol ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] !!! fatal: internal classification ` + + ' cannot pull in external classification ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/display.xsl b/src/current/include/display.xsl new file mode 100644 index 00000000..7296b560 --- /dev/null +++ b/src/current/include/display.xsl @@ -0,0 +1,551 @@ + + + + + + + + + + + + + + + + + + + + + + + scalar + + + + + + + + + + generator; vector + + + ( + + + + ) + + + + + + + + + + + + + + + + + + + + " + + " + classification + + + + scalar + + + + vector + + + + matrix + + + + [dim + + ] + + + + + + ( + + + + ) + + + + + + + + + + + + + + + + + + + ( + + + + ) + + + + + + + (!) + + + + + + + + + + + + + + + + + + + _{ + + } + + + + _{ + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fparam + + + + + + class + + + + generator + + + + + + + + + + + + + + + \textrm{ + + } + + + + + + + + + ( + + + + + + + + + + + + + + _ + + + + + + + + { + + + + + + + + } + + + + ) + + + + + _{ + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unknown @name reference: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [summary] !!! unknown let-list type + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
  • + + + + + + + \( + + = + + + + + \) + + + ( + + ) + + + + + let \( + + \) = + + + + + + +
  • +
    + +
    diff --git a/src/current/include/dslc-base.xsl b/src/current/include/dslc-base.xsl new file mode 100644 index 00000000..53a31959 --- /dev/null +++ b/src/current/include/dslc-base.xsl @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/entry-form.xsl b/src/current/include/entry-form.xsl new file mode 100644 index 00000000..3d6b3c8b --- /dev/null +++ b/src/current/include/entry-form.xsl @@ -0,0 +1,323 @@ + + + + + + + + + + +
    +

    Rating Test Case

    + +
    +

    + +
    + + +
    + +
    + +
    + + +
    + +
    +

    Submit Test Case

    + +

    Submission comments (please describe what you were testing, the + desired result and, if the premium was incorrect, what went wrong):

    + + + +
    +

    Expected premium (if known; must be exact); this will allow us to + automatically re-run this test when we believe that the problem has been + fixed. Otherwise, you must re-test manually:

    + + (Only fill out if it does not hit the minimum premium.) +
    + +
    + + +
    + + + +
    +
    + +
    + + + + + +
    +
    + + +
    + + + + + + + + + + + + + + + [] + + + + + +
    + +
    + + + + matrix + + + + +
    +
    +
    + + + + + + + + + + +
    + + + + +
    + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + selected + + + + + + selected + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [summary] warning: unknown param type ` + + / + + ' + + + + Unknown type: + + + + + + + + + + + + + + + + + + + + +
    diff --git a/src/current/include/exslt/str.tokenize.template.xsl b/src/current/include/exslt/str.tokenize.template.xsl new file mode 100644 index 00000000..6da270b3 --- /dev/null +++ b/src/current/include/exslt/str.tokenize.template.xsl @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/orderizer.xsl b/src/current/include/orderizer.xsl new file mode 100644 index 00000000..170bd2b9 --- /dev/null +++ b/src/current/include/orderizer.xsl @@ -0,0 +1,268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [orderizer] recursively discovering param classes... + + + + + + + + + + + + + + + [orderizer] checking previous UI siblings: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/preproc/domain.xsl b/src/current/include/preproc/domain.xsl new file mode 100644 index 00000000..6dc436d3 --- /dev/null +++ b/src/current/include/preproc/domain.xsl @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + warning: union ` + + ' has no subdomains; something is probably wrong + + + + + + + + + + + + + + + + + + + + + + + + + + warning: typedef ` + + ' is empty; something is probably wrong + + + + + + + + + + + + + error: typedef ` + + ' must not contain both @value and non-@value items + + + + + + + + + error: malformed typedef ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + internal error: preproc:mkdomain on non-value item: + + + + + + + + + + + + + internal error: unknown domain source: + + + + + + diff --git a/src/current/include/preproc/eligclass.xsl b/src/current/include/preproc/eligclass.xsl new file mode 100644 index 00000000..8e78c09a --- /dev/null +++ b/src/current/include/preproc/eligclass.xsl @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/eligclass] generating eligibility class + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/eligclass] error: could not load ` + + ' object file + + + + + + + + + + [preproc/eligclass] internal: empty eligibility + class for ` + + '; skipping + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/preproc/expand.xsl b/src/current/include/preproc/expand.xsl new file mode 100644 index 00000000..57c68564 --- /dev/null +++ b/src/current/include/preproc/expand.xsl @@ -0,0 +1,691 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + matrix + + + + + + + + + vector + + + + + + + + __is + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + __is + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/preproc/macros.xsl b/src/current/include/preproc/macros.xsl new file mode 100644 index 00000000..4c4f8e6b --- /dev/null +++ b/src/current/include/preproc/macros.xsl @@ -0,0 +1,456 @@ + + + + + + + + + + + + + + + + + + + + + + + + !!! [preproc] error: + + + + + + + + + + + + [preproc] *REPASS* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cannot take index of scalar value: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] waiting to expand rate-each + + (immediate template(s) need expansion)... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + rate-each must provide either @yields or @generates + + + + + + + + + + + + + + + + + Set of individual + + premiums + + + + + + Zero if not + + , otherwise one + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/preproc/package.xsl b/src/current/include/preproc/package.xsl new file mode 100644 index 00000000..48536af4 --- /dev/null +++ b/src/current/include/preproc/package.xsl @@ -0,0 +1,817 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] error: missing random seed `__rseed' + + + + + [preproc] *beginning macro expansion... + + + + + + + + + + [preproc] *macro pass complete; expanding... + + + + + + + + + [preproc] *expansion complete; generating symbol table... + + + + + + + + + + + [preproc] *symbol table generated; checking for + unprocessed templates... + + + + + + + + + + + !!! [preproc] error: + + + + + + + + + + + + + + + + + + + + + + + !!! [preproc] error: + + + + + ~~~~[begin document dump]~~~~ + + ~~~~[end document dump]~~~~ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] compiling fragments... + + + + + + + + + + + + + + + + + + + + + + [preproc] fatal: unexpanded template parameter: + + + + + [preproc] fatal: reference node: + + + + ~~~~[begin document dump]~~~~ + + ~~~~[end document dump]~~~~ + + [preproc] notice: Document dumped. + + + + + + + [preproc] fatal: unexpanded template: + + + + + [preproc] fatal: reference node: + + + + + + ~~~~[begin document dump]~~~~ + + ~~~~[end document dump]~~~~ + + [preproc] notice: Document dumped. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] + + template(s) still need application: + + + + , + + + + + + + + + + + + + + + + + + + !!! [preproc] fatal: unable to locate symbols for + remaining templates: + + + + ; + + + + + + + + + + + !!! [preproc] fatal: terminating due to errors + + + + + + + + + + + + [preproc] *expansion complete (recursive) + + + + + + + + + + + + + !!! [preproc] fatal: expansion of remaining + templates aborted (have all been imported?): + + + + ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] template symbol not yet available: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] !!! recursion limit reached in resolving ` + + ' symbols + + + + + + + + + [preproc] *resolving symbol attributes... + + + + + + + + + + + + + + [preproc] *SYM REPASS* + + [preproc] The following + + symbol(s) are still unresolved: + + + + + [preproc] - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] !!! failed to look up symbol ` + + ' + + + + + + + + + + + + + + + + [preproc] deferring ` + + ' dimensions with unresolved dependencies + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + [preproc] !!! failed to determine dimensions of ` + + ' + + + + + + [preproc] resolved ` + + ' dimensions as ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + !!! + + + + ( + + ) + + + : + + + + + + + + Compilation failed due to validation errors. + + + + + + + + ~~~~[begin document dump]~~~~ + + ~~~~[end document dump]~~~~ + internal: document dumped. + + + + + + + diff --git a/src/current/include/preproc/path.xsl b/src/current/include/preproc/path.xsl new file mode 100644 index 00000000..469603d6 --- /dev/null +++ b/src/current/include/preproc/path.xsl @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + ../ + + + + + + + + + + + + + + + + + + + + + + ../ + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + + + + + diff --git a/src/current/include/preproc/symtable.xsl b/src/current/include/preproc/symtable.xsl new file mode 100644 index 00000000..9210c76c --- /dev/null +++ b/src/current/include/preproc/symtable.xsl @@ -0,0 +1,959 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/symtable] discovering symbols... + + + + + + + + + + + + + + + + + + + + [preproc/symtable] warning: symbol / + + / + + has @override set, but does not override anything + + + + + + + + + + + + + + [preproc/symtable] error: cannot override non-virtual symbol / + + / + + + + + + + + [preproc/symtable] error: duplicate symbol / + + / + + (defined in ./ + + + + + and ./ + + + + + ) + + + + ; did you forget @override? + + + + + + + + + ~~~~[begin document dump]~~~~ + + ~~~~[end document dump]~~~~ + + ~~~~[begin symbol dump]~~~~ + + ~~~~[end symbol dump]~~~~ + + + [preproc/symtable] fatal: aborting due to symbol errors + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/symtable] done. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + extern mismatch: ' + + ' (imported from + + ) + + + + ; + + + = + + , + + expected + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + unresolved extern ' + + ' + + + + (required by + + ) + + + + + + + + + + + + + + + + + [preproc/symtable] processing symbol table... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/symtable] error: refusing to import non-package + + ; use @allow-nonpkg to force (if you know what you are doing) + + + + + + + + + + + + + + + [preproc/symtable] importing symbol table of + + ... + + + + + + [preproc/symtable] internal error: + failed to locate symbol table: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + + + + 1 + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/symtable] internal error: + failed to resolve type primitve of ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + \textrm{ + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/symtable] internal error: + failed to resolve type: + + + + + + + + + + + + + + + + + + + + + + 1 + + + + 2 + + + + 0 + + + + + diff --git a/src/current/include/preproc/template.xsl b/src/current/include/preproc/template.xsl new file mode 100644 index 00000000..e1e8edb9 --- /dev/null +++ b/src/current/include/preproc/template.xsl @@ -0,0 +1,1149 @@ + + + + + + + + + + + + + + + + + + + k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Undefined template + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] expanding template parameters for + + ... + + + + + + + + + + + + + + + + + + + + + Undefined template + + + + + + + + + + + + + + + + + + + undefined template param + / + ; available params are + + + + ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] preparing inline template + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] deferring application of unknown template + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] expanding param-copy... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + : + + + + + + + + + + + + + + + warning: + + : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unknown template comparison attribute for + + in + + : + + + + + =" + + " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + error: unable to determine @yields for class ` + + ' (has the class been imported?) + + + + + + + + + + + + + + + + + + + + + + error: unknown param node content: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/preprocess.xsl b/src/current/include/preprocess.xsl new file mode 100644 index 00000000..b0d8cd53 --- /dev/null +++ b/src/current/include/preprocess.xsl @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + [preproc] [rater] + + + + + + + + + + + + + + diff --git a/src/current/include/symbol-map.xml b/src/current/include/symbol-map.xml new file mode 100644 index 00000000..9cf64218 --- /dev/null +++ b/src/current/include/symbol-map.xml @@ -0,0 +1,80 @@ + + + + \Theta + + + \theta + + + C + + + E + + \kappa + + + K + + + + + + + + \omega + + + G + + \sigma + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/util.xsl b/src/current/include/util.xsl new file mode 100644 index 00000000..0e0030fe --- /dev/null +++ b/src/current/include/util.xsl @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + " + + + + ": + + + + + [ + + + , + + + + + ] + + + + { + + + , + + + + + } + + + + " + + + + " + + + + [util] !!! invalid util:json + + + + + + + + + + + + diff --git a/src/current/link.xsl b/src/current/link.xsl new file mode 100644 index 00000000..1c984614 --- /dev/null +++ b/src/current/link.xsl @@ -0,0 +1,8 @@ + + + + + + diff --git a/src/current/map.xsd b/src/current/map.xsd new file mode 100644 index 00000000..d10d3ceb --- /dev/null +++ b/src/current/map.xsd @@ -0,0 +1,412 @@ + + + + + + + + + Classification name (lv:classify/@as) + + + + + + + + Classification should not add a match requiring that at least one + eligible supplier use it (if supported by implementation) + + + + + + + + + + String constant + + + + + + + + + + + Default complex value for a translation + + Concatenates each value. + + + + + + + + + + + + + + Defines a translation for a given value + + + + + + + + + + + + Source value to match against for translation + + + + + + + + Value to translate to + + + + + + + + Default value when the resulting translation is the + empty string + + + + + + + + + + Defines translation rules between source and destination fields; not + to be used with @from + + + + + + + + + + + + + Identifier of source field + + + + + + + + Optional default value if no source value is available + + + + + + + + Whether this field should be considered when generating eligibility + classes (if supported by implementation); default true + + + + + + + + + + + + + + + Maps a static value + + + + + + + + Static value to map to destination + + + + + + + + + + + Maps a source value to its destination by index + + + + + + + + Source field identifier + + + + + + + + Iterator variable or constant integer representing the source + value index + + + + + + + + + + + + + Translates source data into a set + + + + + + + + + + + Source field identifier to use as index for the iterator + + + + + + + + Variable to serve as a reference for the iterator index + + + + + + + + When true, if a transformation yields a value that is undefined, an + empty string, or the string "0", then omit it from the set + + + + + + + + + + Defines a map from a source field to a destination field with optional + transformation rules + + + + + + + + + + + + Identifier of destination field + + + + + + + + Identifier of source field if no data transformations are to be + performed; cannot be used with @value + + + + + + + + Constant value to be mapped to destination; cannot be used with @from + or from node + + + + + + + + Whether this field should be considered when generating eligibility + classes (if supported by implementation); default true + + + + + + + + Override mapping sharing the same destination identifier in an + imported package + + + + + + + + + + Maps from a source field to a destination field of the same name without + any translation; shorthand for identical @to and @from attributes on a + general map node + + + + + + + Identifier of the source (and consequently destination) field + + + + + + + + Do not validate that the field exists; useful for mapping data that is + not explicitly recognized as a field by the source + + + + + + + + Whether this field should be considered when generating eligibility + classes (if supported by implementation); default true + + + + + + + + Override mapping sharing the same destination identifier in an + imported package + + + + + + + + + + + + + + + + + + + Includes mappings from another source file + + + + + + + Path to source file + + + + + + + + + + Maps program data between two points + + + + + + + + + + + + + + + Source document to validate against (document root node must be + known to the implementation) + + + + + + + + + + + Specifies data transformations/filtering to be performed on data before + being returned to a caller + + + + + + + + + + + + diff --git a/src/current/pkg-dep.xsl b/src/current/pkg-dep.xsl new file mode 100644 index 00000000..64c6e9fa --- /dev/null +++ b/src/current/pkg-dep.xsl @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/scripts/entry-form.js b/src/current/scripts/entry-form.js new file mode 100644 index 00000000..b67d9a22 --- /dev/null +++ b/src/current/scripts/entry-form.js @@ -0,0 +1,2164 @@ +/** + * This file is used for direct interaction with the rater for testing purposes. + * As such, much of it is a rushed implementation; it's a bit of a kluge and + * could use some refactoring. + * + * Also, it is terriby stateful and difficult to work with. I have the utmost + * confidence in your ability to look away and pretend you never saw this + * script. + */ + +// intentionally global; developers can override +var program = document.location.pathname.match( '/raters/(.*?)/' )[1], + submit_url = '/raters/submit-test.php?program=' + program, + supplier = rater.supplier, + prior_url = '/raters/submit-test.php?retrieve=' + supplier + + '&program=' + program, + qdata_host = 'dev'; + +var client = ( function() +{ + // URL to which quote/result submissions should be POSTed + var form = document.querySelector( 'form.entry-form' ), + final_prem = form.querySelector( '.final-premium' ), + final_accept = form.querySelector( '.final-accept' ), + final_comments = form.querySelector( '.final-comments' ), + voi = document.getElementById( 'voi-list' ), + coview = document.getElementById( 'class-overview-list' ), + + final_good = document.getElementById( 'final-accept-good' ), + final_bad = document.getElementById( 'final-accept-bad' ), + + load_prior = document.getElementById( 'load-prior' ), + + workstatus = null, + + valspan = {}, + bucket = {}, + rate_result = {}, + + // used to overwrite existing test cases rather than create a new + save_id = '', + prior_result, + + rate_callback = function() {}, + + // whether to ignore user input (do not put in bucket) + ignore_input = false; + + + populateBucket(); + + + function setWorkStatus( message ) + { + if ( workstatus === null ) + { + workstatus = document.createElement( 'div' ); + workstatus.id = 'workstatus'; + + document.body.appendChild( workstatus ); + } + + workstatus.innerHTML = message; + workstatus.className = ( message ) ? 'show' : ''; + } + + function populateBucket() + { + Array.prototype.slice.call( form.querySelectorAll( '[name]' ) ).forEach( + function( field ) + { + var name = field.name.replace( /\[\]$/, '' ); + + if ( !name ) + { + return; + } + + // if the name does not match, then we removed the square + // brackets, meaning that this is a set + bucket[ name ] = ( name === field.name ) + ? field.value + : [ field.value ]; + } + ); + } + + + function overrideBucket( boverride ) + { + for ( var name in boverride ) + { + bucket[ name ] = boverride[ name ]; + } + + emptyBucket(); + } + + + function removeEntryFocus() + { + form.className = form.className.replace( /\bfocus\b/, '' ); + } + + document.body.addEventListener( 'mouseup', function( e ) + { + var overform = hasParent( form, e.target ); + + if ( overform === false ) + { + removeEntryFocus(); + } + } ); + + form.addEventListener( 'reset', function() + { + if ( ignore_input ) + { + return; + } + + // wait until *after* reset + setTimeout( function() + { + clearTestCase(); + + bucket = {}; + populateBucket(); + clearSummaryPremium(); + + setWorkStatus(); + }, 0 ); + } ); + + form.addEventListener( 'mouseover', function() + { + showEntryForm(); + } ); + + + function clearTestCase() + { + save_id = ''; + prior_result = undefined; + + // clear prior message + Prior.setPriorMessage( null ); + + // clear prior class from body + document.body.className = document.body.className.replace( + /\bprior\b/, '' + ); + } + + + function setTestCase( id, result ) + { + save_id = ''+( id ); + prior_result = result; + + // this really should be set... + if ( !( prior_result.vars ) ) + { + prior_result.vars = {}; + } + + // add prior class name to body + document.body.className += ' prior'; + } + + + function showEntryForm() + { + if ( form.className.match( /\bfocus\b/ ) ) + { + return; + } + + form.className += ' focus'; + } + + + // on field change, update bucket + form.addEventListener( 'change', function( e ) + { + if ( ignore_input ) + { + return; + } + + // if we changed something, then the displayed premium (if any) must be + // invalidated + clearSummaryPremium(); + + var target = e.target, + name = target.name.replace( /\[\]$/, '' ), + value = target.value.trim(); + + if ( !name ) + { + return; + } + + // if this is a set, we want to store every value + if ( name !== target.name ) + { + var toarr = Array.prototype.slice; + + // retrieve all the rows + var rows = toarr.call( + target.parentElement.parentElement.parentElement + .querySelectorAll( '.entry-row' ) + ); + + // determine if we're working with a matrix + var matrix = /\bmatrix\b/.test( rows[ 0 ].className ); + + value = []; + rows.forEach( function( row, i ) + { + var ref = value; + + // for matricies, add value to a sub-array; vectors, just keep + // appending to the original array + if ( matrix ) + { + ref = value[ i ] = []; + } + + // add each value + toarr.call( row.querySelectorAll( '[name]' ) ).forEach( + function( node ) + { + ref.push( node.value.trim() ); + } + ); + } ); + } + + bucket[ name ] = value; + } ); + + // update screen on submit + form.addEventListener( 'submit', function( e ) + { + // do not submit the form + e.preventDefault(); + rate( bucket ); + } ); + + form.addEventListener( 'click', function( e ) + { + if ( e.target.className === 'entry-add' ) + { + addRow( e.target.parentElement, e.target ); + e.preventDefault(); + } + else if ( e.target.className === 'entry-rm' ) + { + removeColumn( e.target ); + e.preventDefault(); + } + else if ( e.target.className === 'entry-add-matrix' ) + { + addColumn( e.target ); + e.preventDefault(); + } + } ); + + + + final_good.addEventListener( 'click', function( e ) + { + e.preventDefault(); + + showFinalComments( true, function( comment, _, waiting ) + { + var prem = rate_result.premium; + + hideFinalAccept(); + submitQuote( bucket, rate_result, comment, true, waiting, prem, save_id ); + } ); + } ); + + final_bad.addEventListener( 'click', function( e ) + { + e.preventDefault(); + + showFinalComments( false, function( comment, expect, waiting ) + { + hideFinalAccept(); + submitQuote( bucket, rate_result, comment, false, waiting, expect, save_id ); + } ); + } ); + + + function showFinalComments( looksgood, callback ) + { + final_comments.className += ' show'; + + var submit = document.getElementById( 'final-submit' ), + cancel = document.getElementById( 'final-cancel' ), + + expect_container = document.getElementById( + 'final-expect-container' + ), + + submit_new = document.getElementById( 'final-submit-new' ), + + listener; + + // we do not care about the expected value if the premium looks good + expect_container.style.display = ( looksgood ) + ? 'none' + : 'inline'; + + // if a test case is set, give them the option to clear it and submit it + // as a new test case + submit_new.style.display = ( save_id ) + ? 'inline' + : 'none'; + + // make it very clear what the user is about to do + submit.innerHTML = ( save_id ) + ? 'Update Existing Test Case' + : 'Submit'; + + // we won't use addEventListener becuase we only want one event to be + // attached + submit.onclick = function( e ) + { + e.preventDefault(); + + var comments = document.getElementById( 'final-comments' ), + expected = document.getElementById( 'final-expected' ), + waiting = document.getElementById( 'final-waiting' ); + + callback( + comments.value, + +( expected.value.replace( /^\$/, '' ) ), + !!waiting.checked + ); + + rmclass( final_comments, 'show' ); + }; + + submit_new.onclick = function( e ) + { + e.preventDefault(); + + // clear save id and trigger normal submit + save_id = ''; + submit.onclick( e ); + }; + + cancel.onclick = function( e ) + { + e.preventDefault(); + rmclass( final_comments, 'show' ); + }; + + // give focus to final comments + document.getElementById( 'final-comments' ).focus(); + } + + + function hideFinalAccept() + { + // replace all shows since there may be multiple + final_accept.className = final_accept.className.replace( + /\bshow\b/, + '' + ); + } + + + function getXhrJsonSync( method, url, data ) + { + var xhttp = new XMLHttpRequest(); + + xhttp.open( method, url, false ); + + if ( method.toLowerCase() === 'post' ) + { + xhttp.setRequestHeader( 'Content-type', + 'application/x-www-form-urlencoded' + ); + } + + xhttp.send( ( data ) ? 'data=' + JSON.stringify( data ) : null ); + + if ( xhttp.status !== 200 ) + { + throw Error( 'Submit failed; status: ' + xhttp.status ); + } + + // this will fail if the response is crap, but will be caught by the + // exception + return JSON.parse( xhttp.responseText ); + } + + + function getXhrJson( method, url, data, callback ) + { + var xhttp = new XMLHttpRequest(); + xhttp.open( method, url, true ); + + if ( method.toLowerCase() === 'post' ) + { + xhttp.setRequestHeader( 'Content-type', + 'application/x-www-form-urlencoded' + ); + } + + xhttp.onload = function() + { + if ( xhttp.status !== 200 ) + { + callback( null, + Error( 'Submit failed; status: ' + xhttp.status ) + ); + return; + } + + callback( JSON.parse( xhttp.responseText ) ); + } + + xhttp.send( ( data ) ? 'data=' + JSON.stringify( data ) : null ); + } + + + function submitQuote( + bucket, result, comment, looksgood, waiting, expected, caseid, success_callback + ) + { + // we don't want to modify the original result (could use + // Object.create() here, but they may be using IE) + var tmpresult = function() {}; + tmpresult.prototype = result; + + // it is absolutely pointless to store debug information since the ids + // change at any time and are dependent on the XSL processor + var submit_result = new tmpresult(); + + // so that it's property serialized + for ( var name in result ) + { + submit_result[ name ] = result[ name ]; + } + + // we do not need the debug information (there's a lot of it and it + // changes frequently) + submit_result.debug = undefined; + + // nor do we need constants (especially large ones)! + submit_result.consts = undefined; + + var data = { + bucket: bucket, + result: submit_result, + looksgood: !!looksgood, + waiting: !!waiting, + comment: encodeURIComponent( comment ), + expected: expected, + supplier: supplier, + + // will cause an existing test case to be overwritten, if set + caseid: caseid, + }; + + getXhrJson( 'POST', submit_url, data, function( response, err ) + { + // check the response of the actual save (just because we + // got a HTTP 200 doesn't mean we successfully saved to the + // server; we could have also hit the wrong page + // (misconfigured)!) + if ( err ) + { + alert( + 'Ah, crap! Quote submission failed! Contact IT before ' + + 'you do anything else.\n\n' + + 'Here are the boring details:\n' + + ' ' + err.message + ); + + return; + } + + success_callback && success_callback(); + } ); + } + + + + function addRow( parent, before ) + { + before = before || parent.querySelector( '.entry-add' ); + + // get the row to duplicate + var dup = parent.querySelector( '.entry-row' ) + .cloneNode( true ); + + parent.insertBefore( dup, before ); + + // trigger change so that its value can be recorded + triggerChange( dup.querySelector( '[name]' ) ); + } + + + function addColumn( event_target ) + { + // get the field to duplicate + var dup = event_target.parentElement.querySelector( '.entry-field' ) + .cloneNode( true ); + + event_target.parentElement.insertBefore( dup, event_target ); + + // trigger change so that its value can be recorded + triggerChange( dup.querySelector( '[name]' ) ); + } + + + function removeColumn( event_target ) + { + var rm = event_target.parentElement, + parent = rm.parentElement, + rowParent = parent.parentElement, + + rows = rowParent.querySelectorAll( '.entry-row' ).length, + cols = parent.querySelectorAll( '.entry-field' ).length; + + // do not remove last column of last row + if ( ( rows + cols ) === 2 ) + { + return; + } + + // remove the element + parent.removeChild( rm ); + + // if there are no more columns, remove the row + if ( cols === 1 ) + { + rowParent.removeChild( parent ); + } + + // re-gather values in bucket to accomodate missing value (we can do so + // simply by triggering a change on one of the elements of the same + // name) + triggerChange( rowParent.querySelector( '[name]' ) ); + } + + + function triggerChange( element ) + { + if ( !element ) + { + return; + } + + // create change event + var event = document.createEvent( 'Event' ); + event.initEvent( 'change', true, true ); + + // trigger event + element.dispatchEvent( event ); + } + + + function rate( args, showresults, exception ) + { + showresults = ( showresults === undefined ) ? true : !!showresults; + exception = !!exception; + + var rater = window.rater; + + if ( !( window.rater ) ) + { + alert( 'fatal: rater unavailable.' ); + return; + } + + setWorkStatus( 'Performing rating...' ); + + try + { + var result = rater( args ); + + // XXX: ewwww + rate_result = result; + + if ( !( showresults ) ) + { + return; + } + + // log result to the console in case we want to peeky peeky + console.log( result ); + + rate_callback( result ); + + setWorkStatus( 'Updating premium...' ); + updateSummaryPremium( result.premium ); + + // VOIs are referenced immediately, so render them first + updateVois( result.vars, function() + { + // classes are faster to process than the other summary values + updateSummaryClasses( + result.classes, + result.vars, + undefined, + + function() + { + updateSummaryValues( result.vars ); + } + ); + } ); + } + catch ( e ) + { + setWorkStatus( 'Rating error occurred.' ); + + console && console.log( e ); + + if ( exception ) + { + throw e; + } + else + { + alert( 'fatal: ' + e.message ); + } + } + } + + + function updateSummaryPremium( premium ) + { + final_prem.innerHTML = premium; + final_prem.className += ' show'; + + final_accept.className += ' show'; + + setPlaceholderValue( 'yields_premium', '', premium ); + } + + + function clearSummaryPremium() + { + final_prem.innerHTML = ''; + + rmclass( final_prem, 'show' ); + rmclass( final_accept, 'show' ); + } + + + function getValueDisplay( value ) + { + if ( Array.isArray( value ) ) + { + return joinValues( value ); + } + + return ( value === undefined ) + ? '' + : ''+( value ); + } + + + function updateVois( vars, callback ) + { + setWorkStatus( 'Processing VOIs...' ); + voi.innerHTML = ''; + + var queue = []; + for ( var name in vars ) + { + queue.push( name ); + } + + var vois = {}, + qlen = queue.length, + i = qlen; + + dequeueSetsOf( 10, function( c ) + { + if ( i-- === 0 ) + { + // display the VOIs + processVois( vois ); + document.getElementById( 'voi-container' ).className += ' show'; + + setWorkStatus(); + callback && callback(); + + return; + } + + setWorkStatus( + 'Processing VOIs (' + + Math.floor( ( ( qlen - i ) / qlen ) * 100 ) + + '%)...' + ); + + var name = queue[ i ], + value = vars[ name ]; + + if ( value + && /^prem|^min|^surcharge|^cov(erage)?|^credit|^factor|^rate|Prem|[tT]otal/ + .test( name ) + && !( /^_/.test( name ) ) + ) + { + var display = getValueDisplay( value ), + prior = ( prior_result && prior_result.vars[ name ] ) + ? getValueDisplay( prior_result.vars[ name ] ) + : ''; + + // update values of interest (voi) + if ( display !== '[]' ) + { + vois[ name ] = [ display, prior ]; + } + } + + // continue + c(); + } )(); + } + + + function updateSummaryValues( vars, placeid, callback ) + { + var queue = []; + + for ( var name in vars ) + { + queue.push( name ); + } + + var qlen = queue.length; + + // repaint frequently; this is intensive + dequeueSetsOf( 10, function( c ) + { + if ( queue.length === 0 ) + { + setWorkStatus(); + return; + } + + name = queue.pop(); + + setWorkStatus( + 'Formatting summary values (' + + Math.floor( ( ( qlen - queue.length ) / qlen ) * 100 ) + + '%)...' + ); + + var value = vars[ name ], + display = getValueDisplay( value ), + prior = ( prior_result && prior_result.vars[ name ] ) + ? getValueDisplay( prior_result.vars[ name ] ) + : ''; + + + setPlaceholderValue( name, '', display ); + + if ( prior ) + { + setPlaceholderValue( name, '-prior', prior ); + } + + setLetListPlaceholders( name, display, prior ); + + // continue + c(); + } )(); + } + + + function dequeueSetsOf( n, c ) + { + return function dq( i ) + { + i = i || 0; + + c( function() + { + if ( i === 0 ) + { + setTimeout( function() + { + dq( n ) + }, 0 ); + } + else + { + dq( i - 1 ); + } + } ); + } + } + + + function processVois( vois ) + { + // add the vois to the screen in the proper order (reversed) + var i = window.voi_order.length; + while ( i-- ) + { + var data = window.voi_order[ i ], + name = data[ 0 ], + depth = data[ 1 ], + href = data[ 2 ]; + + if ( vois[ name ] ) + { + var voi = vois[ name ]; + addVoi( name, voi[ 0 ], voi[ 1 ], href, depth ); + } + } + } + + + function addVoi( name, value, prior, href, depth ) + { + depth = depth || 0; + + // if the VOI has a value other than 0 (our poor-man check is using a + // regex to remove anything and see if we have a non-empty string left) + if ( ( value.replace( /[\[\]0,]/g, '' ) === '' ) + && ( prior.replace( /[\[\]0,]/g, '' ) === '' ) + ) + { + return; + } + + var depthstr = '', + i = depth; + while ( i-- ) + { + if ( i === 0 ) + { + depthstr += '|-'; + } + + depthstr += '  '; + } + + // if href is not given, then use name + href = href || name; + + // got lazy. + var tr = document.createElement( 'tr' ); + tr.className = 'depth' + depth; + tr.innerHTML = ( + '' + + '' + + depthstr + name + + '' + + '' + + '' + depthstr.replace( /-/, '' ) + value + '' + + ( ( !prior ) ? '' : + '' + prior + '' + ) + ); + + tr.addEventListener( 'click', function( e ) + { + // ignore link clicks + if ( e.target.nodeName === 'A' ) + { + return; + } + + var val = JSON.parse( value ); + if ( Array.isArray( val ) ) + { + var t = 0; + for ( var i in val ) + { + t += val[ i ]; + } + + val = t; + } + + voiPainterAdd( tr, val ); + } ); + + voi.appendChild( tr ); + } + + + function addClassOverview( name, value ) + { + var prior = ( prior_result && prior_result.vars[ name ] ) + ? getValueDisplay( prior_result.vars[ name ] ) + : ''; + + // got lazy. + var tr = document.createElement( 'tr' ); + tr.innerHTML = ( + '' + + '' + + name + + '' + + '' + ); + + coview.appendChild( tr ); + } + + + function joinValues( values ) + { + var ret = '['; + + if ( Array.isArray( values[ 0 ] ) ) + { + var subvals = []; + + for ( var i in values ) + { + subvals.push( joinValues( values[ i ] ) ); + } + + ret += subvals.join( ', ' ); + } + else + { + ret += ( Array.isArray( values ) ) + ? values.join( ', ' ) + : values; + } + + return ret + ']'; + } + + + function updateSummaryClasses( classes, vars, placeid, callback ) + { + coview.innerHTML = ''; + + var queue = []; + + for ( var name in classes ) + { + queue.push( name ); + } + + var qlen = queue.length; + + dequeueSetsOf( 10, function( c ) + { + if ( queue.length === 0 ) + { + setWorkStatus(); + callback && callback(); + + return; + } + + var name = queue.pop(); + + setWorkStatus( + 'Formatting class summary values (' + + Math.floor( ( ( qlen - queue.length ) / qlen ) * 100 ) + + '%)...' + ); + + // output the classification and the total premium for the class + setPlaceholderValue( 'class-' + name, placeid, + ( + ''+( classes[ name ] ) + + ' -> ' + + vars[ name ] + ), + classes[ name ] + ); + + if ( prior_result + && prior_result.classes + && prior_result.classes[ name ] + ) + { + // XXX: duplicate + setPlaceholderValue( 'class-' + name, '-prior', + ( + ''+( prior_result.classes[ name ] ) + + ' -> ' + + prior_result.vars[ name ] + ), + classes[ name ] + ); + } + + // if this class was a match, add it to the overview with its + // accumulator value + if ( classes[ name ] ) + { + addClassOverview( name, vars[ name ] ); + } + + c(); + } )(); + + document.getElementById( 'class-overview' ).className += ' show'; + } + + + function updateSummaryDebug( debug, parent, callback ) + { + var queue = []; + + // do nothing if debug data is not yet available + if ( !debug ) + { + return; + } + + // loop through each element on the DOM, *not* each debug id returned to + // us, since we want to clear any that may be missing + Array.prototype.slice.call( parent.querySelectorAll( '.debugid' ) ) + .forEach( function( element ) + { + queue.push( element.id ); + } ); + + var qlen = queue.length; + + dequeueSetsOf( 10, function( c ) + { + if ( queue.length === 0 ) + { + setWorkStatus(); + callback && callback(); + + return; + } + + setWorkStatus( + 'Processing breakdown values (' + + Math.floor( ( ( qlen - queue.length ) / qlen ) * 100 ) + + '%)...' + ); + + var id = queue.pop(), + did = id.replace( /^ubd-/, '' ); + + try + { + setPlaceholderValue( id, '', ( debug[ did ] ) + ? JSON.stringify( debug[ did ] ) + : '' + ); + } + catch ( e ) + { + console.error( + 'Debug (stringify debug ' + did + ' ): ' + + e.message + ); + } + + c(); + } )(); + } + + + var getPlaceholder = ( function() + { + var domcache = {}; + + function getPlaceholder( name, placeid ) + { + var classname = ( 'entry-value' + ( placeid || '' ) ); + + var current = domcache[ name + placeid ]; + if ( current ) + { + return current; + } + + // ignore system vars + if ( name.match( /^___/ ) ) + { + return null; + } + + var parent = document.getElementById( name ); + + if ( !parent ) + { + return null; + } + + var legend = parent.getElementsByTagName( 'legend' ), + dest = ( legend.length ) ? legend[ 0 ] : parent; + + var element = document.createElement( 'span' ); + element.className = classname; + dest.appendChild( element ); + + // rather than re-scanning the DOM each time + domcache[ name + placeid ] = element; + + return element; + } + + return getPlaceholder; + } )(); + + + function setPlaceholderValue( name, placeid, value, hasval ) + { + var p = getPlaceholder( name, placeid ); + if ( p === null ) + { + return; + } + + p.innerHTML = value; + + // do not handle prior flagging + if ( placeid === '-prior' ) + { + return; + } + + // get fieldset + var fs = p.parentNode.parentNode; + if ( fs.nodeName === 'FIELDSET' ) + { + fs.className = fs.className.replace( /\Bhasval\B/, '' ); + if ( ( hasval !== undefined && hasval ) + // progressively more time-consuming checks + || ( ( hasval === undefined ) + && value + && +value !== 0 + && value.replace( /[\[\],0]/g, '' ) + ) + ) + { + fs.className += ' hasval'; + } + } + } + + + function setLetListPlaceholders( name, value, prior ) + { + if ( name.match( /^___/ ) ) + { + return; + } + + // certainly room for improvement here (especially performance-wise), + // but this is a quick implementation + var elements = document.querySelectorAll( '.letlist-' + name ); + Array.prototype.slice.call( elements ).forEach( function( element ) + { + if ( !( element.id ) ) + { + // prefix with alpha so as not to cause a syntax error on query + element.id = 'll' + Math.floor( + ( new Date() ).getTime() * Math.random() + ); + } + + setPlaceholderValue( element.id, '', value ); + + // include prior values, if available + if ( prior ) + { + setPlaceholderValue( element.id, '-prior', prior ); + } + } ); + } + + + function rmclass( element, name ) + { + element.className = element.className.replace( + new RegExp( '\\b' + name + '\\b', 'g' ), + '' + ); + } + + + function hasParent( parent, element ) + { + var parentElement = element.parentElement; + + if ( parentElement === parent ) + { + return true; + } + + return ( parentElement ) + ? hasParent( parent, parentElement ) + : false; + } + + + // XXX: This is a mess. THIS IS WHAT TIME CONSTRAINTS DO TO CODE QUALITY! + // LET ME HACK IN PEACE! >:@ (What? Unconstrained development is a fantasy? + // Is unlimited time unreasonable? Phf. Maybe that Time Weaver frog person + // knows how to help with that. If you don't know that reference and you're + // in here hacking this code, then that implies that you are new; it then + // begs the question: why has it persisted for so long!!! Of course it has, + // though. That's how TODOs/XXXs work: they don't get fixed; they just turn + // text in your editor pretty [obnoxious] colors.) + function resetFields() + { + // XXX: gahhhhhh!!!!!!! + ignore_input = true; + + function rowquery( name ) + { + return document.querySelectorAll( + '#param-input-' + name + ' > .entry-row' + ); + } + + for ( var field in bucket ) + { + // may happen if we're loading data from another source + if ( bucket[ field ] === undefined ) + { + continue; + } + + var fdata = bucket[ field ], + elements = rowquery( field ), + + length = ( fdata.length > elements.length ) + ? fdata.length + : elements.length; + + if ( elements.length === 0 ) + { + continue; + } + + // not everything is an array of values + if ( Array.isArray( fdata ) ) + { + // add/clear fields on the form as necessary to accomdate bucket + // data + for ( var i = 0; i < length; i++ ) + { + // field exists in bucket but not on the form + if ( ( fdata[ i ] !== undefined ) && !( elements[ i ] ) ) + { + addRow( elements[ 0 ].parentNode ); + } + // field exists on form but not in the bucket + else if ( elements[ i ] && ( fdata[ i ] === undefined ) ) + { + // TODO: remove field instead + elements[ i ].querySelector( '[name]' ).value = ''; + } + + // if we have a matrix of values, we must also add columns + // for each + if ( Array.isArray( fdata[ i ] ) ) + { + var element = rowquery( field )[ i ], + cols = element.querySelectorAll( + '.entry-field' + ), + + len = ( fdata[ i ].length > cols.length ) + ? fdata[ i ].length + : cols.length; + + // check each column + for ( var j = 0; j < len; j++ ) + { + if ( ( fdata[ i ][ j ] !== undefined ) + && !( cols[ j ] ) + ) + { + // re-query in case we just added a row + addColumn( element.querySelector( + '.entry-add-matrix' + ) ); + } + else if ( cols[ j ] + && ( fdata[ i ][ j ] === undefined ) + ) + { + // TODO: remove field instead + cols[ i ].querySelector( '[name]' ).value = ''; + } + } + } + } + } + } + + form.reset(); + ignore_input = false; + } + + + function emptyBucket() + { + resetFields(); + + // prevent form updates from propagating to the bucket + ignore_input = true; + + for ( var field in bucket ) + { + var fdata = bucket[ field ]; + + // not everything is an array; if not, simply set the value and move + // on + if ( !( Array.isArray( fdata ) ) ) + { + var element = document.querySelector( + '[name="' + field + '"]' + ); + + if ( element ) + { + element.value = fdata; + } + + continue; + } + + var elements = document.querySelectorAll( + '[name="' + field + '[]"]' + ); + + var total = 0; + for ( var i = 0, l = fdata.length; i < l; i++ ) + { + if ( !( elements[ i ] ) ) + { + continue; + } + + // if a matrix, update each value + if ( Array.isArray( fdata[ i ] ) ) + { + for ( var j = 0, jl = fdata[ i ].length; j < jl; j++ ) + { + elements[ total++ ].value = fdata[ i ][ j ]; + } + } + else + { + // not a matrix + elements[ total++ ].value = fdata[ i ]; + } + } + } + + // re-allow input + ignore_input = false; + } + + + function getUserFromHostname( hostname ) + { + // strip off any domain, remove number from username and strip anything + // after a dash (e.g. gerwitm-ubuntu2.lovullo.local => gerwitm) + return hostname.split( '.' )[ 0 ].replace( /[0-9]+$/, '' ) + .split( '-' )[ 0 ]; + } + + + /** + * Prior module: load prior quotes (test cases) + * + * Not to be confused in speech with the Friar module, which would have your + * premiums divinely calculated and communicated through a deep meditation. + */ + var Prior = ( function ___loadprior( dom ) + { + var exports = {}, + + // current set of loaded test cases + curset = {}; + + var getLoadDialog = function() + { + // URL with fragment to automatically display this dialog + var url = document.location.href.replace( /#.*$/, '' ) + '#prior'; + + var dialog = dom.createElement( 'div' ); + dialog.id = 'prior'; + dialog.className = 'load-dialog'; + dialog.innerHTML = + "

    Load Prior Quotes

    " + + "

    " + + "Below is a list of all prior saved quotes; choose one " + + "to load it into the test area." + + "

    " + + "

    " + + "To load this dialog automatically on page load, you " + + "may use the following link: " + + url + "" + "

    "; + + // re-test button + var retest = dom.createElement( 'button' ); + retest.innerHTML = 'Regression Test'; + retest.addEventListener( 'click', function( e ) + { + e.preventDefault(); + e.target.disabled = 'disabled'; + + retestAll( function() + { + e.target.disabled = ''; + } ); + } ); + + // load quote number + var loadquote = dom.createElement( 'button' ); + loadquote.innerHTML = 'Load Quote #'; + loadquote.addEventListener( 'click', function( e ) + { + e.preventDefault(); + + var qid = prompt( 'Enter quote #:' ); + + if ( !qid ) + { + return; + } + + exports.hideLoad(); + + loadQuote( qid, qdata_host ); + } ); + + dialog.appendChild( retest ); + dialog.appendChild( loadquote ); + dialog.appendChild( getPriorTable() ); + + dom.body.appendChild( dialog ); + + // reassign the function to always return the instance + getLoadDialog = function() + { + return dialog; + }; + + return getLoadDialog(); + }; + + + var getPriorTable = function() + { + var table = dom.createElement( 'table' ), + headings = [ + "Date", "Description", "User", "Premium", "Expected" + ]; + + // add headings + for ( var head in headings ) + { + var th = dom.createElement( 'th' ); + th.innerHTML = headings[ head ]; + th.className = headings[ head ].toLowerCase(); + + table.appendChild( th ); + } + + // add count + var count = dom.createElement( 'caption' ); + count.innerHTML = + 'Total Count: 0'; + table.appendChild( count ); + + table.clear = function() + { + var rows = table.querySelectorAll( 'tr' ); + for ( var i = 0; i < rows.length; i++ ) + { + table.removeChild( rows[ i ] ); + } + }; + + table.addRow = function( looksgood, waiting /*, ... */ ) + { + var tr = dom.createElement( 'tr' ); + + // the first argument is the id + var id = arguments[ 0 ]; + tr.id = '_testcase_' + id; + + // the second argument will determine the row color (looksgood) + tr.className = + ( ( arguments[ 1 ] ) + ? 'good' + : 'bad' + ) + + ( ( arguments[ 2 ] ) + ? ' waiting' + : '' + ); + + // all other arguments will be cells + for ( var i = 3; i < arguments.length; i++ ) + { + var td = dom.createElement( 'td' ); + td.innerHTML = arguments[ i ]; + td.className = headings[ i - 3 ].toLowerCase(); + + // first cell will contain a hyperlink for auto-loading on + // visit + if ( i === 3 ) + { + var a = dom.createElement( 'a' ); + a.href = ( '#prior/' + id ); + a.innerHTML = td.innerHTML; + + td.innerHTML = ''; + td.appendChild( a ); + + a.addEventListener( 'click', function( e ) + { + doLoad( id ); + } ); + } + + tr.appendChild( td ); + } + + table.appendChild( tr ); + }; + + table.setCount = function( count ) + { + table.querySelector( '.count' ).innerHTML = +count; + }; + + table.mark = function( id, type ) + { + table.querySelector( '#_testcase_' + id ).className = type; + }; + + table.changePremium = function( id, premium ) + { + var element = table.querySelector( + '#_testcase_' + id + ' .premium' + ); + + // add the value and retain the previous value + element.innerHTML = '$' + premium + + '
    (was ' + element.innerHTML + + ')
    '; + }; + + table.changeComment = function( id, comment ) + { + var element = table.querySelector( + '#_testcase_' + id + ' .description' + ); + + element.innerHTML = comment.replace( /\n/g, '
    ' ); + }; + + function doLoad( id ) + { + exports.hideLoad(); + + // give them an indication that something is happening + setTimeout( function() + { + loadPriorTestCase( id ); + }, 0 ); + } + + // when a row is clicked, trigger the load + table.addEventListener( 'click', function( e ) + { + // we care only of row clicks + if ( e.target.nodeName.toLowerCase() !== 'td' ) + { + return; + } + + // get the unique id for this test case + var id = e.target.parentNode.id.replace( /^_testcase_/, '' ); + doLoad( id ); + } ); + + getPriorTable = function() + { + return table; + }; + + return getPriorTable(); + }; + + + function loadPrior() + { + // first, clear out any existing results + getPriorTable().clear(); + + // load prior data from server + var response = getXhrJsonSync( 'GET', prior_url ), + table = getPriorTable(), + results = response.results; + + // store the current set of test cases + curset = results; + + // add test test case to the table + for ( testcase in results ) + { + var result = results[ testcase ]; + + table.addRow( + result.id, + result.looksgood, + result.waiting, + result.date, + + // comment + ( result.comment.replace( /\n/g, '
    ' ) + || '(no comment)' + ), + + // username (from hostname) + getUserFromHostname( result.hostname ), + + // premium + ( '$' + ( result.premium || 0.00 ) ), + + // expected premium + ( ( result.expected ) + ? '$' + result.expected + : ( result.looksgood ) + ? '$' + result.premium + : '-' + ) + ); + } + + table.setCount( results.length ); + } + + + function getTestCaseData( id ) + { + return getXhrJsonSync( 'GET', prior_url + '&id=' + id ); + } + + + function getQuoteData( id, qdata_host ) + { + try + { + return getXhrJsonSync( + 'GET', prior_url + '&host=' + qdata_host + '&qid=' + id + ); + } + catch ( e ) + { + return { error: 'Invalid response from server.' }; + } + } + + + function showRatingResultPage() + { + dom.location.hash = 'test-data'; + } + + + function loadQuote( qid, host, bucket_override ) + { + var data = getQuoteData( qid, host ); + if ( data.error !== 'OK' ) + { + alert( data.error ); + return; + } + + rater.fromMap( data.results.bucket, function( data ) + { + bucket = data; + emptyBucket(); + + if ( bucket_override ) + { + overrideBucket( bucket_override ); + } + + showRatingResultPage(); + rate( bucket ); + } ); + } + + + function loadPriorTestCase( id ) + { + var casedata = getTestCaseData( id ); + + if ( casedata.status !== 200 ) + { + alert( 'Could not load test case.\n\n' + casedata.error ); + } + + var data = casedata.results; + + // display the message so that they know what they're looking at + exports.setPriorMessage( + data.hostname, data.comment, data.looksgood, id + ); + + // overwrite the bucket + bucket = data.bucket; + emptyBucket(); + + // set this test case so that our next save overwrites it + setTestCase( id, data.result ); + + // make it obvious to the user that the data has been loaded + clearSummaryPremium(); + showEntryForm(); + + // prefill the comment and expected data on the submission form, + // leaving room at the top for additional comments + document.getElementById( 'final-comments' ) + .innerHTML = ( + "\n\n\n" + + getPrevSubmitCommentText( + data.hostname, + data.comment + ) + ); + document.getElementById( 'final-expected' ).value = data.expected; + + // let the browser catch up and then perform rating + setTimeout( function() + { + // switch to test data and rate + document.location.hash = '#test-data'; + rate( bucket ); + }, 0 ); + } + + + function getPrevSubmitCommentText( hostname, comment ) + { + return "Previously submitted by " + + getUserFromHostname( hostname ) + ": " + comment; + } + + + function retestAll( callback ) + { + var queue = [], + skipped = 0, + + // regression test results, which may or may not be submitted to + // the server + history = {}; + + // queue each of the test cases + for ( var testcase in curset ) + { + queue.push( curset[ testcase ] ); + } + + var count = failures = changed = 0, + start = ( new Date() ).getTime(); + + var run = function() + { + // do not pop(); we want to do them in order so it doesn't look + // too odd to the user + var test = queue.shift(); + + // all done + if ( !( test ) ) + { + var time = ( new Date() ).getTime() - start; + + var msg = ( + 'Test complete. Re-ran ' + count + ' test(s) with ' + + failures + ' failure(s) in ' + ( time / 1000 ) + 's.' + + "\n\n" + + + ( ( skipped ) + ? skipped + " test(s) premium checks " + + "were skipped because they " + + "have no expected premium; please aid in the " + + "automated testing of these by selecting " + + "them and entering an expected premium when " + + "re-submitting it (by clicking Incorrect). " + + "These skipped tests are still noted if " + + "their premiums changed (in italics), but " + + "their success statuses are left untouched." + : '' + ) + + + ( ( failures === 0 ) + ? ( !skipped ) + ? "\n\nYou should feel pretty sweet right now." + : '' + : "\n\nSomeone's got some splainin' to do." + ) + + + ( ( !changed ) ? "\n\nNo test cases have changed." : + "\n\n" + changed + " case(s) changed." + + "\n\nWould you like the results of this regression " + + "to be recorded? This will cause the status of each " + + "test case to be updated as shown. If unsure, click " + + "'Cancel'." + ) + ); + + // if we have changes, show a box asking if the changes + // should be uploaded to the server; otheriwse, just alert + // (which will return undefined and cast to false) + var submit = !!( changed && confirm || alert ) + .call( window, msg ); + + if ( submit ) + { + saveRegression( history ); + } + + callback && callback( count, failures, time ); + + return; + } + + var table = getPriorTable(); + table.mark( test.id, 'testing' ); + + setTimeout( function() + { + var testdata = getTestCaseData( test.id ).results; + + try + { + // rate, but do not update the screen + rate( testdata.bucket, false, true ); + } + catch ( e ) + { + console.log( e ); + table.mark( test.id, 'skip' ); + + // abort! abort! + //alert( 'An error occurred. Aborting.' ); + run(); + return; + } + + // determine what premium we're expecting (default to + // existing premium) + var expected = testdata.expected || testdata.result.premium, + skipme = !( testdata.looksgood || testdata.expected ); + + var correct = ( + rate_result.premium + && ( rate_result.premium == expected ) + ); + + // add to changed count if the status changed + var has_changed = ( testdata.looksgood !== correct ); + changed += ( +has_changed && !skipme ); + + skipped += +skipme; + + // only add to the total count if the premium was actually + // compared + if ( !skipme ) + { + count++; + + if ( !( correct ) ) + { + failures++; + } + + // store in case the user decides to save to the server + if ( has_changed ) + { + history[ test.id ] = { + looksgood: correct, + bucket: testdata.bucket, + result: rate_result, + expected: expected, + comment: testdata.comment, + hostname: testdata.hostname, + previous: testdata.result, + }; + + // show the comment that would be saved to the + // server, should they choose to do so + table.changeComment( + test.id, + genRegressionComment( history[ test.id ] ) + ); + } + } + + // update table + table.changePremium( test.id, rate_result.premium ); + table.mark( + test.id, + ( + ( ( correct ) + ? 'good' + : 'bad' + ) + + ( ( has_changed ) + ? ' changed' + : '' + ) + + ( ( rate_result.premium !== testdata.result.premium ) + ? ' premchanged' + : '' + ) + + ( ( skipme ) + ? ' skipped' + : '' + ) + ) + ); + + // continue + run(); + }, 0 ); + } + + // run 'em one by one + setTimeout( run, 0 ); + } + + + function genRegressionComment( item ) + { + return "[Regression Test: " + + ( ( item.looksgood ) ? "Pass" : "Fail" ) + + "] Expected $" + item.expected + "; calculated $" + + item.result.premium + "; previously $" + + item.previous.premium + "\n\n" + + getPrevSubmitCommentText( item.hostname, item.comment ); + } + + + function saveRegression( history ) + { + for ( var id in history ) + { + var item = history[ id ]; + + // generate comment + var comment = genRegressionComment( item ); + + submitQuote( + item.bucket, + item.result, + comment, + item.looksgood, + ( item.waiting || false ), + item.expected, + id, + function() {} + ); + } + } + + + exports.initHtml = function() + { + getLoadDialog(); + } + + + exports.showLoad = function() + { + removeEntryFocus(); + + getLoadDialog().className += ' show'; + loadPrior(); + } + + + exports.hideLoad = function() + { + var dialog = getLoadDialog(); + dialog.className = dialog.className.replace( /\bshow\b/g, '' ); + } + + + exports.setPriorMessage = function( host, message, good, id ) + { + var container = document.getElementById( 'prior-message' ); + + if ( !container ) + { + return; + } + + container.style.display = ( message ) ? 'inline-block' : 'none'; + container.className = ( good ) ? 'good' : 'bad'; + container.innerHTML = ( + '' + getUserFromHostname( host ) + ': ' + + message + .replace( /^\n+|\n+$/g, '' ) + .replace( / /g, '  ' ) + .replace( /\t/g, '    ' ) + .replace( /\n/g, '
    ' ) + .replace( + /(Previously submitted by [^:]+:)/g, + '$1' + ) + + '

    [Direct Link]' + ); + }; + + exports.loadQuote = loadQuote; + exports.loadPriorTestCase = loadPriorTestCase; + + return exports; + } )( document ); + + + function begin() + { + // initialize prior div + Prior.initHtml(); + + // allow linking to test cases + var pmatch; + if ( pmatch = document.location.href.match( /#prior(?:\/(.*))?$/ ) ) + { + var id = pmatch[ 1 ]; + + if ( !( id ) ) + { + // no id given; let them choose + Prior.showLoad(); + } + else + { + // we were given an id; load it! + console.log( 'Loading ' + id + '...' ); + Prior.loadPriorTestCase( id ); + } + } + + // allow settings params from the URL (very basic parsing; barely used); we + // use a colon rather than ? because ? is not included in the location + // object + var pdata; + var bucket_override = []; + if ( pdata = document.location.hash.match( /:(.*)$/ ) ) + { + try + { + // params delimited by & + var params = pdata[1].split( '&' ); + for ( var param in params ) + { + // values delimited from the name by = + var valdata = params[ param ].split( '=' ), + val = JSON.parse( valdata[ 1 ] ); + + bucket_override[ valdata[ 0 ] ] = val; + bucket[ valdata[ 0 ] ] = val; + + console.log( 'Bucket override: ' + valdata[ 0 ] + '=' + val ); + } + + overrideBucket( bucket_override ); + } + catch ( e ) + { + alert( 'Failed setting param values from URL.\n\n' + e.message ); + } + } + + // allow loading of quote ids + var mdata; + if ( mdata = document.location.hash.match( /#load\/([a-z]+)\/([0-9]+)/ ) ) + { + var host = mdata[1], + id = mdata[2]; + + // load the quote + Prior.loadQuote( id, host, bucket_override ); + } + } + + + var vpt = [ 0, 0, 0 ], + vpt_cur = 0; + function voiPainterAdd( tr, value ) + { + var c = 'sel' + vpt_cur; + tr.classList.toggle( c ); + + vpt[ vpt_cur ] += ( value * ( tr.classList.contains( c ) ? 1 : -1 ) ); + vpt[ vpt_cur ] = +( vpt[ vpt_cur ].toFixed( 6 ) ); + + showVoiPainter( vpt[ vpt_cur ] ); + } + + + var vp_element = null, + vpt_dest = []; + function showVoiPainter( val ) + { + if ( !vp_element ) + { + vp_element = document.createElement( 'div' ); + vp_element.id = 'voi-painter'; + + for ( var i in vpt ) + { + vpt_dest[ i ] = document.createElement( 'div' ); + vpt_dest[ i ].classList.add( 'sel' + i ); + vpt_dest[ i ].innerHTML = '0'; + vp_element.appendChild( vpt_dest[ i ] ); + + ( function( i ) + { + vpt_dest[ i ].addEventListener( 'click', function() + { + vpt_cur = i; + } ); + } )( i ); + } + + document.getElementById( 'test-data' ).appendChild( vp_element ); + } + + vpt_dest[ vpt_cur ] .innerHTML = val; + } + + + return { + updateSummaryDebug: updateSummaryDebug, + + onRate: function( callback ) + { + rate_callback = callback; + }, + + begin: begin, + Prior: Prior, + }; +} )(); diff --git a/src/current/src/.gitignore b/src/current/src/.gitignore new file mode 100644 index 00000000..fd9d5a65 --- /dev/null +++ b/src/current/src/.gitignore @@ -0,0 +1,6 @@ +# may be copied into the cwd for testing, since it is a dep +saxon8.jar + +*.class +*.jar +*.manifest diff --git a/src/current/src/Makefile b/src/current/src/Makefile new file mode 100644 index 00000000..2b9d08e6 --- /dev/null +++ b/src/current/src/Makefile @@ -0,0 +1,18 @@ + +dslc_src := $(wildcard com/lovullo/dslc/*.java) +dslc_bin := $(dslc_src:.java=.class) + +.PHONY: dslc clean + +dslc: dslc.jar + +%.class: %.java + javac $< + +# we explicitly specify a glob on the path because inner classes are compiled +# into their own files +dslc.jar: $(dslc_bin) + jar cfm $@ dslc.manifest com/lovullo/dslc/*.class + +clean: + rm -f $(dslc_bin) dslc.jar diff --git a/src/current/src/com/lovullo/dslc/DslCompiler.java b/src/current/src/com/lovullo/dslc/DslCompiler.java new file mode 100644 index 00000000..8747b566 --- /dev/null +++ b/src/current/src/com/lovullo/dslc/DslCompiler.java @@ -0,0 +1,303 @@ + +package com.lovullo.dslc; + +import java.io.*; +import java.util.Map; +import java.util.HashMap; +import javax.xml.XMLConstants; +import javax.xml.transform.stream.StreamSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.*; +import javax.xml.validation.*; +import javax.xml.transform.sax.SAXTransformerFactory; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +public class DslCompiler +{ + private static class _DslCompiler + { + private Validator _xsd; + private HashMap _xsl; + + + public _DslCompiler() + { + _xsd = _createXsd(); + _xsl = new HashMap(); + } + + + public void compile( + Source doc, + String cmd, + String src, + String dest, + HashMap params + ) throws Exception + { + if ( cmd.equals( "validate" ) ) + { + _xsd.validate( doc ); + return; + } + else if ( cmd.equals( "rm" ) ) + { + // remove file (purposely uncaught) + ( new File( src ) ).delete(); + + return; + } + + if ( dest.equals( "" ) ) + { + System.err.printf( + "fatal: no destination path provided\n" + ); + + System.exit( 4 ); + } + + // transform to dest + File destfile = new File( dest ); + try + { + _transform( + src, + doc, + cmd, + new StreamResult( new File( dest ) ), + params + ); + } + catch ( Exception e ) + { + // delete the output file; it's garbage + destfile.delete(); + + // be verbose and unprofessional. + throw e; + } + } + + + private void _transform( + String src, + Source doc, + String cmd, + StreamResult dest, + HashMap params + ) throws Exception + { + // load the stylesheet if it has not been already (we load lazily in + // case the stylesheet is never needed) + if ( !( _xsl.containsKey( cmd ) ) ) + { + _xsl.put( cmd, _createXslt( cmd ) ); + } + + // since XSL's abstraction does not provide a means to retrieve the + // document path (nor does it make sense to), we will pass it in + // ourselves, stripped of the file extension + String srcpkg = src.substring( 0, src.lastIndexOf( '.' ) ); + + // similarily, quickly resolve the relative root path + Integer dircount = srcpkg.replaceAll( "[^/]", "" ).length(); + String relroot = new String( new char[ dircount ] ).replace( "\0", "../" ); + + Transformer t = _xsl.get( cmd ); + t.setParameter( "__srcpkg", srcpkg ); + t.setParameter( "__relroot", relroot ); + t.setParameter( "__rseed", (int)( Math.random() * 10e6 ) ); + + _setTemplateParams( t, params ); + + t.transform( doc, dest ); + } + + + private void _setTemplateParams( + Transformer t, + HashMap params + ) throws Exception + { + for ( Map.Entry param : params.entrySet() ) + { + t.setParameter( param.getKey(), param.getValue() ); + } + } + + + private Validator _createXsd() + { + final SchemaFactory factory = SchemaFactory.newInstance( + XMLConstants.W3C_XML_SCHEMA_NS_URI + ); + + // we must disable Unique Particle Attribution (UPC) checking; the + // validator used during development did not check for this and it + // currently does not pass this test (note that disabling this also + // improves the speed of the validator) + try + { + factory.setFeature( + "http://apache.org/xml/features/validation/schema-full-checking", + false + ); + } + catch ( Exception e ) + { + System.err.println( + "fatal: cannot disable UPA checking; " + + e.getMessage() + ); + + System.exit( 1 ); + } + + try + { + final Schema schema = + factory.newSchema( new File( "rater/rater.xsd" ) ); + + return schema.newValidator(); + } + catch ( SAXException e ) + { + System.err.printf( + "fatal: %s\n", + e.getMessage() + ); + + System.exit( 1 ); + } + + return null; + } + + + private Transformer _createXslt( String src ) + { + try + { + final TransformerFactory factory = TransformerFactory.newInstance( + "net.sf.saxon.TransformerFactoryImpl", null + ); + + final Source xsl = new StreamSource( "rater/" + src + ".xsl" ); + + return factory.newTransformer( xsl ); + } + catch ( Exception e ) + { + System.err.printf( + "fatal: compilation failed; %s\n", + e.getMessage() + ); + + System.exit( 2 ); + } + + return null; + } + } + + + + public static void main( String[] args ) throws Exception + { + BufferedReader stdin = new BufferedReader( + new InputStreamReader( System.in ) + ); + + String src = ( args.length > 0 ) ? args[0] : ""; + + _DslCompiler dslc = new _DslCompiler(); + + try + { + if ( src != "" ) + { + compileSrc( dslc, src ); + } + else + { + while ( ( src = stdin.readLine() ) != null ) + { + compileSrc( dslc, src ); + } + } + } + catch ( IOException e ) + { + System.err.println( + "fatal: I/O error while reading input files: " + + e.getMessage() + ); + + System.exit( 1 ); + } + catch ( Exception e ) + { + System.err.printf( + "fatal: `%s': %s\n", + src, + e.getMessage() + ); + + // generic exception..ruh roh + throw e; + } + } + + + private static void compileSrc( _DslCompiler dslc, String cmdline ) throws Exception + { + System.err.println( cmdline ); + String[] args = cmdline.split( " " ); + String dest = ""; + + if ( args.length < 2 ) + { + System.err.printf( "fatal: invalid command: %s\n", cmdline ); + System.exit( 3 ); + } + else if ( args.length >= 3 ) + { + dest = args[2]; + } + + String cmd = args[0]; + String src = args[1]; + + HashMap params = _getXslParams( args ); + + Source doc = new StreamSource( src ); + dslc.compile( doc, cmd, src, dest, params ); + } + + + private static HashMap _getXslParams( String[] args ) + throws Exception + { + HashMap params = new HashMap(); + + for ( int i = 3; i < args.length; i++ ) + { + String[] keyval = args[ i ].split( "=" ); + + if ( keyval.length < 2 ) + { + throw new Exception( + "Invalid template param assignment: " + + args[ i ] + ); + } + + params.put( keyval[ 0 ], keyval[ 1 ] ); + } + + return params; + } +} diff --git a/src/current/standalone.xsl b/src/current/standalone.xsl new file mode 100644 index 00000000..8ce7f36d --- /dev/null +++ b/src/current/standalone.xsl @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + var rater = + + ; + + + + + + + rater.fromMap = + + + + + + + + + function(d,c){c(d);} + + + ; + + + rater._retmap = + + + + + + + + + function(d,c){c(d);} + + + ; + + + module.exports = function( args_base ) { + var ret; rater.fromMap( args_base, function( args ) { + + var rater_result = rater( args ); + + // perf counter + var start = ( new Date() ).getTime(); + + rater._retmap( rater_result.vars, function( result ) + { + // add the final premium + result.premium = rater_result.premium; + result.__classes = rater_result.classes; + + // process the rating worksheet + try + { + result.__worksheet = process_worksheet( + rater.worksheet, + rater_result.vars, + rater_result.consts, + rater_result.debug, + rater_result.premium + ); + } + catch ( e ) + { + result.__worksheet = [ 'Failed: ' + e.message ]; + } + ret = result; + } ); + + // add performance data + var end = ( new Date() ).getTime(), + time = ( ( new Date() ).getTime() - start ); + + ret.__perf = { + time: { + start: start, + end: end, + total: time + } + }; + + } ); + + return ret; + }; + + + function process_worksheet( worksheet, vars, consts, debug, premium ) + { + var ret = {}; + + for ( var name in worksheet ) + { + var data = Array.prototype.slice.call( worksheet[ name ] ), + disp = data[0], + calc = data[1], + always = data[2]; + + ret[ name ] = [ + disp, + process_wdisplay_set( [calc], vars, consts, debug ), + + ( ( name === 'yield' ) + ? premium + : ( vars[ name ] || consts[ name ] ) + ), + + ( always === 'true' ) + ]; + } + + return ret; + } + + function process_wdisplay( data, vars, consts, debug ) + { + if ( data === null ) + { + return null; + } + + var name = data[ 0 ], + desc = data[ 1 ], + sub = data[ 2 ], + val = data[ 3 ]; // may not exist + + return [ + name, + desc, + process_wdisplay_set( sub, vars, consts, debug ), + val || process_wval( name, desc, vars, consts, debug ) + ]; + } + + + function process_wval( type, desc, vars, consts, debug ) + { + if ( desc.runtime ) + { + type = 'runtime'; + } + + switch ( type ) + { + case 'apply': + case 'cases': + case 'case': + case 'otherwise': + case 'runtime': + return ( debug[ desc._id ] ); + + case 'value-of': + return ( vars[ desc.name ] || consts[ desc.name ] ); + + default: + return ''; + } + } + + + function process_wdisplay_set( sub, vars, consts, debug ) + { + var ret = [], + i = sub.length; + + while ( i-- ) + { + if ( sub[ i ] === undefined ) + { + continue; + } + + ret[ i ] = process_wdisplay( sub[ i ], vars, consts, debug ); + } + + return ret; + } + + + + module.exports.rater = rater; + + + diff --git a/src/current/summary.css b/src/current/summary.css new file mode 100644 index 00000000..cc878f2b --- /dev/null +++ b/src/current/summary.css @@ -0,0 +1,835 @@ +/** + * Rater XML summary stylesheet + */ + +body { + /* menu width * menu em + 1 */ + margin: 0em 0em 0em 13em; +} + +.menu +{ + position: fixed; + overflow: scroll; + + background-color: #ad7fa8; + border-right: 1px solid black; + + top: 0px; + left: 0px; + bottom: 0px; + width: 15em; + + padding: 0.25em; + + font-size: 0.8em; + + resize: horizontal; + z-index: 10; +} + +.menu h1 +{ + font-size: 1.4em; + margin-bottom: 0.15em; + border-bottom: 1px solid #75507b; +} +.menu h1:not(:first-child) +{ + margin-top: 2em; +} + +.menu h2 +{ + font-size: 1.2em; + margin-left: 0.5em; + margin-bottom: 0.15em; +} + +.menu ul +{ + margin: 0px; + padding-left: 1.25em; + list-style: none; +} + +fieldset, +.container-param, +.tcontent +{ + display: none; +} +fieldset:target, +.container-param:target, +.tcontent:target +{ + display: block; +} + +fieldset fieldset +{ + display: block; +} + + +#xml-raw:not(.show) +{ + display: none; +} + +table > caption +{ + font-weight: bold; +} + +dt +{ + font-size: 1.1em; + font-weight: bold; + + margin-top: 0.5em; +} + +dt.param.classifies { + color: green; +} +dt.param > .type +{ + font-size: 0.8em; + font-weight: normal; +} + +dl.params > .default +{ + font-size: 0.8em; +} + +table +{ + border: 1px solid #888a87; + margin: 1em 0px 0px 0px; +} +table th +{ + border-bottom: 2px solid #888a87; + padding: 0.5em; +} +table tr > td +{ + padding: 0.5em; +} +table tr:not(:last-child) > td +{ + border-bottom: 1px solid #888a87; +} + +fieldset +{ + border: 0px; + margin: 0px; +} + +.class .requires, +.class .name, +.class .usedby, +.typedef .type, +.typedef .name, +.params .usedby, +.rate .yields, +.rate .param, +.func .param, +.func .usedby +{ + font-size: 0.8em; +} + +.usedby a +{ + text-decoration: none; +} + +.calc-order, +.classifier-calcs +{ + max-height: 20em; + overflow-y: scroll; +} + +#workstatus +{ + position: fixed; + display: none; + + background-color: #eeeeec; + + left: 0px; + top: 0px; + right: auto; + padding: 0.25em; + + font-size: 0.9em; + border-bottom: 1px solid #babdb6; + border-right: 1px solid #babdb6; + + /* entry-form is 2000 */ + z-index: 1999; +} + +#workstatus.show +{ + display: block; +} + +.package +{ + background-color: #eeeeec; + + border: 1px solid #babdb6; + border-radius: 1em; + + padding: 1em; + + margin-bottom: 3em; + + clear: both; +} +.package.devsummary +{ + background-color: #ad7fa8; + border-color: #75507b; +} + +.package > .title +{ + position: relative; + + background-color: #d3d7cf; + + border-bottom: 1px solid #babdb6; + border-radius: 1em 1em 0px 0px; + + margin: -1em -1em 0px -1em; + padding: 1em; +} +.package > .title > h2 +{ + margin: 0; + padding: 0; +} + +.package > h3, +.package > div > h3 +{ + border-width: 0px 0px 2px 0px; + border-style: solid; + border-color: #babdb6; + + margin: 1em -0.9em; + padding: 0.1em 0.5em; +} + +.package.us > .title, +.package.devsummary > .title +{ + background-color: #ad7fa8; +} +.package.devsummary > .title, +.package.devsummary > h3, +.package.devsummary > div > h3 +{ + border-bottom-color: #75507b; +} + +.package h4.rate-group +{ + border-bottom: 1px dashed #babdb6; + margin-top: 3em; + margin-left: -0.5em; +} +.rate-groups .generates +{ + font-size: 0.9em; +} + +.package > .title > .imports +{ + position: absolute; + top: 0px; + right: 0px; + + margin: 1.25em; +} +.package > .title > .imports::before +{ + content: 'Imports: '; + font-weight: bold; +} + +body > fieldset +{ + position: relative; + padding: 5em 0em 0em 0em; +} + +body > fieldset > legend +{ + position: absolute; + background-color: #eeeeec; + + border-top: 1px solid #babdb6; + border-bottom: 1px solid #babdb6; + + padding: 0.5em; + left: -0.5em; + top: 0em; + right: 0px; + + font-size: 1.5em; + letter-spacing: 0.1em; +} + +body > fieldset > legend > a.pkg +{ + float: right; + font-size: 0.5em; + line-height: 2.5em; + + color: inherit; + border: none; + text-decoration: none; +} + +body > fieldset > legend + p.desc +{ + margin-top: 0em; + font-size: 1.1em; +} + +fieldset.rate > legend > a +{ + text-decoration: none; + border-bottom: 1px dotted black; +} + +fieldset.rate .classes +{ + display: inline-block; + + margin: -1em 0em 2em 0em; + padding-bottom: 0.25em; + + font-size: 0.9em; + border-bottom: 1px dotted black; +} + +fieldset.rate .classes > .prefix +{ + font-variant: small-caps; +} + +/* more than just .rate */ +fieldset .calc-yields +{ + font-variant: small-caps; +} + + +ul.let +{ + list-style: none; + margin: 0; + padding: 0; +} + +ul.let li.letequ +{ + margin-top: 1em; +} + +ul.let .letdesc +{ + font-size: 0.9em; + margin-left: 1em; +} + + +.rate .body, +.func .body, +.yield .body +{ + float: left; +} +.rate .right, +.func .right, +.yield .right +{ + float: right; + padding: 0; + margin: 0; + + max-width: 40%; +} +.rate .body +{ + /** give room for accumulators, depends, etc **/ + margin-bottom: 5em; +} +.right h4 +{ + border-bottom: 1px solid black; + + + margin-top: 0; + margin-bottom: 0.5em; +} +.right > div:not(:first-child) +{ + margin-top: 1em; +} +.right > .parts.many +{ + -webkit-columns: 2; + -moz-columns: 2; +} +.right > .parts > .part, +.right > .generators > .generator +{ + text-align: center; + margin-top: 2em; +} +.right > .parts > .part:first-child +{ + margin-top: 0em; +} +.right > .parts.many > .part +{ + /** FF, Webkit and W3C respectively */ + display: table; + -webkit-column-break-inside: avoid; + break-inside: avoid-column; +} +.right > .parts > .part > .label, +.right > .generators > .generator > .desc +{ + font-size: 0.9em; +} +.accum +{ + position: absolute; + bottom: 1em; + + font-size: 0.9em; + + max-width: 60%; +} + +.error +{ + font-weight: bold; + color: red; +} + + +/** entry form **/ +#test-data +{ + position: relative; +} +#test-data:not(:target) +{ + display: none; +} + +form.entry-form +{ +} + +form.entry-form.focus +} + +form.entry-form > dl +} + +form.entry-form.focus > dl +{ +} + +form.entry-form dt +{ + clear: left; +} + +form.entry-form .matrix +{ + display: inline-block; + border: 1px inset; + padding: 0.25em; + + float: left; + clear: left; +} + +form.entry-form .entry-add +{ + float: left; + clear: left; +} + +form.entry-form > .foot +{ +} + +form.entry-form > .foot > .ratemsg +{ + display: inline-block; + + font-weight: bold; + font-size: 1.2em; +} + +form.entry-form .final-accept:not(.show), +form.entry-form .final-premium:not(.show) +{ + display: none; +} + +form.entry-form .final-premium +{ + margin: 0.25em; + + font-size: 3em; + font-weight: bold; + color: green; + + text-shadow: 1px 1px 1px black; +} + + +form.entry-form .final-premium:before +{ + content: '$'; + + min-height: 0em; + + white-space: nowrap; +} + + +form.entry-form input[type="reset"] +{ + /* help protect against accidental clicks */ + margin-left: 1em; +} + +form .final-comments +{ + background-color: rgba( 255, 255, 255, 0.90 ); + + display: none; + + text-align: left; + + padding: 1em; +} +form .final-comments.show +{ + position: fixed; + display: block; + + border: 0.25em solid black; + + top: 0.25em; + right: 0.25em; + bottom: 0.25em; + left: 12.7em; +} + +form .final-comments textarea +{ + width: 95%; + height: 20em; +} + +form .final-comments button +{ + padding: 0.5em 1em; + margin-right: 1em; +} + +form .final-comments #final-submit +{ + font-weight: bold; +} + + +/** load dialog **/ +#prior:not(:target) +{ + display: none; +} + +.load-dialog td +{ + cursor: pointer; +} + +.load-dialog > button +{ + margin-top: 0.5em; + padding: 0.5em 1em; + font-size: 1.1em; +} + +.load-dialog tr > td:first-child, +.load-dialog tr > td.premium +{ + white-space: nowrap; +} + +.load-dialog tr > td.premium, +.load-dialog tr > td.expected +{ + text-align: right; +} + +.load-dialog tr.good +{ + background-color: #c0ffc0; +} +.load-dialog tr.bad +{ + background-color: #ffc0c0; +} +.load-dialog tr.good.waiting +{ + background-color: #edd400; +} +.load-dialog tr.bad.waiting +{ + background-color: #f57900; +} +.load-dialog tr.changed:not(.skipped) +{ + font-weight: bold; + font-style: normal !important; +} +.load-dialog tr.premchanged +{ + font-style: italic; +} +.load-dialog tr.skipped +{ + background-color: gray; +} + + +.load-dialog.show +{ + display: block; +} + + + +.entry-value, +.entry-value-prior +{ + background-color: yellow; + + padding: 0.1em; + margin-left: 1em; + + font-weight: bold; + color: green; +} +.entry-value-prior +{ + background-color: purple; + + font-weight: normal; + font-size: 0.9em; + color: white; +} +body:not(.prior) .entry-value-prior +{ + display: none; +} + + +/** validation errors **/ +.validation-errors +{ + position: fixed; + background-color: #FFAFAF; + + border: 0.5em solid rgba( 255, 0, 0, 0.75 ); + border-bottom: none; + + bottom: -30.5em; + left: 0px; + right: 0px; + + padding: 0px 0px 0px 0.5em; + + z-index: 9000; +} + +.validation-errors:hover +{ + background-color: white; + + bottom: 0px; +} + +.validation-errors ol +{ + height: 30em; + + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; + + overflow-y: scroll; +} + +.validation-errors li > .content +{ + font-weight: normal; +} + +.nb +{ + border-top: 1px solid #babdb6; + padding-top: 1em; +} + + + +.ultra-breakdown +{ + display: block; + + font-size: 0.9em; + clear: both; +} + +.ultra-breakdown > h2 +{ + margin-top: 3em; +} + +.ultra-breakdown + .yields +{ + margin-top: 2em; +} + +.ultra-breakdown legend > .uid +{ + font-size: 0.8em; +} + +.ultra-breakdown fieldset +{ + margin-top: 1em; + + border: 1px solid #babdb6; + border-radius: 0.5em; +} + +.ultra-breakdown fieldset:hover +{ + border-color: black; +} + + +.test-summary +{ + float: right; +} +.test-summary table +{ + float: right; + clear: both; +} + +#voi-container, +#class-overview +{ + display: none; + margin: 0em 0.5em 2em 0em; +} +#class-overview td.prior +{ + font-size: 0.9em; + color: purple; +} +body:not(.prior) #class-overview td.prior +{ + display: none; +} + +#voi-container.show, +#class-overview.show +{ + display: inline; +} + +#voi-container td.prior +{ + font-size: 0.9em; + color: purple; +} +body:not(.prior) #voi-container td.prior +{ + display: none; +} + +.sel0 +{ + background-color: #ccccff; +} +.sel1 +{ + background-color: #ccffcc; +} +.sel2 +{ + background-color: #ffcccc; +} + +#voi-painter +{ + position: fixed; + display: block; + + background-color: white; + border: 3px solid #eeeeec; + border-radius: 0.25em; + + top: -3px; + left: 30em; + + font-weight: bold; + font-size: 1.3em; + + padding: 0.25em; +} + +#prior-message +{ + background-color: #c0ffc0; + display: none; + + border: 0.25em solid #4e9a06; + width: 50%; + + font-family: monospace; + + padding: 0.5em; +} + +#prior-message.bad +{ + background-color: #ffc0c0; + border-color: #c00000; +} diff --git a/src/current/summary.xsl b/src/current/summary.xsl new file mode 100644 index 00000000..a59510cb --- /dev/null +++ b/src/current/summary.xsl @@ -0,0 +1,2107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [summary] processing + + + + ... (please be patient) + + + + + + + + + + + + + + + + + + + + + + + <!DOCTYPE html> + + + + + + + + + + + + + + rater/ + + + + + + + <xsl:value-of select="$title" /> + + + + + + [summary] typsetting self... + + + + + + + + + [summary] typesetting package + + ... + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    Values of Interest
    NameValue
    + + + + + + +
    Classification Overview
    +
    + + + + +
    + + + + + + + + +
    + + + + + + + [summary] building package list... + + + + + + + + + + + + + + + + + + + +

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Rate Blocks

    +
      + + + + + + + + !!! failed to locate + + source document + + + + + +
    • + +
    • +
      + + + + + + +
    • + + + +
    • +
      +
      +
    +
    +
    + + + + + + + + + + + + +
  • + + + + ( + + ) + + + : + + + +
  • +
    + + +
  • + Preprocessor error + + + ( + + ) + + + : + + + +
  • +
    + + + + + + + + [summary] [] + + + + pkg- + + + +

    + +

    + + +
    + + + + + + + + + + + + + [summary] + + for + + + + + + + + + + + + + + + + + / + + + + + + + + + param + + + + classifies + + + + + + processing + + + + + + + + +
    + + + + + + + + + + + + + \( + + \) + + + + + + + + + + + + + + \(\in + + + + \) + + + ( + + + # + + + + + + + + + + + + ) + + + + + + + +

    + +

    + + + +
    + Default: + + + + { + + + + + + + + + + \(\epsilon\) + + + + + } + +
    +
    + + + + + + +
    + Value: +
    +
    + + + + + Too many values; not typesetting. + + + + + +
    + Values: + \(\left[\begin{array}\\ + + + + \\ + + + + + + \end{array}\right]\) +
    +
    + + +
    + Values: + \( \left[ \begin{array}\\ + + + \\ + + + + + & + + + + + + \end{array} \right] \) +
    +
    +
    +
    + + + +

    Defined by type + + + +

    +
    +
    +
    + + + + + + + + + + + + + + + + processing rate group " + + " + + + + + + + + + + + + + + + + + + + + + + + (final premium) + + + + + + + + + + + + + processing typedefs + + + + +
    + + + + + + + + + + ( + + ) + + + + + + + +
    + Type: + + + + + + + + + ( + + ) + +
    + + +
    + + + +
    + + + + +
    + + + + + + + + + + ( + + ) + + + + + + +

    Union of:

    + + +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + +
    NameValueDescription
    + + + +
    +
    + + + + +

    Base type declaration (defined internally)

    +
    + + + + + + + + + + + + + + + + + processing classifications + + + + +
    + + + :class: + + + + + + + ( + + ) + + + + + + +
    +
    + +
    +
    + + +
    + + + + + Yields: + +
    +
    +
    +
    + + + + + +

    + + + + or + + + + and + + + +

    + + +
    + + + + + + + + + + + + + + + + + + warning: failed to locate generated class ref ` + + ' + + + +
    + +
    +
    + + + + + + + +

    + + ubd- + + + + + + # + + + + + + + + + + + + + + + + + + + ( + + ) + + + must + + + + + , assuming that: + +

    + +

    +
    + + + + is ignored during classification + + + + + has the value + + + + + + + + + + + + match any value in + + + + + + + \( + + \) ( + + + + + # + + + + + + + + ) + + + + + + + [Undefined type: + + ] + + + + + + + + match the pattern: + + + + + + + + + = + + + + + + + + + be + + \( + + \) + + + + + + + + + + + + processing functions + + + + + + +
    + + + + + + + \( + + + + + \; + + + + \textrm{ + + } + + + + \) + + + + ( + + ) + + + + + + +
    +

    + + + + +
    + Yields: + \( + + + + + + + + \) +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + + + + + +
    + + + + + + + + + + + \( + + \) + + + + + + + + + + + +
    + +
    + Applicability: + + + Always applicable. + + + + + + + + + + + , + + + + + + + but not + + + + nor + + + + + + + + [summary] fatal: empty lv:class/@ref! + + + + + + + + + + + + +
    + + + + + + + +
    + Yields: + \( + + + + + + + + \) +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + { + + + + + + + + [summary] internal: missing TeX symbol for ` + + ' within the context of ` + + ' + + + ~~~~[begin symbol dump]~~~~ + + ~~~~[end symbol dump]~~~~ + + ?^! + + + + + + + ( + + ) + + + + + + + + + } + + + + + + + + + + + + + + + + + + + + + + +
    +

    Calculation Breakdown

    + +
    +
    + + + + + + + + + + + + + + + +
    + Scope boundary (let) + + Each of the "let" statements below are only present + within this scope boundary and exist to simplify the equation. + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + let \( + + \) = + + + + + + + + + +
    + + + ubd- + + + + + + + + + + ( + + ) + + + + +
    +
    + + + + + + + + \( + + + + + \) + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Context-Specific Constants

    +
      + +
    • + + = + +
    • +
      +
    +
    +
    + + + + +

    Summary Breakdown

    +
    + + parts + + + + many + + + + + + + + +
    + + \( + + + + + \) + + + + + + +
    + +
    +
    +
    +
    +
    + + + + + +
    +

    Generators

    + + +
    + + \( + \theta_{ + + } + + + = + + \) + + + + + + +
    + + ( + + ) +
    +
    +
    +
    +
    +
    + + + + +
    +
    + + + +
    + \( + + \) + + + +
    + +
    + +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + + #:class: + + + + + + + + + + + [Undefined classification: + + ] + + + + + + + + +
    +

    N.B.

    +
    +
    Iverson's Convention
    +
    +

    + As is customary for many mathematical notations in CS, this system uses + Iverson's convention (Iverson's brackets) to denote certain conditional + expressions. It should be understood that the notation will produce a + value of \( 1 \) if the expression is true; otherwise, it will be + strongly \( 0 \) --- that is, even if the expression would + be undefined, it will still yield \( 0 \). +

    +

    + \( [ 1 \gt 0 ] = 1 \); \( [ 0 = 1 ] = 0 \); \( [ 5 \textrm{ is prime} ] = 1 \); +

    +

    + \( \sum \limits_{1 \leq k \leq 5} k = \sum \limits_k k [ 1 \leq k \leq 5 ] \) +

    +
    + +
    Sets
    +
    +

    + In the equations represented above, it is to be assumed that undefined + values in a set are implicitly 0; this simplifies the representations of + the various summations; they are not intended to be vigorous. +

    +

    + For example: let \( x \) = \( \{ 1, 2, 3 \} \). Given the equation \( + \sum_k x_k \), it is assumed that the solution is \( 1 + 2 + 3 = 6 \), + not undefined. Formally, the former sum is to be interpreted as: \( + \sum_{k=0}^n x_k \) where \( n \) is the length of set \( x \), or \( + \sum_k x_k [x_k \textrm{ is defined}] \) using Iverson's convention (the + latter of which our first notation is based upon by simply omitting the + brackets and implying their existence). +

    +
    + +
    Counting Sets
    +
    + Let \(N(S)\) = the number of values within the set \(S\); this notation is + used within certain summations. You may also see the following notations: + +
      +
    • + \(\sum_{k} S_k\) to count the number of one-values in boolean set + \(S\) (e.g. if \(S\) denotes properties with swimming pools, we can + count the number of swimming pools). +
    • +
    • + \(\sum_{k=0}^{N(S)} 1\) to count the number of values in set \(S\). +
    • +
    +
    + +
    Vector Arithmetic
    +
    + Only one type of vector arithmetic (dot products) is currently supported, + but others may be done manually using sums and products. Dot products are + denoted by \(a\cdot b\), where \(a\) and \(b\) are vectors. +
    + +
    Subscript Precedence
    +
    + Subscripts should be applied from right to left. That is: + \(S_{x_{y_z}}\) = \(S_{(x_{(y_z)})}\). In the event where a notation may + be ambiguous (e.g. \(\theta_{1_x}\), since \(1_x\) could not possibly make + sense in the context of this system), parenthesis will always be added to + clarify intent. +
    +
    +
    +
    + + + + + + + + + + [' + + ', + 0 + + + + + ,' + + ' + + + ], + + + + [' + + ', + 0 + + ], + + + + + + + + + + + + + + + +

    + Calculation Order ( + + ) +

    + +
      + +
    1. + + + +
    2. +
      +
    +
    + + + + + + + + + + + + +
    diff --git a/src/current/tools/csv2xml b/src/current/tools/csv2xml new file mode 100755 index 00000000..3a5d1b83 --- /dev/null +++ b/src/current/tools/csv2xml @@ -0,0 +1,110 @@ +#!/usr/bin/awk -f +# +# Compiles the given CSV into a table definition + + +function columngen( header ) +{ + # output a field constant for each field in the header + i = 0 + while ( field = header[ ++i ] ) + { + printf " \n", + field, + ( i - 1 ), + ( seq[ i ] ) ? "true" : "false" + } +} + + +function seqchk( last ) +{ + # if there's no last row, then do not bother + i = 0 + while ( i++ < NF ) + { + if ( seq[ i ] == "" ) seq[ i ] = 1 + + # this field is sequential if it is greater than or equal to the last field + # (we don't check for descending [yet]); note that on the first check, last + # will be empty and therefore this check will succeed (properly + # initializing seq[i] to 1) + seq[ i ] = seq[ i ] && ( $(i) >= last[ i ] ) + } +} + + +# header +BEGIN { + rootpath = "../../../" + file = ARGV[1] + + # grab only the filename (remove all preceding directories and the file ext) + name = gensub( /^.*\/|\.[^.]+$/, "", "g", file ) + + + # output package header + printf \ + "\n" \ + "\n\n" \ + " \n\n" \ + " \n" \ + " \n\n", \ + rootpath, name + + # the first row of the CSV is the header representing the column identifiers + getline + split( $0, header, /,/ ) + + # table constant identifier + tconst = toupper( gensub( /-/, "_", "g", name ) ) "_RATE_TABLE" + + # generate the header for the table constant + printf " \n", name + + printf "%s", " 1 ) ? "," : "" ) $(i) + } + + print ";" + + seqchk( last ) + split( $0, last ) +} + + +# footer +END { + # end of table-rows node + print "\" />" + + # columns can't be generated until after we know which ones represent + # sequential data + columngen( header ) + + print " " + print "" +} diff --git a/src/current/tools/csvi b/src/current/tools/csvi new file mode 100755 index 00000000..08d80e2a --- /dev/null +++ b/src/current/tools/csvi @@ -0,0 +1,124 @@ +#!/usr/bin/awk -f +# +# Performs interpolation for columns in a CSV and outputs the result +# +# Configurable values (use -vname=value from command line): +# step - use predeterminated step instead of calculating from first two rows +# +# # + +function storeline() +{ + for ( i = 1; i <= hlen; i++ ) { + prev[i] = $i + } +} + +function clearline() +{ + for ( i = 1; i <= hlen; i++ ) { + prev[i] = 0 + } +} + +function getprev() +{ + for ( i = 1; i <= hlen; i++ ) { + $i = prev[i] + } +} + + +function interpolate() +{ + lastval = prev[1] + + curval = $1 + diff = curval - lastval + + # does this value fall in line with the requested step? + if ( diff == step ) + { + storeline() + + # we're good; continue + print + next + } + + # if we do not yet have a value large enough to reach our step, then continue + # until we do (do not store this line) + n = int( diff / step ) + if ( n <= 0 ) { + next + } + + # determine interpolation values + for ( i = 2; i <= hlen; i++ ) { + ival[i] = ( ( $i - prev[i] ) / n ) + } + + getprev() + + # let us interpolate values that are divisible by the step + do + { + # increase the last value by our step + $1 += step + + # interpolate each column value (notice that we skip the first column, which + # was handled directly above) + for ( i = 2; i <= hlen; i++ ) { + $i += ival[i] + } + + # print the new line + print + } while ( ( diff -= step ) > 0 ) + + # anything remaining does not fit into our step and will be ignored; we'll + # continue with our next step at the next line + + # consider this to be our last line + storeline() +} + + +BEGIN { + # the first row of the CSV is the header representing the column identifiers + getline + hlen = split( $0, header, /,/ ) + + # output the header + print $0 + + # delimit fields by commas (the field separator for CSVs); note that this + # won't work properly if strings contain commas + FS = OFS = "," + + clearline() + getline + + # if no step was provided, then calculate one based on the first two rows + if ( step == 0 ) { + # output the first row, which does not need to be interpolated + print + + # compute the step + vala = $1 + getline + valb = $1 + step = valb - vala + + # since the second line is used to determine the step, then it must match the + # step and therefore is good to output + print + + # begin. + storeline() + } +} + + +# for each row +{ interpolate() } diff --git a/src/current/tools/csvm2csv b/src/current/tools/csvm2csv new file mode 100755 index 00000000..410d9fac --- /dev/null +++ b/src/current/tools/csvm2csv @@ -0,0 +1,112 @@ +#!/usr/bin/awk -f +# +# Compiles a "magic" CSV file into a normal CSV +# +# "Magic" CSVs simply exist to make life easier: they permit comments, blank +# lines, variables, sub-delimiter expansion, and any number of ranges per line. +# Ranges will be expanded in every combination, making rate tables highly +# maintainable. +# +# Variables are also supported when defined using :var=val. Variables may expand +# into ranges, 'cause they're awesome. Multiple variables may be delimited by +# semi-colons, as may multiple values. +# +# For example: +# :foo=1--3 +# $foo;7;9--10:$foo, 5--10 +# +# Would generate: +# 1, 5 +# 1, 6 +# ... +# 5, 10 +# 2, 5 +# ... +# 9, 5 +# ... +# 1, 5 +# 1, 6 +# ... + + +function rangeout( i, m, j, me, orig ) +{ + if ( i > NF ) + { + print + return + } + + orig = $i + + # check first for delimiters + if ( match( $i, /^([^;]+);(.*)$/, m ) ) + { + # give it a shot with the first value + $i = m[1] + rangeout( i ) + + # strip off the first value and process with following value(s) + $i = m[2] + rangeout( i ) + + # we've delegated; we're done + $i = orig + return + } + + # attempt to parse variable (may expand into a range) + if ( match( $i, /^\$([a-zA-Z_-]+)$/, m ) ) + { + $i = vars[ m[1] ]; + } + + # parse range + if ( match( $i, /^([0-9]+)--([0-9]+)$/, m ) ) + { + j = m[1] + me = m[2] + do + { + $i = j + rangeout( i + 1 ) + } while ( j++ < me ) + } + else + { + rangeout( i + 1 ); + } + + # restore to original value + $i = orig +} + + +BEGIN { + # we're parsing CSVs + FS = " *, *" + OFS = "," +} + + +# skip all lines that begin with `#', which denotes a comment, or are empty +/^#|^$/ { next; } + +# lines that begin with a colon are variable definitions +/^:/ { + match( $0, /^:([a-zA-Z_-]+)=(.*?)$/, m ) + vars[ m[1] ] = m[2] + next +} + +# lines containing ranges (denoted by `--', the en dash, which is a typesetting +# convetion for ranges), sub-delimiters, or variables must be expanded +/--|;|\$[a-zA-Z_-]/ { rangeout( 1 ); next; } + +# all other lines are normal; simply output them verbatim +{ + # this assignment will ensure that awk processes the output, ensuring that + # extra spaces between commas are stripped + $1=$1 + print +} diff --git a/src/current/tools/gen-make b/src/current/tools/gen-make new file mode 100755 index 00000000..3f59bfea --- /dev/null +++ b/src/current/tools/gen-make @@ -0,0 +1,96 @@ +#!/bin/bash +# +# Generates Makefile containing dependencies for each package +# # + +# windows machines may not have the tools to resolve a path, so let's do so +# ourselves (TODO: there's better (and more performant) ways of doing this than +# repeated string replacements); TODO: ./ +resolv-path() +{ + # no need to do anything if the string does not contain a parent dir reference + # (we use this convoluted string replacement check for woe32/64 to prevent + # additional spawns (e.g. sed) that would slow us down and because =~ is not + # properly supported in msys + [[ "$1" != "${1/..\//}"a ]] || { + echo "$1" + return + } + + local path= + while read name; do + if [ "$name" == .. ]; then + [ -n "$path" ] || { + echo "warning: will not resolve $1" >&2 + return 5 + } + + path="${path%/*}" + continue + fi + + path="$path/$name" + done <<< "${1//\//$'\n'}" + + # echo path without leading / + echo -n "${path:1}" +} + + +# rule for building +[ -z "$GEN_MAKE" ] && { + echo "%.xmlo:: %.tmp" + echo -e "\t@rm -f \$@ \$<" + [ -n "$xmlo_cmd" ] \ + && echo -e "\t$xmlo_cmd" \ + || echo -e "\ttouch \$@" + + echo "%.xmlo:: %.xml | prexmlo" + [ -n "$xmlo_cmd" ] \ + && echo -e "\t$xmlo_cmd" \ + || echo -e "\ttouch \$@" + + export GEN_MAKE="$( pwd )/$0" + exec "$GEN_MAKE" "$@" +} + +until [ $# -eq 0 ]; do ( + path="${1%%/}" + echo "[gen-make] scanning $path" >&2 + + cd "$( basename $path )/" || exit $? + + deps=$( find -maxdepth 1 -iname '*.dep' ) + for dpath in $deps; do + # equivalent to basename command; use this since spawning processes on + # windoze is slow as shit (originally we did find -exec bashename) + d="${dpath##*/}" + + echo "[gen-make] found $path/$d" >&2 + echo -n "$path/${d%.*}.xmlo:" + + # output deps + while read dep; do + # if the first character is a slash, then it's relative to the project + # root---the resolution has already been done for us! + if [ "${dep:0:1}" == '/' ]; then + echo -n " ${dep:1}.xmlo" + continue + fi + + echo -n ' ' + resolv-path "$path/$dep.xmlo" + done < "$d" + + echo + done + + # recurse on every subdirectory + for p in */; do + [ "$p" == ./ -o "$p" == ../ ] && continue + [ ! -d "$p" ] || "$GEN_MAKE" "$path/$p" || { + echo "fatal: failed to recurse on $( pwd )/$path/$p" >&2 + exit 1 + } + done +); shift; done diff --git a/src/current/tools/lib/zipre.php b/src/current/tools/lib/zipre.php new file mode 100644 index 00000000..b4f22e1a --- /dev/null +++ b/src/current/tools/lib/zipre.php @@ -0,0 +1,124 @@ + 3 ) && is_seq( $digits ) ) + { + return sprintf( '[%d-%d]', + $digits[ 0 ], + $digits[ count( $digits ) - 1 ] + ); + } + elseif ( count( $digits ) === 1 ) + { + // if there's only one digit, then that's all we need to return + return $digits[ 0 ]; + } + + return '[' . implode( '', $digits ) . ']'; + }, $re ); +} + +function is_seq( $digits, $last = '' ) +{ + // stop recursing once we're out of digits + if ( count( $digits ) === 0 ) + { + return true; + } + + // grab the current digit and remove it from the list (this has the effect + // of both cons and cdr) + $digit = (int)( array_shift( $digits ) ); + + // consider this a sequence if this digit is one more than the last (or if + // there is no last digit) and if the following digit is sequential + return ( ( $last === '' ) || ( $digit === ( $last + 1) ) ) + && is_seq( $digits, $digit ); +} diff --git a/src/current/tools/tdat2xml b/src/current/tools/tdat2xml new file mode 100755 index 00000000..db4e9b15 --- /dev/null +++ b/src/current/tools/tdat2xml @@ -0,0 +1,274 @@ +#!/usr/bin/env php + +' . "\n"; + } + + return sprintf( + '' . + "\n%s" . + " %s\n" . + "\n\n", + $name, + gen_identifier( $id ), + $desc, + $yields, + $prev_value, + gen_any_block( $queue, $or ) + ); +} + + +function gen_any_block( $queue, $or ) +{ + $any = gen_zip_re( $queue ) . + gen_on_class( $or ); + + return ( $any ) + ? '' . $any . '' + : ''; +} + + +function gen_zip_re( $data ) +{ + if ( count( $data ) === 0 ) + { + return ''; + } + + return sprintf( + '', + gen_re_quick( $data ) + ); +} + +function gen_on_class( $data ) +{ + if ( count( $data ) === 0 ) + { + return ''; + } + + $cur = array_shift( $data ); + + return sprintf( + '%s', + $cur, + gen_on_class( $data ) + ); +} + +function gen_identifier( $id ) +{ + return is_numeric( $id ) + ? $id + : '-' . strtolower( $id ); +} + +function gen_identifier_value( $id ) +{ + // for non-numeric identifiers, return ascii value + // of character to represent our value + return is_numeric( $id ) + ? $id + : ord( $id ); +} + +$file = $argv[ 1 ]; +$fdat = explode( '.', basename( $file ) ); +$name = $fdat[ 0 ]; + +$cur = ''; +$queue = array(); +$or = array(); + +$fh = fopen( $file, 'r' ); + +echo 'name="rates/territories/', $name, '" ', "\n", + 'desc="', ucfirst( $name ), ' territory classifications">' . "\n\n"; + +echo "\n\n"; + +$ids = array(); +$params = array(); +$imports = array(); +$prev_yields = ''; +$prev_yields_all = array(); +$classes = ''; + +$param_type = 'terrType' . ucfirst( $name ); + +while ( true ) +{ + // read the line within the loop so that we do not terminate until after we + // treat eof as an empty line + $line = str_replace( array( "\n", "\r" ), '', fgets( $fh ) ); + + if ( !$cur ) + { + if ( substr( $line, 0, 12 ) === '@import-pkg ' ) + { + $imports[] = substr( $line, 12 ); + continue; + } + + // we expect this line to be a territory descriptor + try + { + list ( $id, $desc ) = parse_tdesc( $line ); + } + catch ( Exception $e ) + { + fwrite( STDERR, 'Invalid territory descriptor: ' . $line ); + exit( 1 ); + } + + $ids[] = $id; + $cur = $id; + } + elseif ( ( $line === '' ) || feof( $fh ) ) + { + // generate param for typedef + $params[ $id ] = $desc; + + // if there's nothing in the queue, then treat this as an 'ROS' (this + // should appear as the *last* territory, or it will not function as + // expected) + if ( count( $queue ) === 0 ) + { + $prev = $prev_yields_all; + } + else + { + $prev = array( $prev_yields ); + } + + // generate the classification + $classes .= gen_classification( $id, $name, $desc, $prev, $queue, $or ); + + // this accomplishes two things: (1) avoids regexes if there's a + // previous match and (2) ensures that we cannot possibly match multiple + // territories + $prev_yields = gen_yields( $id, $name ); + $prev_yields_all[] = $prev_yields; + + $cur = ''; + $queue = array(); + $or = array(); + + if ( feof( $fh ) ) + { + break; + } + } + elseif ( $line[0] === '=' ) + { + // =foo means match on classification @yields "foo" + $or[] = substr( $line, 1 ); + } + else + { + $queue[] = $line; + } +} + +$param_name = 'territory_' . $name; +?> + + + + + + + + + + + + + + + + + $desc ) { ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/tools/zipre b/src/current/tools/zipre new file mode 100755 index 00000000..4e6966f2 --- /dev/null +++ b/src/current/tools/zipre @@ -0,0 +1,23 @@ +#!/usr/bin/env php + + + + + + + + + Root node for rating worksheets + + + + + + + + + + + + + + Package for which worksheet is being generated + + + + + + +