cja-phoenix 0.2.9 → 0.2.11
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.
- package/dist/cja-phoenix.es.js +5535 -4712
- package/dist/style.css +1 -1
- package/dist/types/components/composite/InfoShowcase.vue.d.ts +25 -0
- package/dist/types/components/composite/ResultsSidebar.vue.d.ts +1 -28
- package/dist/types/components/index.d.ts +2 -1
- package/dist/types/utils/findScrollAncestor.d.ts +1 -0
- package/dist/types/utils/getFromUrl.d.ts +1 -0
- package/dist/types/utils/getI18nMessages.d.ts +1 -0
- package/dist/types/utils/index.d.ts +9 -4
- package/dist/types/utils/jsonReviver.d.ts +1 -0
- package/dist/types/utils/updateForm.d.ts +10 -0
- package/dist/types/utils/uploadFile.d.ts +8 -0
- package/package.json +1 -1
- package/src/components/composite/CheckoutCrossSell.vue +37 -21
- package/src/components/composite/CheckoutLayout.vue +6 -4
- package/src/components/composite/CheckoutMilestones.vue +8 -8
- package/src/components/composite/InfoShowcase.vue +83 -0
- package/src/components/composite/ResultsSidebar.vue +1 -33
- package/src/components/forms/SelectInput.vue +9 -1
- package/src/components/index.ts +2 -0
- package/src/components/structural/InfoMessage.vue +17 -5
- package/src/utils/findScrollAncestor.ts +16 -0
- package/src/utils/getFromUrl.ts +16 -0
- package/src/utils/getI18nMessages.ts +23 -0
- package/src/utils/index.ts +18 -4
- package/src/utils/{JsonReviver.ts → jsonReviver.ts} +1 -1
- package/src/utils/updateForm.ts +35 -0
- package/src/utils/uploadFile.ts +22 -0
- package/dist/types/utils/JsonReviver.d.ts +0 -1
- /package/dist/types/utils/{RouteGenerator.d.ts → generateRoutes.d.ts} +0 -0
- /package/dist/types/utils/{ViewportDetector.d.ts → useViewportDetector.d.ts} +0 -0
- /package/src/utils/{RouteGenerator.ts → generateRoutes.ts} +0 -0
- /package/src/utils/{ViewportDetector.ts → useViewportDetector.ts} +0 -0
|
@@ -10,9 +10,11 @@
|
|
|
10
10
|
</GridItem>
|
|
11
11
|
<GridItem
|
|
12
12
|
class="checkout-sidebar"
|
|
13
|
-
v-if="
|
|
13
|
+
v-if="$slots.sidebar"
|
|
14
|
+
:size-sm="2"
|
|
15
|
+
:size-md="4"
|
|
14
16
|
:size-lg="4"
|
|
15
|
-
:style="{ background: sidebarBackground }"
|
|
17
|
+
:style="{ background: activeViewport.lg ? sidebarBackground : '' }"
|
|
16
18
|
>
|
|
17
19
|
<slot name="sidebar"></slot>
|
|
18
20
|
</GridItem>
|
|
@@ -35,7 +37,7 @@ defineProps<{
|
|
|
35
37
|
.checkout-container {
|
|
36
38
|
.checkout-wrapper {
|
|
37
39
|
max-width: 750px;
|
|
38
|
-
padding: 32px
|
|
40
|
+
padding: 32px 0;
|
|
39
41
|
margin: 0 auto;
|
|
40
42
|
|
|
41
43
|
@media screen and (min-width: 1024px) {
|
|
@@ -44,7 +46,7 @@ defineProps<{
|
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
.checkout-sidebar {
|
|
47
|
-
padding: 32px
|
|
49
|
+
padding: 32px 0;
|
|
48
50
|
border-top: 1px solid #dedede;
|
|
49
51
|
|
|
50
52
|
@media screen and (min-width: 992px) {
|
|
@@ -49,14 +49,14 @@ defineProps<{
|
|
|
49
49
|
gap: 15px;
|
|
50
50
|
padding: 0 16px;
|
|
51
51
|
|
|
52
|
+
$step-icon-size: 25px;
|
|
53
|
+
|
|
52
54
|
.step-icon {
|
|
53
|
-
position: relative;
|
|
54
|
-
z-index: 1;
|
|
55
55
|
display: flex;
|
|
56
56
|
justify-content: center;
|
|
57
57
|
align-items: center;
|
|
58
|
-
width:
|
|
59
|
-
height:
|
|
58
|
+
width: $step-icon-size;
|
|
59
|
+
height: $step-icon-size;
|
|
60
60
|
border-radius: 50%;
|
|
61
61
|
color: #fff;
|
|
62
62
|
font-weight: 700;
|
|
@@ -95,9 +95,9 @@ defineProps<{
|
|
|
95
95
|
&.milestone-past {
|
|
96
96
|
&::after {
|
|
97
97
|
content: "";
|
|
98
|
-
top:
|
|
98
|
+
top: $step-icon-size;
|
|
99
99
|
background-color: #77aa43;
|
|
100
|
-
height: calc(100% + 35px);
|
|
100
|
+
height: calc(100% - $step-icon-size + 35px);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
.step-icon {
|
|
@@ -118,8 +118,8 @@ defineProps<{
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
&:not(:last-child)::after {
|
|
121
|
-
top:
|
|
122
|
-
height: 100
|
|
121
|
+
top: $step-icon-size;
|
|
122
|
+
height: calc(100% - $step-icon-size);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
.step-icon {
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="info-showcase">
|
|
3
|
+
<h2>{{ title }}</h2>
|
|
4
|
+
<div class="showcase-list">
|
|
5
|
+
<div class="showcase-item" v-for="item in items">
|
|
6
|
+
<div class="image-container">
|
|
7
|
+
<img :src="item.image" />
|
|
8
|
+
</div>
|
|
9
|
+
<div class="text-container">
|
|
10
|
+
<div class="title">
|
|
11
|
+
{{ item.title }}
|
|
12
|
+
</div>
|
|
13
|
+
<div class="description">
|
|
14
|
+
{{ item.description }}
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script lang="ts" setup>
|
|
23
|
+
defineProps<{
|
|
24
|
+
title: string;
|
|
25
|
+
items: {
|
|
26
|
+
title: string;
|
|
27
|
+
description: string;
|
|
28
|
+
image: string;
|
|
29
|
+
}[];
|
|
30
|
+
}>();
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<style lang="scss" scoped>
|
|
34
|
+
.info-showcase {
|
|
35
|
+
padding: 24px 36px;
|
|
36
|
+
background: #fff;
|
|
37
|
+
box-shadow: 0px 4px 40px rgba(0, 0, 0, 0.15);
|
|
38
|
+
|
|
39
|
+
h2 {
|
|
40
|
+
text-align: center;
|
|
41
|
+
font-weight: 700;
|
|
42
|
+
font-size: 24px;
|
|
43
|
+
line-height: 29px;
|
|
44
|
+
margin: 0 0 30px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.showcase-list {
|
|
48
|
+
display: grid;
|
|
49
|
+
grid-template-columns: repeat(3, 1fr);
|
|
50
|
+
gap: 56px;
|
|
51
|
+
max-width: 1200px;
|
|
52
|
+
margin: 0 auto;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.showcase-item {
|
|
56
|
+
display: grid;
|
|
57
|
+
align-items: center;
|
|
58
|
+
grid-template-columns: 80px 1fr;
|
|
59
|
+
gap: 24px;
|
|
60
|
+
|
|
61
|
+
.image-container {
|
|
62
|
+
img {
|
|
63
|
+
display: block;
|
|
64
|
+
max-width: 100%;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.text-container {
|
|
69
|
+
.title {
|
|
70
|
+
font-weight: 700;
|
|
71
|
+
font-size: 18px;
|
|
72
|
+
line-height: 22px;
|
|
73
|
+
margin-bottom: 10px;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.description {
|
|
77
|
+
font-size: 14px;
|
|
78
|
+
line-height: 17px;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
</style>
|
|
@@ -12,14 +12,8 @@
|
|
|
12
12
|
maxHeight: !fixedContainer?.positionFixed ? sidebarMaxHeight : '',
|
|
13
13
|
}"
|
|
14
14
|
>
|
|
15
|
-
<div class="sidebar-title">
|
|
16
|
-
<span class="m-cgg-icon--filtros"></span>
|
|
17
|
-
<span>{{ title }}</span>
|
|
18
|
-
</div>
|
|
19
15
|
<div class="sidebar-body">
|
|
20
|
-
<
|
|
21
|
-
<slot></slot>
|
|
22
|
-
</div>
|
|
16
|
+
<slot></slot>
|
|
23
17
|
</div>
|
|
24
18
|
</div>
|
|
25
19
|
</FixedContainer>
|
|
@@ -35,15 +29,6 @@ const fixedContainer = ref();
|
|
|
35
29
|
const sidebarContainer = ref();
|
|
36
30
|
const sidebarMaxHeight = ref();
|
|
37
31
|
|
|
38
|
-
withDefaults(
|
|
39
|
-
defineProps<{
|
|
40
|
-
title?: string;
|
|
41
|
-
}>(),
|
|
42
|
-
{
|
|
43
|
-
title: "Filtros",
|
|
44
|
-
}
|
|
45
|
-
);
|
|
46
|
-
|
|
47
32
|
const setSidebarHeight = () => {
|
|
48
33
|
sidebarMaxHeight.value = `${
|
|
49
34
|
window.innerHeight - sidebarContainer.value.offsetTop - 16 + window.scrollY
|
|
@@ -64,7 +49,6 @@ onUnmounted(() => {
|
|
|
64
49
|
.sidebar-container {
|
|
65
50
|
display: flex;
|
|
66
51
|
flex-direction: column;
|
|
67
|
-
gap: 16px;
|
|
68
52
|
padding: 24px 16px;
|
|
69
53
|
background: #ffffff;
|
|
70
54
|
border: 1px solid #dedede;
|
|
@@ -75,22 +59,6 @@ onUnmounted(() => {
|
|
|
75
59
|
max-height: 100%;
|
|
76
60
|
}
|
|
77
61
|
|
|
78
|
-
.sidebar-title {
|
|
79
|
-
display: flex;
|
|
80
|
-
align-items: center;
|
|
81
|
-
gap: 16px;
|
|
82
|
-
border-bottom: 1px solid #dedede;
|
|
83
|
-
padding-bottom: 16px;
|
|
84
|
-
font-weight: 700;
|
|
85
|
-
font-size: 18px;
|
|
86
|
-
line-height: 22px;
|
|
87
|
-
|
|
88
|
-
.m-cgg-icon--filtros {
|
|
89
|
-
color: #076b9c;
|
|
90
|
-
font-weight: 700;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
62
|
.sidebar-body {
|
|
95
63
|
overflow-y: auto;
|
|
96
64
|
overflow-x: hidden;
|
|
@@ -66,7 +66,6 @@ import { useField } from "vee-validate";
|
|
|
66
66
|
import {
|
|
67
67
|
ref,
|
|
68
68
|
computed,
|
|
69
|
-
watch,
|
|
70
69
|
onMounted,
|
|
71
70
|
onUnmounted,
|
|
72
71
|
InputHTMLAttributes,
|
|
@@ -76,6 +75,7 @@ import { SelectHTMLAttributes } from "vue";
|
|
|
76
75
|
import { SelectOption } from "../../types/SelectOption";
|
|
77
76
|
import InputError from "./structure/InputError.vue";
|
|
78
77
|
import InputContainer from "./structure/InputContainer.vue";
|
|
78
|
+
import { findScrollAncestor } from "../../utils";
|
|
79
79
|
|
|
80
80
|
const props = withDefaults(
|
|
81
81
|
defineProps<{
|
|
@@ -190,9 +190,17 @@ const toggleCollapse = () => {
|
|
|
190
190
|
}, 300);
|
|
191
191
|
window.removeEventListener("click", closeSelectOutside);
|
|
192
192
|
window.removeEventListener("scroll", closeSelectOutside);
|
|
193
|
+
findScrollAncestor(inputEl.value).removeEventListener(
|
|
194
|
+
"scroll",
|
|
195
|
+
closeSelectOutside
|
|
196
|
+
);
|
|
193
197
|
} else {
|
|
194
198
|
window.addEventListener("click", closeSelectOutside);
|
|
195
199
|
window.addEventListener("scroll", closeSelectOutside);
|
|
200
|
+
findScrollAncestor(inputEl.value).addEventListener(
|
|
201
|
+
"scroll",
|
|
202
|
+
closeSelectOutside
|
|
203
|
+
);
|
|
196
204
|
}
|
|
197
205
|
}
|
|
198
206
|
};
|
package/src/components/index.ts
CHANGED
|
@@ -31,6 +31,7 @@ import CheckoutLayout from "./composite/CheckoutLayout.vue";
|
|
|
31
31
|
import CheckoutMilestones from "./composite/CheckoutMilestones.vue";
|
|
32
32
|
import ProductDetails from "./composite/ProductDetails.vue";
|
|
33
33
|
import CjaMenuBar from "./composite/CjaMenuBar.vue";
|
|
34
|
+
import InfoShowcase from "./composite/InfoShowcase.vue";
|
|
34
35
|
|
|
35
36
|
export {
|
|
36
37
|
Modal,
|
|
@@ -64,4 +65,5 @@ export {
|
|
|
64
65
|
CjaMenuBar,
|
|
65
66
|
FixedContainer,
|
|
66
67
|
InfoMessage,
|
|
68
|
+
InfoShowcase,
|
|
67
69
|
};
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
class="info-message"
|
|
4
4
|
:class="[
|
|
5
5
|
`color-${color}`,
|
|
6
|
-
{ 'has-icon': $slots.icon, 'has-toggle': toggle },
|
|
6
|
+
{ 'has-icon': $slots.icon && activeViewport.m, 'has-toggle': toggle },
|
|
7
7
|
]"
|
|
8
8
|
>
|
|
9
|
-
<div class="icon-container" v-if="$slots.icon">
|
|
9
|
+
<div class="icon-container" v-if="$slots.icon && activeViewport.m">
|
|
10
10
|
<slot name="icon"></slot>
|
|
11
11
|
</div>
|
|
12
12
|
<div class="text-container">
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
</template>
|
|
21
21
|
|
|
22
22
|
<script lang="ts" setup>
|
|
23
|
+
import { inject } from "vue";
|
|
24
|
+
|
|
23
25
|
defineProps<{
|
|
24
26
|
title?: string;
|
|
25
27
|
description?: string;
|
|
@@ -27,6 +29,8 @@ defineProps<{
|
|
|
27
29
|
color: "blue" | "green";
|
|
28
30
|
}>();
|
|
29
31
|
|
|
32
|
+
const activeViewport: any = inject("activeViewport");
|
|
33
|
+
|
|
30
34
|
defineEmits(["btn:close"]);
|
|
31
35
|
</script>
|
|
32
36
|
|
|
@@ -35,12 +39,18 @@ defineEmits(["btn:close"]);
|
|
|
35
39
|
display: grid;
|
|
36
40
|
grid-template-columns: 1fr;
|
|
37
41
|
gap: 16px;
|
|
38
|
-
padding: 16px
|
|
42
|
+
padding: 8px 16px;
|
|
39
43
|
border: 2px solid #000;
|
|
40
44
|
border-radius: 16px;
|
|
41
45
|
|
|
46
|
+
@media screen and (min-width: 768px) {
|
|
47
|
+
padding: 16px 24px;
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
&.has-icon {
|
|
43
|
-
|
|
51
|
+
@media screen and (min-width: 768px) {
|
|
52
|
+
grid-template-columns: auto 1fr;
|
|
53
|
+
}
|
|
44
54
|
}
|
|
45
55
|
|
|
46
56
|
&.has-toggle {
|
|
@@ -48,7 +58,9 @@ defineEmits(["btn:close"]);
|
|
|
48
58
|
}
|
|
49
59
|
|
|
50
60
|
&.has-icon.has-toggle {
|
|
51
|
-
|
|
61
|
+
@media screen and (min-width: 768px) {
|
|
62
|
+
grid-template-columns: auto 1fr 18px;
|
|
63
|
+
}
|
|
52
64
|
}
|
|
53
65
|
|
|
54
66
|
&.color-green {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const findScrollAncestor = (element) => {
|
|
2
|
+
if (!element) {
|
|
3
|
+
return undefined;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
let parent = element.parentElement;
|
|
7
|
+
while (parent) {
|
|
8
|
+
const { overflowY } = window.getComputedStyle(parent);
|
|
9
|
+
if (overflowY === "auto" || overflowY === "scroll") {
|
|
10
|
+
return parent;
|
|
11
|
+
}
|
|
12
|
+
parent = parent.parentElement;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return document.documentElement;
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const getFromUrl = (param: string, removeFromUrl?: boolean) => {
|
|
2
|
+
const url = new URL(window.location.href);
|
|
3
|
+
|
|
4
|
+
if (url.searchParams.has(param)) {
|
|
5
|
+
const returnParam = url.searchParams.get(param);
|
|
6
|
+
|
|
7
|
+
if (removeFromUrl) {
|
|
8
|
+
url.searchParams.delete(param);
|
|
9
|
+
history.replaceState(history.state, "", url.toString());
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return returnParam;
|
|
13
|
+
} else {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { I18nOptions, createI18n } from "vue-i18n";
|
|
2
|
+
|
|
3
|
+
export const getI18nMessages = async (queryMessages: string) => {
|
|
4
|
+
const i18n = createI18n({
|
|
5
|
+
locale: "PT",
|
|
6
|
+
fallbackLocale: "PT",
|
|
7
|
+
messages: undefined,
|
|
8
|
+
legacy: false,
|
|
9
|
+
missingWarn: false,
|
|
10
|
+
fallbackWarn: false,
|
|
11
|
+
warnHtmlMessage: false,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
await fetch(
|
|
15
|
+
`${process.env.VUE_APP_API_URL}/Internationalization?contains=${queryMessages}`
|
|
16
|
+
)
|
|
17
|
+
.then((response) => response.json())
|
|
18
|
+
.then((data: I18nOptions["messages"]) =>
|
|
19
|
+
i18n.global.setLocaleMessage("PT", data || {})
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
return i18n;
|
|
23
|
+
};
|
package/src/utils/index.ts
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
|
-
import { generateRoutes } from "./
|
|
2
|
-
import { useViewportDetector } from "./
|
|
3
|
-
import {
|
|
1
|
+
import { generateRoutes } from "./generateRoutes";
|
|
2
|
+
import { useViewportDetector } from "./useViewportDetector";
|
|
3
|
+
import { jsonReviver } from "./jsonReviver";
|
|
4
|
+
import { getI18nMessages } from "./getI18nMessages";
|
|
5
|
+
import { findScrollAncestor } from "./findScrollAncestor";
|
|
6
|
+
import { updateForm } from "./updateForm";
|
|
7
|
+
import { getFromUrl } from "./getFromUrl";
|
|
8
|
+
import { uploadFile } from "./uploadFile";
|
|
4
9
|
|
|
5
|
-
export {
|
|
10
|
+
export {
|
|
11
|
+
generateRoutes,
|
|
12
|
+
useViewportDetector,
|
|
13
|
+
jsonReviver,
|
|
14
|
+
getI18nMessages,
|
|
15
|
+
findScrollAncestor,
|
|
16
|
+
updateForm,
|
|
17
|
+
getFromUrl,
|
|
18
|
+
uploadFile,
|
|
19
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export const updateForm = (options: {
|
|
2
|
+
journeyId: string | undefined;
|
|
3
|
+
step: number;
|
|
4
|
+
payload: any;
|
|
5
|
+
stepName: string;
|
|
6
|
+
isCompleted?: boolean;
|
|
7
|
+
sentToDialer?: boolean;
|
|
8
|
+
eventType?: string;
|
|
9
|
+
formType: string;
|
|
10
|
+
}) =>
|
|
11
|
+
fetch(`${process.env.VUE_APP_API_URL}/core/apis/data/updateForm`, {
|
|
12
|
+
method: "PUT",
|
|
13
|
+
body: JSON.stringify(
|
|
14
|
+
Object.fromEntries(
|
|
15
|
+
Object.entries({
|
|
16
|
+
eventType: options.eventType || "STEP_CHANGED",
|
|
17
|
+
isActionEvent: true,
|
|
18
|
+
journeyId: options.journeyId,
|
|
19
|
+
stepName: options.stepName,
|
|
20
|
+
isCompleted: options.isCompleted || false,
|
|
21
|
+
sentToDialer: options.sentToDialer || true,
|
|
22
|
+
lastStepNumber: options.step,
|
|
23
|
+
lastStepType: options.formType,
|
|
24
|
+
lastStepUrl:
|
|
25
|
+
window.location.pathname +
|
|
26
|
+
window.location.search +
|
|
27
|
+
window.location.hash,
|
|
28
|
+
data: JSON.stringify({
|
|
29
|
+
...options.payload,
|
|
30
|
+
formType: options.formType,
|
|
31
|
+
}),
|
|
32
|
+
}).filter(([_, v]) => v != null)
|
|
33
|
+
)
|
|
34
|
+
),
|
|
35
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const uploadFile = (options: {
|
|
2
|
+
basePath: string;
|
|
3
|
+
journeyId: string;
|
|
4
|
+
file: any;
|
|
5
|
+
fileName: string;
|
|
6
|
+
extension: string;
|
|
7
|
+
bucketName: string;
|
|
8
|
+
}) => {
|
|
9
|
+
const data = new FormData();
|
|
10
|
+
|
|
11
|
+
data.append(
|
|
12
|
+
"path",
|
|
13
|
+
`${options.basePath}/${options.journeyId}/${options.fileName}.${options.extension}`
|
|
14
|
+
);
|
|
15
|
+
data.append("file", options.file);
|
|
16
|
+
data.append("bucketName", options.bucketName);
|
|
17
|
+
|
|
18
|
+
return fetch(`${process.env.VUE_APP_API_URL}/core/apis/data/saveFileToS3`, {
|
|
19
|
+
method: "POST",
|
|
20
|
+
body: data,
|
|
21
|
+
});
|
|
22
|
+
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const JsonReviver: (data: any) => any;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|