@lancom/shared 0.0.208 → 0.0.210

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.
@@ -428,8 +428,17 @@ export default {
428
428
  fetchWarehouseLocations(params) {
429
429
  return _get('admin/warehouse-locations', params);
430
430
  },
431
- fetchWarehouseAllocations(warehouse, params) {
432
- return _get(`admin/warehouse/${warehouse}/allocations`, params);
431
+ fetchWarehouseAllocations(warehouse) {
432
+ return _get('admin/allocations', { warehouse });
433
+ },
434
+ createWarehouseAllocation(allocation) {
435
+ return _post(`admin/allocations`, allocation);
436
+ },
437
+ updateWarehouseAllocation(allocation) {
438
+ return _put(`admin/allocations/${allocation._id}`, allocation);
439
+ },
440
+ removeWarehouseAllocation(allocation) {
441
+ return _delete(`admin/allocations/${allocation._id}`, allocation);
433
442
  },
434
443
  fetchWarehouseLocationById(id) {
435
444
  return _get(`admin/warehouse-locations/${id}`);
@@ -443,6 +452,9 @@ export default {
443
452
  moveToWarehouseLocation(move) {
444
453
  return _post(`admin/warehouse-locations/move`, move);
445
454
  },
455
+ moveToWarehouseLocations(move) {
456
+ return _post(`admin/warehouse-locations/move/bulk`, move);
457
+ },
446
458
  async fetchBanners(params) {
447
459
  return sortByName(await _get('admin/banners', params));
448
460
  },
@@ -15,7 +15,8 @@ export function groupSimpleProducts(entity, isGroupByColor, isPopulateEmptyProdu
15
15
  simpleProducts: [],
16
16
  unitCosts: [],
17
17
  amount: 0,
18
- productsTotal: 0
18
+ productsTotal: 0,
19
+ name: simpleProduct.color?.name || simpleProduct.SKU
19
20
  };
20
21
  const group = groups.get(key) || defaultGroup;
21
22
 
@@ -0,0 +1,61 @@
1
+ function surveyOptin(order, shop) {
2
+ if (!window.renderOptIn) {
3
+ const tag = document.createElement('script');
4
+ tag.src = "https://apis.google.com/js/platform.js?onload=renderOptIn";
5
+ tag.defer = true;
6
+ tag.async = true;
7
+ const firstScriptTag = document.getElementsByTagName('script')[0];
8
+ firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
9
+
10
+ window.renderOptIn = () => {
11
+ surveyoptinRender(order, shop);
12
+ }
13
+ } else {
14
+ surveyoptinLoad(order, shop);
15
+ }
16
+ }
17
+
18
+ function surveyoptinLoad(order, shop) {
19
+ const { enabledSurveyoptin, MERCHANT_ID } = shop.settings.gapis || {};
20
+ if (enabledSurveyoptin && MERCHANT_ID) {
21
+ if (!window.gapi.surveyoptin.render) {
22
+ window.gapi.load('surveyoptin', function() {
23
+ surveyoptinRender(order, shop);
24
+ });
25
+ } else {
26
+ surveyoptinRender(order, shop);
27
+ }
28
+ }
29
+ }
30
+
31
+ function surveyoptinRender(order, shop) {
32
+ const { MERCHANT_ID } = shop.settings.gapis || {};
33
+ const products = order.products.reduce((gtins, { simpleProducts, product }) => {
34
+ return [
35
+ ...gtins,
36
+ ...(simpleProducts || [])
37
+ .filter(({ amount }) => amount > 0)
38
+ .map(({ SKU }) => {
39
+ const simpleProduct = (product?.simpleProducts || []).find(sp => sp.SKU === SKU);
40
+ return simpleProduct?.gtin;
41
+ })
42
+ .filter(gtin => !!gtin)
43
+ ];
44
+ }, []);
45
+ const estimated_delivery_date = "2023-11-28";
46
+ const data = {
47
+ merchant_id: MERCHANT_ID,
48
+ order_id: order.code,
49
+ email: order.shippingAddress.email,
50
+ delivery_country: order.shippingAddress.country,
51
+ estimated_delivery_date,
52
+ products,
53
+ opt_in_style: "BOTTOM_RIGHT_DIALOG"
54
+ };
55
+ console.log('surveyoptinRender: ', data);
56
+ window.gapi.surveyoptin.render(data);
57
+ }
58
+
59
+ export default {
60
+ surveyOptin
61
+ };
@@ -13,7 +13,7 @@
13
13
  height: 36px;
14
14
  padding: 2px !important;
15
15
  &.empty {
16
- color: #B0B0BA;
16
+ color: #272727;
17
17
  }
18
18
  }
19
19
  &__label {
@@ -45,7 +45,7 @@
45
45
  -moz-appearance: textfield;
46
46
  }
47
47
  &.empty {
48
- color: #B0B0BA;
48
+ color: #272727;
49
49
  }
50
50
  }
51
51
  &__price {
@@ -117,6 +117,7 @@
117
117
  import { mapGetters, mapActions, mapMutations } from 'vuex';
118
118
  import { price } from '@lancom/shared/assets/js/utils/filters';
119
119
  import gtm from '@lancom/shared/assets/js/utils/gtm';
120
+ import gapis from '@lancom/shared/assets/js/utils/gapis';
120
121
  import PaymentSuccess from '@lancom/shared/components/checkout/payment/payment_success/payment-success';
121
122
  import PaymentFailed from '@lancom/shared/components/checkout/payment/payment_failed/payment-failed';
122
123
 
@@ -253,6 +254,7 @@ export default {
253
254
  },
254
255
  sendConversionData() {
255
256
  gtm.purchase(this.orderData);
257
+ gapis.surveyOptin(this.orderData, this.shop);
256
258
  },
257
259
  back() {
258
260
  /*
@@ -4,14 +4,16 @@
4
4
  :style="{ backgroundImage }">
5
5
  <nuxt-link
6
6
  class="NewsListItem__overlay"
7
- :to="{ path: linkToNews }"></nuxt-link>
7
+ :to="{ path: linkToNews }"
8
+ :title="item.title"></nuxt-link>
8
9
  <div class="NewsListItem__info">
9
10
  <template v-if="!item.isHiddenThumbLink">
10
11
  <h1>
11
12
  <nuxt-link
12
13
  :to="{ path: linkToNews }"
13
14
  class="NewsListItem__link"
14
- :style="{ color: item.color }">
15
+ :style="{ color: item.color }"
16
+ :title="item.title">
15
17
  {{ item.title }}
16
18
  </nuxt-link>
17
19
  </h1>
@@ -29,7 +31,8 @@
29
31
  </div>
30
32
  <nuxt-link
31
33
  :to="{ path: linkToNews }"
32
- class="NewsListItem__more">
34
+ class="NewsListItem__more"
35
+ :title="item.title">
33
36
  <span>Read More</span>
34
37
  </nuxt-link>
35
38
  </article>
@@ -54,6 +54,7 @@
54
54
  &__small {
55
55
  overflow: hidden;
56
56
  position: relative;
57
+ margin: 20px 0;
57
58
  }
58
59
  &__zoom {
59
60
  position: absolute;
@@ -68,6 +69,7 @@
68
69
  justify-content: center;
69
70
  cursor: pointer;
70
71
  display: flex;
72
+ display: none !important;
71
73
  border: 1px solid grey;
72
74
  }
73
75
  &__big-image,
@@ -79,10 +81,27 @@
79
81
  background-size: contain;
80
82
  touch-action: auto !important;
81
83
  -ms-touch-action: auto !important;
82
- &::after {
83
- content: ' ';
84
- display: block;
85
- padding-top: 100%;
84
+ // &::after {
85
+ // content: ' ';
86
+ // display: block;
87
+ // padding-top: 100%;
88
+ // }
89
+ }
90
+ &__small-image {
91
+ height: 75px;
92
+ padding: 5px 0;
93
+ &-src {
94
+ max-width: 65px;
95
+ max-height: 65px;
96
+ margin: auto;
97
+ }
98
+ }
99
+ &__big-image {
100
+ height: 400px;
101
+ &-src {
102
+ max-width: 400px;
103
+ max-height: 400px;
104
+ margin: auto;
86
105
  }
87
106
  }
88
107
  &__big {
@@ -19,16 +19,22 @@
19
19
  v-hammer:pressup="onPanend"
20
20
  v-hammer:panend="onPanend"
21
21
  class="Gallery__big-image"
22
+ style="width: 300px; height: 300px;"
22
23
  :style="{
23
- 'background-image': `url(${staticLink(image.large)}`,
24
- 'background-size': backgroundSize,
25
- 'background-position': backgroundPosition,
24
+ // 'background-image': `url(${staticLink(image.large)}`,
25
+ // 'background-size': backgroundSize,
26
+ // 'background-position': backgroundPosition,
26
27
  'touch-action': zoomEnable ? 'none' : 'auto'
27
28
  }"
28
29
  @mousedown="onMouseDown"
29
30
  @mouseenter="onMouseEnter"
30
31
  @mouseleave="onMouseLeave"
31
32
  @mousemove="onMouseMove">
33
+ <img
34
+ :src="staticLink(image.large)"
35
+ :alt="product.name"
36
+ class="Gallery__big-image-src"
37
+ />
32
38
  <div
33
39
  v-if="image.print"
34
40
  class="Gallery__big-print">
@@ -71,8 +77,13 @@
71
77
  }"
72
78
  @click="goToSlideAndChangeColor(index)"
73
79
  :style="{
74
- 'background-image': `url(${staticLink(image.small)}`
80
+ // 'background-image': `url(${staticLink(image.small)}`
75
81
  }">
82
+ <img
83
+ :src="staticLink(image.small)"
84
+ :alt="product.name"
85
+ class="Gallery__small-image-src"
86
+ />
76
87
  <div class="Gallery__small-printed">
77
88
  {{ image.printType ? 'Printed' : (product.prePrint ? product.prePrintText : image.colorName || 'Blank') }}
78
89
  </div>
@@ -9,160 +9,168 @@
9
9
  tag="form"
10
10
  class="AddReview__form">
11
11
  <div class="row">
12
- <div class="col-sm-7 col-12">
13
- <validation-provider
14
- v-slot="{ errors }"
15
- tag="div"
16
- name="Name"
17
- rules="required"
18
- class="form-row">
19
- <input
20
- id="add-review-name"
21
- ref="name"
22
- v-model="form.name"
23
- name="name"
24
- type="text"
25
- class="form-field"
26
- :class="{
27
- 'is-danger': errors.length,
28
- filled: form.name
29
- }"
30
- @keyup.enter="$refs.email.focus()" />
31
- <label
32
- for="add-review-name"
33
- class="form-label label-inner">
34
- Name
35
- </label>
36
- <span
37
- v-if="errors.length"
38
- class="form-help is-danger">
39
- {{ errors[0] }}
40
- </span>
41
- </validation-provider>
42
- </div>
43
- <div class="col-sm-5 col-12">
44
- <validation-provider
45
- v-slot="{ errors }"
46
- tag="div"
47
- name="Email"
48
- rules="required|email"
49
- class="form-row">
50
- <input
51
- id="add-review-email"
52
- ref="email"
53
- v-model="form.email"
54
- name="email"
55
- type="text"
56
- class="form-field"
57
- :class="{
58
- 'is-danger': errors.length,
59
- filled: form.email
60
- }"
61
- @keyup.enter="$refs.text.focus()" />
62
- <label
63
- for="add-review-email"
64
- class="form-label label-inner">
65
- Email (Not published)
66
- </label>
67
- <span
68
- v-if="errors.length"
69
- class="form-help is-danger">
70
- {{ errors[0] }}
71
- </span>
72
- </validation-provider>
73
- </div>
74
- </div>
75
- <div
76
- class="row"
77
- style="margin-top: -20px;">
78
- <div class="col-sm-7 col-12">
79
- <validation-provider
80
- v-slot="{ errors }"
81
- tag="div"
82
- name="Review"
83
- rules="required|max:1024"
84
- class="form-row">
85
- <textarea
86
- id="add-review-body"
87
- ref="body"
88
- v-model="form.text"
89
- name="body"
90
- class="form-textarea--size3"
91
- :class="{
92
- 'is-danger': errors.length,
93
- filled: form.text
94
- }">
95
- </textarea>
96
- <label
97
- for="add-review-body"
98
- class="form-label label-inner">
99
- Your review...
100
- </label>
101
- <span
102
- v-if="errors.length"
103
- class="form-help is-danger">
104
- {{ errors[0] }}
105
- </span>
106
- </validation-provider>
107
- </div>
108
- <div class="col-sm-5 col-12">
109
- <div>
110
- <validation-provider
111
- v-slot="{ errors }"
112
- tag="div"
113
- name="Pro"
114
- class="form-row">
115
- <input
116
- id="add-review-pro"
117
- ref="pro"
118
- v-model="form.pro"
119
- name="pro"
120
- type="text"
121
- class="form-field"
122
- :class="{
123
- 'is-danger': errors.length,
124
- filled: form.pro
125
- }" />
126
- <label
127
- for="add-review-pro"
128
- class="form-label label-inner">
129
- Pro
130
- </label>
131
- <span
132
- v-if="errors.length"
133
- class="form-help is-danger">
134
- {{ errors[0] }}
135
- </span>
136
- </validation-provider>
12
+ <div class="col-7">
13
+ <div class="row">
14
+ <div class="col-12">
15
+ <validation-provider
16
+ v-slot="{ errors }"
17
+ tag="div"
18
+ name="Name"
19
+ rules="required"
20
+ class="form-row">
21
+ <input
22
+ id="add-review-name"
23
+ ref="name"
24
+ v-model="form.name"
25
+ name="name"
26
+ type="text"
27
+ class="form-field"
28
+ :class="{
29
+ 'is-danger': errors.length,
30
+ filled: form.name
31
+ }"
32
+ @keyup.enter="$refs.email.focus()" />
33
+ <label
34
+ for="add-review-name"
35
+ class="form-label label-inner">
36
+ Name
37
+ </label>
38
+ <span
39
+ v-if="errors.length"
40
+ class="form-help is-danger">
41
+ {{ errors[0] }}
42
+ </span>
43
+ </validation-provider>
44
+ </div>
45
+ <div
46
+ class="col-12"
47
+ style="margin-top: -20px">
48
+ <validation-provider
49
+ v-slot="{ errors }"
50
+ tag="div"
51
+ name="Email"
52
+ rules="required|email"
53
+ class="form-row">
54
+ <input
55
+ id="add-review-email"
56
+ ref="email"
57
+ v-model="form.email"
58
+ name="email"
59
+ type="text"
60
+ class="form-field"
61
+ :class="{
62
+ 'is-danger': errors.length,
63
+ filled: form.email
64
+ }"
65
+ @keyup.enter="$refs.text.focus()" />
66
+ <label
67
+ for="add-review-email"
68
+ class="form-label label-inner">
69
+ Email (Not published)
70
+ </label>
71
+ <span
72
+ v-if="errors.length"
73
+ class="form-help is-danger">
74
+ {{ errors[0] }}
75
+ </span>
76
+ </validation-provider>
77
+ </div>
78
+ <div
79
+ class="col-12"
80
+ style="margin-top: -20px">
81
+ <validation-provider
82
+ v-slot="{ errors }"
83
+ tag="div"
84
+ name="Review"
85
+ rules="required|max:1024"
86
+ class="form-row">
87
+ <textarea
88
+ id="add-review-body"
89
+ ref="body"
90
+ v-model="form.text"
91
+ name="body"
92
+ class="form-textarea--size3"
93
+ :class="{
94
+ 'is-danger': errors.length,
95
+ filled: form.text
96
+ }">
97
+ </textarea>
98
+ <label
99
+ for="add-review-body"
100
+ class="form-label label-inner">
101
+ Your review...
102
+ </label>
103
+ <span
104
+ v-if="errors.length"
105
+ class="form-help is-danger">
106
+ {{ errors[0] }}
107
+ </span>
108
+ </validation-provider>
109
+ </div>
137
110
  </div>
138
- <div class="mt-10">
139
- <validation-provider
140
- v-slot="{ errors }"
141
- tag="div"
142
- name="Cons"
143
- class="form-row">
144
- <input
145
- id="add-review-cons"
146
- ref="cons"
147
- v-model="form.cons"
148
- name="cons"
149
- type="text"
150
- class="form-field"
151
- :class="{
152
- 'is-danger': errors.length,
153
- filled: form.cons
154
- }" />
155
- <label
156
- for="add-review-cons"
157
- class="form-label label-inner">
158
- Cons
159
- </label>
160
- <span
161
- v-if="errors.length"
162
- class="form-help is-danger">
163
- {{ errors[0] }}
164
- </span>
165
- </validation-provider>
111
+ </div>
112
+ <div class="col-5">
113
+ <div class="row">
114
+ <div class="col-12">
115
+ <div>
116
+ <validation-provider
117
+ v-slot="{ errors }"
118
+ tag="div"
119
+ name="Pro"
120
+ class="form-row">
121
+ <textarea
122
+ id="add-review-pro"
123
+ ref="pro"
124
+ v-model="form.pro"
125
+ name="pro"
126
+ class="form-field"
127
+ style="height: 125px;"
128
+ :class="{
129
+ 'is-danger': errors.length,
130
+ filled: form.pro
131
+ }"></textarea>
132
+ <label
133
+ for="add-review-pro"
134
+ class="form-label label-inner">
135
+ Pro
136
+ </label>
137
+ <span
138
+ v-if="errors.length"
139
+ class="form-help is-danger">
140
+ {{ errors[0] }}
141
+ </span>
142
+ </validation-provider>
143
+ </div>
144
+ <div class="mt-10">
145
+ <validation-provider
146
+ v-slot="{ errors }"
147
+ tag="div"
148
+ name="Cons"
149
+ class="form-row">
150
+ <textarea
151
+ id="add-review-cons"
152
+ ref="cons"
153
+ v-model="form.cons"
154
+ name="cons"
155
+ class="form-field"
156
+ style="height: 125px;"
157
+ :class="{
158
+ 'is-danger': errors.length,
159
+ filled: form.cons
160
+ }"></textarea>
161
+ <label
162
+ for="add-review-cons"
163
+ class="form-label label-inner">
164
+ Cons
165
+ </label>
166
+ <span
167
+ v-if="errors.length"
168
+ class="form-help is-danger">
169
+ {{ errors[0] }}
170
+ </span>
171
+ </validation-provider>
172
+ </div>
173
+ </div>
166
174
  </div>
167
175
  </div>
168
176
  </div>
@@ -18,6 +18,9 @@
18
18
  }
19
19
  }
20
20
  }
21
+ &__lable {
22
+ display: none;
23
+ }
21
24
  &__field {
22
25
  position: relative;
23
26
  width: 100%;
@@ -31,7 +34,7 @@
31
34
  opacity: .3;
32
35
  }
33
36
  &.empty {
34
- color: $grey_2;
37
+ color: #272727;
35
38
  }
36
39
  }
37
40
  }
@@ -12,13 +12,20 @@
12
12
  @click="model -= step">
13
13
  <span> - </span>
14
14
  </div>
15
+ <label
16
+ :for="uniqueFieldId"
17
+ class="ProductSizeSelectorColorCell__lable">
18
+ {{ size.name }}
19
+ </label>
15
20
  <input
21
+ :id="uniqueFieldId"
16
22
  v-model.number="model"
17
23
  type="number"
18
24
  min="0"
19
25
  max="9999"
20
26
  class="form-field"
21
27
  :class="{ invalidate: disabled, empty: !model }"
28
+ :aria-label="size.name"
22
29
  :disabled="disabled"
23
30
  @focus="onFocus()"
24
31
  @blur="onBlur()" />
@@ -76,6 +83,7 @@ export default {
76
83
  },
77
84
  data() {
78
85
  return {
86
+ uniqueFieldId: `size-selector-${this.color._id}-${this.size._id}`,
79
87
  defaultValue: 0
80
88
  };
81
89
  },
@@ -1,6 +1,7 @@
1
1
  import { mapGetters, mapActions, mapMutations } from 'vuex';
2
2
  import api from '@lancom/shared/assets/js/api';
3
3
  import gtm from '@lancom/shared/assets/js/utils/gtm';
4
+ import gapis from '@lancom/shared/assets/js/utils/gapis';
4
5
  import { price, shortDate, tax } from '@lancom/shared/assets/js/utils/filters';
5
6
  import { convertQuoteToOrder } from '@lancom/shared/assets/js/utils/quote';
6
7
 
@@ -37,6 +38,7 @@ export default {
37
38
  this.order = await this.createOrder(option);
38
39
  this.setOrder(this.order);
39
40
  gtm.purchase(this.order);
41
+ gapis.surveyOptin(this.order, this.shop);
40
42
  this.clear();
41
43
  } catch (e) {
42
44
  const { message } = (e.response && e.response.data) || e;
package/mixins/payment.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { mapGetters, mapActions, mapMutations } from 'vuex';
2
2
  import gtm from '@lancom/shared/assets/js/utils/gtm';
3
+ import gapis from '@lancom/shared/assets/js/utils/gapis';
3
4
  import { ORDER_PAYMENT_METHOD } from '@lancom/shared/assets/js/constants/order';
4
5
 
5
6
  export default {
@@ -64,6 +65,7 @@ export default {
64
65
  },
65
66
  sendConversionData() {
66
67
  gtm.purchase(this.orderData);
68
+ gapis.surveyOptin(this.orderData, this.shop);
67
69
  },
68
70
  clearFailedCharge() {
69
71
  this.errorMessage = null;
package/nuxt.config.js CHANGED
@@ -65,6 +65,9 @@ module.exports = (config, axios, { raygunClient, publicPath } = {}) => ({
65
65
  { src: '@/node_modules/@lancom/shared/plugins/vue-recaptcha', ssr: false },
66
66
  // { src: '@/node_modules/@lancom/shared/plugins/vue-tables-2', ssr: false }
67
67
  ],
68
+ serverMiddleware: [
69
+ '@/node_modules/@lancom/shared/plugins/headers'
70
+ ],
68
71
  modules: [
69
72
  'nuxt-helmet',
70
73
  '@nuxtjs/axios',
@@ -146,6 +149,7 @@ module.exports = (config, axios, { raygunClient, publicPath } = {}) => ({
146
149
  }
147
150
  },
148
151
  review_timestamp: { _text: review.createdAt },
152
+ title: { _text: product.name },
149
153
  content: { _text: review.text },
150
154
  review_url: {
151
155
  _attributes: {
@@ -165,27 +169,34 @@ module.exports = (config, axios, { raygunClient, publicPath } = {}) => ({
165
169
  products: {
166
170
  product: {
167
171
  product_ids: {
168
- // gtins: {
169
- // gtin: { _text: '541710238425' }
170
- // },
172
+ brands: {
173
+ brand: { _text: product.brand.name }
174
+ },
171
175
  // mpns: {
172
176
  // mpn: { _text: '60101-10000' }
173
177
  // },
174
- skus: {
175
- sku: { _text: review.product.SKU }
176
- },
177
- brands: {
178
- brand: { _text: review.product.brand.name }
179
- },
180
178
  // asins: {
181
179
  // asin: { _text: 'B07YMJ57MB' }
182
180
  // }
183
181
  },
184
- product_name: { _text: review.product.name },
182
+ product_name: { _text: product.name },
185
183
  product_url: { _text: productUrl }
186
184
  }
187
185
  }
188
186
  };
187
+
188
+ if (product.simpleProduct?.gtin) {
189
+ item.products.product.product_ids.gtins = {
190
+ gtin: { _text: product.simpleProduct?.gtin }
191
+ };
192
+ }
193
+
194
+ if (product.simpleProduct?.SKU) {
195
+ item.products.product.product_ids.skus = {
196
+ sku: { _text: product.simpleProduct?.SKU }
197
+ };
198
+ }
199
+
189
200
  if (review.pro) {
190
201
  item.pros = {
191
202
  pro: [{ _text: review.pro }]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lancom/shared",
3
- "version": "0.0.208",
3
+ "version": "0.0.210",
4
4
  "description": "lancom common scripts",
5
5
  "author": "e.tokovenko <e.tokovenko@gmail.com>",
6
6
  "repository": {
@@ -1,5 +1,7 @@
1
1
  import Vue from 'vue';
2
2
 
3
+ Vue.config.productionTip = false;
4
+
3
5
  Vue.directive('focus', {
4
6
  inserted: (el, binding) => {
5
7
  const delay = binding.value || 500;
@@ -0,0 +1,4 @@
1
+ module.exports = function (req, res, next) {
2
+ res.removeHeader('Expect-CT');
3
+ next();
4
+ };