diff options
author | Mike Gerwitz <gerwitzm@lovullo.com> | 2017-04-06 23:28:38 -0400 |
---|---|---|
committer | Mike Gerwitz <gerwitzm@lovullo.com> | 2017-04-06 23:28:38 -0400 |
commit | e06759dcd046b9974c665d94868baeb2e1f638fa (patch) | |
tree | 01eaf4cd811264c63234cd3cc41103595425e9bf /tools | |
parent | 1d3aaf3339f30e43ee764e8dd898b382dc9e3e76 (diff) | |
download | tame-e06759dcd046b9974c665d94868baeb2e1f638fa.tar.gz tame-e06759dcd046b9974c665d94868baeb2e1f638fa.tar.bz2 tame-e06759dcd046b9974c665d94868baeb2e1f638fa.zip |
Add missing format conversion/compilation tools
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/csv2xml | 126 | ||||
-rwxr-xr-x | tools/csvi | 138 | ||||
-rwxr-xr-x | tools/csvm2csv | 128 | ||||
-rwxr-xr-x | tools/gen-make | 111 | ||||
-rw-r--r-- | tools/lib/zipre.php | 142 | ||||
-rwxr-xr-x | tools/tdat2xml | 294 | ||||
-rwxr-xr-x | tools/zipre | 37 |
7 files changed, 976 insertions, 0 deletions
diff --git a/tools/csv2xml b/tools/csv2xml new file mode 100755 index 0000000..60bd745 --- /dev/null +++ b/tools/csv2xml @@ -0,0 +1,126 @@ +#!/usr/bin/awk -f +# +# Compiles the given CSV into a table definition +# +# Copyright (C) 2016 LoVullo Associates, Inc. +# +# 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 Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +## + + +function columngen( header ) +{ + # output a field constant for each field in the header + i = 0 + while ( field = header[ ++i ] ) + { + printf " <t:table-column name=\"%s\" " \ + "index=\"%d\" seq=\"%s\" />\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 \ + "<?xml-stylesheet type=\"text/xsl\" href=\"%1$srater/summary.xsl\"?>\n" \ + "<package\n" \ + " xmlns=\"http://www.lovullo.com/rater\"\n" \ + " xmlns:c=\"http://www.lovullo.com/calc\"\n" \ + " xmlns:t=\"http://www.lovullo.com/rater/apply-template\"\n" \ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" \ + " xsi:schemaLocation=\"http://www.lovullo.com/rater %1$srater/rater.xsd\"\n\n" \ + " name=\"suppliers/rates/tables/%2$s\"\n" \ + " desc=\"%2$s rate table\">\n\n" \ + " <!--\n" \ + " WARNING: This file was generated by csv2xml; do not modify!\n" \ + " -->\n\n" \ + " <import package=\"/rater/core\" />\n" \ + " <import package=\"/rater/core/vector/table\" />\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 " <t:create-table name=\"%s\">\n", name + + printf "%s", " <t:table-rows data=\"\n" + + # delimit fields by commas (the field separator for CSVs); note that this + # won't work properly if strings contain commas + FS = "," +} + + +# each row of the CSV +{ + # generate value string for each field + i = 0 + while ( i++ < NF ) + { + printf "%s", ( ( i > 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 " </t:create-table>" + print "</package>" +} diff --git a/tools/csvi b/tools/csvi new file mode 100755 index 0000000..6b9af78 --- /dev/null +++ b/tools/csvi @@ -0,0 +1,138 @@ +#!/usr/bin/awk -f +# +# Performs interpolation for columns in a CSV and outputs the result +# +# Copyright (C) 2016 LoVullo Associates, Inc. +# +# 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 Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# 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/tools/csvm2csv b/tools/csvm2csv new file mode 100755 index 0000000..3bcbc7b --- /dev/null +++ b/tools/csvm2csv @@ -0,0 +1,128 @@ +#!/usr/bin/awk -f +# +# Compiles a "magic" CSV file into a normal CSV +# +# Copyright (C) 2016 LoVullo Associates, Inc. +# +# 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 Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# "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/tools/gen-make b/tools/gen-make new file mode 100755 index 0000000..48f53ba --- /dev/null +++ b/tools/gen-make @@ -0,0 +1,111 @@ +#!/bin/bash +# +# Generates Makefile containing dependencies for each package +# +# Copyright (C) 2016 LoVullo Associates, Inc. +# +# 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 Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +## + +# 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/tools/lib/zipre.php b/tools/lib/zipre.php new file mode 100644 index 0000000..d019794 --- /dev/null +++ b/tools/lib/zipre.php @@ -0,0 +1,142 @@ +<?php +/** + * Generate regular expressions to match a list of zip codes + * + * Copyright (C) 2016 LoVullo Associates, Inc. + * + * 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 Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +function gen_re_quick( $data ) +{ + $re = ( '^' . gen_re( $data, 0 ) ); + + // attempt to simplify the regex (we're not going to put a lot of effort into + // this) + return re_simplify( $re ); +} + + +function gen_re( $data, $offset ) +{ + // if we've reached the end of the zip length, or if there's no more zips to + // look at, then stop + if ( ( count( $data ) === 0 ) + || ( $offset === 5 ) + ) + { + return ''; + } + + $out = '('; + + // loop through each digit at the current offset + $last = ''; + foreach ( $data as $zip ) + { + if ( !( isset( $zip[ $offset ] ) ) ) + { + continue; + } + + $digit = $zip[ $offset ]; + + // if we've already seen this digit in the current position, then + // continue + if ( $digit === $last ) + { + continue; + } + + // we're going to recurse now, delimiting allowable digits with pipes + // (for 'OR'); we'll recurse on a sublist that matches the zip up to + // (and including) the current digit (to do this, note that we only need + // to check the current digit, since our current list is already a + // sublist of the parent list up to the current point) + $prefix = substr( $zip, 0, $offset + 1 ); + + $out .= ( $last === '' ) ? '' : '|'; + $out .= $digit . gen_re( + filter_data( $data, $digit, $offset ), + ( $offset + 1 ) + ); + + $last = $digit; + } + + return $out . ')'; +} + +function filter_data( $data, $chr, $offset ) +{ + $ret = array(); + + foreach ( $data as $val ) + { + if ( $val[ $offset] === $chr ) + { + $ret[] = $val; + } + } + + return $ret; +} + +function re_simplify( $re ) +{ + // the only simplification we currently do is joining sequential digit ORs + // into a character range (e.g. (1|2|3|4) becomes [1-4]) + return preg_replace_callback( '/\([0-9](\|[0-9])*\)/', function( $results ) + { + $match = $results[ 0 ]; + $digits = explode( '|', str_replace( array( '(', ')' ), '', $match ) ); + + // are the digits sequential (we will only perform this optimization if + // there's more than 3 digits, since otherwise the replacement would + // result in a string of equal or greater length)? + if ( ( count( $digits ) > 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/tools/tdat2xml b/tools/tdat2xml new file mode 100755 index 0000000..e08ca7c --- /dev/null +++ b/tools/tdat2xml @@ -0,0 +1,294 @@ +#!/usr/bin/env php +<?php +/** + * Generate territory matrices from data files + * + * Copyright (C) 2016 LoVullo Associates, Inc. + * + * 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 Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +?> +<?xml-stylesheet type="text/xsl" href="../../rater/summary.xsl"?> +<lv:package + xmlns:lv="http://www.lovullo.com/rater" + xmlns:c="http://www.lovullo.com/calc" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.lovullo.com/rater ../../rater/rater.xsd" + +<?php + +include 'lib/zipre.php'; + +function parse_tdesc( $line ) +{ + if ( !( preg_match( '/^([0-9A-Z]+) (.+)$/', $line, $match ) ) ) + { + throw new Exception( 'Invalid territory descriptor' ); + } + + return array( $match[ 1 ], $match[ 2 ] ); +} + +function gen_yields( $id, $name ) +{ + return sprintf( 'is%sTerr%s', ucfirst( $name ), $id ); +} + +function gen_classification( $id, $name, $desc, $prev_yields, $queue, $or ) +{ + $yields = gen_yields( $id, $name ); + + $prev_value = ''; + foreach ( $prev_yields as $prev ) + { + if ( !$prev ) + { + continue; + } + + $prev_value .= ' <lv:match on="' . $prev . '" value="FALSE" />' . "\n"; + } + + return sprintf( + '<lv:classify as="%s-terr%s" desc="%s" yields="%s">' . + "\n%s" . + " %s\n" . + "\n</lv:classify>\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 ) + ? '<lv:any>' . $any . '</lv:any>' + : ''; +} + + +function gen_zip_re( $data ) +{ + if ( count( $data ) === 0 ) + { + return ''; + } + + return sprintf( + '<lv:match on="zip" pattern="%s" />', + gen_re_quick( $data ) + ); +} + +function gen_on_class( $data ) +{ + if ( count( $data ) === 0 ) + { + return ''; + } + + $cur = array_shift( $data ); + + return sprintf( + '<lv:match on="%s" value="TRUE" />%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", + " WARNING: This file was generated by {$argv[0]}; do not modify!\n", + "-->\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; +?> + +<?php /* XXX: This is hard-coded! */ ?> +<lv:import package="/rater/core/tdat" /> + +<?php foreach ( $imports as $pkg ) { ?> + <lv:import package="<?php echo $pkg; ?>" /> +<?php } ?> + +<lv:extern name="zip" type="param" dtype="integer" dim="1" + missing="this territory package requires an available `zip' parameter; please + import a package that provides it" /> + +<lv:param name="<?php echo $param_name; ?>" type="<?php echo $param_type; ?>" default="0" set="vector" desc="Territory Override" /> + +<lv:typedef name="<?php echo $param_type; ?>" desc="<?php echo ucfirst( $name ); ?> Territories"> + <lv:enum type="integer"> + <?php $item_prefix = 'TERR_' . strtoupper( $name ) . '_'; ?> + <lv:item name="<?php echo $item_prefix; ?>_NONE" value="0" desc="No Override" /> + <?php foreach ( $params as $id => $desc ) { ?> + <?php $item_name = $item_prefix . $id; ?> + <lv:item name="<?php echo $item_name; ?>" value="<?php echo gen_identifier_value( $id ); ?>" desc="<?php echo $desc; ?>" /> + <?php } ?> + </lv:enum> +</lv:typedef> + +<?php echo $classes; ?> + +<lv:section title="Territory Determination"> + <?php foreach ( $ids as $id ) { ?> + <?php $yields = sprintf( '%sTerr%s', $name, $id ); ?> + <?php $class = sprintf( '%s-terr%s', $name, gen_identifier( $id ) ); ?> + <lv:apply-template name="_terr-code_" class="<?php echo $class; ?>" code="<?php echo gen_identifier_value( $id ); ?>" generates="<?php echo $yields; ?>" /> + <?php } ?> + + <lv:rate yields="_<?php echo $name; ?>TerrCode"> + <c:sum of="zip" index="k" generates="<?php echo $name; ?>TerrCode" desc="Territory code"> + <c:cases> + <c:case> + <c:when name="<?php echo $param_name; ?>" index="k"> + <c:gt> + <c:const value="0" type="integer" desc="Use territory override if set" /> + </c:gt> + </c:when> + + <c:value-of name="<?php echo $param_name; ?>" index="k" /> + </c:case> + + <c:otherwise> + <c:sum label="Determine applicable territory code"> + <?php foreach ( $ids as $id ) { ?> + <c:value-of name="<?php echo $name; ?>Terr<?php echo $id; ?>" index="k" /> + <?php } ?> + </c:sum> + </c:otherwise> + </c:cases> + </c:sum> + </lv:rate> +</lv:section> +</lv:package> diff --git a/tools/zipre b/tools/zipre new file mode 100755 index 0000000..e16a5e9 --- /dev/null +++ b/tools/zipre @@ -0,0 +1,37 @@ +#!/usr/bin/env php +<?php +/** + * Given a set of sorted zips, generates a regular expression to match only the + * given input + * + * Copyright (C) 2016 LoVullo Associates, Inc. + * + * 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 Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * I wanted to write this in Scheme (it's a perfect recursive application), but + * I figured that other developers may get annoyed having to find a Scheme impl + * that works for them...so...PHP it is... + * + * THIS SCRIPT EXPECTS THE DATA TO BE SORTED! This can be easily accomplished by + * doing the following: + * sort -d zipfile | ./zipre + */ + +include 'lib/zipre.php'; + +// grab input from stdin (must be sorted!) +$data = explode( "\n", file_get_contents( 'php://stdin' ) ); + +// build and output +echo gen_re_quick( $data ); |