profile-pane 2.0.0-shadowDom-5e9cd6d2 → 2.0.0-shadowDom-6f51c34b

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 (39) hide show
  1. package/lib/CVCardElement.js +105 -113
  2. package/lib/CVPresenter.js +92 -79
  3. package/lib/ChatWithMeElement.js +149 -149
  4. package/lib/FriendListElement.js +59 -58
  5. package/lib/FriendsPresenter.js +60 -55
  6. package/lib/ProfileCardElement.js +88 -86
  7. package/lib/ProfileViewElement.js +77 -74
  8. package/lib/QRCodeCardElement.js +104 -102
  9. package/lib/SocialCardElement.js +67 -67
  10. package/lib/SocialPresenter.js +78 -69
  11. package/lib/StuffCardElement.js +66 -65
  12. package/lib/StuffPresenter.js +48 -27
  13. package/lib/addMeToYourFriends.js +89 -95
  14. package/lib/buttonsHelper.js +37 -31
  15. package/lib/editProfilePane/editProfile.view.js +123 -116
  16. package/lib/editProfilePane/profile.dom.js +32 -28
  17. package/lib/index.js +38 -34
  18. package/lib/presenter.js +57 -52
  19. package/lib/texts.js +19 -12
  20. package/package.json +8 -7
  21. package/lib/CVCardElement.js.map +0 -1
  22. package/lib/CVPresenter.js.map +0 -1
  23. package/lib/ChatWithMeElement.js.map +0 -1
  24. package/lib/FriendListElement.js.map +0 -1
  25. package/lib/FriendsPresenter.js.map +0 -1
  26. package/lib/ProfileCardElement.js.map +0 -1
  27. package/lib/ProfileViewElement.js.map +0 -1
  28. package/lib/QRCodeCardElement.js.map +0 -1
  29. package/lib/SocialCardElement.js.map +0 -1
  30. package/lib/SocialPresenter.js.map +0 -1
  31. package/lib/StuffCardElement.js.map +0 -1
  32. package/lib/StuffPresenter.js.map +0 -1
  33. package/lib/addMeToYourFriends.js.map +0 -1
  34. package/lib/buttonsHelper.js.map +0 -1
  35. package/lib/editProfilePane/editProfile.view.js.map +0 -1
  36. package/lib/editProfilePane/profile.dom.js.map +0 -1
  37. package/lib/index.js.map +0 -1
  38. package/lib/presenter.js.map +0 -1
  39. package/lib/texts.js.map +0 -1
@@ -1,73 +1,80 @@
1
- import cvCardCss from './styles/CVCard.css';
2
- import { html, render } from 'lit-html';
3
- import globalCssText from './styles/global.css';
1
+ "use strict";
2
+
3
+ var _CVCard = _interopRequireDefault(require("./styles/CVCard.css"));
4
+ var _litHtml = require("lit-html");
5
+ var _global = _interopRequireDefault(require("./styles/global.css"));
6
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
4
7
  class CVCardElement extends HTMLElement {
5
- constructor() {
6
- super();
7
- this.shadow = this.attachShadow({ mode: 'open' });
8
- }
9
- async connectedCallback() {
10
- let globalSheet = null;
11
- let cardSheet = null;
12
- let canUseSheets = typeof CSSStyleSheet !== 'undefined' && typeof globalCssText === 'string' && typeof cvCardCss === 'string';
13
- try {
14
- if (canUseSheets) {
15
- globalSheet = new CSSStyleSheet();
16
- globalSheet.replaceSync(globalCssText);
17
- if (!CVCardElement.sheet) {
18
- CVCardElement.sheet = new CSSStyleSheet();
19
- CVCardElement.sheet.replaceSync(cvCardCss);
20
- }
21
- cardSheet = CVCardElement.sheet;
22
- }
23
- }
24
- catch (e) {
25
- globalSheet = null;
26
- cardSheet = null;
27
- }
28
- if ('adoptedStyleSheets' in Document.prototype && globalSheet && cardSheet) {
29
- this.shadow.adoptedStyleSheets = [globalSheet, cardSheet];
8
+ static sheet = null;
9
+ constructor() {
10
+ super();
11
+ this.shadow = this.attachShadow({
12
+ mode: 'open'
13
+ });
14
+ }
15
+ async connectedCallback() {
16
+ let globalSheet = null;
17
+ let cardSheet = null;
18
+ let canUseSheets = typeof CSSStyleSheet !== 'undefined' && typeof _global.default === 'string' && typeof _CVCard.default === 'string';
19
+ try {
20
+ if (canUseSheets) {
21
+ globalSheet = new CSSStyleSheet();
22
+ globalSheet.replaceSync(_global.default);
23
+ if (!CVCardElement.sheet) {
24
+ CVCardElement.sheet = new CSSStyleSheet();
25
+ CVCardElement.sheet.replaceSync(_CVCard.default);
30
26
  }
31
- else {
32
- // Fallback for browsers or test environments without adoptedStyleSheets or CSSStyleSheet
33
- if (typeof globalCssText === 'string') {
34
- const styleGlobal = document.createElement('style');
35
- styleGlobal.textContent = globalCssText;
36
- this.shadow.appendChild(styleGlobal);
37
- }
38
- if (typeof cvCardCss === 'string') {
39
- const styleCard = document.createElement('style');
40
- styleCard.textContent = cvCardCss;
41
- this.shadow.appendChild(styleCard);
42
- }
43
- }
44
- this.render();
27
+ cardSheet = CVCardElement.sheet;
28
+ }
29
+ } catch (e) {
30
+ globalSheet = null;
31
+ cardSheet = null;
45
32
  }
46
- render() {
47
- // .cardFrame wrapper already present from previous patch
48
- // Assume cvData is passed as a property
49
- const cvData = this.cvData;
50
- if (!cvData)
51
- return;
52
- const { rolesByType, skills, languages } = cvData;
53
- const futureRolesArr = rolesByType['FutureRole'] || [];
54
- const currentRolesArr = rolesByType['CurrentRole'] || [];
55
- const pastRolesArr = rolesByType['PastRole'] || [];
56
- const skillsArr = skills || [];
57
- const languagesArr = languages || [];
58
- const hasFutureRole = Array.isArray(futureRolesArr) && futureRolesArr.length > 0;
59
- const hasCurrentRole = Array.isArray(currentRolesArr) && currentRolesArr.length > 0;
60
- const hasPastRole = Array.isArray(pastRolesArr) && pastRolesArr.length > 0;
61
- const hasSkills = Array.isArray(skillsArr) && skillsArr.length > 0;
62
- const hasLanguages = Array.isArray(languagesArr) && languagesArr.length > 0;
63
- if (!(hasFutureRole || hasCurrentRole || hasPastRole || hasSkills || hasLanguages)) {
64
- render(html ``, this.shadow);
65
- return;
66
- }
67
- render(html `
33
+ if ('adoptedStyleSheets' in Document.prototype && globalSheet && cardSheet) {
34
+ this.shadow.adoptedStyleSheets = [globalSheet, cardSheet];
35
+ } else {
36
+ // Fallback for browsers or test environments without adoptedStyleSheets or CSSStyleSheet
37
+ if (typeof _global.default === 'string') {
38
+ const styleGlobal = document.createElement('style');
39
+ styleGlobal.textContent = _global.default;
40
+ this.shadow.appendChild(styleGlobal);
41
+ }
42
+ if (typeof _CVCard.default === 'string') {
43
+ const styleCard = document.createElement('style');
44
+ styleCard.textContent = _CVCard.default;
45
+ this.shadow.appendChild(styleCard);
46
+ }
47
+ }
48
+ this.render();
49
+ }
50
+ render() {
51
+ // .cardFrame wrapper already present from previous patch
52
+ // Assume cvData is passed as a property
53
+ const cvData = this.cvData;
54
+ if (!cvData) return;
55
+ const {
56
+ rolesByType,
57
+ skills,
58
+ languages
59
+ } = cvData;
60
+ const futureRolesArr = rolesByType['FutureRole'] || [];
61
+ const currentRolesArr = rolesByType['CurrentRole'] || [];
62
+ const pastRolesArr = rolesByType['PastRole'] || [];
63
+ const skillsArr = skills || [];
64
+ const languagesArr = languages || [];
65
+ const hasFutureRole = Array.isArray(futureRolesArr) && futureRolesArr.length > 0;
66
+ const hasCurrentRole = Array.isArray(currentRolesArr) && currentRolesArr.length > 0;
67
+ const hasPastRole = Array.isArray(pastRolesArr) && pastRolesArr.length > 0;
68
+ const hasSkills = Array.isArray(skillsArr) && skillsArr.length > 0;
69
+ const hasLanguages = Array.isArray(languagesArr) && languagesArr.length > 0;
70
+ if (!(hasFutureRole || hasCurrentRole || hasPastRole || hasSkills || hasLanguages)) {
71
+ (0, _litHtml.render)((0, _litHtml.html)``, this.shadow);
72
+ return;
73
+ }
74
+ (0, _litHtml.render)((0, _litHtml.html)`
68
75
  <div class="cardFrame">
69
76
  <article class="cvCard" aria-label="Professional Experience" data-testid="curriculum-vitae">
70
- ${hasFutureRole ? html `
77
+ ${hasFutureRole ? (0, _litHtml.html)`
71
78
  <section class="cvSection" aria-labelledby="cv-future-heading">
72
79
  <h3 id="cv-future-heading">Future Roles</h3>
73
80
  <ul role="list" aria-label="Upcoming professional roles">
@@ -75,7 +82,7 @@ class CVCardElement extends HTMLElement {
75
82
  </ul>
76
83
  </section>
77
84
  ` : ''}
78
- ${hasCurrentRole ? html `
85
+ ${hasCurrentRole ? (0, _litHtml.html)`
79
86
  <section class="cvSection" aria-labelledby="cv-current-heading">
80
87
  <h3 id="cv-current-heading">Current Roles</h3>
81
88
  <ul role="list" aria-label="Current professional positions">
@@ -83,7 +90,7 @@ class CVCardElement extends HTMLElement {
83
90
  </ul>
84
91
  </section>
85
92
  ` : ''}
86
- ${hasPastRole ? html `
93
+ ${hasPastRole ? (0, _litHtml.html)`
87
94
  <section class="cvSection" aria-labelledby="cv-past-heading">
88
95
  <h3 id="cv-past-heading">Past Roles</h3>
89
96
  <ul role="list" aria-label="Previous work experience">
@@ -91,7 +98,7 @@ class CVCardElement extends HTMLElement {
91
98
  </ul>
92
99
  </section>
93
100
  ` : ''}
94
- ${hasSkills ? html `
101
+ ${hasSkills ? (0, _litHtml.html)`
95
102
  <section class="cvSection" aria-labelledby="cv-skills-heading">
96
103
  <h3 id="cv-skills-heading">Skills</h3>
97
104
  <ul role="list" aria-label="Professional skills and competencies">
@@ -99,7 +106,7 @@ class CVCardElement extends HTMLElement {
99
106
  </ul>
100
107
  </section>
101
108
  ` : ''}
102
- ${hasLanguages ? html `
109
+ ${hasLanguages ? (0, _litHtml.html)`
103
110
  <section class="cvSection" aria-labelledby="cv-languages-heading">
104
111
  <h3 id="cv-languages-heading">Languages</h3>
105
112
  <ul role="list" aria-label="Known languages">
@@ -110,67 +117,52 @@ class CVCardElement extends HTMLElement {
110
117
  </article>
111
118
  </div>
112
119
  `, this.shadow);
113
- }
114
- get cvData() {
115
- return this._cvData;
116
- }
117
- set cvData(val) {
118
- this._cvData = val;
119
- this.render();
120
- }
120
+ }
121
+ get cvData() {
122
+ return this._cvData;
123
+ }
124
+ set cvData(val) {
125
+ this._cvData = val;
126
+ this.render();
127
+ }
121
128
  }
122
- CVCardElement.sheet = null;
123
129
  customElements.define('cv-card', CVCardElement);
124
130
  function renderRoles(roles, asList = false) {
125
- if (!roles || !roles.length || !roles[0])
126
- return html ``;
127
- return html `${renderRole(roles[0], asList)}${roles.length > 1 ? renderRoles(roles.slice(1), asList) : html ``}`;
131
+ if (!roles || !roles.length || !roles[0]) return (0, _litHtml.html)``;
132
+ return (0, _litHtml.html)`${renderRole(roles[0], asList)}${roles.length > 1 ? renderRoles(roles.slice(1), asList) : (0, _litHtml.html)``}`;
128
133
  }
129
134
  function renderRole(role, asList = false) {
130
- if (!role)
131
- return html ``;
132
- return asList
133
- ? html `
135
+ if (!role) return (0, _litHtml.html)``;
136
+ return asList ? (0, _litHtml.html)`
134
137
  <li class="cvRole" role="listitem">
135
138
  <strong class="cvOrg" aria-label="Organization">${role.orgName}</strong>
136
139
  <span aria-label="Role title">${strToUpperCase(role.roleText)}</span>
137
140
  <time aria-label="Employment period">${role.dates}</time>
138
- </li>`
139
- : html ``;
141
+ </li>` : (0, _litHtml.html)``;
140
142
  }
141
143
  function renderSkill(skill, asList = false) {
142
- if (!skill)
143
- return html ``;
144
- return asList
145
- ? html `<li class="cvSkill">${strToUpperCase(skill)}</li>`
146
- : html ``;
144
+ if (!skill) return (0, _litHtml.html)``;
145
+ return asList ? (0, _litHtml.html)`<li class="cvSkill">${strToUpperCase(skill)}</li>` : (0, _litHtml.html)``;
147
146
  }
148
147
  function renderSkills(skills, asList = false) {
149
- if (!skills || !skills.length || !skills[0])
150
- return html ``;
151
- return html `${renderSkill(skills[0], asList)}${skills.length > 1 ? renderSkills(skills.slice(1), asList) : html ``}`;
148
+ if (!skills || !skills.length || !skills[0]) return (0, _litHtml.html)``;
149
+ return (0, _litHtml.html)`${renderSkill(skills[0], asList)}${skills.length > 1 ? renderSkills(skills.slice(1), asList) : (0, _litHtml.html)``}`;
152
150
  }
153
151
  function renderLan(language, asList = false) {
154
- if (!language)
155
- return html ``;
156
- return asList
157
- ? html `<li class="cvLanguage">${language}</li>`
158
- : html ``;
152
+ if (!language) return (0, _litHtml.html)``;
153
+ return asList ? (0, _litHtml.html)`<li class="cvLanguage">${language}</li>` : (0, _litHtml.html)``;
159
154
  }
160
155
  function renderLanguages(languages, asList = false) {
161
- if (!languages || !languages.length || !languages[0])
162
- return html ``;
163
- return html `${renderLan(languages[0], asList)}${languages.length > 1 ? renderLanguages(languages.slice(1), asList) : html ``}`;
156
+ if (!languages || !languages.length || !languages[0]) return (0, _litHtml.html)``;
157
+ return (0, _litHtml.html)`${renderLan(languages[0], asList)}${languages.length > 1 ? renderLanguages(languages.slice(1), asList) : (0, _litHtml.html)``}`;
164
158
  }
165
159
  function strToUpperCase(str) {
166
- if (str && str[0] > '') {
167
- const strCase = str.split(' ');
168
- for (let i = 0; i < strCase.length; i++) {
169
- strCase[i] = strCase[i].charAt(0).toUpperCase() +
170
- strCase[i].substring(1);
171
- }
172
- return strCase.join(' ');
160
+ if (str && str[0] > '') {
161
+ const strCase = str.split(' ');
162
+ for (let i = 0; i < strCase.length; i++) {
163
+ strCase[i] = strCase[i].charAt(0).toUpperCase() + strCase[i].substring(1);
173
164
  }
174
- return '';
175
- }
176
- //# sourceMappingURL=CVCardElement.js.map
165
+ return strCase.join(' ');
166
+ }
167
+ return '';
168
+ }
@@ -1,87 +1,100 @@
1
- import { Namespace } from 'rdflib';
2
- import { ns, utils } from 'solid-ui';
3
- const ORG = Namespace('http://www.w3.org/ns/org#');
4
- export const typesOfRole = ['PastRole', 'CurrentRole', 'FutureRole'];
5
- export function skillAsText(store, sk) {
6
- if (sk.termType === 'Literal')
7
- return sk.value; // Not normal but allow this
8
- const publicId = store.anyJS(sk, ns.solid('publicId'));
9
- if (publicId) {
10
- const name = store.anyJS(publicId, ns.schema('name'));
11
- if (name)
12
- return name; // @@ check language and get name in diff language if necessary
13
- }
14
- const manual = store.anyJS(sk, ns.vcard('role'));
15
- if (manual && manual[0] > '')
16
- return manual;
17
- return '¿¿¿ skill ???';
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.datesAsText = datesAsText;
7
+ exports.languageAsText = languageAsText;
8
+ exports.presentCV = presentCV;
9
+ exports.skillAsText = skillAsText;
10
+ exports.typesOfRole = void 0;
11
+ var _rdflib = require("rdflib");
12
+ var _solidUi = require("solid-ui");
13
+ const ORG = (0, _rdflib.Namespace)('http://www.w3.org/ns/org#');
14
+ const typesOfRole = exports.typesOfRole = ['PastRole', 'CurrentRole', 'FutureRole'];
15
+ function skillAsText(store, sk) {
16
+ if (sk.termType === 'Literal') return sk.value; // Not normal but allow this
17
+ const publicId = store.anyJS(sk, _solidUi.ns.solid('publicId'));
18
+ if (publicId) {
19
+ const name = store.anyJS(publicId, _solidUi.ns.schema('name'));
20
+ if (name) return name; // @@ check language and get name in diff language if necessary
21
+ }
22
+ const manual = store.anyJS(sk, _solidUi.ns.vcard('role'));
23
+ if (manual && manual[0] > '') return manual;
24
+ return '¿¿¿ skill ???';
18
25
  }
19
- export function languageAsText(store, lan) {
20
- if (lan.termType === 'Literal')
21
- return lan.value; // Not normal but allow this
22
- const publicId = store.anyJS(lan, ns.solid('publicId'));
23
- if (publicId)
24
- return utils.label(publicId, true); // @@ check language and get name in diff language if necessary
25
- return '-';
26
+ function languageAsText(store, lan) {
27
+ if (lan.termType === 'Literal') return lan.value; // Not normal but allow this
28
+ const publicId = store.anyJS(lan, _solidUi.ns.solid('publicId'));
29
+ if (publicId) return _solidUi.utils.label(publicId, true); // @@ check language and get name in diff language if necessary
30
+ return '-';
26
31
  }
27
- export function datesAsText(startDate, endDate) {
28
- return startDate ? '(' + startDate.value.slice(0, 10) + ' to ' +
29
- (endDate ? endDate.value.slice(0, 10) : '') + ')'
30
- : '';
32
+ function datesAsText(startDate, endDate) {
33
+ return startDate ? '(' + startDate.value.slice(0, 10) + ' to ' + (endDate ? endDate.value.slice(0, 10) : '') + ')' : '';
31
34
  }
32
35
  function getRolesByType(store, subject) {
33
- const memberships = store.each(null, ORG('member'), subject, null);
34
- const rolesByType = { PastRole: [], CurrentRole: [], FutureRole: [] };
35
- for (const membership of memberships) {
36
- let orgHomePage, orgNameGiven, publicIdName, roleName, publicId;
37
- // Things should have start dates but we will be very lenient in this view
38
- const startDate = store.any(membership, ns.schema('startDate'));
39
- const endDate = store.any(membership, ns.schema('endDate'));
40
- const dates = datesAsText(startDate, endDate);
41
- const organization = store.any(membership, ORG('organization'));
42
- if (organization) {
43
- orgNameGiven = store.anyJS(organization, ns.schema('name'));
44
- orgHomePage = store.any(organization, ns.schema('uri'));
45
- publicId = store.any(organization, ns.solid('publicId'));
46
- }
47
- if (publicId) {
48
- publicIdName = store.anyJS(publicId, ns.schema('name'));
49
- }
50
- const orgName = publicIdName || orgNameGiven;
51
- const escoRole = store.any(membership, ORG('role'));
52
- if (escoRole) {
53
- roleName = store.anyJS(escoRole, ns.schema('name'));
54
- }
55
- const roleText0 = store.anyJS(membership, ns.vcard('role'));
56
- const roleText = (roleText0 && roleName) ? roleName + ' - ' + roleText0
57
- : roleText0 || roleName;
58
- const item = {
59
- startDate: startDate, endDate, orgName, roleText, dates, orgHomePage
60
- };
61
- for (const t of typesOfRole) {
62
- if (store.holds(membership, ns.rdf('type'), ns.solid(t))) {
63
- rolesByType[t].push(item);
64
- }
65
- }
36
+ const memberships = store.each(null, ORG('member'), subject, null);
37
+ const rolesByType = {
38
+ PastRole: [],
39
+ CurrentRole: [],
40
+ FutureRole: []
41
+ };
42
+ for (const membership of memberships) {
43
+ let orgHomePage, orgNameGiven, publicIdName, roleName, publicId;
44
+ // Things should have start dates but we will be very lenient in this view
45
+ const startDate = store.any(membership, _solidUi.ns.schema('startDate'));
46
+ const endDate = store.any(membership, _solidUi.ns.schema('endDate'));
47
+ const dates = datesAsText(startDate, endDate);
48
+ const organization = store.any(membership, ORG('organization'));
49
+ if (organization) {
50
+ orgNameGiven = store.anyJS(organization, _solidUi.ns.schema('name'));
51
+ orgHomePage = store.any(organization, _solidUi.ns.schema('uri'));
52
+ publicId = store.any(organization, _solidUi.ns.solid('publicId'));
66
53
  }
67
- return rolesByType;
68
- }
69
- export function presentCV(subject, store) {
70
- const rolesByType = getRolesByType(store, subject);
71
- // Most recent thing most relevant -> sort by end date
54
+ if (publicId) {
55
+ publicIdName = store.anyJS(publicId, _solidUi.ns.schema('name'));
56
+ }
57
+ const orgName = publicIdName || orgNameGiven;
58
+ const escoRole = store.any(membership, ORG('role'));
59
+ if (escoRole) {
60
+ roleName = store.anyJS(escoRole, _solidUi.ns.schema('name'));
61
+ }
62
+ const roleText0 = store.anyJS(membership, _solidUi.ns.vcard('role'));
63
+ const roleText = roleText0 && roleName ? roleName + ' - ' + roleText0 : roleText0 || roleName;
64
+ const item = {
65
+ startDate: startDate,
66
+ endDate,
67
+ orgName,
68
+ roleText,
69
+ dates,
70
+ orgHomePage
71
+ };
72
72
  for (const t of typesOfRole) {
73
- rolesByType[t].sort(function (x, y) {
74
- if (x.endDate && y.endDate) {
75
- return x.endDate > y.endDate ? -1 : 1;
76
- }
77
- return x.startDate > y.startDate ? -1 : 1;
78
- });
73
+ if (store.holds(membership, _solidUi.ns.rdf('type'), _solidUi.ns.solid(t))) {
74
+ rolesByType[t].push(item);
75
+ }
79
76
  }
80
- const skills = store.each(subject, ns.schema('skills')).map(sk => skillAsText(store, sk));
81
- const languagesInStore = store.anyJS(subject, ns.schema('knowsLanguage'));
82
- let languages = [];
83
- if (languagesInStore)
84
- languages = languagesInStore.map(lan => languageAsText(store, lan));
85
- return { rolesByType, skills, languages };
77
+ }
78
+ return rolesByType;
86
79
  }
87
- //# sourceMappingURL=CVPresenter.js.map
80
+ function presentCV(subject, store) {
81
+ const rolesByType = getRolesByType(store, subject);
82
+ // Most recent thing most relevant -> sort by end date
83
+ for (const t of typesOfRole) {
84
+ rolesByType[t].sort(function (x, y) {
85
+ if (x.endDate && y.endDate) {
86
+ return x.endDate > y.endDate ? -1 : 1;
87
+ }
88
+ return x.startDate > y.startDate ? -1 : 1;
89
+ });
90
+ }
91
+ const skills = store.each(subject, _solidUi.ns.schema('skills')).map(sk => skillAsText(store, sk));
92
+ const languagesInStore = store.anyJS(subject, _solidUi.ns.schema('knowsLanguage'));
93
+ let languages = [];
94
+ if (languagesInStore) languages = languagesInStore.map(lan => languageAsText(store, lan));
95
+ return {
96
+ rolesByType,
97
+ skills,
98
+ languages
99
+ };
100
+ }