APSF
//- Output global observations in a given date range, as rows in an
//- HTML table.
//-
//- Author: Paul Rodman, May 2008
//- Inspired by Paul Kemp
//-
//- Version 1.0 15 May 2008
//- First release.
//- Version 1.1 15 May 2008
//- Sort observations by various methods.
//- Version 1.2 15 May 2008
//- Option to restrict to specified site and/or telescope.
//- Version 1.3 22 May 2008
//- Date and Time formatting options
//- Global placeholders (for session info)
//- Include observations only after 12pm on start date and before
//- 12pm on the day after the end date.
//- Version 1.4 22 May 2008
//- Add additional placeholder fields
//- Version 1.5 23 May 2008
//- Add {{ID/Name}} and {{ID-Name}}
//- Version 1.6 23 May 2008
//- Add Type substitutions field
//- Version 1.7 24 May 2008
//- Add Moon and Sun placeholders
//- Version 1.8 25 May 2008
//- Bug fixes
//- Version 1.9 25 May 2008
//- [[DistanceFromHome]] + Home Site popup in dialog
//- Version 1.10 26 May 2008
//- Fixed End Of Line problem in Windows
//- Version 1.11 27 May 2008
//- Fix for Date format problem.
//- Avoid blank placeholder names.
//- Version 1.12 2 June 2008
//- Fix for HTML compatibility (converting special characters to correct HTML)
//- Version 1.13 5 Feb 2010
//- Added ability to do a reverse sort
//- Version 1.14 5 Feb 2010
//- Bug fix
// Usage Notes:
// The template file should contain an HTML table with one data row.
// In the columns of that row, use the {{placeholder}} strings listed below.
// The row will be duplicated for each relevant observation, and the placeholders
// replaced by the data for that observation. Note: These {{strings}} MUST ONLY
// BE USED IN THE TABLE ROW.
//
// {{Placeholder}} Strings (case-insensitive):
//
// {{Date}}
// {{Julian}}
// {{Time}}
// {{ID}}
// {{Name}}
// {{ID/Name}} (ID if no name or ID=Name, ID
Name otherwise)
// {{ID-Name}} (ID if no name or ID=Name, ID, Name otherwise)
// {{Type}}
// {{Plan}}
// {{Observer}}
// {{Constellation}}
// {{RA}}
// {{Dec}}
// {{VisualAid}}
// {{Eyepiece}}
// {{Filter}}
// {{Site}}
// {{Notes}}
// {{Rating}}
// {{Seeing}}
// {{Telescope}}
// {{Transparency}}
// {{User1}}
// {{User2}}
// {{User1Title}}
// {{User2Title}}
// {{Magnification}}
// {{FOV}}
//
// The following [[placeholder]] strings can be used anywhere (including in the table
// rows - although that would imply duplication).
//
// [[Sites]] List of sites used in the observations, separated by the
// list separator as defined in the dialog.
// [[Telescopes]] List of telescopes used in the observations, ditto.
// [[Eyepieces]] List of eyepieces used in the observations, ditto.
// [[VisualAids]] List of visual aids used in the observations, ditto.
// [[Filters]] List of filters used in the observations, ditto.
// [[Combos]] Inventory of all combinations of the above (e.g. scope A with Eyepiece X, scope A with eyepiece Y, etc.)
//
// [[StartDate]] Date of first observation
// [[StartTime]] Time of first observation
// [[EndDate]] Date of last observation
// [[EndTime]] Time of last observation
//
// [[Transparency]] Transparency reported in observations
// [[Seeing]] Transparency reported in observations
//
// [[Sunrise]]
// [[Sunset]]
// [[CivilStart]]
// [[CivilEnd]]
// [[NauticalStart]]
// [[NauticalEnd]]
// [[AstronomicalStart]]
// [[AstronomicalEnd]]
//
// [[Moonrise]]
// [[Moonset]]
// [[MoonPhase]] Full, New, 1st Q, Last Q
// [[MoonIllumination]] 0 - 100%
//
// [[DistanceFromHome]] Distance from home site in km (as the crow flies)
const MoonPhaseSlop = 45
const maxSmallUserPlaceholders = 4
const maxLargeUserPlaceholders = 2
//---------------------------------------------------------------------------------------------------
function HTMLCompatible(sraw as string) as string
// Convert special characters to HTML
dim s as string
s=sraw
s=ReplaceAll(s,"&","&")
s=ReplaceAll(s,"<","<")
s=ReplaceAll(s,">",">")
s=ReplaceAll(s,DegreeSymbol,"°")
s=ReplaceAll(s,EndOfLine,"
")
s=ReplaceAll(s,"""",""")
s=ReplaceAll(s,"‛","'")
s=ReplaceAll(s,"‘","'")
s=ReplaceAll(s,"’","'")
s=ReplaceAll(s,"‟","""")
s=ReplaceAll(s,"′","'")
s=ReplaceAll(s,"″",""")
s=ReplaceAll(s,"'","&039;")
return s
end function
//---------------------------------------------------------------------------------------------------
function Magnification(gob as APGlobalObservation) as string
dim t as TelescopeResource, e as EyepieceResource, v as VisualAidResource
t=Telescope(gob.Telescope)
if t=nil then return "n/a"
e=Eyepiece(gob.Eyepiece)
if e=nil then return "n/a"
v=VisualAid(gob.Aid)
return str(round(Magnification(t,e,v)))+"X"
end function
//---------------------------------------------------------------------------------------------------
function FOV(gob as APGlobalObservation) as string
dim t as TelescopeResource, e as EyepieceResource, v as VisualAidResource
t=Telescope(gob.Telescope)
if t=nil then return "n/a"
e=Eyepiece(gob.Eyepiece)
if e=nil then return "n/a"
v=VisualAid(gob.Aid)
return format(ActualFOV(t,e,v),"0.00")+DegreeSymbol
end function
//---------------------------------------------------------------------------------------------------
function MassageID(id as string) as string
// Reconstruct common IDs so that they can be sorted
dim i as integer, s,sid as string
sid=id
while sid<>"" and IsNumeric(left(sid,1))
// Look for non-numeric
s=s+left(sid,1)
sid=mid(sid,2)
wend
while sid<>"" and not IsNumeric(left(sid,1))
// Look for numeric
s=s+left(sid,1)
sid=mid(sid,2)
wend
if IsNumeric(sid) then
s=s+format(val(sid),"0000000")
else
s=s+sid
end if
return s
end function
//---------------------------------------------------------------------------------------------------
sub Substitute(placeholder as string, items() as string, listsep as string, byref a as string, byref b as string, byref c as string)
dim s as string
if ubound(items)<0 then
s="n/a"
else
s=HTMLCompatible(Join(items,listsep))
end if
a=ReplaceAll(a,placeholder,s)
b=ReplaceAll(b,placeholder,s)
c=ReplaceAll(c,placeholder,s)
end sub
//---------------------------------------------------------------------------------------------------
sub Substitute(placeholder as string, item as string, byref a as string, byref b as string, byref c as string)
dim s as string
s=trim(item)
s=ReplaceAll(s,chr(13)+chr(10),"{{eol}}")
s=ReplaceAll(s,chr(13),"{{eol}}")
s=ReplaceAll(s,chr(10),"{{eol}}")
if instr(s,"{{eol}}")>0 then
s="
"+s+"
" s=ReplaceAll(s,"{{eol}}"+"{{eol}}","")
s=ReplaceAll(s,"{{eol}}","
")
end if
s=HTMLCompatible(s)
a=ReplaceAll(a,placeholder,s)
b=ReplaceAll(b,placeholder,s)
c=ReplaceAll(c,placeholder,s)
end sub
//---------------------------------------------------------------------------------------------------
sub SubstituteSunStuff(d as double, fmt as integer, sites() as string, listsep as string, byref a as string, byref b as string, byref c as string)
dim s,sall,placeholder,values(3) as string, r(-1) as double, i,j as integer
sall=a+b+c
if instr(sall,"[[Sunrise]]")>0 or instr(sall,"[[CivilStart]]")>0 or instr(sall,"[[NauticalStart]]")>0 or _
instr(sall,"[[AstronomicalStart]]")>0 then
for i=0 to ubound(sites)
r=SunRise(d+86400.0,Site(sites(i))) // sunrise tomorrow
for j=0 to 3
if values(j)<>"" then values(j)=values(j)+listsep
if r(j)>=0 then values(j)=values(j)+FormatTime(r(j),fmt) else values(j)=values(j)+"n/a"
next
next
Substitute("[[Sunrise]]",values(0),a,b,c)
Substitute("[[CivilStart]]",values(1),a,b,c)
Substitute("[[NauticalStart]]",values(2),a,b,c)
Substitute("[[AstronomicalStart]]",values(3),a,b,c)
end if
if instr(sall,"[[Sunset]]")>0 or instr(sall,"[[CivilEnd]]")>0 or instr(sall,"[[NauticalEnd]]")>0 or _
instr(sall,"[[AstronomicalEnd]]")>0 then
for j=0 to 3
values(j)=""
next
for i=0 to ubound(sites)
r=SunSet(d,Site(sites(i))) // sunset today
for j=0 to 3
if values(j)<>"" then values(j)=values(j)+listsep
if r(j)>=0 then values(j)=values(j)+FormatTime(r(j),fmt) else values(j)=values(j)+"n/a"
next
next
Substitute("[[Sunset]]",values(0),a,b,c)
Substitute("[[CivilEnd]]",values(1),a,b,c)
Substitute("[[NauticalEnd]]",values(2),a,b,c)
Substitute("[[AstronomicalEnd]]",values(3),a,b,c)
end if
end sub
//---------------------------------------------------------------------------------------------------
sub SubstituteMoonStuff(d as double, fmt as integer, sites() as string, listsep as string, byref a as string, byref b as string, byref c as string)
dim s,sall,placeholder,values(-1) as string, r as double, i,j as integer
sall=a+b+c
if instr(sall,"[[Moonrise]]")>0 then
for i=0 to ubound(sites)
r=MoonRise(d,Site(sites(i)))
if r>=0 then values.Append FormatTime(r,fmt) else values.Append "n/a"
next
Substitute("[[Moonrise]]",Join(values,listsep),a,b,c)
end if
if instr(sall,"[[Moonset]]")>0 then
redim values(-1)
for i=0 to ubound(sites)
r=MoonSet(d,Site(sites(i)))
if r<15.0 then r=MoonSet(d+86400.0,Site(sites(i)))
if r>=0 then values.Append FormatTime(r,fmt) else values.Append "n/a"
next
Substitute("[[Moonset]]",Join(values,listsep),a,b,c)
end if
if instr(sall,"[[MoonPhase]]")>0 then
redim values(-1)
for i=0 to ubound(sites)
r=MoonPhase(d,Site(sites(i)))
if r>=-MoonPhaseSlop and r<=MoonPhaseSlop then
values.Append "Full"
elseif r<-180+MoonPhaseSlop or r>180-MoonPhaseSlop then
values.Append "New"
elseif r>0 then
values.Append "First Q"
else
values.Append "Last Q"
end if
next
Substitute("[[MoonPhase]]",Join(values,listsep),a,b,c)
end if
if instr(sall,"[[MoonIllumination]]")>0 then
redim values(-1)
for i=0 to ubound(sites)
r=MoonIllumination(d,Site(sites(i)))*100.0
values.Append format(r,"0.0")+"%"
next
Substitute("[[MoonIllumination]]",Join(values,listsep),a,b,c)
end if
end sub
//---------------------------------------------------------------------------------------------------
function FixStringGlitch(s as string) as string
if Platform=platform_Windows then return left(s,len(s)-1) else return s
end function
//---------------------------------------------------------------------------------------------------
function DayOfWeek(dt as double, abbrev as boolean = true) as string
dim dt0 as double, dow(),s as string, diff,i as integer
dt0=MakeDate(2001,1,1)
diff=floor((dt-dt0)/86400.0)+1
if abbrev then dow=DayAbbreviations else dow=DayNames
s=dow((diff mod 7)+1)
return FixStringGlitch(s)
end function
//---------------------------------------------------------------------------------------------------
function FormatDate(dt as double, fmt as integer) as string
dim d,m,y as integer, s(),dow as string
if fmt=0 then return DoubleToDate(dt)
y=YearOfDate(dt)
m=MonthOfDate(dt)
d=DayOfDate(dt)
select case fmt
case 1 // yyyy-mm-dd
return format(y,"0000")+"-"+format(m,"00")+"-"+format(d,"00")
case 2 // m/d/yyyy
return format(m,"0")+"/"+format(d,"0")+"/"+format(y,"0000")
case 3 // d/m/yyyy
return format(d,"0")+"/"+format(m,"0")+"/"+format(y,"0000")
case 4 // yyyy/m/d
return format(y,"0000")+"/"+format(m,"0")+"/"+format(d,"0")
case 5 // whole enchilada 1
s=MonthAbbreviations
dow=DayOfWeek(dt,true)
return dow+", "+format(d,"0")+" "+FixStringGlitch(s(m))+", "+format(y,"0000")
case 6 // whole enchilada 2
s=MonthNames
dow=DayOfWeek(dt,false)
return dow+", "+format(d,"0")+" "+FixStringGlitch(s(m))+", "+format(y,"0000")
end select
end function
//---------------------------------------------------------------------------------------------------
function FormatTime(dte as double, fmt as integer) as string
dim postfix as string, h as integer, dt as double
dt=dte
if dt<24.0 then dt=dt*3600.0
if fmt=0 then return DoubleToTime(dt)
select case fmt
case 1 // hh:mm
return format(HourOfDate(dt),"00")+":"+format(MinuteOfDate(dt),"00")
case 2 // hh:mm:ss
return format(HourOfDate(dt),"00")+":"+format(MinuteOfDate(dt),"00")+":"+format(SecondOfDate(dt),"00")
case 3 // hh:mm am/pm
h=HourOfDate(dt)
if h>=12 then postfix="pm" else postfix="am"
if h>=13 then h=h-12
return format(h,"0")+":"+format(MinuteOfDate(dt),"00")+" "+postfix
case 4 // hh:mm:ss am/pm
h=HourOfDate(dt)
if h>=12 then postfix="pm" else postfix="am"
if h>=13 then h=h-12
return format(h,"0")+":"+format(MinuteOfDate(dt),"00")+":"+format(SecondOfDate(dt),"00")+" "+postfix
end select
end function
//---------------------------------------------------------------------------------------------------
function IDName(gob as APGlobalObservation, sep as string) as string
dim id,name as string
id=trim(gob.ID)
name=trim(gob.Name)
if name="" or name=id then return HTMLCompatible(id)
if id="" then return HTMLCompatible(name)
return HTMLCompatible(id)+sep+HTMLCompatible(name)
end function
//---------------------------------------------------------------------------------------------------
function SubstituteType( t as string, tsubst as string) as string
dim lines(-1),a(-1),b(-1),s as string, i,j as integer
s=tsubst
s=ReplaceAll(s,chr(13)+chr(10),"{{eol}}")
s=ReplaceAll(s,chr(13),"{{eol}}")
s=ReplaceAll(s,chr(10),"{{eol}}")
lines=Split(ReplaceAll(s,",","{{eol}}"),"{{eol}}")
for i=0 to ubound(lines)
j=instr(lines(i),"=")
if j>1 then
a.Append trim(left(lines(i),j-1))
b.Append trim(mid(lines(i),j+1))
end if
next
i=a.IndexOf(trim(t))
if i>=0 then return b(i) else return t
end function
//---------------------------------------------------------------------------------------------------
function DistanceBetweenSites(a as string, b as string) as double
if Site(a)<>nil and Site(b)<>nil then
return AngleBetween((Site(a).Longitude+180.0)/15.0,Site(a).Latitude,(Site(b).Longitude+180.0)/15.0,Site(b).Latitude)*111.1
else
return 0.0
end if
end function
//---------------------------------------------------------------------------------------------------
dim dstart,dend,mindt,maxdt,dt as double
dim templatefile,stemplate,s,preamble,postamble,sorting(-1),sorter(-1),sitenames(-1),scopenames(-1) as string
dim listseparator,siteList(-1),telescopeList(-1),eyepieceList(-1),aidList(-1),filterList(-1),comboList(-1) as string
dim combo(-1),transList(-1),seeingList(-1),tsubst,hsitenames(-1),distList(-1) as string
dim tfile,i,j,sortby,rsite,rtelescope,dateformat,timeformat,hsite as integer
dim templatef,foutput as APTextFile
dim gob as APGlobalObservation
dim smplaceholders(maxSmallUserPlaceholders-1),smstringvalues(maxSmallUserPlaceholders-1) as string
dim lgplaceholders(maxLargeUserPlaceholders-1),lgstringvalues(maxLargeUserPlaceholders-1) as string
dim allgood,revsort as boolean
// Load non-volatile parameters
SaveRestoreGlobal(true)
dstart=RestoreDoubleValue("dstart",MakeDate(1990,1,1))
dend=RestoreDoubleValue("dend",CurrentDate)
templatefile=RestoreStringValue("templatefile","")
sortby=RestoreIntegerValue("sortby",0)
rsite=RestoreIntegerValue("rsite",0)
hsite=RestoreIntegerValue("hsite",0)
rtelescope=RestoreIntegerValue("rtelescope",0)
listseparator=RestoreStringValue("listseparator",", ")
dateformat=RestoreIntegerValue("dateformat",0)
timeformat=RestoreIntegerValue("timeformat",0)
tsubst=RestoreStringValue("tsubst","P Neb=Planetary Nebula, D Neb=Dark Nebula, Globular=Globular Cluster")
revsort=RestoreBooleanValue("revsort",false)
j=1
for i=1 to maxSmallUserPlaceholders
smplaceholders(i-1)=RestoreStringValue("SmPlaceholder"+str(i),"[[placeholder_"+str(j)+"]]")
smstringvalues(i-1)=RestoreStringValue("SmStringValue"+str(i),"some text here")
j=j+1
next
for i=1 to maxLargeUserPlaceholders
lgplaceholders(i-1)=RestoreStringValue("LgPlaceholder"+str(i),"[[placeholder_"+str(j)+"]]")
lgstringvalues(i-1)=RestoreStringValue("LgStringValue"+str(i),"some text here")
j=j+1
next
// Select parameters via a dialog
do
SetDateParameter("Start Date",dstart)
SetDateParameter(true,"End Date",dend)
if templatefile<>"" then tfile=1 else tfile=0
if templatefile="" or not FileExists(templatefile) then
SetChoiceParameter("Template File",tfile,"Choose")
else
i=len(templatefile)
while i>0 and mid(templatefile,i,1)<>":" and mid(templatefile,i,1)<>"\"
i=i-1
wend
SetChoiceParameter("Template File",tfile,"Choose","Use: "+mid(templatefile,i+1))
end if
SetStringParameter(true,"Type substitutions",tsubst,true)
redim sorting(-1)
sorting.Append "Date/Time"
sorting.Append "ID"
sorting.Append "Name"
sorting.Append "Type"
sorting.Append "RA"
sorting.Append "Dec"
sorting.Append "User Field 1"
sorting.Append "User Field 2"
SetPopupParameter("Sort by",sortby,sorting)
SetStringParameter(true,"List separator",listseparator)
SetBooleanParameter("Reverse sort",revsort)
dt=CurrentDate
redim sorting(-1)
sorting.Append "Default"
for i=1 to 6
sorting.Append FormatDate(dt,i)
next
SetPopupParameter("Date format",dateformat,sorting)
redim sorting(-1)
sorting.Append "Default"
for i=1 to 4
sorting.Append FormatTime(dt,i)
next
SetPopupParameter(true,"Time format",timeformat,sorting)
sitenames.Append "All Sites"
for i=1 to nSites
sitenames.Append Site(i).Name
next
SetPopupParameter("Restrict to Site",rsite,sitenames)
scopenames.Append "All Telescopes"
for i=1 to nTelescopes
scopenames.Append Telescope(i).Name
next
SetPopupParameter(true,"Restrict to Telescope",rtelescope,scopenames)
hsitenames.Append "N/A"
for i=1 to nSites
hsitenames.Append Site(i).Name
next
SetPopupParameter("Home Site",hsite,hsitenames)
j=1
for i=1 to maxSmallUserPlaceholders
SetStringParameter("Placeholder "+str(j),smplaceholders(i-1))
SetStringParameter(true,"String Value "+str(j),smstringvalues(i-1))
j=j+1
next
for i=1 to maxLargeUserPlaceholders
SetStringParameter("Placeholder "+str(j),lgplaceholders(i-1))
SetStringParameter(true,"String Value "+str(j),lgstringvalues(i-1),true)
j=j+1
next
if not EditParameters("Observation HTML") then return
allgood=true
dstart=GetDateParameter("Start Date")
dend=GetDateParameter("End Date")
tfile=GetChoiceParameter("Template File")
sortby=GetPopupParameter("Sort by")
rsite=GetPopupParameter("Restrict to Site")
hsite=GetPopupParameter("Home Site")
rtelescope=GetPopupParameter("Restrict to Telescope")
listseparator=GetStringParameter("List separator")
dateformat=GetPopupParameter("Date format")
timeformat=GetPopupParameter("Time format")
tsubst=GetStringParameter("Type substitutions")
revsort=GetBooleanParameter("Reverse sort")
j=1
for i=1 to maxSmallUserPlaceholders
smplaceholders(i-1)=GetStringParameter("Placeholder "+str(j))
if trim(smplaceholders(i-1))="" then allgood=false
smstringvalues(i-1)=GetStringParameter("String Value "+str(j))
j=j+1
next
for i=1 to maxLargeUserPlaceholders
lgplaceholders(i-1)=GetStringParameter("Placeholder "+str(j))
if trim(lgplaceholders(i-1))="" then allgood=false
lgstringvalues(i-1)=GetStringParameter("String Value "+str(j))
j=j+1
next
if not allgood then print "Blank placeholder! Please correct..."
loop until allgood
if tfile=0 then templatefile=""
// Get template file, where needed
if templatefile="" then templatefile=GetFilePath("Open HTML Template file")
if templatefile="" then return
// Save non-volatile parameters for next time
SaveDoubleValue("dstart",dstart)
SaveDoubleValue("dend",dend)
SaveStringValue("templatefile",templatefile)
SaveIntegerValue("sortby",sortby)
SaveIntegerValue("rsite",rsite)
SaveIntegerValue("hsite",hsite)
SaveIntegerValue("rtelescope",rtelescope)
SaveStringValue("listseparator",listseparator)
SaveIntegerValue("dateformat",dateformat)
SaveIntegerValue("timeformat",timeformat)
SaveStringValue("tsubst",tsubst)
SaveBooleanValue("revsort",revsort)
for i=1 to maxSmallUserPlaceholders
SaveStringValue("SmPlaceholder"+str(i),smplaceholders(i-1))
SaveStringValue("SmStringValue"+str(i),smstringvalues(i-1))
next
for i=1 to maxLargeUserPlaceholders
SaveStringValue("LgPlaceholder"+str(i),lgplaceholders(i-1))
SaveStringValue("LgStringValue"+str(i),lgstringvalues(i-1))
next
// Read the template file into a string
templatef=ReadTextFile(templatefile)
if templatef=nil or FileErrorCode<0 then return
stemplate=templatef.ReadAll
templatef.Close
for i=1 to maxSmallUserPlaceholders
while left(smplaceholders(i-1),2)<>"[["
smplaceholders(i-1)="["+smplaceholders(i-1)
wend
while right(smplaceholders(i-1),2)<>"]]"
smplaceholders(i-1)=smplaceholders(i-1)+"]"
wend
next
for i=1 to maxLargeUserPlaceholders
while left(lgplaceholders(i-1),2)<>"[["
lgplaceholders(i-1)="["+lgplaceholders(i-1)
wend
while right(lgplaceholders(i-1),2)<>"]]"
lgplaceholders(i-1)=lgplaceholders(i-1)+"]"
wend
next
// Find and extract the template row
i=instr(stemplate,"{{")
if i<=0 then
Print "No {{placeholders}} found in the template"
return
end if
j=i-3
while j>0 and instr(j,stemplate,"