cozy-sharing 5.0.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/SharingBanner/components/getHomeLinkHref.js +5 -0
  3. package/dist/SharingBanner/components/getHomeLinkHref.spec.js +9 -0
  4. package/dist/SharingBanner/hooks/useSharingInfos.js +3 -2
  5. package/dist/SharingBanner/index.js +7 -2
  6. package/dist/components/EditLinkPermissionDialog.js +72 -0
  7. package/dist/components/EditLinkPermissionDialog.spec.js +48 -0
  8. package/dist/components/Recipient/AvatarPlusX.js +41 -0
  9. package/dist/components/Recipient/Identity.js +43 -0
  10. package/dist/components/Recipient/LinkRecipient.js +72 -0
  11. package/dist/components/Recipient/LinkRecipientPermissions.js +159 -0
  12. package/dist/components/Recipient/OwnerIdentity.js +44 -0
  13. package/dist/components/Recipient/Recipient.js +72 -0
  14. package/dist/components/Recipient/Recipient.spec.js +178 -0
  15. package/dist/components/Recipient/RecipientAvatar.js +33 -0
  16. package/dist/components/Recipient/RecipientConfirm.js +63 -0
  17. package/dist/components/Recipient/RecipientPermissions.js +126 -0
  18. package/dist/components/Recipient/RecipientPlusX.js +45 -0
  19. package/dist/components/Recipient/RecipientStatus.js +64 -0
  20. package/dist/components/Recipient/RecipientWithoutStatus.js +45 -0
  21. package/dist/components/Recipient/RecipientsAvatars.js +100 -0
  22. package/dist/components/Recipient/RecipientsAvatars.spec.js +145 -0
  23. package/dist/components/Recipient/recipient.styl +82 -0
  24. package/dist/components/ShareButtonWithRecipients.js +8 -0
  25. package/dist/helpers/documentType.js +6 -0
  26. package/dist/helpers/link.js +5 -0
  27. package/dist/helpers/permissions.js +8 -0
  28. package/dist/helpers/recipients.js +24 -0
  29. package/dist/helpers/synchronousJobQueue.js +67 -0
  30. package/dist/helpers/synchronousJobQueue.spec.js +97 -0
  31. package/dist/queries/queries.js +72 -0
  32. package/package.json +2 -3
  33. package/src/SharingBanner/hooks/useSharingInfos.jsx +3 -3
  34. package/src/SharingBanner/index.jsx +7 -3
  35. package/LICENSE +0 -21
@@ -0,0 +1,145 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
4
+ var _excluded = ["recipients", "link", "isOwner", "onClick"];
5
+ import React from 'react';
6
+ import { createMockClient } from 'cozy-client';
7
+ import { render } from '@testing-library/react';
8
+ import RecipientsAvatars, { MAX_DISPLAYED_RECIPIENTS, excludeMeAsOwnerFromRecipients } from './RecipientsAvatars';
9
+ import AppLike from '../../../test/AppLike';
10
+ var mockRecipients = new Array(MAX_DISPLAYED_RECIPIENTS - 1).fill({
11
+ status: 'owner',
12
+ public_name: 'cozy'
13
+ }, 0, 1).fill({
14
+ status: 'pending',
15
+ name: 'Mitch Young'
16
+ }, 1);
17
+ var mockMoreRecipientsThanMaxDisplayed = [].concat(_toConsumableArray(mockRecipients), [{
18
+ status: 'mail-not-send',
19
+ name: 'Lyn Webster'
20
+ }, {
21
+ status: 'ready',
22
+ name: 'Richelle Young'
23
+ }, {
24
+ status: 'ready',
25
+ name: 'John Connor'
26
+ }]);
27
+ describe('RecipientsAvatars', function () {
28
+ var client = createMockClient({});
29
+
30
+ var setup = function setup(_ref) {
31
+ var _ref$recipients = _ref.recipients,
32
+ recipients = _ref$recipients === void 0 ? mockRecipients : _ref$recipients,
33
+ _ref$link = _ref.link,
34
+ link = _ref$link === void 0 ? false : _ref$link,
35
+ _ref$isOwner = _ref.isOwner,
36
+ isOwner = _ref$isOwner === void 0 ? true : _ref$isOwner,
37
+ _ref$onClick = _ref.onClick,
38
+ onClick = _ref$onClick === void 0 ? function () {
39
+ return jest.fn();
40
+ } : _ref$onClick,
41
+ rest = _objectWithoutProperties(_ref, _excluded);
42
+
43
+ return render( /*#__PURE__*/React.createElement(AppLike, {
44
+ client: client
45
+ }, /*#__PURE__*/React.createElement(RecipientsAvatars, _extends({
46
+ recipients: recipients,
47
+ onClick: onClick,
48
+ isOwner: isOwner,
49
+ link: link
50
+ }, rest))));
51
+ };
52
+
53
+ it('should render link icon if a link is generated', function () {
54
+ var _setup = setup({
55
+ link: true
56
+ }),
57
+ getByTestId = _setup.getByTestId;
58
+
59
+ expect(getByTestId('recipientsAvatars-link')).toBeTruthy();
60
+ });
61
+ it('should not render link icon if a link is not generated', function () {
62
+ var _setup2 = setup({}),
63
+ queryByTestId = _setup2.queryByTestId;
64
+
65
+ expect(queryByTestId('recipientsAvatars-link')).toBeNull();
66
+ });
67
+ it('should hide me as owner by default', function () {
68
+ var _setup3 = setup({}),
69
+ queryByTestId = _setup3.queryByTestId;
70
+
71
+ expect(queryByTestId('recipientsAvatars-avatar-owner')).toBeNull();
72
+ });
73
+ it('should show me as owner if required', function () {
74
+ var _setup4 = setup({
75
+ showMeAsOwner: true
76
+ }),
77
+ getByTestId = _setup4.getByTestId;
78
+
79
+ expect(getByTestId('recipientsAvatars-avatar-owner')).toBeTruthy();
80
+ });
81
+ it('should show a +X icon with the correct number if there is more avatars than expected', function () {
82
+ var _setup5 = setup({
83
+ recipients: mockMoreRecipientsThanMaxDisplayed,
84
+ showMeAsOwner: true
85
+ }),
86
+ getByTestId = _setup5.getByTestId,
87
+ getByText = _setup5.getByText;
88
+
89
+ var delta = mockMoreRecipientsThanMaxDisplayed.length - MAX_DISPLAYED_RECIPIENTS;
90
+ expect(getByTestId('recipientsAvatars-plusX')).toBeTruthy();
91
+ expect(getByText("+".concat(delta))).toBeTruthy();
92
+ });
93
+ it('should show both +X and link icon if necessary', function () {
94
+ var _setup6 = setup({
95
+ recipients: mockMoreRecipientsThanMaxDisplayed,
96
+ showMeAsOwner: true,
97
+ link: true
98
+ }),
99
+ getByTestId = _setup6.getByTestId;
100
+
101
+ expect(getByTestId('recipientsAvatars-plusX')).toBeTruthy();
102
+ expect(getByTestId('recipientsAvatars-link')).toBeTruthy();
103
+ });
104
+ });
105
+ describe('excludeMeAsOwnerFromRecipients', function () {
106
+ test('excludeMeAsOwnerFromRecipients behavior', function () {
107
+ var recipients = [{
108
+ status: 'owner',
109
+ instance: 'http://foo1.cozy.bar'
110
+ }, {
111
+ status: 'pending',
112
+ instance: 'http://foo2.cozy.bar'
113
+ }, {
114
+ status: 'pending',
115
+ instance: 'http://foo3.cozy.bar'
116
+ }];
117
+ var client = {
118
+ options: {
119
+ uri: 'http://foo2.cozy.bar'
120
+ }
121
+ };
122
+ expect(excludeMeAsOwnerFromRecipients({
123
+ recipients: recipients,
124
+ isOwner: true,
125
+ client: client
126
+ })).toEqual([{
127
+ status: 'pending',
128
+ instance: 'http://foo2.cozy.bar'
129
+ }, {
130
+ status: 'pending',
131
+ instance: 'http://foo3.cozy.bar'
132
+ }]);
133
+ expect(excludeMeAsOwnerFromRecipients({
134
+ recipients: recipients,
135
+ isOwner: false,
136
+ client: client
137
+ })).toEqual([{
138
+ status: 'owner',
139
+ instance: 'http://foo1.cozy.bar'
140
+ }, {
141
+ status: 'pending',
142
+ instance: 'http://foo3.cozy.bar'
143
+ }]);
144
+ });
145
+ });
@@ -0,0 +1,82 @@
1
+ @require 'components/button.styl'
2
+ @require 'settings/breakpoints.styl'
3
+ @require 'settings/palette.styl'
4
+
5
+ :root
6
+ --genericRecipientBackground: var(--slateGrey)
7
+ --genericRecipientColor: var(--white)
8
+
9
+ .recipient
10
+ display flex
11
+ flex-direction row
12
+ align-items center
13
+
14
+ +small-screen()
15
+ align-items flex-start
16
+
17
+ .recipients-list-light
18
+ .recipient
19
+ margin 1rem 0
20
+
21
+ & + .recipient
22
+ margin-top 1rem
23
+
24
+ .recipient-idents
25
+ flex 1 1 auto
26
+ overflow hidden
27
+ text-overflow ellipsis
28
+
29
+ .recipient-status-icon
30
+ margin-right: .25rem
31
+
32
+ .recipient-user
33
+ .recipient-details
34
+ text-overflow ellipsis
35
+ overflow hidden
36
+ white-space nowrap
37
+ line-height 1.3
38
+
39
+ .recipient-user
40
+ font-size 1rem
41
+ font-weight bold
42
+
43
+ .recipient-details
44
+ font-size .875rem
45
+ color var(--coolGrey)
46
+
47
+ .avatar
48
+ display flex
49
+ flex-direction row
50
+ align-items center
51
+
52
+ .recipient-user
53
+ font-size 1.125rem
54
+
55
+ .link-recipient-icon-circle
56
+ border 1px solid var(--borderMainColor)
57
+ background-color unset
58
+ color unset
59
+
60
+ .recipients-avatars
61
+ display inline-flex
62
+ flex-direction row-reverse
63
+ margin-right 0.5rem
64
+
65
+ &.--interactive
66
+ cursor pointer
67
+
68
+ &--link,
69
+ &--plusX,
70
+ &--avatar
71
+ border-width 2px
72
+ border-style solid
73
+ border-color var(--white)
74
+
75
+ &--link
76
+ background-color var(--genericRecipientBackground)
77
+ svg
78
+ fill: var(--genericRecipientColor)
79
+
80
+ &--plusX,
81
+ &--avatar
82
+ margin-right -0.6rem
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import ShareButton from '../ShareButton';
3
+
4
+ var ShareButtonWithRecipients = function ShareButtonWithRecipients(props) {
5
+ return /*#__PURE__*/React.createElement(ShareButton, props);
6
+ };
7
+
8
+ export default ShareButtonWithRecipients;
@@ -0,0 +1,6 @@
1
+ export var DOCUMENT_TYPE = {
2
+ ALBUMS: 'Albums',
3
+ FILES: 'Files',
4
+ NOTES: 'Notes',
5
+ ORGANIZATIONS: 'Organizations'
6
+ };
@@ -0,0 +1,5 @@
1
+ import { DOCUMENT_TYPE } from './documentType';
2
+ export var isOnlyReadOnlyLinkAllowed = function isOnlyReadOnlyLinkAllowed(_ref) {
3
+ var documentType = _ref.documentType;
4
+ return documentType === DOCUMENT_TYPE.ALBUMS;
5
+ };
@@ -0,0 +1,8 @@
1
+ import get from 'lodash/get';
2
+ import { models } from 'cozy-client';
3
+ export var checkIsReadOnlyPermissions = function checkIsReadOnlyPermissions(permissions) {
4
+ var permissionCategories = get(permissions, '[0].attributes.permissions', {});
5
+ return Object.values(permissionCategories).filter(function (permissionCategory) {
6
+ return models.permission.isReadOnly(permissionCategory);
7
+ }).length > 0;
8
+ };
@@ -0,0 +1,24 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+
3
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
4
+
5
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
6
+
7
+ export var filterAndReworkRecipients = function filterAndReworkRecipients(recipients, previousRecipients) {
8
+ return recipients.filter(function (recipient) {
9
+ return recipient.status !== 'owner';
10
+ }).map(function (recipient) {
11
+ var recipientHasChanged = previousRecipients && !previousRecipients.find(function (previousRecipient) {
12
+ return previousRecipient.name === recipient.name && previousRecipient.email === recipient.email;
13
+ });
14
+
15
+ if (recipientHasChanged) {
16
+ return _objectSpread(_objectSpread({}, recipient), {}, {
17
+ hasBeenJustAdded: true
18
+ });
19
+ }
20
+
21
+ return recipient;
22
+ });
23
+ };
24
+ export var FADE_IN_DURATION = 600;
@@ -0,0 +1,67 @@
1
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
3
+ import _createClass from "@babel/runtime/helpers/createClass";
4
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
5
+ export var SynchronousJobQueue = /*#__PURE__*/function () {
6
+ function SynchronousJobQueue() {
7
+ _classCallCheck(this, SynchronousJobQueue);
8
+
9
+ this.isRunning = false;
10
+ this.queue = [];
11
+ }
12
+
13
+ _createClass(SynchronousJobQueue, [{
14
+ key: "push",
15
+ value: function push(job) {
16
+ this.queue.push(job);
17
+
18
+ if (!this.isRunning) {
19
+ this.run();
20
+ }
21
+ }
22
+ }, {
23
+ key: "run",
24
+ value: function () {
25
+ var _run = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
26
+ var job;
27
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
28
+ while (1) {
29
+ switch (_context.prev = _context.next) {
30
+ case 0:
31
+ this.isRunning = true;
32
+
33
+ case 1:
34
+ if (!(this.queue.length > 0)) {
35
+ _context.next = 7;
36
+ break;
37
+ }
38
+
39
+ job = this.queue.shift();
40
+ _context.next = 5;
41
+ return job.function(job.arguments);
42
+
43
+ case 5:
44
+ _context.next = 1;
45
+ break;
46
+
47
+ case 7:
48
+ this.isRunning = false;
49
+
50
+ case 8:
51
+ case "end":
52
+ return _context.stop();
53
+ }
54
+ }
55
+ }, _callee, this);
56
+ }));
57
+
58
+ function run() {
59
+ return _run.apply(this, arguments);
60
+ }
61
+
62
+ return run;
63
+ }()
64
+ }]);
65
+
66
+ return SynchronousJobQueue;
67
+ }();
@@ -0,0 +1,97 @@
1
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
3
+ import { SynchronousJobQueue } from './synchronousJobQueue';
4
+
5
+ var flushPromises = function flushPromises() {
6
+ return new Promise(process.nextTick);
7
+ };
8
+
9
+ var callback = jest.fn();
10
+ var resolveAfter100Ms = jest.fn().mockImplementation(function () {
11
+ callback('100Ms start');
12
+ return new Promise(function (resolve) {
13
+ setTimeout(function () {
14
+ callback('100Ms end');
15
+ resolve();
16
+ }, 100);
17
+ });
18
+ });
19
+ var resolveAfter500Ms = jest.fn().mockImplementation(function () {
20
+ callback('500Ms start');
21
+ return new Promise(function (resolve) {
22
+ setTimeout(function () {
23
+ callback('500Ms end');
24
+ resolve();
25
+ }, 500);
26
+ });
27
+ });
28
+ describe('SynchronousJobQueue', function () {
29
+ beforeEach(function () {
30
+ jest.useFakeTimers();
31
+ });
32
+ afterEach(function () {
33
+ jest.useRealTimers();
34
+ jest.clearAllMocks();
35
+ });
36
+ it('should execute job synchronously with SynchronousJobQueue', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
37
+ var synchronousJobQueue, expectedCallbackOrder;
38
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
39
+ while (1) {
40
+ switch (_context.prev = _context.next) {
41
+ case 0:
42
+ synchronousJobQueue = new SynchronousJobQueue();
43
+ synchronousJobQueue.push({
44
+ function: resolveAfter500Ms
45
+ });
46
+ synchronousJobQueue.push({
47
+ function: resolveAfter100Ms
48
+ });
49
+ jest.runAllTimers();
50
+ _context.next = 6;
51
+ return flushPromises();
52
+
53
+ case 6:
54
+ jest.runAllTimers();
55
+ _context.next = 9;
56
+ return flushPromises();
57
+
58
+ case 9:
59
+ expectedCallbackOrder = [['500Ms start'], ['500Ms end'], ['100Ms start'], ['100Ms end']];
60
+ expect(callback.mock.calls).toEqual(expectedCallbackOrder);
61
+
62
+ case 11:
63
+ case "end":
64
+ return _context.stop();
65
+ }
66
+ }
67
+ }, _callee);
68
+ })));
69
+ it('should execute job asynchronously without SynchronousJobQueue', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
70
+ var expectedCallbackOrder;
71
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
72
+ while (1) {
73
+ switch (_context2.prev = _context2.next) {
74
+ case 0:
75
+ resolveAfter500Ms();
76
+ resolveAfter100Ms();
77
+ jest.runAllTimers();
78
+ _context2.next = 5;
79
+ return flushPromises();
80
+
81
+ case 5:
82
+ jest.runAllTimers();
83
+ _context2.next = 8;
84
+ return flushPromises();
85
+
86
+ case 8:
87
+ expectedCallbackOrder = [['500Ms start'], ['100Ms start'], ['100Ms end'], ['500Ms end']];
88
+ expect(callback.mock.calls).toEqual(expectedCallbackOrder);
89
+
90
+ case 10:
91
+ case "end":
92
+ return _context2.stop();
93
+ }
94
+ }
95
+ }, _callee2);
96
+ })));
97
+ });
@@ -0,0 +1,72 @@
1
+ import { Q, fetchPolicies } from 'cozy-client';
2
+ import { Contact, Group } from '../models';
3
+ var DEFAULT_CACHE_TIMEOUT_QUERIES = 9 * 60 * 1000;
4
+ var defaultFetchPolicy = fetchPolicies.olderThan(DEFAULT_CACHE_TIMEOUT_QUERIES);
5
+ export var fetchApps = function fetchApps() {
6
+ return {
7
+ definition: Q('io.cozy.apps'),
8
+ options: {
9
+ as: 'io.cozy.apps',
10
+ fetchPolicy: defaultFetchPolicy
11
+ }
12
+ };
13
+ };
14
+ export var buildSharingsByIdQuery = function buildSharingsByIdQuery(sharingId) {
15
+ return {
16
+ definition: Q('io.cozy.sharings').getById(sharingId),
17
+ options: {
18
+ as: "io.cozy.sharings/".concat(sharingId),
19
+ fetchPolicy: defaultFetchPolicy
20
+ }
21
+ };
22
+ };
23
+ export var buildContactsQuery = function buildContactsQuery() {
24
+ return {
25
+ definition: Q(Contact.doctype).where({
26
+ _id: {
27
+ $gt: null
28
+ }
29
+ }).partialIndex({
30
+ trashed: {
31
+ $or: [{
32
+ $eq: false
33
+ }, {
34
+ $exists: false
35
+ }]
36
+ },
37
+ $or: [{
38
+ cozy: {
39
+ $not: {
40
+ $size: 0
41
+ }
42
+ }
43
+ }, {
44
+ email: {
45
+ $not: {
46
+ $size: 0
47
+ }
48
+ }
49
+ }]
50
+ }).indexFields(['_id']).limitBy(1000),
51
+ options: {
52
+ as: 'io.cozy.contacts'
53
+ }
54
+ };
55
+ };
56
+ export var buildGroupsQuery = function buildGroupsQuery() {
57
+ return {
58
+ definition: Q(Group.doctype),
59
+ options: {
60
+ as: 'io.cozy.contacts.groups'
61
+ }
62
+ };
63
+ };
64
+ export var buildInstanceSettingsQuery = function buildInstanceSettingsQuery() {
65
+ return {
66
+ definition: Q('io.cozy.settings').getById('instance'),
67
+ options: {
68
+ as: 'io.cozy.settings/instance',
69
+ singleDocData: true
70
+ }
71
+ };
72
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-sharing",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "description": "Provides sharing login for React applications.",
5
5
  "main": "dist/index.js",
6
6
  "author": "Cozy",
@@ -60,6 +60,5 @@
60
60
  },
61
61
  "sideEffects": [
62
62
  "*.css"
63
- ],
64
- "gitHead": "621683a1fd3dfe4abc029f5c3238c164acb5aec0"
63
+ ]
65
64
  }
@@ -12,7 +12,7 @@ const getSharingId = permission => {
12
12
  return sharingId
13
13
  }
14
14
 
15
- export const useSharingInfos = () => {
15
+ export const useSharingInfos = (previewPath = '/preview') => {
16
16
  const client = useClient()
17
17
 
18
18
  const [discoveryLink, setDiscoveryLink] = useState()
@@ -52,12 +52,12 @@ export const useSharingInfos = () => {
52
52
  }
53
53
  }
54
54
 
55
- if (window.location.pathname === '/preview') {
55
+ if (window.location.pathname === previewPath) {
56
56
  loadSharingDiscoveryLink()
57
57
  } else {
58
58
  setLoading(false)
59
59
  }
60
- }, [client])
60
+ }, [client, previewPath])
61
61
 
62
62
  return {
63
63
  sharing,
@@ -1,13 +1,17 @@
1
1
  import React from 'react'
2
+ import PropTypes from 'prop-types'
2
3
 
3
4
  import withLocales from '../withLocales'
4
5
  import { useSharingInfos } from './hooks/useSharingInfos'
5
6
  import { SharingBanner } from './components/SharingBanner'
6
7
 
7
- const Plugin = () => {
8
- const sharingInfos = useSharingInfos()
9
-
8
+ const Plugin = ({ previewPath }) => {
9
+ const sharingInfos = useSharingInfos(previewPath)
10
10
  return <SharingBanner sharingInfos={sharingInfos} />
11
11
  }
12
12
 
13
+ Plugin.propTypes = {
14
+ previewPath: PropTypes.string
15
+ }
16
+
13
17
  export const SharingBannerPlugin = withLocales(Plugin)
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2016 Cozy.io
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.