Index: branches/pap/magic/Makefile.in
===================================================================
--- branches/pap/magic/Makefile.in	(revision 25027)
+++ branches/pap/magic/Makefile.in	(revision 25027)
@@ -0,0 +1,47 @@
+
+default: all
+
+all: ssa-core-cpp magic remove
+
+install: magic.install remove.install
+
+clean:
+	if [ -d magic ]; then (cd magic && make -f Makefile.magic clean); fi
+	if [ -d ssa-core-cpp ]; then (cd ssa-core-cpp && make clean); fi
+	cd $(REMOVE) && make -f Makefile.simple clean
+
+update:
+	# get the source code (replace this with SVN interactions)
+	tar xvzf ~/magic.tgz
+	tar xvzf ~/ssa-core-cpp.tgz
+	cp Makefile.magic magic/Makefile.magic
+
+ssa-core-cpp: ssa-core-cpp/build/libSSA.a
+
+ssa-core-cpp/build/libSSA.a:
+	if [ -d ssa-core-cpp ]; then (cd ssa-core-cpp && ./configure && make); fi
+
+magic: magic/DetectStreaks
+
+magic/DetectStreaks:
+	if [ -d magic ]; then (cd magic && make -f Makefile.magic); fi
+
+magic.install:	ssa-core-cpp
+	if [ -d magic ]; then (cd magic && make -f Makefile.magic install); fi
+
+REMOVE = remove/src
+
+REMOVE_PROGRAMS = \
+$(REMOVE)/isdestreaked \
+$(REMOVE)/streakscompare \
+$(REMOVE)/streaksrelease \
+$(REMOVE)/streaksremove \
+$(REMOVE)/streaksreplace 
+
+remove: $(REMOVE_PROGRAMS)
+
+ $(REMOVE_PROGRAMS):
+	@cd $(REMOVE) && make -f Makefile.simple all
+
+remove.install: remove
+	@cd $(REMOVE) && make -f Makefile.simple install
Index: branches/pap/magic/Makefile.magic
===================================================================
--- branches/pap/magic/Makefile.magic	(revision 25027)
+++ branches/pap/magic/Makefile.magic	(revision 25027)
@@ -0,0 +1,38 @@
+TARGETS =  DetectStreaks
+
+CXX = c++
+CXXFLAGS = -W -Wall -O3 -DNDEBUG
+# CXXFLAGS = -W -Wall -g
+
+SSA_SRC_DIR = ../ssa-core-cpp/src
+INCLUDEDIRS = -I. -I$(SSA_SRC_DIR)
+OTHER_SRCS = $(SSA_SRC_DIR)/math/Constants.cpp
+
+# CFITSIO_DIR = ../cfitsio
+CFITSIO_DIR = $(PSCONFDIR)/$(PSCONFIG)
+
+CFITSIO_INC =  -I$(CFITSIO_DIR)
+CFITSIO_LIB = -L$(CFITSIO_DIR) -lcfitsio
+
+all : $(TARGETS)
+
+RemoveStreaks : $(OTHER_SRCS)
+
+DetectStats : $(OTHER_SRCS)
+
+% :: %.cpp
+	$(CXX) $(CXXFLAGS) $(INCLUDEDIRS) $(CFITSIO_INC) $< $(OTHER_SRCS) $(CFITSIO_LIB) -o $@
+
+.PHONY : clean
+
+.SILENT : clean
+
+clean :
+	   - rm $(TARGETS)
+
+DESTDIR=$(PSCONFDIR)/$(PSCONFIG)
+
+install:        $(TARGETS)
+	cp DetectStreaks $(DESTDIR)/bin
+	chmod 755  $(DESTDIR)/bin/DetectStreaks
+
Index: branches/pap/magic/README
===================================================================
--- branches/pap/magic/README	(revision 23948)
+++ branches/pap/magic/README	(revision 25027)
@@ -1,8 +1,9 @@
-To build The remove streaks portions of magic
+To build the DetectStreaks portion of magic
 
-tar zxf ~sydney/magic.tgz
-tar xzf ~sydney/ssa-core-cpp.tgz
+tar xf ~sydney/magic.tgz
+tar xf ~sydney/ssa-core-cpp.tgz
 
 cd ssa-core-cpp
+make distclean
 ./configure
 make
@@ -11,4 +12,6 @@
 make install
 
+# to build streaksremove and related tools
+
 cd ../remove/src
 make install
Index: branches/pap/magic/autogen.sh
===================================================================
--- branches/pap/magic/autogen.sh	(revision 25027)
+++ branches/pap/magic/autogen.sh	(revision 25027)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+for arg in $*; do
+    case $arg in
+        --no-configure)
+	    exit 0
+            ;;
+        *)
+            ;;
+    esac
+done
+
+./configure.tcsh $*
Index: branches/pap/magic/censorObjects/Doxyfile.in
===================================================================
--- branches/pap/magic/censorObjects/Doxyfile.in	(revision 25027)
+++ branches/pap/magic/censorObjects/Doxyfile.in	(revision 25027)
@@ -0,0 +1,1310 @@
+# Doxyfile 1.5.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file that 
+# follow. The default is UTF-8 which is also the encoding used for all text before 
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into 
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of 
+# possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = censor
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = ipp-2.7.dev
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = ./docs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, 
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, 
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, 
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to 
+# include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct (or union) is 
+# documented as struct with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code where the coding convention is that all structs are 
+# typedef'ed and only the typedef is referenced never the struct's name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be extracted 
+# and appear in the documentation as a namespace called 'anonymous_namespace{file}', 
+# where file will be replaced with the base name of the file that contains the anonymous 
+# namespace. By default anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from the 
+# version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text "
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = ./src
+
+# This tag can be used to specify the character encoding of the source files that 
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default 
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. 
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the output. 
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, 
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH 
+# then you must also enable this option. If you don't then doxygen will produce 
+# a warning and turn it on anyway
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.  Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to 
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to 
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to 
+# be found in the default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will 
+# generate a caller dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable caller graphs for selected 
+# functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the number 
+# of direct children of the root node in a graph is already larger than 
+# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, which results in a white background. 
+# Warning: Depending on the platform used, enabling this option may lead to 
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to 
+# read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
Index: branches/pap/magic/censorObjects/Makefile.am
===================================================================
--- branches/pap/magic/censorObjects/Makefile.am	(revision 25027)
+++ branches/pap/magic/censorObjects/Makefile.am	(revision 25027)
@@ -0,0 +1,4 @@
+SUBDIRS = src
+
+CLEANFILES = *.pyc *~ core core.*
+
Index: branches/pap/magic/censorObjects/autogen.sh
===================================================================
--- branches/pap/magic/censorObjects/autogen.sh	(revision 25027)
+++ branches/pap/magic/censorObjects/autogen.sh	(revision 25027)
@@ -0,0 +1,103 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+PROJECT=censor
+TEST_TYPE=-f
+# change this to be a unique filename in the top level dir
+FILE=autogen.sh
+
+DIE=0
+
+LIBTOOLIZE=libtoolize
+ACLOCAL="aclocal $ACLOCAL_FLAGS"
+AUTOHEADER=autoheader
+AUTOMAKE=automake
+AUTOCONF=autoconf
+
+($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $LIBTOOLIZE installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/libtool/"
+        DIE=1
+}
+
+($ACLOCAL --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $ACLOCAL installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/automake/"
+        DIE=1
+}
+
+($AUTOHEADER --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $AUTOHEADER installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/autoconf/"
+        DIE=1
+}
+
+($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $AUTOMAKE installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/automake/"
+        DIE=1
+}
+
+($AUTOCONF --version) < /dev/null > /dev/null 2>&1 || {
+        echo
+        echo "You must have $AUTOCONF installed to compile $PROJECT."
+        echo "Download the appropriate package for your distribution,"
+        echo "or get the source tarball at http://ftp.gnu.org/gnu/autoconf/"
+        DIE=1
+}
+
+if test "$DIE" -eq 1; then
+        exit 1
+fi
+
+test $TEST_TYPE $FILE || {
+        echo "You must run this script in the top-level $PROJECT directory"
+        exit 1
+}
+
+if test -z "$*"; then
+        echo "I am going to run ./configure with no arguments - if you wish "
+        echo "to pass any to it, please specify them on the $0 command line."
+fi
+
+$LIBTOOLIZE --copy --force || echo "$LIBTOOLIZE failed"
+$ACLOCAL || echo "$ACLOCAL failed"
+$AUTOHEADER || echo "$AUTOHEADER failed"
+$AUTOMAKE --add-missing --force-missing --copy || echo "$AUTOMAKE  failed"
+$AUTOCONF || echo "$AUTOCONF failed"
+
+cd $ORIGDIR
+
+run_configure=true
+for arg in $*; do
+    case $arg in
+        --no-configure)
+            run_configure=false
+            ;;
+        *)
+            ;;
+    esac
+done
+
+if $run_configure; then
+    $srcdir/configure --enable-maintainer-mode "$@"
+    echo
+    echo "Now type 'make' to compile $PROJECT."
+else
+    echo
+    echo "Now run 'configure' and 'make' to compile $PROJECT."
+fi
Index: branches/pap/magic/censorObjects/censorObjects.pc.in
===================================================================
--- branches/pap/magic/censorObjects/censorObjects.pc.in	(revision 25027)
+++ branches/pap/magic/censorObjects/censorObjects.pc.in	(revision 25027)
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libcensor
+Description: Pan-STARRS Photometry Library
+Version: @VERSION@
+Requires: pslib psmodules
+Libs: -L${libdir} -lcensor
+Libs.private: @CENSOR_LIBS@
+Cflags: -I${includedir} @CENSOR_CFLAGS@
Index: branches/pap/magic/censorObjects/configure.ac
===================================================================
--- branches/pap/magic/censorObjects/configure.ac	(revision 25027)
+++ branches/pap/magic/censorObjects/configure.ac	(revision 25027)
@@ -0,0 +1,48 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.61)
+
+AC_INIT([censorObjects], [0.9.0], [ipp-support@ifa.hawaii.edu])
+AC_CONFIG_SRCDIR([src])
+
+AM_INIT_AUTOMAKE([1.6 foreign dist-bzip2])
+AM_CONFIG_HEADER([src/config.h])
+AM_MAINTAINER_MODE
+
+IPP_STDCFLAGS
+
+AC_LANG(C)
+AC_GNU_SOURCE
+AC_PROG_CC_C99
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+AC_SYS_LARGEFILE
+
+dnl ------------------------------------------------------------
+
+AC_PATH_PROG([ERRORCODES], [psParseErrorCodes], [missing])
+if test "$ERRORCODES" = "missing" ; then
+  AC_MSG_ERROR([psParseErrorCodes is required])
+fi
+
+dnl ------------- psLib, psModules ---------------
+PKG_CHECK_MODULES([PSLIB],    [pslib >= 1.0.0])
+PKG_CHECK_MODULES([PSMODULE], [psmodules >= 1.0.0])
+
+dnl Set CFLAGS for build
+IPP_STDOPTS
+CFLAGS="${CFLAGS=} -Wall -Werror"
+echo "CENSOR_CFLAGS: $CENSOR_CFLAGS"
+echo "CENSOR_LIBS: $CENSOR_LIBS"
+
+IPP_VERSION
+
+AC_SUBST([CENSOR_CFLAGS])
+AC_SUBST([CENSOR_LIBS])
+
+AC_CONFIG_FILES([
+  Makefile
+  src/Makefile
+  Doxyfile
+])
+
+AC_OUTPUT
Index: branches/pap/magic/censorObjects/src/Makefile.am
===================================================================
--- branches/pap/magic/censorObjects/src/Makefile.am	(revision 25027)
+++ branches/pap/magic/censorObjects/src/Makefile.am	(revision 25027)
@@ -0,0 +1,57 @@
+if HAVE_SVNVERSION
+CENSOR_VERSION=`$(SVNVERSION) ..`
+else
+CENSOR_VERSION="UNKNOWN"
+endif
+
+if HAVE_SVN
+CENSOR_BRANCH=`$(SVN) info .. | $(SED) -n -e '/URL:/ h' -e '/Repository Root:/ { x; H; x; s|Repository Root: \(.*\)\nURL: \1\(.*\)|\2| ; s|^/|| ; s|/[a-zA-Z]*/src.*|| ; p }'`
+CENSOR_SOURCE=`$(SVN) info | $(SED) -n -e 's/Repository UUID: // p'`
+else
+CENSOR_BRANCH="UNKNOWN"
+CENSOR_SOURCE="UNKNOWN"
+endif
+
+# Force recompilation of censorVersion.c, since it gets the version information
+censorVersion.c: censorVersionDefinitions.h
+censorVersionDefinitions.h: censorVersionDefinitions.h.in FORCE
+	-$(RM) censorVersionDefinitions.h
+	$(SED) -e "s|@CENSOR_VERSION@|\"$(CENSOR_VERSION)\"|" -e "s|@CENSOR_BRANCH@|\"$(CENSOR_BRANCH)\"|" -e "s|@CENSOR_SOURCE@|\"$(CENSOR_SOURCE)\"|" censorVersionDefinitions.h.in > censorVersionDefinitions.h
+FORCE: ;
+
+bin_PROGRAMS = censorObjects
+
+censorObjects_CFLAGS = $(CENSOR_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
+censorObjects_LDFLAGS = $(CENSOR_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
+
+censorObjects_SOURCES = \
+	censor.c		    \
+        censorArguments.c	    \
+	censorParseCamera.c   	    \
+	censorLoop.c                \
+	censorReadout.c             \
+	censorErrorCodes.c          \
+	censorVersion.c             \
+	censorCleanup.c
+
+include_HEADERS = \
+	censor.h \
+	censorErrorCodes.h
+
+clean-local:
+	-rm -f TAGS
+
+# Tags for emacs
+tags:
+	etags `find . -name \*.[ch] -print`
+
+### Error codes.
+BUILT_SOURCES = censorErrorCodes.h censorErrorCodes.c censorVersionDefinitions.h
+CLEANFILES = censorErrorCodes.h censorErrorCodes.c
+EXTRA_DIST = censorErrorCodes.dat censorErrorCodes.h.in censorErrorCodes.c.in
+
+censorErrorCodes.h : censorErrorCodes.dat censorErrorCodes.h.in
+	$(ERRORCODES) --data=censorErrorCodes.dat --outdir=. censorErrorCodes.h
+
+censorErrorCodes.c : censorErrorCodes.dat censorErrorCodes.c.in censorErrorCodes.h
+	$(ERRORCODES) --data=censorErrorCodes.dat --outdir=. censorErrorCodes.c
Index: branches/pap/magic/censorObjects/src/censor.c
===================================================================
--- branches/pap/magic/censorObjects/src/censor.c	(revision 25027)
+++ branches/pap/magic/censorObjects/src/censor.c	(revision 25027)
@@ -0,0 +1,57 @@
+/** @file censor.c
+ *
+ *  @brief
+ *
+ *  @ingroup censor
+ *
+ *  @author IfA
+ *  @version $Revision: 1.28 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-07 02:03:34 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# include "censor.h"
+
+static void usage(void) {
+    fprintf(stderr, "USAGE: censor [-file image(s)] [-list imagelist] (output)\n");
+    exit(PS_EXIT_CONFIG_ERROR);
+}
+
+int main (int argc, char **argv)
+{
+    psTimerStart ("complete");
+
+    censorErrorRegister();              // register our error codes/messages
+
+    // model inits are needed in pmSourceIO
+    // models defined in psphot/src/models are not available in censor
+    pmModelClassInit();
+
+    // load configuration information
+    pmConfig *config = censorArguments(argc, argv);
+    if (!config) {
+        usage();
+    }
+
+    censorVersionPrint();
+
+    // load identify the data sources
+    if (!censorParseCamera (config)) {
+        psErrorStackPrint(stderr, "error setting up the camera\n");
+        psFree(config);
+        exit(PS_EXIT_CONFIG_ERROR);
+    }
+
+    // load the raw detection data (using PSPHOT.SOURCES filerule)
+    // select subset of stars for astrometry
+    if (!censorLoop (config)) {
+        psErrorStackPrint(stderr, "error loading input data\n");
+        psFree(config);
+        exit(PS_EXIT_DATA_ERROR);
+    }
+
+    psLogMsg("censor", 3, "complete censor run: %f sec\n", psTimerMark ("complete"));
+
+    censorCleanup(config);
+    exit(PS_EXIT_SUCCESS);
+}
Index: branches/pap/magic/censorObjects/src/censor.h
===================================================================
--- branches/pap/magic/censorObjects/src/censor.h	(revision 25027)
+++ branches/pap/magic/censorObjects/src/censor.h	(revision 25027)
@@ -0,0 +1,46 @@
+/** @file censor.h
+ *
+ *  @brief censorObjects rejects objects from smf files that land on magic masks
+ *
+ *  @ingroup censor
+ *
+ *  @author IfA
+ *  @version $Revision: 1.49 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-09 21:25:34 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# ifndef CENSOR_H
+# define CENSOR_H
+
+# include <stdio.h>
+# include <string.h>
+# include <strings.h>  // for strcasecmp
+# include <unistd.h>   // for unlink
+# include <pslib.h>
+# include <psmodules.h>
+# include <ppStats.h>
+# include "censorErrorCodes.h"
+
+/// @addtogroup censor
+/// @{
+
+# define CENSOR_RECIPE "CENSOR" ///< Name of the recipe to use
+
+pmConfig *censorArguments (int argc, char **argv);
+bool censorParseCamera (pmConfig *config);
+bool censorLoop (pmConfig *config);
+bool censorReadout (pmReadout *readout, pmConfig *config, const pmFPAview *view, bool badMaskFile);
+void censorCleanup (pmConfig *config);
+bool censorBadFileByView (bool badFile, pmFPAfile *file, pmConfig *config, pmFPAview *view);
+
+// Return version strings.
+psString          censorVersion(void);
+psString          censorSource(void);
+psString          censorVersionLong(void);
+bool              censorVersionHeader(psMetadata *header);
+bool              censorVersionHeaderFull(psMetadata *header);
+void              censorVersionPrint(void);
+
+///@}
+# endif /* CENSOR_H */
Index: branches/pap/magic/censorObjects/src/censorArguments.c
===================================================================
--- branches/pap/magic/censorObjects/src/censorArguments.c	(revision 25027)
+++ branches/pap/magic/censorObjects/src/censorArguments.c	(revision 25027)
@@ -0,0 +1,62 @@
+/** @file censorArguments.c
+ *
+ *  @brief
+ *
+ *  @ingroup censor
+ *
+ *  @author IfA
+ *  @version $Revision: 1.34.2.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-19 17:59:50 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# include "censor.h"
+
+pmConfig *censorArguments (int argc, char **argv) {
+
+    bool status;
+    int N;
+
+    if (argc == 1) {
+        psError(CENSOR_ERR_ARGUMENTS, true, "No arguments supplied");
+        psErrorStackPrint(stderr, "exit");
+        return NULL;
+    }
+
+    // load config data from default locations
+    pmConfig *config = pmConfigRead(&argc, argv, CENSOR_RECIPE);
+    if (config == NULL) {
+        psError(CENSOR_ERR_CONFIG, false, "Can't read site configuration");
+        psErrorStackPrint(stderr, "exit");
+        return NULL;
+    }
+
+    // define the input mask
+    status = pmConfigFileSetsMD (config->arguments, &argc, argv, "INPUT.MASK", "-mask", "-masklist");
+
+    // dump the configuration to a file?
+    if ((N = psArgumentGet (argc, argv, "-dumpconfig"))) {
+        psArgumentRemove (N, &argc, argv);
+        psMetadataAddStr (config->arguments, PS_LIST_TAIL, "DUMP_CONFIG", PS_META_REPLACE, "", argv[N]);
+        psArgumentRemove (N, &argc, argv);
+    }
+
+    status = pmConfigFileSetsMD (config->arguments, &argc, argv, "INPUT", "-file", "-list");
+    if (!status) {
+        psError(CENSOR_ERR_ARGUMENTS, true, "Missing -file (input) or -list (input)");
+        psErrorStackPrint(stderr, "exit");
+        return NULL;
+    }
+
+    if (argc != 2) {
+        psError(CENSOR_ERR_ARGUMENTS, true, "Incorrect arguments supplied");
+        psErrorStackPrint(stderr, "exit");
+        return NULL;
+    }
+
+    // output positions is fixed
+    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "", argv[1]);
+
+    psTrace("censor", 1, "Done with censorArguments...\n");
+    return (config);
+}
Index: branches/pap/magic/censorObjects/src/censorCleanup.c
===================================================================
--- branches/pap/magic/censorObjects/src/censorCleanup.c	(revision 25027)
+++ branches/pap/magic/censorObjects/src/censorCleanup.c	(revision 25027)
@@ -0,0 +1,30 @@
+/** @file censorCleanup.c
+ *
+ *  @brief
+ *
+ *  @ingroup censor
+ *
+ *  @author IfA
+ *  @version $Revision: 1.8.2.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-19 17:59:50 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# include "censor.h"
+
+void censorCleanup (pmConfig *config) {
+
+    psFree (config);
+    pmVisualClose ();
+
+    psTimerStop ();
+    psMemCheckCorruption (stderr, true);
+    pmModelClassCleanup ();
+    psTimeFinalize ();
+    pmConceptsDone ();
+    pmConfigDone ();
+    fprintf (stderr, "found %d leaks at %s\n", psMemCheckLeaks (0, NULL, stdout, false), "censor");
+    // fprintf (stderr, "found %d leaks at %s\n", psMemCheckLeaks (0, NULL, NULL, false), "censor");
+
+    return;
+}
Index: branches/pap/magic/censorObjects/src/censorErrorCodes.c.in
===================================================================
--- branches/pap/magic/censorObjects/src/censorErrorCodes.c.in	(revision 25027)
+++ branches/pap/magic/censorObjects/src/censorErrorCodes.c.in	(revision 25027)
@@ -0,0 +1,37 @@
+/** @file censorErrorCodes.c
+ *
+ *  @brief
+ *
+ *  @ingroup censor
+ *
+ *  @author IfA
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-07 02:03:34 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#include "pslib.h"
+#include "censorErrorCodes.h"
+
+/*
+ * The line
+    { CENSOR_ERR_$X{ErrorCode}, "$X{ErrorDescription}"},
+ * (without the Xs)
+ * will be replaced by values from errorCodes.dat
+ */
+void censorErrorRegister(void)
+{
+    static psErrorDescription errors[] = {
+       { CENSOR_ERR_BASE, "First value we use; lower values belong to psLib" },
+       { CENSOR_ERR_${ErrorCode}, "${ErrorDescription}"},
+    };
+    static int nerror = CENSOR_ERR_NERROR - CENSOR_ERR_BASE; // number of values in enum
+
+    for (int i = 0; i < nerror; i++) {
+       psErrorDescription *tmp = psAlloc(sizeof(psErrorDescription));
+       *tmp = errors[i];
+       psErrorRegister(tmp, 1);
+       psFree(tmp);			/* it's on the internal list */
+    }
+    nerror = 0;			                // don't register more than once
+}
Index: branches/pap/magic/censorObjects/src/censorErrorCodes.dat
===================================================================
--- branches/pap/magic/censorObjects/src/censorErrorCodes.dat	(revision 25027)
+++ branches/pap/magic/censorObjects/src/censorErrorCodes.dat	(revision 25027)
@@ -0,0 +1,12 @@
+#
+# This file is used to generate pmErrorClasses.h
+#
+BASE = 4000		First value we use; lower values belong to psLib
+UNKNOWN			Unknown censorObject error code
+NOT_IMPLEMENTED		Desired feature is not yet implemented
+ARGUMENTS		Incorrect arguments
+CONFIG			Problem in configure files
+IO			Problem in FITS I/O
+WCS      		Error interpreting FITS WCS information
+DATA                    Problem in data values
+REFSTARS                Problem in data values
Index: branches/pap/magic/censorObjects/src/censorErrorCodes.h.in
===================================================================
--- branches/pap/magic/censorObjects/src/censorErrorCodes.h.in	(revision 25027)
+++ branches/pap/magic/censorObjects/src/censorErrorCodes.h.in	(revision 25027)
@@ -0,0 +1,30 @@
+/** @file censorErrorCodes.h
+ *
+ *  @brief
+ *
+ *  @ingroup censor
+ *
+ *  @author IfA
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-07 02:03:34 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#if !defined(CENSOR_ERROR_CODES_H)
+#define CENSOR_ERROR_CODES_H
+/*
+ * The line
+ *  CENSOR_ERR_$X{ErrorCode},
+ * (without the X)
+ *
+ * will be replaced by values from errorCodes.dat
+ */
+typedef enum {
+    CENSOR_ERR_BASE = 4000,
+    CENSOR_ERR_${ErrorCode},
+    CENSOR_ERR_NERROR
+} censorErrorCode;
+
+void censorErrorRegister(void);
+
+#endif
Index: branches/pap/magic/censorObjects/src/censorLoop.c
===================================================================
--- branches/pap/magic/censorObjects/src/censorLoop.c	(revision 25027)
+++ branches/pap/magic/censorObjects/src/censorLoop.c	(revision 25027)
@@ -0,0 +1,126 @@
+/** @file censorLoop.c
+ *
+ *  @ingroup censor
+ *
+ *  @author IfA
+ *  @version $Revision: 1.12 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-07 02:03:34 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# include "censor.h"
+
+# define ESCAPE { \
+  psError(PS_ERR_UNKNOWN, false, "Failure in censorLoop"); \
+  psFree (view); \
+  return false; \
+}
+  
+/**
+ * \brief this loop loads the data from the input smf file(s) and mask(s).  call censorReadout
+ * to perform the actual rejection.
+ */
+bool censorLoop (pmConfig *config) {
+
+    pmChip *chip;
+    pmCell *cell;
+    pmReadout *readout;
+
+    psTimerStart ("censor");
+
+    // select the current recipe
+    psMetadata *recipe  = psMetadataLookupPtr (NULL, config->recipes, CENSOR_RECIPE);
+    if (!recipe) {
+	psError(CENSOR_ERR_CONFIG, true, "Can't find CENSOR recipe!\n");
+	return false;
+    }
+
+    // select the input data sources
+    pmFPAfile *input = psMetadataLookupPtr (NULL, config->files, "CENSOR.INPUT");
+    if (!input) {
+	psError(CENSOR_ERR_CONFIG, true, "Can't find input data!\n");
+	return false;
+    }
+
+    // select the input data sources
+    pmFPAfile *inMask = psMetadataLookupPtr (NULL, config->files, "CENSOR.INPUT.MASK");
+    if (!inMask) {
+	psError(CENSOR_ERR_CONFIG, true, "Can't find input masks!\n");
+	return false;
+    }
+
+    pmFPAview *view = pmFPAviewAlloc (0);
+    bool badMaskFile = false;
+
+    // check on the mask file at this level if possible
+    badMaskFile = censorBadFileByView(badMaskFile, inMask, config, view);
+
+    // files associated with the science image
+    if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;
+
+    while ((chip = pmFPAviewNextChip (view, input->fpa, 1)) != NULL) {
+	psTrace ("censor", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
+	if (!chip->process || !chip->file_exists) { continue; }
+
+	// check on the mask file at this level if possible
+	badMaskFile = censorBadFileByView(badMaskFile, inMask, config, view);
+
+	if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;
+
+	while ((cell = pmFPAviewNextCell (view, input->fpa, 1)) != NULL) {
+	    psTrace ("censor", 4, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process);
+	    if (!cell->process || !cell->file_exists) { continue; }
+
+	    // check on the mask file at this level if possible
+	    badMaskFile = censorBadFileByView(badMaskFile, inMask, config, view);
+
+	    if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;
+
+	    // process each of the readouts
+	    while ((readout = pmFPAviewNextReadout (view, input->fpa, 1)) != NULL) {
+
+		// check on the mask file at this level if possible
+		badMaskFile = censorBadFileByView(badMaskFile, inMask, config, view);
+
+		if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;
+		if (!readout->data_exists) { continue; }
+
+		if (!censorReadout (readout, config, view, badMaskFile)) ESCAPE;
+
+		if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
+	    }
+	    if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
+	}
+	if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
+    }
+    if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
+
+    psLogMsg ("censor", 3, "censorLoop done : %f sec\n", psTimerMark ("censor"));
+
+    psFree (view);
+    return true;
+}
+
+bool censorBadFileByView (bool badFile, pmFPAfile *file, pmConfig *config, pmFPAview *view) {
+
+    // get the current level
+    pmFPALevel level = pmFPAviewLevel (view);
+
+    // can we try to open this file? (if not, leave the existing badView intact)
+    if (level != file->fileLevel) return badFile;
+
+    // free, and if needed, realloc badView below
+    badFile = false;
+
+    char *filename = pmFPAfileName(file, view, config);
+    if (filename) {
+	// activate the file
+	pmFPAfileActivate (config->files, true, file->name);
+	psFree (filename);
+	return false;
+    }
+
+    // de-activate the file
+    pmFPAfileActivate (config->files, false, file->name);
+    return true;
+}
Index: branches/pap/magic/censorObjects/src/censorParseCamera.c
===================================================================
--- branches/pap/magic/censorObjects/src/censorParseCamera.c	(revision 25027)
+++ branches/pap/magic/censorObjects/src/censorParseCamera.c	(revision 25027)
@@ -0,0 +1,50 @@
+/** @file censorParseCamera.c
+ *
+ *  @brief
+ *
+ *  @ingroup censor
+ *
+ *  @author IfA
+ *  @version $Revision: 1.18 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-07 02:03:34 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# include "censor.h"
+
+bool censorParseCamera (pmConfig *config) {
+
+    bool status = false;
+
+    // the input image(s) are required arguments; they define the camera
+    pmFPAfile *input = pmFPAfileDefineFromArgs (&status, config, "CENSOR.INPUT", "INPUT");
+    if (!status) {
+	psError(CENSOR_ERR_CONFIG, false, "Failed to build FPA from CENSOR.INPUT");
+	return false;
+    }
+
+    pmFPAfile *output = pmFPAfileDefineOutput (config, input->fpa, "CENSOR.OUTPUT");
+    if (!output) {
+	psError(CENSOR_ERR_CONFIG, false, "Failed to build output FPA from CENSOR.INPUT");
+	return false;
+    }
+    output->save = true;
+
+    // look for the file on the argument list
+    pmFPAfile *inMask = pmFPAfileDefineFromArgs  (&status, config, "CENSOR.INPUT.MASK", "INPUT.MASK");
+    if (!status) {
+	psError (PS_ERR_UNKNOWN, false, "failed to load input mask definition");
+	return false;
+    }
+    if (!inMask) {
+	psError (PS_ERR_UNKNOWN, false, "failed to load input mask");
+	return false;
+    }
+    if (inMask->type != PM_FPA_FILE_MASK) {
+	psError(PS_ERR_IO, true, "CENSOR.INPUT.MASK is not of type MASK");
+	return false;
+    }
+
+    psTrace("censor", 1, "Done with censorParseCamera...\n");
+    return true;
+}
Index: branches/pap/magic/censorObjects/src/censorReadout.c
===================================================================
--- branches/pap/magic/censorObjects/src/censorReadout.c	(revision 25027)
+++ branches/pap/magic/censorObjects/src/censorReadout.c	(revision 25027)
@@ -0,0 +1,92 @@
+/** @file censorReadout.c
+ *
+ *  @brief reject detections that land within the streak mask regions
+ *
+ *  @ingroup censor
+ *
+ *  @author IfA
+ *  @version $Revision: 1.7 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-07 02:03:34 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# include "censor.h"
+
+bool censorReadout (pmReadout *readout, pmConfig *config, const pmFPAview *view, bool badMaskFile) {
+
+    bool status;
+
+    // if there is no mask file for this readout drop all sources
+    if (badMaskFile) {
+      psMetadataRemoveKey (readout->analysis, "PSPHOT.SOURCES");
+      return true;
+    }
+
+    // select the current recipe
+    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, CENSOR_RECIPE);
+    if (!recipe) {
+        psError(CENSOR_ERR_CONFIG, true, "Can't find CENSOR recipe");
+        return false;
+    }
+
+    psImageMaskType streakMaskValue = pmConfigMaskGet("STREAK", config); // Mask value for streak pixels
+
+    psLogMsg ("censor", PS_LOG_INFO, "generating a bright-star mask");
+
+    // select the reference mask fpa :: we use this to determine cell boundaries
+    pmFPAfile *inMask = psMetadataLookupPtr (NULL, config->files, "CENSOR.INPUT.MASK");
+    if (!inMask) {
+        psError(CENSOR_ERR_CONFIG, true, "Can't find mask files");
+        return false;
+    }
+
+    // XXX why not do this? 
+    pmReadout *readoutMask = pmFPAviewThisReadout (view, inMask->fpa);
+    if (!readoutMask) {
+        psError(CENSOR_ERR_CONFIG, true, "Can't find mask for this readout");
+	return false;
+    }
+
+    // select the raw objects for this readout, flag is they fall in a mask
+    psArray *inSources = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.SOURCES");
+    if (inSources == NULL) {
+        psError(CENSOR_ERR_CONFIG, true, "Can't find sources for this readout");
+	return false;
+    }
+		
+    // create a replacement output array:
+    psArray *outSources = psArrayAllocEmpty(100);
+
+    // only keep sources that do not match the specified mask bit
+    for (int i = 0; i < inSources->n; i++) {
+	pmSource *source = inSources->data[i];
+
+	int xChip = source->peak->x;
+	int yChip = source->peak->y;
+
+	bool onChip = true;
+	onChip &= (xChip >= 0);
+	onChip &= (xChip < readoutMask->mask->numCols);
+	onChip &= (yChip >= 0);
+	onChip &= (yChip < readoutMask->mask->numRows);
+
+	if (onChip) {
+	    psImageMaskType value = readoutMask->mask->data.PS_TYPE_IMAGE_MASK_DATA[yChip][xChip];
+	    if (value & streakMaskValue) {
+		// skip sources on streak masks
+		continue;
+	    }
+	}
+	psArrayAdd (outSources, 100, source);
+    }
+
+    psLogMsg ("censor", PS_LOG_INFO, "keeping %ld of %ld sources", outSources->n, inSources->n);
+
+    // remove the inSources and replace with the outSources
+    psMetadataRemoveKey (readout->analysis, "PSPHOT.SOURCES");
+    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_DATA_ARRAY, "sources", outSources);
+    psFree (outSources);
+
+    return true;
+}
+
Index: branches/pap/magic/censorObjects/src/censorVersion.c
===================================================================
--- branches/pap/magic/censorObjects/src/censorVersion.c	(revision 25027)
+++ branches/pap/magic/censorObjects/src/censorVersion.c	(revision 25027)
@@ -0,0 +1,113 @@
+/** @file censorVersion.c
+ *
+ *  @brief
+ *
+ *  @ingroup censor
+ *
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#include "censor.h"
+#include "censorVersionDefinitions.h"
+
+#ifndef CENSOR_VERSION
+#error "CENSOR_VERSION is not set"
+#endif
+#ifndef CENSOR_BRANCH
+#error "CENSOR_BRANCH is not set"
+#endif
+#ifndef CENSOR_SOURCE
+#error "CENSOR_SOURCE is not set"
+#endif
+
+psString censorVersion(void)
+{
+    char *value = NULL;
+    psStringAppend(&value, "%s@%s", CENSOR_BRANCH, CENSOR_VERSION);
+    return value;
+}
+
+psString censorSource(void)
+{
+  return psStringCopy(CENSOR_SOURCE);
+}
+
+psString censorVersionLong(void)
+{
+    psString version = censorVersion();  // Version, to return
+    psString source = censorSource();    // Source
+
+    psStringPrepend(&version, "censor ");
+    psStringAppend(&version, " from %s, built %s, %s", source, __DATE__, __TIME__);
+    psFree(source);
+
+#ifdef __OPTIMIZE__
+    psStringAppend(&version, " optimised");
+#else
+    psStringAppend(&version, " unoptimised");
+#endif
+
+    return version;
+};
+
+bool censorVersionHeader(psMetadata *header)
+{
+    PS_ASSERT_METADATA_NON_NULL(header, false);
+
+    psString version = censorVersion(); // Software version
+    psString source = censorSource();   // Software source
+
+    psStringPrepend(&version, "censor version: ");
+    psStringPrepend(&source, "censor source: ");
+
+    psMetadataAddStr(header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, version);
+    psMetadataAddStr(header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, source);
+
+    psFree(version);
+    psFree(source);
+
+    return true;
+}
+
+bool censorVersionHeaderFull(psMetadata *header)
+{
+    PS_ASSERT_METADATA_NON_NULL(header, false);
+
+    psTime *time = psTimeGetNow(PS_TIME_TAI); // The time now
+    psString timeString = psTimeToISO(time); // The time in an ISO string
+    psFree(time);
+    psString history = NULL;               // History string
+    psStringAppend(&history, "censor at %s", timeString);
+    psFree(timeString);
+    psMetadataAddStr(header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, history);
+    psFree(history);
+
+    psLibVersionHeader(header);
+    psModulesVersionHeader(header);
+    censorVersionHeader(header);
+
+    return true;
+}
+
+void censorVersionPrint(void)
+{
+    psTime *time = psTimeGetNow(PS_TIME_TAI); // The time now
+    psString timeString = psTimeToISO(time); // The time in an ISO string
+    psFree(time);
+    psLogMsg("censor", PS_LOG_INFO, "censor at %s", timeString);
+    psFree(timeString);
+
+    psString pslib = psLibVersionLong();// psLib version
+    psString psmodules = psModulesVersionLong(); // psModules version
+    psString censor = censorVersionLong(); // censor version
+
+    psLogMsg("censor", PS_LOG_INFO, "%s", pslib);
+    psLogMsg("censor", PS_LOG_INFO, "%s", psmodules);
+    psLogMsg("censor", PS_LOG_INFO, "%s", censor);
+
+    psFree(pslib);
+    psFree(psmodules);
+    psFree(censor);
+
+    return;
+}
Index: branches/pap/magic/censorObjects/src/censorVersionDefinitions.h.in
===================================================================
--- branches/pap/magic/censorObjects/src/censorVersionDefinitions.h.in	(revision 25027)
+++ branches/pap/magic/censorObjects/src/censorVersionDefinitions.h.in	(revision 25027)
@@ -0,0 +1,8 @@
+#ifndef CENSOR_VERSION_DEFINITIONS_H
+#define CENSOR_VERSION_DEFINITIONS_H
+
+#define CENSOR_VERSION @CENSOR_VERSION@ // SVN version
+#define CENSOR_BRANCH  @CENSOR_BRANCH@  // SVN branch
+#define CENSOR_SOURCE  @CENSOR_SOURCE@  // SVN source
+
+#endif
Index: branches/pap/magic/config.tools
===================================================================
--- branches/pap/magic/config.tools	(revision 25027)
+++ branches/pap/magic/config.tools	(revision 25027)
@@ -0,0 +1,47 @@
+#!/bin/csh -f
+
+if ($#argv == 0) then
+  echo "USAGE: config.tools [fixpath | fixconf]"
+  exit 2
+endif
+
+if ("$argv[1]" == "fixpath") goto fixpath
+if ("$argv[1]" == "fixconf") goto fixconf
+
+echo "unknown option $argv[1]"
+exit 1
+
+#######
+fixpath:
+
+if ($#argv != 2) then
+  echo "USAGE: config.tools fixpath (path)"
+  exit 2
+endif
+
+set indir = $argv[2]
+
+# convert // to / in pathnames
+echo $indir | grep "\/\/" > /dev/null
+set success = $status
+while ($success == 0) 
+  set indir = `echo $indir | sed 's|\/\/|\/|g'`
+  echo $indir | grep "\/\/" > /dev/null
+  set success = $status
+end
+
+set indir = `echo $indir | sed 's|\/$||'`
+echo $indir
+exit 0
+
+#######
+fixconf:
+
+if ($#argv != 3) then
+  echo "USAGE: config.tools fixconf (NAME) (value)"
+  exit 2
+endif
+
+cat Makefile | sed "s|$argv[2]|$argv[3]|" > Makefile.tmp
+mv -f Makefile.tmp Makefile
+exit 0;
Index: branches/pap/magic/configure
===================================================================
--- branches/pap/magic/configure	(revision 25027)
+++ branches/pap/magic/configure	(revision 25027)
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# strip out CC, CFLAGS, CPPFLAGS, LDFLAGS and set env vars
+while ( test $# -gt 0 ); do
+
+  skip=0
+
+  # strip out CC, set as env variable
+  echo $1 | grep "^CC=" > /dev/null
+  if ( test $? -eq 0 ) ; then
+    val=`echo $1 | sed "s|^CC=||"`
+    export CC=$val
+    skip=1
+  fi
+  # strip out CFLAGS, set as env variable
+  echo $1 | grep "^CFLAGS=" > /dev/null
+  if ( test $? -eq 0 ) ; then
+    val=`echo $1 | sed "s|^CFLAGS=||"`
+    export CFLAGS=$val
+    skip=1
+  fi
+  # strip out CPPFLAGS, set as env variable
+  echo $1 | grep "^CPPFLAGS=" > /dev/null
+  if ( test $? -eq 0 ) ; then
+    val=`echo $1 | sed "s|^CPPFLAGS=||"`
+    export CPPFLAGS=$val
+    skip=1
+  fi
+  # strip out LDFLAGS, set as env variable
+  echo $1 | grep "^LDFLAGS=" > /dev/null
+  if ( test $? -eq 0 ) ; then
+    val=`echo $1 | sed "s|^LDFLAGS=||"`
+    export LDFLAGS=$val
+    skip=1
+  fi
+  if ( test $skip -eq 0 ) ; then
+    args="$args $1"
+  fi
+  shift
+done
+
+./configure.tcsh $args
Index: branches/pap/magic/configure.tcsh
===================================================================
--- branches/pap/magic/configure.tcsh	(revision 25027)
+++ branches/pap/magic/configure.tcsh	(revision 25027)
@@ -0,0 +1,179 @@
+#!/bin/csh -f
+
+# this is a very low-tech version of configure, not built by autoconf.
+# we check for the following libraries:
+
+# we need to be able to list the required libraries for a given distribution
+
+# evaluate command-line options
+set prefix  = ""
+set bindir  = ""
+set libdir  = ""
+set incdir  = ""
+set mandir  = ""
+set datadir  = ""
+set sysconfdir  = ""
+set exec_prefix = ""
+set defines = ""
+set profile = 0
+
+set root    = ""
+set args    = ""
+
+while ("$1" != "") 
+ switch ("$1")
+  # switch options passed by build systems which we ignore
+  case --enable-maintainer-mode
+  case --no-create
+  case --no-recursion
+  case --enable-optimize
+  case --disable-shared
+  case --enable-shared
+  case --disable-static
+  case --enable-static
+  case --enable-profile
+  case --pedantic
+   shift
+   breaksw;
+  # key/value options passed by build systems which we ignore
+  case --sbindir*
+  case --libexecdir*
+  case --sharedstatedir*
+  case --localstatedir*
+  case --oldincludedir*
+  case --infodir*
+  case --exec-prefix*
+  case --libdir*
+  case --includedir*
+  case --sysconfdir*
+  case --datadir*
+   # we need to strip the --opt word and --opt=word versions
+   set word = `echo $1 | tr = ' '`
+   if ($#word == 1) then
+     if ($#argv > 1) then
+      shift
+     endif
+   endif
+   breaksw;
+  case --prefix*
+   if ("$1" == "--prefix") then
+     shift
+     set prefix = $1
+   else
+     set prefix = `echo $1 | tr = ' ' | awk '{print $2}'`
+   endif
+   breaksw;
+  case --bindir*
+   if ("$1" == "--bindir") then
+     shift
+     set bindir = $1
+   else
+     set bindir = `echo $1 | tr = ' ' | awk '{print $2}'`
+   endif
+   breaksw;
+  case --mandir*
+   if ("$1" == "--mandir") then
+     shift
+     set mandir = $1
+   else
+     set mandir = `echo $1 | tr = ' ' | awk '{print $2}'`
+   endif
+   breaksw;
+  case --help:
+   goto usage
+  case -*: 
+   echo ""
+   echo "Unknown option: $1"
+   goto usage
+  default:
+   set args=($args $1);
+   breaksw;
+ endsw
+ shift
+end
+if ($#args != 1) goto usage
+
+# gpc build ignores CC, CFLAGS, CPPFLAGS, LDFLAGS
+
+# set up the basic directory names:
+set root = `pwd`
+if ($prefix == "") set prefix = $root
+
+echo 
+echo "install destinations:"
+echo "ROOT: $root"
+echo "PREFIX: $prefix"
+echo 
+
+# the config.tools fixconf operations below interpolate values in Makefile
+if (-e Makefile) mv Makefile Makefile.bak
+cp -f Makefile.in Makefile
+
+# BINDIR holds the output binary files
+if ("$bindir" == "") then
+  set subdir = bin
+  set bindir = $prefix/$subdir
+endif
+set bindir = `./config.tools fixpath $bindir`
+./config.tools fixconf @BINDIR@ $bindir
+echo BINDIR $bindir
+
+# MANDIR (DESTMAN) holds the output man pages
+if ("$mandir" == "") then
+  set mandir = $prefix/man
+endif
+set mandir = `./config.tools fixpath $mandir`
+./config.tools fixconf @MANDIR@ $mandir
+echo DESTMAN $mandir
+
+echo ""
+echo "include $bindir in your path"
+
+exit 0
+
+usage:
+cat <<EOF
+USAGE: configure [OPTION]
+
+echo remaining args: $args
+
+set the installation directory root with --prefix
+if you define the environment variable ARCH, you can set --vararch
+ 
+Configuration:
+  -h, --help              display this help and exit
+  --enable-optimize       enable compiler optimization (-O2)
+  --enable-memcheck       enable ohana memory tests
+  --pedantic              include -Wall -Werror on compilation
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+  --vararch               install with ARCH suffixes for variable architectures
+
+Fine tuning of the installation directories:
+  --bindir=DIR           user executables [PREFIX/bin/$ARCH] 
+  --libdir=DIR           object code libraries [PREFIX/lib/$ARCH]
+  --includedir=DIR       C header files [PREFIX/include]
+  --mandir=DIR           man documentation [PREFIX/man]
+  --datadir=DIR          read-only architecture-independent data [PREFIX/share]
+  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]
+
+Makefile flags:
+  CC=options
+  CFLAGS=options
+  CPPFLAGS=options
+  LDFLAGS=options
+
+The following options are silently ignored for compatibility:
+  --enable-maintainer-mode
+  --no-create
+  --no-recursion
+  --sbindir
+  --libexecdir
+  --sharedstatedir
+  --localstatedir
+  --oldincludedir
+  --infodir
+
+EOF
+ exit 2;
Index: branches/pap/magic/remove/src/Line.c
===================================================================
--- branches/pap/magic/remove/src/Line.c	(revision 23948)
+++ branches/pap/magic/remove/src/Line.c	(revision 25027)
@@ -16,4 +16,13 @@
 {
     double temp = *first;
+    *first = *second;
+    *second = temp;
+}
+
+/** Internal routine to swap integer values */
+
+void SwapInt (int* first, int* second)
+{
+    int temp = *first;
     *first = *second;
     *second = temp;
@@ -255,15 +264,110 @@
 }
 
-/** Map a line to an image for its specified width and store as a list
-    of pixel positions
+/** Clip the line between (minX,minY) and (maxX,maxY)
+
+    @param[in,out] line line to be clipped within the bounds
+    @param[in] minX minimum X (columns) for the line
+    @param[in] minY minimum Y (rows) for the line
+    @param[in] maxX maximum X (columns) for the line
+    @param[in] maxY maximum Y (rows) for the line
+    @return true if line overlaps the clip boundaries           */
+
+bool LineClipFull (Line *line, int minX, int minY, int maxX, int maxY)
+{
+    unsigned int i, found = 0;
+    Line boundLine, clipLine;
+    strkPt tuple1, tuple2, vertices[4];
+    vertices[0].x = minX; vertices[0].y = minY;
+    vertices[1].x = maxX; vertices[1].y = minY;
+    vertices[2].x = maxX; vertices[2].y = maxY;
+    vertices[3].x = minX; vertices[3].y = maxY;
+
+    for (i = 0; i < 4 && found < 2; ++i)
+    {
+        boundLine.begin = vertices[i];
+        boundLine.end   = vertices[(i + 1) % 4];
+        if (LineIntercept (line, &boundLine, &tuple1, &tuple2, false, true))
+        {
+            if (found == 0)
+            {
+                clipLine.begin = tuple1;
+                ++found;
+            }
+            else if (tuple1.x != clipLine.begin.x || 
+                     tuple1.y != clipLine.begin.y)
+            {
+                clipLine.end = tuple1;
+                ++found;
+            }
+        }
+    }
+    
+    // If two endpoints are found, clip the line
+    
+    if (found > 1)
+    {
+        if (clipLine.begin.x <= clipLine.end.x)
+        {
+            line->begin = clipLine.begin;
+            line->end   = clipLine.end;
+        }
+        else
+        {
+            line->begin = clipLine.end;
+            line->end   = clipLine.begin;
+        }
+    }
+    return found > 1;
+}
+
+/** Move a line by the specified X and Y offsets
+    @param[in,out] line Line to move by X and Y offsets
+    @param[in] xOffset X shift applied to both endpoints
+    @param[in] yOffset Y shift applied to both endpoints        */
+
+void LineMove (Line *line, double xOffset, double yOffset)
+{
+    line->begin.x += xOffset;
+    line->begin.y += yOffset;
+    line->end.x   += xOffset;
+    line->end.y   += yOffset;
+}
+
+/** Return the maximum bounds between the line endpoints and
+    current bounds
+    @param[in] line Line endpoints to compare
+    @param[in,out] xMin minimum X value to update
+    @param[in,out] xMax maximum X value to update
+    @param[in,out] yMin minimum Y value to update
+    @param[in,out] yMax maximum Y value to update               */
+
+void MaxBounds (Line *line, int *xMin, int *xMax,  int *yMin, int *yMax)
+{
+    if (line->begin.x < *xMin) *xMin = (int) floor (line->begin.x);
+    if (line->end.x   < *xMin) *xMin = (int) floor (line->end.x);
+    if (line->begin.y < *yMin) *yMin = (int) floor (line->begin.y);
+    if (line->end.y   < *yMin) *yMin = (int) floor (line->end.y);
+
+    if (line->begin.x > *xMax) *xMax = (int) ceil (line->begin.x);
+    if (line->end.x   > *xMax) *xMax = (int) ceil (line->end.x);
+    if (line->begin.y > *yMax) *yMax = (int) ceil (line->begin.y);
+    if (line->end.y   > *yMax) *yMax = (int) ceil (line->end.y);
+}
+
+/** Map a line to an image for its specified width and store as
+    a list of pixel positions
 
     @param[out] pixels list of PixelPos pointers corresponding
                        based on the line settings
-    @param[in] line Line to map to pixels                       */
-
-void PixelsFromLine (StreakPixels* pixels, Line *line)
-{
+    @param[in] line Line to map to pixels   
+    @param[in] numCols maximum X (columns) for the line
+    @param[in] numRows maximum Y (rows) for the line            */
+
+void PixelsFromLine (StreakPixels* pixels, Line *line, int numCols, int numRows)
+{
+    Line offsetLine;
     PixelPos *pixel;
-    double slope, xOffset, yOffset, xMid, yMid, xBegin, yBegin, xEnd, yEnd, x, y;
+    double slope, xOffset, yOffset, xMid, yMid;
+    int x, y, xBegin = numCols, yBegin = numRows, xEnd = 0, yEnd = 0;
 
     // Extract the endpoints
@@ -280,7 +384,22 @@
     double dr = sqrt (dx * dx + dy * dy);
     double halfWidth  = line->width / 2.0;
-    double halfWidth2 = halfWidth * halfWidth;
     if (!dr) return;
-    
+
+    // Compute the intercepts of line width bounds and determine maximum
+    // bounds in each axis
+
+    xOffset = -halfWidth * dy / dr;
+    yOffset =  halfWidth * dx / dr;
+
+    offsetLine = *line;
+    LineMove (&offsetLine, xOffset, yOffset);
+    if (LineClip (&offsetLine, numCols, numRows))
+        MaxBounds (&offsetLine, &xBegin, &xEnd, &yBegin, &yEnd);
+
+    offsetLine = *line;
+    LineMove (&offsetLine, -xOffset, -yOffset);
+    if (LineClip (&offsetLine, numCols, numRows))
+        MaxBounds (&offsetLine, &xBegin, &xEnd, &yBegin, &yEnd);
+
     // Step point by point based on the dominate axis
     
@@ -307,25 +426,23 @@
         // Compute the x and y offsets for the line width extent
 
-        xOffset = halfWidth * dy / dr;
-        yOffset = halfWidth * dr / dx;
-        yMid   = y1 + slope * (floor (x1 - xOffset) - x1);
-        xBegin = floor (x1 - xOffset);
-        xEnd   = ceil  (x2 + xOffset) + 1.0;
-
-        for (x = xBegin; x < xEnd; ++x)
-        {
-            yBegin = floor (yMid - yOffset);
-            yEnd   = ceil  (yMid + yOffset) + 1.0;
-            for (y = yBegin; y < yEnd; ++y)
-            {
-                if (DistanceSquared (line, x, y) <= halfWidth2)
+        if (xBegin > xEnd) 
+            SwapInt (&xBegin, &xEnd);
+        else
+            ++xEnd;
+        if (xBegin < 0) xBegin = 0;
+        if (xEnd > numCols) xEnd = numCols;
+
+        yMid = y1 + slope * (xBegin - x1);
+        yOffset = fabs (halfWidth * dr / dx);
+
+        for (x = xBegin; x != xEnd; ++x)
+        {
+            yBegin = (int) floor (yMid - yOffset);
+            yEnd   = (int) ceil  (yMid + yOffset) + 1;
+            for (y = yBegin; y != yEnd; ++y)
+            {
+                if (y >= 0 && y < numRows)
                 {
-                    if (x >=0 && y >= 0) {
-                        pixel = psAlloc (sizeof(PixelPos));
-                        pixel->x = (unsigned int) x;
-                        pixel->y = (unsigned int) y;
-                        psArrayAdd (pixels, 1024, pixel);
-                        psFree (pixel);
-                    }
+                    psImageSet(pixels, x, y, 1);
                 }
             }
@@ -354,27 +471,24 @@
         
         // Compute the x and y offsets for the line width extent
-        
-        xOffset = halfWidth * dr / dy;
-        yOffset = halfWidth * dx / dr;
-
-        xMid   = x1 + slope * (floor (y1 - yOffset) - y1);
-        yBegin = floor (y1 - yOffset);
-        yEnd   = ceil  (y2 + yOffset) + 1.0;
-        
-        for (y = yBegin; y < yEnd; ++y)
-        {
-            xBegin = floor (xMid - xOffset);
-            xEnd   = ceil  (xMid + xOffset) + 1.0;
-            for (x = xBegin; x < xEnd; ++x)
-            {
-                if (DistanceSquared (line, x, y) <= halfWidth2)
+
+        if (yBegin > yEnd)
+            SwapInt (&yBegin, &yEnd);
+        else
+            ++yEnd;
+        if (yBegin < 0) yBegin = 0;
+        if (yEnd > numRows) yEnd = numRows;
+
+        xMid = x1 + slope * (yBegin - y1);
+        xOffset = fabs (halfWidth * dr / dy);
+        
+        for (y = yBegin; y != yEnd; ++y)
+        {
+            xBegin = (int) floor (xMid - xOffset);
+            xEnd   = (int) ceil  (xMid + xOffset) + 1;
+            for (x = xBegin; x != xEnd; ++x)
+            {
+                if (x >=0 && x < numCols)
                 {
-                    if (x >=0 && y >= 0) {
-                        pixel = psAlloc (sizeof(PixelPos));
-                        pixel->x = (unsigned int) x;
-                        pixel->y = (unsigned int) y;
-                        psArrayAdd (pixels, 1024, pixel);
-                        psFree (pixel);
-                    }
+                    psImageSet(pixels, x, y, 1);
                 }
             }
Index: branches/pap/magic/remove/src/Line.h
===================================================================
--- branches/pap/magic/remove/src/Line.h	(revision 23948)
+++ branches/pap/magic/remove/src/Line.h	(revision 25027)
@@ -21,4 +21,15 @@
 extern bool LineClip (Line *line, int numCols, int numRows);
 
+/** Clip the line between (minX,minY) and (maxX,maxY)
+
+    @param[in,out] line line to be clipped within the bounds
+    @param[in] minX minimum X (columns) for the line
+    @param[in] minY minimum Y (rows) for the line
+    @param[in] maxX maximum X (columns) for the line
+    @param[in] maxY maximum Y (rows) for the line
+    @return true if line overlaps the clip boundaries           */
+
+extern bool LineClipFull (Line *line, int minX, int minY, int maxX, int maxY);
+
 /** Map a line to an image for its specified width and append as
     a list of pixel positions
@@ -26,7 +37,10 @@
     @param[out] pixels list of PixelPos pointers corresponding
                        based on the line settings
-    @param[in] line Line to map to pixels                       */
+    @param[in] line Line to map to pixels   
+    @param[in] numCols maximum X (columns) for the line
+    @param[in] numRows maximum Y (rows) for the line            */
 
-extern void PixelsFromLine (StreakPixels* pixels, Line *line);
+extern void PixelsFromLine (StreakPixels* pixels, Line *line,
+                            int numCols, int numRows);
 
 #endif /* STREAK_LINE_H */
Index: branches/pap/magic/remove/src/Makefile.simple
===================================================================
--- branches/pap/magic/remove/src/Makefile.simple	(revision 23948)
+++ branches/pap/magic/remove/src/Makefile.simple	(revision 25027)
@@ -28,15 +28,24 @@
     streaksrelease.o
 
-# STREAKSFLAGS=-DSTREAKS_COMPRESS_OUTPUT=1
+ISDESTREAKED_OBJECTS=      \
+    ${COMMON_OBJECTS} \
+    isdestreaked.o
+
+
+HEADERS= Line.h  streaksastrom.h  streaksextern.h  streaksio.h  streaksremove.h
+
+STREAKSFLAGS=-DSTREAKS_COMPRESS_OUTPUT=1
 OPTFLAGS= -g -O2
-OPTFLAGS= -g
+#OPTFLAGS= -g
 CFLAGS=`psmodules-config --cflags` -std=gnu99 ${OPTFLAGS} ${STREAKSFLAGS}
 #CFLAGS=`psmodules-config --cflags` -std=gnu99 ${OPTFLAGS}
 LDFLAGS=`psmodules-config --libs`
 
-PROGRAMS= streaksremove streaksreplace streakscompare streaksrelease
+PROGRAMS= streaksremove streaksreplace streakscompare streaksrelease isdestreaked
+HEADERS=Line.h streaksastrom.h streaksextern.h streaksio.h streaksremove.h
 
 all:	${PROGRAMS}
 
+${REMOVE_OBJECTS}:	${HEADERS}
 streaksremove:  ${REMOVE_OBJECTS}
 
@@ -47,4 +56,7 @@
 streaksrelease:  ${RELEASE_OBJECTS}
 
+isdestreaked:	${ISDESTREAKED_OBJECTS}
+
+
 install:	${PROGRAMS}
 	install -t  $(PSCONFDIR)/$(PSCONFIG)/bin streaksremove
@@ -52,4 +64,5 @@
 	install -t  $(PSCONFDIR)/$(PSCONFIG)/bin streakscompare
 	install -t  $(PSCONFDIR)/$(PSCONFIG)/bin streaksrelease
+	install -t  $(PSCONFDIR)/$(PSCONFIG)/bin isdestreaked
 
 clean:
Index: branches/pap/magic/remove/src/isdestreaked.c
===================================================================
--- branches/pap/magic/remove/src/isdestreaked.c	(revision 25027)
+++ branches/pap/magic/remove/src/isdestreaked.c	(revision 25027)
@@ -0,0 +1,41 @@
+#include "streaksremove.h"
+
+int
+main(int argc, char *argv[])
+{
+    pmConfig *config = pmConfigRead(&argc, argv, NULL);
+    if (!config) {
+        psErrorStackPrint(stderr, "failed to parse arguments\n");
+        exit(PS_EXIT_CONFIG_ERROR);
+    }
+
+    char *fileName = argv[1];
+    if (!fileName) {
+        fprintf(stderr, "Usage: %s filename\n", argv[0]);
+        exit(PS_EXIT_DATA_ERROR);
+    }
+
+    psFits *fits = psFitsOpen(fileName, "r");
+    if (!fits) {
+        psError(PS_ERR_UNKNOWN, false, "failed to open fits file: %s\n", fileName);
+        psErrorStackPrint(stderr, "");
+        exit(PS_EXIT_DATA_ERROR);
+    }
+
+    psMetadata *header = psFitsReadHeader(NULL, fits);
+    if (!header) {
+        psError(PS_ERR_IO, false, "failed to read header for: %s", fileName);
+        psErrorStackPrint(stderr, "");
+        exit(PS_EXIT_DATA_ERROR);
+    }
+
+    bool mdok;
+    bool isDestreaked = psMetadataLookupBool(&mdok, header, "PSDESTRK");
+    if (mdok && isDestreaked) {
+        printf("%s is a destreaked file\n", fileName);
+        exit(0);
+    } else {
+        printf("%s is not a destreaked file\n", fileName);
+        exit(42);
+    }
+}
Index: branches/pap/magic/remove/src/streaksastrom.c
===================================================================
--- branches/pap/magic/remove/src/streaksastrom.c	(revision 23948)
+++ branches/pap/magic/remove/src/streaksastrom.c	(revision 25027)
@@ -150,4 +150,100 @@
  
 bool
+SkyToLocal(strkPt *outPt, strkAstrom *astrom, double ra, double dec)
+{
+    // generate a local project using the RA, DEC of the 0,0 pixel of the chip as the
+    // projection center with the same plate scale as the nominal TP->Sky astrometry.
+
+    pmFPA *fpa   = (pmFPA *) astrom->fpa;
+    pmChip *chip = (pmChip *) astrom->chip;
+
+    // find the RA,DEC coords of the 0,0 pixel for this chip:
+
+    psPlane ptTP;
+    psSphere ptSky;
+
+    ptSky.r = ra;
+    ptSky.d = dec;
+    ptSky.rErr = 0.0;
+    ptSky.dErr = 0.0;
+
+    psProject(&ptTP, &ptSky, fpa->toSky);
+
+    outPt->x = ptTP.x;
+    outPt->y = ptTP.y;
+
+    return true;
+}
+
+bool
+LocalToSky(strkPt *outPt, strkAstrom *astrom, strkPt *inPt)
+{
+    // generate a local project using the RA, DEC of the 0,0 pixel of the chip as the
+    // projection center with the same plate scale as the nominal TP->Sky astrometry.
+
+    pmFPA *fpa   = (pmFPA *) astrom->fpa;
+    pmChip *chip = (pmChip *) astrom->chip;
+
+    // find the RA,DEC coords of the 0,0 pixel for this chip:
+
+    psPlane ptTP;
+    psSphere ptSky;
+
+    ptTP.x = inPt->x;
+    ptTP.y = inPt->y;
+    ptTP.xErr = 0.0;
+    ptTP.yErr = 0.0;
+
+    psDeproject(&ptSky, &ptTP, fpa->toSky);
+
+    outPt->x = ptSky.r;
+    outPt->y = ptSky.d;
+
+    return true;
+}
+
+bool
+componentBounds(int *minX, int *minY, int *maxX, int *maxY, strkAstrom *astrom, int numCols, int numRows)
+{
+    // find the bounds of the (padded) chip region in tangent-plane coordinates
+
+    pmFPA *fpa   = (pmFPA *) astrom->fpa;
+    pmChip *chip = (pmChip *) astrom->chip;
+
+    psPlane ptCH, ptFP, TPo, TPx, TPy;
+
+    // coordinate of the chip center:
+    ptCH.x = 0.5*numCols;
+    ptCH.y = 0.5*numRows;
+    psPlaneTransformApply(&ptFP, chip->toFPA, &ptCH);
+    psPlaneTransformApply(&TPo, fpa->toTPA,  &ptFP);
+
+    // coordinate of the chip center + dX/2:
+    ptCH.x = numCols;
+    ptCH.y = 0.5*numRows;
+    psPlaneTransformApply(&ptFP, chip->toFPA, &ptCH);
+    psPlaneTransformApply(&TPx, fpa->toTPA,  &ptFP);
+
+    // coordinate of the chip center + dY/2:
+    ptCH.x = 0.5*numCols;
+    ptCH.y = numRows;
+    psPlaneTransformApply(&ptFP, chip->toFPA, &ptCH);
+    psPlaneTransformApply(&TPy, fpa->toTPA,  &ptFP);
+
+    // half-lengths of the two sides in tangent-plane coords:
+    double xSize = hypot (TPx.x - TPo.x, TPx.y - TPo.y);
+    double ySize = hypot (TPy.x - TPo.x, TPy.y - TPo.y);
+    double radius = hypot (xSize, ySize);
+
+    // define the region encompassed by the radius with some padding:
+    *minX = TPo.x - 1.1*radius;
+    *minY = TPo.y - 1.1*radius;
+    *maxX = TPo.x + 1.1*radius;
+    *maxY = TPo.y + 1.1*radius;
+
+    return true;
+}
+
+bool
 skyToCell(strkPt *outPt, strkAstrom *astrom, double ra, double dec)
 {
@@ -281,9 +377,12 @@
 }
 
-void
+bool
 linearizeTransforms(strkAstrom *astrom)
 {
     if (!pmAstromLinearizeTransforms((pmFPA *) astrom->fpa, (pmChip *) astrom->chip)) {
-        streaksExit("linear fit to astrometry failed\n", PS_EXIT_UNKNOWN_ERROR);
-    }
-}
+        // streaksExit("linear fit to astrometry failed\n", PS_EXIT_UNKNOWN_ERROR);
+        psError(PS_ERR_UNKNOWN, false, "linear fit to astrometry failed ignoring");
+        return false;
+    }
+    return true;
+}
Index: branches/pap/magic/remove/src/streaksastrom.h
===================================================================
--- branches/pap/magic/remove/src/streaksastrom.h	(revision 23948)
+++ branches/pap/magic/remove/src/streaksastrom.h	(revision 25027)
@@ -30,5 +30,9 @@
 extern bool skyToCell(strkPt *, strkAstrom *astrom, double ra, double dec);
 extern bool cellToSky(strkPt *, strkAstrom *astrom, double x, double y);
-extern void linearizeTransforms(strkAstrom *astrom);
+extern bool linearizeTransforms(strkAstrom *astrom);
+
+extern bool SkyToLocal(strkPt *outPt, strkAstrom *astrom, double ra, double dec);
+extern bool LocalToSky(strkPt *outPt, strkAstrom *astrom, strkPt *inPt);
+extern bool componentBounds(int *minX, int *minY, int *maxX, int *maxY, strkAstrom *astrom, int numCols, int numRows);
 
 #endif // STREAKS_ASTROM_H
Index: branches/pap/magic/remove/src/streaksextern.c
===================================================================
--- branches/pap/magic/remove/src/streaksextern.c	(revision 23948)
+++ branches/pap/magic/remove/src/streaksextern.c	(revision 25027)
@@ -34,6 +34,13 @@
     int i;
     Line line;
-    StreakPixels *pixels = psArrayAllocEmpty (1024);
+    StreakPixels *pixels = psImageAlloc(numCols, numRows, PS_TYPE_U8);
+    psImageInit(pixels, 0);
     int streaksOnComponent = 0;
+
+    int minX, minY, maxX, maxY;
+
+    // find the chip dimensions in the tangent-plane coordinates (length of hypotenuse)
+    componentBounds (&minX, &minY, &maxX, &maxY, astrom, numCols, numRows);
+
     for (i = 0; i != streaks->size; ++i)
     {
@@ -41,11 +48,31 @@
 
         line.width = streaks->list[i].width;
-        if (skyToCell (&line.begin, astrom,
-                       streaks->list[i].ra1, streaks->list[i].dec1) &&
-            skyToCell (&line.end, astrom,
-                       streaks->list[i].ra2, streaks->list[i].dec2) &&
+
+	/* Use tangent plane coordinates to narrow down the ra,dec range of the line closer to
+	 * the chip boundaries.  Use these new ra,dec positions to generate the line on the
+	 * chip using the full non-linear astrometry */
+	   
+	// project the ends of the line using a linear projection centered on the chip center:
+	Line full;
+	SkyToLocal (&full.begin, astrom, streaks->list[i].ra1, streaks->list[i].dec1);
+	SkyToLocal (&full.end,   astrom, streaks->list[i].ra2, streaks->list[i].dec2);
+
+	// clip the line to a square box with diameter = hypotenuse of the chip image centerd
+	// on the chip center in tangent-plane coordinates.  skip the rest of this streak if
+	// the line does not intersect this region
+	if (!LineClipFull (&full, minX, minY, maxX, maxY)) {
+	    continue;
+	}
+
+	// convert the end points back into ra, dec pairs:
+	strkPt sky1, sky2;
+	LocalToSky (&sky1, astrom, &full.begin);
+	LocalToSky (&sky2, astrom, &full.end);
+
+        if (skyToCell (&line.begin, astrom, sky1.x, sky1.y) &&
+            skyToCell (&line.end,   astrom, sky2.x, sky2.y) &&
             LineClip (&line, numCols, numRows))
         {
-            PixelsFromLine (pixels, &line);
+            PixelsFromLine (pixels, &line, numCols, numRows);
             streaksOnComponent++;
         }
Index: branches/pap/magic/remove/src/streaksextern.h
===================================================================
--- branches/pap/magic/remove/src/streaksextern.h	(revision 23948)
+++ branches/pap/magic/remove/src/streaksextern.h	(revision 25027)
@@ -4,5 +4,5 @@
 /** psLib includes */
 
-#include "psArray.h"
+#include "psImage.h"
 
 /** streakremove includes */
@@ -36,5 +36,5 @@
 /** For now, use psArray to define a list of PixelPos pointers */
 
-typedef psArray StreakPixels;
+typedef psImage StreakPixels;
 
 /** Create a list of pixel positions from a Streaks pointer list
Index: branches/pap/magic/remove/src/streaksio.c
===================================================================
--- branches/pap/magic/remove/src/streaksio.c	(revision 23948)
+++ branches/pap/magic/remove/src/streaksio.c	(revision 25027)
@@ -10,8 +10,13 @@
 static nebServer *ourNebServer = NULL;
 
+// Assumptions about the file structure of non-raw files
+// The 'image' for each file (image, mask weight) is contained in the first
+// extension. 
+
+
 // open the files required for streaks procesing.
 // if remove is true the calling program is streaksremove and the recovery files are outputs
 // if false the recovery files are inputs
-streakFiles *openFiles(pmConfig *config, bool remove)
+streakFiles *openFiles(pmConfig *config, bool remove, char *program_name)
 {
     bool status;
@@ -21,4 +26,11 @@
 
     sf->config = config;
+    sf->program_name = basename(program_name);
+
+    if (remove) {
+        // remember pointer so that streaksExit can delete temps
+        setStreakFiles(sf);
+    }
+
 
     // error checking is done by sFileOpen. If a file can't be opened we just exit
@@ -59,9 +71,12 @@
     // if we are passed a mask it is camera stage mask and we also
     // need to destreak the chip level mask file as well
+    // If it doesn't exist, we didn't have a camera mask
     if (remove && sf->inMask && (stage == IPP_STAGE_CHIP)) {
-        sf->inChMask = sFileOpen(config, stage, "INPUT.CHMASK", NULL, true);
-        inputBasename = basename(sf->inChMask->name);
-        sf->outChMask = sFileOpen(config, stage, "OUTPUT", inputBasename, true);
-        sf->recChMask = sFileOpen(config, stage, "RECOVERY", inputBasename, false);
+        sf->inChMask = sFileOpen(config, stage, "INPUT.CHMASK", NULL, false);
+        if (sf->inChMask) {
+            inputBasename = basename(sf->inChMask->name);
+            sf->outChMask = sFileOpen(config, stage, "OUTPUT", inputBasename, true);
+            sf->recChMask = sFileOpen(config, stage, "RECOVERY", inputBasename, false);
+        }
     }
 
@@ -74,4 +89,11 @@
         } else {
             sf->recWeight = sFileOpen(config, stage, "RECOVERY.WEIGHT", NULL, true);
+        }
+    }
+    if (remove) {
+        sf->inSources = sFileOpen(config, stage, "SOURCES", NULL, false);
+        if (sf->inSources) {
+            inputBasename = basename(sf->inSources->name);
+            sf->outSources = sFileOpen(config, stage, "OUTPUT", inputBasename, true);
         }
     }
@@ -159,4 +181,33 @@
 }
 
+// figure out if a nebulous instance is a non-destreaked file
+static bool
+nebFileIsDestreaked(sFile *sfile)
+{
+    if (!sfile->resolved_name) {
+        psError(PS_ERR_PROGRAMMING, true, "resolved name is null");
+        return false;
+    }
+    psFits *fits = psFitsOpen(sfile->resolved_name, "r");
+    if (!fits) {
+        psError(PS_ERR_IO, true, "failed open %s", sfile->name);
+        // can't tell if it is a destreaked file
+        return false;
+    }
+    psMetadata *header = psFitsReadHeader(NULL, fits);
+    if (!header) {
+        psError(PS_ERR_IO, true, "failed to read header for: %s", sfile->name);
+        return false;
+    }
+    bool mdok;
+    bool isDestreaked = psMetadataLookupBool(&mdok, header, "PSDESTRK");
+    if (mdok && isDestreaked) {
+        return true;
+    } else {
+        psError(PS_ERR_IO, false, "output file already exists and may not be de-streaked: %s", sfile->name);
+        return false;
+    }
+}
+
 static psString
 resolveFilename(pmConfig *config, sFile *sfile, bool create)
@@ -170,5 +221,11 @@
             // delete the existing file, since there may be more than one
             // instance. It will get created below in pmConfigConvertFilename
-            if (nebFind(server, sfile->name)) {
+            if ((sfile->resolved_name = nebFind(server, sfile->name)) != NULL) {
+                if (!nebFileIsDestreaked(sfile)) {
+                    psError(PS_ERR_IO, false, "attempting to delete file that has not been destreaked %s", sfile->name);
+                    return NULL;
+                }
+                nebFree(sfile->resolved_name);
+                sfile->resolved_name = NULL;
                 nebDelete(server, sfile->name);
             }
@@ -192,5 +249,5 @@
     // all of the keywords in the raw image files written to the output destreaked files
 
-    if (!CHIP_LEVEL_INPUT(stage) && !strcmp(fileSelect, "INPUT")) {
+    if (!outputFilename && !CHIP_LEVEL_INPUT(stage) && !strcmp(fileSelect, "INPUT")) {
         // stage is warp or diff AND fileSelect eq "INPUT"
         // get data from pmFPAfile.
@@ -234,4 +291,6 @@
         sfile->header = (psMetadata*) psMemIncrRefCounter(sfile->pmfile->fpa->hdu->header);
 
+        sfile->nHDU = psFitsGetSize(sfile->pmfile->fits);
+
         return sfile;
     }
@@ -249,5 +308,5 @@
     }
 
-    // if outputFilename is not null name it contains the "directory"
+    // if outputFilename is not null name it contains the "directory" (perhaps with a prefix like SR_)
     // and outputFilename is the basename name of the file (or nebulous key)
     // and the file is to be opened for writing
@@ -333,4 +392,18 @@
 
 void
+addDestreakKeyword(psMetadata *header)
+{
+    psMetadataAddBool(header, PS_LIST_TAIL, "PSDESTRK", PS_META_REPLACE,
+        "Have streaks been removed from image?", true);
+}
+
+void
+addRecoveryKeyword(psMetadata *header)
+{
+    psMetadataAddBool(header, PS_LIST_TAIL, "PSRECOVR", PS_META_REPLACE,
+        "Does this image contain excised streak pixels?", true);
+}
+
+void
 copyPHU(streakFiles *sfiles, bool remove)
 {
@@ -343,6 +416,13 @@
         streaksExit("", PS_EXIT_DATA_ERROR);
     }
-
-    // TODO: add keyword indicating that streaks have been removed
+    psMetadata *recHeader = NULL;
+    if (remove && sfiles->recImage) {
+       recHeader = psMetadataCopy(NULL, imageHeader);
+       addRecoveryKeyword(recHeader);
+    }
+
+    // add keyword indicating that streaks have been removed
+    addDestreakKeyword(imageHeader);
+
     if (!psFitsWriteBlank(sfiles->outImage->fits, imageHeader, NULL)) {
         psError(PS_ERR_IO, false, "failed to write primary header to %s",
@@ -350,10 +430,11 @@
         streaksExit("", PS_EXIT_DATA_ERROR);
     }
-    // TODO: add keyword indicating that this is the recovery image
-    if (remove && sfiles->recImage && !psFitsWriteBlank(sfiles->recImage->fits, imageHeader, NULL)) {
+    if (recHeader && !psFitsWriteBlank(sfiles->recImage->fits, recHeader, NULL)) {
         psError(PS_ERR_IO, false, "failed to write primary header to %s",
             sfiles->recImage->resolved_name);
         streaksExit("", PS_EXIT_DATA_ERROR);
     }
+    psFree(recHeader);
+    recHeader = NULL;
     psFree(imageHeader);
 
@@ -366,5 +447,11 @@
             streaksExit("", 1);
         }
-        // TODO: add keyword indicating that streaks have been removed
+        if (remove && sfiles->recMask) {
+            recHeader = psMetadataCopy(NULL, maskHeader);
+            // add keyword indicating that this is the recovery image
+           addRecoveryKeyword(recHeader);
+        }
+        // add keyword indicating that streaks have been removed
+        addDestreakKeyword(maskHeader);
         if (!psFitsWriteBlank(sfiles->outMask->fits, maskHeader, NULL)) {
             psError(PS_ERR_IO, false, "failed to write primary header to %s",
@@ -372,10 +459,11 @@
             streaksExit("", PS_EXIT_DATA_ERROR);
         }
-        // TODO: add keyword indicating that this is the recovery image
-        if (remove && sfiles->recMask && !psFitsWriteBlank(sfiles->recMask->fits, maskHeader, NULL)) {
+        if (recHeader && !psFitsWriteBlank(sfiles->recMask->fits, recHeader, NULL)) {
             psError(PS_ERR_IO, false, "failed to write primary header to %s",
                 sfiles->recMask->resolved_name);
             streaksExit("", PS_EXIT_DATA_ERROR);
         }
+        psFree(recHeader);
+        recHeader = NULL;
         psFree(maskHeader);
     }
@@ -388,5 +476,12 @@
             streaksExit("", 1);
         }
-        // TODO: add keyword indicating that streaks have been removed
+        if (remove && sfiles->recWeight) {
+            recHeader = psMetadataCopy(NULL, weightHeader);
+            // add keyword indicating that this is a recovery image
+           addRecoveryKeyword(recHeader);
+        }
+
+        // add keyword indicating that streaks have been removed
+        addDestreakKeyword(weightHeader);
         if (!psFitsWriteBlank(sfiles->outWeight->fits, weightHeader, NULL)) {
             psError(PS_ERR_IO, false, "failed to write primary header to %s",
@@ -394,6 +489,5 @@
             streaksExit("", PS_EXIT_DATA_ERROR);
         }
-        // TODO: add keyword indicating that this is a recovery image
-        if (remove && sfiles->recWeight && !psFitsWriteBlank(sfiles->recWeight->fits, weightHeader, NULL)) {
+        if (recHeader && !psFitsWriteBlank(sfiles->recWeight->fits, recHeader, NULL)) {
             psError(PS_ERR_IO, false, "failed to write primary header to %s",
                 sfiles->recWeight->resolved_name);
@@ -401,4 +495,5 @@
         }
         psFree(weightHeader);
+        psFree(recHeader);
     }
 }
@@ -530,5 +625,5 @@
         streaksExit("", PS_EXIT_DATA_ERROR);
     }
-
+ 
     bool status;
     in->extname = psMetadataLookupStr(&status, in->header, "EXTNAME");
@@ -565,5 +660,6 @@
 
 static void
-setFitsOptions(sFile *sfile, int bitpix, float bscale, float bzero)
+setFitsOptions(sFile *sfile, int bitpix, float bscale, float bzero, psFitsCompressionType compType,
+    psVector *tiles)
 {
     if (!sfile) {
@@ -578,9 +674,17 @@
     sfile->fits->options->bscale = bscale;
     sfile->fits->options->bzero = bzero;
-}
-
-void
-copyFitsOptions(sFile *out, sFile *rec, sFile *in)
-{
+
+    psFitsSetCompression(sfile->fits, compType, tiles, 8, 0, 0);
+}
+
+void
+copyFitsOptions(sFile *out, sFile *rec, sFile *in, psVector *tiles)
+{
+    bool mdok;
+    psString compTypeStr = psMetadataLookupStr(&mdok, in->header, "ZCMPTYPE");
+    psFitsCompressionType compType = psFitsCompressionTypeFromString(compTypeStr);
+    if (compType == PS_FITS_COMPRESS_NONE) {
+        return;
+    }
     // Get current BITPIX, BSCALE, BZERO, EXTNAME
     // Probably not necessary to look the numerical values up in this
@@ -609,8 +713,7 @@
 
 #ifdef STREAKS_COMPRESS_OUTPUT
-    // Paul says that I should be able to leave this blank
-    bitpix = 0;
-    setFitsOptions(out, bitpix, bscale, bzero);
-    setFitsOptions(rec, bitpix, bscale, bzero);
+    // printf("%d %f %f\n", bitpix, bscale, bzero);
+    setFitsOptions(out, bitpix, bscale, bzero, compType, tiles);
+    setFitsOptions(rec, bitpix, bscale, bzero, compType, tiles);
 #endif
 }
@@ -789,19 +892,27 @@
 
 bool
-replicate(sFile *sfile, void *xattr)
-{
-    if (!sfile->inNebulous) {
+replicate(sFile *outFile, sFile *inFile)
+{
+    if (!outFile->inNebulous) {
         return true;
     }
     nebServer *server = getNebServer(NULL);
 
-    // for now just set "user.copies" to 2
-    if (!nebSetXattr(server, sfile->name, "user.copies", "2",  NEB_REPLACE)) {
-        psError(PM_ERR_UNKNOWN, true, "nebSetXattr failed for %s\n%s", sfile->name, nebErr(server));
+    char *user_copies = nebGetXattr(server, inFile->name, "user.copies");
+    bool free_user_copies = true;
+    if (user_copies == NULL) {
+        user_copies = "2";
+        free_user_copies = false;
+    }
+    if (!nebSetXattr(server, outFile->name, "user.copies", user_copies,  NEB_REPLACE)) {
+        psError(PM_ERR_UNKNOWN, true, "nebSetXattr failed for %s\n%s", outFile->name, nebErr(server));
         return false;
     }
-    if (!nebReplicate(server, sfile->name, NULL, NULL)) {
-        psError(PM_ERR_UNKNOWN, true, "nebSetXattr failed for %s\n%s", sfile->name, nebErr(server));
+    if (!nebReplicate(server, outFile->name, "any", NULL)) {
+        psError(PM_ERR_UNKNOWN, true, "nebReplicate failed for %s\n%s", outFile->name, nebErr(server));
         return false;
+    }
+    if (free_user_copies) {
+        nebFree(user_copies);
     }
     return true;
@@ -816,35 +927,36 @@
     bool status = false;
 
-    // XXX: TODO: need a nebGetXatrr function, but there isn't one
-    // another option would be to take the number of copies to be
-    // created as an option. That way the system could decide
-    // whether to replicate anything other than raw Image files
-    void *xattr = NULL;
-
-    if (!replicate(sfiles->outImage, xattr)) {
+    if (!replicate(sfiles->outImage, sfiles->inImage)) {
         psError(PM_ERR_SYS, false, "failed to replicate outImage.");
         return false;
     }
 
-#ifdef notyet
-    // XXX: don't replicate mask and weight images until we can look up
-    // the input's xattr. There may be a perl program that can getXattr
     if (sfiles->outMask) {
-        // get xattr from input to see if we need to replicate
-        if (!replicate(sfiles->outMask, xattr)) {
+        if (!replicate(sfiles->outMask, sfiles->inMask)) {
             psError(PM_ERR_SYS, false, "failed to replicate outImage.");
             return false;
         }
     }
-    if (sfiles->outWeight) {
-        // get xattr from input to see if we need to replicate
-        if (!replicate(sfiles->outWeight, xattr)) {
+    if (sfiles->outChMask) {
+        if (!replicate(sfiles->outChMask, sfiles->inChMask)) {
             psError(PM_ERR_SYS, false, "failed to replicate outImage.");
             return false;
         }
     }
-#endif
-
-//      replicate the recovery images (if in nebulous)
+    if (sfiles->outWeight) {
+        if (!replicate(sfiles->outWeight, sfiles->inWeight)) {
+            psError(PM_ERR_SYS, false, "failed to replicate outImage.");
+            return false;
+        }
+    }
+
+    if (sfiles->outSources) {
+        if (!replicate(sfiles->outSources, sfiles->inSources)) {
+            psError(PM_ERR_SYS, false, "failed to replicate outSources.");
+            return false;
+        }
+    }
+
+//      XXX: replicate the recovery images (if in nebulous)
 //      perhaps whether we do that or not should be configurable.
 //      Sounds like we need a recipe
@@ -903,4 +1015,18 @@
     }
 
+    if (sfiles->outChMask) {
+        if (!swapOutputToInput(sfiles->inChMask, sfiles->outChMask)) {
+            psError(PM_ERR_SYS, false, "failed to swap instances for chip mask.");
+            return false;
+        }
+    }
+
+    if (sfiles->outSources) {
+        if (!swapOutputToInput(sfiles->inSources, sfiles->outSources)) {
+            psError(PM_ERR_SYS, false, "failed to swap instances for sources.");
+            return false;
+        }
+    }
+
     if (!swapOutputToInput(sfiles->inImage, sfiles->outImage)) {
         psError(PM_ERR_SYS, false, "failed to swap instances for Image.");
@@ -908,4 +1034,5 @@
     }
 
+
     return true;
 }
@@ -914,6 +1041,4 @@
 deleteFile(sFile *sfile)
 {
-#if 0
-    // XXX API for nebDelete has changed; need to fix this later
     if (sfile->inNebulous) {
         nebServer *server = getNebServer(NULL);
@@ -930,5 +1055,4 @@
         }
     }
-#endif
     return true;
 }
@@ -938,20 +1062,21 @@
 {
     if (sfiles->outMask) {
-        if (!deleteFile(sfiles->outMask)) {
-            psError(PM_ERR_SYS, false, "failed to delete Mask.");
-            return false;
-        }
+        deleteFile(sfiles->outMask);
+    }
+
+    if (sfiles->outChMask) {
+        deleteFile(sfiles->outChMask);
     }
 
     if (sfiles->outWeight) {
-        if (!deleteFile(sfiles->outWeight)) {
-            psError(PM_ERR_SYS, false, "failed to delete Weight.");
-            return false;
-        }
-    }
-
-    if (!deleteFile(sfiles->outImage)) {
-        psError(PM_ERR_SYS, false, "failed to delete Image.");
-        return false;
+        deleteFile(sfiles->outWeight);
+    }
+
+    if (sfiles->outImage) {
+        deleteFile(sfiles->outImage);
+    }
+
+    if (sfiles->outSources) {
+        deleteFile(sfiles->outSources);
     }
 
@@ -1018,11 +1143,11 @@
         }
         if (printCounts) {
-            printf("time to NAN mask pixels: %f\n", psTimerClear("NAN_MASKED"));
+            psLogMsg(sfiles->program_name, PS_LOG_INFO, "time to NAN mask pixels: %f\n", psTimerClear("NAN_MASKED"));
             int totalPixels = image->numRows * image->numCols;
-            printf("pixels:        %10ld\n", totalPixels);
-            printf("masked pixels: %10ld %4.2f%%\n", maskedPixels, 100. * maskedPixels / totalPixels);
-            printf("nand pixels:   %10ld %4.2f%%\n", nandPixels, 100. * nandPixels / totalPixels);
+            psLogMsg(sfiles->program_name, PS_LOG_INFO, "pixels:        %10ld\n", totalPixels);
+            psLogMsg(sfiles->program_name, PS_LOG_INFO, "masked pixels: %10ld %4.2f%%\n", maskedPixels, 100. * maskedPixels / totalPixels);
+            psLogMsg(sfiles->program_name, PS_LOG_INFO, "nand pixels:   %10ld %4.2f%%\n", nandPixels, 100. * nandPixels / totalPixels);
             if (weight) {
-                printf("nand weights:  %10ld %4.2f%%\n", nandWeights, 100. * nandWeights / totalPixels);
+                psLogMsg(sfiles->program_name, PS_LOG_INFO, "nand weights:  %10ld %4.2f%%\n", nandWeights, 100. * nandWeights / totalPixels);
             }
         }
@@ -1050,5 +1175,5 @@
 strkGetMaskValues(streakFiles *sfiles, psU32 *maskStreak, psU32 *maskMask)
 {
-    if (sfiles->inMask->header) {
+    if (sfiles->inMask && sfiles->inMask->header) {
         if (!pmConfigMaskReadHeader(sfiles->config, sfiles->inMask->header)) {
             streaksExit("failed to read mask values from file", PS_EXIT_CONFIG_ERROR);
@@ -1080,2 +1205,59 @@
     *maskMask = ~convPoor;
 }
+
+static void
+doCopyExtraExtensions(streakFiles *sf, sFile *in, sFile *out)
+{
+    for (int extnum = sf->extnum; extnum < in->nHDU; extnum++) {
+        moveExt(in, extnum);
+        readImage(in, extnum, sf->stage, false);
+
+        if (SFILE_IS_IMAGE(in)) {
+            // Turn off compression (code adapted from pmFPAWrite)
+#ifdef SAVE_AND_RESTORE_COMPRESSION
+            int bitpix = out->fits->options ? out->fits->options->bitpix : 0; // Desired bits per pixel
+            psFitsCompression *compress = psFitsCompressionGet(out->fits); // Current compression options
+#endif
+            if (!psFitsSetCompression(out->fits, PS_FITS_COMPRESS_NONE, NULL, 0, 0, 0)) {
+                psError(PM_ERR_UNKNOWN, false, "failed to turn off compression for extension %d\n", extnum);
+                streaksExit("", PS_EXIT_UNKNOWN_ERROR);
+            }
+#ifdef SAVE_AND_RESTORE_COMPRESSION
+            if (out->fits->options) {
+                out->fits->options->bitpix = 0;
+            }
+            if (!psFitsWriteImage(out->fits, in->header, in->image, 0, in->extname)) {
+                psError(PM_ERR_UNKNOWN, false, "failed to write image for extension %d\n", extnum);
+                streaksExit("", PS_EXIT_UNKNOWN_ERROR);
+            }
+            if (out->fits->options) {
+                out->fits->options->bitpix = bitpix;
+            }
+            if (!psFitsCompressionApply(out->fits, compress)) {
+                psError(PM_ERR_UNKNOWN, false, "failed to rest compression image for extension %d\n", extnum);
+                streaksExit("", PS_EXIT_UNKNOWN_ERROR);
+            }
+#endif
+        } else {
+            copyTable(out, in, extnum);
+        }
+    }
+}
+
+void
+copyExtraExtensions(streakFiles *sf)
+{
+    // XXX: Bad assumption, the begining of the mask and weight files have the same structure as the image
+    // So we are currently at the image portion
+    sf->extnum = sf->inImage->nHDU;
+
+    if (sf->inWeight && sf->outWeight) {
+        doCopyExtraExtensions(sf, sf->inWeight, sf->outWeight);
+    }
+    if (sf->inMask && sf->outMask) {
+        doCopyExtraExtensions(sf, sf->inMask, sf->outMask);
+    }
+    if (sf->inChMask && sf->outChMask) {
+        doCopyExtraExtensions(sf, sf->inChMask, sf->outChMask);
+    }
+}
Index: branches/pap/magic/remove/src/streaksio.h
===================================================================
--- branches/pap/magic/remove/src/streaksio.h	(revision 23948)
+++ branches/pap/magic/remove/src/streaksio.h	(revision 25027)
@@ -2,5 +2,5 @@
 #define STREAKS_IO_H 1
 
-streakFiles *openFiles(pmConfig *config, bool remove);
+streakFiles *openFiles(pmConfig *config, bool remove, char *program_name);
 
 sFile *sFileOpen(pmConfig *config, ippStage stage, psString fileSelect,
@@ -14,12 +14,16 @@
 void copyPHU(streakFiles *sfiles, bool remove);
 void copyTable(sFile *out, sFile *in, int extnum);
-void copyFitsOptions(sFile *out, sFile *rec, sFile *in);
+void copyFitsOptions(sFile *out, sFile *rec, sFile *in, psVector *tiles);
 void setupImageRefs(sFile *out, sFile *recoveryOut, sFile *in, int extnum, bool exciseAll);
 void strkGetMaskValues(streakFiles *sfiles, psU32 *maskStreak, psU32 *maskMask);
+void copyExtraExtensions(streakFiles *sfiles);
 
 void writeImage(sFile *sfile, psString extname, int extnum);
 void writeImageCube(sFile *sfile, psArray *imagecube, psString extname, int extnum);
-bool replicate(sFile *sfile, void *xattr);
+bool replicate(sFile *outFile, sFile *inFile);
 void readImageFrom_pmFile(streakFiles *sf);
+
+void addDestreakKeyword(psMetadata *);
+void addRecoveryKeyword(psMetadata *);
 
 bool streakFilesNextExtension(streakFiles *sf);
Index: branches/pap/magic/remove/src/streaksrelease.c
===================================================================
--- branches/pap/magic/remove/src/streaksrelease.c	(revision 23948)
+++ branches/pap/magic/remove/src/streaksrelease.c	(revision 25027)
@@ -23,19 +23,10 @@
     }
 
-    psMetadata *masks = psMetadataLookupMetadata(&status, config->recipes, "MASKS");
-    if (!status) {
-        psError(PM_ERR_CONFIG, false, "failed to lookup MASKS in recipes\n");
-        return PS_EXIT_CONFIG_ERROR;
-    }
-    psU8 poorWarp = (double) psMetadataLookupU8(&status, masks, "POOR.WARP");
-    if (!status) {
-        psError(PM_ERR_CONFIG, false, "failed to lookup mask value for POOR.WARP in recipes\n");
-        return PS_EXIT_CONFIG_ERROR;
-    }
-    // we're setting pixels with any mask bits execpt POOR.WARP to NAN
-    psU8 maskMask = ~poorWarp;
+    // Values to set for masked pixels
+    psU32 maskStreak = 0;           // for the image and weight (usually NAN, MAXINT for integer images)
+    psU32 maskMask = 0;             // value looked up for MASK.STREAK 
 
     // Does true work here?
-    streakFiles *sfiles = openFiles(config, true);
+    streakFiles *sfiles = openFiles(config, true, argv[0]);
 
     if (sfiles->stage == IPP_STAGE_RAW) {
@@ -64,4 +55,9 @@
         }
 
+        // now that we've read the input files, lookup the mask values that we read
+        if (maskStreak == 0) {
+            strkGetMaskValues(sfiles, &maskStreak, &maskMask);
+        }
+
         setMaskedToNAN(sfiles, maskMask, true);
 
@@ -71,4 +67,10 @@
         printf("time to process component %d: %f\n", sfiles->extnum, psTimerClear("PROCESS_COMPONENT"));
     } while (streakFilesNextExtension(sfiles));
+
+    // check the weight and mask files for extra extensions that might be in files
+    // (covariance matrix for example)
+    copyExtraExtensions(sfiles);
+
+
 
     psTimerStart("CLOSE_IMAGES");
@@ -77,41 +79,4 @@
     printf("time to close images: %f\n", psTimerClear("CLOSE_IMAGES"));
 
-#ifdef NOTYET
-    if (!replicateOutputs(sfiles)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to replicate output files");
-        psErrorStackPrint(stderr, "");
-        exit(PS_EXIT_UNKNOWN_ERROR);
-    }
-
-    if (psMetadataLookupBool(&status, config->arguments, "REPLACE")) {
-        //     swap the instances for the input and output
-        //     Note this is a database operation. No file I/O is performed
-        if (!swapOutputsToInputs(sfiles)) {
-            psError(PS_ERR_UNKNOWN, false, "failed to swap files");
-
-            // XXX: Now what? I guess swapOutputsToInputs will need to undo anything that
-            // it has done and give a detailed report of what happened
-
-            psErrorStackPrint(stderr, "");
-            exit(PS_EXIT_UNKNOWN_ERROR);
-        }
-
-        if (psMetadataLookupBool(&status, config->arguments, "REMOVE")) {
-            //      delete the temporary storage objects (which now points to the original image(s)
-            if (!deleteTemps(sfiles)) {
-                psError(PS_ERR_UNKNOWN, false, "failed to delete temporary files");
-                // XXX: Now what? At this point the output files have been swapped, so we can't
-                // repeat the operation.
-
-                // Returning error status here is problematic. The inputs have been streak removed
-                // but they're still lying around
-                // Maybe just print an error message and
-                // let other system tools clean up
-                psErrorStackPrint(stderr, "");
-                exit(PS_EXIT_UNKNOWN_ERROR);
-            }
-        }
-    }
-#endif  // REPLACE, REMOVE
     printf("time to run streaksrelease: %f\n", psTimerClear("STREAKSREMOVE"));
 
@@ -275,17 +240,5 @@
 
     // set up the compression parameters
-#ifdef STREAKS_COMPRESS_OUTPUT
-    // compression of the image pixels is disabled for now. Some consortium members
-    // have problems reading them
-    copyFitsOptions(sf->outImage, sf->recImage, sf->inImage);
-
-    // XXX: TODO: can we derive these values from the input header?
-    // psFitsCompressionGet(sf->inImage->image) gives compression none
-    // perhaps we should just use the definition of COMP_IMG in the configuration 
-    psFitsSetCompression(sf->outImage->fits, PS_FITS_COMPRESS_RICE, sf->tiles, 8, 0, 0);
-    if (sf->recImage) {
-        psFitsSetCompression(sf->recImage->fits, PS_FITS_COMPRESS_RICE, sf->tiles, 8, 0, 0);
-    }
-#endif
+    copyFitsOptions(sf->outImage, sf->recImage, sf->inImage, sf->tiles);
 
     if (sf->inMask) {
@@ -306,19 +259,8 @@
             }
 
-#ifdef STREAKS_COMPRESS_OUTPUT
-            // XXX: see note above
-            copyFitsOptions(sf->outMask, sf->recMask, sf->inMask);
-            psFitsSetCompression(sf->outMask->fits, PS_FITS_COMPRESS_PLIO, sf->tiles, 8, 0, 0);
-            if (sf->recMask) {
-                psFitsSetCompression(sf->recMask->fits, PS_FITS_COMPRESS_PLIO, sf->tiles, 8, 0, 0);
-            }
+            copyFitsOptions(sf->outMask, sf->recMask, sf->inMask, sf->tiles);
             if (sf->outChMask) {
-                copyFitsOptions(sf->outChMask, sf->recChMask, sf->inMask);
-                psFitsSetCompression(sf->outChMask->fits, PS_FITS_COMPRESS_PLIO, sf->tiles, 8, 0, 0);
-                if (sf->recChMask) {
-                    psFitsSetCompression(sf->recChMask->fits, PS_FITS_COMPRESS_PLIO, sf->tiles, 8, 0, 0);
-                }
-            }
-#endif
+                copyFitsOptions(sf->outChMask, sf->recChMask, sf->inMask, sf->tiles);
+            }
         }
     }
@@ -332,12 +274,5 @@
         setupImageRefs(sf->outWeight, sf->recWeight, sf->inWeight, sf->extnum, exciseAll);
 
-#ifdef STREAKS_COMPRESS_OUTPUT
-        copyFitsOptions(sf->outWeight, sf->recWeight, sf->inWeight);
-        // XXX: see note above
-        psFitsSetCompression(sf->outWeight->fits, PS_FITS_COMPRESS_RICE, sf->tiles, 8, 0, 0);
-        if (sf->recWeight) {
-            psFitsSetCompression(sf->recWeight->fits, PS_FITS_COMPRESS_RICE, sf->tiles, 8, 0, 0);
-        }
-#endif
+        copyFitsOptions(sf->outWeight, sf->recWeight, sf->inWeight, sf->tiles);
     }
     // and for raw images, create sub images that represent the actual image
Index: branches/pap/magic/remove/src/streaksremove.c
===================================================================
--- branches/pap/magic/remove/src/streaksremove.c	(revision 23948)
+++ branches/pap/magic/remove/src/streaksremove.c	(revision 25027)
@@ -1,2 +1,11 @@
+/*
+ * streaksremove
+ *
+ * Convert satellite streak detctions into masks and remove the covered pixels from the
+ * input images.
+ * Optionally swap the inputs with the outputs so that subsequent references to the original
+ * images access the destreaked versions.
+ */
+
 #include "streaksremove.h"
 
@@ -4,8 +13,9 @@
 static bool readAndCopyToOutput(streakFiles *sf, bool exciseAll);
 static void exciseNonWarpedPixels(streakFiles *sfiles, double newMaskValue);
-static bool warpedPixel(streakFiles *sfiles, PixelPos *cellCoord);
+static bool warpedPixel(streakFiles *sfiles, int x, int y);
 static void excisePixel(streakFiles *sfiles, unsigned int x, unsigned int y, bool streak, double newMaskValue);
 static void writeImages(streakFiles *sf, bool exciseImageCube);
 static void updateAstrometry(streakFiles *sfiles);
+static void censorSources(streakFiles *sfiles, psU32 maskStreak);
 
 int
@@ -23,18 +33,24 @@
     }
 
-    psU32 maskStreak = 0;
-    psU32 maskMask = 0;
+    // Values to set for masked pixels
+    psU32 maskStreak = 0;           // for the image and weight (usually NAN, MAXINT for integer images)
+    psU32 maskMask = 0;             // value looked up for MASK.STREAK 
 
     psString streaksFileName = psMetadataLookupStr(NULL, config->arguments, "STREAKS");
 
+    // call Paul Sydney's code to parse the streaks file that DetectStreaks produced
     Streaks *streaks = readStreaksFile(streaksFileName);
     if (!streaks) {
-        psErrorStackPrint(stderr, "failed to read streaks file: %s", streaksFileName);
+        psError(PS_ERR_UNKNOWN, "failed to read streaks file: %s", streaksFileName);
         streaksExit("", PS_EXIT_PROG_ERROR);
     }
 
-    streakFiles *sfiles = openFiles(config, true);
+    // open all of the input and output files, save their descriptions in the streakFiles struct
+    streakFiles *sfiles = openFiles(config, true, argv[0]);
     setupAstrometry(sfiles);
 
+    // Optionally we can set pixels that are masked to NAN since they couldn't have been
+    // examined for streaks. Usually this is done by the distribution system just prior
+    // to release
     bool nanForRelease = psMetadataLookupBool(&status, config->arguments, "NAN_FOR_RELEASE");
     if (nanForRelease && (sfiles->inMask == NULL)) {
@@ -52,5 +68,5 @@
 
     if (checkNonWarpedPixels ) {
-        // From ICD:
+        // From magic ICD:
         // In the raw and detrended images, the pixels which were not
         // included in any of the streak-processed warps must also be masked.
@@ -65,9 +81,11 @@
         }
         psF64 cwp_t = psTimerClear("COMPUTE_WARPED_PIXELS");
-        printf("time to compute warped pixels: %f\n", cwp_t);
+        psLogMsg("streaksremove", PS_LOG_INFO, "time to compute warped pixels: %f\n", cwp_t);
     }
     
     if (sfiles->stage == IPP_STAGE_RAW) {
-        // copy PHU to output files
+        // Except for raw stage, all of our (GPC1) files have one image extension.
+        // Raw files have a phu and multiple extensions, one per chip
+        // Since this is a raw file, copy it's PHU to output files
         copyPHU(sfiles, true);
 
@@ -82,5 +100,5 @@
     int totalStreakPixels = 0;
 
-    // Iterate through each component of the input (there is only one except for raw images)
+    // Iterate through each component of the input (except for raw images there is only one)
     do {
         bool exciseImageCube = false;
@@ -110,10 +128,11 @@
             psTimerStart("GET_STREAK_PIXELS");
 
-            StreakPixels *pixels = streak_on_component (streaks, sfiles->astrom,
-                                      sfiles->inImage->numCols, sfiles->inImage->numRows);
-
-            printf("time to get streak pixels: %f\n", psTimerClear("GET_STREAK_PIXELS"));
-
+            // call Paul Sydney's code to compute the set of pixels that are covered by the detected streaks
+            StreakPixels *pixels = streak_on_component(streaks, sfiles->astrom, sfiles->inImage->numCols,
+                                                        sfiles->inImage->numRows);
+            psLogMsg("streaksremove", PS_LOG_INFO, "time to get streak pixels: %f\n", psTimerClear("GET_STREAK_PIXELS"));
             
+            // if this extension contained an image, excise the streaked pixels.
+            // otherwise it contained an image cube (video cell) which is handled in the if block
             if (sfiles->inImage->image) {
                 if (checkNonWarpedPixels) {
@@ -124,91 +143,103 @@
                     exciseNonWarpedPixels(sfiles, maskStreak);
 
-                    printf("time to excise non warped pixels: %f\n", psTimerClear("EXCISE_NON_WARPED"));
+                    psLogMsg("streaksremove", PS_LOG_INFO, "time to excise non warped pixels: %f\n", psTimerClear("EXCISE_NON_WARPED"));
                 }
-                totalStreakPixels +=  psArrayLength(pixels);
+
+
                 psTimerStart("REMOVE_STREAKS");
-                for (int i = 0; i < psArrayLength (pixels); ++i) {
-                    PixelPos *pixelPos = psArrayGet (pixels, i);
-
-                    if (!checkNonWarpedPixels || warpedPixel(sfiles, pixelPos)) {
-
-                        excisePixel(sfiles, pixelPos->x, pixelPos->y, true, maskStreak);
-
-                    } else {
-                        // This pixel was not included in any warp and has thus already excised
-                        // by exciseNonWarpedPixels
+
+                for (int y=0 ; y < sfiles->inImage->numRows; y++) {
+                    for (int x = 0; x < sfiles->inImage->numCols; x++) {
+                        if (psImageGet(pixels, x, y)) {
+                            ++totalStreakPixels;
+                            if (!checkNonWarpedPixels || warpedPixel(sfiles, x, y)) {
+
+                                excisePixel(sfiles, x, y, true, maskStreak);
+
+                            } else {
+                                // This pixel was not included in any warp and has thus already excised
+                                // by exciseNonWarpedPixels
+                            }
+                        }
                     }
                 }
-                printf("time to remove streak pixels: %f\n", psTimerClear("REMOVE_STREAKS"));
+
+                psLogMsg("streaksremove", PS_LOG_INFO, "time to remove streak pixels: %f\n", psTimerClear("REMOVE_STREAKS"));
 
                 if (nanForRelease) {
+                    // set any pixels that were masked, to NAN (unless they are already NAN)
                     setMaskedToNAN(sfiles, maskMask, true);
                 }
 
             } else { 
-                // this component contains an image cube, excise it completely
+                // this component contains an image cube
+                // For now excise it completely
                 exciseImageCube = true;
             }
-            psArrayElementsFree (pixels);
             psFree(pixels);
         }
 
         if (sfiles->stage == IPP_STAGE_CHIP) {
+            // as a convience to the user of the output, replace the bogus WCS transform in the
+            // chip processed files with the data calcuated by psastro at the camera stage
+            // (actually we use a linear approximation)
             updateAstrometry(sfiles);
         }
 
-        // write out the destreaked temporary images and the recovery images
+        censorSources(sfiles, maskStreak);
+
+        // write the destreaked "temporary" images and the recovery images
         writeImages(sfiles, exciseImageCube);
 
-        printf("time to process component %d: %f\n", sfiles->extnum, psTimerClear("PROCESS_COMPONENT"));
+
+        psLogMsg("streaksremove", PS_LOG_INFO, "time to process component %d: %f\n", sfiles->extnum, psTimerClear("PROCESS_COMPONENT"));
     } while (streakFilesNextExtension(sfiles));
 
+
     psFree(streaks);
 
-    printf("pixels: %ld streak pixels: %ld %4.2f%%\n", totalPixels, totalStreakPixels, 100. * totalStreakPixels / totalPixels);
+    psLogMsg("streaksremove", PS_LOG_INFO, "pixels: %ld streak pixels: %ld %4.2f%%\n", totalPixels, totalStreakPixels, 100. * totalStreakPixels / totalPixels);
+
+    // check the weight and mask files for extra extensions that might be in files
+    // (covariance matrix for example)
+    copyExtraExtensions(sfiles);
+
+    // all done close the files. This is where the files are written so it can take a long time.
 
     psTimerStart("CLOSE_IMAGES");
-    // close all files
+
     closeImages(sfiles);
-    printf("time to close images: %f\n", psTimerClear("CLOSE_IMAGES"));
+
+    psLogMsg("streaksremove", PS_LOG_INFO, "time to close images: %f\n", psTimerClear("CLOSE_IMAGES"));
+
+
+    if (!replicateOutputs(sfiles)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to replicate output files");
+        deleteTemps(sfiles);
+        psErrorStackPrint(stderr, "");
+        exit(PS_EXIT_UNKNOWN_ERROR);
+    }
 
     // NOTE: from here on we can't just quit if something goes wrong.
     // especially if we're working at the raw stage
-
-    if (!replicateOutputs(sfiles)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to replicate output files");
-        psErrorStackPrint(stderr, "");
-        exit(PS_EXIT_UNKNOWN_ERROR);
-    }
+    // turn off automatic deletion of output files by streaksExit
+    setStreakFiles(NULL);
 
     if (psMetadataLookupBool(&status, config->arguments, "REPLACE")) {
         //     swap the instances for the input and output
-        //     Note this is a database operation. No file I/O is performed
+        //     Note this is a nebulous database operation. No file I/O is performed
         if (!swapOutputsToInputs(sfiles)) {
-            psError(PS_ERR_UNKNOWN, false, "failed to swap files");
-
-            // XXX: Now what? I guess swapOutputsToInputs will need to undo anything that
-            // it has done and give a detailed report of what happened
-
-            psErrorStackPrint(stderr, "");
+            // XXX: Now what?
+            // It is up to the program that reverts failed destreak runs to insure that
+            // any input files that have been swapped are restored and that the de-streaked
+            // versions are deleted
+
+            psErrorStackPrint(stderr, "failed to swap files");
+
+            // XXX: pick a specific error code for this failure
             exit(PS_EXIT_UNKNOWN_ERROR);
         }
-
-        if (psMetadataLookupBool(&status, config->arguments, "REMOVE")) {
-            //      delete the temporary storage objects (which now points to the original image(s)
-            if (!deleteTemps(sfiles)) {
-                psError(PS_ERR_UNKNOWN, false, "failed to delete temporary files");
-                // XXX: Now what? At this point the output files have been swapped, so we can't
-                // repeat the operation.
-
-                // Returning error status here is problematic. The inputs have been streak removed
-                // but they're still lying around
-                // Maybe just print an error message and
-                // let other system tools clean up
-                psErrorStackPrint(stderr, "");
-                exit(PS_EXIT_UNKNOWN_ERROR);
-            }
-        }
-    }
+    }
+    // all done. Clean up to look for memory leaks.
 
     psFree(sfiles);
@@ -218,5 +249,5 @@
     streaksNebulousCleanup(); 
     pmConfigDone();
-    printf("time to run streaksremove: %f\n", psTimerClear("STREAKSREMOVE"));
+    psLogMsg("streaksremove", PS_LOG_INFO, "time to run streaksremove: %f\n", psTimerClear("STREAKSREMOVE"));
     psLibFinalize();
 
@@ -235,5 +266,4 @@
     fprintf(stderr, "\t-weight WEIGHT.fits: weight file to de-streak\n");
     fprintf(stderr, "\t-replace: replace the input images with the output\n");
-    fprintf(stderr, "\t-remove: remove the original image after processing (requires -replace)\n");
     fprintf(stderr, "\t-keepnonwarped: do not exise pixels that were not part of difference processing\n");
     fprintf(stderr, "\t-transparent val: instead of setting excicsed pixel to NAN add val\n");
@@ -311,4 +341,8 @@
     bool gotReplace = false;
     if ((argnum = psArgumentGet(argc, argv, "-replace"))) {
+        if (!nebulousImage) {
+            psError(PS_ERR_UNKNOWN, true, "replace is only supported for nebulous files");
+            usage();
+        }
         gotReplace = true;
         psArgumentRemove(argnum, &argc, argv);
@@ -394,4 +428,16 @@
         psArgumentRemove(argnum, &argc, argv);
     }
+    if ((argnum = psArgumentGet(argc, argv, "-sources"))) {
+        psArgumentRemove(argnum, &argc, argv);
+        bool nebulousSources = IN_NEBULOUS(argv[argnum]);
+        if (nebulousSources != nebulousImage) {
+            psError(PS_ERR_UNKNOWN, true, "sources file must have %snebulous path with %s image path\n",
+                nebulousImage ? "" : "non ", nebulousImage ? "nebulous" : "regular");
+            usage();
+        }
+        psMetadataAddStr(config->arguments, PS_LIST_TAIL, "SOURCES", 0,
+                "name of input sources file", argv[argnum]);
+        psArgumentRemove(argnum, &argc, argv);
+    }
 
     if ((argnum = psArgumentGet(argc, argv, "-tmproot"))) {
@@ -403,8 +449,6 @@
             usage();
         }
-        psString dir = pathToDirectory(argv[argnum]);
-        psMetadataAddStr(config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "directory for temporary files",
-            dir);
-        psFree(dir);
+        psMetadataAddStr(config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "path for (temporary if replae) output files",
+            argv[argnum]);
         psArgumentRemove(argnum, &argc, argv);
     } else {
@@ -415,22 +459,10 @@
     if ((argnum = psArgumentGet(argc, argv, "-recovery"))) {
         psArgumentRemove(argnum, &argc, argv);
-        psString dir = pathToDirectory(argv[argnum]);
-        psMetadataAddStr(config->arguments, PS_LIST_TAIL, "RECOVERY", 0, "directory for recovery files",
-            dir);
-        psFree(dir);
+        psMetadataAddStr(config->arguments, PS_LIST_TAIL, "RECOVERY", 0, "path for recovery files",
+            argv[argnum]);
         psArgumentRemove(argnum, &argc, argv);
     } else if ((stage == IPP_STAGE_RAW) && gotReplace) {
         psError(PS_ERR_UNKNOWN, true, "-recovery is required for -stage raw with -replace\n");
         usage();
-    }
-
-    if ((argnum = psArgumentGet(argc, argv, "-remove"))) {
-        if (!gotReplace) {
-            psError(PS_ERR_UNKNOWN, true, "-replace is required with -remove\n");
-            usage();
-        }
-        psArgumentRemove(argnum, &argc, argv);
-        psMetadataAddBool(config->arguments, PS_LIST_TAIL, "REMOVE", 0, "remove original files",
-            true);
     }
 
@@ -451,7 +483,11 @@
 updateAstrometry(streakFiles *sf)
 {
+    // XXX: why do I check this here? Shouldn't it be just around the call to linearizeTransforms?
     if (sf->bilevelAstrometry) {
 
-        linearizeTransforms(sf->astrom);
+        if (!linearizeTransforms(sf->astrom)) {
+            // fit failed, leave the astrometry unchanged
+            return;
+        }
 
         if (!pmAstromWriteWCS(sf->outImage->header, sf->inAstrom->fpa, sf->chip, 0.001)) {
@@ -501,8 +537,10 @@
         }
     }
-    sf->outImage->header = (psMetadata*) psMemIncrRefCounter(sf->inImage->header);
+    sf->outImage->header =  psMemIncrRefCounter(sf->inImage->header);
     if (sf->recImage) {
-        sf->recImage->header = (psMetadata*) psMemIncrRefCounter(sf->inImage->header);
-    }
+        sf->recImage->header = psMetadataCopy(NULL, sf->inImage->header);
+        addRecoveryKeyword(sf->recImage->header);
+    }
+    addDestreakKeyword(sf->outImage->header);
 
     if (!SFILE_IS_IMAGE(sf->inImage)) {
@@ -520,17 +558,5 @@
 
     // set up the compression parameters
-#ifdef STREAKS_COMPRESS_OUTPUT
-    // compression of the image pixels is disabled for now. Some consortium members
-    // have problems reading them
-    copyFitsOptions(sf->outImage, sf->recImage, sf->inImage);
-
-    // XXX: TODO: can we derive these values from the input header?
-    // psFitsCompressionGet(sf->inImage->image) gives compression none
-    // perhaps we should just use the definition of COMP_IMG in the configuration 
-    psFitsSetCompression(sf->outImage->fits, PS_FITS_COMPRESS_RICE, sf->tiles, 8, 0, 0);
-    if (sf->recImage) {
-        psFitsSetCompression(sf->recImage->fits, PS_FITS_COMPRESS_RICE, sf->tiles, 8, 0, 0);
-    }
-#endif
+    copyFitsOptions(sf->outImage, sf->recImage, sf->inImage, sf->tiles);
 
     if (sf->inMask) {
@@ -539,6 +565,8 @@
             sf->outMask->header = (psMetadata*) psMemIncrRefCounter(sf->inMask->header);
             if (sf->recMask) {
-                sf->recMask->header = (psMetadata*) psMemIncrRefCounter(sf->inMask->header);
-            }
+                sf->recMask->header = psMetadataCopy(NULL, sf->outMask->header);
+                addRecoveryKeyword(sf->recMask->header);
+            }
+            addDestreakKeyword(sf->outMask->header);
             if (updateAstrometry) {
                 pmAstromWriteWCS(sf->outMask->header, sf->inAstrom->fpa, sf->chip, 0.001);
@@ -554,19 +582,8 @@
             }
 
-#ifdef STREAKS_COMPRESS_OUTPUT
-            // XXX: see note above
-            copyFitsOptions(sf->outMask, sf->recMask, sf->inMask);
-            psFitsSetCompression(sf->outMask->fits, PS_FITS_COMPRESS_PLIO, sf->tiles, 8, 0, 0);
-            if (sf->recMask) {
-                psFitsSetCompression(sf->recMask->fits, PS_FITS_COMPRESS_PLIO, sf->tiles, 8, 0, 0);
-            }
+            copyFitsOptions(sf->outMask, sf->recMask, sf->inMask, sf->tiles);
             if (sf->outChMask) {
-                copyFitsOptions(sf->outChMask, sf->recChMask, sf->inMask);
-                psFitsSetCompression(sf->outChMask->fits, PS_FITS_COMPRESS_PLIO, sf->tiles, 8, 0, 0);
-                if (sf->recChMask) {
-                    psFitsSetCompression(sf->recChMask->fits, PS_FITS_COMPRESS_PLIO, sf->tiles, 8, 0, 0);
-                }
-            }
-#endif
+                copyFitsOptions(sf->outChMask, sf->recChMask, sf->inMask, sf->tiles);
+            }
         }
     }
@@ -576,6 +593,8 @@
         sf->outWeight->header = (psMetadata*) psMemIncrRefCounter(sf->inWeight->header);
         if (sf->recWeight) {
-            sf->recWeight->header = (psMetadata*) psMemIncrRefCounter(sf->inWeight->header);
-        }
+            sf->recWeight->header = psMetadataCopy(NULL, sf->outWeight->header);
+            addRecoveryKeyword(sf->recWeight->header);
+        }
+        addDestreakKeyword(sf->outWeight->header);
         if (updateAstrometry) {
             pmAstromWriteWCS(sf->inWeight->header, sf->inAstrom->fpa, sf->chip, 0.001);
@@ -583,20 +602,9 @@
         setupImageRefs(sf->outWeight, sf->recWeight, sf->inWeight, sf->extnum, exciseAll);
 
-#ifdef STREAKS_COMPRESS_OUTPUT
-        copyFitsOptions(sf->outWeight, sf->recWeight, sf->inWeight);
-        // XXX: see note above
-        psFitsSetCompression(sf->outWeight->fits, PS_FITS_COMPRESS_RICE, sf->tiles, 8, 0, 0);
-        if (sf->recWeight) {
-            psFitsSetCompression(sf->recWeight->fits, PS_FITS_COMPRESS_RICE, sf->tiles, 8, 0, 0);
-        }
-#endif
-    }
-    // and for raw images, create sub images that represent the actual image
-    // area (no overscan)
+        copyFitsOptions(sf->outWeight, sf->recWeight, sf->inWeight, sf->tiles);
+    }
 
     return true;
 }
-
-
 
 static void
@@ -746,5 +754,5 @@
 
 static bool
-warpedPixel(streakFiles *sfiles, PixelPos *cellCoord)
+warpedPixel(streakFiles *sfiles, int x, int y)
 {
     PixelPos chipCoord;
@@ -757,10 +765,10 @@
     // we clip so that the streak calculation code doesn't have to
     // clipping here insures that we don't touch the overscan regions
-    if ((cellCoord->x < 0) || (cellCoord->x >= sfiles->inImage->numCols) ||
-        (cellCoord->y < 0) || (cellCoord->y >= sfiles->inImage->numRows)) {
+    if ((x < 0) || (x >= sfiles->inImage->numCols) ||
+        (y < 0) || (y >= sfiles->inImage->numRows)) {
         return false;
     }
 
-    cellToChipInt(&chipCoord.x, &chipCoord.y, sfiles->astrom, cellCoord->x, cellCoord->y);
+    cellToChipInt(&chipCoord.x, &chipCoord.y, sfiles->astrom, x, y);
 
     if (chipCoord.x < 0 || chipCoord.x >= sfiles->warpedPixels->numCols) {
@@ -774,2 +782,80 @@
 }
 
+// read a sources file (.cmf) and remove any rows whose coordinate is convered by a
+// streak mask
+static void
+censorSources(streakFiles *sfiles, psU32 maskStreak)
+{
+    if ((!sfiles->inSources) || (!sfiles->outMask)) {
+        return;
+    }
+    psImage *maskImage = sfiles->outMask->image;
+    if (!maskImage) {
+        psError(PS_ERR_IO, false, "maskImage is null!");
+        streaksExit("", PS_EXIT_PROG_ERROR);
+    }
+
+    sFile *in = sfiles->inSources;
+    sFile *out = sfiles->outSources;
+
+    in->header = psFitsReadHeader(NULL, in->fits);
+    if (!in->header) {
+        psError(PS_ERR_IO, false, "failed to read header from %s", in->resolved_name);
+        streaksExit("", PS_EXIT_DATA_ERROR);
+    }
+
+    bool status;
+    psString extname = psMetadataLookupStr(&status, in->header, "EXTNAME");
+    if (!extname) {
+        psError(PS_ERR_IO, false, "failed to find extname in header of %s", in->resolved_name);
+        streaksExit("", PS_EXIT_DATA_ERROR);
+    }
+
+    psArray *inTable = psFitsReadTable(in->fits);
+    if (!inTable->n) {
+        psError(PS_ERR_IO, false, "table in %s is empty", in->resolved_name);
+        streaksExit("", PS_EXIT_DATA_ERROR);
+    }
+
+    psArray *outTable = psArrayAllocEmpty(inTable->n);
+    int j = 0;
+    int numCensored = 0;
+    for (int i = 0 ; i < inTable->n; i++) {
+        psMetadata *row = inTable->data[i];
+
+        psF32 x = psMetadataLookupF32 (&status, row, "X_PSF");
+        psF32 y = psMetadataLookupF32 (&status, row, "Y_PSF");
+        
+        psU32 mask = psImageGet(maskImage, x, y);
+
+        // Key the source if the center pixel is not masked with maskStreak
+        if (! (mask & maskStreak) ) {
+            psArraySet(outTable, j++, row);
+        } else {
+            numCensored++;
+        }
+    }
+
+    // get rid of unused elements (don't know if this is necessary)
+    psArrayRealloc(outTable, j);
+
+    addDestreakKeyword(in->header);
+    if (psArrayLength(outTable) > 0) {
+        printf("Censored %d sources\n", numCensored);
+        if (! psFitsWriteTable(out->fits, in->header, outTable, extname)) {
+            psError(PS_ERR_IO, false, "failed to write table to %s", out->resolved_name);
+            streaksExit("", PS_EXIT_DATA_ERROR);
+        }
+    } else {
+        printf("Censored ALL %d sources\n", numCensored);
+        if (! psFitsWriteTableEmpty(out->fits, in->header, inTable->data[0], extname)) {
+            psError(PS_ERR_IO, false, "failed to write empty table to %s", out->resolved_name);
+            streaksExit("", PS_EXIT_DATA_ERROR);
+        }
+    }
+
+    if (!psFitsClose(out->fits)) {
+        psError(PS_ERR_IO, false, "failed to close table %s", out->resolved_name);
+        streaksExit("", PS_EXIT_DATA_ERROR);
+    }
+}
Index: branches/pap/magic/remove/src/streaksremove.h
===================================================================
--- branches/pap/magic/remove/src/streaksremove.h	(revision 23948)
+++ branches/pap/magic/remove/src/streaksremove.h	(revision 25027)
@@ -62,4 +62,6 @@
     sFile *outChMask;
     sFile *recChMask;
+    sFile *inSources;
+    sFile *outSources;
     psString class_id;
     pmFPAfile  *inAstrom;
@@ -72,4 +74,5 @@
     psVector    *tiles;
     double  transparentStreaks;
+    psString    program_name;
 } streakFiles;
 
@@ -87,4 +90,5 @@
 extern ippStage parseStage(psString);
 extern psString pathToDirectory(char *path);
+extern void setStreakFiles( streakFiles *);
 
 #define CHIP_LEVEL_INPUT(_stage) ((_stage == IPP_STAGE_RAW) || (_stage == IPP_STAGE_CHIP))
@@ -94,3 +98,4 @@
 #define IN_NEBULOUS(_filename) (!strncasecmp(_filename, "neb://", strlen("neb://")))
 
+
 #endif // STREAKS_H
Index: branches/pap/magic/remove/src/streaksreplace.c
===================================================================
--- branches/pap/magic/remove/src/streaksreplace.c	(revision 23948)
+++ branches/pap/magic/remove/src/streaksreplace.c	(revision 25027)
@@ -33,5 +33,5 @@
     }
 
-    streakFiles *sfiles = openFiles(config, false);
+    streakFiles *sfiles = openFiles(config, false, argv[0]);
 
     if (sfiles->stage == IPP_STAGE_RAW) {
@@ -97,35 +97,4 @@
     }
 
-#ifdef NOTYET
-    if (psMetadataLookupBool(&status, config->arguments, "REPLACE")) {
-        //     swap the instances for the input and output
-        //     Note this is a database operation. No file I/O is performed
-        if (!swapOutputsToInputs(sfiles)) {
-            psError(PS_ERR_UNKNOWN, false, "failed to swap files");
-
-            // XXX: Now what? I guess swapOutputsToInputs will need to undo anything that
-            // it has done and give a detailed report of what happened
-
-            psErrorStackPrint(stderr, "");
-            exit(PS_EXIT_UNKNOWN_ERROR);
-        }
-
-        if (psMetadataLookupBool(&status, config->arguments, "REMOVE")) {
-            //      delete the temporary storage objects (which now points to the original image(s)
-            if (!deleteTemps(sfiles)) {
-                psError(PS_ERR_UNKNOWN, false, "failed to delete temporary files");
-                // XXX: Now what? At this point the output files have been swapped, so we can't
-                // repeat the operation.
-
-                // Returning error status here is problematic. The inputs have been streak removed
-                // but they're still lying around
-                // Maybe just print an error message and
-                // let other system tools clean up
-                psErrorStackPrint(stderr, "");
-                exit(PS_EXIT_UNKNOWN_ERROR);
-            }
-        }
-    }
-#endif  // REPLACE, REMOVE
 //    nebServerFree(ourNebServer);
     psFree(config);
@@ -344,14 +313,6 @@
 
     // set up the compression parameters
-#ifdef STREAKS_COMPRESS_OUTPUT
-    // compression of the image pixels is disabled for now. Some consortium members
-    // have problems reading compressed images.
-    copyFitsOptions(sf->outImage, sf->recImage, sf->inImage);
-
-    // XXX: TODO: can we derive these values from the input header?
-    // psFitsCompressionGet(sf->inImage->image) gives compression none
-    // perhaps we should just use the definition of COMP_IMG in the configuration 
-    psFitsSetCompression(sf->outImage->fits, PS_FITS_COMPRESS_RICE, sf->tiles, 8, 0, 0);
-#endif
+    copyFitsOptions(sf->outImage, sf->recImage, sf->inImage, sf->tiles);
+
     if (sf->inMask) {
         readImage(sf->inMask, sf->extnum, sf->stage, true);
@@ -362,7 +323,5 @@
         setupImageRefs(sf->outMask, NULL, sf->inMask, sf->extnum, false);
 
-        // XXX: see note above
-        copyFitsOptions(sf->outMask, NULL, sf->inMask);
-        psFitsSetCompression(sf->outMask->fits, PS_FITS_COMPRESS_PLIO, sf->tiles, 8, 0, 0);
+        copyFitsOptions(sf->outMask, NULL, sf->inMask, sf->tiles);
     }
 
@@ -374,7 +333,5 @@
         setupImageRefs(sf->outMask, NULL, sf->inMask, sf->extnum, false);
 
-        copyFitsOptions(sf->outWeight, NULL, sf->inWeight);
-        // XXX: see note above
-        psFitsSetCompression(sf->outWeight->fits, PS_FITS_COMPRESS_RICE, sf->tiles, 8, 0, 0);
+        copyFitsOptions(sf->outWeight, NULL, sf->inWeight, sf->tiles);
     }
 
Index: branches/pap/magic/remove/src/streaksutil.c
===================================================================
--- branches/pap/magic/remove/src/streaksutil.c	(revision 23948)
+++ branches/pap/magic/remove/src/streaksutil.c	(revision 25027)
@@ -33,8 +33,19 @@
 }
 
+streakFiles *ourStreakFiles = NULL;
+
+void
+setStreakFiles(streakFiles *sfiles)
+{
+    ourStreakFiles = sfiles;
+}
+
 // to enhance clarity in these programs we don't propagate errors up the stack
 // we just bail out
 void streaksExit(psString str, int exitCode) {
     psErrorStackPrint(stderr, str);
+    if (ourStreakFiles) {
+        deleteTemps(ourStreakFiles);
+    }
     exit(exitCode);
 }
