@hulkapps/app-manager-vue 2.0.4 → 2.0.7

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.
@@ -1,527 +1,26 @@
1
1
  <template>
2
- <PPage
3
- class="app-manager-plan-page custom-title"
4
- title="Choose plan"
5
- :subtitle = "subtitleContent"
6
- >
7
-
8
- <PStack slot="primaryAction">
9
- <PStackItem style="margin-top: 20px">
10
- <PButtonGroup class="btn-group" segmented>
11
- <PButton v-if="monthlyPlan.length && yearlyPlan.length" :style="selectedPlan === 'monthly' ? monthlySelectedStyle : monthlyStyle " @click="selectPlan('monthly')">
12
- <p style="font-size: 17px; font-weight: 500" slot="default">{{('Monthly')}}</p>
13
- </PButton>
14
-
15
- <PButton v-if="yearlyPlan.length && monthlyPlan.length" :style="selectedPlan === 'annually' ? yearlySelectedStyle : yearlyStyle " @click="selectPlan('annually')" :primary="selectedPlan === 'annually' " >
16
- <YearlyPlanPromotion />
17
- </PButton>
18
- </PButtonGroup>
19
- </PStackItem>
20
- </PStack>
21
- <hr style="width: 100%; margin-right: auto;margin-left: auto;margin-bottom: 20px;" />
22
- <!--=======================================================-->
23
-
24
- <PLayout class="custom-plan">
25
- <PLayoutSection>
26
- <template style="margin-bottom: 20px;">
27
- <template>
28
- <PDataTable class="plan-table">
29
- <template slot="head">
30
- <PDataTableRow v-if="selectedPlan === 'monthly'" style="box-shadow: none!important;">
31
- <PDataTableCol style="opacity: 0;visibility: hidden;border: 0 !important;" class="plan-heading">
32
- <b>{{('features')}}</b>
33
- </PDataTableCol>
34
- <template v-for="(plan, key) in monthlyPlan" >
35
- <PDataTableCol :class="{'first-column': key === 0, 'plan-heading': true, 'last-column': (key+1) === monthlyPlan.length}" :style="activePlanStyle(plan)">
36
- <b style="font-size: 16px">{{(plan.name)}}</b>
37
- <div v-if="plan.discount && plan.discount > 0" >
38
- <p style="display: flex;margin-top: 10px">
39
- <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(calculateDiscountedPrice(plan)).toFixed(2)}}</PHeading>
40
- <b style="margin-top: 5px;font-size: 17px">/{{("mo")}}</b>
41
- </p>
42
- <p style="display: flex;margin-top: 7px">
43
- <PHeading style="font-size: 18px;font-weight: 500; text-decoration:line-through;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
44
- <b style="margin-top: 3px;font-size: 14px">/{{("mo")}}</b>
45
- </p>
46
- </div>
47
- <div v-else>
48
- <p style="display: flex;margin-top: 10px">
49
- <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
50
- <b style="margin-top: 5px;font-size: 17px">/{{("mo")}}</b>
51
- </p>
52
- </div>
53
- </PDataTableCol>
54
- </template>
55
- </PDataTableRow>
56
- <PDataTableRow v-else>
57
- <PDataTableCol style="opacity: 0;visibility: hidden; border: 0 !important;" class="plan-heading">
58
- <b>{{('features')}}</b>
59
- </PDataTableCol>
60
- <template v-for="(plan,key) in yearlyPlan">
61
- <PDataTableCol :class="{'first-column': key === 0, 'plan-heading': true, 'last-column': (key+1) === yearlyPlan.length}" :style="activePlanStyle(plan)">
62
- <b style="font-size: 16px">{{(plan.name)}}</b>
63
- <div v-if="plan.discount && plan.discount > 0" >
64
- <p style="display: flex;margin-top: 10px">
65
- <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(calculateDiscountedPrice(plan)).toFixed(2)}}</PHeading>
66
- <b style="margin-top: 5px;font-size: 17px">/{{("year")}}</b>
67
- </p>
68
- <p style="display: flex;margin-top: 7px">
69
- <PHeading style="font-size: 18px;font-weight: 500; text-decoration:line-through;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
70
- <b style="margin-top: 3px;font-size: 14px">/{{("year")}}</b>
71
- </p>
72
- </div>
73
- <div v-else>
74
- <p style="display: flex;margin-top: 10px">
75
- <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
76
- <b style="margin-top: 5px;font-size: 17px">/{{("year")}}</b>
77
- </p>
78
- </div>
79
- </PDataTableCol>
80
- </template>
81
- </PDataTableRow>
82
- </template>
83
- <template slot="body">
84
- <PDataTableRow
85
- v-for="(feature, rIndex) in features" :key="`row-${rIndex}`"
86
- >
87
- <PDataTableCol>{{ (feature.name) }}</PDataTableCol>
88
- <PDataTableCol v-for="(plan, cIndex) in selectedPlan === 'monthly' ? monthlyPlan : yearlyPlan" :key="`cell-${cIndex}-row-${rIndex}`" :style="activePlanStyle(plan)">
89
- <template v-if="plan.features">
90
- <template v-if="feature.value_type === 'boolean'">
91
- <PIcon v-if="plan.features[feature.uuid]" color="success"
92
- source="TickMinor"/>
93
- <PIcon v-else color="subdued" source="MinusMinor"/>
94
- </template>
95
- <template v-else>
96
- <span v-if="plan.features[feature.uuid]">{{ format(plan.features[feature.uuid]) }}</span>
97
- <PIcon v-else color="subdued" source="MinusMinor"/>
98
- </template>
99
- </template>
100
- <template v-else>
101
- <PIcon color="subdued" source="MinusMinor"/>
102
- </template>
103
- </PDataTableCol>
104
- </PDataTableRow>
105
- <PDataTableRow v-if="plans.length" class="row-alignment" >
106
- <PDataTableCol></PDataTableCol>
107
- <PDataTableCol v-for="(plan, cIndex) in selectedPlan === 'monthly' ? monthlyPlan : yearlyPlan" :key="`cell-${cIndex}-row-plan`" style="max-width: 0">
108
- <PButton v-if="isCurrentPlan(plan)" :disabled="isCurrentPlan(plan)"
109
- full-width
110
- :pressed="isCurrentPlan(plan)">
111
- {{ ('Current Plan') }}
112
- </PButton>
113
- <PButton v-else-if="!plan.store_base_plan || plan.shopify_plans.includes(shop.shopify_plan)"
114
- full-width
115
- @click="plan ? getPlanUrl(plan):'javascript:void'"
116
- :primary="true" >
117
- {{ ('Choose Plan') }}
118
- </PButton>
119
- <PButton v-else :disabled="true"
120
- full-width
121
- :pressed="true">
122
- {{ ('Not applicable') }}
123
- </PButton>
124
- <PTextContainer v-if="plan.store_base_plan && shop.plan && plan.shopify_plans.includes(shop.shopify_plan) && !isCurrentPlan(plan)" class="footer-note-container">
125
- <PTextStyle class="text-break" v-if="plan.store_base_plan && !plan.shopify_plans.includes(shop.shopify_plan) && !(isCurrentPlan(plan)) && !isSamePlanInOtherInterval(plan)">Note: On account of your recent Shopify plan upgrade, you should consider upgrading your current app plan</PTextStyle>
126
- </PTextContainer>
127
- </PDataTableCol>
128
- </PDataTableRow>
129
- </template>
130
- </PDataTable>
131
- </template>
132
- </template>
133
- <PStack v-if="onboard && !shop.has_plan" class="choose-plan-btn" alignment="center" distribution="center" vertical>
134
- <PStackItem fill>
135
- <PButton plain @click="activePlan">{{ ('I will choose the plan later') }}</PButton>
136
- </PStackItem>
137
- </PStack>
138
- </PLayoutSection>
139
- <PlanBanners />
140
- </PLayout>
141
- <!--====================================================================-->
142
- </PPage>
2
+ <AppManagerGroupPlan v-on="$listeners" v-if="group_plan" :shop_domain="shop_domain" ></AppManagerGroupPlan>
3
+ <AppManagerSliderPlan v-on="$listeners" v-else :shop_domain="shop_domain" ></AppManagerSliderPlan>
143
4
  </template>
144
5
 
145
6
  <script>
146
-
147
- import axios from "axios";
148
- import PlanBanners from "./PlanBanners";
149
- import YearlyPlanPromotion from "./YearlyPlanPromotion";
150
- import PPage from "../polaris-vue/src/components/PPage/PPage";
151
- import PStack from "../polaris-vue/src/components/PStack/PStack";
152
- import PStackItem from "../polaris-vue/src/components/PStack/components/PStackItem/PStackItem";
153
- import {PButton} from "../polaris-vue/src/components/PButton";
154
- import {PButtonGroup} from "../polaris-vue/src/components/PButtonGroup";
155
- import {PHeading} from "../polaris-vue/src/components/PHeading";
156
- import {PLayout} from "../polaris-vue/src/components/PLayout";
157
- import {PLayoutSection} from "../polaris-vue/src/components/PLayout/components/PLayoutSection";
158
- import {PTextContainer} from "../polaris-vue/src/components/PTextContainer";
159
- import {PDataTable} from "../polaris-vue/src/components/PDataTable";
160
- import {PDataTableCol} from "../polaris-vue/src/components/PDataTable/components/PDataTableCol";
161
- import {PDataTableRow} from "../polaris-vue/src/components/PDataTable/components/PDataTableRow";
162
- import {PIcon} from "../polaris-vue/src/components/PIcon";
163
- import {PTextStyle} from "../polaris-vue/src/components/PTextStyle";
164
-
7
+ import AppManagerGroupPlan from "./AppManagerGroupPlan";
8
+ import AppManagerSliderPlan from "./AppManagerSliderPlan";
165
9
  export default {
166
10
  name: "AppManagerPlan",
167
- components: { YearlyPlanPromotion, PlanBanners, PPage, PStack, PStackItem, PButton, PButtonGroup, PHeading, PLayout, PLayoutSection, PTextContainer, PDataTable, PDataTableCol, PDataTableRow, PIcon, PTextStyle },
168
- props: ['shop_domain'],
169
- data() {
170
- return {
171
- plan: {},
172
- plans: [],
173
- features: [],
174
- shopify_plan: '',
175
- default_plan_id: null,
176
- onboard: true,
177
- subtitleContent: '',
178
- checkList: [
179
- "60 days free trial",
180
- ],
181
- selectedPlan:'monthly',
182
- monthlySelectedStyle:{
183
- height: '60px',
184
- backgroundColor:'#257f60',
185
- color:'#fff',
186
- position:'relative',
187
- right:'-5px',
188
- borderRadius:'8px',
189
- zIndex: 1,
190
- },
191
- yearlySelectedStyle:{
192
- height: '60px',
193
- backgroundColor:'#257f60',
194
- position:'relative',
195
- left:'-5px',
196
- borderRadius:'8px'
197
- },
198
- monthlyStyle:{
199
- height: '55px',
200
- backgroundColor:'#f0f8f5',
201
- boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px',
202
- border:'none',
203
- borderRadius:'8px',
204
- ZIndex: 11,
205
- },
206
- yearlyStyle:{
207
- color:'#258060',
208
- height: '55px',
209
- backgroundColor:'#f0f8f5',
210
- boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px',
211
- border:'none',
212
- borderRadius:'8px'
213
- },
214
- }
215
- },
216
- computed: {
217
- shop() {
218
- return {
219
- "name": this.shop_domain,
220
- "shopify_plan": this.shopify_plan,
221
- "has_plan": !!this.plan,
222
- "plan": this.plan,
223
- "default_plan_id": this.default_plan_id,
224
- };
225
- },
226
- headings() {
227
- let headings = [('Plans & Features')];
228
- this.plans.forEach(plan => {
229
-
230
- let heading = (plan.name);
231
- if (plan.price > 0) heading += ` ($${plan.price}/mo)`;
232
- headings.push(heading);
233
- });
234
- return headings;
235
- },
236
- monthlyPlan() {
237
- const plans = [];
238
- for(let planKey in this.plans) {
239
- if(this.plans[planKey].interval === 'EVERY_30_DAYS') {
240
- plans.push(this.plans[planKey]);
241
- }
242
- }
243
- return plans;
244
- },
245
- yearlyPlan() {
246
- const plans = [];
247
- for(let planKey in this.plans) {
248
- if(this.plans[planKey].interval === 'ANNUAL') {
249
- plans.push(this.plans[planKey]);
250
- }
251
- }
252
- return plans;
253
- }
254
- },
255
- methods: {
256
-
257
- activePlanStyle(plan) {
258
- return [plan.shopify_plans.includes(this.shop.shopify_plan) || !plan.store_base_plan ? {backgroundColor: '#f0f8f5', color: '#257f60'} : {}];
259
- },
260
- isCurrentPlan(plan) {
261
- return this.shop.plan && (plan.id === this.shop.plan.id || (!plan.is_custom && plan.base_plan === this.shop.plan.id));
262
- },
263
- isSamePlanInOtherInterval(plan) {
264
- return this.shop.plan && (plan.shopify_plans === this.shop.plan.shopify_plans)
265
- },
266
- format(feature) {
267
- if (['double', 'integer'].includes(feature?.value_type)) {
268
- if (feature.format === 'percentage') {
269
- return `${feature.value}%`
270
- } else if (feature.format === 'count') {
271
- return (feature.value < 0 ? (`Unlimited`) : feature.value)
272
- } else return feature.value
273
- }
274
- else if(['string', 'array'].includes(feature?.value_type)) {
275
- return feature.value
276
- }
277
- },
278
- calculateDiscountedPrice(plan) {
279
- if (plan.discount_type === 'percentage') {
280
- return plan.price - (plan.price * plan.discount)/100
281
- }
282
- else if (plan.discount_type === 'amount') {
283
- return plan.price - plan.discount
284
- }
285
- },
286
- async getPlanUrl(plan) {
287
- let shopName = this.shop.name;
288
- const response = await axios.get(`${this.app_manager_config.baseUrl}/api/app-manager/plan/process/${plan.id}?shop=${shopName}`).catch(error => {
289
- console.error(error)
290
- });
291
- let redirectUrl = response.data.redirect_url;
292
- if (redirectUrl) {
293
- window.top.location.href = redirectUrl;
294
- }
295
- },
296
- async activePlan() {
297
- const response = await this.activeWithoutPlan()
298
- if (response.data.status === true && this.onboard) {
299
- // Create the event
300
- this.$emit('handlePlanSelect', {chose_later: true})
301
- this.onboard = false;
302
- }
303
- },
304
- async activeWithoutPlan() {
305
- return await axios.post(`${this.app_manager_config.baseUrl}/api/app-manager/active-without-plan`, {
306
- shop_domain: this.shop.name,
307
- plan_id: this.shop.default_plan_id
308
- }).catch(error => {
309
- console.error(error)
310
- });
311
- },
312
- async selectPlan(value){
313
- this.selectedPlan= value;
314
- },
315
- headerClasses(firstColumn) {
316
- return {
317
- 'Polaris-DataTable__Cell': true,
318
- 'Polaris-DataTable__Cell--header': true,
319
- 'Polaris-DataTable__Cell--verticalAlignMiddle': true,
320
- 'Polaris-DataTable__Cell--firstColumn': Boolean(firstColumn),
321
- };
11
+ components: {AppManagerSliderPlan, AppManagerGroupPlan},
12
+ props: {
13
+ shop_domain: {
14
+ type: String
15
+ },
16
+ group_plan: {
17
+ type : Boolean,
18
+ default : false
322
19
  }
323
- },
324
- async mounted() {
325
-
326
- const featuresData = await axios.get(`${this.app_manager_config.baseUrl}/api/app-manager/plan-features`).catch(error => {
327
- console.error(error)
328
- });
329
- this.features = featuresData.data.features;
330
- this.features = this.features.sort((featureA, featureB) => parseInt(featureA.display_order) - parseInt(featureB.display_order))
331
-
332
- const plansData = await axios.get(`${this.app_manager_config.baseUrl}/api/app-manager/plans`, { params: { 'shop_domain': this.shop_domain } }).catch(error => {
333
- console.error(error)
334
- });
335
- this.plans = plansData.data.plans;
336
- this.plans = this.plans.sort((planA, planB) => parseFloat(planA.price) - parseFloat(planB.price));
337
- if (this.plans && this.plans[0].store_base_plan) {
338
- this.subtitleContent = 'App plans are based on your existing shopify plan';
339
- }
340
- this.shopify_plan = plansData.data.shopify_plan;
341
- this.plan = plansData.data.plan;
342
- if (this.plan?.interval === 'ANNUAL') {
343
- this.selectedPlan = 'annually'
344
- }
345
- this.default_plan_id = plansData.data.default_plan_id;
346
- this.onboard = !this.plan
347
20
  }
348
21
  }
349
22
  </script>
350
23
 
351
- <style lang="scss">
352
-
353
- @import url('https://fonts.googleapis.com/css2?family=Satisfy&display=swap');
24
+ <style scoped>
354
25
 
355
- .app-manager-plan-page .plan-table td:last-child>*[data-v-7d902277],
356
- .app-manager-plan-page .plan-table td:last-child>*[data-v-5a078dbb] {
357
- float:none;
358
- }
359
- .app-manager-plan-page .active {
360
- background: #f0f8f5;
361
- }
362
- .app-manager-plan-page .plan-table td:last-child>*[data-v-0d1b0d63] {
363
- float:none;
364
- }
365
- .app-manager-plan-page .plan-table td {
366
- border: 0.01px solid #ececee !important;
367
- border-collapse: collapse !important;
368
- }
369
- .app-manager-plan-page .plan-table .Polaris-DataTable__ScrollContainer{
370
- border-radius:12px;
371
- overflow: visible;
372
- }
373
- .app-manager-plan-page .plan-table table {
374
- border-collapse: collapse !important;
375
- }
376
- .app-manager-plan-page .custom-plan table {
377
- border-collapse: collapse !important;
378
- }
379
- .app-manager-plan-page .custom-plan table thead .first-column {
380
- border-radius: 12px 0 0 0;
381
- border-top: 0px !important;
382
- border-left: 0px !important;
383
- }
384
- .app-manager-plan-page .custom-plan table thead .plan-heading.last-column {
385
- text-align: left !important;
386
- border-radius: 0 12px 0 0;
387
- border-top: 0px !important;
388
- }
389
- .app-manager-plan-page .custom-plan table thead .plan-heading {
390
- background-color: rgb(255, 255, 255);
391
- box-shadow: rgb(23 24 24 / 5%) 1px 0px 8px, rgb(0 0 0 / 15%) 0px 0px 2px;
392
- }
393
- .app-manager-plan-page .custom-plan table tbody tr:first-child {
394
- background-color: #fff;
395
- box-shadow: 0 0 5px rgb(23 24 24 / 5%), 0 1px 2px rgb(0 0 0 / 15%);
396
- border-radius: 12px 0 0 0;
397
- overflow: hidden;
398
- }
399
- .app-manager-plan-page .custom-plan table tbody tr:not(:first-child :last-child ) {
400
- background-color: #fff;
401
- overflow: hidden;
402
- }
403
- .app-manager-plan-page .custom-plan table tbody tr:not(:first-child :last-child) {
404
- background-color: #fff;
405
- box-shadow: 0 0 5px rgb(23 24 24 / 5%), 0 1px 2px rgb(0 0 0 / 15%);
406
- overflow: hidden;
407
- }
408
- .app-manager-plan-page .custom-plan table tbody tr:not( :nth-last-child(2) ) {
409
- background-color: #fff;
410
- overflow: hidden;
411
- }
412
- .app-manager-plan-page .custom-plan table tbody tr:not( :nth-last-child(2) ) {
413
- border-bottom: 0;
414
- }
415
- .app-manager-plan-page .custom-plan table tbody tr:last-child {
416
- border-bottom: 0;
417
- background-color: transparent !important;
418
- box-shadow: none !important;
419
- }
420
- .app-manager-plan-page .custom-plan table tbody tr:not(:last-child) {
421
- pointer-events: none;
422
- }
423
- .app-manager-plan-page .custom-plan table thead tr td{
424
- pointer-events: none;
425
- }
426
- .app-manager-plan-page .custom-plan table tbody tr:first-child td:first-child {
427
- overflow: hidden;
428
- border-radius: 12px 0 0 0;
429
- }
430
- .app-manager-plan-page .custom-plan table tbody tr:nth-last-child(2) {
431
- overflow: hidden;
432
- border-bottom-right-radius: 12px;
433
- border-bottom-left-radius: 12px;
434
- }
435
- .app-manager-plan-page .custom-plan table tbody tr:nth-last-child(2) td:first-child {
436
- overflow: hidden;
437
- border-bottom: 0px !important;
438
- border-radius: 0 0 0 12px;
439
- }
440
- .app-manager-plan-page .custom-plan table tbody tr:nth-last-child(2) td:last-child {
441
- overflow: hidden;
442
- border-radius: 0 0 12px;
443
- }
444
- .app-manager-plan-page .custom-plan table tbody tr td:first-child {
445
- border-left: 0px !important;
446
- border-top: 0px !important;
447
- padding-left: 20px;
448
- }
449
- .app-manager-plan-page .custom-plan table tbody tr td:last-child {
450
- border-right: 0px !important;
451
- border-bottom: 0px !important;
452
- text-align: center !important;
453
- }
454
- .app-manager-plan-page .custom-plan table thead tr td:last-child {
455
- border-right: 0px !important;
456
- border-bottom: 0px !important;
457
- text-align: center !important;
458
- }
459
- .app-manager-plan-page .custom-plan table tbody td:not(:first-child) {
460
- text-align: center !important;
461
- }
462
- .app-manager-plan-page .custom-plan table tbody tr:last-child td:last-child {
463
- background: transparent;
464
- border-radius: 0 0 12px 0;
465
- }
466
- .app-manager-plan-page .custom-plan table tbody tr:last-child td {
467
- border: 0 !important;
468
- background: transparent;
469
- }
470
- .app-manager-plan-page .custom-plan table tbody tr:last-child td:hover {
471
- border: 0 !important;
472
- background: transparent;
473
- }
474
- .app-manager-plan-page .custom-plan tbody tr:last-child td.Polaris-DataTable__Cell--verticalAlignTop{
475
- background: transparent !important;
476
- }
477
- .app-manager-plan-page .custom-plan table tbody tr:last-child {
478
- background: transparent;
479
- opacity:1.0;
480
- }
481
- .app-manager-plan-page .custom-plan table tbody tr:last-child td:first-child{
482
- visibility: hidden;
483
- }
484
- .app-manager-plan-page .plan-heading {
485
- padding-top: 30px;
486
- }
487
- .app-manager-plan-page .custom-plan .Polaris-Layout__Section{
488
- max-width: calc(100% - 2rem) !important;
489
- }
490
- .app-manager-plan-page .later-link {
491
- text-align: center;
492
- clear: both;
493
- padding-top: 15px;
494
- }
495
- .app-manager-plan-page .plan-badge ul {
496
- text-align: center;
497
- padding-top: 2rem;
498
- border-top: 0.1rem solid #e1e3e5;
499
- }
500
- .app-manager-plan-page .plan-badge ul li {
501
- list-style: none;
502
- display: inline-block;
503
- padding-right: 25px;
504
- }
505
- .app-manager-plan-page .plan-badge ul li img {
506
- max-width: 133px;
507
- }
508
- .app-manager-plan-page .btn-group .Polaris-ButtonGroup__Item{
509
- margin-left: 0px !important;
510
- z-index: unset !important;
511
- }
512
- .app-manager-plan-page.custom-title .Polaris-HorizontalDivider{
513
- background-color: #e2e3e4;
514
- }
515
- /*.app-manager-plan-page .annual_heading{
516
- margin-top: 2px !important;
517
- color: #E2C138;
518
- border: 2px dotted #E2C138;
519
- padding: 5px;
520
- font-size: 16px !important;
521
- font-weight: normal !important;
522
- font-family: 'Satisfy', cursive;
523
- }*/
524
- .app-manager-plan-page .Polaris-Page__Content hr{
525
- border: 1px solid #e2e3e4;
526
- }
527
- </style>
26
+ </style>