@multiplatform.one/i18n 7.83.1 → 7.84.0

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 (50) hide show
  1. package/dist/cjs/createI18nConfig.cjs +56 -0
  2. package/dist/cjs/createI18nConfig.native.js +59 -0
  3. package/dist/cjs/createI18nConfig.native.js.map +1 -0
  4. package/dist/cjs/detectLanguage.cjs +62 -0
  5. package/dist/cjs/detectLanguage.native.js +95 -0
  6. package/dist/cjs/detectLanguage.native.js.map +1 -0
  7. package/dist/cjs/formatters.cjs +79 -0
  8. package/dist/cjs/formatters.native.js +96 -0
  9. package/dist/cjs/formatters.native.js.map +1 -0
  10. package/dist/cjs/frappeBackend.cjs +51 -0
  11. package/dist/cjs/frappeBackend.native.js +59 -0
  12. package/dist/cjs/frappeBackend.native.js.map +1 -0
  13. package/dist/cjs/index.cjs +45 -0
  14. package/dist/cjs/index.native.js +48 -0
  15. package/dist/cjs/index.native.js.map +1 -0
  16. package/dist/cjs/localePersistence.cjs +46 -0
  17. package/dist/cjs/localePersistence.native.js +52 -0
  18. package/dist/cjs/localePersistence.native.js.map +1 -0
  19. package/dist/cjs/useLanguage.cjs +59 -0
  20. package/dist/cjs/useLanguage.native.js +64 -0
  21. package/dist/cjs/useLanguage.native.js.map +1 -0
  22. package/dist/esm/createI18nConfig.mjs +31 -0
  23. package/dist/esm/createI18nConfig.mjs.map +1 -0
  24. package/dist/esm/createI18nConfig.native.js +31 -0
  25. package/dist/esm/createI18nConfig.native.js.map +1 -0
  26. package/dist/esm/detectLanguage.mjs +37 -0
  27. package/dist/esm/detectLanguage.mjs.map +1 -0
  28. package/dist/esm/detectLanguage.native.js +67 -0
  29. package/dist/esm/detectLanguage.native.js.map +1 -0
  30. package/dist/esm/formatters.mjs +49 -0
  31. package/dist/esm/formatters.mjs.map +1 -0
  32. package/dist/esm/formatters.native.js +63 -0
  33. package/dist/esm/formatters.native.js.map +1 -0
  34. package/dist/esm/frappeBackend.mjs +26 -0
  35. package/dist/esm/frappeBackend.mjs.map +1 -0
  36. package/dist/esm/frappeBackend.native.js +31 -0
  37. package/dist/esm/frappeBackend.native.js.map +1 -0
  38. package/dist/esm/index.mjs +8 -0
  39. package/dist/esm/index.mjs.map +1 -0
  40. package/dist/esm/index.native.js +8 -0
  41. package/dist/esm/index.native.js.map +1 -0
  42. package/dist/esm/localePersistence.mjs +19 -0
  43. package/dist/esm/localePersistence.mjs.map +1 -0
  44. package/dist/esm/localePersistence.native.js +22 -0
  45. package/dist/esm/localePersistence.native.js.map +1 -0
  46. package/dist/esm/useLanguage.mjs +23 -0
  47. package/dist/esm/useLanguage.mjs.map +1 -0
  48. package/dist/esm/useLanguage.native.js +25 -0
  49. package/dist/esm/useLanguage.native.js.map +1 -0
  50. package/package.json +13 -4
@@ -0,0 +1,31 @@
1
+ async function fetchTranslations(language, options) {
2
+ var _options_baseUrl, _options_fetch, _data_message;
3
+ var base = (_options_baseUrl = options.baseUrl) !== null && _options_baseUrl !== void 0 ? _options_baseUrl : "";
4
+ var fetchFn = (_options_fetch = options.fetch) !== null && _options_fetch !== void 0 ? _options_fetch : globalThis.fetch;
5
+ var url = `${base}/api/method/frappe.translate.get_dict?language=${encodeURIComponent(language)}`;
6
+ var res = await fetchFn(url, {
7
+ credentials: "include"
8
+ });
9
+ if (!res.ok) throw new Error(`Frappe translation fetch failed: ${res.status}`);
10
+ var data = await res.json();
11
+ return (_data_message = data.message) !== null && _data_message !== void 0 ? _data_message : {};
12
+ }
13
+ function createFrappeBackend() {
14
+ if (process.env.VITE_FRAPPE_ENABLED !== "true") return null;
15
+ var opts = {};
16
+ return {
17
+ type: "backend",
18
+ init(_services, backendOptions, _i18nextOptions) {
19
+ opts = backendOptions !== null && backendOptions !== void 0 ? backendOptions : {};
20
+ },
21
+ read(language, _namespace, callback) {
22
+ fetchTranslations(language, opts).then(function (translations) {
23
+ return callback(null, translations);
24
+ }).catch(function (err) {
25
+ return callback(err, null);
26
+ });
27
+ }
28
+ };
29
+ }
30
+ export { createFrappeBackend };
31
+ //# sourceMappingURL=frappeBackend.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["fetchTranslations","language","options","_options_baseUrl","_options_fetch","_data_message","base","baseUrl","fetchFn","fetch","globalThis","url","encodeURIComponent","res","credentials","ok","Error","status","data","json","message","createFrappeBackend","process","env","VITE_FRAPPE_ENABLED","opts","type","init","_services","backendOptions","_i18nextOptions","read","_namespace","callback","then","translations"],"sources":["../../src/frappeBackend.ts"],"sourcesContent":[null],"mappings":"AAcA,eAAeA,kBACbC,QAAA,EACAC,OAAA,EACiC;EACjC,IAAAC,gBAAa,EAAQC,cAAW,EAAAC,aAAA;EAChC,IAAAC,IAAM,IAAAH,gBAAkB,GAAAD,OAAS,CAAAK,OAAW,cAAAJ,gBAAA,cAAAA,gBAAA;EAC5C,IAAAK,OAAM,GAAM,CAAGJ,cAAI,GAAAF,OAAA,CAAAO,KAAA,cAAAL,cAAkD,cAAAA,cAA4B,GAAAM,UAAA,CAAAD,KAAA;EACjG,IAAAE,GAAM,MAAML,IAAA,kDAA6CM,kBAAA,CAAAX,QAAA;EACzD,IAAIY,GAAC,GAAI,MAAIL,OAAU,CAAAG,GAAA,EAAM;IAC7BG,WAAwC;EACxC;EACF,KAAAD,GAAA,CAAAE,EAAA,YAAAC,KAAA,qCAAAH,GAAA,CAAAI,MAAA;EAMA,IAAAC,IAAS,SAAAL,GAAA,CAAAM,IAAA;EACP,OAAI,CAAAd,aAAY,GAAAa,IAAA,CAAAE,OAAA,MAAwB,QAAQf,aAAO,cAAAA,aAAA;AAEvD;AAEA,SAAOgB,oBAAA;EAAA,IACLC,OAAM,CAAAC,GAAA,CAAAC,mBAAA;EAAA,IACNC,IAAK;EACH;IACFC,IAAA;IACAC,KAAKC,SAAA,EAAkBC,cAAoB,EAAAC,eAAwB;MACjEL,IAAA,GAAAI,cAAkB,SAAU,IACzBA,cAAM,UAAiB,IAAAA,cAAe;IAE3C;IACFE,KAAA9B,QAAA,EAAA+B,UAAA,EAAAC,QAAA;MACFjC,iBAAA,CAAAC,QAAA,EAAAwB,IAAA,EAAAS,IAAA,WAAAC,YAAA","ignoreList":[]}
@@ -0,0 +1,8 @@
1
+ import { createI18nConfig } from "./createI18nConfig.mjs";
2
+ import { createFrappeBackend } from "./frappeBackend.mjs";
3
+ import { useLanguage } from "./useLanguage.mjs";
4
+ import { getPersistedLanguage, persistLanguage, parseCookieValue } from "./localePersistence.mjs";
5
+ import { detectLanguage } from "./detectLanguage.mjs";
6
+ import { useFormatDate, useFormatNumber, useFormatCurrency, createDateFormatter, createNumberFormatter, createCurrencyFormatter } from "./formatters.mjs";
7
+ export { createCurrencyFormatter, createDateFormatter, createFrappeBackend, createI18nConfig, createNumberFormatter, detectLanguage, getPersistedLanguage, parseCookieValue, persistLanguage, useFormatCurrency, useFormatDate, useFormatNumber, useLanguage };
8
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["createI18nConfig","createFrappeBackend","useLanguage","getPersistedLanguage","persistLanguage","parseCookieValue","detectLanguage","useFormatDate","useFormatNumber","useFormatCurrency","createDateFormatter","createNumberFormatter","createCurrencyFormatter"],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA,SAASA,gBAAA,QAAwB;AAEjC,SAASC,mBAAA,QAA2B;AAEpC,SAASC,WAAA,QAAmB;AAC5B,SAASC,oBAAA,EAAsBC,eAAA,EAAiBC,gBAAA,QAAwB;AACxE,SAASC,cAAA,QAAsB;AAC/B,SACEC,aAAA,EACAC,eAAA,EACAC,iBAAA,EACAC,mBAAA,EACAC,qBAAA,EACAC,uBAAA,QACK","ignoreList":[]}
@@ -0,0 +1,8 @@
1
+ import { createI18nConfig } from "./createI18nConfig.native.js";
2
+ import { createFrappeBackend } from "./frappeBackend.native.js";
3
+ import { useLanguage } from "./useLanguage.native.js";
4
+ import { getPersistedLanguage, persistLanguage, parseCookieValue } from "./localePersistence.native.js";
5
+ import { detectLanguage } from "./detectLanguage.native.js";
6
+ import { useFormatDate, useFormatNumber, useFormatCurrency, createDateFormatter, createNumberFormatter, createCurrencyFormatter } from "./formatters.native.js";
7
+ export { createCurrencyFormatter, createDateFormatter, createFrappeBackend, createI18nConfig, createNumberFormatter, detectLanguage, getPersistedLanguage, parseCookieValue, persistLanguage, useFormatCurrency, useFormatDate, useFormatNumber, useLanguage };
8
+ //# sourceMappingURL=index.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["createI18nConfig","createFrappeBackend","useLanguage","getPersistedLanguage","persistLanguage","parseCookieValue","detectLanguage","useFormatDate","useFormatNumber","useFormatCurrency","createDateFormatter","createNumberFormatter","createCurrencyFormatter"],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA,SAASA,gBAAA,QAAwB;AAEjC,SAASC,mBAAA,QAA2B;AAEpC,SAASC,WAAA,QAAmB;AAC5B,SAASC,oBAAA,EAAsBC,eAAA,EAAiBC,gBAAA,QAAwB;AACxE,SAASC,cAAA,QAAsB;AAC/B,SAAAC,aAAA,EAAAC,eAAA,EAAAC,iBAAA,EAAAC,mBAAA,EAAAC,qBAAA,EAAAC,uBAAA;AAAA,SAEEA,uBAAA,EACAF,mBAAA,EACAT,mBAAA,EACAD,gBAAA,EACAW,qBAAA,EAAAL,cACK,E","ignoreList":[]}
@@ -0,0 +1,19 @@
1
+ import { getCookie, setCookie } from "@multiplatform.one/platform";
2
+ const cookieName = "preferred_language";
3
+ function getPersistedLanguage() {
4
+ return getCookie(cookieName);
5
+ }
6
+ function persistLanguage(lang) {
7
+ setCookie(cookieName, lang, {
8
+ days: 365,
9
+ sameSite: "Lax"
10
+ });
11
+ }
12
+ function parseCookieValue(cookieHeader, name) {
13
+ const match = cookieHeader.split(";").find(c => c.trim().startsWith(`${name}=`));
14
+ if (!match) return null;
15
+ const val = match.split("=")[1]?.trim();
16
+ return val ? decodeURIComponent(val) : null;
17
+ }
18
+ export { getPersistedLanguage, parseCookieValue, persistLanguage };
19
+ //# sourceMappingURL=localePersistence.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["getCookie","setCookie","cookieName","getPersistedLanguage","persistLanguage","lang","days","sameSite","parseCookieValue","cookieHeader","name","match","split","find","c","trim","startsWith","val","decodeURIComponent"],"sources":["../../src/localePersistence.ts"],"sourcesContent":[null],"mappings":"AAAA,SAASA,SAAA,EAAWC,SAAA,QAAiB;AAGrC,MAAMC,UAAA,GAAa;AAGZ,SAASC,qBAAA,EAAsC;EACpD,OAAOH,SAAA,CAAUE,UAAU;AAC7B;AAGO,SAASE,gBAAgBC,IAAA,EAAoB;EAClDJ,SAAA,CAAUC,UAAA,EAAYG,IAAA,EAAM;IAAEC,IAAA,EAAM;IAAKC,QAAA,EAAU;EAAM,CAAC;AAC5D;AAGO,SAASC,iBAAiBC,YAAA,EAAsBC,IAAA,EAA6B;EAClF,MAAMC,KAAA,GAAQF,YAAA,CAAaG,KAAA,CAAM,GAAG,EAAEC,IAAA,CAAMC,CAAA,IAAMA,CAAA,CAAEC,IAAA,CAAK,EAAEC,UAAA,CAAW,GAAGN,IAAI,GAAG,CAAC;EACjF,IAAI,CAACC,KAAA,EAAO,OAAO;EACnB,MAAMM,GAAA,GAAMN,KAAA,CAAMC,KAAA,CAAM,GAAG,EAAE,CAAC,GAAGG,IAAA,CAAK;EACtC,OAAOE,GAAA,GAAMC,kBAAA,CAAmBD,GAAG,IAAI;AACzC","ignoreList":[]}
@@ -0,0 +1,22 @@
1
+ import { getCookie, setCookie } from "@multiplatform.one/platform";
2
+ var cookieName = "preferred_language";
3
+ function getPersistedLanguage() {
4
+ return getCookie(cookieName);
5
+ }
6
+ function persistLanguage(lang) {
7
+ setCookie(cookieName, lang, {
8
+ days: 365,
9
+ sameSite: "Lax"
10
+ });
11
+ }
12
+ function parseCookieValue(cookieHeader, name) {
13
+ var _match_split_;
14
+ var match = cookieHeader.split(";").find(function (c) {
15
+ return c.trim().startsWith(`${name}=`);
16
+ });
17
+ if (!match) return null;
18
+ var val = (_match_split_ = match.split("=")[1]) === null || _match_split_ === void 0 ? void 0 : _match_split_.trim();
19
+ return val ? decodeURIComponent(val) : null;
20
+ }
21
+ export { getPersistedLanguage, parseCookieValue, persistLanguage };
22
+ //# sourceMappingURL=localePersistence.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["getCookie","setCookie","cookieName","getPersistedLanguage","persistLanguage","lang","days","sameSite","parseCookieValue","cookieHeader","name","_match_split_","match","split","find","c"],"sources":["../../src/localePersistence.ts"],"sourcesContent":[null],"mappings":"AAAA,SAASA,SAAA,EAAWC,SAAA,QAAiB;AAGrC,IAAAC,UAAM,uBAAa;AAGZ,SAASC,qBAAA,EAAsC;EACpD,OAAOH,SAAA,CAAUE,UAAU;AAC7B;AAGO,SAASE,gBAAgBC,IAAA,EAAoB;EAClDJ,SAAA,CAAUC,UAAA,EAAYG,IAAA,EAAM;IAC9BC,IAAA;IAGOC,QAAS;EACd;AACA;AACA,SAAMC,gBAAYA,CAAMC,YAAS,EAAKC,IAAA;EACtC,IAAAC,aAAa;EACf,IAAAC,KAAA,GAAAH,YAAA,CAAAI,KAAA,MAAAC,IAAA,WAAAC,CAAA","ignoreList":[]}
@@ -0,0 +1,23 @@
1
+ import i18n from "i18next";
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import { getPersistedLanguage, persistLanguage } from "./localePersistence.mjs";
4
+ function useLanguage() {
5
+ const [language, setLanguage] = useState(() => {
6
+ return getPersistedLanguage() || i18n?.language || "en";
7
+ });
8
+ useEffect(() => {
9
+ const persisted = getPersistedLanguage();
10
+ if (persisted && persisted !== i18n?.language) {
11
+ i18n?.changeLanguage(persisted);
12
+ }
13
+ i18n.on("languageChanged", setLanguage);
14
+ return () => i18n.off("languageChanged", setLanguage);
15
+ }, []);
16
+ const changeLanguage = useCallback(lang => {
17
+ persistLanguage(lang);
18
+ i18n?.changeLanguage(lang);
19
+ }, []);
20
+ return [language, changeLanguage];
21
+ }
22
+ export { useLanguage };
23
+ //# sourceMappingURL=useLanguage.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["i18n","useCallback","useEffect","useState","getPersistedLanguage","persistLanguage","useLanguage","language","setLanguage","persisted","changeLanguage","on","off","lang"],"sources":["../../src/useLanguage.ts"],"sourcesContent":[null],"mappings":"AAAA,OAAOA,IAAA,MAAU;AACjB,SAASC,WAAA,EAAaC,SAAA,EAAWC,QAAA,QAAgB;AACjD,SAASC,oBAAA,EAAsBC,eAAA,QAAuB;AAE/C,SAASC,YAAA,EAAkD;EAChE,MAAM,CAACC,QAAA,EAAUC,WAAW,IAAIL,QAAA,CAAS,MAAM;IAE7C,OAAOC,oBAAA,CAAqB,KAAKJ,IAAA,EAAMO,QAAA,IAAY;EACrD,CAAC;EAEDL,SAAA,CAAU,MAAM;IAEd,MAAMO,SAAA,GAAYL,oBAAA,CAAqB;IACvC,IAAIK,SAAA,IAAaA,SAAA,KAAcT,IAAA,EAAMO,QAAA,EAAU;MAC7CP,IAAA,EAAMU,cAAA,CAAeD,SAAS;IAChC;IACAT,IAAA,CAAKW,EAAA,CAAG,mBAAmBH,WAAW;IACtC,OAAO,MAAMR,IAAA,CAAKY,GAAA,CAAI,mBAAmBJ,WAAW;EACtD,GAAG,EAAE;EAEL,MAAME,cAAA,GAAiBT,WAAA,CAAaY,IAAA,IAAiB;IACnDR,eAAA,CAAgBQ,IAAI;IACpBb,IAAA,EAAMU,cAAA,CAAeG,IAAI;EAC3B,GAAG,EAAE;EAEL,OAAO,CAACN,QAAA,EAAUG,cAAc;AAClC","ignoreList":[]}
@@ -0,0 +1,25 @@
1
+ import i18n from "i18next";
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import { getPersistedLanguage, persistLanguage } from "./localePersistence.native.js";
4
+ function useLanguage() {
5
+ var [language, setLanguage] = useState(function () {
6
+ return getPersistedLanguage() || (i18n === null || i18n === void 0 ? void 0 : i18n.language) || "en";
7
+ });
8
+ useEffect(function () {
9
+ var persisted = getPersistedLanguage();
10
+ if (persisted && persisted !== (i18n === null || i18n === void 0 ? void 0 : i18n.language)) {
11
+ i18n === null || i18n === void 0 ? void 0 : i18n.changeLanguage(persisted);
12
+ }
13
+ i18n.on("languageChanged", setLanguage);
14
+ return function () {
15
+ return i18n.off("languageChanged", setLanguage);
16
+ };
17
+ }, []);
18
+ var changeLanguage = useCallback(function (lang) {
19
+ persistLanguage(lang);
20
+ i18n === null || i18n === void 0 ? void 0 : i18n.changeLanguage(lang);
21
+ }, []);
22
+ return [language, changeLanguage];
23
+ }
24
+ export { useLanguage };
25
+ //# sourceMappingURL=useLanguage.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["i18n","useCallback","useEffect","useState","getPersistedLanguage","persistLanguage","useLanguage","language","setLanguage","persisted","changeLanguage","on","off","lang"],"sources":["../../src/useLanguage.ts"],"sourcesContent":[null],"mappings":"AAAA,OAAOA,IAAA,MAAU;AACjB,SAASC,WAAA,EAAaC,SAAA,EAAWC,QAAA,QAAgB;AACjD,SAASC,oBAAA,EAAsBC,eAAA,QAAuB;AAE/C,SAASC,YAAA,EAAkD;EAChE,KAAAC,QAAO,EAAAC,WAAU,IAAWL,QAAI,aAAe;IAE7C,OAAOC,oBAAA,CAAqB,MAAKJ,IAAA,KAAM,QAAYA,IAAA,uBAAAA,IAAA,CAAAO,QAAA;EACrD,CAAC;EAEDL,SAAA,CAAU,YAAM;IAEd,IAAAO,SAAM,GAAAL,oBAAY;IAClB,IAAIK,SAAA,IAAaA,SAAA,MAAcT,IAAA,KAAM,QAAUA,IAAA,uBAAAA,IAAA,CAAAO,QAAA;MAC7CP,IAAA,KAAM,QAAAA,IAAe,UAAS,aAAAA,IAAA,CAAAU,cAAA,CAAAD,SAAA;IAChC;IACAT,IAAA,CAAKW,EAAA,CAAG,mBAAmBH,WAAW;IACtC,OAAO,YAAW;MAChB,OAACR,IAAA,CAAAY,GAAA,oBAAAJ,WAAA;IAEL;EACE;EACA,IAAAE,cAAM,GAAAT,WAAmB,WAAAY,IAAA;IAC3BR,eAAK,CAAAQ,IAAA;IAELb,IAAA,KAAQ,QAAUA,IAAA,UAAc,aAAAA,IAAA,CAAAU,cAAA,CAAAG,IAAA;EAClC","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multiplatform.one/i18n",
3
- "version": "7.83.1",
3
+ "version": "7.84.0",
4
4
  "description": "Internationalization utilities and hooks for multiplatform.one",
5
5
  "keywords": [
6
6
  "i18n",
@@ -17,6 +17,7 @@
17
17
  },
18
18
  "source": "src/index.ts",
19
19
  "files": [
20
+ "dist",
20
21
  "src",
21
22
  "types",
22
23
  "!types/.tsbuildinfo"
@@ -30,16 +31,24 @@
30
31
  ".": {
31
32
  "source": "./src/index.ts",
32
33
  "types": "./types/index.d.ts",
33
- "default": "./src/index.ts"
34
+ "react-native": {
35
+ "types": "./types/index.d.ts",
36
+ "import": "./dist/esm/index.native.js",
37
+ "require": "./dist/cjs/index.native.js"
38
+ },
39
+ "import": "./dist/esm/index.mjs",
40
+ "require": "./dist/cjs/index.cjs",
41
+ "default": "./dist/esm/index.mjs"
34
42
  }
35
43
  },
36
44
  "publishConfig": {
37
45
  "access": "public"
38
46
  },
39
47
  "dependencies": {
40
- "@multiplatform.one/platform": "^7.83.1"
48
+ "@multiplatform.one/platform": "^7.84.0"
41
49
  },
42
50
  "devDependencies": {
51
+ "@tamagui/build": "2.7.6",
43
52
  "i18next": "^25.10.10",
44
53
  "react": "19.2.5",
45
54
  "typescript": "~5.9.3"
@@ -50,7 +59,7 @@
50
59
  },
51
60
  "scripts": {
52
61
  "typecheck": "tsgo --noEmit",
53
- "build": "rm -rf types 2>/dev/null && tsc -p tsconfig.build.json",
62
+ "build": "rm -rf dist types 2>/dev/null && tamagui-build --ts-project ./tsconfig.build.json --exclude '\\.spec\\.|\\.test\\.|\\.stories\\.'",
54
63
  "test": "vitest run --coverage --coverage.provider=v8 --coverage.reporter=text --coverage.reporter=lcov --coverage.reporter=html"
55
64
  }
56
65
  }