diff --git a/chart/.helmignore b/chart/.helmignore
deleted file mode 100644
index 0e8a0eb36f4ca2c939201c0d54b5d82a1ea34778..0000000000000000000000000000000000000000
--- a/chart/.helmignore
+++ /dev/null
@@ -1,23 +0,0 @@
-# Patterns to ignore when building packages.
-# This supports shell glob matching, relative path matching, and
-# negation (prefixed with !). Only one pattern per line.
-.DS_Store
-# Common VCS dirs
-.git/
-.gitignore
-.bzr/
-.bzrignore
-.hg/
-.hgignore
-.svn/
-# Common backup files
-*.swp
-*.bak
-*.tmp
-*.orig
-*~
-# Various IDEs
-.project
-.idea/
-*.tmproj
-.vscode/
diff --git a/chart/Chart.yaml b/chart/Chart.yaml
deleted file mode 100644
index 4acf55a2d44bae7a4ff6157f1b1646c4725a823d..0000000000000000000000000000000000000000
--- a/chart/Chart.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
-apiVersion: v2
-name: dawn-gdd
-description: A Helm chart for Kubernetes
-
-# A chart can be either an 'application' or a 'library' chart.
-#
-# Application charts are a collection of templates that can be packaged into versioned archives
-# to be deployed.
-#
-# Library charts provide useful utilities or functions for the chart developer. They're included as
-# a dependency of application charts to inject those utilities and functions into the rendering
-# pipeline. Library charts do not define any templates and therefore cannot be deployed.
-type: application
-
-# This is the chart version. This version number should be incremented each time you make changes
-# to the chart and its templates, including the app version.
-# Versions are expected to follow Semantic Versioning (https://semver.org/)
-version: 0.1.0
-
-# This is the version number of the application being deployed. This version number should be
-# incremented each time you make changes to the application. Versions are not expected to
-# follow Semantic Versioning. They should reflect the version the application is using.
-# It is recommended to use it with quotes.
-appVersion: "0.1.0"
diff --git a/chart/templates/_helpers.tpl b/chart/templates/_helpers.tpl
deleted file mode 100644
index 57ac2c921b4bc3ac122010da99311443b6595f3d..0000000000000000000000000000000000000000
--- a/chart/templates/_helpers.tpl
+++ /dev/null
@@ -1,62 +0,0 @@
-{{/*
-Expand the name of the chart.
-*/}}
-{{- define "dawn-gateway.name" -}}
-{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
-{{- end }}
-
-{{/*
-Create a default fully qualified app name.
-We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
-If release name contains chart name it will be used as a full name.
-*/}}
-{{- define "dawn-gateway.fullname" -}}
-{{- if .Values.fullnameOverride }}
-{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
-{{- else }}
-{{- $name := default .Chart.Name .Values.nameOverride }}
-{{- if contains $name .Release.Name }}
-{{- .Release.Name | trunc 63 | trimSuffix "-" }}
-{{- else }}
-{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
-{{- end }}
-{{- end }}
-{{- end }}
-
-{{/*
-Create chart name and version as used by the chart label.
-*/}}
-{{- define "dawn-gateway.chart" -}}
-{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
-{{- end }}
-
-{{/*
-Common labels
-*/}}
-{{- define "dawn-gateway.labels" -}}
-helm.sh/chart: {{ include "dawn-gateway.chart" . }}
-{{ include "dawn-gateway.selectorLabels" . }}
-{{- if .Chart.AppVersion }}
-app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
-{{- end }}
-app.kubernetes.io/managed-by: {{ .Release.Service }}
-{{- end }}
-
-{{/*
-Selector labels
-*/}}
-{{- define "dawn-gateway.selectorLabels" -}}
-app.kubernetes.io/name: {{ include "dawn-gateway.name" . }}
-app.kubernetes.io/instance: {{ .Release.Name }}
-{{- end }}
-
-{{/*
-Create the name of the service account to use
-*/}}
-{{- define "dawn-gateway.serviceAccountName" -}}
-{{- if .Values.serviceAccount.create }}
-{{- default (include "dawn-gateway.fullname" .) .Values.serviceAccount.name }}
-{{- else }}
-{{- default "default" .Values.serviceAccount.name }}
-{{- end }}
-{{- end }}
diff --git a/chart/templates/configMap.yaml b/chart/templates/configMap.yaml
deleted file mode 100644
index fb0c1d2ba5a5142b4cb4f2b21eb29ea2d5dea469..0000000000000000000000000000000000000000
--- a/chart/templates/configMap.yaml
+++ /dev/null
@@ -1,25 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
-  name: dawn-gdd-conf
-  namespace: {{ .Release.Namespace }}
-data:
-  conf: |
-    app:
-      name: {{ .Values.conf.app.name }}
-      logLevel: {{ .Values.conf.app.logLevel }}
-      logType: {{ .Values.conf.app.logType }}
-      swagger: {{ .Values.conf.app.swagger }}
-      auth: {{ .Values.conf.app.auth }}
-      swagger-host-url: {{ .Values.conf.app.swaggerHostUrl }}
-      api-version: {{ .Values.conf.app.apiVersion }}
-
-    server:
-      host: {{ .Values.conf.server.host }}
-      port: {{ .Values.conf.server.port }}
-      context-path: {{ .Values.conf.server.contextPath }}
-
-    db:
-      uri: {{ .Values.conf.db.uri }}
-      database: {{ .Values.conf.db.database }}
-  
\ No newline at end of file
diff --git a/chart/templates/deployment.yaml b/chart/templates/deployment.yaml
deleted file mode 100644
index 940317e0f2d2e0a9a9d15159431ee0cd015cafbc..0000000000000000000000000000000000000000
--- a/chart/templates/deployment.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-apiVersion: apps/v1 #  for k8s versions before 1.9.0 use apps/v1beta2  and before 1.8.0 use extensions/v1beta1
-kind: Deployment
-metadata:
-  name: dawn-gdd
-  namespace: {{ .Release.Namespace }}
-  labels:
-    version: {{ .Chart.AppVersion }}
-spec:
-  selector:
-    matchLabels:
-      service: dawn-gdd
-      env: {{ .Release.Namespace }}
-  replicas: 1
-  template:
-    metadata:
-      labels:
-        service: dawn-gdd
-        env: {{ .Release.Namespace }}
-        version: {{ .Chart.AppVersion }}
-      annotations:
-        checksum/config: {{ include (print $.Template.BasePath "/configMap.yaml") . | sha256sum }}
-    spec:
-      containers:
-        - name: dawn-gdd
-          image: docker.registry.dawn.int:5000/dawn/dawn-gdd:{{.Chart.AppVersion}}
-          resources:
-            requests:
-              cpu: {{.Values.resources.requests.cpu}}
-              memory: {{.Values.resources.requests.memory}}
-          volumeMounts:
-            - name: conf
-              mountPath: "/root/config/conf"
-              subPath: conf
-              readOnly: true
-          args:
-            - --config
-            - conf
-          ports:
-            - containerPort: {{.Values.port}}
-      volumes:
-        - name: conf
-          configMap:
-            name: dawn-gdd-conf
diff --git a/chart/templates/service.yaml b/chart/templates/service.yaml
deleted file mode 100644
index af3b224540c79d4d587395d0015ce81f02460c6c..0000000000000000000000000000000000000000
--- a/chart/templates/service.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-apiVersion: v1
-kind: Service
-metadata:
-  name: dawn-gdd
-  namespace: {{ .Release.Namespace }}
-  labels:
-    service: dawn-gdd
-    env: {{ .Release.Namespace }}
-spec:
-  type: ClusterIP
-  ports:
-  - port: 80
-    targetPort: {{.Values.port}}
-  selector:
-    service: dawn-gdd
-    env: {{ .Release.Namespace }}
\ No newline at end of file
diff --git a/chart/values.yaml b/chart/values.yaml
deleted file mode 100644
index 069af186c43979595bee83a47a763a1d24e85387..0000000000000000000000000000000000000000
--- a/chart/values.yaml
+++ /dev/null
@@ -1,25 +0,0 @@
-port: 5000
-resources:
-  requests:
-    cpu: 100m
-    memory: 100Mi
-
-# default for staging
-conf:
-  app:
-    name: gdd-service
-    logType: json
-    logLevel: DEBUG
-    swagger: true
-    auth: false
-    swaggerHostUrl: "localhost:5000"
-    apiVersion: 1
-
-  server:
-    host: "localhost"
-    port: 5000
-    contextPath: "/api/weather"
-
-  db:
-    uri: "mongodb://deployment-internal-mongo.deployment-internal.svc.cluster.local:27017/"
-    database: "weather-service"
diff --git a/services/forecast_service.go b/services/forecast_service.go
index d83bebba1f99b84c9e325b2f06e06699e1a43609..800af411a96b66888576869c179ad191c28de2cd 100644
--- a/services/forecast_service.go
+++ b/services/forecast_service.go
@@ -1,249 +1,251 @@
-package services
-
-import (
-	"math"
-	"sort"
-	"time"
-
-	"github.com/montanaflynn/stats"
-	"github.com/tgs266/dawn-go-common/common"
-	"gitlab.cs.umd.edu/dawn/go-backend/dawn-gdd/models"
-	"gitlab.cs.umd.edu/dawn/go-backend/dawn-gdd/models/enums"
-	"gitlab.cs.umd.edu/dawn/go-backend/dawn-gdd/persistence"
-	"gitlab.cs.umd.edu/dawn/go-backend/dawn-gdd/persistence/entities"
-	"gitlab.cs.umd.edu/dawn/go-backend/dawn-gdd/utils"
-)
-
-func GetStageYearData(ctx common.DawnCtx, request models.GddRequest, comparison int) models.StageData {
-	product := enums.GetProductFromString(request.Product)
-	gddData := persistence.CurrentGddFindFirstByYearAndLocation(ctx, request.BuildLocation())
-	gdds := utils.CalculateGddValues(gddData.MinTemps, gddData.MaxTemps, product, false)
-	request.Year = gddData.AnalogYear
-
-	var gs []entities.Gdd
-	norms := persistence.GetLastNormalsYearly(request.BuildLocation())
-
-	if comparison == -1 {
-		gs = norms
-	} else {
-		gs = []entities.Gdd{persistence.GddFindFirstByYearAndLocation(comparison, request.BuildLocation())}
-	}
-	var normalMeanNonAcc []float64
-	comparisonRows := [][]float64{}
-
-	for i := 0; i < len(gs[0].MinTemps); i++ {
-		rowComp := []float64{}
-		rowNormal := []float64{}
-		for j := 0; j < len(gs); j++ {
-			rowComp = append(rowComp, utils.CalculateSingleGdd(gs[j].MinTemps[i], gs[j].MaxTemps[i], product))
-		}
-		for j := 0; j < len(norms); j++ {
-			rowNormal = append(rowNormal, utils.CalculateSingleGdd(norms[j].MinTemps[i], norms[j].MaxTemps[i], product))
-		}
-		comparisonRows = append(comparisonRows, rowComp)
-		normMeanNoAccValue, _ := stats.Mean(rowNormal)
-		normalMeanNonAcc = append(normalMeanNonAcc, normMeanNoAccValue)
-	}
-
-	allCfs := persistence.CfsFindByLocationMultiple(request.BuildLocation(), 4)
-	// cfsMeans := persistence.CfsFindAllByLocation(request.BuildLocation())
-
-	gddArr := [][]float64{}
-	for i, c := range allCfs {
-		gddArr = append(gddArr, gdds)
-		cfsGddData := utils.CalculateGddValues(c.MinTemps, c.MaxTemps, product, false) // not accumulated
-		// anomaly adjustment function
-		// cfsGddData := utils.CalculateGddValuesCfsNormed(c.MinTemps, c.MaxTemps, product, cfsMeans.MinTemps, cfsMeans.MaxTemps, normalMeanNonAcc) // not accumulated
-		gddArr[i] = append(gddArr[i], cfsGddData...)
-		if len(gddArr[i]) > len(normalMeanNonAcc) {
-			gddArr[i] = gddArr[i][:len(normalMeanNonAcc)]
-		} else {
-			gddArr[i] = append(gddArr[i], normalMeanNonAcc[len(gddArr[i]):]...)
-		}
-	}
-	// none of this data is accumulated
-	returnData := models.StageData{
-		AllGdds:       gddArr,
-		ComparisonAll: comparisonRows,
-	}
-	return returnData
-}
-
-func CalculateStages(ctx common.DawnCtx, request models.StageRequest) map[string]models.Bins {
-	gddReq := models.GddRequest{
-		Year:       request.PlantDate.Year(),
-		Latitude:   request.Latitude,
-		Longitude:  request.Longitude,
-		Accumulate: false,
-		Product:    "CORN",
-	}
-	fyData := GetStageYearData(ctx, gddReq, request.Comparison)
-
-	start := request.PlantDate.YearDay()
-	year := request.PlantDate.Year()
-	if year%4 == 0 && year%100 != 0 || year%400 == 0 {
-		start -= 1
-	}
-
-	state := map[string]models.StageStateInner{}
-	stageMatches := models.BuildStageMatches(request.Mode, request.Value, start, fyData, request)
-
-	accs := make([]float64, len(fyData.AllGdds))
-	accs2 := make([]float64, len(fyData.ComparisonAll[0]))
-	accNormal := 0.0
-	for i := start; i < len(fyData.AllGdds[0]); i++ {
-
-		for r, v := range fyData.AllGdds {
-			accs[r] += v[i]
-		}
-		for j := 0; j < len(fyData.ComparisonAll[0]); j++ {
-			accs2[j] += fyData.ComparisonAll[i][j]
-		}
-
-		normal, _ := stats.Mean(accs2)
-
-		accNormal = normal
-
-		for stage, stageVal := range stageMatches {
-			dists := make([]float64, len(fyData.AllGdds))
-			for r, v := range accs {
-				dists[r] = math.Abs(stageVal - v)
-			}
-			if val, ok := state[stage]; !ok {
-
-				state[stage] = models.StageStateInner{
-					Dists:          dists,
-					Hists:          make([]int, len(fyData.AllGdds)),
-					NormalMeanDist: 1000000,
-					NormalMeanIdx:  0,
-				}
-			} else {
-				normalMeanDist := math.Abs(stageVal - accNormal)
-
-				if normalMeanDist < val.NormalMeanDist {
-					val.NormalMeanDist = normalMeanDist
-					val.NormalMeanIdx = i
-				}
-
-				for r := range accs {
-					if dists[r] < val.Dists[r] {
-						val.Hists[r] = i
-						val.Dists[r] = dists[r]
-					}
-				}
-				state[stage] = val
-			}
-		}
-
-	}
-	ret := BinStageMatches(state, year, start, request.PlantDate)
-	return ret
-
-}
-
-func AvgDiff(data []int) float64 {
-	sort.Ints(data)
-	sum := 0.0
-	c := 0
-	for i := 0; i < len(data)-1; i++ {
-		diff := math.Abs(float64(data[i] - data[i+1]))
-		sum += diff
-		c += 1
-	}
-	return sum / float64(c)
-}
-func Min(data []int) int {
-	sort.Ints(data)
-	return data[0]
-}
-
-func BinStageMatches(stageState map[string]models.StageStateInner, year int, start int, plantDate time.Time) map[string]models.Bins {
-	response := map[string]models.Bins{}
-	alpha := 1.0
-	add := 0
-	if year%4 == 0 && year%100 != 0 || year%400 == 0 {
-		add -= 1
-	}
-
-	for state, stateVal := range stageState {
-		// min := stateVal.Normal95thIdx
-		min := Min(stateVal.Hists)
-		stepSize := int(math.Ceil(AvgDiff(stateVal.Hists)) + 1) // add 1 to increase range (cheating a little) and for uncertainty
-		arr := []float64{}
-		idxs := []int{}
-		base := min
-		total := 0
-		for i := 0; i < 5; i++ {
-			count := 0.0
-			for _, h := range stateVal.Hists {
-				if base <= h && h < base+stepSize {
-					count += 1
-					total += 1
-				}
-			}
-			idxs = append(idxs, base)
-			arr = append(arr, count)
-			base += stepSize
-		}
-		inner := models.Bins{}
-		inner.Bins = []models.Bin{}
-		for i := 0; i < 5; i++ {
-			idx := idxs[i] + add
-			date := plantDate.AddDate(0, 0, idx-start)
-			val := arr[i]
-			smoothedVal := (val + alpha) / (float64(total) + 5*alpha) // modified version of laplace smoothing to remove 0%
-			inner.Bins = append(inner.Bins, models.Bin{
-				Date:  date,
-				Value: smoothedVal,
-			})
-		}
-		inner.ComparisonMean = plantDate.AddDate(0, 0, stateVal.NormalMeanIdx-start)
-		inner.Count = total
-		response[state] = inner
-	}
-	return response
-}
-
-func ForecastFirstLastFreeze(ctx common.DawnCtx, request models.FreezingForecastRequest) models.FreezingForecastResponse {
-	lastFreezeIdx := 0
-	firstFreezeIdx := 0
-
-	baseData := persistence.CurrentGddFindFirstByYearAndLocation(ctx, models.BuildLocation(request.Latitude, request.Longitude))
-	cfsData := persistence.CfsFindAllByLocation(models.BuildLocation(request.Latitude, request.Longitude))
-	normalsData := persistence.NormalsFindFirstByYearAndLocation(models.BuildLocation(request.Latitude, request.Longitude))
-
-	cfsData.MinTemps = append(baseData.MinTemps, cfsData.MinTemps...)
-
-	if len(cfsData.MinTemps) < len(normalsData.MinTemps) {
-		smallerNormalRegion := normalsData.MinTemps[len(cfsData.MinTemps):]
-		cfsData.MinTemps = append(cfsData.MinTemps, smallerNormalRegion...)
-	}
-
-	startDate := time.Date(time.Now().Year(), time.January, 1, 0, 0, 0, 0, time.UTC)
-
-	firstHalfFirstDate := time.Date(time.Now().Year(), time.January, 1, 0, 0, 0, 0, time.UTC)
-	firstHalfLastDate := time.Date(time.Now().Year(), time.July, 31, 0, 0, 0, 0, time.UTC)
-
-	lastHalfFirstDate := time.Date(time.Now().Year(), time.August, 1, 0, 0, 0, 0, time.UTC)
-	lastHalfLastDate := time.Date(time.Now().Year(), time.December, 31, 0, 0, 0, 0, time.UTC)
-
-	for i := 0; i < len(cfsData.MinTemps); i++ {
-		currentDate := startDate.AddDate(0, 0, i)
-		if cfsData.MinTemps[i] <= request.FreezingTemp && currentDate.After(firstHalfFirstDate) && currentDate.Before(firstHalfLastDate) {
-			lastFreezeIdx = i
-		}
-		if cfsData.MinTemps[i] <= request.FreezingTemp && currentDate.After(lastHalfFirstDate) && currentDate.Before(lastHalfLastDate) && firstFreezeIdx == 0 {
-			firstFreezeIdx = i
-			break
-		}
-	}
-
-	lastFreezeDate := startDate.AddDate(0, 0, lastFreezeIdx)
-	firstFreezeDate := startDate.AddDate(0, 0, firstFreezeIdx)
-
-	return models.FreezingForecastResponse{
-		LastFreeze:  []time.Time{lastFreezeDate},
-		FirstFreeze: []time.Time{firstFreezeDate},
-	}
-
-}
+package services
+
+import (
+	"math"
+	"sort"
+	"time"
+
+	"github.com/montanaflynn/stats"
+	"github.com/tgs266/dawn-go-common/common"
+	"gitlab.cs.umd.edu/dawn/go-backend/dawn-gdd/models"
+	"gitlab.cs.umd.edu/dawn/go-backend/dawn-gdd/models/enums"
+	"gitlab.cs.umd.edu/dawn/go-backend/dawn-gdd/persistence"
+	"gitlab.cs.umd.edu/dawn/go-backend/dawn-gdd/persistence/entities"
+	"gitlab.cs.umd.edu/dawn/go-backend/dawn-gdd/utils"
+)
+
+func GetStageYearData(ctx common.DawnCtx, request models.GddRequest, comparison int) models.StageData {
+	product := enums.GetProductFromString(request.Product)
+	gddData := persistence.CurrentGddFindFirstByYearAndLocation(ctx, request.BuildLocation())
+	gdds := utils.CalculateGddValues(gddData.MinTemps, gddData.MaxTemps, product, false)
+	request.Year = gddData.AnalogYear
+
+	var gs []entities.Gdd
+	norms := persistence.GetLastNormalsYearly(request.BuildLocation())
+
+	if comparison == -1 {
+		gs = norms
+	} else {
+		gs = []entities.Gdd{persistence.GddFindFirstByYearAndLocation(comparison, request.BuildLocation())}
+	}
+	var normalMeanNonAcc []float64
+	comparisonRows := [][]float64{}
+
+	for i := 0; i < len(gs[0].MinTemps); i++ {
+		rowComp := []float64{}
+		rowNormal := []float64{}
+		for j := 0; j < len(gs); j++ {
+			rowComp = append(rowComp, utils.CalculateSingleGdd(gs[j].MinTemps[i], gs[j].MaxTemps[i], product))
+		}
+		for j := 0; j < len(norms); j++ {
+			rowNormal = append(rowNormal, utils.CalculateSingleGdd(norms[j].MinTemps[i], norms[j].MaxTemps[i], product))
+		}
+		comparisonRows = append(comparisonRows, rowComp)
+		normMeanNoAccValue, _ := stats.Mean(rowNormal)
+		normalMeanNonAcc = append(normalMeanNonAcc, normMeanNoAccValue)
+	}
+
+	allCfs := persistence.CfsFindByLocationMultiple(request.BuildLocation(), 4)
+	// cfsMeans := persistence.CfsFindAllByLocation(request.BuildLocation())
+
+	gddArr := [][]float64{}
+	for i, c := range allCfs {
+		gddArr = append(gddArr, gdds)
+		cfsGddData := utils.CalculateGddValues(c.MinTemps, c.MaxTemps, product, false) // not accumulated
+		// anomaly adjustment function
+		// cfsGddData := utils.CalculateGddValuesCfsNormed(c.MinTemps, c.MaxTemps, product, cfsMeans.MinTemps, cfsMeans.MaxTemps, normalMeanNonAcc) // not accumulated
+		gddArr[i] = append(gddArr[i], cfsGddData...)
+		if len(gddArr[i]) > len(normalMeanNonAcc) {
+			gddArr[i] = gddArr[i][:len(normalMeanNonAcc)]
+		} else {
+			gddArr[i] = append(gddArr[i], normalMeanNonAcc[len(gddArr[i]):]...)
+		}
+	}
+	// none of this data is accumulated
+	returnData := models.StageData{
+		AllGdds:       gddArr,
+		ComparisonAll: comparisonRows,
+	}
+	return returnData
+}
+
+func CalculateStages(ctx common.DawnCtx, request models.StageRequest) map[string]models.Bins {
+	gddReq := models.GddRequest{
+		Year:       request.PlantDate.Year(),
+		Latitude:   request.Latitude,
+		Longitude:  request.Longitude,
+		Accumulate: false,
+		Product:    "CORN",
+	}
+	fyData := GetStageYearData(ctx, gddReq, request.Comparison)
+
+	start := request.PlantDate.YearDay()
+	year := request.PlantDate.Year()
+	if year%4 == 0 && year%100 != 0 || year%400 == 0 {
+		start -= 1
+	}
+
+	state := map[string]models.StageStateInner{}
+	stageMatches := models.BuildStageMatches(request.Mode, request.Value, start, fyData, request)
+
+	accs := make([]float64, len(fyData.AllGdds))
+	accs2 := make([]float64, len(fyData.ComparisonAll[0]))
+	accNormal := 0.0
+	for i := start; i < len(fyData.AllGdds[0]); i++ {
+
+		for r, v := range fyData.AllGdds {
+			accs[r] += v[i]
+		}
+		for j := 0; j < len(fyData.ComparisonAll[0]); j++ {
+			accs2[j] += fyData.ComparisonAll[i][j]
+		}
+
+		normal, _ := stats.Mean(accs2)
+
+		accNormal = normal
+
+		for stage, stageVal := range stageMatches {
+			dists := make([]float64, len(fyData.AllGdds))
+			for r, v := range accs {
+				dists[r] = math.Abs(stageVal - v)
+			}
+			if val, ok := state[stage]; !ok {
+
+				state[stage] = models.StageStateInner{
+					Dists:          dists,
+					Hists:          make([]int, len(fyData.AllGdds)),
+					NormalMeanDist: 1000000,
+					NormalMeanIdx:  0,
+				}
+			} else {
+				normalMeanDist := math.Abs(stageVal - accNormal)
+
+				if normalMeanDist < val.NormalMeanDist {
+					val.NormalMeanDist = normalMeanDist
+					val.NormalMeanIdx = i
+				}
+
+				for r := range accs {
+					if dists[r] < val.Dists[r] {
+						val.Hists[r] = i
+						val.Dists[r] = dists[r]
+					}
+				}
+				state[stage] = val
+			}
+		}
+
+	}
+	ret := BinStageMatches(state, year, start, request.PlantDate)
+	return ret
+
+}
+
+func AvgDiff(data []int) float64 {
+	sort.Ints(data)
+	sum := 0.0
+	c := 0
+	for i := 0; i < len(data)-1; i++ {
+		diff := math.Abs(float64(data[i] - data[i+1]))
+		sum += diff
+		c += 1
+	}
+	return sum / float64(c)
+}
+func Min(data []int) int {
+	sort.Ints(data)
+	return data[0]
+}
+
+func BinStageMatches(stageState map[string]models.StageStateInner, year int, start int, plantDate time.Time) map[string]models.Bins {
+	response := map[string]models.Bins{}
+	alpha := 1.0
+	add := 0
+	if year%4 == 0 && year%100 != 0 || year%400 == 0 {
+		add -= 1
+	}
+
+	binCount := 3
+
+	for state, stateVal := range stageState {
+		// min := stateVal.Normal95thIdx
+		min := Min(stateVal.Hists)
+		stepSize := int(math.Ceil(AvgDiff(stateVal.Hists)) + 1) // add 1 to increase range (cheating a little) and for uncertainty
+		arr := []float64{}
+		idxs := []int{}
+		base := min
+		total := 0
+		for i := 0; i < binCount; i++ {
+			count := 0.0
+			for _, h := range stateVal.Hists {
+				if base <= h && h < base+stepSize {
+					count += 1
+					total += 1
+				}
+			}
+			idxs = append(idxs, base)
+			arr = append(arr, count)
+			base += stepSize
+		}
+		inner := models.Bins{}
+		inner.Bins = []models.Bin{}
+		for i := 0; i < binCount; i++ {
+			idx := idxs[i] + add
+			date := plantDate.AddDate(0, 0, idx-start)
+			val := arr[i]
+			smoothedVal := (val + alpha) / (float64(total) + float64(binCount)*alpha) // modified version of laplace smoothing to remove 0%
+			inner.Bins = append(inner.Bins, models.Bin{
+				Date:  date,
+				Value: smoothedVal,
+			})
+		}
+		inner.ComparisonMean = plantDate.AddDate(0, 0, stateVal.NormalMeanIdx-start)
+		inner.Count = total
+		response[state] = inner
+	}
+	return response
+}
+
+func ForecastFirstLastFreeze(ctx common.DawnCtx, request models.FreezingForecastRequest) models.FreezingForecastResponse {
+	lastFreezeIdx := 0
+	firstFreezeIdx := 0
+
+	baseData := persistence.CurrentGddFindFirstByYearAndLocation(ctx, models.BuildLocation(request.Latitude, request.Longitude))
+	cfsData := persistence.CfsFindAllByLocation(models.BuildLocation(request.Latitude, request.Longitude))
+	normalsData := persistence.NormalsFindFirstByYearAndLocation(models.BuildLocation(request.Latitude, request.Longitude))
+
+	cfsData.MinTemps = append(baseData.MinTemps, cfsData.MinTemps...)
+
+	if len(cfsData.MinTemps) < len(normalsData.MinTemps) {
+		smallerNormalRegion := normalsData.MinTemps[len(cfsData.MinTemps):]
+		cfsData.MinTemps = append(cfsData.MinTemps, smallerNormalRegion...)
+	}
+
+	startDate := time.Date(time.Now().Year(), time.January, 1, 0, 0, 0, 0, time.UTC)
+
+	firstHalfFirstDate := time.Date(time.Now().Year(), time.January, 1, 0, 0, 0, 0, time.UTC)
+	firstHalfLastDate := time.Date(time.Now().Year(), time.July, 31, 0, 0, 0, 0, time.UTC)
+
+	lastHalfFirstDate := time.Date(time.Now().Year(), time.August, 1, 0, 0, 0, 0, time.UTC)
+	lastHalfLastDate := time.Date(time.Now().Year(), time.December, 31, 0, 0, 0, 0, time.UTC)
+
+	for i := 0; i < len(cfsData.MinTemps); i++ {
+		currentDate := startDate.AddDate(0, 0, i)
+		if cfsData.MinTemps[i] <= request.FreezingTemp && currentDate.After(firstHalfFirstDate) && currentDate.Before(firstHalfLastDate) {
+			lastFreezeIdx = i
+		}
+		if cfsData.MinTemps[i] <= request.FreezingTemp && currentDate.After(lastHalfFirstDate) && currentDate.Before(lastHalfLastDate) && firstFreezeIdx == 0 {
+			firstFreezeIdx = i
+			break
+		}
+	}
+
+	lastFreezeDate := startDate.AddDate(0, 0, lastFreezeIdx)
+	firstFreezeDate := startDate.AddDate(0, 0, firstFreezeIdx)
+
+	return models.FreezingForecastResponse{
+		LastFreeze:  []time.Time{lastFreezeDate},
+		FirstFreeze: []time.Time{firstFreezeDate},
+	}
+
+}
diff --git a/spec.yaml b/spec.yaml
deleted file mode 100644
index 8517e4b8dc73940f79a61d42aedb42d801ab8495..0000000000000000000000000000000000000000
--- a/spec.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-kind: product
-name: dawn-gdd
----
-kind: release
-product-name: dawn-gdd
-product-version: 0.1.0
-release-channel: DEV
-helm-chart: dawn/dawn-gdd
\ No newline at end of file