@adminforth/two-factors-auth 1.0.22 → 1.0.28
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/Changelog.md
CHANGED
|
@@ -17,14 +17,13 @@
|
|
|
17
17
|
<div class="my-4 flex justify-center items-center">
|
|
18
18
|
<v-otp-input
|
|
19
19
|
ref="code"
|
|
20
|
-
input-classes="
|
|
20
|
+
input-classes="bg-gray-50 text-center flex justify-center otp-input border leading-none border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-10 h-10 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
21
21
|
:conditionalClass="['one', 'two', 'three', 'four', 'five', 'six']"
|
|
22
22
|
inputType="number"
|
|
23
23
|
:num-inputs="6"
|
|
24
24
|
v-model:value="bindValue"
|
|
25
25
|
:should-auto-focus="true"
|
|
26
26
|
:should-focus-order="true"
|
|
27
|
-
@on-change="handleOnChange"
|
|
28
27
|
@on-complete="handleOnComplete"
|
|
29
28
|
/>
|
|
30
29
|
</div>
|
|
@@ -98,13 +97,12 @@
|
|
|
98
97
|
|
|
99
98
|
onMounted(async () => {
|
|
100
99
|
coreStore.getPublicConfig();
|
|
101
|
-
window.addEventListener('
|
|
100
|
+
window.addEventListener('paste', handlePaste);
|
|
102
101
|
});
|
|
103
102
|
|
|
104
103
|
onBeforeUnmount(() => {
|
|
105
|
-
window.removeEventListener('
|
|
104
|
+
window.removeEventListener('paste', handlePaste);
|
|
106
105
|
});
|
|
107
|
-
|
|
108
106
|
|
|
109
107
|
async function sendCode (value) {
|
|
110
108
|
inProgress.value = true;
|
|
@@ -129,16 +127,14 @@
|
|
|
129
127
|
// }
|
|
130
128
|
// })
|
|
131
129
|
|
|
132
|
-
function
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
console.error('Failed to read clipboard contents: ', err);
|
|
141
|
-
});
|
|
130
|
+
function handlePaste(event) {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
if (event.target.classList.contains('otp-input')) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const pastedText = event.clipboardData?.getData('text') || '';
|
|
136
|
+
if (pastedText.length === 6) {
|
|
137
|
+
code.value?.fillInput(pastedText);
|
|
142
138
|
}
|
|
143
139
|
}
|
|
144
140
|
</script>
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
<div class="w-full max-w-[46rem]">
|
|
23
23
|
<div class="relative">
|
|
24
24
|
<label for="npm-install-copy-text" class="sr-only">Label</label>
|
|
25
|
-
<input id="npm-install-copy-text" type="text" class="col-span-10 bg-gray-50 border border-gray-300 text-gray-500 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full px-2.5 py-4 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-gray-400 dark:focus:ring-blue-500 dark:focus:border-blue-500" :value="totp.newSecret"
|
|
26
|
-
<button data-copy-to-clipboard-target="npm-install-copy-text" class="absolute end-2.5 top-1/2 -translate-y-1/2 text-gray-900 dark:text-gray-400 hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-600 dark:hover:bg-gray-700 rounded-lg py-2 px-2.5 inline-flex items-center justify-center bg-white border-gray-200 border">
|
|
27
|
-
<span id="default-message" class="inline-flex items-center">
|
|
25
|
+
<input id="npm-install-copy-text" type="text" class="col-span-10 bg-gray-50 border border-gray-300 text-gray-500 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full px-2.5 py-4 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-gray-400 dark:focus:ring-blue-500 dark:focus:border-blue-500 pr-20" :value="totp.newSecret" readonly>
|
|
26
|
+
<button @click="onCopyClick" data-copy-to-clipboard-target="npm-install-copy-text" class="absolute end-2.5 top-1/2 -translate-y-1/2 text-gray-900 dark:text-gray-400 hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-600 dark:hover:bg-gray-700 rounded-lg py-2 px-2.5 inline-flex items-center justify-center bg-white border-gray-200 border">
|
|
27
|
+
<span v-if="isCopied === false" id="default-message" class="inline-flex items-center">
|
|
28
28
|
<svg class="w-3 h-3 me-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 18 20">
|
|
29
29
|
<path d="M16 1h-3.278A1.992 1.992 0 0 0 11 0H7a1.993 1.993 0 0 0-1.722 1H2a2 2 0 0 0-2 2v15a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2Zm-3 14H5a1 1 0 0 1 0-2h8a1 1 0 0 1 0 2Zm0-4H5a1 1 0 0 1 0-2h8a1 1 0 1 1 0 2Zm0-5H5a1 1 0 0 1 0-2h2V2h4v2h2a1 1 0 1 1 0 2Z"/>
|
|
30
30
|
</svg>
|
|
31
|
-
<span
|
|
31
|
+
<span class="text-xs font-semibold">Copy</span>
|
|
32
32
|
</span>
|
|
33
|
-
<span id="success-message" class="
|
|
33
|
+
<span v-if="isCopied === true" id="success-message" class="inline-flex items-center">
|
|
34
34
|
<svg class="w-3 h-3 text-lightPrimary dark:text-darkPrimary me-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 12">
|
|
35
35
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5.917 5.724 10.5 15 1.5"/>
|
|
36
36
|
</svg>
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
<div class="my-4 flex justify-center items-center">
|
|
44
44
|
<v-otp-input
|
|
45
45
|
ref="code"
|
|
46
|
-
input-classes="
|
|
46
|
+
input-classes="bg-gray-50 text-center flex justify-center otp-input border leading-none border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-10 h-10 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
47
47
|
:conditionalClass="['one', 'two', 'three', 'four', 'five', 'six']"
|
|
48
48
|
inputType="number"
|
|
49
49
|
:num-inputs="6"
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
@on-complete="handleOnComplete"
|
|
53
53
|
/>
|
|
54
54
|
</div>
|
|
55
|
-
|
|
56
55
|
<!-- <Vue2FACodeInput v-model="code" autofocus /> -->
|
|
57
56
|
<Button @click="()=>{router.push('./login')}"
|
|
58
57
|
class="w-full">Cancel
|
|
@@ -67,7 +66,7 @@
|
|
|
67
66
|
</template>
|
|
68
67
|
|
|
69
68
|
|
|
70
|
-
<script setup>
|
|
69
|
+
<script setup lang="ts">
|
|
71
70
|
|
|
72
71
|
import { onMounted, onBeforeUnmount, ref, watchEffect,computed,watch } from 'vue';
|
|
73
72
|
import { useCoreStore } from '@/stores/core';
|
|
@@ -81,14 +80,11 @@ import Vue2FACodeInput from '@loltech/vue3-2fa-code-input';
|
|
|
81
80
|
import VOtpInput from "vue3-otp-input";
|
|
82
81
|
|
|
83
82
|
const code = ref(null);
|
|
83
|
+
const isCopied = ref<boolean>(false);
|
|
84
84
|
const handleOnComplete = (value) => {
|
|
85
85
|
sendCode(value);
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
-
const fillInput = (value) => {
|
|
89
|
-
code.value?.fillInput(value);
|
|
90
|
-
};
|
|
91
|
-
|
|
92
88
|
const router = useRouter();
|
|
93
89
|
const inProgress = ref(false);
|
|
94
90
|
|
|
@@ -97,9 +93,6 @@ const user = useUserStore();
|
|
|
97
93
|
|
|
98
94
|
// use this simple function to automatically focus on the next input
|
|
99
95
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
96
|
const showPw = ref(false);
|
|
104
97
|
|
|
105
98
|
const error = ref(null);
|
|
@@ -129,16 +122,11 @@ function parseJwt(token) {
|
|
|
129
122
|
}
|
|
130
123
|
|
|
131
124
|
function onCopyClick(){
|
|
125
|
+
isCopied.value = true;
|
|
126
|
+
navigator.clipboard.writeText(totp.value.newSecret);
|
|
132
127
|
window.adminforth.alert({message: 'Copied to clipboard', variant: 'success'})
|
|
133
128
|
}
|
|
134
129
|
|
|
135
|
-
// watch(code, async (nv)=>{
|
|
136
|
-
// if (nv){
|
|
137
|
-
// console.log(code.value);
|
|
138
|
-
// sendCode();
|
|
139
|
-
// }
|
|
140
|
-
// })
|
|
141
|
-
|
|
142
130
|
onMounted(async () => {
|
|
143
131
|
coreStore.getPublicConfig()
|
|
144
132
|
const resp = await callAdminForthApi({
|
|
@@ -151,11 +139,12 @@ onMounted(async () => {
|
|
|
151
139
|
|
|
152
140
|
totp.value=parseJwt(totpJWT.value);
|
|
153
141
|
|
|
154
|
-
|
|
142
|
+
|
|
143
|
+
window.addEventListener('paste', handlePaste);
|
|
155
144
|
});
|
|
156
145
|
|
|
157
146
|
onBeforeUnmount(() => {
|
|
158
|
-
window.removeEventListener('
|
|
147
|
+
window.removeEventListener('paste', handlePaste);
|
|
159
148
|
});
|
|
160
149
|
|
|
161
150
|
async function sendCode (value) {
|
|
@@ -178,22 +167,19 @@ async function sendCode (value) {
|
|
|
178
167
|
}
|
|
179
168
|
|
|
180
169
|
|
|
181
|
-
function
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
console.error('Failed to read clipboard contents: ', err);
|
|
190
|
-
});
|
|
170
|
+
function handlePaste(event) {
|
|
171
|
+
event.preventDefault();
|
|
172
|
+
if (event.target.classList.contains('otp-input')) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const pastedText = event.clipboardData?.getData('text') || '';
|
|
176
|
+
if (pastedText.length === 6) {
|
|
177
|
+
code.value?.fillInput(pastedText);
|
|
191
178
|
}
|
|
192
179
|
}
|
|
193
180
|
</script>
|
|
194
181
|
<style>
|
|
195
182
|
.otp-input {
|
|
196
183
|
margin: 0 5px;
|
|
197
|
-
|
|
198
184
|
}
|
|
199
185
|
</style>
|
|
@@ -17,14 +17,13 @@
|
|
|
17
17
|
<div class="my-4 flex justify-center items-center">
|
|
18
18
|
<v-otp-input
|
|
19
19
|
ref="code"
|
|
20
|
-
input-classes="
|
|
20
|
+
input-classes="bg-gray-50 text-center flex justify-center otp-input border leading-none border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-10 h-10 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
21
21
|
:conditionalClass="['one', 'two', 'three', 'four', 'five', 'six']"
|
|
22
22
|
inputType="number"
|
|
23
23
|
:num-inputs="6"
|
|
24
24
|
v-model:value="bindValue"
|
|
25
25
|
:should-auto-focus="true"
|
|
26
26
|
:should-focus-order="true"
|
|
27
|
-
@on-change="handleOnChange"
|
|
28
27
|
@on-complete="handleOnComplete"
|
|
29
28
|
/>
|
|
30
29
|
</div>
|
|
@@ -98,13 +97,12 @@
|
|
|
98
97
|
|
|
99
98
|
onMounted(async () => {
|
|
100
99
|
coreStore.getPublicConfig();
|
|
101
|
-
window.addEventListener('
|
|
100
|
+
window.addEventListener('paste', handlePaste);
|
|
102
101
|
});
|
|
103
102
|
|
|
104
103
|
onBeforeUnmount(() => {
|
|
105
|
-
window.removeEventListener('
|
|
104
|
+
window.removeEventListener('paste', handlePaste);
|
|
106
105
|
});
|
|
107
|
-
|
|
108
106
|
|
|
109
107
|
async function sendCode (value) {
|
|
110
108
|
inProgress.value = true;
|
|
@@ -129,16 +127,14 @@
|
|
|
129
127
|
// }
|
|
130
128
|
// })
|
|
131
129
|
|
|
132
|
-
function
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
console.error('Failed to read clipboard contents: ', err);
|
|
141
|
-
});
|
|
130
|
+
function handlePaste(event) {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
if (event.target.classList.contains('otp-input')) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const pastedText = event.clipboardData?.getData('text') || '';
|
|
136
|
+
if (pastedText.length === 6) {
|
|
137
|
+
code.value?.fillInput(pastedText);
|
|
142
138
|
}
|
|
143
139
|
}
|
|
144
140
|
</script>
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
<div class="w-full max-w-[46rem]">
|
|
23
23
|
<div class="relative">
|
|
24
24
|
<label for="npm-install-copy-text" class="sr-only">Label</label>
|
|
25
|
-
<input id="npm-install-copy-text" type="text" class="col-span-10 bg-gray-50 border border-gray-300 text-gray-500 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full px-2.5 py-4 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-gray-400 dark:focus:ring-blue-500 dark:focus:border-blue-500" :value="totp.newSecret"
|
|
26
|
-
<button data-copy-to-clipboard-target="npm-install-copy-text" class="absolute end-2.5 top-1/2 -translate-y-1/2 text-gray-900 dark:text-gray-400 hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-600 dark:hover:bg-gray-700 rounded-lg py-2 px-2.5 inline-flex items-center justify-center bg-white border-gray-200 border">
|
|
27
|
-
<span id="default-message" class="inline-flex items-center">
|
|
25
|
+
<input id="npm-install-copy-text" type="text" class="col-span-10 bg-gray-50 border border-gray-300 text-gray-500 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full px-2.5 py-4 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-gray-400 dark:focus:ring-blue-500 dark:focus:border-blue-500 pr-20" :value="totp.newSecret" readonly>
|
|
26
|
+
<button @click="onCopyClick" data-copy-to-clipboard-target="npm-install-copy-text" class="absolute end-2.5 top-1/2 -translate-y-1/2 text-gray-900 dark:text-gray-400 hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-600 dark:hover:bg-gray-700 rounded-lg py-2 px-2.5 inline-flex items-center justify-center bg-white border-gray-200 border">
|
|
27
|
+
<span v-if="isCopied === false" id="default-message" class="inline-flex items-center">
|
|
28
28
|
<svg class="w-3 h-3 me-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 18 20">
|
|
29
29
|
<path d="M16 1h-3.278A1.992 1.992 0 0 0 11 0H7a1.993 1.993 0 0 0-1.722 1H2a2 2 0 0 0-2 2v15a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2Zm-3 14H5a1 1 0 0 1 0-2h8a1 1 0 0 1 0 2Zm0-4H5a1 1 0 0 1 0-2h8a1 1 0 1 1 0 2Zm0-5H5a1 1 0 0 1 0-2h2V2h4v2h2a1 1 0 1 1 0 2Z"/>
|
|
30
30
|
</svg>
|
|
31
|
-
<span
|
|
31
|
+
<span class="text-xs font-semibold">Copy</span>
|
|
32
32
|
</span>
|
|
33
|
-
<span id="success-message" class="
|
|
33
|
+
<span v-if="isCopied === true" id="success-message" class="inline-flex items-center">
|
|
34
34
|
<svg class="w-3 h-3 text-lightPrimary dark:text-darkPrimary me-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 12">
|
|
35
35
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5.917 5.724 10.5 15 1.5"/>
|
|
36
36
|
</svg>
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
<div class="my-4 flex justify-center items-center">
|
|
44
44
|
<v-otp-input
|
|
45
45
|
ref="code"
|
|
46
|
-
input-classes="
|
|
46
|
+
input-classes="bg-gray-50 text-center flex justify-center otp-input border leading-none border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-10 h-10 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
47
47
|
:conditionalClass="['one', 'two', 'three', 'four', 'five', 'six']"
|
|
48
48
|
inputType="number"
|
|
49
49
|
:num-inputs="6"
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
@on-complete="handleOnComplete"
|
|
53
53
|
/>
|
|
54
54
|
</div>
|
|
55
|
-
|
|
56
55
|
<!-- <Vue2FACodeInput v-model="code" autofocus /> -->
|
|
57
56
|
<Button @click="()=>{router.push('./login')}"
|
|
58
57
|
class="w-full">Cancel
|
|
@@ -67,7 +66,7 @@
|
|
|
67
66
|
</template>
|
|
68
67
|
|
|
69
68
|
|
|
70
|
-
<script setup>
|
|
69
|
+
<script setup lang="ts">
|
|
71
70
|
|
|
72
71
|
import { onMounted, onBeforeUnmount, ref, watchEffect,computed,watch } from 'vue';
|
|
73
72
|
import { useCoreStore } from '@/stores/core';
|
|
@@ -81,14 +80,11 @@ import Vue2FACodeInput from '@loltech/vue3-2fa-code-input';
|
|
|
81
80
|
import VOtpInput from "vue3-otp-input";
|
|
82
81
|
|
|
83
82
|
const code = ref(null);
|
|
83
|
+
const isCopied = ref<boolean>(false);
|
|
84
84
|
const handleOnComplete = (value) => {
|
|
85
85
|
sendCode(value);
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
-
const fillInput = (value) => {
|
|
89
|
-
code.value?.fillInput(value);
|
|
90
|
-
};
|
|
91
|
-
|
|
92
88
|
const router = useRouter();
|
|
93
89
|
const inProgress = ref(false);
|
|
94
90
|
|
|
@@ -97,9 +93,6 @@ const user = useUserStore();
|
|
|
97
93
|
|
|
98
94
|
// use this simple function to automatically focus on the next input
|
|
99
95
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
96
|
const showPw = ref(false);
|
|
104
97
|
|
|
105
98
|
const error = ref(null);
|
|
@@ -129,16 +122,11 @@ function parseJwt(token) {
|
|
|
129
122
|
}
|
|
130
123
|
|
|
131
124
|
function onCopyClick(){
|
|
125
|
+
isCopied.value = true;
|
|
126
|
+
navigator.clipboard.writeText(totp.value.newSecret);
|
|
132
127
|
window.adminforth.alert({message: 'Copied to clipboard', variant: 'success'})
|
|
133
128
|
}
|
|
134
129
|
|
|
135
|
-
// watch(code, async (nv)=>{
|
|
136
|
-
// if (nv){
|
|
137
|
-
// console.log(code.value);
|
|
138
|
-
// sendCode();
|
|
139
|
-
// }
|
|
140
|
-
// })
|
|
141
|
-
|
|
142
130
|
onMounted(async () => {
|
|
143
131
|
coreStore.getPublicConfig()
|
|
144
132
|
const resp = await callAdminForthApi({
|
|
@@ -151,11 +139,12 @@ onMounted(async () => {
|
|
|
151
139
|
|
|
152
140
|
totp.value=parseJwt(totpJWT.value);
|
|
153
141
|
|
|
154
|
-
|
|
142
|
+
|
|
143
|
+
window.addEventListener('paste', handlePaste);
|
|
155
144
|
});
|
|
156
145
|
|
|
157
146
|
onBeforeUnmount(() => {
|
|
158
|
-
window.removeEventListener('
|
|
147
|
+
window.removeEventListener('paste', handlePaste);
|
|
159
148
|
});
|
|
160
149
|
|
|
161
150
|
async function sendCode (value) {
|
|
@@ -178,22 +167,19 @@ async function sendCode (value) {
|
|
|
178
167
|
}
|
|
179
168
|
|
|
180
169
|
|
|
181
|
-
function
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
console.error('Failed to read clipboard contents: ', err);
|
|
190
|
-
});
|
|
170
|
+
function handlePaste(event) {
|
|
171
|
+
event.preventDefault();
|
|
172
|
+
if (event.target.classList.contains('otp-input')) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const pastedText = event.clipboardData?.getData('text') || '';
|
|
176
|
+
if (pastedText.length === 6) {
|
|
177
|
+
code.value?.fillInput(pastedText);
|
|
191
178
|
}
|
|
192
179
|
}
|
|
193
180
|
</script>
|
|
194
181
|
<style>
|
|
195
182
|
.otp-input {
|
|
196
183
|
margin: 0 5px;
|
|
197
|
-
|
|
198
184
|
}
|
|
199
185
|
</style>
|
package/package.json
CHANGED
|
File without changes
|