@procedures/weather 0.27.8 → 0.28.1

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/module.d.ts CHANGED
@@ -2,8 +2,14 @@
2
2
  * The procedures of @procedures/weather as data. Importing this file registers nothing.
3
3
  */
4
4
  import { type ProcedureModule, type ProcedureRegistry } from "@procedures/client";
5
+ import { type WeatherProceduresOptions } from "./procedures.js";
5
6
  export declare const weatherModule: ProcedureModule;
6
7
  export default weatherModule;
8
+ /**
9
+ * This function gives the module with the settings of the host: the `fetch` of the requests.
10
+ * Without options, it gives `weatherModule`.
11
+ */
12
+ export declare function createWeatherModule(options?: WeatherProceduresOptions): ProcedureModule;
7
13
  /**
8
14
  * This function registers the procedures of @procedures/weather in a registry. The default is the
9
15
  * global registry.
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAqD,KAAK,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAGrI,eAAO,MAAM,aAAa,EAAE,eAAwE,CAAC;eAEtF,aAAa;AAE5B;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,GAAE,iBAAsC,GAAG,IAAI,CAEhG"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAqD,KAAK,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACrI,OAAO,EAA8C,KAAK,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAE5G,eAAO,MAAM,aAAa,EAAE,eAAwE,CAAC;eAEtF,aAAa;AAE5B;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,wBAA6B,GAAG,eAAe,CAG3F;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,GAAE,iBAAsC,GAAG,IAAI,CAEhG"}
package/dist/module.js CHANGED
@@ -2,9 +2,18 @@
2
2
  * The procedures of @procedures/weather as data. Importing this file registers nothing.
3
3
  */
4
4
  import { defineModule, registerModules, PROCEDURE_REGISTRY } from "@procedures/client";
5
- import { weatherProcedures } from "./procedures.js";
5
+ import { createWeatherProcedures, weatherProcedures } from "./procedures.js";
6
6
  export const weatherModule = defineModule("@procedures/weather", weatherProcedures);
7
7
  export default weatherModule;
8
+ /**
9
+ * This function gives the module with the settings of the host: the `fetch` of the requests.
10
+ * Without options, it gives `weatherModule`.
11
+ */
12
+ export function createWeatherModule(options = {}) {
13
+ if (options.fetch === undefined)
14
+ return weatherModule;
15
+ return defineModule("@procedures/weather", createWeatherProcedures(options));
16
+ }
8
17
  /**
9
18
  * This function registers the procedures of @procedures/weather in a registry. The default is the
10
19
  * global registry.
@@ -1 +1 @@
1
- {"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAgD,MAAM,oBAAoB,CAAC;AACrI,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,CAAC,MAAM,aAAa,GAAoB,YAAY,CAAC,qBAAqB,EAAE,iBAAiB,CAAC,CAAC;AAErG,eAAe,aAAa,CAAC;AAE7B;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAAQ,GAAsB,kBAAkB;IACxF,eAAe,CAAC,QAAQ,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;AAC7C,CAAC"}
1
+ {"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAgD,MAAM,oBAAoB,CAAC;AACrI,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAiC,MAAM,iBAAiB,CAAC;AAE5G,MAAM,CAAC,MAAM,aAAa,GAAoB,YAAY,CAAC,qBAAqB,EAAE,iBAAiB,CAAC,CAAC;AAErG,eAAe,aAAa,CAAC;AAE7B;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAO,GAA6B,EAAE;IACxE,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;QAAE,OAAO,aAAa,CAAC;IACtD,OAAO,YAAY,CAAC,qBAAqB,EAAE,uBAAuB,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAAQ,GAAsB,kBAAkB;IACxF,eAAe,CAAC,QAAQ,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;AAC7C,CAAC"}
@@ -1,7 +1,44 @@
1
1
  /**
2
2
  * The procedure of `@procedures/weather`: `weather.forecast`.
3
+ *
4
+ * The request goes through the host policy of `@procedures/http` (audit pass 2, O55). In 0.28, a
5
+ * `baseUrl` on a loopback, private or link-local address still works, with a deprecation notice.
6
+ * Version 0.29.0 refuses it, unless the host allows it.
3
7
  */
4
8
  import { type AnyProcedure } from "@procedures/client";
5
- export declare const weatherForecastProcedure: AnyProcedure;
9
+ import { type DeprecationNotice } from "@procedures/http";
10
+ /**
11
+ * The deprecation notice of the default module: a `baseUrl` on a host that the host policy refuses.
12
+ * The default module sends the request with the global `fetch`, as before. Version 0.29.0 refuses it.
13
+ */
14
+ export declare const WEATHER_PRIVATE_HOST_NOTICE: DeprecationNotice;
15
+ /**
16
+ * The part of `fetch` that `weather.forecast` uses. The default is `createHostFetch()` of
17
+ * `@procedures/http`, with the notice `WEATHER_PRIVATE_HOST_NOTICE` for a refused host.
18
+ */
19
+ export type FetchForecast = (url: string, init: {
20
+ headers: Record<string, string>;
21
+ signal: AbortSignal;
22
+ }) => Promise<{
23
+ ok: boolean;
24
+ status: number;
25
+ json(): Promise<unknown>;
26
+ }>;
27
+ /** The settings of the host for the procedures of this package. The procedure input cannot change them. */
28
+ export interface WeatherProceduresOptions {
29
+ /**
30
+ * The function that sends the request. The default is `createHostFetch()` with a notice for a
31
+ * refused host. A host with its own Open-Meteo server on a private address gives
32
+ * `createHostFetch({ allow: ["10.0.0.5:8080"] })`.
33
+ */
34
+ readonly fetch?: FetchForecast | undefined;
35
+ }
36
+ /**
37
+ * This function gives the procedures of this package with the settings of the host. Without
38
+ * options, the requests go through the default host policy of `@procedures/http`, and a refused
39
+ * host gets the notice `WEATHER_PRIVATE_HOST_NOTICE`.
40
+ */
41
+ export declare function createWeatherProcedures(options?: WeatherProceduresOptions): AnyProcedure[];
6
42
  export declare const weatherProcedures: AnyProcedure[];
43
+ export declare const weatherForecastProcedure: AnyProcedure;
7
44
  //# sourceMappingURL=procedures.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"procedures.d.ts","sourceRoot":"","sources":["../src/procedures.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAA+B,KAAK,YAAY,EAAyB,MAAM,oBAAoB,CAAC;AAkC3G,eAAO,MAAM,wBAAwB,EAAE,YAqBb,CAAC;AAE3B,eAAO,MAAM,iBAAiB,EAAE,YAAY,EAA+B,CAAC"}
1
+ {"version":3,"file":"procedures.d.ts","sourceRoot":"","sources":["../src/procedures.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAA+B,KAAK,YAAY,EAAyB,MAAM,oBAAoB,CAAC;AAC3G,OAAO,EAAqC,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAI7F;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAE,iBAKzC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,KAC3D,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,CAAC,CAAC;AAExE,2GAA2G;AAC3G,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;CAC5C;AAgCD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,wBAA6B,GAAG,YAAY,EAAE,CA2B9F;AAED,eAAO,MAAM,iBAAiB,EAAE,YAAY,EAA8B,CAAC;AAE3E,eAAO,MAAM,wBAAwB,EAAE,YAAoC,CAAC"}
@@ -1,9 +1,23 @@
1
1
  /**
2
2
  * The procedure of `@procedures/weather`: `weather.forecast`.
3
+ *
4
+ * The request goes through the host policy of `@procedures/http` (audit pass 2, O55). In 0.28, a
5
+ * `baseUrl` on a loopback, private or link-local address still works, with a deprecation notice.
6
+ * Version 0.29.0 refuses it, unless the host allows it.
3
7
  */
4
8
  import { createProcedure, zodAdapter } from "@procedures/client";
9
+ import { createHostFetch, isHostNotAllowed } from "@procedures/http";
5
10
  import { z } from "zod";
6
11
  import { forecastUrl, readForecast } from "./weather.js";
12
+ /**
13
+ * The deprecation notice of the default module: a `baseUrl` on a host that the host policy refuses.
14
+ * The default module sends the request with the global `fetch`, as before. Version 0.29.0 refuses it.
15
+ */
16
+ export const WEATHER_PRIVATE_HOST_NOTICE = {
17
+ code: "PROCEDURES_WEATHER_PRIVATE_HOST",
18
+ message: "weather.forecast sent a request to a loopback, private or link-local host. @procedures/weather 0.29.0 refuses such a host. " +
19
+ "To keep this server, give createWeatherModule({ fetch: createHostFetch({ allow: [...] }) }) with the host and port of the server.",
20
+ };
7
21
  const ForecastInputSchema = z.object({
8
22
  lat: z.number().min(-90).max(90).describe("The latitude of the point, in degrees"),
9
23
  lon: z.number().min(-180).max(180).describe("The longitude of the point, in degrees"),
@@ -29,29 +43,42 @@ const ForecastOutputSchema = z.object({
29
43
  .array(z.object({ time: z.string(), temperature: nullableNumber, precipitationProbability: nullableNumber, weatherCode: nullableNumber }))
30
44
  .optional(),
31
45
  });
32
- export const weatherForecastProcedure = createProcedure()
33
- .path(["weather", "forecast"])
34
- .input(zodAdapter(ForecastInputSchema))
35
- .output(zodAdapter(ForecastOutputSchema))
36
- .meta({
37
- description: "Give the weather forecast of a point for each day, and optionally each hour (Open-Meteo)",
38
- output: "json",
39
- effects: { reads: ["network"], writes: [] },
40
- })
41
- .handler(async (input, ctx) => {
42
- const signals = [AbortSignal.timeout(input.timeoutMs), ...(ctx?.signal ? [ctx.signal] : [])];
43
- let response;
44
- try {
45
- response = await fetch(forecastUrl(input), { signal: AbortSignal.any(signals), headers: { accept: "application/json" } });
46
- }
47
- catch (error) {
48
- const reason = error.name === "TimeoutError" ? `no answer in ${input.timeoutMs} ms` : "the request failed";
49
- throw new Error(`Open-Meteo did not answer: ${reason}`);
50
- }
51
- if (!response.ok)
52
- throw new Error(`Open-Meteo gave HTTP ${response.status}`);
53
- return readForecast(await response.json(), input.hourly);
54
- })
55
- .build();
56
- export const weatherProcedures = [weatherForecastProcedure];
46
+ /**
47
+ * This function gives the procedures of this package with the settings of the host. Without
48
+ * options, the requests go through the default host policy of `@procedures/http`, and a refused
49
+ * host gets the notice `WEATHER_PRIVATE_HOST_NOTICE`.
50
+ */
51
+ export function createWeatherProcedures(options = {}) {
52
+ const fetchForecast = options.fetch ?? createHostFetch({ warnOnRefusal: WEATHER_PRIVATE_HOST_NOTICE });
53
+ const forecast = createProcedure()
54
+ .path(["weather", "forecast"])
55
+ .input(zodAdapter(ForecastInputSchema))
56
+ .output(zodAdapter(ForecastOutputSchema))
57
+ .meta({
58
+ description: "Give the weather forecast of a point for each day, and optionally each hour (Open-Meteo)",
59
+ output: "json",
60
+ effects: { reads: ["network"], writes: [] },
61
+ })
62
+ .handler(async (input, ctx) => {
63
+ const signals = [AbortSignal.timeout(input.timeoutMs), ...(ctx?.signal ? [ctx.signal] : [])];
64
+ let response;
65
+ try {
66
+ response = await fetchForecast(forecastUrl(input), { signal: AbortSignal.any(signals), headers: { accept: "application/json" } });
67
+ }
68
+ catch (error) {
69
+ // A refusal of the host policy keeps its code and its reason
70
+ if (isHostNotAllowed(error))
71
+ throw error;
72
+ const reason = error.name === "TimeoutError" ? `no answer in ${input.timeoutMs} ms` : "the request failed";
73
+ throw new Error(`Open-Meteo did not answer: ${reason}`);
74
+ }
75
+ if (!response.ok)
76
+ throw new Error(`Open-Meteo gave HTTP ${response.status}`);
77
+ return readForecast(await response.json(), input.hourly);
78
+ })
79
+ .build();
80
+ return [forecast];
81
+ }
82
+ export const weatherProcedures = createWeatherProcedures();
83
+ export const weatherForecastProcedure = weatherProcedures[0];
57
84
  //# sourceMappingURL=procedures.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"procedures.js","sourceRoot":"","sources":["../src/procedures.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"procedures.js","sourceRoot":"","sources":["../src/procedures.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@procedures/weather",
4
- "version": "0.27.8",
4
+ "version": "0.28.1",
5
5
  "description": "A weather forecast for a point from Open-Meteo, without a key: each day and each hour, metric or imperial.",
6
6
  "keywords": [
7
7
  "weather",
@@ -56,7 +56,8 @@
56
56
  "provenance": true
57
57
  },
58
58
  "dependencies": {
59
- "@procedures/client": "0.27.8",
59
+ "@procedures/client": "0.28.1",
60
+ "@procedures/http": "0.28.1",
60
61
  "zod": "^4.6.5"
61
62
  },
62
63
  "devDependencies": {
package/src/module.ts CHANGED
@@ -3,12 +3,21 @@
3
3
  */
4
4
 
5
5
  import { defineModule, registerModules, PROCEDURE_REGISTRY, type ProcedureModule, type ProcedureRegistry } from "@procedures/client";
6
- import { weatherProcedures } from "./procedures.js";
6
+ import { createWeatherProcedures, weatherProcedures, type WeatherProceduresOptions } from "./procedures.js";
7
7
 
8
8
  export const weatherModule: ProcedureModule = defineModule("@procedures/weather", weatherProcedures);
9
9
 
10
10
  export default weatherModule;
11
11
 
12
+ /**
13
+ * This function gives the module with the settings of the host: the `fetch` of the requests.
14
+ * Without options, it gives `weatherModule`.
15
+ */
16
+ export function createWeatherModule(options: WeatherProceduresOptions = {}): ProcedureModule {
17
+ if (options.fetch === undefined) return weatherModule;
18
+ return defineModule("@procedures/weather", createWeatherProcedures(options));
19
+ }
20
+
12
21
  /**
13
22
  * This function registers the procedures of @procedures/weather in a registry. The default is the
14
23
  * global registry.
package/src/procedures.ts CHANGED
@@ -1,11 +1,46 @@
1
1
  /**
2
2
  * The procedure of `@procedures/weather`: `weather.forecast`.
3
+ *
4
+ * The request goes through the host policy of `@procedures/http` (audit pass 2, O55). In 0.28, a
5
+ * `baseUrl` on a loopback, private or link-local address still works, with a deprecation notice.
6
+ * Version 0.29.0 refuses it, unless the host allows it.
3
7
  */
4
8
 
5
9
  import { createProcedure, zodAdapter, type AnyProcedure, type ProcedureContext } from "@procedures/client";
10
+ import { createHostFetch, isHostNotAllowed, type DeprecationNotice } from "@procedures/http";
6
11
  import { z } from "zod";
7
12
  import { forecastUrl, readForecast, type Forecast } from "./weather.js";
8
13
 
14
+ /**
15
+ * The deprecation notice of the default module: a `baseUrl` on a host that the host policy refuses.
16
+ * The default module sends the request with the global `fetch`, as before. Version 0.29.0 refuses it.
17
+ */
18
+ export const WEATHER_PRIVATE_HOST_NOTICE: DeprecationNotice = {
19
+ code: "PROCEDURES_WEATHER_PRIVATE_HOST",
20
+ message:
21
+ "weather.forecast sent a request to a loopback, private or link-local host. @procedures/weather 0.29.0 refuses such a host. " +
22
+ "To keep this server, give createWeatherModule({ fetch: createHostFetch({ allow: [...] }) }) with the host and port of the server.",
23
+ };
24
+
25
+ /**
26
+ * The part of `fetch` that `weather.forecast` uses. The default is `createHostFetch()` of
27
+ * `@procedures/http`, with the notice `WEATHER_PRIVATE_HOST_NOTICE` for a refused host.
28
+ */
29
+ export type FetchForecast = (
30
+ url: string,
31
+ init: { headers: Record<string, string>; signal: AbortSignal }
32
+ ) => Promise<{ ok: boolean; status: number; json(): Promise<unknown> }>;
33
+
34
+ /** The settings of the host for the procedures of this package. The procedure input cannot change them. */
35
+ export interface WeatherProceduresOptions {
36
+ /**
37
+ * The function that sends the request. The default is `createHostFetch()` with a notice for a
38
+ * refused host. A host with its own Open-Meteo server on a private address gives
39
+ * `createHostFetch({ allow: ["10.0.0.5:8080"] })`.
40
+ */
41
+ readonly fetch?: FetchForecast | undefined;
42
+ }
43
+
9
44
  const ForecastInputSchema = z.object({
10
45
  lat: z.number().min(-90).max(90).describe("The latitude of the point, in degrees"),
11
46
  lon: z.number().min(-180).max(180).describe("The longitude of the point, in degrees"),
@@ -36,27 +71,40 @@ const ForecastOutputSchema = z.object({
36
71
  .optional(),
37
72
  });
38
73
 
39
- export const weatherForecastProcedure: AnyProcedure = createProcedure()
40
- .path(["weather", "forecast"])
41
- .input(zodAdapter<ForecastInput>(ForecastInputSchema))
42
- .output(zodAdapter<Forecast>(ForecastOutputSchema))
43
- .meta({
44
- description: "Give the weather forecast of a point for each day, and optionally each hour (Open-Meteo)",
45
- output: "json",
46
- effects: { reads: ["network"], writes: [] },
47
- })
48
- .handler(async (input: ForecastInput, ctx?: ProcedureContext): Promise<Forecast> => {
49
- const signals = [AbortSignal.timeout(input.timeoutMs), ...(ctx?.signal ? [ctx.signal] : [])];
50
- let response: Response;
51
- try {
52
- response = await fetch(forecastUrl(input), { signal: AbortSignal.any(signals), headers: { accept: "application/json" } });
53
- } catch (error) {
54
- const reason = (error as { name?: string }).name === "TimeoutError" ? `no answer in ${input.timeoutMs} ms` : "the request failed";
55
- throw new Error(`Open-Meteo did not answer: ${reason}`);
56
- }
57
- if (!response.ok) throw new Error(`Open-Meteo gave HTTP ${response.status}`);
58
- return readForecast(await response.json(), input.hourly);
59
- })
60
- .build() as AnyProcedure;
61
-
62
- export const weatherProcedures: AnyProcedure[] = [weatherForecastProcedure];
74
+ /**
75
+ * This function gives the procedures of this package with the settings of the host. Without
76
+ * options, the requests go through the default host policy of `@procedures/http`, and a refused
77
+ * host gets the notice `WEATHER_PRIVATE_HOST_NOTICE`.
78
+ */
79
+ export function createWeatherProcedures(options: WeatherProceduresOptions = {}): AnyProcedure[] {
80
+ const fetchForecast: FetchForecast = options.fetch ?? createHostFetch({ warnOnRefusal: WEATHER_PRIVATE_HOST_NOTICE });
81
+ const forecast = createProcedure()
82
+ .path(["weather", "forecast"])
83
+ .input(zodAdapter<ForecastInput>(ForecastInputSchema))
84
+ .output(zodAdapter<Forecast>(ForecastOutputSchema))
85
+ .meta({
86
+ description: "Give the weather forecast of a point for each day, and optionally each hour (Open-Meteo)",
87
+ output: "json",
88
+ effects: { reads: ["network"], writes: [] },
89
+ })
90
+ .handler(async (input: ForecastInput, ctx?: ProcedureContext): Promise<Forecast> => {
91
+ const signals = [AbortSignal.timeout(input.timeoutMs), ...(ctx?.signal ? [ctx.signal] : [])];
92
+ let response: Awaited<ReturnType<FetchForecast>>;
93
+ try {
94
+ response = await fetchForecast(forecastUrl(input), { signal: AbortSignal.any(signals), headers: { accept: "application/json" } });
95
+ } catch (error) {
96
+ // A refusal of the host policy keeps its code and its reason
97
+ if (isHostNotAllowed(error)) throw error;
98
+ const reason = (error as { name?: string }).name === "TimeoutError" ? `no answer in ${input.timeoutMs} ms` : "the request failed";
99
+ throw new Error(`Open-Meteo did not answer: ${reason}`);
100
+ }
101
+ if (!response.ok) throw new Error(`Open-Meteo gave HTTP ${response.status}`);
102
+ return readForecast(await response.json(), input.hourly);
103
+ })
104
+ .build() as AnyProcedure;
105
+ return [forecast];
106
+ }
107
+
108
+ export const weatherProcedures: AnyProcedure[] = createWeatherProcedures();
109
+
110
+ export const weatherForecastProcedure: AnyProcedure = weatherProcedures[0]!;