favesalon-embed 1.1.0 → 1.1.2

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 (54) hide show
  1. package/dist/favesalon-embed/activate-form.entry.js +2 -2
  2. package/dist/favesalon-embed/{app-globals-74127f4b.js → app-globals-0130ce1b.js} +1 -1
  3. package/dist/favesalon-embed/buy-giftcard-form.entry.js +2 -2
  4. package/dist/favesalon-embed/buy-giftcard-succeed.entry.js +1 -1
  5. package/dist/favesalon-embed/buy-giftcard-verification.entry.js +6 -2
  6. package/dist/favesalon-embed/change-password-form.entry.js +2 -2
  7. package/dist/favesalon-embed/chat-box.entry.js +2 -2
  8. package/dist/favesalon-embed/chat-button.entry.js +85 -14
  9. package/dist/favesalon-embed/chat-form.entry.js +25 -17
  10. package/dist/favesalon-embed/chat-messages.entry.js +2 -2
  11. package/dist/favesalon-embed/chat-rooms.entry.js +2 -2
  12. package/dist/favesalon-embed/credit-card-types.entry.js +1 -1
  13. package/dist/favesalon-embed/favesalon-embed.esm.js +4 -4
  14. package/dist/favesalon-embed/google-map.entry.js +1 -1
  15. package/dist/favesalon-embed/icon-checked.entry.js +1 -1
  16. package/dist/favesalon-embed/icon-date.entry.js +1 -1
  17. package/dist/favesalon-embed/icon-loading.entry.js +1 -1
  18. package/dist/favesalon-embed/icon-location-marker.entry.js +1 -1
  19. package/dist/favesalon-embed/icon-phone.entry.js +1 -1
  20. package/dist/favesalon-embed/{index-888e99e3.js → index-759c34ea.js} +1 -1
  21. package/dist/favesalon-embed/login-form.entry.js +2 -2
  22. package/dist/favesalon-embed/magensa-payment.entry.js +2 -2
  23. package/dist/favesalon-embed/notify-sounds.entry.js +17 -5
  24. package/dist/favesalon-embed/powered-by-favesalon.entry.js +1 -1
  25. package/dist/favesalon-embed/register-form.entry.js +2 -2
  26. package/dist/favesalon-embed/reset-password-form.entry.js +2 -2
  27. package/dist/favesalon-embed/salon-booking-modal.entry.js +1 -1
  28. package/dist/favesalon-embed/salon-booking.entry.js +1 -1
  29. package/dist/favesalon-embed/salon-gift-card-modal.entry.js +1 -1
  30. package/dist/favesalon-embed/salon-gift-card.entry.js +1 -1
  31. package/dist/favesalon-embed/salon-info.entry.js +2 -2
  32. package/dist/favesalon-embed/salon-latest-reviews.entry.js +2 -2
  33. package/dist/favesalon-embed/salon-latest-styles.entry.js +2 -2
  34. package/dist/favesalon-embed/salon-locations.entry.js +2 -2
  35. package/dist/favesalon-embed/salon-lookbook.entry.js +2 -2
  36. package/dist/favesalon-embed/salon-ranking.entry.js +1 -1
  37. package/dist/favesalon-embed/salon-reviews.entry.js +2 -2
  38. package/dist/favesalon-embed/salon-schedules.entry.js +2 -2
  39. package/dist/favesalon-embed/salon-services.entry.js +2 -2
  40. package/dist/favesalon-embed/salon-stylists.entry.js +2 -2
  41. package/dist/favesalon-embed/{services-48c99e41.js → services-b2dd15e7.js} +35 -1
  42. package/dist/favesalon-embed/style-detail.entry.js +2 -2
  43. package/dist/favesalon-embed/user-avatar.entry.js +1 -1
  44. package/dist/favesalon-embed/user-form.entry.js +1 -1
  45. package/dist/favesalon-embed/wizard-existing-user.entry.js +3 -6
  46. package/dist/favesalon-embed/wizard-new-user.entry.js +3 -6
  47. package/dist/types/components/chat-button/index.d.ts +4 -1
  48. package/dist/types/components/chat-button/notify-sounds.d.ts +3 -1
  49. package/dist/types/components/chat-form/index.d.ts +1 -0
  50. package/dist/types/components.d.ts +5 -1
  51. package/dist/types/services/services.d.ts +3 -0
  52. package/package.json +1 -1
  53. package/dist/favesalon-embed/app-globals-8f27cbc0.js +0 -7
  54. package/dist/favesalon-embed/index-761e92c1.js +0 -3371
@@ -1,5 +1,5 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
2
- import { H as HttpService, g as get_1 } from './services-48c99e41.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
+ import { H as HttpService, g as get_1 } from './services-b2dd15e7.js';
3
3
  import { C as Colors } from './colors-ea36347a.js';
4
4
  import './_commonjsHelpers-9bc404fc.js';
5
5
 
@@ -1,4 +1,4 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
2
  import { C as Colors } from './colors-ea36347a.js';
3
3
 
4
4
  const indexCss = ".salon-modal.salon-modal--booking:before{display:none}.salon-modal.salon-modal--booking .salon-modal--inner,.salon-modal.salon-modal--booking .salon-modal--content{max-width:none;width:100%;height:100%}.salon-modal.salon-modal--booking .salon-modal--close{background-color:#EFEFEF;width:40px;height:40px;right:16px;top:16px;-moz-border-radius:50px;-webkit-border-radius:50px;border-radius:50px}@media (min-width: 768px){.salon-modal.salon-modal--booking .salon-modal--close{right:20px;top:20px}}";
@@ -1,4 +1,4 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
2
  import { c as color, l as lib } from './index-ac52896a.js';
3
3
  import { C as Colors } from './colors-ea36347a.js';
4
4
  import './_commonjsHelpers-9bc404fc.js';
@@ -1,4 +1,4 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
2
  import { C as Colors } from './colors-ea36347a.js';
3
3
 
4
4
  const indexCss = ".salon-modal.salon-modal--gift-card:before{display:none}.salon-modal.salon-modal--gift-card .salon-modal--inner,.salon-modal.salon-modal--gift-card .salon-modal--content{max-width:none;width:100%;height:100%}.salon-modal.salon-modal--gift-card .salon-modal--close{background-color:#EFEFEF;width:40px;height:40px;right:16px;top:16px;-moz-border-radius:50px;-webkit-border-radius:50px;border-radius:50px}@media (min-width: 768px){.salon-modal.salon-modal--gift-card .salon-modal--close{right:20px;top:20px}}";
@@ -1,4 +1,4 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
2
  import { c as color, l as lib } from './index-ac52896a.js';
3
3
  import { C as Colors } from './colors-ea36347a.js';
4
4
  import './_commonjsHelpers-9bc404fc.js';
@@ -1,5 +1,5 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
2
- import { H as HttpService } from './services-48c99e41.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
+ import { H as HttpService } from './services-b2dd15e7.js';
3
3
  import './_commonjsHelpers-9bc404fc.js';
4
4
  import './colors-ea36347a.js';
5
5
 
@@ -1,5 +1,5 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
2
- import { H as HttpService, d as dayjs_min, h as shortDateYearFormat } from './services-48c99e41.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
+ import { H as HttpService, d as dayjs_min, h as shortDateYearFormat } from './services-b2dd15e7.js';
3
3
  import { C as Colors } from './colors-ea36347a.js';
4
4
  import { g as getRatingText } from './utils-359c37f7.js';
5
5
  import './_commonjsHelpers-9bc404fc.js';
@@ -1,6 +1,6 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
2
  import { C as Colors } from './colors-ea36347a.js';
3
- import { H as HttpService, k as isVideoMedia } from './services-48c99e41.js';
3
+ import { H as HttpService, k as isVideoMedia } from './services-b2dd15e7.js';
4
4
  import './_commonjsHelpers-9bc404fc.js';
5
5
 
6
6
  const indexCss = "salon-latest-styles .view--salon-styles--item{width:120px;height:120px}@media (min-width: 1024px){salon-latest-styles .view--salon-styles--item{width:200px;height:200px}}";
@@ -1,7 +1,7 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
2
  import { a as formatWebsiteUrl, b as formatFullAddress } from './utils-359c37f7.js';
3
3
  import { C as Colors } from './colors-ea36347a.js';
4
- import { H as HttpService } from './services-48c99e41.js';
4
+ import { H as HttpService } from './services-b2dd15e7.js';
5
5
  import './_commonjsHelpers-9bc404fc.js';
6
6
 
7
7
  const indexCss = "@media (min-width: 768px){salon-locations .salon-contact--links{overflow:hidden;margin-left:-32px}salon-locations .salon-contact--links-item{float:left;display:flex;flex-direction:row;align-items:center;font-size:16px;min-width:300px;padding-left:32px}salon-locations .salon-contact--links-item:nth-child(2n+1){clear:left}salon-locations .salon-contact--links-item+.salon-contact--links-item{margin-top:8px}}";
@@ -1,6 +1,6 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
2
  import { C as Colors } from './colors-ea36347a.js';
3
- import { H as HttpService } from './services-48c99e41.js';
3
+ import { H as HttpService } from './services-b2dd15e7.js';
4
4
  import './_commonjsHelpers-9bc404fc.js';
5
5
 
6
6
  const indexCss = "@media (max-width: 768px){salon-lookbook .view-header{display:block !important}salon-lookbook .salon-loobook--serch-result{margin-bottom:16px}salon-lookbook .salon-loobook--filter-wrapper>label,salon-lookbook .salon-loobook--sort-wrapper>label{display:none !important}}";
@@ -1,4 +1,4 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
2
  import { C as Colors } from './colors-ea36347a.js';
3
3
 
4
4
  const indexCss = "salon-ranking{display:block}";
@@ -1,5 +1,5 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
2
- import { H as HttpService, d as dayjs_min, h as shortDateYearFormat } from './services-48c99e41.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
+ import { H as HttpService, d as dayjs_min, h as shortDateYearFormat } from './services-b2dd15e7.js';
3
3
  import { C as Colors } from './colors-ea36347a.js';
4
4
  import './_commonjsHelpers-9bc404fc.js';
5
5
 
@@ -1,5 +1,5 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
2
- import { H as HttpService, B as BusinessHourStatus } from './services-48c99e41.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
+ import { H as HttpService, B as BusinessHourStatus } from './services-b2dd15e7.js';
3
3
  import { C as Colors } from './colors-ea36347a.js';
4
4
  import './_commonjsHelpers-9bc404fc.js';
5
5
 
@@ -1,5 +1,5 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
2
- import { H as HttpService, j as sortBy_1 } from './services-48c99e41.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
+ import { H as HttpService, j as sortBy_1 } from './services-b2dd15e7.js';
3
3
  import { C as Colors } from './colors-ea36347a.js';
4
4
  import './_commonjsHelpers-9bc404fc.js';
5
5
 
@@ -1,6 +1,6 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
2
  import { C as Colors } from './colors-ea36347a.js';
3
- import { H as HttpService } from './services-48c99e41.js';
3
+ import { H as HttpService } from './services-b2dd15e7.js';
4
4
  import './_commonjsHelpers-9bc404fc.js';
5
5
 
6
6
  const indexCss = ".view--salon-stylists{overflow:hidden;margin-left:-12px;margin-top:-12px}.view--salon-stylists .salon-stylist{float:left;padding-left:12px;padding-top:12px;width:50%}.view--salon-stylists .salon-stylist--avatar{height:180px}@media (min-width: 576px){.view--salon-stylists .salon-stylist{width:33.33%;max-width:240px}}@media (min-width: 768px){.view--salon-stylists{margin-left:-24px;margin-top:-24px}.view--salon-stylists .salon-stylist{padding-left:24px;padding-top:24px;width:264px;max-width:none}.view--salon-stylists .salon-stylist--avatar{height:240px}}";
@@ -23927,6 +23927,36 @@ class HttpService {
23927
23927
  })
23928
23928
  .catch(() => ({ total: 0, data: [] }));
23929
23929
  }
23930
+ fetchSalonOwnerOnlineStatus(userId, onDone) {
23931
+ if (this.firebaseDatabase) {
23932
+ try {
23933
+ const roomInchatRef = ref(this.firebaseDatabase, `presence/in_chat`);
23934
+ const roomQuery = query(roomInchatRef, orderByChild(userId), equalTo(true));
23935
+ onValue(roomQuery, (snapshot) => {
23936
+ const data = snapshot.val();
23937
+ onDone(!!data);
23938
+ });
23939
+ }
23940
+ catch (error) {
23941
+ onDone(false);
23942
+ }
23943
+ }
23944
+ onDone(false);
23945
+ }
23946
+ fetchChatroomUserInChat(roomId, userId) {
23947
+ const roomUsersRef = ref(this.firebaseDatabase);
23948
+ return get(child(roomUsersRef, `presence/in_chat/${roomId}`))
23949
+ .then((snapshot) => {
23950
+ if (snapshot.exists()) {
23951
+ const allUsersStatues = snapshot.val();
23952
+ return !!(allUsersStatues || {})[userId];
23953
+ }
23954
+ return false;
23955
+ })
23956
+ .catch(() => {
23957
+ return false;
23958
+ });
23959
+ }
23930
23960
  createChatRoom(receiverId, accessToken) {
23931
23961
  const url = `${apiV2Prefix}/chatroom/create/${receiverId}?access_token=${accessToken}`;
23932
23962
  return this.http.get(url)
@@ -23941,7 +23971,7 @@ class HttpService {
23941
23971
  return this.http.get(url)
23942
23972
  .then(response => {
23943
23973
  const blobs = get_1(response, 'data.data', []);
23944
- const chatRooms = blobs.map(createChatRoom);
23974
+ const chatRooms = blobs.filter(blob => blob.firebase_room_id && blob.from_user && blob.to_user).map(createChatRoom);
23945
23975
  // fetch next page's styles
23946
23976
  if (chatRooms.length >= 20) {
23947
23977
  return this.fetchRooms(accessToken, page + 1, allRooms.concat(chatRooms));
@@ -24027,6 +24057,10 @@ class HttpService {
24027
24057
  }
24028
24058
  return Promise.reject();
24029
24059
  }
24060
+ sendChatNotification(options, accessToken) {
24061
+ const url = `${apiV2Prefix}/chatroom/send-notification?access_token=${accessToken}`;
24062
+ return this.http.post(url, options);
24063
+ }
24030
24064
  sendNotification(options, accessToken) {
24031
24065
  const url = `${apiV2Prefix}/push-notification/send-users?access_token=${accessToken}`;
24032
24066
  return this.http.post(url, options);
@@ -1,5 +1,5 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
2
- import { d as dayjs_min, H as HttpService, k as isVideoMedia, e as getSalonImage, h as shortDateYearFormat } from './services-48c99e41.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
+ import { d as dayjs_min, H as HttpService, k as isVideoMedia, e as getSalonImage, h as shortDateYearFormat } from './services-b2dd15e7.js';
3
3
  import { r as relativeTime } from './relativeTime-15477f02.js';
4
4
  import { C as Colors } from './colors-ea36347a.js';
5
5
  import './_commonjsHelpers-9bc404fc.js';
@@ -1,4 +1,4 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
2
  import { C as Colors } from './colors-ea36347a.js';
3
3
 
4
4
  const indexCss = "";
@@ -1,4 +1,4 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
2
 
3
3
  const userFormCss = ":host{display:block}";
4
4
 
@@ -1,5 +1,5 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
2
- import { H as HttpService, g as get_1 } from './services-48c99e41.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
+ import { H as HttpService, g as get_1 } from './services-b2dd15e7.js';
3
3
  import { C as Colors } from './colors-ea36347a.js';
4
4
  import './_commonjsHelpers-9bc404fc.js';
5
5
 
@@ -161,11 +161,8 @@ const WizardExistingUser = class {
161
161
  color: Colors.Black,
162
162
  borderColor: Colors.Gray03,
163
163
  backgroundColor: Colors.Gray03,
164
- display: 'flex',
165
- alignItems: 'center',
166
- justifyContent: 'center',
167
164
  } : {},
168
- }, onClick: () => this.sendLoginCode() }, "Verify now ", this.isSubmitting && (h("span", { style: { marginLeft: '4px' } }, h("icon-loading", null)))))));
165
+ }, onClick: () => this.sendLoginCode() }, "Verify now ", this.isSubmitting && (h("span", { style: { marginLeft: '4px', position: 'relative', top: '2px' } }, h("icon-loading", null)))))));
169
166
  }
170
167
  };
171
168
  WizardExistingUser.style = wizardExistingUserCss;
@@ -1,5 +1,5 @@
1
- import { r as registerInstance, h } from './index-888e99e3.js';
2
- import { H as HttpService, g as get_1 } from './services-48c99e41.js';
1
+ import { r as registerInstance, h } from './index-759c34ea.js';
2
+ import { H as HttpService, g as get_1 } from './services-b2dd15e7.js';
3
3
  import { C as Colors } from './colors-ea36347a.js';
4
4
  import './_commonjsHelpers-9bc404fc.js';
5
5
 
@@ -193,11 +193,8 @@ const WizardNewUser = class {
193
193
  color: Colors.Black,
194
194
  borderColor: Colors.Gray03,
195
195
  backgroundColor: Colors.Gray03,
196
- display: 'flex',
197
- alignItems: 'center',
198
- justifyContent: 'center',
199
196
  } : {},
200
- }, onClick: () => this.verifyAccount() }, "Verify now ", this.isSubmitting && (h("span", { style: { marginLeft: '4px' } }, h("icon-loading", null)))))));
197
+ }, onClick: () => this.verifyAccount() }, "Verify now ", this.isSubmitting && (h("span", { style: { marginLeft: '4px', position: 'relative', top: '2px' } }, h("icon-loading", null)))))));
201
198
  }
202
199
  };
203
200
  WizardNewUser.style = wizardNewUserCss;
@@ -6,6 +6,7 @@ export declare class ChatButton {
6
6
  receiverAvatar?: string;
7
7
  accessToken?: string;
8
8
  senderId?: string;
9
+ isSalonOwnerOnline: boolean;
9
10
  senderIdState: string;
10
11
  accessTokenState: string;
11
12
  senderInfo: User;
@@ -22,9 +23,11 @@ export declare class ChatButton {
22
23
  componentDidLoad(): void;
23
24
  componentWillLoad(): void;
24
25
  onContentScrolled(): void;
26
+ checkSalonOwnerOnlineStatus(): void;
25
27
  onSetupChat(): void;
28
+ markMessagesAsRead(): Promise<void>;
26
29
  onClickChat(): void;
27
- fetchData(): Promise<void>;
30
+ fetchData(markMessagesAsRead?: boolean): Promise<void>;
28
31
  onVerificationSuccess(user: User): void;
29
32
  render(): any;
30
33
  }
@@ -1,5 +1,7 @@
1
1
  export declare class NotifySounds {
2
- componentDidLoad(): void;
2
+ unreadMessages: number;
3
+ componentDidRender(): void;
4
+ watchHandler(newValue: any, oldValue: any): void;
3
5
  private playSound;
4
6
  render(): any;
5
7
  }
@@ -4,6 +4,7 @@ export declare class ChatForm {
4
4
  accessToken: string;
5
5
  sender: User;
6
6
  chatRoom: ChatRoom;
7
+ private playSound;
7
8
  private sendNotification;
8
9
  private updateChatroomInfo;
9
10
  private onSubmitMessage;
@@ -39,7 +39,9 @@ export namespace Components {
39
39
  }
40
40
  interface ChatButton {
41
41
  "accessToken"?: string;
42
- "fetchData": () => Promise<void>;
42
+ "checkSalonOwnerOnlineStatus": () => Promise<void>;
43
+ "fetchData": (markMessagesAsRead?: boolean) => Promise<void>;
44
+ "markMessagesAsRead": () => Promise<void>;
43
45
  "onClickChat": () => Promise<void>;
44
46
  "onSetupChat": () => Promise<void>;
45
47
  "onVerificationSuccess": (user: User) => Promise<void>;
@@ -103,6 +105,7 @@ export namespace Components {
103
105
  "salonId": string;
104
106
  }
105
107
  interface NotifySounds {
108
+ "unreadMessages": number;
106
109
  }
107
110
  interface PoweredByFavesalon {
108
111
  "css": any;
@@ -606,6 +609,7 @@ declare namespace LocalJSX {
606
609
  "salonId"?: string;
607
610
  }
608
611
  interface NotifySounds {
612
+ "unreadMessages"?: number;
609
613
  }
610
614
  interface PoweredByFavesalon {
611
615
  "css"?: any;
@@ -75,6 +75,8 @@ declare class HttpService {
75
75
  total: number;
76
76
  data: any[];
77
77
  }>;
78
+ fetchSalonOwnerOnlineStatus(userId: any, onDone: any): void;
79
+ fetchChatroomUserInChat(roomId: any, userId: any): Promise<boolean>;
78
80
  createChatRoom(receiverId: any, accessToken: any): Promise<any>;
79
81
  private fetchRooms;
80
82
  fetchChatRooms(accessToken: string): any;
@@ -88,6 +90,7 @@ declare class HttpService {
88
90
  senderId: any;
89
91
  timestamp: number;
90
92
  }>;
93
+ sendChatNotification(options: any, accessToken: any): Promise<import("axios").AxiosResponse<any>>;
91
94
  sendNotification(options: any, accessToken: any): Promise<import("axios").AxiosResponse<any>>;
92
95
  loginByPhoneCode(options: any): Promise<{
93
96
  id: any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "favesalon-embed",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Favesalon Embed",
5
5
  "author": "Trung Luu <trung@favesalon.com> (https://favesalon.com)",
6
6
  "main": "dist/index.cjs.js",
@@ -1,7 +0,0 @@
1
- import './index-761e92c1.js';
2
-
3
- const globalFn = () => { };
4
-
5
- const globalScripts = globalFn;
6
-
7
- export { globalScripts as g };