@balena/jellyfish-client-sdk v0.3.0-grahammcculloch-sales-thread-ownership-34437fac279b8d7135fc68929d26342ad2b5deac
Jellyfish Client SDK
The sdk is a client side library to interact with the Jellyfish infrastructure through its public interfaces (i.e. HTTP). Its meant to provide high level useful functionality to the web UI and any other clients.
Usage
Below is an example how to use IceCave DB:
import {
getSdk
} from '@balena/jellyfish-client-sdk'
// Create a new SDK instance, providing the API url and prefix
const sdk = getSdk({
apiUrl: 'https://api.ly.fish',
apiPrefix: 'api/v2/',
})
// Authorise the SDK using an auth token
sdk.setAuthToken('MY-AUTH-TOKEN')
// Retrieve a card by id
const card = await sdk.card.get('b1d31eca-6182-4c34-8a74-f89f1c3e4e26')Documentation
SDK instance
Kind: global namespace
- JellyfishSDK : object
- new JellyfishSDK(API_URL, API_PREFIX, [authToken])
- .auth : object
- .whoami() ⇒ Promise
- .signup(user) ⇒ Promise
- .loginWithToken(token) ⇒ String
- .login(options) ⇒ Object
- .refreshToken() ⇒ String
- .logout()
- .card : object
- .get(idOrSlug, options) ⇒ Promise
- .get(idOrSlug, options) ⇒ Promise
- .CardSdk#getWithLinks(idOrSlug, verbs, options) ⇒ Promise
- .getAllByType(cardType) ⇒ Promise
- .create(card) ⇒ Promise
- .update(id, type, patch) ⇒ Promise
- .remove(id, type) ⇒ Promise
- .remove(fromCard, toCard, verb) ⇒ Promise
- .unlink(fromCard, toCard, verb) ⇒ Promise
- .markAsRead(userSlug, card) ⇒ Promise
- .markAsUnread(userSlug, card) ⇒ Promise
- .event : object
- .create(event) ⇒ Promise
- .getConfig() ⇒ Promise
- .getFile(cardId, name) ⇒ Promise
- .setApiUrl(apiUrl)
- .getApiUrl() ⇒ String | undefined
- .setApiBase(apiUrl, apiPrefix)
- .setAauthToken(token)
- .getAauthToken() ⇒ String | undefined
- .clearAuthToken()
- .cancelAllRequests([reason])
- .cancelAllstreams()
- .get(endpoint, [options]) ⇒ Promise
- .post(endpoint, body, [options]) ⇒ Promise
- .query(schema, [options]) ⇒ Promise
- .view(viewSlug, params, [options]) ⇒ Promise
- .getByType(type) ⇒ Promise
- .getById(id) ⇒ Promise
- .getBySlug(slug) ⇒ Promise
- .action(body) ⇒ Promise
- .stream(query) ⇒ Promise
new JellyfishSDK(API_URL, API_PREFIX, authToken)
| Param | Type | Description |
|---|---|---|
| API_URL | String | The URL of the Jellyfish API |
| API_PREFIX | String | The prefix used for the API endpoint, e.g. v1, v2 |
| authToken | String | An optional authentication token to instantiate the SDK with |
JellyfishSDK.auth : object
Kind: static namespace of JellyfishSDK
- .auth : object
- .whoami() ⇒ Promise
- .signup(user) ⇒ Promise
- .loginWithToken(token) ⇒ String
- .login(options) ⇒ Object
- .refreshToken() ⇒ String
- .logout()
auth.whoami() ⇒ Promise
Gets the user card of the currently authorised user using their auth token
Kind: static method of auth
Summary: Get the currently authenticated user
Access: public
Fulfil: Object|null - A single user card, or null if one wasn't found
Example
sdk.auth.whoami()
.then((user) => {
console.log(user)
})auth.signup(user) ⇒ Promise
Create a new user account and return the newly created user's id
Kind: static method of auth
Summary: Create a new user account
Access: public
Fulfil: Object - The newly created user
| Param | Type | Description |
|---|---|---|
| user | Object | The user object |
| user.username | String | The username |
| user.email | String | The users email address |
| user.password | String | The users password |
Example
sdk.auth.signup({
username: 'johndoe',
email: 'johndoe@example.com',
password: 'password123'
})
.then((id) => {
console.log(id)
})auth.loginWithToken(token) ⇒ String
Authenticate the SDK using a token. The token is checked for
validity and then saved using jellyFishSdk.setAuthToken to be used for
later requests. Once logged in, there is no need to set the token again
Kind: static method of auth
Summary: Authenticate the SDK using a token
Returns: String - The new authentication token
Access: public
| Param | Type | Description |
|---|---|---|
| token | String | Authentication token |
Example
sdk.auth.loginWithToken('8b465c9a-b4cb-44c1-9df9-632649d7c4c3')
.then(() => {
console.log('Authenticated')
})auth.login(options) ⇒ Object
Authenticate the SDK using a username and password. If the
username and password are valid, a user session card will be returned.
The id of the user session id (which is used to authenticate requests) is
then saved using jellyFishSdk.setAuthToken to be used for later requests.
Once logged in, there is no need to set the token again
Kind: static method of auth
Summary: Authenticate the SDK using a username and password
Returns: Object - The generated user session
Access: public
| Param | Type | Description |
|---|---|---|
| options | Object | login data |
| options.username | String | Username |
| options.password | String | Password |
Example
sdk.auth.login({
username: 'johndoe',
password: 'password123'
})
.then((session) => {
console.log('Authenticated', session)
})auth.refreshToken() ⇒ String
Refreshes the auth token used by the SDK
Kind: static method of auth
Summary: Generate a new session token
Returns: String - The generated session token
Access: public
Example
sdk.auth.refreshToken
.then((token) => {
console.log('New token', token)
})auth.logout()
Logout, removing the current authToken and closing all streams and network requests
Kind: static method of auth
Summary: Logout
Access: public
Example
sdk.auth.logout()JellyfishSDK.card : object
Kind: static namespace of JellyfishSDK
- .card : object
- .get(idOrSlug, options) ⇒ Promise
- .get(idOrSlug, options) ⇒ Promise
- .CardSdk#getWithLinks(idOrSlug, verbs, options) ⇒ Promise
- .getAllByType(cardType) ⇒ Promise
- .create(card) ⇒ Promise
- .update(id, type, patch) ⇒ Promise
- .remove(id, type) ⇒ Promise
- .remove(fromCard, toCard, verb) ⇒ Promise
- .unlink(fromCard, toCard, verb) ⇒ Promise
- .markAsRead(userSlug, card) ⇒ Promise
- .markAsUnread(userSlug, card) ⇒ Promise
card.get(idOrSlug, options) ⇒ Promise
Get a card using an id or a slug
Kind: static method of card
Summary: Get a card
Access: public
Fulfil: Object|null - A single card, or null if one wasn't found
| Param | Type | Description |
|---|---|---|
| idOrSlug | String | The id or slug of the card to retrieve |
| options | Object | Extra query options to use |
| options.schema | Object | Additional schema that will be merged into the query |
Example
sdk.card.get('user-johndoe')
.then((card) => {
console.log(card)
})
sdk.card.get('8b465c9a-b4cb-44c1-9df9-632649d7c4c3')
.then((card) => {
console.log(card)
})card.get(idOrSlug, options) ⇒ Promise
Get a card and its timeline using an id or a slug
Kind: static method of card
Summary: Get a card and its attached timeline
Access: public
Fulfil: Object|null - A single card, or null if one wasn't found
| Param | Type | Description |
|---|---|---|
| idOrSlug | String | The id or slug of the card to retrieve |
| options | Object | Additional options |
Example
sdk.card.getWithTimeline('user-johndoe')
.then((card) => {
console.log(card)
})
sdk.card.getWithTimeline('8b465c9a-b4cb-44c1-9df9-632649d7c4c3')
.then((card) => {
console.log(card)
})card.CardSdk#getWithLinks(idOrSlug, verbs, options) ⇒ Promise
Get a card and its timeline using an id or a slug
Kind: static method of card
Summary: Get a card and cards linked to it using a verb
Access: public
Fulfil: Object|null - A single card, or null if one wasn't found
| Param | Type | Description |
|---|---|---|
| idOrSlug | String | The id or slug of the card to retrieve |
| verbs | Array.<String> | Verbs to load |
| options | Object | Additional options |
Example
sdk.card.getWithLinks('user-johndoe', [ 'has attached element' ])
.then((card) => {
console.log(card)
})
sdk.card.getWithTimeline('8b465c9a-b4cb-44c1-9df9-632649d7c4c3', [ 'has attached element' ])
.then((card) => {
console.log(card)
})card.getAllByType(cardType) ⇒ Promise
Get all cards that have the provided 'type' attribute
Kind: static method of card
Summary: Get all cards of a given type
Access: public
Fulfil: Object[] - All cards of the given type
| Param | Type | Description |
|---|---|---|
| cardType | String | The type of card to retrieve |
Example
sdk.card.getAllByType('view')
.then((cards) => {
console.log(cards)
})card.create(card) ⇒ Promise
Send an action request to create a new card
Kind: static method of card
Summary: Create a new card
Access: public
Fulfil: Card - The newly created card
| Param | Type | Description |
|---|---|---|
| card | Object | The card that should be created, must include a 'type' attribute. |
Example
sdk.card.create({
type: 'thread',
data: {
description: 'lorem ipsum dolor sit amet'
}
})
.then((id) => {
console.log(id)
})card.update(id, type, patch) ⇒ Promise
Send an action request to update a card
Kind: static method of card
Summary: Update a card
Access: public
Fulfil: Object - An action response object
| Param | Type | Description |
|---|---|---|
| id | String | The id of the card that should be updated |
| type | String | The card type |
| patch | Array.<Object> | A JSON Patch set of operationss |
Example
sdk.card.update('8b465c9a-b4cb-44c1-9df9-632649d7c4c3', 'support-thread', [
{
op: 'add',
path: '/data/description',
value: 'foo bar baz'
}
]).then((response) => {
console.log(response)
})card.remove(id, type) ⇒ Promise
Send an action request to remove a card
Kind: static method of card
Summary: Remove a card
Access: public
| Param | Type | Description |
|---|---|---|
| id | String | The id of the card that should be removed |
| type | String | The type of the card that should be removed |
Example
sdk.card.remove('8b465c9a-b4cb-44c1-9df9-632649d7c4c3', 'card')card.remove(fromCard, toCard, verb) ⇒ Promise
Link two cards together
Kind: static method of card
Summary: Create a link card
Access: public
| Param | Type | Description |
|---|---|---|
| fromCard | String | The id of the card that should be linked from |
| toCard | String | The id of the card that should be linked to |
| verb | String | The name of the relationship |
card.unlink(fromCard, toCard, verb) ⇒ Promise
Un-link two cards
Kind: static method of card
Summary: Remove a link card
Access: public
| Param | Type | Description |
|---|---|---|
| fromCard | String | The id of the card that the link is from |
| toCard | String | The id of the card that the link is to |
| verb | String | The name of the relationship |
card.markAsRead(userSlug, card) ⇒ Promise
Link two cards together
Kind: static method of card
Summary: Mark a card as read
Access: public
| Param | Type | Description |
|---|---|---|
| userSlug | String | The slug of the user who has read the card |
| card | String | The card that should be marked as read |
card.markAsUnread(userSlug, card) ⇒ Promise
Link two cards together
Kind: static method of card
Summary: Mark a card as unread
Access: public
| Param | Type | Description |
|---|---|---|
| userSlug | String | The slug of the user who has read the card |
| card | String | The card that should be marked as unread |
JellyfishSDK.event : object
Kind: static namespace of JellyfishSDK
event.create(event) ⇒ Promise
Send an action request to create a new event
Kind: static method of event
Summary: Create a new event
Access: public
Fulfil: Event - The newly created event
| Param | Type | Description |
|---|---|---|
| event | Object | The card that should be created, must include a 'type' attribute. |
Example
sdk.event.create({
card: '1234-5687',
data: {
description: 'lorem ipsum dolor sit amet'
}
})
.then((id) => {
console.log(id)
})JellyfishSDK.getConfig() ⇒ Promise
Retrieve configuration data from the API
Kind: static method of JellyfishSDK
Summary: Load config object from the API
Access: public
Fulfil: Object - Config object
Example
sdk.getConfig()
.then((config) => {
console.log(config);
});JellyfishSDK.getFile(cardId, name) ⇒ Promise
Retrieve a file from the API
Kind: static method of JellyfishSDK
Summary: Retrieve a file form the API
Access: public
Fulfil: File - The requested file
| Param | Type | Description |
|---|---|---|
| cardId | String | The id of the card this file is attached to |
| name | String | The name of the file |
JellyfishSDK.setApiUrl(apiUrl)
Set the url of the Jellyfish API instance the SDK should communicate with
Kind: static method of JellyfishSDK
Summary: Set the API url
Access: public
| Param | Type | Description |
|---|---|---|
| apiUrl | String | The API url |
Example
sdk.setApiUrl('http://localhost:8000')JellyfishSDK.getApiUrl() ⇒ String | undefined
Get the url of the Jellyfish API instance the SDK should communicate with
Kind: static method of JellyfishSDK
Summary: Get the API url
Returns: String | undefined - The API url
Access: public
Example
const url = sdk.getApiUrl()
console.log(url) //--> 'http://localhost:8000'JellyfishSDK.setApiBase(apiUrl, apiPrefix)
Set the url and path prefix to use when sending requests to the API
Kind: static method of JellyfishSDK
Summary: Set the base API url
Access: public
| Param | Type | Description |
|---|---|---|
| apiUrl | String | The API url |
| apiPrefix | String | The API path prefix |
Example
sdk.setApiBase('http://localhost:8000', 'api/v2')JellyfishSDK.setAauthToken(token)
Set authentication token used when sending request to the API
Kind: static method of JellyfishSDK
Summary: Set the auth token
Access: public
| Param | Type | Description |
|---|---|---|
| token | String | The authentication token |
Example
sdk.setAuthToken('799de256-31bb-4399-b2d2-3c2a2483ddd8')JellyfishSDK.getAauthToken() ⇒ String | undefined
Get authentication token used when sending request to the API
Kind: static method of JellyfishSDK
Summary: Get the auth token
Returns: String | undefined - The authentication token if it has been set
Access: public
Example
const token = sdk.getAuthToken(
console.log(token) //--> '799de256-31bb-4399-b2d2-3c2a2483ddd8'JellyfishSDK.clearAuthToken()
Clear the authentication token used when sending request to the API
Kind: static method of JellyfishSDK
Summary: clear the auth token
Access: public
Example
sdk.clearAuthToken()JellyfishSDK.cancelAllRequests(reason)
Cancel all network requests that are currently in progress, optionally providing a reason for doing so.
Kind: static method of JellyfishSDK
Summary: Cancel all network requests
Access: public
| Param | Type | Default | Description |
|---|---|---|---|
| reason | String | 'Operation canceled by user' | The reason for cancelling the network requests |
Example
sdk.cancelAllRequests()JellyfishSDK.cancelAllstreams()
Close all open streams to the Jellyfish API
Kind: static method of JellyfishSDK
Summary: Cancel all streams
Access: public
Example
sdk.cancelAllStreams()JellyfishSDK.get(endpoint, options) ⇒ Promise
Send a get request to the Jellyfish API. Uses Axios under the hood.
Kind: static method of JellyfishSDK
Summary: Send a GET request to the API
Access: public
Fulfil: Object - Request response object
| Param | Type | Description |
|---|---|---|
| endpoint | String | The endpoint to send the POST request to |
| options | Object | Request configuration options. See https://github.com/axios/axios#request-config |
JellyfishSDK.post(endpoint, body, options) ⇒ Promise
Send a POST request to the Jellyfish API. Uses Axios under the hood. Requests are automatically authorized using a token if it has been set.
Kind: static method of JellyfishSDK
Summary: Send a POST request to the API
Access: public
Fulfil: Object - Request response object
| Param | Type | Description |
|---|---|---|
| endpoint | String | The endpoint to send the POST request to |
| body | Object | The body data to send |
| options | Object | Request configuration options. See https://github.com/axios/axios#request-config |
Example
sdk.post('action', { foo: 'bar'})
.then((data) => {
console.log(data);
});JellyfishSDK.query(schema, options) ⇒ Promise
Query the API for card data, using a JSON schema. Cards that match the JSON schema are returned
Kind: static method of JellyfishSDK
Summary: Send a query request to the API
Access: public
Fulfil: Object[] - An array of cards that match the schema
| Param | Type | Description |
|---|---|---|
| schema | Object | The JSON schema to query with |
| options | Object | Additional options |
| options.limit | Number | Limit the number of results |
| options.skip | Number | Skip a set amount of results |
Example
const schema = {
type: 'object',
properies: {
type: {
const: 'thread'
}
}
};
sdk.query(schema)
.then((cards) => {
console.log(cards);
});JellyfishSDK.view(viewSlug, params, options) ⇒ Promise
Query the API for card data, referencing a view template by
slug@version and providing its params and options. Internally, it uses
query, so any constraint specific to it is also applied
Kind: static method of JellyfishSDK
Summary: Send a view request to the API
Access: public
Fulfil: Object[] - An array of cards that match the schema specified by the view
| Param | Type | Description |
|---|---|---|
| viewSlug | String | the slug@version of the view to use |
| params | Object | the optional params used by the view template |
| options | Object | Additional options |
| options.limit | Number | Limit the number of results |
| options.skip | Number | Skip a set amount of results |
Example
const params = {
types: [ 'view', 'view@1.0.0' ]
}
sdk.view('view-all-by-type@1.0.0', params)
.then((cards) => {
console.log(cards);
});JellyfishSDK.getByType(type) ⇒ Promise
Kind: static method of JellyfishSDK
Summary: Get all cards by type
Access: public
Fulfil: Object[] - The resulting cards
| Param | Type | Description |
|---|---|---|
| type | String | The card type |
JellyfishSDK.getById(id) ⇒ Promise
Kind: static method of JellyfishSDK
Summary: Get a card by type and id
Access: public
Fulfil: Object - The resulting card
| Param | Type | Description |
|---|---|---|
| id | String | The card id |
JellyfishSDK.getBySlug(slug) ⇒ Promise
Kind: static method of JellyfishSDK
Summary: Get a card by type and slug
Access: public
Fulfil: Object - The resulting card
| Param | Type | Description |
|---|---|---|
| slug | String | The card slug |
JellyfishSDK.action(body) ⇒ Promise
Send an action to the API, the request will resolve once the action is complete
Kind: static method of JellyfishSDK
Summary: Send an action to the API
Access: public
Fulfil: ActionResponse - An action response object
| Param | Type | Description |
|---|---|---|
| body | Object | The action request |
| body.card | String | The slug or UUID of the target card |
| body.type | String | The type of the target card |
| body.action | String | The name of the action to run |
| body.arguments | * | The arguments to use when running the action |
| body.transient | * | The transient arguments to use when running the action |
Example
sdk.action({
card: 'thread',
action: 'action-create-card@1.0.0',
arguments: {
data: {
description: 'lorem ipsum dolor sit amet'
}
}
})
.then((response) => {
console.log(response);
});JellyfishSDK.stream(query) ⇒ Promise
Stream updates and insertions for cards that match a JSON schema
Kind: static method of JellyfishSDK
Summary: Stream cards from the API
Access: public
Fulfil: EventEmitter
| Param | Type | Description |
|---|---|---|
| query | Object | The JSON schema to query with |
Example
const schema = {
type: 'object',
properies: {
type: {
const: 'thread'
}
}
};
const stream = sdk.stream(schema)
stream.on('update', (data) => {
console.log(data);
})
stream.on('streamError', (error) => {
console.error(error);
})2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago