mirror of https://github.com/statping/statping
				
				
				
			not finalized, notifications works, additional testing
							parent
							
								
									c92fe8a329
								
							
						
					
					
						commit
						1cfc5b4bda
					
				| 
						 | 
				
			
			@ -20,6 +20,8 @@
 | 
			
		|||
 | 
			
		||||
                    <h6 class="mt-4 text-muted">Notifiers</h6>
 | 
			
		||||
 | 
			
		||||
                  {{notifiers}}
 | 
			
		||||
 | 
			
		||||
                    <div id="notifiers_tabs">
 | 
			
		||||
                        <a v-for="(notifier, index) in notifiers" v-bind:key="`${notifier.method}`" @click.prevent="changeTab" class="nav-link text-capitalize" v-bind:class="{active: liClass(`v-pills-${notifier.method.toLowerCase()}-tab`)}" v-bind:id="`v-pills-${notifier.method.toLowerCase()}-tab`" data-toggle="pill" v-bind:href="`#v-pills-${notifier.method.toLowerCase()}`" role="tab" v-bind:aria-controls="`v-pills-${notifier.method.toLowerCase()}`" aria-selected="false">
 | 
			
		||||
                            <font-awesome-icon :icon="iconName(notifier.icon)" class="mr-2"/> {{notifier.title}}
 | 
			
		||||
| 
						 | 
				
			
			@ -152,10 +154,10 @@
 | 
			
		|||
          }
 | 
			
		||||
      },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        this.update()
 | 
			
		||||
 | 
			
		||||
      },
 | 
			
		||||
    created() {
 | 
			
		||||
          this.update()
 | 
			
		||||
      this.update()
 | 
			
		||||
      },
 | 
			
		||||
      methods: {
 | 
			
		||||
        async update() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,12 +12,10 @@ import (
 | 
			
		|||
 | 
			
		||||
func apiNotifiersHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	var notifs []notifications.Notification
 | 
			
		||||
	notifiers := services.AllNotifiers()
 | 
			
		||||
	for _, n := range notifiers {
 | 
			
		||||
		notif := n.Select()
 | 
			
		||||
		notifer, _ := notifications.Find(notif.Method)
 | 
			
		||||
		notif.UpdateFields(notifer)
 | 
			
		||||
		notifs = append(notifs, *notif)
 | 
			
		||||
	for _, n := range services.AllNotifiers() {
 | 
			
		||||
		no := n.Select()
 | 
			
		||||
		notif, _ := notifications.Find(no.Method)
 | 
			
		||||
		notifs = append(notifs, *no.UpdateFields(notif))
 | 
			
		||||
	}
 | 
			
		||||
	sort.Sort(notifications.NotificationOrder(notifs))
 | 
			
		||||
	returnJson(notifs, w, r)
 | 
			
		||||
| 
						 | 
				
			
			@ -25,12 +23,12 @@ func apiNotifiersHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
 | 
			
		||||
func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	vars := mux.Vars(r)
 | 
			
		||||
	notif := services.FindNotifier(vars["notifier"])
 | 
			
		||||
	if notif == nil {
 | 
			
		||||
	notifer := services.FindNotifier(vars["notifier"])
 | 
			
		||||
	if notifer == nil {
 | 
			
		||||
		sendErrorJson(errors.New("could not find notifier"), w, r)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	returnJson(notif, w, r)
 | 
			
		||||
	returnJson(notifer, w, r)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func apiNotifierUpdateHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
| 
						 | 
				
			
			@ -48,8 +46,7 @@ func apiNotifierUpdateHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
 | 
			
		||||
	log.Infof("Updating %s Notifier", notifer.Title)
 | 
			
		||||
 | 
			
		||||
	err = notifer.Update()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	if err := notifer.Update(); err != nil {
 | 
			
		||||
		sendErrorJson(err, w, r)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ import (
 | 
			
		|||
	"github.com/statping/statping/types/services"
 | 
			
		||||
	"github.com/statping/statping/utils"
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -12,7 +13,7 @@ func TestAttachment(t *testing.T) {
 | 
			
		|||
	notifiers.InitNotifiers()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUnAuthenticatedNotifierRoutes(t *testing.T) {
 | 
			
		||||
func TestAuthenticatedNotifierRoutes(t *testing.T) {
 | 
			
		||||
	slackWebhookUrl := utils.Params.GetString("SLACK_URL")
 | 
			
		||||
 | 
			
		||||
	tests := []HTTPTest{
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +43,12 @@ func TestUnAuthenticatedNotifierRoutes(t *testing.T) {
 | 
			
		|||
			URL:            "/api/notifier/slack",
 | 
			
		||||
			Method:         "GET",
 | 
			
		||||
			ExpectedStatus: 200,
 | 
			
		||||
			BeforeTest:     SetTestENV,
 | 
			
		||||
			BeforeTest: func(t *testing.T) error {
 | 
			
		||||
				notif := services.FindNotifier("slack")
 | 
			
		||||
				require.NotNil(t, notif)
 | 
			
		||||
				assert.Equal(t, "slack", notif.Method)
 | 
			
		||||
				return SetTestENV(t)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Name:   "No Authentication - Update Notifier",
 | 
			
		||||
| 
						 | 
				
			
			@ -68,7 +74,20 @@ func TestUnAuthenticatedNotifierRoutes(t *testing.T) {
 | 
			
		|||
					"limits": 55
 | 
			
		||||
				}`,
 | 
			
		||||
			ExpectedStatus: 200,
 | 
			
		||||
			BeforeTest:     SetTestENV,
 | 
			
		||||
			BeforeTest: func(t *testing.T) error {
 | 
			
		||||
				notif := services.FindNotifier("slack")
 | 
			
		||||
				require.NotNil(t, notif)
 | 
			
		||||
				assert.Equal(t, "slack", notif.Method)
 | 
			
		||||
				assert.False(t, notif.Enabled.Bool)
 | 
			
		||||
				return SetTestENV(t)
 | 
			
		||||
			},
 | 
			
		||||
			AfterTest: func(t *testing.T) error {
 | 
			
		||||
				notif := services.FindNotifier("slack")
 | 
			
		||||
				require.NotNil(t, notif)
 | 
			
		||||
				assert.Equal(t, "slack", notif.Method)
 | 
			
		||||
				assert.True(t, notif.Enabled.Bool)
 | 
			
		||||
				return UnsetTestENV(t)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Name:   "Test Notifier (OnSuccess)",
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +173,7 @@ func TestApiNotifiersRoutes(t *testing.T) {
 | 
			
		|||
			URL:              "/api/notifier/slack",
 | 
			
		||||
			Method:           "GET",
 | 
			
		||||
			ExpectedStatus:   200,
 | 
			
		||||
			ExpectedContains: []string{`"method":"slack"`},
 | 
			
		||||
			ExpectedContains: []string{`"method":"slack"`, `"host":"https://slack.api/example/12345"`},
 | 
			
		||||
			BeforeTest:       SetTestENV,
 | 
			
		||||
			SecureRoute:      true,
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,10 @@ func (c *commandLine) Select() *notifications.Notification {
 | 
			
		|||
	return c.Notification
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *commandLine) Valid(values notifications.Values) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var Command = &commandLine{¬ifications.Notification{
 | 
			
		||||
	Method:      "command",
 | 
			
		||||
	Title:       "Command",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,6 +51,10 @@ func (d *discord) Select() *notifications.Notification {
 | 
			
		|||
	return d.Notification
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *discord) Valid(values notifications.Values) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OnFailure will trigger failing service
 | 
			
		||||
func (d *discord) OnFailure(s services.Service, f failures.Failure) (string, error) {
 | 
			
		||||
	out, err := d.sendRequest(ReplaceVars(d.FailureData.String, s, f))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,10 @@ func (e *emailer) Select() *notifications.Notification {
 | 
			
		|||
	return e.Notification
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *emailer) Valid(values notifications.Values) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var email = &emailer{¬ifications.Notification{
 | 
			
		||||
	Method:      "email",
 | 
			
		||||
	Title:       "SMTP Mail",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,10 @@ func (g *gotify) Select() *notifications.Notification {
 | 
			
		|||
	return g.Notification
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g *gotify) Valid(values notifications.Values) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var Gotify = &gotify{¬ifications.Notification{
 | 
			
		||||
	Method:      "gotify",
 | 
			
		||||
	Title:       "Gotify",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,10 @@ func (l *lineNotifier) Select() *notifications.Notification {
 | 
			
		|||
	return l.Notification
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *lineNotifier) Valid(values notifications.Values) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var LineNotify = &lineNotifier{¬ifications.Notification{
 | 
			
		||||
	Method:      lineNotifyMethod,
 | 
			
		||||
	Title:       "LINE Notify",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,10 @@ func (m *mobilePush) Select() *notifications.Notification {
 | 
			
		|||
	return m.Notification
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *mobilePush) Valid(values notifications.Values) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var Mobile = &mobilePush{¬ifications.Notification{
 | 
			
		||||
	Method: "mobile",
 | 
			
		||||
	Title:  "Mobile",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,6 +27,10 @@ func (t *pushover) Select() *notifications.Notification {
 | 
			
		|||
	return t.Notification
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *pushover) Valid(values notifications.Values) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var Pushover = &pushover{¬ifications.Notification{
 | 
			
		||||
	Method:      "pushover",
 | 
			
		||||
	Title:       "Pushover",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,3 +91,7 @@ func (s *slack) OnSuccess(srv services.Service) (string, error) {
 | 
			
		|||
func (s *slack) OnSave() (string, error) {
 | 
			
		||||
	return "", nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *slack) Valid(values notifications.Values) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,6 +27,10 @@ func (s *statpingEmailer) Select() *notifications.Notification {
 | 
			
		|||
	return s.Notification
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *statpingEmailer) Valid(values notifications.Values) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var statpingMailer = &statpingEmailer{¬ifications.Notification{
 | 
			
		||||
	Method:      statpingEmailerName,
 | 
			
		||||
	Title:       "Email",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,10 @@ func (t *telegram) Select() *notifications.Notification {
 | 
			
		|||
	return t.Notification
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *telegram) Valid(values notifications.Values) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var Telegram = &telegram{¬ifications.Notification{
 | 
			
		||||
	Method:      "telegram",
 | 
			
		||||
	Title:       "Telegram",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,10 @@ func (t *twilio) Select() *notifications.Notification {
 | 
			
		|||
	return t.Notification
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *twilio) Valid(values notifications.Values) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var Twilio = &twilio{¬ifications.Notification{
 | 
			
		||||
	Method:      "twilio",
 | 
			
		||||
	Title:       "Twilio",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,6 +80,10 @@ func (w *webhooker) Select() *notifications.Notification {
 | 
			
		|||
	return w.Notification
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *webhooker) Valid(values notifications.Values) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *webhooker) sendHttpWebhook(body string) (*http.Response, error) {
 | 
			
		||||
	utils.Log.Infoln(fmt.Sprintf("sending body: '%v' to %v as a %v request", body, w.Host.String, w.Var1.String))
 | 
			
		||||
	client := new(http.Client)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,6 +48,10 @@ func Select() (*Core, error) {
 | 
			
		|||
func (c *Core) Create() error {
 | 
			
		||||
	if c.ApiSecret == "" {
 | 
			
		||||
		c.ApiSecret = utils.RandomString(16)
 | 
			
		||||
		apiEnv := utils.Params.GetString("API_SECRET")
 | 
			
		||||
		if apiEnv != "" {
 | 
			
		||||
			c.ApiSecret = apiEnv
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	q := db.Create(c)
 | 
			
		||||
	utils.Log.Infof("API Key created: %s", c.ApiSecret)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
package notifications
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"github.com/statping/statping/database"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -16,11 +15,10 @@ func SetDB(database database.Database) {
 | 
			
		|||
func Find(method string) (*Notification, error) {
 | 
			
		||||
	var n Notification
 | 
			
		||||
	q := db.Where("method = ?", method).Find(&n)
 | 
			
		||||
	if &n == nil {
 | 
			
		||||
		return nil, errors.New("cannot find notifier")
 | 
			
		||||
	if q.Error() != nil {
 | 
			
		||||
		return nil, q.Error()
 | 
			
		||||
	}
 | 
			
		||||
	n.UpdateFields(&n)
 | 
			
		||||
	return &n, q.Error()
 | 
			
		||||
	return &n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n *Notification) Create() error {
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +43,7 @@ func (n *Notification) Create() error {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (n *Notification) UpdateFields(notif *Notification) *Notification {
 | 
			
		||||
	n.Id = notif.Id
 | 
			
		||||
	n.Limits = notif.Limits
 | 
			
		||||
	n.Enabled = notif.Enabled
 | 
			
		||||
	n.Host = notif.Host
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,13 +2,9 @@ package notifications
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/statping/statping/types/metrics"
 | 
			
		||||
	"github.com/statping/statping/utils"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// AfterFind for Notification will set the timezone
 | 
			
		||||
func (n *Notification) AfterFind() (err error) {
 | 
			
		||||
	n.CreatedAt = utils.Now()
 | 
			
		||||
	n.UpdatedAt = utils.Now()
 | 
			
		||||
	metrics.Query("notifier", "find")
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,6 +61,17 @@ func (n *Notification) Logger() *logrus.Logger {
 | 
			
		|||
 | 
			
		||||
type RunFunc func(interface{}) error
 | 
			
		||||
 | 
			
		||||
type Values struct {
 | 
			
		||||
	Host      string
 | 
			
		||||
	Port      int64
 | 
			
		||||
	Username  string
 | 
			
		||||
	Password  string
 | 
			
		||||
	Var1      string
 | 
			
		||||
	Var2      string
 | 
			
		||||
	ApiKey    string
 | 
			
		||||
	ApiSecret string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NotificationForm contains the HTML fields for each variable/input you want the notifier to accept.
 | 
			
		||||
type NotificationForm struct {
 | 
			
		||||
	Type        string   `json:"type"`        // the html input type (text, password, email)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,9 @@ func ReturnNotifier(method string) ServiceNotifier {
 | 
			
		|||
func FindNotifier(method string) *notifications.Notification {
 | 
			
		||||
	n := allNotifiers[method]
 | 
			
		||||
	if n != nil {
 | 
			
		||||
		return n.Select()
 | 
			
		||||
		notif := n.Select()
 | 
			
		||||
		no, _ := notifications.Find(notif.Method)
 | 
			
		||||
		return notif.UpdateFields(no)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -31,4 +33,5 @@ type ServiceNotifier interface {
 | 
			
		|||
	OnTest() (string, error)                             // OnTest is triggered for testing
 | 
			
		||||
	OnSave() (string, error)                             // OnSave is triggered for testing
 | 
			
		||||
	Select() *notifications.Notification                 // OnTest is triggered for testing
 | 
			
		||||
	Valid(notifications.Values) error                    // Valid checks your form values
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ import (
 | 
			
		|||
	"github.com/statping/statping/types/failures"
 | 
			
		||||
	"github.com/statping/statping/types/hits"
 | 
			
		||||
	"github.com/statping/statping/types/incidents"
 | 
			
		||||
	"github.com/statping/statping/types/notifications"
 | 
			
		||||
	"github.com/statping/statping/types/null"
 | 
			
		||||
	"github.com/statping/statping/utils"
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
| 
						 | 
				
			
			@ -182,10 +183,11 @@ func startupDb(t *testing.T) {
 | 
			
		|||
	require.Nil(t, err)
 | 
			
		||||
	db, err := database.OpenTester()
 | 
			
		||||
	require.Nil(t, err)
 | 
			
		||||
	db.AutoMigrate(&Service{}, &hits.Hit{}, &checkins.Checkin{}, &checkins.CheckinHit{}, &failures.Failure{}, &incidents.Incident{}, &incidents.IncidentUpdate{})
 | 
			
		||||
	db.AutoMigrate(&Service{}, ¬ifications.Notification{}, &hits.Hit{}, &checkins.Checkin{}, &checkins.CheckinHit{}, &failures.Failure{}, &incidents.Incident{}, &incidents.IncidentUpdate{})
 | 
			
		||||
	checkins.SetDB(db)
 | 
			
		||||
	failures.SetDB(db)
 | 
			
		||||
	incidents.SetDB(db)
 | 
			
		||||
	notifications.SetDB(db)
 | 
			
		||||
	hits.SetDB(db)
 | 
			
		||||
	SetDB(db)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -198,6 +200,7 @@ func startupDb(t *testing.T) {
 | 
			
		|||
	db.Create(&fail2)
 | 
			
		||||
	db.Create(&incident1)
 | 
			
		||||
	db.Create(&incidentUpdate1)
 | 
			
		||||
	db.Create(&incidentUpdate1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestServices(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -322,3 +322,7 @@ func (e *exampleNotifier) OnTest() (string, error) {
 | 
			
		|||
	e.tests++
 | 
			
		||||
	return "", nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *exampleNotifier) Valid(form notifications.Values) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue