vonage

package module
v0.13.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 30, 2021 License: Apache-2.0 Imports: 15 Imported by: 0

README

Vonage Go SDK

PkgGoDev Actions

Nexmo is now known as Vonage

This is the community-supported Golang library for Vonage. It has support for most of our APIs, but is still under active development. Issues, pull requests and other input is very welcome. The package documentation is available on pkg.go.

If you don't already know Vonage: We make telephony APIs. If you need to make a call, check a phone number, or send an SMS then you are in the right place! If you don't have one yet, you can sign up for a Vonage account and get some free credit to get you started.

Installation

Find current and past releases on the releases page.

Import the package and use it in your own project

import ("github.com/vonage/vonage-go-sdk")

Usage

Usage examples are in the docs/ folder - also rendered via GitHub pages: https://vonage.github.io/vonage-go-sdk/

API Support

Current state of API support in this library:

API API Release Status Supported?
Account API General Availability
Alerts API General Availability
Application API General Availability
Audit API Beta
Conversation API Beta
Dispatch API Beta
External Accounts API Beta
Media API Beta
Messages API Beta
Number Insight API General Availability
Number Management API General Availability
Pricing API General Availability
Redact API Developer Preview
Reports API Beta
SMS API General Availability
Verify API General Availability
Voice API General Availability

Contributions

Yes please! This library is open source, community-driven, and benefits greatly from the input of its users.

Please make all your changes on a branch, and open a pull request, these are welcome and will be reviewed with delight! If it's a big change, it is recommended to open an issue for discussion before you start.

All changes require tests to go with them.

Using a Local Branch

Refer to this excellent blog post for instructions on how to use a local clone of this repository as the import in your own project. This is really useful when you are using a version of the library other than the latest stable release - for example if you are working on a change, or testing an open pull request.

Getting Help

We love to hear from you so if you have questions, comments or find a bug in the project, let us know! You can either:

Further Reading

License

This library is released under the Apache 2.0 License

Documentation

Overview

Package vonage provides lightweight wrappers and helper functionality to support integrations using the Vonage APIs.

Each API is a product in its own right and they may not be consistent between APIs - each has its own client, e.g. smsClient, and associated methods.

This library is at an alpha stage, comments, questions and feedback are always welcome! Just open an issue on the GitHub project.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetUserAgent

func GetUserAgent() string

func GetVersion

func GetVersion() string

Types

type APITransport

type APITransport struct {
	APISecret string

	// Transport is the underlying HTTP transport to use when making requests.
	// It will default to http.DefaultTransport if nil.
	Transport http.RoundTripper
}

APITransport lets us add extra HTTP features and pass them around elegantly

func (*APITransport) Client

func (t *APITransport) Client() *http.Client

Client is our HTTP Client with custom rountripper set

func (*APITransport) RoundTrip

func (t *APITransport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements the RoundTripper interface.

type ApplicationCapabilities

type ApplicationCapabilities struct {
	Voice    *ApplicationVoice    `json:"voice,omitempty"`
	Rtc      *ApplicationRtc      `json:"rtc,omitempty"`
	Messages *ApplicationMessages `json:"messages,omitempty"`
	Vbc      *ApplicationVbc      `json:"vbc,omitempty"`
}

Use pointers so we can tell which things were intentionally sent, or not

type ApplicationClient

type ApplicationClient struct {
	Config *application.Configuration
	// contains filtered or unexported fields
}

ApplicationClient for working with the Application API

func NewApplicationClient

func NewApplicationClient(Auth Auth) *ApplicationClient

NewApplicationClient Creates a new Application Client, supplying an Auth to work with

func (*ApplicationClient) CreateApplication

CreateApplication creates a new application

func (*ApplicationClient) DeleteApplication

func (client *ApplicationClient) DeleteApplication(app_id string) (bool, ApplicationErrorResponse, error)

Delete application deletes an application

func (*ApplicationClient) GetApplication

func (client *ApplicationClient) GetApplication(app_id string) (ApplicationResponse, ApplicationErrorResponse, error)

GetApplication returns one application, by app ID

func (*ApplicationClient) GetApplications

List your Applications

func (*ApplicationClient) UpdateApplication

UpdateApplication updates an existing application

type ApplicationErrorResponse

type ApplicationErrorResponse struct {
	Type     string `json:"type,omitempty"`
	Title    string `json:"title,omitempty"`
	Detail   string `json:"detail,omitempty"`
	Instance string `json:"instance,omitempty"`
}

ApplicationErrorResponse respresents error responses

type ApplicationKeys

type ApplicationKeys struct {
	PublicKey string `json:"public_key,omitempty"`
}

type ApplicationMessages

type ApplicationMessages struct {
	Webhooks ApplicationMessagesWebhooks `json:"webhooks,omitempty"`
}

type ApplicationMessagesWebhooks

type ApplicationMessagesWebhooks struct {
	InboundUrl ApplicationUrl `json:"inbound_url,omitempty"`
	StatusUrl  ApplicationUrl `json:"status_url,omitempty"`
}

type ApplicationResponse

type ApplicationResponse struct {
	Id           string
	Name         string
	Capabilities application.ApplicationResponseCapabilities
	Keys         application.ApplicationResponseKeys
}

type ApplicationResponseCollection

type ApplicationResponseCollection struct {
	PageSize   int32
	Page       int32
	TotalItems int32
	TotalPages int32
	Embedded   ApplicationResponseCollectionEmbedded
}

type ApplicationResponseCollectionEmbedded

type ApplicationResponseCollectionEmbedded struct {
	Applications []ApplicationResponse
}

type ApplicationRtc

type ApplicationRtc struct {
	Webhooks ApplicationRtcWebhooks `json:"webhooks,omitempty"`
}

type ApplicationRtcWebhooks

type ApplicationRtcWebhooks struct {
	EventUrl ApplicationUrl `json:"event_url,omitempty"`
}

type ApplicationUrl

type ApplicationUrl struct {
	Address    string `json:"address,omitempty"`
	HttpMethod string `json:"http_method,omitempty"`
}

type ApplicationVbc

type ApplicationVbc struct {
}

type ApplicationVoice

type ApplicationVoice struct {
	Webhooks ApplicationVoiceWebhooks `json:"webhooks,omitempty"`
}

type ApplicationVoiceWebhooks

type ApplicationVoiceWebhooks struct {
	AnswerUrl         ApplicationUrl `json:"answer_url,omitempty"`
	FallbackAnswerUrl ApplicationUrl `json:"fallback_answer_url,omitempty"`
	EventUrl          ApplicationUrl `json:"event_url,omitempty"`
}

type Auth

type Auth interface {
	GetCreds() []string
}

Auth types are various but support a common interface

type CallFrom

type CallFrom struct {
	Type   string
	Number string
}

CallFrom details of the caller

type CallTo

type CallTo struct {
	Type       string
	Number     string
	DtmfAnswer string
}

CallTo details of the callee

type CreateApplicationOpts

type CreateApplicationOpts struct {
	Keys         ApplicationKeys
	Capabilities ApplicationCapabilities
}

CreateApplicationOpts holds the optional values for a CreateApplication operation

type CreateApplicationRequestOpts

type CreateApplicationRequestOpts struct {
	Name         string                  `json:"name,omitempty"`
	Keys         *ApplicationKeys        `json:"keys,omitempty"`
	Capabilities ApplicationCapabilities `json:"capabilities,omitempty"`
}

CreateApplicationRequestOpts the data structure to send to the API calling code, used inside CreateApplication rather than as an incoming argument

type CreateCallOpts

type CreateCallOpts struct {
	From             CallFrom
	To               CallTo
	Ncco             ncco.Ncco
	AnswerUrl        []string
	AnswerMethod     string
	EventUrl         []string
	EventMethod      string
	MachineDetection string
	LengthTimer      int32
	RingingTimer     int32
}

CreateCallOpts: Options for creating a call

type GetApplicationsOpts

type GetApplicationsOpts struct {
	PageSize int32
	Page     int32
}

type JWTAuth

type JWTAuth struct {
	JWT string
}

JWTAuth is an Auth type to represent a JWT token

func CreateAuthFromAppPrivateKey

func CreateAuthFromAppPrivateKey(appID string, privateKey []byte) (*JWTAuth, error)

CreateAuthFromAppPrivateKey is a helper method to generate auth from an Application ID and a []byte of the private key (use with ioutil.ReadFile)

func CreateAuthFromJwtTokenGenerator

func CreateAuthFromJwtTokenGenerator(generator jwt.Generator) *JWTAuth

CreateAuthFromJwtTokenGenerator accepts a token generator struct, use this to set more of the options on the generator.

func (*JWTAuth) GetCreds

func (auth *JWTAuth) GetCreds() []string

GetCreds returns an array of strings, this time just one element which is the JWT token

type KeySecretAuth

type KeySecretAuth struct {
	// contains filtered or unexported fields
}

KeySecretAuth is an Auth type to represent the API key and API secret combination

func CreateAuthFromKeySecret

func CreateAuthFromKeySecret(apiKey string, apiSecret string) *KeySecretAuth

CreateAuthFromKeySecret returns an Auth type given an API key and API secret

func (*KeySecretAuth) GetCreds

func (auth *KeySecretAuth) GetCreds() []string

GetCreds gives an array of credential strings

type ModifyCallOpts

type ModifyCallOpts struct {
	Action string `json:"action"`
}

type ModifyCallResponse

type ModifyCallResponse struct {
	Status string
}

type NiErrorResponse

type NiErrorResponse struct {
	Status        int32
	StatusMessage string
}

type NiOpts

type NiOpts struct {
	Country string
}

type NiResponseAsync

type NiResponseAsync struct {
	RequestId        string
	Number           string
	RemainingBalance string
	RequestPrice     string
	Status           numberinsight.NiStandardAdvancedStatus
	StatusMessage    string
}

type NiResponseJsonBasic

type NiResponseJsonBasic struct {
	Status                    numberinsight.NiBasicStatus
	StatusMessage             string
	RequestId                 string
	InternationalFormatNumber string
	NationalFormatNumber      string
	CountryCode               string
	CountryCodeIso3           string
	CountryName               string
	CountryPrefix             string
}

type NiResponseJsonStandard

type NiResponseJsonStandard struct {
	Status                    numberinsight.NiBasicStatus
	StatusMessage             string
	RequestId                 string
	InternationalFormatNumber string
	NationalFormatNumber      string
	CountryCode               string
	CountryCodeIso3           string
	CountryName               string
	CountryPrefix             string
	RequestPrice              string
	RefundPrice               string
	RemainingBalance          string
	CurrentCarrier            numberinsight.NiCurrentCarrierProperties
	OriginalCarrier           numberinsight.NiInitialCarrierProperties
	Ported                    string
	Roaming                   numberinsight.NiRoaming
	CallerIdentity            numberinsight.NiCallerIdentity
	CallerName                string
	LastName                  string
	FirstName                 string
	CallerType                string
}

type NumberAvailable

type NumberAvailable struct {
	Country  string
	Msisdn   string
	Type     string
	Cost     string
	Features []string
}

type NumberBuyOpts

type NumberBuyOpts struct {
	TargetAPIKey string
}

NumberBuyOpts enables users to set the Target API Key (and any future params)

type NumberCancelOpts

type NumberCancelOpts struct {
	TargetAPIKey string
}

NumberCancelOpts enables users to set the Target API Key (and any future params)

type NumberCollection

type NumberCollection struct {
	Count   int32
	Numbers []NumberDetail
}

type NumberDetail

type NumberDetail struct {
	Country               string
	Msisdn                string
	MoHttpUrl             string
	Type                  string
	Features              []string
	MessagesCallbackType  string
	MessagesCallbackValue string
	VoiceCallbackType     string
	VoiceCallbackValue    string
}

type NumberInsightClient

type NumberInsightClient struct {
	Config *numberinsight.Configuration
	// contains filtered or unexported fields
}

NumberInsightClient for working with the NumberInsight API

func NewNumberInsightClient

func NewNumberInsightClient(Auth Auth) *NumberInsightClient

NewNumberInsightClient Creates a new NumberInsight Client, supplying an Auth to work with

func (*NumberInsightClient) AdvancedAsync

func (client *NumberInsightClient) AdvancedAsync(number string, callback string, opts NiOpts) (NiResponseAsync, NiErrorResponse, error)

AdvancedAsync requests a callback with advanced-level information about a number

func (*NumberInsightClient) Basic

Basic does a basic-level lookup for data about a number

func (*NumberInsightClient) Standard

func (client *NumberInsightClient) Standard(number string, opts NiOpts) (NiResponseJsonStandard, NiErrorResponse, error)

Standard does a Standard-level lookup for data about a number

type NumberSearch

type NumberSearch struct {
	Count   int32
	Numbers []NumberAvailable
}

type NumberSearchOpts

type NumberSearchOpts struct {
	Type          string
	Features      string
	Pattern       string
	SearchPattern int32
	Size          int32
	Index         int32
}

NumberSearchOpts sets the optional values in the Search method

type NumberUpdateOpts

type NumberUpdateOpts struct {
	AppID                 string
	MoHTTPURL             string
	VoiceCallbackType     string
	VoiceCallbackValue    string
	VoiceStatusCallback   string
	MessagesCallbackType  string
	MessagesCallbackValue string
}

NumberUpdateOpts sets all the various fields for the number config

type NumbersClient

type NumbersClient struct {
	Config *number.Configuration
	// contains filtered or unexported fields
}

NumbersClient for working with the Numbers API

func NewNumbersClient

func NewNumbersClient(Auth Auth) *NumbersClient

NewNumbersClient Creates a new Numbers Client, supplying an Auth to work with

func (*NumbersClient) Buy

func (client *NumbersClient) Buy(country string, msisdn string, opts NumberBuyOpts) (NumbersResponse, NumbersErrorResponse, error)

Buy the best phone number to use in your app

func (*NumbersClient) Cancel

func (client *NumbersClient) Cancel(country string, msisdn string, opts NumberCancelOpts) (NumbersResponse, NumbersErrorResponse, error)

Cancel a number already in your account

func (*NumbersClient) List

List shows the numbers you already own, filters and pagination are available

func (*NumbersClient) Search

func (client *NumbersClient) Search(country string, opts NumberSearchOpts) (NumberSearch, NumbersErrorResponse, error)

Search lets you find a great phone number to use in your application

func (*NumbersClient) Update

func (client *NumbersClient) Update(country string, msisdn string, opts NumberUpdateOpts) (NumbersResponse, NumbersErrorResponse, error)

Update the configuration for your number

type NumbersErrorResponse

type NumbersErrorResponse struct {
	ErrorCode      string `json:"error-code,omitempty"`
	ErrorCodeLabel string `json:"error-code-label,omitempty"`
}

NumbersErrorResponse is the error format for the Numbers API

type NumbersOpts

type NumbersOpts struct {
	ApplicationID  string
	HasApplication string // string because it's tri-state, not boolean
	Country        string
	Pattern        string
	SearchPattern  int32
	Size           int32
	Index          int32
}

NumbersOpts sets the options to use in finding the numbers already in the user's account

type NumbersResponse

type NumbersResponse struct {
	ErrorCode      string `json:"error-code,omitempty"`
	ErrorCodeLabel string `json:"error-code-label,omitempty"`
}

NumbersResponse is the response format for the Numbers API

type PlayAudioOpts

type PlayAudioOpts struct {
	Loop  string
	Level int
}

type PlayTtsOpts

type PlayTtsOpts struct {
	Text      string
	Loop      int32
	Level     string
	VoiceName string
}

type SMSClient

type SMSClient struct {
	Config *sms.Configuration
	// contains filtered or unexported fields
}

SMSClient for working with the SMS API

func NewSMSClient

func NewSMSClient(Auth Auth) *SMSClient

NewSMSClient Creates a new SMS Client, supplying an Auth to work with

func (*SMSClient) Send

func (client *SMSClient) Send(from string, to string, text string, opts SMSOpts) (Sms, SmsErrorResponse, error)

Send an SMS. Give some text to send and the number to send to - there are some restrictions on what you can send from, to be safe try using a Vonage number associated with your account

type SMSOpts

type SMSOpts struct {
	StatusReportReq bool
	Callback        string
	Type            string
	ClientRef       string
}

SMSOpts holds all the optional values that can be set when sending an SMS, check the https://developer.nexmo.com/api/sms API reference for more information

type Sms

type Sms struct {
	// The amount of messages in the request
	MessageCount string
	Messages     []sms.Message
}

type SmsError

type SmsError struct {
	Status    string `json:"status"`
	ErrorText string `json:"error-text"`
}

type SmsErrorResponse

type SmsErrorResponse struct {
	MessageCount string
	Messages     []SmsError
}

type TransferCallOpts

type TransferCallOpts struct {
	Uuid      string
	Ncco      ncco.Ncco
	AnswerUrl []string
}

TransferCallOpts: Options for transferring a call

type TransferDestinationNcco

type TransferDestinationNcco struct {
	Type string    `json:"type"`
	Ncco ncco.Ncco `json:"ncco"`
}

type TransferDestinationUrl

type TransferDestinationUrl struct {
	Type string   `json:"type"`
	Url  []string `json:"url"`
}

type TransferWithNccoOpts

type TransferWithNccoOpts struct {
	Action      string                  `json:"action"`
	Destination TransferDestinationNcco `json:"destination"`
}

type TransferWithUrlOpts

type TransferWithUrlOpts struct {
	Action      string                 `json:"action"`
	Destination TransferDestinationUrl `json:"destination"`
}

type UpdateApplicationOpts

type UpdateApplicationOpts struct {
	Keys         ApplicationKeys
	Capabilities ApplicationCapabilities
}

UpdateApplicationOpts holds the optional values for a UpdateApplication operation

type UpdateApplicationRequestOpts

type UpdateApplicationRequestOpts struct {
	Name         string                  `json:"name,omitempty"`
	Keys         *ApplicationKeys        `json:"keys,omitempty"`
	Capabilities ApplicationCapabilities `json:"capabilities,omitempty"`
}

UpdateApplicationRequestOpts the data structure to send to the API calling code, used inside UpdateApplication rather than as an incoming argument

type VerifyCheckResponse

type VerifyCheckResponse struct {
	RequestId                  string
	EventId                    string
	Status                     string
	Price                      string
	Currency                   string
	EstimatedPriceMessagesSent string
}

type VerifyClient

type VerifyClient struct {
	Config *verify.Configuration
	// contains filtered or unexported fields
}

VerifyClient for working with the Verify API

func NewVerifyClient

func NewVerifyClient(Auth Auth) *VerifyClient

NewVerifyClient Creates a new Verify Client, supplying an Auth to work with

func (*VerifyClient) Cancel

func (client *VerifyClient) Cancel(requestID string) (VerifyControlResponse, VerifyErrorResponse, error)

Cancel an in-progress request (check API docs for when this is possible)

func (*VerifyClient) Check

func (client *VerifyClient) Check(requestID string, code string) (VerifyCheckResponse, VerifyErrorResponse, error)

Check the user-supplied code for this request ID

func (*VerifyClient) Psd2

func (client *VerifyClient) Psd2(number string, payee string, amount float64, opts VerifyPsd2Opts) (VerifyRequestResponse, VerifyErrorResponse, error)

Psd2 requests a user confirm a payment with amount and payee

func (*VerifyClient) Request

func (client *VerifyClient) Request(number string, brand string, opts VerifyOpts) (VerifyRequestResponse, VerifyErrorResponse, error)

Request a number is verified for ownership

func (*VerifyClient) Search

func (client *VerifyClient) Search(requestID string) (VerifySearchResponse, VerifyErrorResponse, error)

Search for an earlier request by id

func (*VerifyClient) TriggerNextEvent

func (client *VerifyClient) TriggerNextEvent(requestID string) (VerifyControlResponse, VerifyErrorResponse, error)

TriggerNextEvent moves on to the next event in the workflow

type VerifyControlResponse

type VerifyControlResponse struct {
	Status  string
	Command string
}

type VerifyErrorResponse

type VerifyErrorResponse struct {
	RequestId string `json:"request_id"`
	Status    string `json:"status"`
	ErrorText string `json:"error_text,omitempty"`
}

type VerifyOpts

type VerifyOpts struct {
	Country       string
	SenderID      string
	CodeLength    int32
	Lg            string
	PinExpiry     int32
	NextEventWait int32
	WorkflowID    int32
}

VerifyOpts holds all the optional arguments for the verify request function

type VerifyPsd2Opts

type VerifyPsd2Opts struct {
	Country       string
	CodeLength    int32
	Lg            string
	PinExpiry     int32
	NextEventWait int32
	WorkflowID    int32
}

VerifyPsd2Opts holds all the optional arguments for the verify psd2 function

type VerifyRequestResponse

type VerifyRequestResponse struct {
	// The unique ID of the Verify request. You need this `request_id` for the Verify check.
	RequestId string
	Status    string
}

type VerifySearchResponse

type VerifySearchResponse struct {
	RequestId                  string
	AccountId                  string
	Status                     string
	Number                     string
	Price                      string
	Currency                   string
	SenderId                   string
	DateSubmitted              string
	DateFinalized              string
	FirstEventDate             string
	LastEventDate              string
	Checks                     []verify.SearchResponseChecks
	Events                     []verify.SearchResponseEvents
	EstimatedPriceMessagesSent string
}

type VoiceClient

type VoiceClient struct {
	Config *voice.Configuration
	JWT    string
}

VoiceClient for working with the Voice API

func NewVoiceClient

func NewVoiceClient(Auth Auth) *VoiceClient

NewVoiceClient Creates a new Voice Client, supplying an Auth to work with

func (*VoiceClient) CreateCall

CreateCall Makes a phone call given the from/to details and an NCCO or an Answer URL

func (*VoiceClient) Earmuff

func (client *VoiceClient) Earmuff(uuid string) (ModifyCallResponse, VoiceErrorResponse, error)

Earmuff wraps the Modify Call API endpoint

func (*VoiceClient) GetCall

func (client *VoiceClient) GetCall(uuid string) (voice.GetCallResponse, VoiceErrorResponse, error)

GetCall for the details of a specific call

func (*VoiceClient) GetCalls

List your calls

func (*VoiceClient) Hangup

Hangup wraps the Modify Call API endpoint

func (*VoiceClient) Mute

Mute wraps the Modify Call API endpoint

func (*VoiceClient) PlayAudioStream

func (client *VoiceClient) PlayAudioStream(uuid string, streamUrl string, opts PlayAudioOpts) (voice.StartStreamResponse, VoiceErrorResponse, error)

PlayAudioStream starts an audio file from a URL playing in a call

func (*VoiceClient) PlayDtmf

func (client *VoiceClient) PlayDtmf(uuid string, dtmf string) (voice.DtmfResponse, VoiceErrorResponse, error)

PlayDTMF starts playing a string of DTMF digits into the call

func (*VoiceClient) PlayTts

func (client *VoiceClient) PlayTts(uuid string, text string, opts PlayTtsOpts) (voice.StartTalkResponse, VoiceErrorResponse, error)

PlayTts starts playing TTS into the call

func (*VoiceClient) StopAudioStream

func (client *VoiceClient) StopAudioStream(uuid string) (voice.StopStreamResponse, VoiceErrorResponse, error)

StopAudioStream stops the currently-playing audio stream

func (*VoiceClient) StopTts

StopTts stops the current TTS from playing

func (*VoiceClient) TransferCall

TransferCall wraps the Modify Call API endpoint

func (*VoiceClient) Unearmuff

func (client *VoiceClient) Unearmuff(uuid string) (ModifyCallResponse, VoiceErrorResponse, error)

Unearmuff wraps the Modify Call API endpoint

func (*VoiceClient) Unmute

Unmute wraps the Modify Call API endpoint

type VoiceErrorGeneralResponse

type VoiceErrorGeneralResponse struct {
	Type  string `json:"type,omitempty"`
	Title string `json:"error_title,omitempty"`
}

VoiceErrorGeneralResponse covers some common error types that come from the webserver/gateway rather than the API itself

type VoiceErrorInvalidParamsResponse

type VoiceErrorInvalidParamsResponse struct {
	Type              int                 `json:"type,omitempty"`
	Title             string              `json:"title,omitempty"`
	Detail            string              `json:"detail,omitempty"`
	Instance          string              `json:"instance,omitempty"`
	InvalidParameters []map[string]string `json:"invalid_parameters,omitempty"`
}

VoiceErrorInvalidParamsResponse can come with a 400 response if it is caused by some invalid_parameters

type VoiceErrorResponse

type VoiceErrorResponse struct {
	Error interface{}
}

VoiceErrorResponse is a container for error types since we can get more than one type of error back and they have incompatible data types

Directories

Path Synopsis
examples
cli/vongo/cmd
Package cmd is an example app Package cmd is an example app Package cmd is an example app Package cmd is an example app
Package cmd is an example app Package cmd is an example app Package cmd is an example app Package cmd is an example app
internal
sms

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL