about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorCode Carefully <CodeCarefully@users.noreply.github.com>2020-03-26 19:00:42 +0200
committerCode Carefully <CodeCarefully@users.noreply.github.com>2020-03-26 19:00:42 +0200
commit9918422f1dc7a7b276bdf7b4020aa335bf688850 (patch)
tree9baad81097596cb88bb0a5ca359da89a842d0f18
parent68204e4de281891cd58db7943769a2f7779a96a8 (diff)
downloadmyCovidCLI-9918422f1dc7a7b276bdf7b4020aa335bf688850.tar.gz
initial version
-rw-r--r--.gitignore15
-rw-r--r--README.md18
-rw-r--r--parse.go137
-rw-r--r--renderfloat/renderfloat.go194
4 files changed, 363 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..66fd13c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
diff --git a/README.md b/README.md
index 460c37c..d58bbfc 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,18 @@
 # myCOVIDcli
-just a fast covid cli fetcher
+
+Hi!
+I'm pretty new to Go, but I decided to use some of my downtime in this terrible situation to be able to see a 
+nice printout of the places I'm monitoring from the CLI.
+
+Please be respectful of the other connected projects!
+
+Credits:
+
+COVID19 updates from (Novel Coronavirus (COVID-19) Cases, provided by JHU CSSE)
+https://github.com/CSSEGISandData/COVID-19/
+
+Some .gitignore inspiration from: https://github.com/github/gitignore
+
+"DownloadFile" from https://golangcode.com/download-a-file-from-a-url/
+
+renderfloat from https://gist.github.com/gorhill/5285193 (WTFPL)
\ No newline at end of file
diff --git a/parse.go b/parse.go
new file mode 100644
index 0000000..4b22082
--- /dev/null
+++ b/parse.go
@@ -0,0 +1,137 @@
+package main
+
+import (
+	"bufio"
+	"coronaVirus/renderfloat"
+	"encoding/csv"
+	"fmt"
+	"github.com/olekukonko/tablewriter"
+	"io"
+	"log"
+	"net/http"
+	"os"
+	"strconv"
+	"time"
+)
+
+// DownloadFile will download a url to a local file. It's efficient because it will
+// write as it downloads and not load the whole file into memory.
+func DownloadFile(filepath string, url string) error {
+
+	// Get the data
+	resp, err := http.Get(url)
+	if err != nil {
+		return err
+	}
+	defer resp.Body.Close()
+
+	// Create the file
+	out, err := os.Create(filepath)
+	if err != nil {
+		return err
+	}
+	defer out.Close()
+
+	// Write the body to file
+	_, err = io.Copy(out, resp.Body)
+	return err
+}
+
+func main() {
+	currentTime := time.Now() //get current time/date
+	currentTime = currentTime.AddDate(0, 0, -1) //go to yesterday, this source updates only daily
+	strcurrentdate := currentTime.Format("01-02-2006") //reformat for URL format
+	COVIDurl := "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_daily_reports/"+strcurrentdate+".csv"
+
+	//fmt.Println(COVIDurl)
+
+	filepath := "covid.csv" // path to save the CSV to.
+	if err := DownloadFile(filepath, COVIDurl); err != nil {
+		panic(err)
+	}
+
+	csvFile, _ := os.Open(filepath)
+	reader := csv.NewReader(bufio.NewReader(csvFile))
+
+	//zero out all variables
+	usconfirmed := 0
+	usdeaths := 0
+	region := ""
+	state := ""
+	confirmed := ""
+	deaths:=""
+
+	data := [][]string{}
+
+	for {
+		line, error := reader.Read() //read in a line
+		if error == io.EOF {
+			break
+		} else if error != nil {
+			log.Fatal(error)
+		}
+
+		region = line[3]
+		state = line[1]
+		confirmed = line[7]
+		deaths = line[8]
+
+		if region == "US" {
+
+			confirmed, err := strconv.Atoi(line[7]) //convert confirmed to int
+			if err != nil {
+				// handle error
+				fmt.Println(err)
+				os.Exit(2)
+			}
+			deaths, err := strconv.Atoi(line[8]) //convert deaths to int
+			if err != nil {
+				// handle error
+				fmt.Println(err)
+				os.Exit(2)
+			}
+			usconfirmed = usconfirmed + confirmed
+			usdeaths = usdeaths + deaths
+		}
+
+		//create array for table output
+		if state == "New York City" {
+			f, _ := strconv.ParseFloat(confirmed, 8)
+			data = append(data, []string{state, renderfloat.RenderFloat("#,###.", f), deaths})
+			//fmt.Println(state + "   Deaths: " + deaths + " Confirmed: " + confirmed )
+		}
+
+		if region == "Israel" {
+			f, _ := strconv.ParseFloat(confirmed, 8)
+			data = append(data, []string{region, renderfloat.RenderFloat("#,###.", f), deaths})
+			//fmt.Println(region + "   Deaths: " + deaths + " Confirmed: " + confirmed )
+		}
+
+		if region == "Italy" {
+			f, _ := strconv.ParseFloat(confirmed, 8)
+			d, _ := strconv.ParseFloat(deaths, 8)
+			data = append(data, []string{region, renderfloat.RenderFloat("#,###.", f), renderfloat.RenderFloat("#,###.", d)})
+			//fmt.Println(region + "   Deaths: " + deaths + " Confirmed: " + confirmed )
+		}
+
+		if region == "Estonia" {
+			f, _ := strconv.ParseFloat(confirmed, 8)
+			data = append(data, []string{region, renderfloat.RenderFloat("#,###.", f), deaths})
+			//fmt.Println(region + "   Deaths: " + deaths + " Confirmed: " + confirmed )
+		}
+	}
+
+		usconfirmed1, _ := strconv.ParseFloat(strconv.Itoa(usconfirmed), 8)
+		usdeaths1, _ := strconv.ParseFloat(strconv.Itoa(usdeaths), 8)
+		data = append(data, []string{"USA", renderfloat.RenderFloat("#,###.", usconfirmed1), renderfloat.RenderFloat("#,###.", usdeaths1) })
+
+	table := tablewriter.NewWriter(os.Stdout)
+	table.SetHeader([]string{"Area", "Confirmed", "Deaths"})
+
+	for _, v := range data {
+		table.Append(v)
+	}
+	table.Render() // Send output
+
+	}
+
diff --git a/renderfloat/renderfloat.go b/renderfloat/renderfloat.go
new file mode 100644
index 0000000..042a36d
--- /dev/null
+++ b/renderfloat/renderfloat.go
@@ -0,0 +1,194 @@
+/*
+
+Author: https://github.com/gorhill
+Source: https://gist.github.com/gorhill/5285193
+
+A Go function to render a number to a string based on
+the following user-specified criteria:
+
+* thousands separator
+* decimal separator
+* decimal precision
+
+Usage: s := RenderFloat(format, n)
+
+The format parameter tells how to render the number n.
+
+http://play.golang.org/p/LXc1Ddm1lJ
+
+Examples of format strings, given n = 12345.6789:
+
+"#,###.##" => "12,345.67"
+"#,###." => "12,345"
+"#,###" => "12345,678"
+"#\u202F###,##" => "12 345,67"
+"#.###,###### => 12.345,678900
+"" (aka default format) => 12,345.67
+
+The highest precision allowed is 9 digits after the decimal symbol.
+There is also a version for integer number, RenderInteger(),
+which is convenient for calls within template.
+
+I didn't feel it was worth to publish a library just for this piece
+of code, hence the snippet. Feel free to reuse as you wish.
+[my note: the WTFPL was attached: DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE]
+
+*/
+package renderfloat
+
+import (
+"math"
+"strconv"
+)
+
+var renderFloatPrecisionMultipliers = [10]float64{
+1,
+10,
+100,
+1000,
+10000,
+100000,
+1000000,
+10000000,
+100000000,
+1000000000,
+}
+
+var renderFloatPrecisionRounders = [10]float64{
+0.5,
+0.05,
+0.005,
+0.0005,
+0.00005,
+0.000005,
+0.0000005,
+0.00000005,
+0.000000005,
+0.0000000005,
+}
+
+func RenderFloat(format string, n float64) string {
+// Special cases:
+//   NaN = "NaN"
+//   +Inf = "+Infinity"
+//   -Inf = "-Infinity"
+if math.IsNaN(n) {
+return "NaN"
+}
+if n > math.MaxFloat64 {
+return "Infinity"
+}
+if n < -math.MaxFloat64 {
+return "-Infinity"
+}
+
+// default format
+precision := 2
+decimalStr := "."
+thousandStr := ","
+positiveStr := ""
+negativeStr := "-"
+
+if len(format) > 0 {
+// If there is an explicit format directive,
+// then default values are these:
+precision = 9
+thousandStr = ""
+
+// collect indices of meaningful formatting directives
+formatDirectiveChars := []rune(format)
+formatDirectiveIndices := make([]int, 0)
+for i, char := range formatDirectiveChars {
+if char != '#' && char != '0' {
+formatDirectiveIndices = append(formatDirectiveIndices, i)
+}
+}
+
+if len(formatDirectiveIndices) > 0 {
+// Directive at index 0:
+//   Must be a '+'
+//   Raise an error if not the case
+// index: 0123456789
+//        +0.000,000
+//        +000,000.0
+//        +0000.00
+//        +0000
+if formatDirectiveIndices[0] == 0 {
+if formatDirectiveChars[formatDirectiveIndices[0]] != '+' {
+panic("RenderFloat(): invalid positive sign directive")
+}
+positiveStr = "+"
+formatDirectiveIndices = formatDirectiveIndices[1:]
+}
+
+// Two directives:
+//   First is thousands separator
+//   Raise an error if not followed by 3-digit
+// 0123456789
+// 0.000,000
+// 000,000.00
+if len(formatDirectiveIndices) == 2 {
+if (formatDirectiveIndices[1] - formatDirectiveIndices[0]) != 4 {
+panic("RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers")
+}
+thousandStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
+formatDirectiveIndices = formatDirectiveIndices[1:]
+}
+
+// One directive:
+//   Directive is decimal separator
+//   The number of digit-specifier following the separator indicates wanted precision
+// 0123456789
+// 0.00
+// 000,0000
+if len(formatDirectiveIndices) == 1 {
+decimalStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
+precision = len(formatDirectiveChars) - formatDirectiveIndices[0] - 1
+}
+}
+}
+
+// generate sign part
+var signStr string
+if n >= 0.000000001 {
+signStr = positiveStr
+} else if n <= -0.000000001 {
+signStr = negativeStr
+n = -n
+} else {
+signStr = ""
+n = 0.0
+}
+
+// split number into integer and fractional parts
+intf, fracf := math.Modf(n + renderFloatPrecisionRounders[precision])
+
+// generate integer part string
+intStr := strconv.Itoa(int(intf))
+
+// add thousand separator if required
+if len(thousandStr) > 0 {
+for i := len(intStr); i > 3; {
+i -= 3
+intStr = intStr[:i] + thousandStr + intStr[i:]
+}
+}
+
+// no fractional part, we can leave now
+if precision == 0 {
+return signStr + intStr
+}
+
+// generate fractional part
+fracStr := strconv.Itoa(int(fracf * renderFloatPrecisionMultipliers[precision]))
+// may need padding
+if len(fracStr) < precision {
+fracStr = "000000000000000"[:precision-len(fracStr)] + fracStr
+}
+
+return signStr + intStr + decimalStr + fracStr
+}
+
+func RenderInteger(format string, n int) string {
+return RenderFloat(format, float64(n))
+}