summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Daniel Washburn <daniel@washburn.at> 2017-10-04 21:55:00 -0400
committerGravatar Daniel Washburn <daniel@washburn.at> 2017-10-04 21:55:00 -0400
commit61dc07ef400be3613dc4fa395bca161455a402c1 (patch)
tree39aed9dafdee33e50387201c79f2f813bd8b5199
downloadnwscap-61dc07ef400be3613dc4fa395bca161455a402c1.tar.gz
nwscap-61dc07ef400be3613dc4fa395bca161455a402c1.tar.bz2
nwscap-61dc07ef400be3613dc4fa395bca161455a402c1.zip
Initial commit of original 2014 code
-rw-r--r--LICENSE26
-rw-r--r--capatomcustom.xsl446
-rw-r--r--dst_check.xsl142
-rwxr-xr-xnwscap.py132
4 files changed, 746 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..0fbf805
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2013-2014 Daniel Washburn
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors
+may be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/capatomcustom.xsl b/capatomcustom.xsl
new file mode 100644
index 0000000..b9a5726
--- /dev/null
+++ b/capatomcustom.xsl
@@ -0,0 +1,446 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ xmlns:cap="urn:oasis:names:tc:emergency:cap:1.1"
+ xmlns:ha="http://www.alerting.net/namespace/index_1.0" version="1.0">
+
+ <xsl:import href="dst_check.xsl"/>
+
+ <xsl:output method="html"
+ indent="yes"
+ omit-xml-declaration="yes"/>
+
+
+ <!-- Feed header -->
+ <xsl:template match="cap:alert">
+ <table width="525" cellspacing="2" cellpadding="0" border="0">
+ <tr valign="top">
+ <xsl:variable name="lcletters">abcdefghijklmnopqrstuvwxyz</xsl:variable>
+ <xsl:variable name="ucletters">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
+ <xsl:variable name="st">
+ <xsl:value-of select="substring(substring-after(cap:identifier/text(),'NOAA-NWS-ALERTS-'),1,2)"/>
+ </xsl:variable>
+ <xsl:variable name="lcst">
+ <xsl:value-of select="translate(substring(substring-after(cap:identifier/text(),'NOAA-NWS-ALERTS-'),1,2),$ucletters,$lcletters)"/>
+ </xsl:variable>
+
+ <xsl:variable name="forecastoffice">
+ <xsl:value-of select="cap:info/cap:senderName/text()"/>
+ </xsl:variable>
+
+ <td width="100%" colspan="2"><p><a name="contents" id="contents"></a><a href="http://www.weather.gov/">Home</a> &gt; <a href="http://alerts.weather.gov/">Alerts</a> &gt;
+ <a border="0">
+ <xsl:attribute name="href">http://alerts.weather.gov/cap/<xsl:copy-of select="$lcst"/>.php?x=1</xsl:attribute>
+ <xsl:choose>
+ <xsl:when test="contains(cap:note/text(),'(')">
+ <xsl:value-of select="substring-before(substring-after(cap:note/text(),'('),')')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="$st"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </a>
+ &gt; <xsl:value-of select="cap:info/cap:event/text()"/> Issued by <xsl:copy-of select="$forecastoffice"/></p>
+ <table style="width: 100%; margin-top: 5px; background-color: #e0e0e0; font-family: sans-serif; border: 1px solid black;">
+ <tr>
+ <td style="width: 25px; font-weight: bold; vertical-align: text-top; text-align: right;">Message:</td>
+ <td>
+ <xsl:value-of select="cap:identifier/text()"/><span style="text-align: left;"> from </span><xsl:value-of select="cap:sender/text()"/>
+ </td>
+ </tr>
+ <tr>
+ <td style="width: 25px; font-weight: bold; vertical-align: text-top; text-align: right;">Sent:</td>
+ <td>
+ <xsl:value-of select="substring(normalize-space(cap:sent/text()), 12, 5)"/>
+ <xsl:call-template name="timeZoneName">
+ <xsl:with-param name="offset" select="substring(normalize-space(cap:sent/text()), 20, 6)"/>
+ <xsl:with-param name="year" select="substring(normalize-space(cap:sent/text()), 1, 4)"/>
+ <xsl:with-param name="month" select="substring(normalize-space(cap:sent/text()), 6, 2)"/>
+ <xsl:with-param name="day" select="substring(normalize-space(cap:sent/text()), 9, 2)"/>
+ <xsl:with-param name="st" select="$lcst"/>
+ </xsl:call-template>
+ <span style="text-align: left;"> on </span>
+ <xsl:value-of select="substring(normalize-space(cap:sent/text()), 6, 2)"/>-<xsl:value-of select="substring(normalize-space(cap:sent/text()), 9, 2)"/>-<xsl:value-of select="substring(normalize-space(cap:sent/text()), 1, 4)"/>
+ </td>
+ </tr>
+ <tr>
+ <td style="width: 25px; font-weight: bold; vertical-align: text-top; text-align: right;">Effective:</td>
+ <td>
+ <xsl:value-of select="substring(normalize-space(cap:info/cap:effective/text()), 12, 5)"/>
+ <xsl:call-template name="timeZoneName">
+ <xsl:with-param name="offset" select="substring(normalize-space(cap:info/cap:effective/text()), 20, 6)"/>
+ <xsl:with-param name="year" select="substring(normalize-space(cap:info/cap:effective/text()), 1, 4)"/>
+ <xsl:with-param name="month" select="substring(normalize-space(cap:info/cap:effective/text()), 6, 2)"/>
+ <xsl:with-param name="day" select="substring(normalize-space(cap:info/cap:effective/text()), 9, 2)"/>
+ <xsl:with-param name="st" select="$lcst"/>
+ </xsl:call-template>
+ <span style="text-align: left;"> on </span>
+ <xsl:value-of select="substring(normalize-space(cap:info/cap:effective/text()), 6, 2)"/>-<xsl:value-of select="substring(normalize-space(cap:info/cap:effective/text()), 9, 2)"/>-<xsl:value-of select="substring(normalize-space(cap:info/cap:effective/text()), 1, 4)"/>
+ </td>
+ </tr>
+ <tr>
+ <td style="width: 25px; font-weight: bold; vertical-align: text-top; text-align: right;">Expires:</td>
+ <td>
+ <xsl:value-of select="substring(normalize-space(cap:info/cap:expires/text()), 12, 5)"/>
+ <xsl:call-template name="timeZoneName">
+ <xsl:with-param name="offset" select="substring(normalize-space(cap:info/cap:expires/text()), 20, 6)"/>
+ <xsl:with-param name="year" select="substring(normalize-space(cap:info/cap:expires/text()), 1, 4)"/>
+ <xsl:with-param name="month" select="substring(normalize-space(cap:info/cap:expires/text()), 6, 2)"/>
+ <xsl:with-param name="day" select="substring(normalize-space(cap:info/cap:expires/text()), 9, 2)"/>
+ <xsl:with-param name="st" select="$lcst"/>
+ </xsl:call-template>
+ <span style="text-align: left;"> on </span>
+ <xsl:value-of select="substring(normalize-space(cap:info/cap:expires/text()), 6, 2)"/>-<xsl:value-of select="substring(normalize-space(cap:info/cap:expires/text()), 9, 2)"/>-<xsl:value-of select="substring(normalize-space(cap:info/cap:expires/text()), 1, 4)"/>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <table style="background-color: #ffffff; width: 100%; margin-top: 5px; border: 1px solid black;">
+ <tr>
+ <td style="width: 25px; font-weight: bold; vertical-align: text-top; text-align: right;">Event:</td>
+ <td style="font-size: 1.2em; font-weight: bold;"><xsl:value-of select="cap:info/cap:event/text()"/></td>
+ </tr>
+ <tr>
+ <td style="width: 25px; font-weight: bold; vertical-align: text-top; text-align: right;">Alert:</td>
+ <td style="font-size: 1.0em;">
+ <xsl:variable name="descrip">
+ <xsl:call-template name="globalReplace">
+ <xsl:with-param name="outputString" select="substring(cap:info/cap:description/text(),1)"/>
+ <xsl:with-param name="target" select="'&#xa;&#42;'"/>
+ <xsl:with-param name="replacement" select="'&#xa;&#xa;&#42;'"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="descrip2">
+ <xsl:call-template name="globalReplace">
+ <xsl:with-param name="outputString" select="$descrip"/>
+ <xsl:with-param name="target" select="'&#xa;&#46;'"/>
+ <xsl:with-param name="replacement" select="'&#xa;&#xa;&#46;'"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="descrip3">
+ <xsl:call-template name="globalReplace">
+ <xsl:with-param name="outputString" select="$descrip2"/>
+ <xsl:with-param name="target" select="'&#46;&#46;&#46;&#xa;THE'"/>
+ <xsl:with-param name="replacement" select="'&#46;&#46;&#46;&#xa;&#xa;THE'"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="descrip4">
+ <xsl:call-template name="globalReplace">
+ <xsl:with-param name="outputString" select="$descrip3"/>
+ <xsl:with-param name="target" select="'&#46;&#46;&#46;&#xa;A'"/>
+ <xsl:with-param name="replacement" select="'&#46;&#46;&#46;&#xa;&#xa;A'"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <!-- force a space before newline to facilitate url links -->
+ <xsl:variable name="descrip5">
+ <xsl:call-template name="globalReplace">
+ <xsl:with-param name="outputString" select="$descrip4"/>
+ <xsl:with-param name="target" select="'&#xa;'"/>
+ <xsl:with-param name="replacement" select="' &#xa;'"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <!-- make links hot -->
+ <xsl:variable name="descrip6">
+ <xsl:call-template name="hotlink">
+ <xsl:with-param name="text" select="$descrip5"/>
+ <xsl:with-param name="searchterm1" select="'HTTP'"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <pre style="font-size: 1.0em;">
+ <xsl:copy-of select="$descrip6"/>
+ </pre>
+ </td>
+ </tr>
+ <tr>
+ <td style="width: 25px; font-weight: bold; vertical-align: text-top; text-align: right;">Instructions:</td>
+ <td style="font-size: 1.0em;">
+ <xsl:value-of select="cap:info/cap:instruction/text()"/>
+ </td>
+ </tr>
+ <tr>
+ <td style="width: 25px; font-weight: bold; vertical-align: text-top; text-align: right;">Target Area:</td>
+ <td>
+ <table style="background-color: #e0e0e0; margin-right: 20px; font-weight: bold;">
+ <tr>
+ <td colspan="2">
+ <xsl:variable name="areas1">
+ <xsl:call-template name="globalReplace">
+ <xsl:with-param name="outputString" select="cap:info/cap:area/cap:areaDesc/text()"/>
+ <xsl:with-param name="target" select="'/'"/>
+ <xsl:with-param name="replacement" select="'&#xa;'"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="areas">
+ <xsl:call-template name="globalReplace">
+ <xsl:with-param name="outputString" select="$areas1"/>
+ <xsl:with-param name="target" select="';'"/>
+ <xsl:with-param name="replacement" select="'&#xa;'"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="firstchar" select="substring($areas,1,1)"/>
+ <xsl:choose>
+ <xsl:when test = "$firstchar = '&#xa;'"> <!-- first character is a carriage return -->
+ <xsl:call-template name="br-replace">
+ <xsl:with-param name="text" select="substring($areas,2)"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="br-replace">
+ <xsl:with-param name="text" select="$areas"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td style="width: 25px; font-weight: bold; vertical-align: text-top; text-align: right;">Forecast Office:</td>
+ <td><xsl:value-of select="cap:info/cap:senderName/text()"/></td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <table style="background-color: #ffffff; width: 100%; margin-top: 5px; border: 1px solid black;">
+ <tr>
+ <td style="width: 25px; font-weight: bold; vertical-align: text-top; text-align: right;">Raw CAP Message:</td>
+ <td style="font-size: 0.9em; color: #606060">
+ <pre>
+ <xsl:apply-templates select="/cap:alert" mode="escape"/>
+ </pre>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ <!-- end of main content -->
+ </xsl:template>
+
+
+ <xsl:template match="*" mode="escape">
+ <!-- Begin opening tag -->
+ <xsl:text>&lt;</xsl:text>
+ <xsl:value-of select="name()"/>
+
+ <!-- Attributes -->
+ <xsl:for-each select="@*">
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="name()"/>
+ <xsl:text>='</xsl:text>
+ <xsl:call-template name="escape-xml">
+ <xsl:with-param name="text" select="."/>
+ </xsl:call-template>
+ <xsl:text>'</xsl:text>
+ </xsl:for-each>
+
+ <!-- End opening tag -->
+ <xsl:text>&gt;</xsl:text>
+
+ <!-- Content (child elements, text nodes, and PIs) -->
+ <xsl:apply-templates select="node()" mode="escape" />
+
+ <!-- Closing tag -->
+ <xsl:text>&lt;/</xsl:text>
+ <xsl:value-of select="name()"/>
+ <xsl:text>&gt;&#10;</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="text()" mode="escape">
+ <xsl:call-template name="escape-xml">
+ <xsl:with-param name="text" select="."/>
+ </xsl:call-template>
+ </xsl:template>
+
+ <xsl:template match="processing-instruction()" mode="escape">
+ <xsl:text>&lt;?</xsl:text>
+ <xsl:value-of select="name()"/>
+ <xsl:text> </xsl:text>
+ <xsl:call-template name="escape-xml">
+ <xsl:with-param name="text" select="."/>
+ </xsl:call-template>
+ <xsl:text>?&gt;</xsl:text>
+ </xsl:template>
+
+ <xsl:template name="escape-xml">
+ <xsl:param name="text"/>
+ <xsl:if test="$text != ''">
+ <xsl:variable name="head" select="substring($text, 1, 1)"/>
+ <xsl:variable name="tail" select="substring($text, 2)"/>
+ <xsl:choose>
+ <xsl:when test="$head = '&amp;'">&amp;amp;</xsl:when>
+ <xsl:when test="$head = '&lt;'">&amp;lt;</xsl:when>
+ <xsl:when test="$head = '&gt;'">&amp;gt;</xsl:when>
+ <xsl:when test="$head = '&quot;'">&amp;quot;</xsl:when>
+ <xsl:when test="$head = &quot;&apos;&quot;">&amp;apos;</xsl:when>
+ <xsl:otherwise><xsl:value-of select="$head"/></xsl:otherwise>
+ </xsl:choose>
+ <xsl:call-template name="escape-xml">
+ <xsl:with-param name="text" select="$tail"/>
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:template>
+
+ <!-- Time Zone function -->
+ <xsl:template name="timeZoneName">
+ <xsl:param name="offset"/>
+ <xsl:param name="year"/>
+ <xsl:param name="month"/>
+ <xsl:param name="day"/>
+ <xsl:param name="st"/>
+
+ <!-- determine if its DST or not, based on run time -->
+ <xsl:variable name="dst_start">
+ <xsl:call-template name="day-light-savings-start">
+ <xsl:with-param name="year" select="$year"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="dst_end">
+ <xsl:call-template name="day-light-savings-end">
+ <xsl:with-param name="year" select="$year"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="tod_jul">
+ <xsl:call-template name="date-to-absolute-day">
+ <xsl:with-param name="year" select="$year"/>
+ <xsl:with-param name="month" select="$month"/>
+ <xsl:with-param name="day" select="$day"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="dst_flag">
+ <xsl:choose>
+ <xsl:when test="$dst_start &lt;= $tod_jul and $dst_end &gt;= $tod_jul">dst</xsl:when>
+ <xsl:otherwise>nodst</xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:if test="$offset = '+10:00'"> <xsl:text> ChST</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-11:00'"> <xsl:text> SST</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-10:00'"> <xsl:text> HST</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-00:00'"> <xsl:text> GMT</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '+00:00'"> <xsl:text> GMT</xsl:text> </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="$dst_flag = 'nodst'">
+ <xsl:if test="$offset = '-09:00'"> <xsl:text> AKST</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-08:00'"> <xsl:text> PST</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-07:00'"> <xsl:text> MST</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-06:00'"> <xsl:text> CST</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-05:00'"> <xsl:text> EST</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-04:00'"> <xsl:text> AST</xsl:text> </xsl:if>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:choose>
+ <xsl:when test="$st = 'az'">
+ <xsl:if test="$offset = '-08:00'"> <xsl:text> PST</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-07:00'"> <xsl:text> MST</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-06:00'"> <xsl:text> CST</xsl:text> </xsl:if>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:if test="$offset = '-08:00'"> <xsl:text> AKDT</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-07:00'"> <xsl:text> PDT</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-06:00'"> <xsl:text> MDT</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-05:00'"> <xsl:text> CDT</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-04:00'"> <xsl:text> EDT</xsl:text> </xsl:if>
+ <xsl:if test="$offset = '-03:00'"> <xsl:text> ADT</xsl:text> </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ </xsl:template>
+
+ <!-- Replace function -->
+ <xsl:template name="globalReplace">
+ <xsl:param name="outputString"/>
+ <xsl:param name="target"/>
+ <xsl:param name="replacement"/>
+ <xsl:choose>
+ <xsl:when test="contains($outputString,$target)">
+
+ <xsl:value-of select=
+ "concat(substring-before($outputString,$target),$replacement)"/>
+ <xsl:call-template name="globalReplace">
+ <xsl:with-param name="outputString" select="substring-after($outputString,$target)"/>
+ <xsl:with-param name="target" select="$target"/>
+ <xsl:with-param name="replacement" select="$replacement"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$outputString"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- Replace new lines with html <br> tags -->
+ <xsl:template name="br-replace">
+ <xsl:param name="text"/>
+ <xsl:variable name="cr" select="'&#xa;'"/>
+ <xsl:choose>
+ <!-- If the value of the $text parameter contains carriage ret -->
+ <xsl:when test="contains($text,$cr)">
+ <!-- Return the substring of $text before the carriage return -->
+ <xsl:value-of select="substring-before($text,$cr)"/>
+ <!-- And construct a <br/> element -->
+ <br/>
+ <!--
+ | Then invoke this same br-replace template again, passing the
+ | substring *after* the carriage return as the new "$text" to
+ | consider for replacement
+ +-->
+ <xsl:call-template name="br-replace">
+ <xsl:with-param name="text" select="substring-after($text,$cr)"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$text"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- If it looks like a link, make it hot -->
+ <xsl:template name="hotlink">
+ <xsl:param name="text"/>
+ <xsl:param name="searchterm1"/>
+
+ <xsl:variable name="lcletters">abcdefghijklmnopqrstuvwxyz</xsl:variable>
+ <xsl:variable name="ucletters">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
+
+ <xsl:choose>
+ <xsl:when test="contains($text,$searchterm1)">
+
+ <!-- grab data before the searchterm -->
+ <xsl:value-of select="substring-before($text,$searchterm1)"/>
+ <a border="0">
+ <xsl:attribute name="href">
+ <!-- determine actual link by taking data from the searchterm to
+ either the space or the newline - whichever is first -->
+ <xsl:value-of select="translate(concat($searchterm1,substring-before(substring-after($text,$searchterm1),' ')),$ucletters,$lcletters)"/>
+ </xsl:attribute>
+ <xsl:value-of select="translate(concat($searchterm1,substring-before(substring-after($text,$searchterm1),' ')),$ucletters,$lcletters)"/> </a>
+
+ <!-- data after the link - check for more links -->
+ <xsl:call-template name="hotlink">
+ <xsl:with-param name="text" select="substring-after(substring-after($text,$searchterm1),' ')"/>
+ <xsl:with-param name="searchterm1" select="$searchterm1"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$text"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- Ignore anything else -->
+ <xsl:template match="*"></xsl:template>
+
+</xsl:stylesheet>
diff --git a/dst_check.xsl b/dst_check.xsl
new file mode 100644
index 0000000..16d530b
--- /dev/null
+++ b/dst_check.xsl
@@ -0,0 +1,142 @@
+<?xml version="1.0"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="html" encoding="UTF-8"/>
+
+<!-- DST related templates -->
+ <xsl:template name="date-to-absolute-day">
+ <xsl:param name="year"/>
+ <xsl:param name="month"/>
+ <xsl:param name="day"/>
+
+ <xsl:call-template name="julian-day-to-absolute-day">
+ <xsl:with-param name="j-day">
+ <xsl:call-template name="julian-date-to-julian-day">
+ <xsl:with-param name="year" select="$year"/>
+ <xsl:with-param name="month" select="$month"/>
+ <xsl:with-param name="day" select="$day"/>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+
+ <xsl:template name="absolute-day-to-date">
+ <xsl:param name="abs-day"/>
+
+ <xsl:call-template name="absolute-day-to-date">
+ <xsl:with-param name="j-day">
+ <xsl:call-template name="absolute-day-to-julian-day">
+ <xsl:with-param name="abs-day" select="$abs-day"/>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+
+ <xsl:template name="julian-day-to-absolute-day">
+ <xsl:param name="j-day"/>
+ <xsl:value-of select="$j-day - 1721425"/>
+ </xsl:template>
+
+ <xsl:template name="absolute-day-to-julian-day">
+ <xsl:param name="abs-day"/>
+ <xsl:value-of select="$abs-day + 1721425"/>
+ </xsl:template>
+
+ <xsl:template name="julian-date-to-julian-day">
+ <xsl:param name="year"/>
+ <xsl:param name="month"/>
+ <xsl:param name="day"/>
+
+ <xsl:value-of select="(1461 * ($year + 4800 + ($month - 14) div 12)) div 4 + (367 * ($month - 2 - 12 * (($month - 14) div 12))) div 12 - (3 * (($year + 4900 + ($month - 14) div 12) div 100)) div 4 + $day - 32075"/>
+
+ </xsl:template>
+
+ <xsl:template name="last-day-of-month">
+ <xsl:param name="year"/>
+ <xsl:param name="month"/>
+ <xsl:choose>
+ <xsl:when test="$month = 2 and not($year mod 4) and ($year mod 100 or not($year mod 400))">
+ <xsl:value-of select="29"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="substring('312831303130313130313031', 2 * $month - 1,2)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="k-day-on-or-before-abs-day">
+ <xsl:param name="abs-day"/>
+ <xsl:param name="k"/>
+ <xsl:value-of select="$abs-day - (($abs-day - $k) mod 7)"/>
+ </xsl:template>
+
+ <xsl:template name="n-th-k-day">
+ <!-- The n'th occurance of k in the given month -->
+ <!-- Positive n counts from beginning of month; negative from end. -->
+ <xsl:param name="n"/>
+ <!-- k = the day of the week (0=Sun) -->
+ <xsl:param name="k"/>
+ <xsl:param name="month"/>
+ <xsl:param name="year"/>
+
+ <xsl:choose>
+ <xsl:when test="$n > 0">
+ <xsl:variable name="k-day-on-or-before">
+ <xsl:variable name="abs-day">
+ <xsl:call-template name="date-to-absolute-day">
+ <xsl:with-param name="year" select="$year"/>
+ <xsl:with-param name="month" select="$month"/>
+ <xsl:with-param name="day" select="7"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:call-template name="k-day-on-or-before-abs-day">
+ <xsl:with-param name="abs-day" select="$abs-day"/>
+ <xsl:with-param name="k" select="$k"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of select="$k-day-on-or-before + 7 * ($n - 1)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="k-day-on-or-before">
+ <xsl:variable name="abs-day">
+ <xsl:call-template name="date-to-absolute-day">
+ <xsl:with-param name="month" select="$month"/>
+ <xsl:with-param name="day">
+ <xsl:call-template name="last-day-of-month">
+ <xsl:with-param name="month" select="$month"/>
+ <xsl:with-param name="year" select="$year"/>
+ </xsl:call-template>
+ </xsl:with-param>
+ <xsl:with-param name="year" select="$year"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:call-template name="k-day-on-or-before-abs-day">
+ <xsl:with-param name="abs-day" select="$abs-day"/>
+ <xsl:with-param name="k" select="$k"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of select="$k-day-on-or-before + 7 * ($n + 1)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="day-light-savings-start">
+ <xsl:param name="year"/>
+ <xsl:call-template name="n-th-k-day">
+ <xsl:with-param name="n" select="2"/>
+ <xsl:with-param name="k" select="0"/>
+ <xsl:with-param name="month" select="3"/>
+ <xsl:with-param name="year" select="$year"/>
+ </xsl:call-template>
+ </xsl:template>
+
+ <xsl:template name="day-light-savings-end">
+ <xsl:param name="year"/>
+ <xsl:call-template name="n-th-k-day">
+ <xsl:with-param name="n" select="-1"/>
+ <xsl:with-param name="k" select="0"/>
+ <xsl:with-param name="month" select="10"/>
+ <xsl:with-param name="year" select="$year"/>
+ </xsl:call-template>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/nwscap.py b/nwscap.py
new file mode 100755
index 0000000..939a5eb
--- /dev/null
+++ b/nwscap.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+"""Parse active NOAA NWS CAP advisories and output an ATOM feed"""
+
+__author__ = 'Daniel Washburn'
+__copyright__ = 'Copyright (c) 2013, 2014, All rights reserved.'
+__license__ = 'http://opensource.org/licenses/BSD-3-Clause'
+
+import cgi
+import getopt
+import sys
+from lxml import etree
+from lxml.etree import SubElement
+
+ATOM_URI = 'http://www.w3.org/2005/Atom'
+ATOM_NAMESPACE = {'atom': ATOM_URI}
+CAP_URI = 'urn:oasis:names:tc:emergency:cap:1.1'
+CAP_NAMESPACE = {'cap': CAP_URI}
+CAP_SCHEMA_URL = 'http://docs.oasis-open.org/emergency/cap/v1.1/errata/approved/cap.xsd'
+CAP_XSLT_URL = 'capatomcustom.xsl'
+
+CAP_SCHEMA = etree.XMLSchema(etree.parse(CAP_SCHEMA_URL))
+CAP_XSLT = xslt_transform = etree.XSLT(etree.parse(CAP_XSLT_URL))
+
+ATOM_PARSER = etree.XMLParser(ns_clean=True, remove_comments=True)
+CAP_PARSER = etree.XMLParser(ns_clean=True, remove_comments=True,
+ remove_blank_text=True, schema=CAP_SCHEMA)
+
+def usage():
+ print """nwscap.py [-h] -t (region|zone) -a area
+
+-h|--help Print this message and exit
+-t|--type Area type. must be either region or zone
+-a|--area The area to report on
+"""
+
+try:
+ opts, args = getopt.gnu_getopt(sys.argv[1:],
+ "ht:a:",
+ ["help", "type=", "area="])
+except getopt.GetoptError as err:
+ print str(err)
+ usage()
+ sys.exit(2)
+area_type=False
+area=False
+url=False
+
+for o, a in opts:
+ if o in ("-h", "--help"):
+ usage()
+ sys.exit()
+ elif o in ("-t", "--type"):
+ if a in ("region", "zone"):
+ area_type = a
+ else:
+ print """type must be one of: region, zone"""
+ usage()
+ sys.exit()
+ elif o in ("-a", "--area"):
+ area = a
+ else:
+ assert False, "unhandled option"
+
+if area_type and area:
+ if area_type == "region":
+ url='https://alerts.weather.gov/cap/' + area + '.php?x=0'
+ elif area_type == "zone":
+ url='https://alerts.weather.gov/cap/wwaatmget.php?x=' + area + '&y=0'
+else:
+ print """Both type and area must be specified"""
+ usage()
+ sys.exit()
+
+in_feed = etree.parse(url, ATOM_PARSER)
+
+out_feed = etree.XML('''<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+ <feed xmlns='http://www.w3.org/2005/Atom'/>''')
+SubElement(out_feed, 'id').text = "%s" % \
+ in_feed.xpath('/atom:feed/atom:id',
+ namespaces=ATOM_NAMESPACE)[0].text
+SubElement(out_feed, 'updated').text = "%s" % \
+ in_feed.xpath('/atom:feed/atom:updated',
+ namespaces=ATOM_NAMESPACE)[0].text
+out_feed_author = SubElement(out_feed, 'author')
+SubElement(out_feed_author, 'name').text = "%s" % \
+ in_feed.xpath('/atom:feed/atom:author/atom:name',
+ namespaces=ATOM_NAMESPACE)[0].text
+SubElement(out_feed, 'title').text = "%s" % \
+ in_feed.xpath('/atom:feed/atom:title',
+ namespaces=ATOM_NAMESPACE)[0].text
+SubElement(out_feed, 'link', href="%s" % \
+ in_feed.xpath('/atom:feed/atom:link/@href',
+ namespaces=ATOM_NAMESPACE)[0])
+
+# get URLs of active alerts
+entry_titles = in_feed.xpath('/atom:feed/atom:entry/atom:title',
+ namespaces=ATOM_NAMESPACE)
+alert_links=in_feed.xpath('/atom:feed/atom:entry/atom:link/@href',
+ namespaces=ATOM_NAMESPACE)
+
+no_alerts_title = 'There are no active watches, warnings or advisories'
+if no_alerts_title in entry_titles[0].text:
+ alert_links = []
+
+for link in alert_links:
+ cap=etree.parse(link, CAP_PARSER)
+ cap_entry = SubElement(out_feed, 'entry')
+ SubElement(cap_entry, 'id').text = "%s" % \
+ cap.xpath('/cap:alert/cap:identifier',
+ namespaces=CAP_NAMESPACE)[0].text
+
+ cap_entry_author = SubElement(cap_entry, 'author')
+
+ SubElement(cap_entry_author, 'name').text = "%s" % \
+ cap.xpath('/cap:alert/cap:sender',
+ namespaces=CAP_NAMESPACE)[0].text
+
+ SubElement(cap_entry, 'title').text = "%s" % \
+ cap.xpath('/cap:alert/cap:info/cap:headline',
+ namespaces=CAP_NAMESPACE)[0].text
+
+ SubElement(cap_entry, 'published').text = "%s" % \
+ cap.xpath('/cap:alert/cap:sent',
+ namespaces=CAP_NAMESPACE)[0].text
+
+ SubElement(cap_entry, 'link', href=link)
+
+ SubElement(cap_entry, "content", type="text/html").text = "%s" % \
+ etree.tostring(xslt_transform(cap), pretty_print=True)
+
+out_tree = etree.ElementTree(out_feed)
+print(etree.tostring(out_tree, pretty_print=True, method='xml'))