CSV to Candidates

 ↑  csv2candidates.awk

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from csv2candidates.awk


#! /bin/gawk -f

# Program   : csv2candidates.awk
# Purpose   : Generate copy'n'paste-able code for Poliblog's candidate lists
# Author    : Bob Jonkman bjonkman@sobac.com
# Date      : 30 April 2022

# Copyright (c) 2020 Bob Jonkman and/or SOBAC Microcomputer Services

#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.


# Usage     : gawk -f csv2candidates.awk candidates.csv

# Fields    : (fields with * will appear even when empty, social media fields only for those who have them)
#           Static Fields: (update the variable in BEGIN block when this changes!)
#           *  1 Name
#           *  2 Riding
#              3 Party                 # \
#              4 PartyURL              #  > Party info labels appear only if there's party info, so this can be used for municipal elections too
#              5 PartyLogo             # /
#           *  6 Website
#           *  7 Email
#           *  8 Phone
#           *  9 Address     (single line monolithic, at the moment. May use sub-fields later)
#           * 10 ImageURL
#             11 Incumbent
#           * 12 RidingURL
#           * 13 RidingLogo
#
#           Dynamic Fields:
#               "Twitter","Facebook","Instagram","YouTube","LinkedIn", &c.
#               (social media URLs) field numbers may vary  (will eventually be parsed for @Twitter and @instagram)

@include "library.awk"

function makeid(candidatenumber) {
    return(valnameid(candidates[candidatenumber,"Name"] "-" candidates[candidatenumber,"Riding"] "-" candidates[candidatenumber,"Party"]))
}

# ImageUrl() added 27 Feb 2025 --Bob
function ImageUrl(UrlString) {
				# Dealing with ImageUrl shortcut, ie. "bob-jonkman.jpg" instead of "https://poliblog.jonkman.ca/Poliblog-Elections/images/bob-jonkman.jpg"
				if (tolower(substr(UrlString,1,4)) != "http")
				  return ("../images/" UrlString)
                else
                  return (UrlString)
}

BEGIN {

	## Special Purpose fields are ignored in the candidates' list of resources
	### Some are used for images, some for class names (CSS styling), some for page layout
	skipAttributes["Name"]=1                # Used for header, ID
	skipAttributes["Firstname"]=1           # Waterloo Region Votes needs separated FirstName, Lastname (we don't)
	skipAttributes["Lastname"]=1            # Waterloo Region Votes needs separated FirstName, Lastname (we don't)
	skipAttributes["Riding"]=1              # Used for header, ID
	skipAttributes["RidingURL"]=1           # URL to Elections Ontario/Canada website
	skipAttributes["RidingLogo"]=1          # URL to image
	skipAttributes["RidingShortName"]=1     # Selector for Riding Name
	skipAttributes["Party"]=1               # Party name
	skipAttributes["PartyShortName"]=1      # Selector for Party name
	skipAttributes["PartyLogo"]=1           # URL to image
	skipAttributes["PartyURL"]=1            # URL to party website
	skipAttributes["Office"]=1              # Used for grouping, ID (eg. Mayor, Councillor, Trustee)
	skipAttributes["Elect"]=1               # Additional info for Office
	skipAttributes["Municipality"]=1        # Used for grouping, ID
	skipAttributes["MunicipalityURL"]=1     # URL to municipal website
	skipAttributes["MunicipalityLogo"]=1    # URL to image
	skipAttributes["ImageURL"]=1            # URL to candidate image
	skipAttributes["Address"]=1             # Used for OpenStreetMap lookup
	skipAttributes["Unregistered"]=1        # Show only "Registered", not its negated value
    skipAttributes["HiddenNotes"]=1         # 'cos they're hidden, eh?
	skipAttributes["Incumbent"]=1           # Class name (styling), indicator
    skipAttributes["candidateclass"]=1	    # Used internally to transfer styling from table to candidate list
    skipAttributes["Display"]=1             # If set, suppress the display of this candidate altogether (so this attribute wouldn't be shown anyway)

### classarray to turn candidate attributes in to a class for styling
  classarray["Incumbent"]=1		  # for building the class= attribute
  classarray["Withdrawn"]=1
  classarray["Unregistered"]=1
  classarray["Elected"]=1


### Fields to concatenate for search
  concatfields["Name"]=1
  concatfields["Office"]=1
  concatfields["Municipality"]=1
  concatfields["Riding"]=1
  concatfields["Party"]=1

	IFS = ","
	OFS = " "
}

# Read the title and subtitle(s)
(NR == 1) {
	h_num = parsecsv($0, h)
}

# Read field headers
(NR == 2) {
	numfields = getheaders($0, headernums, headernames)
}

# Read rest of the file
(NR > 2) {


	numfields = parsecsv($0, inputarray)
	for (field = 1; field <= numfields; field++) {
		candidates[NR, headernames[field]] = inputarray[field]
	}


### Create negated attribute for "Registered==FALSE" to "Unregistered=TRUE"
  if ("false" == tolower(candidates[NR, "Registered"]) || "0" == candidates[NR, "Registered"]) {
     candidates[NR, "Unregistered"] = "TRUE"
  }

  ### Create an id attribute, same as candidates-search.awk
  concatid = ""
  for ( concatname in concatfields ) {
    if ( "" != trim(candidates[NR, concatname]) ) {
      concatid = concatid candidates[NR, concatname] "-"
    }
  }
  candidates[NR, "concatid"] = valnameid(concatid) ### ensure this string is a valid id attribute


### Build candidateclass for styling in table and name
  candidateclass = ""
  for ( classflag in classarray ) {
    if ( "" != trim(candidates[NR, classflag]) ) {
      candidateclass = candidateclass " " classflag
    }
  }
  candidates[NR, "candidateclass"] = tolower(candidateclass)


### Build list of ridings
	if ( "" != trim(candidates[NR, "Riding"]) ) {
	  riding = candidates[NR, "Riding"]
    	  ridings[riding]++
    	  ridingurls[riding] = candidates[NR, "RidingURL"]
    	  ridinglogos[riding] = candidates[NR, "RidingLogo"]
    	} # if ("" != Riding)

### Build list of parties
  if ( "" != trim(candidates[NR, "Party"]) ) {
      parties[candidates[NR,"Party"]]++    # Build an array of parties
      partyurls[candidates[NR,"Party"]] = candidates[NR, "PartyURL"]
      ridingsxparties[riding, candidates[NR,"Party"]] = candidates[NR,"Name"] # Build an array of Ridings x Parties
  } # if ("" != Party)
}

END {

	printhtmlhead(h[1] " - " h[2], "noclose")
##### Instead of "noclose" use
	print (" <link rel=\"stylesheet\" href=\"../candidates.css\" type=\"text/css\">")
	print (" <link rel=\"shortcut icon\" href=\"https://poliblog.jonkman.ca/blogs/pollywog-32x32b.jpg\" type=\"image/x-icon\">")
	### Close <head> ("noclose")
	print ("</head>")

	print ("<!--")
	print ("This information is provided as-is. Data is public information and not subject to copyright.")
	print ("Images and logos are copyright and trademarked by their respective owners; their source is linked in the entry.")
	print ("They are used under \"Fair Dealing\" as news reporting.")
	print ("")
	print ("Other material on this page is Copyright (c) " strftime("%Y") " by Bob Jonkman")
	print ("and released under a Creative Commons Attribution-only Share-Alike license: http://creativecommons.org/licenses/by-sa/4.0/")
	print (" -->")

	print ("<body>")
	print ("<div  id=\"top_of_page\" class=\"header\">")
	print (" <!--#include virtual=\"header.ssi\" -->")
	print ("</div> <!-- class=header -->")

	for (i = 1; i <= h_num; i++) {
		if ("" != trim(h[i])) {
		  (i > 6) ? hval=6 : hval=i
			print ("<h" hval ">" makehtml(h[i]) "</h" hval ">")
		}
	}

	# Get ridings and parties in alphabetical order
	numridings = asorti(ridings)
	numparties = asorti(parties)



# Create table of ridings and parties




# ########################################## #
#                                            #
# This is the new way of creating a table    #
#    Ridings x Party                         #
#      (because the number of ridings will   #
#       be more consistent than the number   #
#       of parties)                          #
#                                            #
# ########################################## #


	print (" <table")
        print ("  class=\"candidates\"")
	print (">")
	print ("  <thead>")
	print ("  <tr>")
	print ("    <th>&nbsp;</th>") # for the Parties column

  ### Print column headers
  for( riding=1; riding<=numridings ; riding++) {
    print ("    <th><a class=\"internal\" href=\"#" valnameid(ridings[riding]) "\" title=\"Jump to " ridings[riding] "\">" ridings[riding] "</a></th>")
  }
  print "  </tr>"
  print " </thead>"

  print " <tbody>"
  for ( party=1; party<=numparties ; party++ ) {

  print "  <tr>"
  	if ( "" ==  partyurls[parties[party]] ) {
  		print ("    <th>" parties[party] "</th>")
  	} else {
  	  ### The PartyURL field may contain multiple URLs, use only the first one
  	  split(partyurls[parties[party]],partyurlsplit," ")
  	  print ("    <th><a href=\""  partyurlsplit[1] "\" title=\"" partyurls[parties[party]] "\">" parties[party] "</a></th>")
   	} # if ("" = partyurl)


    for ( riding in ridings ) {

    print "    <td>"

      for (candidate = 3 ; candidate <= NR ; candidate++ ) {

              ### Don't display these candidates where Display=False  OR where candidate is blank
       if ( ("FALSE" != candidates[candidate, "Display"]) &&  \
            ("" != trim(candidates[candidate, "Name"]))   )
         {
          if ( (parties[party]  == candidates[candidate, "Party"] ) && \
               (ridings[riding] == candidates[candidate, "Riding"]) ) {
            print "<a href=\"#" candidates[candidate, "concatid"] "\" title=\"" candidates[candidate, "Name"] "\" class=\"internal " candidates[candidate, "candidateclass"] "\">" candidates[candidate, "Name"]
            for ( classflag in classarray ) {
              if ( "" != trim(candidates[candidate, classflag]) ) { # check for non-empty field, contents may not be == classflag
                print " (" classflag ")"
              } # if (candidate, classarray)
            } # for (classflag)
            print "</a><br>"
          } # if (Party, Riding)
        } # if ( "" != candidate )
      } # for (candidate)
      print "   </td>"
    } # for (riding)
    print "  </tr>"
    print ""
  } # for (party)
  print "</tbody>"
  print "</table>"

  print ""

# ########################################## #
#                                            #
#                                            #
#    End of table Ridings x Party            #
#                                            #
#                                            #
# ########################################## #

# Print the list of candidates

	for (i=1 ; i <= numridings ; i++) {	# generate page menu
	    riding=ridings[i]
		print (" <h3 id=\"" valnameid(riding) "\"><a href=\"#top_of_page\" title=\"Go to the top of this page\" class=\"internal\">&thinsp;^&thinsp;</a> " riding)
		if ("" != trim(ridingurls[riding]) ) {
			print ("  <a href=\"" ridingurls[riding] "\" title=\"Information about " riding "\">")
			if ("" != trim(ridinglogos[riding]) ) {
				print ("   <img class=\"icon\" src=\"" ridinglogos[riding] "\" alt=\"Riding logo\"> Info")
			} else {
				print ("Information about this riding")
			}
			print ("  </a>")
		}
		print (" </h3>")
		print (" <dl>")
		for (candidate = 2; candidate <= NR; candidate++) {
			if (candidates[candidate, "Riding"] != riding) {
				# Only print the candidates in this riding
				continue	# with next candidate
			}
		if (candidates[candidate, "Name"] == "") {
				# skip blank records
				continue	# with next candidate
			}
		if (candidates[candidate, "Display"] == "FALSE") {
				# skip DISPLAY==FALSE
				continue	# with next candidate
			}
			print ("")
			print ("   <dt id=\"" candidates[candidate, "concatid"] "\" class=\"h-card\">")
			print ("    <a href=\"#top_of_page\" title=\"Go to the top of this page\" class=\"internal\">&thinsp;^&thinsp;</a> ")

							print "<span class=\"" candidates[candidate, "candidateclass"] "\">"  candidates[candidate, "Name"]

              for ( classflag in classarray ) {
                if ( "" != trim(candidates[candidate, classflag]) ) { # check for non-empty field, contents may not be == classflag
                  print " <strong>(" classflag ")</strong>"
                } # if (candidate, classarray)
              } # for (classflag)


							print "</span>"

			print ("     <a href=\"#" candidates[candidate, "concatid"] "\" title=\"Anchor link for " candidates[candidate, "Party"] " candidate in " riding "\">&#x2693;</a>")

						    print "<a href=\"searchassistant.html#" candidates[candidate, "concatid"] "\" title=\"Find this candidate on the Search Assistant\" class=\"right\">&#x1F50E;</a>"

			print ("   </dt>")
			print ("   <dd  class=\"h-card\">")
			print ("    <div class=\"aside\">")
			if ("" != trim(candidates[candidate, "ImageURL"]) ) {
				if ("" != trim(candidates[candidate, "Website"]) ) {
            ### Ensure we only get the first URL when there are multiples
                    			split(candidates[candidate, "Website"],urls," ")
					print ("<a  href=\"" urls[1] "\" title=\"" gettitle(urls[1]) "\">")
				}

                                print ("     <img src=\"" ImageUrl(candidates[candidate, "ImageURL"]) "\" alt=\"" candidates[candidate, "Name"] "\">")
				if ("" != trim(candidates[candidate, "Website"]) ) {
					print ("</a>")
				}
			} else {
				print ("     <p>No Image</p>")
			}
			print ("    </div> <!-- class=aside -->")
			print ("    <ul>")
			if ("" != trim(candidates[candidate, "Party"]) ) {
				print ("     <li class=\"p-org\"><b>Party</b>: ")	#   Field label is optional, for municipal elections without party affiliation
				if ("" != trim(candidates[candidate, "PartyURL"]) ) {
            ### Ensure we only get the first URL when there are multiples
                    split(candidates[candidate, "PartyURL"],urls," ")
					print ("       <a href=\"" urls[1] "\" title=\"" gettitle(candidates[candidate, "PartyURL"]) "\">" candidates[candidate, "Party"] " ")
					if ("" != trim(candidates[candidate, "PartyLogo"]) ) {
						print ("       <img src=\"" ImageUrl(candidates[candidate, "PartyLogo"]) "\" alt=\"Logo for " candidates[candidate, "Party"] "\">")
					}					# if ("PartyLogo")
					print ("      </a>")
				} else {  	# if no ("PartyURL")
					print (candidates[candidate, "Party"] )
				}	# endif ("PartyURL")
				print ("     </li>")
			}			# if ("Party")




			# Add social media fields
			for (field = 1; field <= numfields; field++) {
    			if ( headernames[field] in skipAttributes) { # if Attribute is in skipAttributes
					  continue	# don't list static attributes
				  }	# if (Attribute ~ skipAttributes)

  				if ("" != trim(candidates[candidate, headernames[field]]) ) {  # Skip empty fields
    				print ("     <li><b>" headernames[field] "</b>: " makehtml(candidates[candidate, headernames[field]]) "</li>")
                } # empty field
			} # for (field <= numfields)


      # Address at the end (and if not empty)  Note: Could be a postal address, could be a Campaign Office address
			if ("" != candidates[candidate, "Address"]) {

            cleanaddress = stripcomments(trim(candidates[candidate, "Address"]),"(",")")




				### Automatically fetch OSM link?
        print ("     <li class=\"h-adr\"><b>Address</b>:")
				print ("      <p>")
				### If we parse out address info
				###          print("<!-- <span class=\"p-street-address\">XXXXXSTREETADDRESS</span>,<br><span class=\"p-locality\">XXXXXLOCALITY</span>, <span class=\"p-region\">Ontario</span>,<br><span class=\"p-country\">Canada</span>&emsp;<span class=\"p-postal-code\">XXXXXPOSTALCODE</span> -->") ;

				### If we DON'T parse out address info (monolithic addresses)
				print ("      <span class=\"p-address\">" candidates[candidate, "Address"] "</span> <a class=\"map\" href=\"https://www.openstreetmap.org/search?query=" txt2uri(cleanaddress) "\" title=\"OpenStreetMap: " cleanaddress "\">Map</a>")
				print ("      </p>")
  			print ("     </li>")
			} # address field not empty
			print ("")


			print ("    </ul>")
			print ("    <br style=\"clear:both;\">")	# Ensure images don't extend beyond <dl> box
			print ("   </dd>")
			print ("")
		}	# for candidate in candidates
		print (" </dl>")
		print ("")
	}	# for riding in ridings
	print ("<div class=\"footer\">")
	print (" <!--#include virtual=\"footer.ssi\" -->")
	print (" <p>Source code for csv2candidates generator: <a href=\"../csv2candidates.html\" title=\"Code Files - csv2candidates.awk and library.awk\">csv2candidates.awk and library.awk</a></p>")
	print (" <p><a property=\"dct:title\" rel=\"cc:attributionURL\" href=\"http://poliblog.jonkman.ca/Poliblog-Elections/\">List of Candidates</a> by <a rel=\"cc:attributionURL dct:creator\" property=\"cc:attributionName\" href=\"http://poliblog.jonkman.ca/blogs/about/\">Bob Jonkman</a> is licensed under <a href=\"http://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1\" target=\"_blank\" rel=\"license noopener noreferrer\">CC BY-SA 4.0<img alt=\"\"  src=\"https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1\"><img alt=\"\" src=\"https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1\"><img alt=\"\" src=\"https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1\"></a></p>")
	print (" <p class=\"bottom\">This page was last updated <!--#config timefmt=\"%a, %d %b %Y %T %z\" --><!--#echo var=\"LAST_MODIFIED\"--> </p>")
	print ("</div> <!-- class=footer -->")
	print ("</body>")
	print ("</html>")
	print ("")
} # END

# EOF: csv2candidates.awk

   

 ↑  csv2municipalcandidates.awk

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from csv2municipalcandidates.awk


#! /bin/gawk -f

# Program   : csv2municipalcandidates.awk
# Purpose   : Generate copy'n'paste-able code for Poliblog's candidate lists for municipal elections
# Author    : Bob Jonkman bjonkman@sobac.com
# Date      : 2 July 2022
# Based on  : csv2municipalcandidates.awk (for provincial and federal elections with Offices)

# Copyright (c) 2020 Bob Jonkman and/or SOBAC Microcomputer Services

#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <https://www.gnu.org/licenses/>.


# Usage     : gawk -f csv2municipalcandidates.awk candidates.csv

# Records   : 1st line: Fields are headers <h1> to <h6>
#           : 2nd line: Field header names
#           : 3rd line to end: Data

# Fields    : Fieldnames with * are required, cannot be empty. Other fields appear only if not empty
#             Fieldnames with ! are used to group entries and are used for layout. Fieldnames with ! must exist, fields may be empty. Itemized in variable skipAttributes, used to skip in attribute lists
#             Fields are referenced by header name, the second line MUST be a field header line

#
#  Static Fields (must exist, if blank the entry is ignored):

#           1 Name
#           2 Office
#           3 Municipality


#                  Address     (single line monolithic, at the moment. May use sub-fields later)
#                  Website
#                  E mail
#                  Phone
#               "Twitter","Facebook","Instagram","YouTube","LinkedIn", &c.
#               (social media URLs) field numbers may vary  (will eventually be parsed for @Twitter and @instagram)

@include "library.awk"



function makeid(candidatenumber)
{
  # Trailing dash is an artifact of how the Search Assistant creates an id value
	return (valnameid(Candidates[candidatenumber]["Name"] "-" Candidates[candidatenumber]["Municipality"] "-" Candidates[candidatenumber]["Office"] "-"))
}

BEGIN {
	#	IFS = ","
	#	OFS = " "
	#	IGNORECASE = 1   # for sorting

	#	staticfields = 7
	#    Municipalities[0][0]=""  # Initialize 2D array

	## Special Purpose fields are ignored in the candidates' list of resources
	### Some are used for images, some for class names (CSS styling), some for page layout
	skipAttributes["Name"]=1                # Used for header, ID
	skipAttributes["Office"]=1              # Used for grouping, ID
	skipAttributes["Elect"]=1               # Additional info for Office
	skipAttributes["Municipality"]=1        # Used for grouping, ID
	skipAttributes["MunicipalityURL"]=1     # URL to municipal website
	skipAttributes["MunicipalityLogo"]=1    # URL to image
	skipAttributes["ImageURL"]=1            # URL to image
	skipAttributes["Address"]=1             # Used for OpenStreetMap lookup
    skipAttributes["HiddenNotes"]=1			# Because they're hidden, eh?

	skipAttributes["Incumbent"]=1           # Class name (styling), indicator
            classarray["Incumbent"]=1		# for building the class= attribute
#   skipAttributes["Not_Running"]=1		### Changed to include reason for withdrawal, eg. "Deceased", so should be shown in candidate info
            classarray["Not_Running"]=1
#	skipAttributes["Elected"]=1             # Class name (styling), indicator ### Modified 2022-10-24 to show "Elected" or "Acclaimed"
            classarray["Elected"]=1
	skipAttributes["Unregistered"]=1        # Class name (styling), indicator (set by Registered == "" )
            classarray["Unregistered"]=1

    skipAttributes["candidateclass"]=1	# Used internally to transfer styling from table to candidate list

} # BEGIN


# Read the title and subtitle(s)
(NR == 1) {
	numheadings = parsecsv($0,heading)
} # (NR == 1)


# Read field headers
(NR == 2) {
	numfields = getheaders($0, headernums, headernames)
} # (NR == 2)


# Read rest of the file
(NR > 2) {
	numfields = parsecsv($0, inputarray)
	## Move input line to candidates record
	for (field = 1; field <= numfields; field++) {
		Candidates[NR][headernames[field]] = inputarray[field]
	}
	## Populate Municipalities arrays
	if ("" != Candidates[NR]["Name"]) {
		Municipalities[Candidates[NR]["Municipality"]]++
		MunicipalitiesURL[Candidates[NR]["Municipality"]] = Candidates[NR]["MunicipalityURL"]
		MunicipalitiesLogo[Candidates[NR]["Municipality"]] = Candidates[NR]["MunicipalityLogo"]
		## Populate Offices arrays
		Offices[Candidates[NR]["Office"]]++
		Elect[Candidates[NR]["Office"],Candidates[NR]["Municipality"]] = Candidates[NR]["Elect"]	# Build an array of Offices, use "Elect" for later use
        CandidatesInOffice[Candidates[NR]["Office"],Candidates[NR]["Municipality"]]++

	}	# if ("" != Candidates[NR]["Name"]
}

# (NR > 2)
END {









	printhtmlhead(heading[1] " - " heading[2], "noclose")
	print (" <link rel=\"stylesheet\" href=\"../candidates.css\" type=\"text/css\">")
	print ("</head>")

	print ("<!--")
	print ("This information is provided as-is. Data is public information and not subject to copyright.")
	print ("Images and logos are copyright and trademarked by their respective owners; their source is linked in the entry.")
	print ("They are used under \"Fair Dealing\" as news reporting.")
	print ("")
	print ("Other material on this page is Copyright (c) " strftime("%Y") " by Bob Jonkman")
	print ("and released under a Creative Commons Attribution-only Share-Alike license: http://creativecommons.org/licenses/by-sa/4.0/")
	print (" -->")

	print ("<body>")
	print ("<div  id=\"top_of_page\" class=\"header\">")
	print (" <!--#include virtual=\"header.ssi\" -->")
	print ("</div> <!-- class=header -->")

    hlevel = 1
    for (hnum=1 ; hnum <= numheadings; hnum++) {
      if ("" != trim(heading[hnum]) )
        print " <h" hlevel ">" makehtml(heading[hnum]) "</h" hlevel ">"
        hlevel<=6 ? hlevel++ : 6
    }

# strftime parameters: %l=12hour, %M=Minute, %P=ampm, %Z=Timezone, %A=Weekday,%e=DoM, %B=Month
	print ("<p>This page was updated at " strftime("%l:%M%P (%Z) %A %e %B %Y") "</p>")

# Get Municipalities and Offices in alphabetical order
	numMunicipalities = asorti(Municipalities)

	numOffices = asorti(Offices)





	# Create table of Municipalities and Offices
	print (" <table")
        print ("  class=\"candidates\"")
	print (">")
	print ("  <thead>")
	print ("  <tr>")
	print ("    <th>&nbsp;</th>")
	for (Municipality = 1; Municipality <= numMunicipalities; Municipality++) {
		if ("" != Municipalities[Municipality]) {
			print ("      <th><a class=\"internal\" href=\"#" valnameid(Municipalities[Municipality]) "\" title=\"Jump to " Municipalities[Municipality] "\">" Municipalities[Municipality] "</a></th>")
		}		# if ("" == Municipalities[])
	}	# for Municipality in Municipalities[]
	print ("   </tr>")
	print ("  </thead>")
	print ("  <tbody>")
	for (Office = 1; Office <= numOffices; Office++) {



		if ("" != Offices[Office]) {
			print ("   <tr>")
			print ("    <th>" Offices[Office] "</th>")
			# list candidates for Municipality here
			for (Municipality = 1; Municipality <= numMunicipalities; Municipality++) {
				if ("" != Municipalities[Municipality]) {
					print "    <td>"
					for (Candidate in Candidates) {
						if ((Candidates[Candidate]["Municipality"] == Municipalities[Municipality]) && (Candidates[Candidate]["Office"] == Offices[Office])) {
						  candidateclass = " "  # clear previous value, space to provide separator between existing class string


                        # Sort out Withdrawn and Registered classes before assigning candidate class
                        ## If the candidate is withdrawn then there is no Registered or Unregistered
                         if (Candidates[Candidate]["Not_Running"]) {
                            Candidates[Candidate]["Unregistered"] = ""
                         } else {

                           if (Candidates[Candidate]["Registered"]) {
                             Candidates[Candidate]["Unregistered"] = ""  # If Registered exists then clear Unregistered
                           } else {
                             Candidates[Candidate]["Unregistered"] = "Unregistered"
                           } # if Registered

                         } # if Withdrawn


						# Construct a class for this candidate (used for styling)
					     for (classflag in classarray) {

							if ("" != Candidates[Candidate][classflag]) {
							    candidateclass = candidateclass " " tolower(classflag)
						    }  # if "" != classflag
						 } # for classflag in classarray
						 Candidates[Candidate]["candidateclass"] = candidateclass  # save for use in list of candidates

						 print "<a href=\"#" makeid(Candidate) "\" title=\"" Candidates[Candidate]["Name"] "\" class=\"internal " candidateclass " \" >" Candidates[Candidate]["Name"]
						 if (Candidates[Candidate]["Incumbent"]) {
							    print " (Incumbent)"
							}

                         if (Candidates[Candidate]["Not_Running"]) {
						   print " (" Candidates[Candidate]["Not_Running"] ")"   # Might contain "Deceased" or other text (which will appear in the candidate's entry)
						 }

				         if (Candidates[Candidate]["Unregistered"]) {
                           print " (Unregistered)"
						 }  # if "" != Unregistered

						 if (Candidates[Candidate]["Elected"]) {
						   print " (" Candidates[Candidate]["Elected"] ")"  # Might contain "Elected" or "Acclaimed"
						 }

						print "</a><br>"
					  }	# if (candidate matches)
					}	# for (Candidate in Candidates)
					print ("    </td>")
				}				# if ("" != Municipalities[])
			}	# for (Municipality in Municipalities)
			print ("   </tr>")
		}		# if ("" != Offices[Office]["Name"])
	}	# for (Office in Offices)
	print ("  </tbody>")
	print (" </table>")





	# Create the list of candidates
	for (Municipality = 1; Municipality <= numMunicipalities; Municipality++) {


		if ("" != Municipalities[Municipality]) {
			print (" <h3 id=\"" valnameid(Municipalities[Municipality]) "\"><a href=\"#top_of_page\" title=\"Go to the top of this page\" class=\"internal navaid\">&thinsp;^&thinsp;</a> " Municipalities[Municipality])
			if ("" != MunicipalitiesURL[Municipalities[Municipality]]) {
				print ("  <a href=\"" MunicipalitiesURL[Municipalities[Municipality]] "\" title=\"Information about " Municipalities[Municipality] "\">")
				if ("" != MunicipalitiesLogo[Municipalities[Municipality]]) {
					print ("   <img class=\"icon\" src=\"" MunicipalitiesLogo[Municipalities[Municipality]] "\" alt=\"Municipality logo\"> Info")
				} else {
					print ("Information about " Municipalities[Municipality] "")
				}	# if (Municpalities logo exists)
				print ("  </a>")
			}			# if (Municipalities URL exists)
			print (" </h3>")

### Construct an array of Candidates in Office so we avoid printing Offices with no candidates (or Offices that don't apply to a Muncipality)
#            for ( Candidate in Candidate ) {
#                if ( Candidates[Candidate]

			for (Office = 1; Office <= numOffices; Office++) {


                if ( CandidatesInOffice[Offices[Office],Municipalities[Municipality]] ) { # If there is at least one candidate running for this office
					print "<h4 id=\"" valnameid(Offices[Office] "-" Municipalities[Municipality]) "\">"
					print "<a href=\"#top_of_page\" title=\"Go to the top of this page\" class=\"internal navaid\">&thinsp;^&thinsp;</a> "
					print "    <a href=\"#" valnameid(Municipalities[Municipality]) "\" title=\"Up to the start of " Municipalities[Municipality] "\" class=\"internal navaid\">&thinsp;&uArr;&thinsp;</a> "
					print Offices[Office] " - " Municipalities[Municipality]
                    if ( Elect[Offices[Office],Municipalities[Municipality]] > 0 ) {
                        print "	: Elect " Elect[Offices[Office],Municipalities[Municipality]]
					} # if ( Elect > 0 )
					print "</h4>"
					print "<dl>"
					for (Candidate in Candidates) {
						if (("" != Candidates[Candidate]["Name"]) && (Candidates[Candidate]["Municipality"] == Municipalities[Municipality]) && (Candidates[Candidate]["Office"] == Offices[Office])) {

							print " <dt id=\"" makeid(Candidate) "\" class=\"h-card\">"
							print "<a href=\"#top_of_page\" title=\"Go to the top of this page\" class=\"internal navaid\">&thinsp;^&thinsp;</a> "

						        print "<a href=\"#" valnameid(Municipalities[Municipality]) "\" title=\"Up to the start of " Municipalities[Municipality] "\" class=\"internal navaid\">&thinsp;&uArr;&thinsp;</a> "
							print "<a href=\"#" valnameid(Offices[Office] "-" Municipalities[Municipality]) "\" title=\"Up to " Offices[Office] " - " Municipalities[Municipality] "\" class=\"internal navaid\" >&thinsp;&uarr;&thinsp;</a> "

                            print "<span class=\"" Candidates[Candidate]["candidateclass"] "\">"  Candidates[Candidate]["Name"]
							if (Candidates[Candidate]["Not_Running"]) {
							    print " <strong>(" Candidates[Candidate]["Not_Running"]  ")</strong>"
							} else {  # Registered status is only valid if the candidate is not withdrawn
							  if (Candidates[Candidate]["Registered"] == "") {
							      print " <strong>(Unregistered)</strong>"
							  }
							}
							if (Candidates[Candidate]["Incumbent"]) {
							    print " <strong>(Incumbent)</strong>"
							}
							if (Candidates[Candidate]["Elected"]) {
							    print " <strong>(" Candidates[Candidate]["Elected"]  ")</strong>"
							}
							print "</span>"

							print ("     <a href=\"#" makeid(Candidate) "\" title=\"Anchor link for " Candidates[Candidate]["Office"] " candidate in " Municipalities[Municipality] " \" class=\"internal\">&#x2693;</a>")

						    print "<a href=\"searchassistant.html#" makeid(Candidate) "\" title=\"Find this candidate on the Search Assistant\" class=\"right\">&#x1F50E;</a>"

							print " </dt>"
							print ("   <dd  class=\"h-card\">")
							print ("    <div class=\"aside\">")
							if ("" != Candidates[Candidate]["ImageURL"]) {
								if ("" != Candidates[Candidate]["Website"]) {
									### Ensure we only get the first URL when there are multiples
									split(Candidates[Candidate]["Website"], urls, " ")
									print ("<a  href=\"" urls[1] "\" title=\"" gettitle(urls[1]) "\">")
								}								# if ("" != Candidates[Website])
								print ("     <img src=\"" Candidates[Candidate]["ImageURL"] "\" alt=\"" Candidates[Candidate]["Name"] "\">")
								if ("" != Candidates[Candidate]["Website"]) {
									print ("</a>")
								}								# if ( "" != Candidates[Website])
							} else {	# if ("" != Candidates[ImageURL])
								print ("     <p>No Image</p>")
							}	# if ("" != Candidates[ImageURL])
							print ("    </div> <!-- class=aside -->")
							print ("    <ul>")

### Print candidatae attributes
							for (Attribute in Candidates[Candidate]) {


								if (Attribute in skipAttributes) { # if Attribute is in skipAttributes
									continue	# don't list static attributes
								}	# if (Attribute ~ skipAttributes)
								if ("" != Candidates[Candidate][Attribute]) {
    								print "     <li><b>" Attribute "</b>: " makehtml(Candidates[Candidate][Attribute]) "</li>"
								} # if ("" != Candidates[Attribute])
							}	# (for Attribute in Candidates)

			if ("" != Candidates[Candidate]["Address"]) {
				### Automatically fetch OSM link
    			print ("     <li class=\"h-adr\"><b>Postal Address</b>:")

				### If we parse out address info
	    		###          print ("      <p style=\"margin-left:2em;\">")
			    ###          print("<!-- <span class=\"p-street-address\">XXXXXSTREETADDRESS</span>,<br><span class=\"p-locality\">XXXXXLOCALITY</span>, <span class=\"p-region\">Ontario</span>,<br><span class=\"p-country\">Canada</span>&emsp;<span class=\"p-postal-code\">XXXXXPOSTALCODE</span> -->") ;
                ###         print ("       </p>")

				### If we DON'T parse out address info (monolithic addresses)
				print ("      <span class=\"p-address\">" Candidates[Candidate]["Address"] "</span> <a class=\"map\" href=\"https://www.openstreetmap.org/search?query=" txt2uri(Candidates[Candidate]["Address"]) "\" title=\"OpenStreetMap: " Candidates[Candidate]["Address"] "\">Map</a>")
    			print ("     </li>")
			}

							print "     </ul>"
							print ("    <br>")	# Ensure images don't extend beyond <dl> box
							print ("   </dd>")
							print ("")
						}						# if ("" != Candidates[Name])
					}	# for candidate in candidates
					print (" </dl>")
					print ("")
				}				# if ("" != Offices[])
            }  # if (CandidatesInOffice > 0 )
		}		# if ("" != Municipalities[[])
	}	# for (Municipality in Municipalities)
	print ("<div class=\"footer\">")
	print (" <!--#include virtual=\"footer.ssi\" -->")
	print (" <p class=\"bottom\">This page was last updated <span class=\"datetime\" title=\"" strftime("%FT%T%z") "\">" strftime("%A, %e %B %Y at %l:%M%P %Z") "</span></p>")
	print ("</div> <!-- class=footer -->")
	print ("</body>")
	print ("</html>")
	print ("")
} # END

# EOF: csv2municipalcandidates.awk



   

 ↑  csv2candidates-search.awk

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from csv2candidates-search.awk


#! /bin/gawk -f

# Program   :	csv2candidates-search.awk
# Purpose   :	Generate a table with links to simplify searching for missing data
# Author    :	Bob Jonkman bjonkman@sobac.com
# Date      :	15 August 2022
# Based on  :	csv2municipalcandidates.awk
# Modified  :	14 Nov 2023 - Added "Party" and "Riding" to id and search term
#		23 Nov 2023 - Create columns for all services we know
#       13 May 2026 - Moved code to generate page headers and start of table to (NR == 2)
#                   - Made concatfields and xxx deterministic (always in same order, name first)
#                   - Add headings from first row

# Copyright (c) 2020-2022 Bob Jonkman and/or SOBAC Microcomputer Services

#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <https://www.gnu.org/licenses/>.


# Usage     :	gawk -f csv2municipalcandidates-search.awk candidates.csv

# Records   :	1st line: Fields are headers <h1> to <h6>
#           :	2nd line: Field header names
#           :	3rd line to end: Data

# Fields    :	Fieldnames with * are required, cannot be empty.
#                 Other fields appear only if not empty
#               Fieldnames with ! are used to group entries and are used for layout.
#                 Fieldnames with ! must exist, fields may be empty. Itemized in
#                 variable skipAttributes, used to skip in attribute lists
#             Fields are referenced by header name,
#                 the second line MUST be a field header line

#
#  Static Fields (must exist, if blank the entry is ignored):

#           1 Name

# Optional Static Fields (field must exist, but may be blank)
#                  Address     (single line monolithic, at the moment. May use sub-fields later)
#                  Website
#                  E mail
#                  Phone

# Dynamic Fields (field may or may not exist, and may be blank)
#               "Twitter","Facebook","Instagram","YouTube","LinkedIn", &c.
#               (social media URLs) field numbers may vary  (will eventually be parsed for @Twitter and @instagram)

@include "library.awk"

function makeid(candidatenumber,   concatfieldname,concatid)
{
  concatid=""
  for ( concatfieldname in concatfields ) {
    if ( "" != inputarray[headernums[concatfieldname]] ) {
    }
  }
	return (valnameid(concatid))
}

function printURL(URL,LinkText,Class)
{
        print "<a href=\"" URL "\" title=\"Search: " txt2uri(LinkText) "\" class=\"" Class "\" target=\"_blank\">" txt2html(LinkText) "</a>"
}

function printsearch(URL,LinkText,   LinkFrag,LinkArray,URLArray)
{   if ( "" == inputarray[headernums[LinkText]] ) {
        Class="red"
    }
    else {
        Class="green"
    }

    print "<td class=\"searchcell\">"
    printURL(URL,LinkText,Class)

    if ("green" == Class) {   ### Putting this here is a horrible kludge. To fix later. -Bob 2025-02-07
        print "<br>"


        split(inputarray[headernums[LinkText]],URLArray," ")


        LinkFrag = split(URLArray[1],LinkArray,"/")
        if ( "" == LinkArray[LinkFrag] ) {
           LinkFrag--
        }


        printURL(URLArray[1],LinkArray[LinkFrag])
    }
    print "</td>"
}


BEGIN {
	#	IFS = ","
	#	OFS = " "
	#	IGNORE	case = 1   # for sorting

	#	staticfields = 7
	#    Municipalities[0][0]=""  # Initialize 2D array

	## Special Purpose fields are ignored in the candidates' list of resources
	### Some are used for images, some for class names (CSS styling), some for page layout
#	skipAttributes["Name"]=1                # Used for header, ID
	skipAttributes["Office"]=1              # Used for grouping, ID
	skipAttributes["Elect"]=1               # Additional info for Office
	skipAttributes["Municipality"]=1        # Used for grouping, ID
	skipAttributes["MunicipalityURL"]=1     # URL to municipal website
	skipAttributes["MunicipalityLogo"]=1    # URL to image
	skipAttributes["Riding"]=1              # Riding name
	skipAttributes["RidingURL"]=1           # URL to Elections Canada/Ontario website
	skipAttributes["RidingLogo"]=1          # URL to Elections Canada/Ontario logo
	skipAttributes["PartyShortName"]=1      # selector in VLOOKUP
	skipAttributes["Party"]=1               # Party Name
	skipAttributes["PartyURL"]=1            # URL to Party URL
	skipAttributes["PartyLogo"]=1           # URL to Party logo
	skipAttributes["ImageURL"]=1            # URL to candidate image
	skipAttributes["Incumbent"]=1           # Class name (styling), indicator
	skipAttributes["Unregistered"]=1        # Class name (styling), indicator
	skipAttributes["Registered"]=1          # Negation of "Unregistered", since Feb 2025
	skipAttributes["Elected"]=1             # Class name (styling), indicator
	skipAttributes["Withdrawn"]=1
	skipAttributes["Address"]=1             # Used for OpenStreetMap lookup


### Things to not search for
	skipAttributes["Website"]=1 # (maybe a general websearch, later)
	skipAttributes["Notes"]=1
	skipAttributes["Calendar"]=1
	skipAttributes["Votes"]=1
	skipAttributes["HiddenNotes"]=1


### Fields to concatenate for search
   concatfields[1]="Name"
   concatfields[2]="Municipality"
   concatfields[3]="Office"
   concatfields[4]="Riding"
   concatfields[5]="Party"

} # BEGIN

# Get headings, itle and subtitle(s)
(NR == 1) { numheadings = parsecsv($0,heading)

} # (NR ==1 )

# Read the column headers
(NR == 2) {
  numfields = getheaders($0, headernums, headernames)
    # Write the headers and table start up front
    LINKREL[1]="<link rel=\"stylesheet\" href=\"../candidates.css\" type=\"text/css\">"
	LINKREL[2]="<link rel=\"shortcut icon\" href=\"https://poliblog.jonkman.ca/blogs/pollywog-32x32b.jpg\" type=\"image/x-icon\">"

	printhtmlhead("Search for Missing Candidate Data | " heading[1] " | " heading[2])

	print ("<!--")
	print ("This information is provided as-is. Data is public information and not subject to copyright.")
	print ("Images and logos are copyright and trademarked by their respective owners; their source is linked in the entry.")
	print ("They are used under \"Fair Dealing\" as news reporting.")
	print ("")
	print ("Other material on this page is Copyright (c) " strftime("%Y") " by Bob Jonkman")
	print ("and released under a Creative Commons Attribution-only Share-Alike license: http://creativecommons.org/licenses/by-sa/4.0/")
	print (" -->")

    print "<body>"
	print ("<div  id=\"top_of_page\" class=\"header\">")
	print (" <!--#include virtual=\"header.ssi\" -->")
	print ("</div> <!-- class=header -->")
    print " <h1>Search for Missing Candidate Data</h1>"

    hlevel = 2
    for (hnum=1 ; hnum <= numheadings; hnum++) {
      if ("" != trim(heading[hnum]) )
        print " <h" hlevel ">" makehtml(heading[hnum]) "</h" hlevel ">"
        hlevel<=6 ? hlevel++ : 6
    }

    print "  <p>Filename: " txt2html(ARGV[1]) "<br>"
    print "    Date: "
    system("stat -c %y " ARGV[1] )
    print "<br>Generated: " strftime("%FT%T") "</p>"

##### Apparently, borders="" and caption="" is no longer a valid attribute for <table>
    print " <table>"
    print "  <thead>"
    print "   <tr>"
    print "    <td>Search: Name, Locality</td>"
    print "    <td>Phone</td>"
    print "    <td>Email</td>"
    print "    <td>Twitter(X)</td>"
    print "    <td>Bluesky</td>"
    print "    <td>Facebook</td>"
    print "    <td>Instagram</td>"
    print "    <td>LinkedIn</td>"
    print "    <td>YouTube</td>"
    print "    <td>Vimeo</td>"
    print "    <td>Reddit</td>"
    print "    <td>Pinterest</td>"
    print "    <td>Flickr</td>"
    print "    <td>Tumblr</td>"
    print "    <td>MySpace</td>"
    print "    <td>TikTok</td>"
    print "    <td>Twitch</td>"
    print "    <td>Snapchat</td>"
    print "    <td>Threads</td>"
    print "    <td>Fediverse</td>"
    print "    <td>Wikipedia</td>"

# (add others as they're discovered)

    print "   </tr>"
    print "  </thead>"
    print "  <tbody>"

}

# Read rest of the file
(NR > 2) {
	numfields = parsecsv($0, inputarray)

	# If name is blank then advance to next record
	if ( "" == inputarray[headernums["Name"]] ) {
	    next
	}

    print "   <tr>"

### No need to step through fields, we only create links for services we know about

### General search (Startpage (was Google)


        searchfieldsquote = ""
        searchfieldsbr = ""
        searchfieldsdash = ""



	for ( i=1; i<=length(concatfields); i++) {
          if ( "" != inputarray[headernums[concatfields[i]]] ) {
            searchfieldsquote = searchfieldsquote txt2uri("\"" inputarray[headernums[concatfields[i]]] "\" ")
            searchfieldsbr = searchfieldsbr  inputarray[headernums[concatfields[i]]] "<br>"
            searchfieldsdash = searchfieldsdash inputarray[headernums[concatfields[i]]] "-"
          } # if ("" != inputarray)
	} # for (concatfields)

	print "    <td id=\"" valnameid(searchfieldsdash) "\">"
	print "<a href=\"index.html#" valnameid(searchfieldsdash) "\" title=\"Main entry for " searchfieldsdash " \" class=\"right\">&oplus;</a>"

 	print "<a href=\"https://www.startpage.com/sp/search?query=" searchfieldsquote "\" title=\"Startpage Search\" target=\"_blank\" >" searchfieldsbr "</a>"

	print "<a href=\"#" valnameid(searchfieldsdash) "\" title=\"Search Assistant Anchor for " searchfieldsdash "\" class=\"right internal\">&#x2693;</a>" # UTF 'anchor' glyph


	if (inputarray[headernums["Website"]]) {
	  numWebs = split(inputarray[headernums["Website"]],Webs," ")
	  for (num in Webs) {
	    print "<a href=\"" Webs[num] "\"  title=\"Go to: " Webs[num] "\" class=\"right\" target=\"_blank\">&#128279;</a> " # UTF 'link' glyph
	  } # for (num in Webs)
        } # if (inputarray)

	print "</td>"

### Phone Number
	print "<td class=\"phone\">"
        numPhones = split(inputarray[headernums["Phone"]],Phones," ")
        for (num in Phones) {
          Phone = substr(Phones[num],index(Phones[num],"-")+1)
          printURL("https://www.startpage.com/sp/search?query=" txt2uri("\"" Phone "\""), Phone)
          print "<br>"
        } # for (num in Phones)

        print "</td>"

### E-mail
        print "<td class=\"email\">"
        numEmails = split(inputarray[headernums["Email"]],Emails," ")
        for (num in Emails) {
          printURL("https://www.startpage.com/sp/search?query=" txt2uri("\"" Emails[num] "\""), Emails[num])
          print "<br>"
        } # for (num in Emails)

        print "</td>"

### Social Media sites

	printsearch("https://x.com/search?src=typed_query&amp;f=user&amp;q=" txt2uri(inputarray[headernums["Name"]]), "Twitter(X)")
	printsearch("https://bsky.app/search?q=" txt2uri(inputarray[headernums["Name"]]), "Bluesky")
	printsearch("https://www.facebook.com/search/top/?q="  txt2uri(inputarray[headernums["Name"]]), "Facebook")
	printsearch("https://www.instagram.com/explore/search/keyword/?q="  txt2uri(inputarray[headernums["Name"]]), "Instagram")
	printsearch("https://linkedin.com/search/results/people/?keywords="  txt2uri(inputarray[headernums["Name"]]), "LinkedIn")
	printsearch("https://www.youtube.com/results?sp=EgIQAg%253D%253D&amp;search_query="  txt2uri(inputarray[headernums["Name"]]), "YouTube")
	printsearch("https://vimeo.com/search/q=" txt2uri(inputarray[headernums["Name"]]), "Vimeo")
	printsearch("https://www.reddit.com/search/?type=user&amp;q=" txt2uri(inputarray[headernums["Name"]]), "Reddit")
	printsearch("https://www.pinterest.ca/search/pins/?q=" txt2uri(inputarray[headernums["Name"]]), "Pinterest")
	printsearch("https://www.flickr.com/search/people/?username="  txt2uri(inputarray[headernums["Name"]]), "Flickr")
	printsearch("https://www.tumblr.com/search/"  txt2uri(inputarray[headernums["Name"]]), "Tumblr")
	printsearch("https://myspace.com/search/people?q="  txt2uri(inputarray[headernums["Name"]]), "MySpace")
	printsearch("https://www.tiktok.com/search/user?q="  txt2uri(inputarray[headernums["Name"]]), "TikTok")
	printsearch("https://www.twitch.tv/search?term=" txt2uri(inputarray[headernums["Name"]]), "Twitch")
    printsearch("https://www.snapchat.com/explore/" txt2uri(gensub(" ","-","G",inputarray[headernums["Name"]])) "/profiles", "Snapchat")
    printsearch("https://www.threads.net/search?filter=profiles&q=" txt2uri(inputarray[headernums["Name"]]), "Threads")
    printsearch("https://thecanadian.social/search?type=accounts&q=" txt2uri(inputarray[headernums["Name"]]), "Fediverse")
    printsearch("https://en.wikipedia.org/wiki/Special:Search?search=" txt2uri(inputarray[headernums["Name"]]), "Wikipedia")

    print "   </tr>"

} # (NR > 2)


END {   print "  </tbody>"
        print " </table>"
        print " <div class=\"footer\">"
        print (" <!--#include virtual=\"footer.ssi\" -->")
    	print (" <p class=\"bottom\">This page was last updated <span class=\"datetime\" title=\"" strftime("%FT%T%z") "\">" strftime("%A, %e %B %Y at %l:%M%P %Z") "</span></p>")
    	print (" </div> <!-- class=footer -->")
    	print ("</body>")
    	print ("</html>")
    	print ("")
}


# EOF: csv2candidates-search.awk



   

 ↑  candidates.css

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from candidates.css


/* ******************************************************** *\
** File     :   candidates.css
** Purpose  :   Stylesheet for Candidates contact list
** Author   :   Bob Jonkman bjonkman@sobac.com
** Date     :   2 May 2022
\* ******************************************************** */

body		{	background-image: none ; /* override default.css */
		}
/* The Party Logo */
 .p-org img { width: auto ;
              max-width: 140px ;
              height: auto ;
              max-height: 140px ;
              background: #888 ;
              border: thin solid black ;
              float: right ;
              margin-right: 5em;
              margin-left: 1em ;
           }

 img.icon   { margin: 0 .5em;
              vertical-align: middle;
              height: 3ex;
              width: auto ;
/*              padding: 0 .3em ; */
            }

 .aside     { text-align: center ;
            }

 .aside img { max-width : 150px ;
              max-height: 150px ;
              margin-left: auto ;
              margin-right: auto ;
            }

 dl li      { margin-bottom: 2.5ex ;  /* line spacing */
              list-style-type: none ;
            }

 dd br      { clear: both ;
            }

 table	    { font-size: small ;
            }
 td	    { background: #eee ;
            }

/* Put each candidate link in a full-cell-width box */
table.candidates td a { display: block ;
		  margin: .1ex 0 ;
		  border: thin solid black ;
		  padding: .3em ;
		  background: white ;
}

td br		{ height: 0 ;
		  margin: 0 ;
}

/* in searchassistant.html */
td.searchcell { text-align:center ;
}

/* Candidates name in main candidate list */
 dt.h-card span { padding: 0 .3em ;
}


/* Flags */

 .incumbent
    { outline: thick solid fuchsia ;
}

 .withdrawn,
 .not_running
    { text-decoration: line-through !important ;
      background: #CCC !important ; /* medium grey */
}

 .unregistered
 	{ background: orange !important ; /* light orange */
}

 .elected
    { background: lime !important ; /* light green */
}

/* EOF: candidates.css */

   

 ↑  /home/bjonkman/bin/awk/csv2html.awk

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from /home/bjonkman/bin/awk/csv2html.awk


#! /usr/bin/gawk -f

# Program    : CSV2HTML.AWK
# Purpose    : Convert a CSV file into an HTML table
# Date       : 18 February 2005
# Author     : Bob Jonkman <bjonkman@sobac.com>

# Copyright 2008 Bob Jonkman and/or SOBAC Microcomputer Services

#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.


# Modified   : 3 February 2006 - Added navaids "Go to the top of this page"
#              31 March 2006   - Changed default from HTTP to NOHTTP primarily in dynamic pages
#                              - Added other code (eg. QUERY_STRING) for dynamic pages
#              25 Sept 2006    - Added "Prev, Next" navigational aids
#              9 January 2007  - Added id attributes to all TR elements
#              30 May 2007     - Using tempfile to place tfoot before tbody
#              6 March 2008    - Added table sorting with sorttable.js
#                                from http://www.kryogenix.org/code/browser/  by Stuart Langridge
#              21 May 2008     - Fixed bug where an empty <tbody> would come from previous file
#                                    (required considerable re-organizing of code)
#                              - Added "1 file(s) processed" logic
#              4 June 2008     - added SVG object when PLOT==1
#              1 May  2022     - Added "@include library.awk" (is this a new feature?)
#              12 Nov 2023     - Added title to LINK anchor
#                              - Create variable VeRsIoN, set to 2023-11-12
#              6  Feb 2025     - Cleaned up code to HTML5 standard
#                                - Removed <table> attributes 'summary' and 'borders'
#                                - Removed <script> attribute 'type'
#                                - Removed <a> attribute 'name'
#                              - Check for existence of ENVIRON["TEMP"] before creating tempfile

BEGIN {	VeRsIoN="2025-02-06" ;
}

# Usage      : gawk -f CSV2HTML.AWK -f LIBRARY.AWK [-v TITLE=title] [0*(-v variable=(0|1) )] 1*(filename.csv)
#               http:\\hostname\csv2html.awk?FILENAME=filename.csv[1*(+filename.csv)][&TITLE=title][0*(&variable(0|1))]
# Note       : Use a literal + to separate filenames in URI

# Variables  :   TITLE = (text) HTML <title> and <h1> elements for the page
#                PLOT   = if TRUE inserts FILENAME.svg object element with fallback to FILENAME.png
#                LINK  = if TRUE Creates link to FILENAME for each table
#                NOHEADER = if TRUE Does not place the first line of CSV file in THEAD entity
#                NOHTTP  = if TRUE Suppresses a "Content-type: text/html" line for dynamic pages
#                SORTABLE = if TRUE adds script=sorttable.js to head and class="sortable" to tables

#
# Optional vars: FIELD_SEPARATOR  (default == ",")
#                FIELD_DELIMITER  (default == QUOTE )
#                RECORD_SEPARATOR (default == "\n")

@include "library.awk" ;

function printbody(printtext)   {           # Send <tbody> parts to temporary file
            if(!tfootflag)
                print(printtext) > tempfile ;
            else
                print(printtext) ;
}

function finishtable()  {
                            if(tfootflag)
                            {   print("    </tfoot>") ;
                            }

                            if(tbodyflag)
                            {
                                close(tempfile) ;   #   stop writing to tempfile
                                print("    <tbody>") ;

                                while(getvalue = (getline templine < tempfile) > 0)
                                {
                                    print(templine) ;     #   copy all records to standard output
                                }

                                close(tempfile) ;   #   stop reading from file

                                if(ENVIRON["windir"])
                                    system ("del " tempfile) ;  #   Clean up after yourself.
                                else
                                    system ("rm "  tempfile) ;

                                print("    </tbody>") ;
                            } else
                            {
                                if(tableflag)   # If a <table> was printed
                                {               #    then print a vestigial <tbody>
                                    print("    <tbody>") ;
                                    print("     <tr>") ;
                                    print("      <td>") ;
                                    print("      </td>") ;
                                    print("     </tr>") ;
                                    print("    </tbody>") ;
                                }
                            }

                            if(tableflag)
                            {
                                print("   </table>")
                                print("   </div> <!-- end of id=" QUOTE valnameid(FILENAME) QUOTE " -->") ;
                                print("")
                            }
                            tfootflag = 0 ;
                            tbodyflag = 0 ;
                            tableflag = 0 ;
                }


function makemenu(topofpage)    {
    # Create header/footer menu
    # parameter==TRUE then include "Top of page" link
            print("  <div class=" QUOTE "menu" QUOTE ) ;
            if(!topofpage)  # if this is NOT at the top of page then ...
                print("        id=" QUOTE "toc" QUOTE ) ;
            print("   >")
            print("   <p>In this page:</p>") ;
            print("   <ul>" )

            if (topofpage)
            {
                print("    <li>[<a href=" QUOTE "#top-of-page" QUOTE " class=" QUOTE "internal" QUOTE ">Top of this page</a>] </li>")
                print("    <li>[<a href=" QUOTE "#toc" QUOTE " class=" QUOTE "internal" QUOTE ">Table of Contents</a>] </li>")
            }

            for(i=1; i<ARGC; i++)
            {
                print("    <li>[<a class=" QUOTE "internal" QUOTE " href=" QUOTE "#" valnameid(ARGV[i]) QUOTE ">" txt2html(ARGV[i]) "</a>] </li>")
            }
            print("   </ul>")
            print("  </div> <!-- end of menu  -->")
}




BEGIN    {  version = "\nVeRsIoN= csv2html.awk " VeRsIoN "\nCoPyRiGhT= Copyright under GNU GPLv3 2008 by Bob Jonkman  bjonkman@sobac.com \n"

            QUOTE = "\"" ;

            if(!FIELD_SEPARATOR)
                FIELD_SEPARATOR = "," ;

            if(!FIELD_DELIMITER)
                FIELD_DELIMITER = "\"" ;

            if(!RECORD_SEPARATOR)
                RECORD_SEPARATOR = "\n" ;

##### Find a way to use 'mktemp' instead  --Bob 2025-02-06 
            tempfile = (ENVIRON["TEMP"] ? ENVIRON["TEMP"] "\\" : "") "csv2html" PROCINFO["pid"] ".tmp" ;     # Temporary file for storing <tbody> parts

            parsecgi(ENVIRON["QUERY_STRING"],qstring)

            if(ARGC == 1)   # no files on the command line
            {
                if(qstring["FILENAME"])
                {
                    ARGC = 1 + split(qstring["FILENAME"],ARGV," ")
                }
            }

            if(!TITLE)
                TITLE = qstring["TITLE"]

            if(!TITLE)          # if there is still no title then...
                TITLE = "Tables from CSV files"

            if(!PLOT)
                PLOT = qstring["PLOT"]

            if(!LINK)
                LINK = qstring["LINK"]

            if(!NOHEADER)
                NOHEADER = qstring["NOHEADER"]

            th = NOHEADER ? "td" : "th" ;  # if NOHEADER then first column cell is <td> else <th>

            if(!SORTABLE)
                SORTABLE = qstring["SORTABLE"]

            if(SORTABLE)
                LINKREL["sortable"] = "<script src=\"/bin/javascript/sorttable.js\"></script>  <!-- from http://www.kryogenix.org/code/browser/  by Stuart Langridge -->" ;

        printhtmlhead(TITLE)

        print(" <body>") ;
        print("  <div>") ;
        print("   <a id=" QUOTE "top-of-page" QUOTE ">");
        print("    <!-- " version " -->");
        print("   </a>") ;
        print("  </div>") ;

#        print("   <div id=" QUOTE "header" QUOTE ">") ;
#        print("    <a href=" QUOTE "/" QUOTE) ;
#        print("      title=" QUOTE "" QUOTE ">") ;
#        print("    <img") ;
#        print("        src=" QUOTE "/images/sitelogo.png" QUOTE ) ;
#        print("        alt=" QUOTE "Site logo" QUOTE ) ;
#        print("      style=" QUOTE "float: left ; height: 48px ; width: 150px ;" QUOTE "></a>") ;
#
#        print("    <a href=" QUOTE "/" QUOTE "") ;
#        print("      title=" QUOTE "" QUOTE ">") ;
#        print("    <img") ;
#        print("        src=" QUOTE "/images/siteicon.png" QUOTE ) ;
#        print("        alt=" QUOTE "Site icon" QUOTE ) ;
#        print("      style=" QUOTE "float: right ; height: 48px ; width: 48px ;" QUOTE "></a>") ;
#
#        print("    <br>") ;
#        print("    <hr>") ;
#        print("   </div><!-- end of header -->") ;
#        print("") ;

        print("  <h1>" makehtml(TITLE) "</h1>")

        if (ARGC == 1)
        {   print("  <div id=" QUOTE "content" QUOTE ">")
            print("   <p>No files specified, nothing to do!</p>")

            exit    # this will process END{}
        }

        if (ARGC > 2)       # If there is more than one file on the page
            makemenu(0) ;   #   create header menu without "Top of page" link

        print("  <div id=" QUOTE "content" QUOTE ">")

} # end of BEGIN


(FNR == 1)  {   # Finish off the previous file
                if(ARGIND > 1)        # check if we've processed multiple files
                    finishtable() ;


        print("   <div  id=" QUOTE valnameid(FILENAME) QUOTE ">") ;
        print("   <h2")
        if (ARGIND > 1)   #  Suppress page-break-before on the first file
            print("        style=" QUOTE "page-break-before: always ; " QUOTE )

        print("       >")

        if (ARGC > 2)   # Display "Prev, Top, Next" navigational aids
        {
            print("    <span class=" QUOTE "internal navaid" QUOTE ">")

            if (ARGIND > 1)       # suppress "Previous" for first file
            {
                print("     <a href=" QUOTE "#" valnameid(ARGV[ARGIND-1]) QUOTE)
                print("        title=" QUOTE "Previous Table: " txt2html(ARGV[ARGIND-1]) QUOTE)
                print("     >&larr;</a>")
            } else
            {   print("     <span class=" QUOTE "disabled" QUOTE ">&larr;</span>")
            }

            print("     <a href=" QUOTE "#top-of-page" QUOTE)
            print("        title=" QUOTE "Go to the top of this page" QUOTE)
            print("     >&thinsp;&uarr;&thinsp;</a>")

            if (ARGIND < ARGC-1 )    # suppress "Next" for last file
            {
                print("     <a href=" QUOTE "#" valnameid(ARGV[ARGIND+1]) QUOTE)
                print("        title=" QUOTE "Next Table: " txt2html(ARGV[ARGIND+1]) QUOTE)
                print("     >&rarr;</a>")
            } else
            {   print("     <span class=" QUOTE "disabled" QUOTE ">&rarr;</span>")
            }
        print("    </span>")
        }

        print("   " txt2html(FILENAME) "</h2>" )


        print("   <p>Generated on <abbr class=" QUOTE "datetime" QUOTE " title=" QUOTE strftime("%Y-%m-%dT%H:%M:%S") QUOTE ">" strftime("%a, %d %b %Y %H:%M:%S %z") "</abbr> from ")

        if(LINK)
            print("    <a href=" QUOTE txt2uri(FILENAME) QUOTE " title=" QUOTE "Download " txt2html(FILENAME) QUOTE ">" txt2html(FILENAME) "</a>")
        else
            print("    " txt2html(FILENAME))

        print("   </p>")
        print("")

        if(PLOT)
        {
            print("   <div class=" QUOTE "box svgobject" QUOTE ">") ;
            print("    <object data=" QUOTE txt2uri(FILENAME ".svg") QUOTE ) ;
            print("           title=" QUOTE "Plot of " txt2html(FILENAME) QUOTE ) ;
            print("            type=" QUOTE "image/svg+xml" QUOTE ) ;
            print("           >" ) ;
            print("     <img src=" QUOTE txt2uri(FILENAME ".png") QUOTE " alt=" QUOTE "Plot of " txt2html(FILENAME ".svg") QUOTE "/>");
            print("    </object>")  ;
            print("    <br>");
            print("    <a href=" QUOTE txt2uri(FILENAME ".svg") QUOTE ">");
            print("      Plot of " txt2html(FILENAME ".svg") ) ;
            print("    </a>") ;
            print("   </div><!-- end of svgobject -->");
            print("") ;
        }

        tableflag = 1 ;  # Yes, we've started a table
        print("   <table")

        if (SORTABLE)
            print("      class=" QUOTE "sortable" QUOTE ) ;

        print("         >")

} # end of (FNR == 1)

((FNR == 1) && (!NOHEADER))  {        # Do the headers, except if NOHEADER is specified
        print("    <thead>")
        print("     <tr id=" QUOTE "line" FNR "file" ARGIND QUOTE ">")
        delete hdr

        numfields = parsecsv($0,header)

        for(i=1; i <= numfields; i++)
        {
            hdr[i] = "hdr" i "file" ARGIND
            print("      <th")
            print("       id=" QUOTE hdr[i] QUOTE )      # doesn't need validnameid(hdr[i]) because we've generated hdr[i]
#           print("       style=" QUOTE "border: thin solid ;" QUOTE )
            print("         >" makehtml(header[i]) "</th>")
        }

        print("     </tr>")
        print("    </thead>")

        bodyflag = 1   # reading tbody

        next
} #end of ((FNR == 1) && (!NOHEADER))


($0 == "=====") {   # My convention for signalling footers in CSV files is "====="
                    tfootflag = 1      # now writing <tfoot>
                    print("    <tfoot>") ;
                    next               # Don't display the footer separator itself

} #end of ($0 == "=====")


((FNR > 1) || (NOHEADER))    {
        if(!tfootflag)      # If we're not writing <tfoot>...
            tbodyflag = 1 ; # ... we must be writing <tbody>

        numfields = parsecsv($0,row)

        printbody("     <tr   id=" QUOTE "line" FNR "file" ARGIND QUOTE ) ;
        printbody("        class=" QUOTE (FNR % 2 ? "odd" : "even" ) QUOTE ">") ;
        printbody("      <" th)       # Note that the first element in a column could be replaced with <th></th>

        if (hdr[1])
            printbody("           headers=" QUOTE hdr[1] QUOTE )

        printbody("         >" makehtml(row[1]) "</" th ">")

        for(i=2; i <= numfields; i++)
        {    printbody("      <td")
            if (hdr[i])
               printbody("      headers=" QUOTE hdr[i] QUOTE )
            printbody("          >" makehtml(row[i]) "</td>")
        }

        printbody("     </tr>")

    } #end of ((FNR > 1) || (NOHEADER))


END {   if(ARGIND)    # Tables are ended only if files have been processed
        {
            finishtable() ;
        }

        print("   <p>" ARGIND " file" ((ARGIND==1) ? "" : "s") " processed.</p>")
        print("  </div> <!-- end of content -->")

        if (ARGC > 2)       # If there is more than one file on the page
        {   print("  <div id=" QUOTE "footer" QUOTE ">")
            makemenu(1) ;   #   Create footer menu with "Top of page" link
            print("  </div> <!-- end of footer -->")
        }

        print(" </body>")
        print("</html>")

    } #end of END

# EOF: CSV2HTML.AWK
   

 ↑  /home/bjonkman/bin/awk/code2html.awk

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from /home/bjonkman/bin/awk/code2html.awk


#! /bin/gawk -f

# Program    : CODE2HTML.AWK
# Purpose    : Convert various program and code files to an HTML page with <code> constructs
# Date       : 13 October 2006
# Author     : Bob Jonkman <bjonkman@sobac.com>

# Copyright 2008 Bob Jonkman and/or SOBAC Microcomputer Services

#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.


# Usage      : gawk -f CODE2HTML.AWK -f LIBRARY.AWK [-v TITLE=title] [-v LINK=(0|1)] 1*(filename.csv)
#               http:\\hostname\code2html.awk?FILENAME=filename.ext[1*(+filename.ext)][&TITLE=title][&LINK=(0|1)]
# Note       : Use a + to separate filenames in URI

# Variables  :   TITLE = HTML <title> and <h1> elements for the page
#                LINK  = Creates link to FILENAME for each table
#                NOHTTP    = Suppress  a "Content-type: text/html" line for dynamic pages

@include "library.awk"

function makemenu(topofpage)    {
    # Create header/footer menu
    # parameter==TRUE then include "Top of page" link
            print("   <div class=" QUOTE "menu" QUOTE ) ;
            if(!topofpage)  # if this is NOT at the top of page then ...
                print("        id=" QUOTE "toc" QUOTE ) ;
            print("    >")
            print("    <p>In this page:</p>") ;
            print("    <ul>" )

            if (topofpage)
            {
                print("     <li>[<a href=" QUOTE "#top-of-page" QUOTE " class=" QUOTE "internal" QUOTE ">Top of this page</a>] </li>")
                print("     <li>[<a href=" QUOTE "#toc" QUOTE " class=" QUOTE "internal" QUOTE ">Table of Contents</a>] </li>")
            }

            for(i=1; i<ARGC; i++)
            {
                print("     <li>[<a class=" QUOTE "internal" QUOTE " href=" QUOTE "#" valnameid(ARGV[i]) QUOTE ">" txt2html(ARGV[i]) "</a>] </li>")
            }
            print("   </ul>")
            print("  </div> <!-- end of menu  -->")
}




BEGIN    {  QUOTE = "\""

            if(!FIELD_SEPARATOR)
                FIELD_SEPARATOR = "," ;

            if(!FIELD_DELIMITER)
                FIELD_DELIMITER = "\"" ;

            if(!RECORD_SEPARATOR)
                RECORD_SEPARATOR = "\n" ;

            parsecgi(ENVIRON["QUERY_STRING"],qstring)

            if(ARGC == 1)   # no files on the command line
            {
                if(qstring["FILENAME"])
                {
                    ARGC = 1 + split(qstring["FILENAME"],ARGV," ")
                }
            }


            if(!NOHTTP)
                NOHTTP = !(ENVIRON["REQUEST_METHOD"]) ;

            if(!TITLE)
                TITLE = qstring["TITLE"]

            if(!TITLE)          # if there is still no title then...
                TITLE = "Code Files"

            if(!LINK)
                LINK = qstring["LINK"]


        printhtmlhead(TITLE)


        print(" <body>") ;
        print("  <div>") ;
        print("   <a id=" QUOTE "top-of-page" QUOTE ">");
        print("    <!-- " version " -->");
        print("   </a>") ;
        print("  </div>") ;

        print("  <h1>" makehtml(TITLE) "</h1>")

        if (ARGC == 1)
        {   print("  <div id=" QUOTE "content" QUOTE ">")
            print("   <p>No files specified, nothing to do!</p>")

            exit    # this will process END{}
        }

        if (ARGC > 2)       # If there is more than one file on the page
            makemenu(0) ;   #   create header menu without "Top of page" link

        print("  <div id=" QUOTE "content" QUOTE ">")

    }

(FNR == 1)    {

        if(ARGIND > 1)        # check if we've processed multiple files
                {   print("   </code></pre>")
                    print("   </div> <!-- end of id=" QUOTE valnameid(ARGV[ARGIND-1]) QUOTE " -->") ;
                    print("")
                }

        print("   <div  id=" QUOTE valnameid(FILENAME) QUOTE ">") ;
        print("    <h2")
        if (ARGIND != 1)   #  Suppress page-break-before on the first file
            print("        style=" QUOTE "page-break-before: always ; " QUOTE )

        print("       >")

        if (ARGC > 2)   # Display "Prev, Top, Next" navigational aids
        {
            print("    <span class=" QUOTE "internal navaid" QUOTE ">")

            if (ARGIND != 1)       # suppress "Previous" for first file
            {
                print("     <a href=" QUOTE "#" valnameid(ARGV[ARGIND-1]) QUOTE)
                print("        title=" QUOTE "Previous Table: " txt2html(ARGV[ARGIND-1]) QUOTE)
                print("     >&larr;</a>")
            } else
            {   print("     <span class=" QUOTE "disabled" QUOTE ">&larr;</span>")
            }

            print("     <a href=" QUOTE "#top-of-page" QUOTE)
            print("        title=" QUOTE "Go to the top of this page" QUOTE)
            print("     >&thinsp;&uarr;&thinsp;</a>")

            if (ARGIND < ARGC-1 )    # suppress "Next" for last file
            {
                print("     <a href=" QUOTE "#" valnameid(ARGV[ARGIND+1]) QUOTE)
                print("        title=" QUOTE "Next Table: " txt2html(ARGV[ARGIND+1]) QUOTE)
                print("     >&rarr;</a>")
            } else
            {   print("     <span class=" QUOTE "disabled" QUOTE ">&rarr;</span>")
            }
        print("    </span>")
        }

        print("   " txt2html(FILENAME) "</h2>" )


        print("    <p>Generated on <abbr class=" QUOTE "datetime" QUOTE " title=" QUOTE strftime("%Y-%m-%dT%H:%M:%S") QUOTE ">" strftime("%a, %d %b %Y %H:%M:%S %z") "</abbr> from ")

        if(LINK)
            print("     <a href=" QUOTE txt2uri(FILENAME) QUOTE ">" txt2html(FILENAME) "</a>")
        else
            print("    " txt2html(FILENAME))

        print("    </p>")
        print("    <pre><code>")

}




# Main : process for every line in the file
        {   print(txt2html($0))
}


END {   if(ARGIND)
        {    print("    </code></pre>")
             print("   </div> <!-- end of id=" QUOTE valnameid(FILENAME) QUOTE " -->") ;
        }
        print("   <p>" ARGIND " files processed.</p>")
        print("  </div> <!-- end of content -->")

        if (ARGC > 2)       # If there is more than one file on the page
        {   print("  <div id=" QUOTE "footer" QUOTE ">")
            makemenu(1) ;   #   Create footer menu with "Top of page" link
            print("  </div> <!-- end of footer -->")
        }

        print(" </body>")
        print("</html>")
    }

# EOF: CODE2HTML.AWK
   

 ↑  /home/bjonkman/bin/awk/library.awk

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from /home/bjonkman/bin/awk/library.awk


# Program   : LIBRARY.AWK
# Purpose   : Contains functions common to many AWK scripts
# Author    : Bob Jonkman <bjonkman@sobac.com>

# Copyright 2008 Bob Jonkman and/or SOBAC Microcomputer Services

#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

# Date      : 19 July 2005

# Contents  :
#             rstring()         - Returns the right-most n characters of string
#             max()             - Maximum of items in list
#             min()             - Minimum of items in list
#             trim()            - Trim whitespace from both ends of a string
#             ltrim()           - Trim whitespace from beginning (left side) of a string
#             rtrim()           - Trim whitespace from end (right side) of a string
#             gwid2smtp()       - escape reserved SMTP characters in GW Object
#                           see http://www.novell.com/documentation/gw55/index.html?page=/documentation/gw55/gw55ia/data/a30135u.html#a30135u
#             smtp2gwid()       - un-escape
#             reverse()         - reverse order of delimited string, eg. a.b.c -> c_b_a
#             txt2html()        - escape reserved HTML characters
#             txt2xml()         - escape reserved XML characters
#             html2txt()        - restore reserved HTML characters
#             txt2uri()         - escape reserved URI characters
#             uri2txt()         - restore reserved URI characters
#             makehtml()        - Create href links (http:// file:// mailto:) from text  (maito: was microformatted with class="vcard" on 2006-08-04)
#             parsecsv()        - Split Comma-Quote fields in string into an array
#             printcsv()        - Determine whether to print a field with delimiters
#             valnameid()       - Validate Name and ID token names (see http://www.w3.org/TR/html4/types.html#type-id )
#             printhtmlhead()   - print headers for an HTML file
#             parsecgi()        - Parse QUERY_STRING or POST data into an array
#             txt2gwapi()       - escape reserved characters in GW API files
#                           (see pg 42,43 "Keyword Ordering Requirements and Delimiters" in GroupWise API Gateway documentation)
#             getheaders()      - Create reverse lookup array for input string
#             printarray()      - Print all elements of an array (for debugging, mostly)  Added 2022-05-01
#             gettitle()        - Get a title attribute from web page (stub added 2022-05-01)
#             stripcomments()   - Remove text between delimiters (and the delimiters). Added 2025-02-02


function rstring(string,n)    {     #  Returns the right-most n characters of string
                                    return(substr(string,length(string)-n+1))
}



function max(a,b)   {   return(( a > b ) ? a : b)
}

function min(a,b)   {   return(( a < b ) ? a : b)
}

function trim(string)   {
                            string = rtrim(string) ;
                            string = ltrim(string) ;
                            return(string) ;
}

##### End trim #####




# trim left-side whitespace
function ltrim(string)	{   gsub(/^[ \t]+/, "", string)
                            return(string)
}
##### End ltrim #####





# trim right-side whitespace
function rtrim(string)  {   gsub(/[ \t]+$/, "", string)
                            return(string)
}

##### End rtrim #####





function gwid2smtp(text,   smtptext)   # Perform GroupWise character translation
# http://www.novell.com/documentation/gw55/index.html?page=/documentation/gw55/gw55ia/data/a30135u.html#a30135u
             {
                 smtptext = text ;
                 gsub(/#/   ,"#h#",smtptext) ;
                 gsub(/_/   ,"#u#",smtptext) ;
                 gsub(/ /   ,"_"  ,smtptext) ;
                 gsub(/\(/  ,"#l#",smtptext) ;
                 gsub(/)/   ,"#r#",smtptext) ;
                 gsub(/,/   ,"#m#",smtptext) ;
                 gsub(/:/   ,"#c#",smtptext) ;
                 gsub(/\\/  ,"#b#",smtptext) ;
                 gsub(/=/   ,"#e#",smtptext) ;
                 gsub(/\//  ,"#s#",smtptext) ;

                 return(smtptext) ;
}

##### End gwid2smpt #####

function smtp2gwid(text,   gwidtext)
         {
             gwidtext = text ;
             gsub(/#s#/,"/" ,gwidtext);
             gsub(/#e#/,"=" ,gwidtext);
             gsub(/#b#/,"\\",gwidtext);
             gsub(/#c#/,":" ,gwidtext);
             gsub(/#m#/,"," ,gwidtext);
             gsub(/#r#/,")" ,gwidtext);
             gsub(/#l#/,"(" ,gwidtext);
             gsub(/_/  ," " ,gwidtext);
             gsub(/#u#/,"_" ,gwidtext);
             gsub(/#h#/,"#" ,gwidtext);
             return(gwidtext) ;
}

##### End smtp2gwid #####




function reverse(instring,inseparator,outseparator,       numelements,array,i,outstring)
        {
            numelements = split(instring, array, inseparator);
            outstring = array[numelements];
            for (i=numelements-1; i>0; i--)
                outstring = outstring outseparator array[i];
            return outstring;
        }

##### End reverse #####





function txt2html(text,   htmltext)
            {
            htmltext = text ;
            gsub(/&/  , "\\&amp;"  ,htmltext)
            gsub(/>/   , "\\&gt;"   ,htmltext)
            gsub(/</   , "\\&lt;"   ,htmltext)
            gsub(/"/   , "\\&quot;" ,htmltext)
            gsub(/'/   , "\\&#39;"  ,htmltext) # ' or tick appears to be invalid in XML UTF-8 documents, substitute numeric entity
            gsub(/\x91/, "\\&lsquo;",htmltext) # &lsquo; left-single-quote or backtick becomes tick
            gsub(/\x92/, "\\&rsquo;",htmltext) # &rsquo; right-single-quote becomes tick
            gsub(/\x93/, "\\&ldquo;",htmltext) # &ldquo; left-double-quote becomes double-quote
            gsub(/\x94/, "\\&rdquo;",htmltext) # &rdquo; right-double-quote becomes double-quote
            gsub(/\x95/, "\\&ndash" ,htmltext) # &ndash; N-dash becomes hyphen (for XML)
            gsub(/\x96/, "\\&mdash" ,htmltext) # &mdash; EM Dash becomes two hyphens



            return(htmltext) ;
            }

##### End txt2html #####

function txt2xml(text,   xmltext)   # converts plain text or HTML to XML
            {
            xmltext = text ;
            gsub(/&/     , "\\&amp;"  ,xmltext)
            gsub(/>/      , "\\&gt;"   ,xmltext)
            gsub(/</      , "\\&lt;"   ,xmltext)
            gsub(/"/      , "\\&quot;" ,xmltext)
            gsub(/'/      , "\\&#39;"  ,xmltext) # ' or tick appears to be invalid in XML UTF-8 documents, substitute numeric entity
            gsub(/\x91/   , "\\&#39;"  ,xmltext) #  left-single-quote or backtick becomes tick
            gsub(/&lsquo;/, "\\&#39;"  ,xmltext) # &lsquo; left-single-quote  becomes tick
            gsub(/\x92/   , "\\&#39;"  ,xmltext) # &rsquo; right-single-quote becomes tick
            gsub(/&rsquo;/, "\\&#39;"  ,xmltext) #         right-single-quote becomes tick
            gsub(/\x93/   , "\\&quot;" ,xmltext) # &ldquo; left-double-quote becomes double-quote
            gsub(/&ldquo;/, "\\&quot;" ,xmltext) #         left-double-quote becomes double-quote
            gsub(/\x94/   , "\\&quot;" ,xmltext) # &rdquo; right-double-quote becomes double-quote
            gsub(/&rdquo;/, "\\&quot;" ,xmltext) #         right-double-quote becomes double-quote
            gsub(/\x95/   , "-"        ,xmltext) # &ndash; N-dash becomes hyphen (for XML)
            gsub(/&ndash;/, "-"        ,xmltext) # &ndash; N-dash becomes hyphen (for XML)
            gsub(/--/     , "\\&#43;\\&#43;" ,xmltext) # two hyphens are invalid inside comments <!-- -->
            gsub(/\x96/   , "\\&#43;\\&#43;" ,xmltext) # &mdash; EM Dash becomes two hyphens
            gsub(/&mdash;/, "\\&#43;\\&#43;" ,xmltext) # &mdash; EM Dash becomes two hyphens


            return(xmltext) ;
            }


function html2txt(htmltext,   text)
            {
            text = htmltext ;
            gsub(/&#8211;/ , "-"   , text)
            gsub(/&ndash;/ , "-"   , text)
            gsub(/&#8212;/ , "--"  , text)
            gsub(/&mdash;/ , "--"  , text)
            gsub(/&#8216;/ , "'"   , text) # left-single-quote value
            gsub(/&lsquo;/ , "'"   , text) # left-single-quote entity
            gsub(/&#8217;/ , "'"   , text) # right-single-quote value
            gsub(/&rsquo;/ , "'"   , text) # right-single-quote entity
            gsub(/&#8220;/ , "\""  , text) # left-double-quote value
            gsub(/&ldquo;/ , "\""  , text) # left-double-quote entity
            gsub(/&#8221;/ , "\""  , text) # right-double-quote value
            gsub(/&rdquo;/ , "\""  , text) # right-double-quote entity
            gsub(/&#39;/   , "'"   , text) # apostrophe or tick '
            gsub(/&apos;/  , "'"   , text) # apostrophe entity
            gsub(/&quot;/  , "\""  , text)
            gsub(/&nbsp;/  , " "   , text)
            gsub(/&lt;/    , "<"   , text)
            gsub(/&gt;/    , ">"   , text)
            gsub(/&amp;/   , "\\&" , text)

            return(text) ;
            }

##### End html2txt #####



function txt2uri(text,   uritext)   # see RFC3986 (STD0066) section 2.2
            {
            uritext = text ;
            gsub(/%/   ,"%25",uritext)
            gsub(/ /   ,"%20",uritext)  # Removed escape (/\ /) 2025-02-27 --Bob.
            gsub(/:/   ,"%3A",uritext)
            gsub(/\//  ,"%2F",uritext)
            gsub(/\?/  ,"%3F",uritext)
            gsub(/#/   ,"%23",uritext)
            gsub(/\[/  ,"%5B",uritext)
            gsub(/]/   ,"%5D",uritext)
            gsub(/@/   ,"%40",uritext)
            gsub(/!/   ,"%21",uritext)
            gsub(/\$/  ,"%24",uritext)
            gsub(/&/   ,"%26",uritext)
            gsub(/'/   ,"%27",uritext)
            gsub(/\(/  ,"%28",uritext)
            gsub(/)/   ,"%29",uritext)
            gsub(/\*/  ,"%2A",uritext)
            gsub(/\+/  ,"%2B",uritext)
            gsub(/,/   ,"%2C",uritext)
            gsub(/;/   ,"%3B",uritext)
            gsub(/=/   ,"%3D",uritext)
            gsub(/\|/  ,"%7C",uritext)  # Not part of RFC3986 (I think)
            gsub(/~/   ,"%7E",uritext)  # Not part of RFC3986 (I think)
            gsub(/\^/  ,"%5E",uritext)  # Not part of RFC3986 (I think)
            gsub(/`/   ,"%60",uritext)  # Not part of RFC3986 (I think)
            gsub(/\{/  ,"%7B",uritext)  # Not part of RFC3986 (I think)
            gsub(/\}/  ,"%7D",uritext)  # Not part of RFC3986 (I think)
            gsub(/"/   ,"%22",uritext)  # Not part of RFC3986 (I think)
            gsub(/</   ,"%3C",uritext)  # Not part of RFC3986 (I think)
            gsub(/>/   ,"%3E",uritext)  # Not part of RFC3986 (I think)
            gsub(/\\/  ,"%5C",uritext)  # Not part of RFC3986 (I think)

            return(uritext) ;
            }
##### End txt2uri #####


function uri2txt(uri,  text)
            {
            text = uri
            gsub(/%20/," "      ,text)
            gsub(/%3A/,":"      ,text)
            gsub(/%2F/,"/"      ,text)
            gsub(/%3F/,"?"      ,text)
            gsub(/%23/,"#"      ,text)
            gsub(/%5B/,"["      ,text)
            gsub(/%5D/,"]"      ,text)
            gsub(/%40/,"@"      ,text)
            gsub(/%21/,"!"      ,text)
            gsub(/%24/,"$"      ,text)
            gsub(/%26/,"\\&"    ,text) # unescaped '&' would indicate "replacement text"
            gsub(/%27/,"'"      ,text)
            gsub(/%28/,"("      ,text)
            gsub(/%29/,")"      ,text)
            gsub(/%2A/,"*"      ,text)
            gsub(/%2B/,"+"      ,text)
            gsub(/%2C/,","      ,text)
            gsub(/%3B/,";"      ,text)
            gsub(/%3D/,"="      ,text)
            gsub(/%7C/,"|"      ,text)
            gsub(/%7E/,"~"      ,text)
            gsub(/%5E/,"^"      ,text)
            gsub(/%60/,"`"      ,text)
            gsub(/%7B/,"{"      ,text)
            gsub(/%7D/,"}"      ,text)
            gsub(/%22/,"\""     ,text)
            gsub(/%3C/,"<"      ,text)
            gsub(/%3E/,">"      ,text)
            gsub(/%0D%0A/,"\\n" ,text)

            gsub(/%5C/,"\\"     ,text)   # not part of RFC3986 ?

            gsub(/%25/,"%"     ,text)
            return(text)
            }


function makehtml(string,   numurls,i,htmlstring,path,gwiduri,outstring)
        {
            numurls = split(string, urls, " ") #split string into urls on space. If a URL is meant to include a space then the input string must substitute '+'
            for (i=1; i<=numurls; i++)
            {
              if(substr(urls[i],1,2) == "\\\\")
              {
                      path = urls[i] ;
                      gsub(/\\\\/,"/",path) ;
                      htmlstring = "<a href=\"file:///" txt2uri(path) "\">" txt2html(urls[i]) "</a>" ;
              }
              else if(tolower(substr(urls[i],1,5)) == "http:")  # If the string starts with http: then assume it is already txt2uri converted
                      htmlstring = "<a href=\"http:" substr(urls[i],6) "\" title=\"" gettitle(urls[i]) "\">" txt2html(urls[i]) "</a>"
              else if(tolower(substr(urls[i],1,6)) == "https:")  # If the string starts with https: then assume it is already txt2uri converted
                      htmlstring = "<a href=\"https:" substr(urls[i],7) "\" title=\"" gettitle(urls[i]) "\">" txt2html(urls[i]) "</a>"
              else if(tolower(substr(urls[i],1,2)) == "//")  # If the string starts with // then assume it is already txt2uri converted
                      htmlstring = "<a href=\"//" substr(urls[i],3) "\" title=\"" gettitle(urls[i]) "\">" txt2html(urls[i]) "</a>"
              else if(atpos=index(urls[i], "@"))
              {
                    htmlstring = "<span class=\"vcard\"><a class=\"email\" href=\"mailto:" txt2uri(urls[i]) "\" title=\"E-mail to " txt2html(urls[i]) "\">" txt2html(urls[i]) "</a>" ;    # E-mail address is not cleaned with txt2uri() so @ stays as symbol. But txt2uri() may be necessary!
#                      if ((substr(urls[i],atpos+1) == "sobac.com") && !NOEGUIDE)
#                      {   gwiduri = txt2uri(smtp2gwid(substr(urls[i],1,atpos-1))) ;
#                          htmlstring = htmlstring " <a class=\"url\" href=\"http://eguide.sobac.com/eGuide/servlet/eGuide?Action=Detail.get&amp;User.dn=cn%3d" gwiduri "%2cou%3dStaff%2co%3dsobac&amp;Directory.uid=Staff\" title=\"Look up " gwiduri " in eGuide Staff Container\" target=\"ldap\">S</a>"
#                          htmlstring = htmlstring " <a class=\"url\" href=\"http://eguide.sobac.com/eGuide/servlet/eGuide?Action=Detail.get&amp;User.dn=cn%3d" gwiduri "%2cou%3dNon%2dStaff%2co%3dsobac&amp;Directory.uid=Non_Staff\" title=\"Look up " gwiduri " in eGuide Non-Staff Container\" target=\"ldap\">N</a>"
#                      }
                    htmlstring = htmlstring "</span>"
              }
              else if( (tolower(substr(urls[i],1,4)) == "tel:" ) || (substr(urls[i],1,1) == "+") )
              {
                if (tolower(substr(urls[i],1,4)) == "tel:" )
                {
                    urls[i] = substr(urls[i],5) # strip out "tel:"
                }
                htmlstring = "<span class=\"vcard h-card\"><a class=\"p-tel\" href=\"tel:" urls[i] "\" title=\"Phone this number\">" urls[i] "</a></span>" ;
              }
              else htmlstring = txt2html(urls[i]) ;
              outstring = outstring " " htmlstring  # Concatenate to outstring separated by spaces

            } # for i<=numurls
            return(trim(outstring)) ;   # Concatenation above prepends an extra space, so trim it
}

##### End makehtml #####




function parsecsv(rawfield,fieldarray,    fieldnum,qflag,i,char)
	{

#
# Note that parsecsv() does not currently handle embedded CRLF
#       eg. "data","data<CRLF>data","data"
#

		delete fieldarray ;
		qflag = 0 ;				# TRUE if inside field delimiters
		fieldnum = 1 ;

        if(!FIELD_SEPARATOR)
            FIELD_SEPARATOR = "," ;

        if(!FIELD_DELIMITER)
            FIELD_DELIMITER = "\"" ;


		for(i=1; i <= length(rawfield); i++)
		{   char     = substr(rawfield,i,1)

			if (char == FIELD_DELIMITER)
            {
                if (substr(rawfield,i+1,1) == FIELD_DELIMITER)  # check for two adjacent field delimiters; treat as one character
                {
                    i++     # skip over the next character, and add the delimiter to the output string
                    fieldarray[fieldnum] = fieldarray[fieldnum] FIELD_DELIMITER
                }
                else
    				qflag = !qflag;


            }
			else if (char == FIELD_SEPARATOR)
			{	if (qflag)
					fieldarray[fieldnum] = fieldarray[fieldnum] FIELD_SEPARATOR ;


				else
				{
					fieldnum++ ;
				}


			}

			else
			{	fieldarray[fieldnum] = fieldarray[fieldnum] char ;
			}

		}

		return(fieldnum);
	}



#####  End of parsecsv() #####


function printcsv(field)    # Determine whether to print a field with delimiters
    {
        if(!FIELD_SEPARATOR)
            FIELD_SEPARATOR = "," ;

        if(!FIELD_DELIMITER)
            FIELD_DELIMITER = "\"" ;

# Double field delimiters to escape them
        gsub(FIELD_DELIMITER,FIELD_DELIMITER FIELD_DELIMITER,field)

# Apply field delimiters when field separator is in field
        if (field ~ FIELD_SEPARATOR)
            field = FIELD_DELIMITER field FIELD_DELIMITER
        return(field)
    }



function valnameid(text,   valtext)     # Validate NAME and ID token names
    {
        valtext = text
        gsub(/[^A-Za-z0-9\-_:\.]/, "_", valtext)
        if(substr(valtext,1,1) !~ /[A-Za-z]/)
        {
            valtext = "a" valtext  # Prepend an 'a'
        }
        return(valtext)
    }

##### End of valnameid() #####



function printhtmlhead(title,noclosetag)
    {

            if (!QUOTE)
                QUOTE = "\""

            if ((ENVIRON["REQUEST_METHOD"]) && (!NOHTTP))		# If this is a CGI request and NOHTTP has not been specified
                print("Content-type: text/html; charset=UTF-8\n")	# ...then print HTTP header

### xml directives are not supported in HTML5
#            print("<?xml version=" QUOTE "1.0" QUOTE " encoding=" QUOTE "utf-8" QUOTE "?>") ;

### Removed XHTML Strict --Bob 2022-05-06
#            print("<!DOCTYPE html PUBLIC " QUOTE "-//W3C//DTD XHTML 1.0 Strict//EN" QUOTE ) ;
#            print("    " QUOTE "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" QUOTE ">") ;
#            print("<html xmlns=" QUOTE "http://www.w3.org/1999/xhtml" QUOTE ) ;
#            print("      xml:lang=" QUOTE "en" QUOTE ) ;
#            print("      lang=" QUOTE "en" QUOTE ">") ;

### Added HTML5 header --Bob 2022-05-06
            print("<!DOCTYPE html>")
            print("<html lang=\"en\">")

            print(" <head>") ;
            print("  <meta http-equiv=" QUOTE "Content-Type" QUOTE ) ;
            print("           content=" QUOTE "text/html;charset=utf-8" QUOTE ">") ;
            print("  <link rel=" QUOTE "stylesheet" QUOTE ) ;
            print("        href=" QUOTE "/default.css" QUOTE ) ;
            print("        type=" QUOTE "text/css" QUOTE ">") ;

            for(i in LINKREL)
                print("  " LINKREL[i])

            print("  <meta name=" QUOTE "generator" QUOTE ) ;
            print("        content=" QUOTE "AWK tools for HTML by Bob Jonkman" QUOTE ">") ;
            print("  <meta name=" QUOTE "author" QUOTE ) ;
            print("        content=" QUOTE "Bob Jonkman  bjonkman@sobac.com;" QUOTE ">") ;
            print("  <meta name=" QUOTE "description" QUOTE ) ;
            print("        content=" QUOTE "Datetime: " strftime("%FT%T") )
            print("                " txt2html(title) QUOTE ">" )
            print("  <title>" txt2html(title) "</title>") ;

            if ("" == noclosetag) { # Suppress close tag if requested
                print (" </head>")
            }
    }

##### End of printhtmlhead() #####



function parsecgi(inputstring,outputarray,     querystring,paramstring,numparam)
    {   delete querystring
        delete outputarray

        numparam = split(inputstring,querystring,"&")


        for(i in querystring)
        {

            gsub(/\+/," ",querystring[i])            # remove + as space substitute

            split(querystring[i],paramstring,"=")


# allow multi-value parameters, separate with FS
            if (outputarray[uri2txt(paramstring[1])])
            {
                outputarray[uri2txt(paramstring[1])] = outputarray[uri2txt(paramstring[1])] FS uri2txt(paramstring[2]) ;
                numparam-- ;
            }
            else
                outputarray[uri2txt(paramstring[1])] = uri2txt(paramstring[2]) ;
        }


        return(numparam)
    }

##### End of parsecgi() #####



function txt2gwapi(text)
    {
        gsub(/;/  ,"\\;"  , text)    # escape semicolon to backslash semicolon
        gsub(/"/ , "\\\"", text)    # escape unpaired double quote to backslash unpaired double quote
        return(text)
    }

##### End of txt2gwapi()



# Results of getheaders("Alpha,Beta,Gamma",namearray,numberarray)
#                           namearray["Alpha"] == 1
#                           namearray["Beta"]  == 2
#                           namearray["Gamma"] == 3
#                           numberarray[1] == "Alpha"
#                           numberarray[2] == "Beta"
#                           numberarray[3] == "Gamma"

function    getheaders(instring,namearray,numberarray,   numfields,i)    {
                    numfields = parsecsv(instring,numberarray)
                    for(i=1; i<=numfields; i++)
                        namearray[numberarray[i]] = i ;
                    return(numfields)
}

##### End of getheaders()


function printarray(arrayname, name, i)
{
    	if (isarray(arrayname)) {
    	    print "Array:"
        	for (name in arrayname) {
        	    if (isarray(arrayname[name])) {
        	        print "\nBegin Subarray"
        	        printarray(arrayname[name])
        	        print "End Subarray\n"

        	    } else {
	            	print i++ " name=" name " arrayname[name]=" arrayname[name]
	            } # if(isarray(arrayname[name]))
	        } # for (name in arrayname)
	    } else {    # not an array
	        print "Scalar: " arrayname
	    } # if(isarray(arrayname))

		return i
}

##### End of printarray()


function gettitle(url)
{   return(txt2html(url))   # It's just a stub for now
}


function stripcomments(string,delimstart,delimend)
{
  return gensub("\\" delimstart ".*" "\\" delimend,"","g",string) # Text to replace (escaped delimiters, eg "\\(" or "\\["), Replacement text, Global, String with text
}


# EOF: LIBRARY.AWK

   

 ↑  makefile

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from makefile


# Program	: makefile
# Purpose	: To re-create the files
# Author	: Bob Jonkman  bjonkman@sobac.com
# Date		: 5 August 2022
# Modified  : 5 March 2025 - Added index.html, ./makeindex

VPATH = /home/bjonkman/bin/awk/

AWKPROGS = csv2html.awk code2html.awk library.awk

CANDIDATEPROGS = csv2candidates.awk csv2municipalcandidates.awk csv2candidates-search.awk candidates.css

.PHONY : all
all : $(CANDIDATEPROGS) \
        csv2municipalcandidates.html \
        csv2candidates.html \
        index \
        rsync

csv2municipalcandidates.awk : csv2municipalcandidates-DEBUG.awk
	grep -v "#####DEBUG#####" csv2municipalcandidates-DEBUG.awk > csv2municipalcandidates.awk

csv2candidates.awk : csv2candidates-DEBUG.awk
	grep -v "#####DEBUG#####" csv2candidates-DEBUG.awk > csv2candidates.awk

csv2candidates-search.awk : csv2candidates-search-DEBUG.awk
	grep -v "#####DEBUG#####" csv2candidates-search-DEBUG.awk > csv2candidates-search.awk

csv2candidates.html : $(AWKPROGS) $(CANDIDATEPROGS) makefile */makefile

	/home/bjonkman/bin/awk/code2html.awk -v LINK=1 -v TITLE="CSV to Candidates" \
    	$(CANDIDATEPROGS) \
    	/home/bjonkman/bin/awk/csv2html.awk \
    	/home/bjonkman/bin/awk/code2html.awk \
	    /home/bjonkman/bin/awk/library.awk \
    	makefile \
	    */makefile > csv2candidates.html

### Everything


.PHONY : index
index  : makeindex FORCE
	./makeindex


.PHONY : rsync
rsync  : FORCE
	rsync -av --no-recursive --dirs --delete * irving:/home/jonkman/public_html/Poliblog-Elections/

FORCE:

# EOF: makefile

   

 ↑  2019-10-29-Federal-Election/makefile

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from 2019-10-29-Federal-Election/makefile


# File		: makefile
# Purpose	: Update 2019 Federal election candidates - Re-run various scripts when updates are made
# Author	: Bob Jonkman
# Date		: 20 November 2023

.PHONY : all
all : candidates.ods candidates.csv index.html Parties-Ridings.html searchassistant.html rsync

#  candidates.ods : /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/2019-10-29-Federal-Election/candidates.ods
#	cp -pv /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/2019-10-29-Federal-Election/candidates.ods

index.html : candidates.csv ../csv2candidates.awk
	../csv2candidates.awk candidates.csv > index.html

candidates.csv : candidates.ods
	soffice --convert-to "csv" candidates.ods

# Parties-Ridings.html : Parties.csv Ridings.csv  ReservedParties.csv UnregisteredParties.csv
Parties-Ridings.html : Parties.csv Ridings.csv
#	/home/bjonkman/bin/awk/csv2html.awk -v TITLE="Parties and Ridings" -v LINK=1 -v SORTABLE=1 Parties.csv Ridings.csv ReservedParties.csv UnregisteredParties.csv > Parties-Ridings.html
	/home/bjonkman/bin/awk/csv2html.awk -v TITLE="Parties and Ridings" -v LINK=1 -v SORTABLE=1 Parties.csv Ridings.csv > Parties-Ridings.html

searchassistant.html : candidates.csv ../csv2candidates-search.awk
	../csv2candidates-search.awk candidates.csv > searchassistant.html


.PHONY : rsync
rsync :
	rsync -av --delete ./	        irving:/home/jonkman/public_html/Poliblog-Elections/2019-10-29-Federal-Election/
	rsync -av --delete ../images/ irving:/home/jonkman/public_html/Poliblog-Elections/images/


# EOF: makefile

   

 ↑  2021-09-20-Federal-Election/makefile

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from 2021-09-20-Federal-Election/makefile


# File		: makefile
# Purpose	: Update 2021 Federal election candidates - Re-run various scripts when updates are made
# Author	: Bob Jonkman
# Date		: 20 November 2023

.PHONY : all
all : candidates.ods candidates.csv index.html Parties-Ridings.html searchassistant.html rsync

index.html : candidates.csv ../csv2candidates.awk
	../csv2candidates.awk candidates.csv > index.html

candidates.csv : candidates.ods
	soffice --convert-to "csv" candidates.ods

# Parties-Ridings.html : Parties.csv Ridings.csv  ReservedParties.csv UnregisteredParties.csv
Parties-Ridings.html : Parties.csv
#	/home/bjonkman/bin/awk/csv2html.awk -v TITLE="Parties and Ridings" -v LINK=1 -v SORTABLE=1 Parties.csv Ridings.csv ReservedParties.csv UnregisteredParties.csv > Parties-Ridings.html
	/home/bjonkman/bin/awk/csv2html.awk -v TITLE="Parties and Ridings" -v LINK=1 -v SORTABLE=1 Parties.csv > Parties-Ridings.html

searchassistant.html : candidates.csv ../csv2candidates-search.awk
	../csv2candidates-search.awk candidates.csv > searchassistant.html


.PHONY : rsync
rsync :
	rsync -av --delete ./	        irving:/home/jonkman/public_html/Poliblog-Elections/2021-09-20-Federal-Election/
	rsync -av --delete ../images/ irving:/home/jonkman/public_html/Poliblog-Elections/images/


# EOF: makefile

   

 ↑  2022-06-02-Provincial-Election/makefile

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from 2022-06-02-Provincial-Election/makefile


# File		: makefile
# Purpose	: Update 2022 Provincial election candidates - Re-run various scripts when updates are made
# Author	: Bob Jonkman
# Date		: 20 November 2023

.PHONY : all
all : candidates.ods candidates.csv index.html Parties-Ridings.html searchassistant.html rsync

#  candidates.ods : /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/2022-06-02-Provincial-Election/candidates.ods
#	cp -pv /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/2022-06-02-Provincial-Election/candidates.ods

index.html : candidates.csv ../csv2candidates.awk
	../csv2candidates.awk candidates.csv > index.html

candidates.csv : candidates.ods
	soffice --convert-to "csv" candidates.ods

# Parties-Ridings.html : Parties.csv Ridings.csv  ReservedParties.csv UnregisteredParties.csv
Parties-Ridings.html : Parties.csv Ridings.csv
#	/home/bjonkman/bin/awk/csv2html.awk -v TITLE="Parties and Ridings" -v LINK=1 -v SORTABLE=1 Parties.csv Ridings.csv ReservedParties.csv UnregisteredParties.csv > Parties-Ridings.html
	/home/bjonkman/bin/awk/csv2html.awk -v TITLE="Parties and Ridings" -v LINK=1 -v SORTABLE=1 Parties.csv Ridings.csv > Parties-Ridings.html

searchassistant.html : candidates.csv ../csv2candidates-search.awk
	../csv2candidates-search.awk candidates.csv > searchassistant.html


.PHONY : rsync
rsync :
	rsync -av --delete ./	        irving:/home/jonkman/public_html/Poliblog-Elections/2022-06-02-Provincial-Election/
	rsync -av --delete ../images/ irving:/home/jonkman/public_html/Poliblog-Elections/images/


# EOF: makefile

   

 ↑  2022-10-24-Municipal-Election/makefile

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from 2022-10-24-Municipal-Election/makefile


# File		: makefile
# Purpose	: csv2municipalcandidates - Re-run various scripts when updates are made
# Author	: Bob Jonkman
# Date		: 30 July 2022

.PHONY : all
all : 2022-Municipal.ods 2022-Municipal.csv index.html Municipality.html searchassistant.html rsync

2022-Municipal.ods : /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/2022-Municipal.ods
	cp -pv /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/2022-Municipal.ods /home/bjonkman/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/

index.html : /home/bjonkman/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/2022-Municipal.csv /home/bjonkman/Documents/Websites/PoliBlog/csv2municipalcandidates.awk
	/home/bjonkman/Documents/Websites/PoliBlog/csv2municipalcandidates.awk /home/bjonkman/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/2022-Municipal.csv > /home/bjonkman/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/index.html

2022-Municipal.csv : /home/bjonkman/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/2022-Municipal.ods
	soffice --convert-to "csv" /home/bjonkman/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/2022-Municipal.ods

Municipality.html : /home/bjonkman/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/Municipality.csv
	/home/bjonkman/bin/awk/csv2html.awk -v TITLE="Municipalities, URLs and Logos" /home/bjonkman/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/Municipality.csv > /home/bjonkman/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/Municipality.html

searchassistant.html : /home/bjonkman/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/2022-Municipal.csv /home/bjonkman/Documents/Websites/PoliBlog/csv2candidates-search.awk
	/home/bjonkman/Documents/Websites/PoliBlog/csv2candidates-search.awk /home/bjonkman/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/2022-Municipal.csv > /home/bjonkman/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/searchassistant.html


.PHONY : rsync
rsync :
	rsync -av --delete /home/bjonkman/Documents/Websites/PoliBlog/2022-10-24-Municipal-Election/		 irving:/home/jonkman/public_html/Poliblog-Elections/2022-10-24-Municipal-Election/
	rsync -av --delete /home/bjonkman/Documents/Websites/PoliBlog/images/ irving://home/jonkman/public_html/Poliblog-Elections/images/


# EOF: makefile

   

 ↑  2023-11-13-Cambridge-Ward01-Byelection/makefile

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from 2023-11-13-Cambridge-Ward01-Byelection/makefile


# File		: makefile
# Purpose	: csv2municipalcandidates - Re-run various scripts when updates are made
# Author	: Bob Jonkman
# Date		: 30 July 2022
# Modified: 1 November 2023

.PHONY : all
all : candidates.ods candidates.csv index.html Municipalities.html searchassistant.html rsync


index.html : /home/bjonkman/Documents/Websites/PoliBlog/2023-11-13-Cambridge-Ward01-Byelection/candidates.csv /home/bjonkman/Documents/Websites/PoliBlog/csv2municipalcandidates.awk
	/home/bjonkman/Documents/Websites/PoliBlog/csv2municipalcandidates.awk /home/bjonkman/Documents/Websites/PoliBlog/2023-11-13-Cambridge-Ward01-Byelection/candidates.csv > /home/bjonkman/Documents/Websites/PoliBlog/2023-11-13-Cambridge-Ward01-Byelection/index.html

candidates.csv : /home/bjonkman/Documents/Websites/PoliBlog/2023-11-13-Cambridge-Ward01-Byelection/candidates.ods
	soffice --convert-to "csv" /home/bjonkman/Documents/Websites/PoliBlog/2023-11-13-Cambridge-Ward01-Byelection/candidates.ods

Municipalities.html : /home/bjonkman/Documents/Websites/PoliBlog/2023-11-13-Cambridge-Ward01-Byelection/Municipalities.csv
	/home/bjonkman/bin/awk/csv2html.awk -v TITLE="Municipalities, URLs and Logos" /home/bjonkman/Documents/Websites/PoliBlog/2023-11-13-Cambridge-Ward01-Byelection/Municipalities.csv > /home/bjonkman/Documents/Websites/PoliBlog/2023-11-13-Cambridge-Ward01-Byelection/Municipalities.html

searchassistant.html : /home/bjonkman/Documents/Websites/PoliBlog/2023-11-13-Cambridge-Ward01-Byelection/candidates.csv /home/bjonkman/Documents/Websites/PoliBlog/csv2candidates-search.awk
	/home/bjonkman/Documents/Websites/PoliBlog/csv2candidates-search.awk /home/bjonkman/Documents/Websites/PoliBlog/2023-11-13-Cambridge-Ward01-Byelection/candidates.csv > /home/bjonkman/Documents/Websites/PoliBlog/2023-11-13-Cambridge-Ward01-Byelection/searchassistant.html


.PHONY : rsync
rsync :
	rsync -av --delete /home/bjonkman/Documents/Websites/PoliBlog/2023-11-13-Cambridge-Ward01-Byelection/		 irving:/home/jonkman/public_html/Poliblog-Elections/2023-11-13-Cambridge-Ward01-Byelection/
	rsync -av --delete /home/bjonkman/Documents/Websites/PoliBlog/images/ irving://home/jonkman/public_html/Poliblog-Elections/images/


# EOF: makefile

   

 ↑  2025-02-27-Provincial-Election/makefile

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from 2025-02-27-Provincial-Election/makefile


# File		: makefile
# Purpose	: Update 2025 Ontario Provincial Election candidates - Re-run various scripts when updates are made
# Author	: Bob Jonkman
# Date		: based on 30 October 2023
# Modified  : 2 Feb 2025 - Added library.awk and csv2html.awk as dependencies
#                        - Add 'rm -v *.tmp'

.PHONY : all
all : candidates.ods candidates.csv index.html Parties-Ridings.html searchassistant.html rsync

#  candidates.ods : /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/2023-Provincial-Byelection-Kitchener/candidates.ods
#	cp -pv /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/2023-Provincial-Byelection-Kitchener/candidates.ods

index.html : candidates.csv ../csv2candidates.awk /home/bjonkman/bin/awk/library.awk
	../csv2candidates.awk candidates.csv > index.html

candidates.csv : candidates.ods
	soffice --convert-to "csv" candidates.ods

Parties-Ridings.html : *.csv /home/bjonkman/bin/awk/csv2html.awk /home/bjonkman/bin/awk/library.awk
	/home/bjonkman/bin/awk/csv2html.awk -v TITLE="Parties and Ridings" -v LINK=1 -v SORTABLE=1 *.csv > Parties-Ridings.html

searchassistant.html : candidates.csv ../csv2candidates-search.awk /home/bjonkman/bin/awk/library.awk
	../csv2candidates-search.awk candidates.csv > searchassistant.html


.PHONY : rsync
rsync :
#    rm -v *.tmp
	rsync -av --delete ./	        irving:/home/jonkman/public_html/Poliblog-Elections/2025-02-27-Provincial-Election/
	rsync -av --delete ../images/ irving:/home/jonkman/public_html/Poliblog-Elections/images/


# EOF: makefile

   

 ↑  2025-Federal-Election/makefile

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from 2025-Federal-Election/makefile


# File		: makefile
# Purpose	: Re-run various scripts when updates are made
# Author	: Bob Jonkman
# Date		: 23 November 2023
# Notes   : for upcoming Federal Election, change folder name when date is known

.PHONY : all
all : candidates.ods candidates.csv index.html Parties-Ridings.html searchassistant.html rsync

#  candidates.ods : /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/2025-Federal-Election/candidates.ods
#	cp -pv /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/2025-Federal-Election/candidates.ods

index.html : candidates.csv ../csv2candidates.awk /home/bjonkman/bin/awk/library.awk
	../csv2candidates.awk candidates.csv > index.html

candidates.csv : candidates.ods
	soffice --convert-to "csv" candidates.ods

Parties-Ridings.html : *.csv /home/bjonkman/bin/awk/csv2html.awk /home/bjonkman/bin/awk/library.awk
	/home/bjonkman/bin/awk/csv2html.awk -v TITLE="Parties and Ridings" -v LINK=1 -v SORTABLE=1 *.csv > Parties-Ridings.html

searchassistant.html : candidates.csv ../csv2candidates-search.awk /home/bjonkman/bin/awk/library.awk
	../csv2candidates-search.awk candidates.csv > searchassistant.html


.PHONY : rsync
rsync :
	rsync -av --delete ./	        irving:/home/jonkman/public_html/Poliblog-Elections/2025-Federal-Election/
	rsync -av --delete ../images/ irving:/home/jonkman/public_html/Poliblog-Elections/images/


# EOF: makefile

   

 ↑  2026-10-26-Municipal-Election/makefile

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from 2026-10-26-Municipal-Election/makefile


# File		: makefile
# Purpose	: csv2municipalcandidates - Re-run various scripts when updates are made
# Author	: Bob Jonkman
# Date		: 10 May 2026

.PHONY : all
all : Municipal.ods Municipal.csv index.html Municipality.html searchassistant.html rsync

## Not copying to/from Nextcloud at moment, maybe if CiviTechWR asks
### Municipal.ods : /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/Municipal.ods
###	cp -pv /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/Municipal.ods /home/bjonkman/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/

index.html : /home/bjonkman/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/Municipal.csv /home/bjonkman/Documents/Websites/PoliBlog/csv2municipalcandidates.awk
	/home/bjonkman/Documents/Websites/PoliBlog/csv2municipalcandidates.awk /home/bjonkman/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/Municipal.csv > /home/bjonkman/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/index.html

Municipal.csv : /home/bjonkman/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/Municipal.ods
	mv Municipal.csv Municipal-previous.csv
	soffice --convert-to "csv" /home/bjonkman/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/Municipal.ods

Municipality.html : /home/bjonkman/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/Municipality.csv
	/home/bjonkman/bin/awk/csv2html.awk -v TITLE="Municipalities, URLs and Logos" /home/bjonkman/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/Municipality.csv > /home/bjonkman/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/Municipality.html

searchassistant.html : /home/bjonkman/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/Municipal.csv /home/bjonkman/Documents/Websites/PoliBlog/csv2candidates-search.awk
	/home/bjonkman/Documents/Websites/PoliBlog/csv2candidates-search.awk /home/bjonkman/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/Municipal.csv > /home/bjonkman/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/searchassistant.html


.PHONY : rsync
rsync :
	rsync -av --delete /home/bjonkman/Documents/Websites/PoliBlog/2026-10-26-Municipal-Election/		 irving:/home/jonkman/public_html/Poliblog-Elections/2026-10-26-Municipal-Election/
	rsync -av --delete /home/bjonkman/Documents/Websites/PoliBlog/images/ irving://home/jonkman/public_html/Poliblog-Elections/images/


# EOF: makefile

   

 ↑  2029-Federal-Election/makefile

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from 2029-Federal-Election/makefile


# File		: makefile
# Purpose	: Re-run various scripts when updates are made
# Author	: Bob Jonkman
# Date		: 23 November 2023
# Notes   : for upcoming Federal Election, change folder name when date is known

.PHONY : all
all : candidates.ods candidates.csv index.html Parties-Ridings.html searchassistant.html rsync

#  candidates.ods : /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/$(basename $(pwd))/candidates.ods
#	cp -pv /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/$(basename $(pwd))2025-Federal-Election/candidates.ods

index.html : candidates.csv ../csv2candidates.awk /home/bjonkman/bin/awk/library.awk
	../csv2candidates.awk candidates.csv > index.html

candidates.csv : candidates.ods
	soffice --convert-to "csv" candidates.ods

Parties-Ridings.html : *.csv /home/bjonkman/bin/awk/csv2html.awk /home/bjonkman/bin/awk/library.awk
	/home/bjonkman/bin/awk/csv2html.awk -v TITLE="Parties and Ridings" -v LINK=1 -v SORTABLE=1 *.csv > Parties-Ridings.html

searchassistant.html : candidates.csv ../csv2candidates-search.awk /home/bjonkman/bin/awk/library.awk
	../csv2candidates-search.awk candidates.csv > searchassistant.html


.PHONY : rsync
rsync :
	rsync -aP --delete ./	        irving:/home/jonkman/public_html/Poliblog-Elections/2029-Federal-Election/
	rsync -aP --delete ../images/ irving:/home/jonkman/public_html/Poliblog-Elections/images/


# EOF: makefile

   

 ↑  MunicipalTestData/makefile

Generated on Thu, 16 Jul 2026 15:29:19 -0400 from MunicipalTestData/makefile


# File		: MunicipalTestData-makefile
# Purpose	: csv2municipalcandidates - Re-run various scripts when updates are made
# Author	: Bob Jonkman
# Date		: 16 June 2026
# Note		: This makefile acts on files in the current folder.

.PHONY : all
### Not rebuilding all these files for test data
#### all : MunicipalTestData.ods MunicipalTestData.csv MunicipalTestData.html Municipality.html MunicipalTestData-searchassistant.html rsync
all : MunicipalTestData.ods MunicipalTestData.csv MunicipalTestData.html MunicipalTestData-searchassistant.html

## Not copying to/from Nextcloud at moment, maybe if CiviTechWR asks
### MunicipalTestData.ods : /home/bjonkman/mount/nextcloud/Documents/Websites/MunicipalTestData/MunicipalTestData.ods
###	cp -pv /home/bjonkman/mount/nextcloud/Documents/Websites/PoliBlog/MunicipalTestData/MunicipalTestData.ods ./

MunicipalTestData.html : MunicipalTestData.csv /home/bjonkman/Documents/Websites/PoliBlog/csv2municipalcandidates-DEBUG.awk
	/home/bjonkman/Documents/Websites/PoliBlog/csv2municipalcandidates-DEBUG.awk MunicipalTestData.csv > MunicipalTestData.html

MunicipalTestData.csv : MunicipalTestData.ods
	mv MunicipalTestData.csv MunicipalTestData-previous.csv
	soffice --convert-to "csv" MunicipalTestData.ods


### Not for test data
#### Municipality.html : ./Municipality.csv
#### 	/home/bjonkman/bin/awk/csv2html-DEBUG.awk -v TITLE="Municipalities, URLs and Logos" /home/bjonkman/Documents/Websites/MunicipalTestData/Municipality.csv > /home/bjonkman/Documents/Websites/MunicipalTestData/Municipality.html

MunicipalTestData-searchassistant.html : MunicipalTestData.csv /home/bjonkman/Documents/Websites/PoliBlog/csv2candidates-search-DEBUG.awk
	/home/bjonkman/Documents/Websites/PoliBlog/csv2candidates-search-DEBUG.awk MunicipalTestData.csv > MunicipalTestData-searchassistant.html


### Not for test data
#### .PHONY : rsync
#### rsync :
#### 	rsync -av --delete /home/bjonkman/Documents/Websites/MunicipalTestData/		 irving:/home/jonkman/public_html/Poliblog-Elections/MunicipalTestData/
#### 	rsync -av --delete /home/bjonkman/Documents/Websites/PoliBlog/images/ irving://home/jonkman/public_html/Poliblog-Elections/images/


# EOF: makefile

    

18 files processed.