Skip to content

Instantly share code, notes, and snippets.

@influx6
Last active January 4, 2016 13:39
Show Gist options
  • Save influx6/88b5d8176ba0204c3084 to your computer and use it in GitHub Desktop.
Save influx6/88b5d8176ba0204c3084 to your computer and use it in GitHub Desktop.
A gist of a forecast parser for the NOAA Coastal Marine forecast txt files
package main
import (
"bufio"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"regexp"
"strings"
)
// Contains rune types for checks.
const (
EOF = rune(0)
)
var (
// markupFormat is a regexp to find defined sections.
markupBeginFormat = regexp.MustCompile("<B><FONT SIZE=\\+1 COLOR=\"#[A-Z|0-9]+\">")
// extraBaseMarkup is a regexp to check if a expected text only ending
// has a markup after its newline
extraBaseMarkup = regexp.MustCompile(`</?[A-Z]+>`)
// extraLeveledMarkup matches markup with deep level contents
extraLeveledMarkup = regexp.MustCompile(`</?[A-Z]+ ([\w\W]+)?>+`)
// timeFormat provides a matcher for the time format used.
timeFormat = regexp.MustCompile("^\\d+.*\\d+$")
)
// MetaForcast provides a page level document of a current forecast page.
type MetaForcast struct {
Station string
Date string
Warning []string
Meta []string
Header []string
Forecasts [][]string
Descriptions []string
Notifications []string
}
// parseURL passes a URL path content into pages using parsePage.
func parseURL(url string) ([]string, error) {
res, err := http.Get(url)
if err != nil {
return nil, err
}
defer res.Body.Close()
return parsePage(res.Body)
}
// parsePage takes a url and passes the input by using a double newline(\n\n)
// delimiter to split the pages into individual page returning a lists of
// each pages.
// Returns a non-nil error if the http get fails.
func parsePage(r io.Reader) ([]string, error) {
var pages []string
var page []string
reader := bufio.NewReader(r)
for {
item, err := reader.ReadString('\n')
if err != nil {
pages = append(pages, strings.Join(page, ""))
break
}
// do we have a do not exist content for page.
if strings.Contains(item, "does not exists") {
return nil, errors.New("Invalid NOAA Document")
}
// Check if we are at a newline, If so, peek the next to check if its also
// a newline(\n) and if so, start a new page
if item == string('\n') {
var addNext bool
// If we have a doubled line-item then skip else schedule to be added
// by next.
item, _ := reader.ReadString('\n')
if item == string('\n') {
continue
} else {
addNext = true
}
pages = append(pages, strings.Join(page, ""))
page = nil
if addNext {
page = append(page, string(item))
}
continue
}
page = append(page, string(item))
}
return pages, nil
}
// cleanMarkup wipes out all html markup related content,leaving only texts in
// inbetween markup.
func cleanMarkup(text string) string {
return extraLeveledMarkup.ReplaceAllString(extraBaseMarkup.ReplaceAllString(text, ""), "")
}
// cleanAllMarkup cleans out markup out of all items in the string slice.
func cleanAllMarkup(text []string) []string {
var clean []string
for _, m := range text {
if cm := cleanMarkup(m); cm != "" {
clean = append(clean, cm)
}
}
return clean
}
// toString provides a string version of the value using json.Marshal.
func toString(value interface{}, indent bool) string {
var data []byte
var err error
if indent {
data, err = json.MarshalIndent(value, "", "\t")
} else {
data, err = json.Marshal(value)
}
if err != nil {
return ""
}
return string(data)
}
// seperatePages takes a lists of parse page contain and wraps
func processPages(station string, pages []string) (*MetaForcast, error) {
if len(pages) == 0 {
return nil, errors.New("No Page Data")
}
station = strings.ToUpper(station)
var head, imeta, notification, warning, desc []string
var forecasts [][]string
var meta MetaForcast
var dateTime string
var hasMeta bool
// Get the header of the current page.
head = cleanAllMarkup(strings.Split(pages[0], "\n"))
// Get the time and date from the header
for n, hl := range head {
if timeFormat.MatchString(hl) {
dateTime = hl
// If we still have content after the Date, its possible, the description
// was merge, cut it and add to description list.
if left := n + 1; left < len(head) {
descjoint := head[left:]
if len(descjoint) > 0 {
desc = append(desc, descjoint...)
}
head = head[:left]
}
break
}
}
// Collect all description header before station information.
pages = pages[1:]
for n, p := range pages {
if strings.HasPrefix(p, station) {
pages = pages[n:]
break
}
desc = append(desc, p)
}
// Collect meta information for station and Region/Area.
undmeta := strings.Split(pages[0], "\n")
dmeta := cleanAllMarkup(undmeta)
// Check to ensure we are not already in forecast instead of being at metadata.
if !markupBeginFormat.MatchString(undmeta[0]) {
hasMeta = true
for n, p := range dmeta {
if timeFormat.MatchString(p) {
imeta = append(imeta, p)
// EDGECASE
if left := n + 1; left < len(dmeta) {
warning = append(warning, cleanAllMarkup(dmeta[n+1:])...)
}
break
}
imeta = append(imeta, p)
}
}
// If we have meta,then skip that page left by 1.
if hasMeta {
pages = pages[1:]
}
// EDGECASE
// Check if we have leaking Warnings as new lines.
for n, p := range pages {
parts := strings.Split(p, "\n")
if len(parts) == 0 {
continue
}
if len(parts) == 1 {
if !markupBeginFormat.MatchString(parts[0]) {
break
}
warning = append(warning, cleanAllMarkup(parts)...)
continue
}
p1, p2 := parts[0], parts[1]
if !markupBeginFormat.MatchString(p1) && !markupBeginFormat.MatchString(p2) {
notification = append(notification, cleanAllMarkup(parts)...)
continue
}
if markupBeginFormat.MatchString(p1) && (!markupBeginFormat.MatchString(p2) && cleanMarkup(p2) != "") {
pages = pages[n:]
break
}
warning = append(warning, cleanAllMarkup(parts)...)
}
// Are we done ?, No Forecasts? Then end.
if len(pages) > 0 {
// We expect atleast a large set of forecasts still greater than two,
// because we want to skim off the footer details that appear clogged with
// the last forecast with the way the pages are usually structure.
expectedPos := len(pages) - 2
// EDGECASE
// If we are in the negative, then run down the forecast as a single
// set.
if expectedPos < 0 {
for _, p := range pages {
// Split the current forecast report and break down its component.
// Remove any uneeded meta spots apart from the first bolded
// header.
report := strings.Split(p, "\n")
// EDGECASE
// If its just one item, its probably a notification.
if len(report) == 1 {
notification = append(notification, cleanAllMarkup(report)...)
continue
} else {
p1 := report[0]
if !markupBeginFormat.MatchString(p1) {
notification = append(notification, cleanAllMarkup(report)...)
continue
}
}
detail := []string{cleanMarkup(report[0])}
for _, d := range report[1:] {
if extraBaseMarkup.MatchString(d) {
break
}
detail = append(detail, d)
}
forecasts = append(forecasts, detail)
}
} else {
// Collect all forecasts description except the last one because it
// has the footer merged in.
for _, p := range pages[:expectedPos] {
// Split the current forecast report and break down its component.
parts := strings.Split(p, "\n")
// Skip zero length parts.
if len(parts) == 0 {
continue
}
// EDGECASE
// If its just one item, its probably a notification.
if len(parts) == 1 {
notification = append(notification, cleanMarkup(p))
continue
} else {
p1 := parts[0]
if !markupBeginFormat.MatchString(p1) {
notification = append(notification, cleanAllMarkup(parts)...)
continue
}
}
forecasts = append(forecasts, cleanAllMarkup(parts))
}
// Get the last forecast report and split out the footer information.
last := strings.Split(pages[len(pages)-1], "\n")
if len(last) > 0 {
var lastReport []string
// Collect the last forecast header,so we only check text+footermarkup
lastReport = append(lastReport, cleanMarkup(last[0]))
last = last[1:]
for _, sl := range last {
if extraBaseMarkup.MatchString(sl) {
break
}
lastReport = append(lastReport, cleanMarkup(sl))
}
forecasts = append(forecasts, lastReport)
}
}
}
meta.Station = station
meta.Date = dateTime
meta.Header = head
meta.Meta = imeta
meta.Warning = warning
meta.Notifications = notification
meta.Forecasts = forecasts
meta.Descriptions = desc
return &meta, nil
}
// GetForecast returns the forcast meta information for a specific page.
func GetForecast(station string, url string) (*MetaForcast, error) {
content, err := parseURL(url)
if err != nil {
return nil, err
}
return processPages(station, content)
}
func main() {
var pages = []map[string]string{
map[string]string{
"station": "GMZ853",
"url": "http://weather.noaa.gov/cgi-bin/fmtbltn.pl?file=forecasts/marine/coastal/GM/GMZ853.txt",
},
map[string]string{
"station": "amz115",
"url": "http://weather.noaa.gov/cgi-bin/fmtbltn.pl?file=forecasts/marine/offshore/am/amz115.txt",
},
map[string]string{
"station": "anz898",
"url": "http://weather.noaa.gov/cgi-bin/fmtbltn.pl?file=forecasts/marine/offshore/an/anz898.txt",
},
map[string]string{
"station": "gmz052",
"url": "http://weather.noaa.gov/cgi-bin/fmtbltn.pl?file=forecasts/marine/coastal/gm/gmz052.txt",
},
map[string]string{
"station": "pkz033",
"url": "http://weather.noaa.gov/cgi-bin/fmtbltn.pl?file=forecasts/marine/coastal/pk/pkz033.txt",
},
map[string]string{
"station": "pkz132",
"url": "http://weather.noaa.gov/cgi-bin/fmtbltn.pl?file=forecasts/marine/coastal/pk/pkz132.txt",
},
map[string]string{
"station": "pkz132",
"url": "http://weather.noaa.gov/cgi-bin/fmtbltn.pl?file=forecasts/marine/coastal/pk/pkz132.txt",
},
map[string]string{
"station": "pmz174",
"url": "http://weather.noaa.gov/cgi-bin/fmtbltn.pl?file=forecasts/marine/coastal/pm/pmz174.txt",
},
map[string]string{
"station": "pzz915",
"url": "http://weather.noaa.gov/cgi-bin/fmtbltn.pl?file=forecasts/marine/offshore/pz/PZZ915.txt",
},
}
for _, page := range pages {
fmt.Printf("\n")
fmt.Printf("----------------Station: %+q---------------------------", page["station"])
fmt.Printf("\n")
f, err := GetForecast(page["station"], page["url"])
if err != nil {
fmt.Printf("%s", err)
} else {
fmt.Printf("%s", toString(f, true))
}
fmt.Printf("\n")
fmt.Println("------------------------------------------------------")
}
}
@influx6
Copy link
Author

influx6 commented Jan 2, 2016

Expected Output

----------------Station: "GMZ853"---------------------------
{
    "Station": "GMZ853",
    "Date": "744 AM EST MON JAN 4 2016",
    "Warning": [
        "SMALL CRAFT ADVISORY IN EFFECT FROM 7 PM EST THIS EVENING THROUGH",
        "LATE TUESDAY NIGHT"
    ],
    "Meta": [
        "GMZ853-042200-",
        "COASTAL WATERS FROM ENGLEWOOD TO TARPON SPRINGS FL OUT 20 NM-",
        "744 AM EST MON JAN 4 2016"
    ],
    "Header": [
        "FZUS52 KTBW 041244",
        "CWFTBW",
        "COASTAL WATERS FORECAST FOR FLORIDA",
        "NATIONAL WEATHER SERVICE TAMPA BAY AREA - RUSKIN FL",
        "744 AM EST MON JAN 4 2016"
    ],
    "Forecasts": [
        [
            "REST OF TODAY",
            "NORTH WINDS AROUND 15 KNOTS INCREASING TO 15 TO",
            "20 KNOTS LATE. SEAS 2 TO 4 FEET BUILDING TO 3 TO 5 FEET LATE. BAY",
            "AND INLAND WATERS A MODERATE CHOP."
        ],
        [
            "TONIGHT",
            "NORTHEAST WINDS AROUND 20 KNOTS INCREASING TO 20 TO 25",
            "KNOTS. SEAS 3 TO 5 FEET. BAY AND INLAND WATERS CHOPPY TO ROUGH."
        ],
        [
            "TUESDAY",
            "NORTHEAST WINDS AROUND 20 KNOTS. SEAS 3 TO 4 FEET. BAY",
            "AND INLAND WATERS CHOPPY."
        ],
        [
            "TUESDAY NIGHT",
            "NORTHEAST WINDS AROUND 20 KNOTS. SEAS 3 TO 4",
            "FEET. BAY AND INLAND WATERS CHOPPY."
        ],
        [
            "WEDNESDAY",
            "NORTHEAST WINDS 15 TO 20 KNOTS DIMINISHING TO 10 TO",
            "15 KNOTS IN THE AFTERNOON. SEAS 2 TO 3 FEET. BAY AND INLAND WATERS",
            "CHOPPY. A SLIGHT CHANCE OF SHOWERS."
        ],
        [
            "WEDNESDAY NIGHT",
            "NORTHEAST WINDS AROUND 15 KNOTS DIMINISHING TO",
            "5 TO 10 KNOTS AFTER MIDNIGHT. SEAS 2 TO 3 FEET. BAY AND INLAND",
            "WATERS A MODERATE CHOP. A SLIGHT CHANCE OF SHOWERS. "
        ],
        [
            "THURSDAY",
            "NORTHEAST WINDS AROUND 10 KNOTS THEN BECOMING EAST",
            "AROUND 5 KNOTS IN THE AFTERNOON. SEAS 2 FEET. BAY AND INLAND WATERS",
            "A LIGHT CHOP. "
        ],
        [
            "FRIDAY",
            "SOUTH WINDS AROUND 10 KNOTS THEN BECOMING SOUTHWEST IN THE",
            "AFTERNOON. SEAS 2 FEET OR LESS. BAY AND INLAND WATERS A LIGHT CHOP.",
            "A CHANCE OF SHOWERS. "
        ]
    ],
    "Descriptions": [
        "GULF COASTAL WATERS FROM BONITA BEACH TO THE MOUTH OF THE",
        "SUWANNEE RIVER OUT TO 60 NM.",
        "IMPORTANT NOTICE TO MARINERS...MARINE FORECASTS ARE ISSUED AT LEAST\nFOUR TIMES A DAY. BOATERS ON EXTENDED TRIPS SHOULD ROUTINELY MONITOR\nSUBSEQUENT FORECAST ISSUANCES AND UPDATES FOR THE LATEST MARINE\nWEATHER INFORMATION.\n",
        "THE WAVE HEIGHTS ARE FORECAST AS SIGNIFICANT WAVE HEIGHT WHICH \nIS THE AVERAGE OF THE HIGHEST ONE-THIRD OF THE WAVES. \nTHE HIGHEST WAVES MAY RARELY BE TWICE THE SIGNIFICANT WAVE HEIGHT. \nTHE WINDS AND SEAS NEAR THUNDERSTORMS MAY BE HIGHER THAN FORECAST. \n"
    ],
    "Notifications": null
}
------------------------------------------------------

----------------Station: "amz115"---------------------------
{
    "Station": "AMZ115",
    "Date": "337 AM EST MON JAN 4 2016",
    "Warning": null,
    "Meta": [
        "AMZ115-042100-",
        "ATLANTIC FROM 27N TO 31N BETWEEN 65W AND 70W-",
        "337 AM EST MON JAN 4 2016"
    ],
    "Header": [
        "FZNT23 KNHC 040837",
        "OFFNT3",
        "OFFSHORE WATERS FORECAST FOR THE SW AND TROPICAL N ATLANTIC AND",
        "CARIBBEAN SEA",
        "NWS NATIONAL HURRICANE CENTER MIAMI FL",
        "337 AM EST MON JAN 4 2016"
    ],
    "Forecasts": [
        [
            "TODAY",
            "S TO SW WINDS 20 TO 30 KT. SEAS 8 TO 11 FT. SCATTERED",
            "SHOWERS. "
        ],
        [
            "TONIGHT",
            "SW TO W WINDS 20 TO 30 KT...DIMINISHING TO 15 TO 20 KT",
            "LATE. SEAS 8 TO 11 FT. SCATTERED SHOWERS."
        ],
        [
            "TUE",
            "NW TO N WINDS 20 TO 25 KT. SEAS 8 TO 12 FT N OF 29N...AND",
            "7 TO 9 FT ELSEWHERE. SCATTERED SHOWERS."
        ],
        [
            "TUE NIGHT",
            "NE WINDS 20 TO 25 KT. SEAS 9 TO 13 FT N OF 29N...",
            "AND 8 TO 11 FT ELSEWHERE. "
        ],
        [
            "WED",
            "NE TO E WINDS 20 TO 25 KT. SEAS 10 TO 12 FT. "
        ],
        [
            "WED NIGHT",
            "E WINDS 20 TO 30 KT. SEAS 10 TO 11 FT. "
        ],
        [
            "THU",
            "SE TO S WINDS 20 TO 30 KT. SEAS 10 TO 12 FT. "
        ],
        [
            "THU NIGHT",
            "SW WINDS 20 TO 30 KT. SEAS 10 TO 13 FT. "
        ],
        [
            "FRI NIGHT",
            "NW TO N WINDS 10 TO 15 KT. SEAS 7 TO 10 FT IN NE",
            "SWELL."
        ]
    ],
    "Descriptions": [
        "OFFSHORE WATERS FORECAST FOR THE TROPICAL N ATLANTIC FROM 07N TO",
        "22N BETWEEN 55W AND 64W...THE SW N ATLANTIC S OF 31N W OF 65W",
        "INCLUDING BAHAMAS...AND THE CARIBBEAN SEA.",
        "SEAS GIVEN AS SIGNIFICANT WAVE HEIGHT...WHICH IS THE AVERAGE\nHEIGHT OF THE HIGHEST 1/3 OF THE WAVES. INDIVIDUAL WAVES MAY BE\nMORE THAN TWICE THE SIGNIFICANT WAVE HEIGHT.\n"
    ],
    "Notifications": null
}
------------------------------------------------------

----------------Station: "anz898"---------------------------
{
    "Station": "ANZ898",
    "Date": "343 AM EST MON JAN 4 2016",
    "Warning": null,
    "Meta": [
        "ANZ898-042100-",
        "343 AM EST MON JAN 4 2016"
    ],
    "Header": [
        "FZNT21 KWBC 040843",
        "OFFNT1",
        "OFFSHORE WATERS FORECAST",
        "NWS OCEAN PREDICTION CENTER WASHINGTON DC",
        "343 AM EST MON JAN 4 2016"
    ],
    "Forecasts": [
        [
            "SYNOPSIS FOR NEW ENGLAND WATERS",
            "A COLD FRONT WILL CROSS THE",
            "WATERS TODAY. A STRONG HIGH PRES RIDGE WILL BUILD IN FROM THE W",
            "TONIGHT INTO TUE...AND SLOWLY WEAKEN AS IT MOVES SE ACROSS THE",
            "WATERS LATE TUE INTO TUE NIGHT. THE RIDGE WILL SHIFT S OF THE",
            "REGION WED AND WED NIGHT...THEN RETURN SLOWLY N OVER THE REGION",
            "THU AND THU NIGHT WHILE WEAKENING. ANOTHER HIGH PRES RIDGE WILL",
            "BUILD OVER THE AREA FROM THE N FRI...THEN MOVE E OF THE AREA FRI",
            "NIGHT AS LOW PRES APPROACHES THE WATERS FROM THE SW."
        ]
    ],
    "Descriptions": [
        "NEW ENGLAND CONTINENTAL SHELF AND SLOPE WATERS FROM 25 NM",
        "OFFSHORE TO THE HAGUE LINE...EXCEPT TO 1000 FM S OF NEW ENGLAND",
        "SEAS GIVEN AS SIGNIFICANT WAVE HEIGHT...WHICH IS THE AVERAGE\nHEIGHT OF THE HIGHEST 1/3 OF THE WAVES. INDIVIDUAL WAVES MAY BE\nMORE THAN TWICE THE SIGNIFICANT WAVE HEIGHT.\n"
    ],
    "Notifications": null
}
------------------------------------------------------

----------------Station: "gmz052"---------------------------
{
    "Station": "GMZ052",
    "Date": "420 AM EST MON JAN 4 2016",
    "Warning": [
        "SMALL CRAFT ADVISORY IN EFFECT FOR INCREASING WINDS"
    ],
    "Meta": [
        "GMZ052\u003e055-072\u003e075-041530-",
        "STRAITS OF FLORIDA FROM OCEAN REEF TO CRAIG KEY OUT 20 NM-",
        "STRAITS OF FLORIDA FROM CRAIG KEY TO WEST END OF SEVEN MILE",
        "BRIDGE OUT 20 NM-",
        "STRAITS OF FLORIDA FROM WEST END OF SEVEN MILE BRIDGE TO SOUTH OF",
        "HALFMOON SHOAL OUT 20 NM-",
        "STRAITS OF FLORIDA FROM HALFMOON SHOAL TO 20 NM WEST OF DRY",
        "TORTUGAS OUT 20 NM-",
        "STRAITS OF FLORIDA FROM OCEAN REEF TO CRAIG KEY 20 TO 60 NM OUT-",
        "STRAITS OF FLORIDA FROM CRAIG KEY TO WEST END OF SEVEN MILE",
        "BRIDGE 20 TO 60 NM OUT-",
        "STRAITS OF FLORIDA FROM WEST END OF SEVEN MILE BRIDGE TO SOUTH OF",
        "HALFMOON SHOAL 20 TO 60 NM OUT-",
        "STRAITS OF FLORIDA FROM HALFMOON SHOAL TO 20 NM WEST OF DRY",
        "TORTUGAS 20 TO 60 NM OUT-",
        "420 AM EST MON JAN 4 2016"
    ],
    "Header": [
        "FZUS52 KKEY 040920",
        "CWFKEY",
        "COASTAL WATERS FORECAST FOR THE FLORIDA KEYS",
        "NATIONAL WEATHER SERVICE KEY WEST FL",
        "420 AM EST MON JAN 4 2016"
    ],
    "Forecasts": [
        [
            "TODAY",
            "NORTH TO NORTHEAST WINDS NEAR 10 KNOTS...INCREASING TO NEAR",
            "20 KNOTS THIS MORNING. SEAS 2 TO 3 FEET...BUILDING TO 4 TO 7 FEET.",
            "SCATTERED SHOWERS THIS MORNING. ISOLATED SHOWERS THIS AFTERNOON. "
        ],
        [
            "TONIGHT",
            "NORTH TO NORTHEAST WINDS NEAR 20 KNOTS. SEAS 4 TO 7 FEET.",
            "ISOLATED SHOWERS. "
        ],
        [
            "TUESDAY",
            "NORTHEAST WINDS 20 TO 25 KNOTS. SEAS 5 TO 7",
            "FEET...BUILDING TO 7 TO 9 FEET. SCATTERED SHOWERS."
        ],
        [
            "TUESDAY NIGHT",
            "NORTHEAST WINDS 20 TO 25 KNOTS. SEAS 7 TO 10 FEET.",
            "NUMEROUS SHOWERS AND ISOLATED THUNDERSTORMS."
        ],
        [
            "WEDNESDAY",
            "NORTHEAST WINDS NEAR 20 KNOTS. SEAS 6 TO 9 FEET.",
            "NUMEROUS SHOWERS AND ISOLATED THUNDERSTORMS."
        ],
        [
            "WEDNESDAY NIGHT",
            "NORTH TO NORTHEAST WINDS 15 TO 20",
            "KNOTS...DECREASING TO NEAR 10 KNOTS BY MIDNIGHT. SEAS 4 TO 6",
            "FEET...SUBSIDING TO 2 TO 4 FEET. ISOLATED SHOWERS."
        ],
        [
            "THURSDAY",
            "NORTH WINDS NEAR 10 KNOTS. SEAS 2 TO 3 FEET."
        ],
        [
            "FRIDAY AND FRIDAY NIGHT",
            "SOUTH WINDS NEAR 10 KNOTS. SEAS 2 TO 3",
            "FEET. ISOLATED SHOWERS. "
        ]
    ],
    "Descriptions": [
        "FLORIDA BAY...HAWK CHANNEL AND STRAITS OF FLORIDA FROM OCEAN REEF TO",
        "SOUTH OF DRY TORTUGAS...AND THE EXTREME SOUTHEASTERN GULF OF",
        "MEXICO...INCLUDING THE FLORIDA KEYS NATIONAL MARINE SANCTUARY.",
        "SEAS ARE GIVEN AS SIGNIFICANT WAVE HEIGHT...WHICH IS THE AVERAGE\nHEIGHT OF THE HIGHEST 1/3 OF THE WAVES. INDIVIDUAL WAVES MAY BE\nMORE THAN TWICE THE SIGNIFICANT WAVE HEIGHT.\n"
    ],
    "Notifications": null
}
------------------------------------------------------

----------------Station: "pkz033"---------------------------
{
    "Station": "PKZ033",
    "Date": "955 PM AKST SUN JAN 3 2016",
    "Warning": null,
    "Meta": [
        "PKZ033-041545-",
        "SOUTHERN CHATHAM STRAIT-",
        "955 PM AKST SUN JAN 3 2016"
    ],
    "Header": [
        "FZAK51 PAJK 040726 AAA",
        "CWFAJK",
        "COASTAL WATERS FORECAST FOR SOUTHEAST ALASKA...UPDATED",
        "NATIONAL WEATHER SERVICE JUNEAU AK",
        "955 PM AKST SUN JAN 3 2016"
    ],
    "Forecasts": [
        [
            "REST OF TONIGHT",
            "NE WIND 10 KT. SEAS 5 FT...EXCEPT 8 FT NEAR",
            "OCEAN ENTRANCES. PATCHY FOG. "
        ],
        [
            "MON",
            "E WIND 10 KT. SEAS 2 FT OR LESS...EXCEPT 7 FT NEAR OCEAN",
            "ENTRANCES. PATCHY FOG IN THE MORNING. "
        ],
        [
            "MON NIGHT",
            "N WIND 10 KT. SEAS 3 FT...EXCEPT 13 FT NEAR OCEAN",
            "ENTRANCES. "
        ],
        [
            "TUE",
            "N WIND 10 KT. SEAS 2 FT OR LESS...EXCEPT 13 FT NEAR",
            "OCEAN ENTRANCES. "
        ],
        [
            "TUE NIGHT",
            "N WIND 10 KT. SEAS 3 FT...EXCEPT 9 FT NEAR OCEAN",
            "ENTRANCES."
        ],
        [
            "WED",
            "NE WIND 15 KT. SEAS 4 FT. "
        ],
        [
            "FRI",
            "SE WIND 20 KT. SEAS 4 FT. "
        ]
    ],
    "Descriptions": [
        "SOUTHEAST ALASKA INSIDE WATERS FROM DIXON ENTRANCE TO SKAGWAY",
        "WIND FORECASTS REFLECT THE PREDOMINANT SPEED AND DIRECTION\nEXPECTED. SEA FORECASTS REPRESENT THE AVERAGE OF THE HIGHEST\nONE-THIRD OF THE COMBINED WINDWAVE AND SWELL HEIGHT.\n"
    ],
    "Notifications": [
        "UPDATED"
    ]
}
------------------------------------------------------

----------------Station: "pkz132"---------------------------
{
    "Station": "PKZ132",
    "Date": "308 AM AKST MON JAN 4 2016",
    "Warning": [
        "SMALL CRAFT ADVISORY THROUGH TUESDAY"
    ],
    "Meta": [
        "PKZ132-050115-",
        "MARMOT ISLAND TO SITKINAK-",
        "308 AM AKST MON JAN 4 2016"
    ],
    "Header": [
        "FZAK51 PAFC 041208",
        "CWFAER",
        "COASTAL WATERS FORECAST",
        "NATIONAL WEATHER SERVICE ANCHORAGE ALASKA",
        "308 AM AKST MON JAN 4 2016"
    ],
    "Forecasts": [
        [
            "TODAY",
            "SE WIND 30 KT. SEAS 16 FT. RAIN."
        ],
        [
            "TONIGHT",
            "SE WIND 30 KT. SEAS 17 FT. RAIN."
        ],
        [
            "TUE",
            "S WIND 30 KT. SEAS 14 FT. RAIN."
        ],
        [
            "TUE NIGHT",
            "SW WIND 15 KT. SEAS 12 FT."
        ],
        [
            "WED",
            "NE WIND 25 KT. SEAS 10 FT."
        ],
        [
            "FRI",
            "E WIND 35 KT. SEAS 21 FT."
        ]
    ],
    "Descriptions": [
        "COASTAL WATERS FORECAST FOR THE NORTHERN GULF OF ALASKA COAST",
        "UP TO 100 NM OUT INCLUDING KODIAK ISLAND AND COOK INLET.",
        "WIND FORECASTS REFLECT THE PREDOMINANT SPEED AND DIRECTION\nEXPECTED. SEA FORECASTS REPRESENT AN AVERAGE OF THE HIGHEST\nONE-THIRD OF THE COMBINED WIND WAVE AND SWELL HEIGHT.\n"
    ],
    "Notifications": null
}
------------------------------------------------------

----------------Station: "pkz132"---------------------------
{
    "Station": "PKZ132",
    "Date": "308 AM AKST MON JAN 4 2016",
    "Warning": [
        "SMALL CRAFT ADVISORY THROUGH TUESDAY"
    ],
    "Meta": [
        "PKZ132-050115-",
        "MARMOT ISLAND TO SITKINAK-",
        "308 AM AKST MON JAN 4 2016"
    ],
    "Header": [
        "FZAK51 PAFC 041208",
        "CWFAER",
        "COASTAL WATERS FORECAST",
        "NATIONAL WEATHER SERVICE ANCHORAGE ALASKA",
        "308 AM AKST MON JAN 4 2016"
    ],
    "Forecasts": [
        [
            "TODAY",
            "SE WIND 30 KT. SEAS 16 FT. RAIN."
        ],
        [
            "TONIGHT",
            "SE WIND 30 KT. SEAS 17 FT. RAIN."
        ],
        [
            "TUE",
            "S WIND 30 KT. SEAS 14 FT. RAIN."
        ],
        [
            "TUE NIGHT",
            "SW WIND 15 KT. SEAS 12 FT."
        ],
        [
            "WED",
            "NE WIND 25 KT. SEAS 10 FT."
        ],
        [
            "FRI",
            "E WIND 35 KT. SEAS 21 FT."
        ]
    ],
    "Descriptions": [
        "COASTAL WATERS FORECAST FOR THE NORTHERN GULF OF ALASKA COAST",
        "UP TO 100 NM OUT INCLUDING KODIAK ISLAND AND COOK INLET.",
        "WIND FORECASTS REFLECT THE PREDOMINANT SPEED AND DIRECTION\nEXPECTED. SEA FORECASTS REPRESENT AN AVERAGE OF THE HIGHEST\nONE-THIRD OF THE COMBINED WIND WAVE AND SWELL HEIGHT.\n"
    ],
    "Notifications": null
}
------------------------------------------------------

----------------Station: "pmz174"---------------------------
{
    "Station": "PMZ174",
    "Date": "257 PM CHST MON JAN 4 2016",
    "Warning": [
        "HIGH SURF ADVISORY REMAINS IN EFFECT ALONG EAST FACING SHORES",
        "WINDS AND SEAS HAZARDOUS FOR SMALL CRAFT THROUGH TUESDAY"
    ],
    "Meta": [
        "PMZ174-041700-",
        "KOSRAE-",
        "257 PM CHST MON JAN 4 2016"
    ],
    "Header": [
        "FZPQ51 PGUM 040457",
        "CWFPQ1",
        "COASTAL WATERS FORECAST FOR EASTERN MICRONESIA",
        "NATIONAL WEATHER SERVICE TIYAN GU",
        "257 PM CHST MON JAN 4 2016"
    ],
    "Forecasts": [
        [
            "TONIGHT",
            "EAST WINDS 15 TO 25 KT. COMBINED SEAS 8 TO 10 FT.",
            "MOSTLY CLOUDY WITH SCATTERED SHOWERS AND ISOLATED THUNDERSTORMS."
        ],
        [
            "TUESDAY",
            "EAST WINDS 15 TO 25 KT. COMBINED SEAS 8 TO 10 FT.",
            "MOSTLY CLOUDY WITH SCATTERED SHOWERS AND ISOLATED THUNDERSTORMS."
        ],
        [
            "TUESDAY NIGHT AND WEDNESDAY",
            "EAST WIND 15 TO 20 KT. COMBINED",
            "SEAS 8 TO 9 FT. MOSTLY CLOUDY WITH ISOLATED SHOWERS AND",
            "THUNDERSTORMS."
        ],
        [
            "THURSDAY THROUGH SATURDAY",
            "NORTHEAST WINDS 10 TO 20 KT.",
            "COMBINED SEAS 6 TO 7 FT. PARTLY CLOUDY WITH ISOLATED SHOWERS."
        ]
    ],
    "Descriptions": [
        "ISLANDS/ATOLLS AND COASTAL WATERS OUT TO 40 NAUTICAL MILES"
    ],
    "Notifications": null
}
------------------------------------------------------
----------------Station: "pzz915"---------------------------
{
    "Station": "PZZ915",
    "Date": "216 AM PST MON JAN 4 2016",
    "Warning": [
        "GALE WARNING"
    ],
    "Meta": [
        "PZZ915-042315-",
        "FLORENCE, OR TO POINT ST. GEORGE BETWEEN 150 NM AND 250 NM",
        "OFFSHORE-",
        "216 AM PST MON JAN 4 2016"
    ],
    "Header": [
        "FZPN25 KWBC 041016",
        "OFFPZ5",
        "OFFSHORE WATERS FORECAST",
        "NWS OCEAN PREDICTION CENTER WASHINGTON DC",
        "216 AM PST MON JAN 4 2016"
    ],
    "Forecasts": [
        [
            "TODAY",
            "SE WINDS 10 TO 15 KT...INCREASING TO 15 TO 25 KT. SEAS",
            "11 TO 12 FT. "
        ],
        [
            "TONIGHT",
            "SE WINDS 15 TO 25 KT...BECOMING W 30 TO 40 KT. SEAS",
            "BUILDING TO 11 TO 19 FT. CHANCE OF RAIN."
        ],
        [
            "TUE",
            "W TO SW WINDS 30 TO 40 KT. SEAS BECOMING 16 TO 21 FT.",
            "CHANCE OF RAIN."
        ],
        [
            "TUE NIGHT",
            "S TO SW WINDS BECOMING 20 TO 30 KT. SEAS SUBSIDING TO 13",
            "TO 18 FT."
        ],
        [
            "WED",
            "W TO SW WINDS BECOMING 5 TO 15 KT. SEAS 13 TO 18 FT."
        ],
        [
            "WED NIGHT",
            "WINDS VEERING TO W TO NW LESS THAN 10 KT. SEAS 15 TO",
            "20 FT."
        ],
        [
            "THU",
            "VARIABLE WINDS LESS THAN 10 KT. SEAS 12 TO 19 FT. "
        ],
        [
            "THU NIGHT",
            "VARIABLE WINDS LESS THAN 10 KT...BECOMING S 10 TO",
            "20 KT. SEAS SUBSIDING TO 10 TO 14 FT. "
        ],
        [
            "FRI",
            "S TO SE WINDS 15 TO 25 KT. SEAS SUBSIDING TO 8 TO 10 FT. "
        ],
        [
            ".FORECASTER ROWLAND. OCEAN PREDICTION CENTER."
        ]
    ],
    "Descriptions": [
        "WASHINGTON AND OREGON WATERS-",
        "INNER WATERS FROM  60 NM TO 150 NM OFFSHORE.",
        "OUTER WATERS FROM 150 NM TO 250 NM OFFSHORE.",
        "SEAS GIVEN AS SIGNIFICANT WAVE HEIGHT...WHICH IS THE AVERAGE\nHEIGHT OF THE HIGHEST 1/3 OF THE WAVES. INDIVIDUAL WAVES MAY BE\nMORE THAN TWICE THE SIGNIFICANT WAVE HEIGHT.\n"
    ],
    "Notifications": null
}
------------------------------------------------------


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment