func (n *Notification) UnmarshalJSON(b []byte) error {
	if string(b) == "null" {
		return nil
	}
	var v struct {
		Namespace  string
		ThreadType string
		ThreadID   uint64
		ImportPaths []string
		Time        time.Time
		Actor       users.User
		Type    string
		Payload json.RawMessage
		Unread        bool
		Participating bool
		Mentioned     bool
	}
	err := json.Unmarshal(b, &v)
	if err != nil {
		return err
	}
	*n = Notification{
		Namespace:     v.Namespace,
		ThreadType:    v.ThreadType,
		ThreadID:      v.ThreadID,
		ImportPaths:   v.ImportPaths,
		Time:          v.Time,
		Actor:         v.Actor,
		Unread:        v.Unread,
		Participating: v.Participating,
		Mentioned:     v.Mentioned,
	}
	switch v.Type {
	case "Issue":
		var p Issue
		err := json.Unmarshal(v.Payload, &p)
		if err != nil {
			return err
		}
		n.Payload = p
	case "Change":
		var p Change
		err := json.Unmarshal(v.Payload, &p)
		if err != nil {
			return err
		}
		n.Payload = p
	case "IssueComment":
		var p IssueComment
		err := json.Unmarshal(v.Payload, &p)
		if err != nil {
			return err
		}
		n.Payload = p
	case "ChangeComment":
		var p ChangeComment
		err := json.Unmarshal(v.Payload, &p)
		if err != nil {
			return err
		}
		n.Payload = p
	case "MarkRead":
		n.Payload = nil  
	default:
		return fmt.Errorf("Notification.UnmarshalJSON: invalid payload type %q", v.Type)
	}
	return nil
}
UnmarshalJSON implements the json.Unmarshaler interface.
package notification
import (
	"context"
	"encoding/json"
	"fmt"
	"time"
	"dmitri.shuralyov.com/state"
	"github.com/shurcooL/users"
)
type Service interface {
	ListNotifications(ctx context.Context, opt ListOptions) ([]Notification, error)
	StreamNotifications(ctx context.Context, ch chan<- []Notification) error
	CountNotifications(ctx context.Context) (uint64, error)
	MarkThreadRead(ctx context.Context, namespace, threadType string, threadID uint64) error
	SubscribeThread(ctx context.Context, namespace, threadType string, threadID uint64, subscribers []users.UserSpec) error
	NotifyThread(ctx context.Context, namespace, threadType string, threadID uint64, nr NotificationRequest) error
}
type ListOptions struct {
	Namespace string
	All bool
}
type NotificationRequest struct {
	ImportPaths []string   
	Time        time.Time  
	Payload interface{}
}
type Notification struct {
	Namespace  string
	ThreadType string
	ThreadID   uint64
	ImportPaths []string  
	Time        time.Time
	Actor       users.User
	Payload interface{}
	Unread        bool
	Participating bool  
	Mentioned     bool  
}
func (n Notification) MarshalJSON() ([]byte, error) {
	v := struct {
		Namespace  string
		ThreadType string
		ThreadID   uint64
		ImportPaths []string
		Time        time.Time
		Actor       users.User
		Type    string
		Payload interface{}
		Unread        bool
		Participating bool
		Mentioned     bool
	}{
		Namespace:     n.Namespace,
		ThreadType:    n.ThreadType,
		ThreadID:      n.ThreadID,
		ImportPaths:   n.ImportPaths,
		Time:          n.Time,
		Actor:         n.Actor,
		Payload:       n.Payload,
		Unread:        n.Unread,
		Participating: n.Participating,
		Mentioned:     n.Mentioned,
	}
	switch n.Payload.(type) {
	case Issue:
		v.Type = "Issue"
	case Change:
		v.Type = "Change"
	case IssueComment:
		v.Type = "IssueComment"
	case ChangeComment:
		v.Type = "ChangeComment"
	case nil:
		v.Type = "MarkRead"  
	default:
		return nil, fmt.Errorf("Notification.MarshalJSON: invalid payload type %T; Notification was %+v", n.Payload, n)
	}
	return json.Marshal(v)
}