<commit_before>// Package gae is a library for interacting with Google App Engine and Datastore.
package gae

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/memcache"
)

const (
	// HeaderCursor is the header for holding the pagination cursor.
	HeaderCursor = "x-cursor"
	// HeaderError is the header for holding error description. This is in all
	// lower-case because it is following the specifications and App Engine
	// changes it to all lowercase no matter the original casing.
	HeaderError = "x-error"
	// KindSession is the kind of entity stored in the Datastore for
	// maintaining session.
	KindSession = "GAESession"
)

var (
	// ErrUnauth is returned when the request is not authenticated.
	ErrUnauth = errors.New("unauthenticated")
)

// DateTime is an auxillary struct for time.Time specifically for the purpose
// of converting to RFC3339 time format in JSON.
//
// DateTime handles time up to the seconds, ignoring the microseconds.
type DateTime struct {
	time.Time
}

// Equal checks whether the two timestamps are referring to the same moment,
// taking into account timezone differences while ignoring sub-second
// differences.
func (d1 *DateTime) Equal(d2 DateTime) bool {
	return d1.Truncate(time.Second).Equal(d2.Truncate(time.Second))
}

// MarshalJSON converts the time into a format like
//
//  "2006-01-02T15:04:05+07:00"
//
// or an empty string if `time.Time.IsZero()`
func (d *DateTime) MarshalJSON() ([]byte, error) {
	if d.IsZero() {
		return json.Marshal("")
	}
	return json.Marshal(d.Format(time.RFC3339))
}

// String for DateTime returns the time in this format
// "YYYY-MM-DDTHH:mm:ss+HH:mm"
//
//	e.g. 2006-01-02T15:04:05+07:00
//
// In other words, the output is formatted using `time.RFC3339`
func (d *DateTime) String() string {
	return d.Format(time.RFC3339)
}

// UnmarshalJSON expects the input to a string like
//
//  "2006-01-02T15:04:05+07:00"
//
// to convert into a time.Time struct wrapped inside DateTime. It is able to
// understand an empty string ("") and convert it to a zeroed `time.Time`
// instance.
func (d *DateTime) UnmarshalJSON(input []byte) error {
	if bytes.Equal([]byte(`""`), input) { //i.e. ""
		d = &DateTime{}
		return nil
	}
	var s string
	if err := json.Unmarshal(input, &s); err != nil {
		return err
	}
	t, err := time.Parse(time.RFC3339, s)
	if err != nil {
		return err
	}
	d.Time = t
	return nil
}

// NewDateTime creates a new DateTime instance from a string. The parameter
// `tstamp` is a string in the format "YYYY-MM-DDTHH:mm:ss+HH:mm"
func NewDateTime(tstamp string) (DateTime, error) {
	t, err := time.Parse(time.RFC3339, tstamp)
	if err != nil {
		return DateTime{}, err
	} else {
		return DateTime{t}, nil
	}
}

// NewDateTimeNow creates a new DateTime instance representing the moment in
// time the function was called. This is basically shorthand for:
//
//	DateTime{time.Now()}
func NewDateTimeNow() DateTime {
	return DateTime{time.Now()}
}

// ErrorResponse should be the return payload if the API endpoints return an
// error response (i.e. error codes in the 4xx and 5xx ranges).
//
// All of the fields are optional. If not set, the fields are omitted from the
// JSON output.
type ErrorResponse struct {
	// ErrorCode is a code that identifies the error. E.g. BAD_FORMAT
	ErrorCode string `json:"errorCode,omitempty"`
	// Field is the name of the field that has the error.
	Field string `json:"email,omitempty"`
	// HelpURL is the URL to the help page that describes the error in more
	// detail. The page should also help the developers know how to fix the
	// error, the cause and resolutions.
	HelpURL string `json:"helpUrl,omitempty"`
	// Message contains a user-friendly message. It may be used to surface to
	// the client directly. For localization, some coordination may be
	// required between the client and server to show the message in the local
	// language.
	Message string `json:"message,omitempty"`
	// OriginalValue contains the original value from the request.
	OriginalValue string `json:"originalValue,omitempty"`
}

// Equal checks if two instances of ErrorResponse are equal. They are<commit_msg>Corrected a JSON conversion bug on ErrorResponse.<commit_after>// Package gae is a library for interacting with Google App Engine and Datastore.
package gae

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/memcache"
)

const (
	// HeaderCursor is the header for holding the pagination cursor.
	HeaderCursor = "x-cursor"
	// HeaderError is the header for holding error description. This is in all
	// lower-case because it is following the specifications and App Engine
	// changes it to all lowercase no matter the original casing.
	HeaderError = "x-error"
	// KindSession is the kind of entity stored in the Datastore for
	// maintaining session.
	KindSession = "GAESession"
)

var (
	// ErrUnauth is returned when the request is not authenticated.
	ErrUnauth = errors.New("unauthenticated")
)

// DateTime is an auxillary struct for time.Time specifically for the purpose
// of converting to RFC3339 time format in JSON.
//
// DateTime handles time up to the seconds, ignoring the microseconds.
type DateTime struct {
	time.Time
}

// Equal checks whether the two timestamps are referring to the same moment,
// taking into account timezone differences while ignoring sub-second
// differences.
func (d1 *DateTime) Equal(d2 DateTime) bool {
	return d1.Truncate(time.Second).Equal(d2.Truncate(time.Second))
}

// MarshalJSON converts the time into a format like
//
//  "2006-01-02T15:04:05+07:00"
//
// or an empty string if `time.Time.IsZero()`
func (d *DateTime) MarshalJSON() ([]byte, error) {
	if d.IsZero() {
		return json.Marshal("")
	}
	return json.Marshal(d.Format(time.RFC3339))
}

// String for DateTime returns the time in this format
// "YYYY-MM-DDTHH:mm:ss+HH:mm"
//
//	e.g. 2006-01-02T15:04:05+07:00
//
// In other words, the output is formatted using `time.RFC3339`
func (d *DateTime) String() string {
	return d.Format(time.RFC3339)
}

// UnmarshalJSON expects the input to a string like
//
//  "2006-01-02T15:04:05+07:00"
//
// to convert into a time.Time struct wrapped inside DateTime. It is able to
// understand an empty string ("") and convert it to a zeroed `time.Time`
// instance.
func (d *DateTime) UnmarshalJSON(input []byte) error {
	if bytes.Equal([]byte(`""`), input) { //i.e. ""
		d = &DateTime{}
		return nil
	}
	var s string
	if err := json.Unmarshal(input, &s); err != nil {
		return err
	}
	t, err := time.Parse(time.RFC3339, s)
	if err != nil {
		return err
	}
	d.Time = t
	return nil
}

// NewDateTime creates a new DateTime instance from a string. The parameter
// `tstamp` is a string in the format "YYYY-MM-DDTHH:mm:ss+HH:mm"
func NewDateTime(tstamp string) (DateTime, error) {
	t, err := time.Parse(time.RFC3339, tstamp)
	if err != nil {
		return DateTime{}, err
	} else {
		return DateTime{t}, nil
	}
}

// NewDateTimeNow creates a new DateTime instance representing the moment in
// time the function was called. This is basically shorthand for:
//
//	DateTime{time.Now()}
func NewDateTimeNow() DateTime {
	return DateTime{time.Now()}
}

// ErrorResponse should be the return payload if the API endpoints return an
// error response (i.e. error codes in the 4xx and 5xx ranges).
//
// All of the fields are optional. If not set, the fields are omitted from the
// JSON output.
type ErrorResponse struct {
	// ErrorCode is a code that identifies the error. E.g. BAD_FORMAT
	ErrorCode string `json:"errorCode,omitempty"`
	// Field is the name of the field that has the error.
	Field string `json:"field,omitempty"`
	// HelpURL is the URL to the help page that describes the error in more
	// detail. The page should also help the developers know how to fix the
	// error, the cause and resolutions.
	HelpURL string `json:"helpUrl,omitempty"`
	// Message contains a user-friendly message. It may be used to surface to
	// the client directly. For localization, some coordination may be
	// required between the client and server to show the message in the local
	// language.
	Message string `json:"message,omitempty"`
	// OriginalValue contains the original value from the request.
	OriginalValue string `json:"originalValue,omitempty"`
}

// Equal checks if two instances of ErrorResponse are equal. They are
{'fraction_non_alphanumeric': 0.10994219653179191, 'fraction_numerical': 0.019421965317919076, 'mean_word_length': 3.6863488624052003, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '687031', 'n_tokens_mistral': 2838, 'n_tokens_neox': 2672, 'n_words': 1047}