create-nola-lang 0.1.10 → 0.1.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.
@@ -5,7 +5,7 @@ import {
5
5
 
6
6
  // src/providers.ts
7
7
  var PROVIDERS = [
8
- { id: "nola", label: "Nola", hint: "25 free runs, no account or provider key needed", model: "nola.infer()" },
8
+ { id: "nola", label: "Nola", hint: "25 free runs, no account or provider key needed", model: '"nola"' },
9
9
  { id: "openai", label: "OpenAI", hint: 'openai("gpt-5-mini"), reads OPENAI_API_KEY', envVar: "OPENAI_API_KEY", model: 'openai("gpt-5-mini")' },
10
10
  {
11
11
  id: "anthropic",
@@ -176,6 +176,11 @@ function providerConfigUrl(provider) {
176
176
  return new URL(`../templates/_providers/${provider}.config.ts`, import.meta.url);
177
177
  }
178
178
  var RENAMES = { _gitignore: ".gitignore" };
179
+ var GITIGNORE_URL = new URL("../templates/_gitignore", import.meta.url);
180
+ async function withRecommendedGitignore(files) {
181
+ if (!files.has(".gitignore")) files.set(".gitignore", await readFile3(GITIGNORE_URL, "utf8"));
182
+ return files;
183
+ }
179
184
  var SUBSTITUTED = /* @__PURE__ */ new Set(["package.json", "README.md", "main.ts"]);
180
185
  function nextStepsComment(ide, template) {
181
186
  if (ide === "vscode") {
@@ -198,11 +203,11 @@ var OFFLINE_ONLY = /* @__PURE__ */ new Set(["nola.replay.jsonl"]);
198
203
  var README_NOTES = {
199
204
  offline: {
200
205
  START_NOTE: "works offline, no API key needed",
201
- PROVIDER_NOTE: "The starter runs offline: `nola.config.ts` replays answers from the committed\n`nola.replay.jsonl` ledger. The ledger is keyed by the exact prompt, so once\nyou edit `src/person.tsi` or add your own asks, switch the config to a real\nmodel (see the comment in `nola.config.ts`) and set `OPENAI_API_KEY`."
206
+ PROVIDER_NOTE: 'The starter runs offline: `nola.config.ts` replays answers from the committed\n`nola.replay.jsonl` ledger. The ledger is keyed by the exact prompt, so once\nyou edit `src/person.tsi` or add your own asks, switch the config to a real\nmodel (see the comment in `nola.config.ts`): `model: "nola"` with a key from\n`npx nola-lang key` (25 free runs), or your own provider and its key.'
202
207
  },
203
208
  nola: {
204
209
  START_NOTE: "uses your 25 free Nola runs (key in .env)",
205
- PROVIDER_NOTE: "`nola.config.ts` sets `model: nola.infer()` \u2014 platform-served inference with the trial key the\nscaffold wrote to `.env` (git-ignored). Out of runs? `npx nola-lang account` opens\nyour Nola account, where prepaid balance is added, or bring your\nown model (see the comment in `nola.config.ts`)."
210
+ PROVIDER_NOTE: '`nola.config.ts` sets `model: "nola"` \u2014 platform-served inference with the trial key the\nscaffold wrote to `.env` (git-ignored). Out of runs? `npx nola-lang account` opens\nyour Nola account, where prepaid balance is added, or bring your\nown model (see the comment in `nola.config.ts`).'
206
211
  }
207
212
  };
208
213
  function readmeNotes(provider) {
@@ -239,7 +244,9 @@ async function scaffold(targetDir, opts = {}) {
239
244
  const version = await ownVersion();
240
245
  if (def.source === "example") {
241
246
  const dev = await devExamplesDir();
242
- const exampleFiles = dev ? await collectExampleFromDisk(dev, template) : await fetchExampleFromGitHub(template, version);
247
+ const exampleFiles = await withRecommendedGitignore(
248
+ dev ? await collectExampleFromDisk(dev, template) : await fetchExampleFromGitHub(template, version)
249
+ );
243
250
  const manifest = exampleFiles.get("package.json");
244
251
  if (manifest) exampleFiles.set("package.json", rewriteExamplePackageJson(manifest, { name, version }));
245
252
  for (const [relPath, content] of exampleFiles) {
@@ -276,6 +283,10 @@ async function scaffold(targetDir, opts = {}) {
276
283
  }
277
284
  };
278
285
  await copyDir(".", ".");
286
+ if (!files.includes(".gitignore")) {
287
+ await writeFile(join3(absRoot, ".gitignore"), await readFile3(GITIGNORE_URL, "utf8"));
288
+ files.push(".gitignore");
289
+ }
279
290
  return { root, files: files.sort() };
280
291
  }
281
292
 
@@ -1286,7 +1297,7 @@ async function applyTrial(dir, init) {
1286
1297
  const { wrote, skipped } = await writeEnvKey(root, init.apiKey);
1287
1298
  wrote.push(...await ensureEnvIgnored(root));
1288
1299
  if (init.hasConfig) {
1289
- skipped.push("nola.config.ts already exists \u2014 set `model: nola.infer()` (nola from @nola-lang/runtime) to use the trial key");
1300
+ skipped.push('nola.config.ts already exists \u2014 set `model: "nola"` to use the trial key');
1290
1301
  } else {
1291
1302
  await writeFile7(join9(root, "nola.config.ts"), await readFile8(TRIAL_CONFIG_URL, "utf8"));
1292
1303
  wrote.push("nola.config.ts");
@@ -1757,7 +1768,7 @@ function trialFailureNote(err) {
1757
1768
  reason = `too many trials from this network${wait} (${err.message})`;
1758
1769
  }
1759
1770
  return `Could not get a Nola API key: ${reason}
1760
- The project uses its default provider instead. Retry later with \`npx nola-lang key\`, then set \`model: nola.infer()\` in nola.config.ts.`;
1771
+ The project uses its default provider instead. Retry later with \`npx nola-lang key\`, then set \`model: "nola"\` in nola.config.ts.`;
1761
1772
  }
1762
1773
  async function obtainTrial(prompter, opts, interactive) {
1763
1774
  try {
package/dist/flow.js CHANGED
@@ -428,7 +428,7 @@ function trialFailureNote(err) {
428
428
  const wait = err.retryAfterMs !== undefined && err.retryAfterMs > 0 ? ` — try again in ${formatWait(err.retryAfterMs)}` : "";
429
429
  reason = `too many trials from this network${wait} (${err.message})`;
430
430
  }
431
- return `Could not get a Nola API key: ${reason}\nThe project uses its default provider instead. Retry later with \`npx nola-lang key\`, then set \`model: nola.infer()\` in nola.config.ts.`;
431
+ return `Could not get a Nola API key: ${reason}\nThe project uses its default provider instead. Retry later with \`npx nola-lang key\`, then set \`model: "nola"\` in nola.config.ts.`;
432
432
  }
433
433
  /**
434
434
  * `acquireKey` for the scaffold: a failure is a note, never an exit code (the
package/dist/index.js CHANGED
@@ -85,7 +85,7 @@ import {
85
85
  writeEnvKey,
86
86
  writeSession,
87
87
  writeVscodeSetup
88
- } from "./chunk-G2TOUJVB.js";
88
+ } from "./chunk-MAULRZZD.js";
89
89
  import {
90
90
  clackPrompter
91
91
  } from "./chunk-7IQIRMK6.js";
package/dist/main.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  CREATE_COMMAND,
4
4
  dispatch,
5
5
  ownVersion
6
- } from "./chunk-G2TOUJVB.js";
6
+ } from "./chunk-MAULRZZD.js";
7
7
  import "./chunk-FPS2V3S4.js";
8
8
 
9
9
  // src/main.ts
package/dist/providers.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export const PROVIDERS = [
2
- { id: "nola", label: "Nola", hint: "25 free runs, no account or provider key needed", model: "nola.infer()" },
2
+ { id: "nola", label: "Nola", hint: "25 free runs, no account or provider key needed", model: '"nola"' },
3
3
  { id: "openai", label: "OpenAI", hint: 'openai("gpt-5-mini"), reads OPENAI_API_KEY', envVar: "OPENAI_API_KEY", model: 'openai("gpt-5-mini")' },
4
4
  {
5
5
  id: "anthropic",
@@ -28,6 +28,12 @@ export interface ScaffoldOptions {
28
28
  }
29
29
  /** The config a live provider choice writes over the template's own (`templates/_providers/<id>.config.ts`). */
30
30
  export declare function providerConfigUrl(provider: Exclude<ProviderId, "none">): URL;
31
+ /**
32
+ * Add the recommended `.gitignore` to an example's files. Examples are copied
33
+ * verbatim from `examples/`, where the monorepo's root ignore file covers them,
34
+ * so they carry none — one an example does carry wins.
35
+ */
36
+ export declare function withRecommendedGitignore(files: Map<string, string>): Promise<Map<string, string>>;
31
37
  /**
32
38
  * The comment that opens src/main.ts — the file the scaffold lands the user
33
39
  * on (VS Code opens it as the active editor), so it carries the first three
package/dist/scaffold.js CHANGED
@@ -13,6 +13,18 @@ export function providerConfigUrl(provider) {
13
13
  }
14
14
  /** _gitignore ships underscored (npm pack strips nested .gitignore files). */
15
15
  const RENAMES = { _gitignore: ".gitignore" };
16
+ /** The ONE recommended .gitignore — every scaffold gets it; no template keeps a copy of its own. */
17
+ const GITIGNORE_URL = new URL("../templates/_gitignore", import.meta.url);
18
+ /**
19
+ * Add the recommended `.gitignore` to an example's files. Examples are copied
20
+ * verbatim from `examples/`, where the monorepo's root ignore file covers them,
21
+ * so they carry none — one an example does carry wins.
22
+ */
23
+ export async function withRecommendedGitignore(files) {
24
+ if (!files.has(".gitignore"))
25
+ files.set(".gitignore", await readFile(GITIGNORE_URL, "utf8"));
26
+ return files;
27
+ }
16
28
  /** Files whose __NAME__/__VERSION__, README-note and __NEXT_STEPS__ placeholders are substituted. */
17
29
  const SUBSTITUTED = new Set(["package.json", "README.md", "main.ts"]);
18
30
  /**
@@ -46,11 +58,12 @@ const README_NOTES = {
46
58
  PROVIDER_NOTE: "The starter runs offline: `nola.config.ts` replays answers from the committed\n" +
47
59
  "`nola.replay.jsonl` ledger. The ledger is keyed by the exact prompt, so once\n" +
48
60
  "you edit `src/person.tsi` or add your own asks, switch the config to a real\n" +
49
- "model (see the comment in `nola.config.ts`) and set `OPENAI_API_KEY`.",
61
+ "model (see the comment in `nola.config.ts`): `model: \"nola\"` with a key from\n" +
62
+ "`npx nola-lang key` (25 free runs), or your own provider and its key.",
50
63
  },
51
64
  nola: {
52
65
  START_NOTE: "uses your 25 free Nola runs (key in .env)",
53
- PROVIDER_NOTE: "`nola.config.ts` sets `model: nola.infer()` — platform-served inference with the trial key the\n" +
66
+ PROVIDER_NOTE: "`nola.config.ts` sets `model: \"nola\"` — platform-served inference with the trial key the\n" +
54
67
  "scaffold wrote to `.env` (git-ignored). Out of runs? `npx nola-lang account` opens\n" +
55
68
  "your Nola account, where prepaid balance is added, or bring your\n" +
56
69
  "own model (see the comment in `nola.config.ts`).",
@@ -104,7 +117,7 @@ export async function scaffold(targetDir, opts = {}) {
104
117
  const version = await ownVersion();
105
118
  if (def.source === "example") {
106
119
  const dev = await devExamplesDir();
107
- const exampleFiles = dev ? await collectExampleFromDisk(dev, template) : await fetchExampleFromGitHub(template, version);
120
+ const exampleFiles = await withRecommendedGitignore(dev ? await collectExampleFromDisk(dev, template) : await fetchExampleFromGitHub(template, version));
108
121
  const manifest = exampleFiles.get("package.json");
109
122
  if (manifest)
110
123
  exampleFiles.set("package.json", rewriteExamplePackageJson(manifest, { name, version }));
@@ -151,6 +164,10 @@ export async function scaffold(targetDir, opts = {}) {
151
164
  }
152
165
  };
153
166
  await copyDir(".", ".");
167
+ if (!files.includes(".gitignore")) {
168
+ await writeFile(join(absRoot, ".gitignore"), await readFile(GITIGNORE_URL, "utf8"));
169
+ files.push(".gitignore");
170
+ }
154
171
  return { root, files: files.sort() };
155
172
  }
156
173
  //# sourceMappingURL=scaffold.js.map
package/dist/trial.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- /** The canonical `model: nola.infer()` config every template gets when Nola is the chosen provider. */
1
+ /** The canonical `model: "nola"` config every template gets when Nola is the chosen provider. */
2
2
  export declare const TRIAL_CONFIG_URL: import("url").URL;
3
3
  export declare const ENV_KEY = "NOLA_API_KEY";
4
4
  export interface TrialApplyResult {
package/dist/trial.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { appendFile, readFile, writeFile } from "node:fs/promises";
3
3
  import { join, resolve } from "node:path";
4
- /** The canonical `model: nola.infer()` config every template gets when Nola is the chosen provider. */
4
+ /** The canonical `model: "nola"` config every template gets when Nola is the chosen provider. */
5
5
  export const TRIAL_CONFIG_URL = new URL("../templates/_providers/nola.config.ts", import.meta.url);
6
6
  export const ENV_KEY = "NOLA_API_KEY";
7
7
  const IGNORE_LINES = [".env", ".env.*"];
@@ -79,7 +79,7 @@ export async function applyTrial(dir, init) {
79
79
  const { wrote, skipped } = await writeEnvKey(root, init.apiKey);
80
80
  wrote.push(...(await ensureEnvIgnored(root)));
81
81
  if (init.hasConfig) {
82
- skipped.push('nola.config.ts already exists — set `model: nola.infer()` (nola from @nola-lang/runtime) to use the trial key');
82
+ skipped.push('nola.config.ts already exists — set `model: "nola"` to use the trial key');
83
83
  }
84
84
  else {
85
85
  await writeFile(join(root, "nola.config.ts"), await readFile(TRIAL_CONFIG_URL, "utf8"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-nola-lang",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Scaffold a new Nola project (npm create nola, or npm create nola-lang)",
5
5
  "keywords": [
6
6
  "nola",
@@ -43,7 +43,7 @@ infer function extractPerson(.text: string) {
43
43
  instruction text.
44
44
  - `ask with <modelName> <intent>` — routes one ask through a named model
45
45
  from `nola.config.ts`. The name must be a static identifier. When the
46
- platform serves inference (`model: nola.infer()`) any unconfigured
46
+ platform serves inference (`model: "nola"`) any unconfigured
47
47
  name is legal — it is sent to the platform as a free-form inference profile.
48
48
  - Prompt templates: inside ANY instruction backticks (marker, extractor,
49
49
  call hint) a hole that starts with a single dot — `${.member}` — reads
@@ -7,8 +7,9 @@ import { defineConfig, nola, terminalTrace } from "@nola-lang/runtime";
7
7
  import { openai, mockProvider, withRetry } from "@nola-lang/providers";
8
8
  ```
9
9
 
10
- `defineConfig`, the `nola` namespace (`nola.infer()`, `nola.tracer()`),
11
- `terminalTrace()` and everything app-facing come from `@nola-lang/runtime`.
10
+ `defineConfig`, the `nola` namespace (`nola.infer()`, `nola.tracer()` —
11
+ import it ONLY when you need their options; the plain cases are the strings
12
+ `model: "nola"` and `telemetry: "<url>"`), `terminalTrace()` and everything app-facing come from `@nola-lang/runtime`.
12
13
  Everything bring-your-own — vendor factories (`openai`, `anthropic`,
13
14
  `google`, `typesafe`, `mockProvider`), resilience combinators (`withRetry`, `fallback`,
14
15
  `roundRobin`, `constant`, `exponential`) and record/replay (`record`,
@@ -48,15 +49,22 @@ fails definitively before the network on anything else. Use it behind
48
49
  escalate to a general model. Never scaffold it as the only model.
49
50
 
50
51
  `nola` is a NAMESPACE, not a function (`nola({})` is a type error).
51
- `nola.infer()` is the platform model — the Nola platform (api.nola.sh, or a
52
- self-hosted console at `baseUrl`) serves inference and reads `NOLA_API_KEY`;
53
- with no argument the platform picks the model:
52
+ The platform model is written as the STRING `"nola"` — the Nola platform
53
+ (api.nola.sh) serves inference, reads `NOLA_API_KEY`, and picks the model.
54
+ PREFER this form; it is what the scaffolder writes and it needs no `nola`
55
+ import:
54
56
 
55
57
  ```ts
56
- import { defineConfig, nola } from "@nola-lang/runtime";
57
- export default defineConfig({ model: nola.infer() });
58
+ import { defineConfig } from "@nola-lang/runtime";
59
+ export default defineConfig({ model: "nola" });
58
60
  ```
59
61
 
62
+ `"nola"` is short for `nola.infer()`. It is the ONLY string the `model` slot
63
+ takes (any other string is NOLA3003 — `model: "gpt-5"` is not a thing) and
64
+ it works as the map's `default` too. Write the `nola.infer(...)` call only
65
+ when you need an argument — the upstream selector or the connection options
66
+ (a self-hosted console at `baseUrl`, a key source, `retry`).
67
+
60
68
  When the platform serves, `ask with <name>` accepts ANY name — a configured
61
69
  map key pins that model as usual, and any other name (`fast`, `careful`, …)
62
70
  is sent with the request as a free-form inference profile that the
@@ -65,9 +73,9 @@ temperature/topK tuning). A local model map keeps strict name validation
65
73
  (unknown names are NOLA3004). `nola.infer("<provider>/<model>")` names the
66
74
  upstream explicitly; `nola.infer({ baseUrl, apiKey, apiKeyEnv, retry, model })`
67
75
  carries the connection. Beside your own models it is the map's `default`:
68
- `model: { default: nola.infer(), fast: openai("gpt-5-nano") }`. Nothing else
69
- is implied — traces go to the platform only when `telemetry` lists
70
- `nola.tracer()`.
76
+ `model: { default: "nola", fast: openai("gpt-5-nano") }`. Nothing else
77
+ is implied — traces go to a Nola console only when `telemetry` lists its
78
+ URL (or `nola.tracer()`).
71
79
 
72
80
  `npm create nola` asks *Select an inference provider:* right after the
73
81
  template — Nola (25 free runs) first, then OpenAI / Anthropic / Gemini, then
@@ -114,7 +122,7 @@ export infer function summarize(.text: string) {
114
122
 
115
123
  An `ask with` name that is not a key of the map fails at run time with
116
124
  NOLA3004, listing the configured names — EXCEPT when `default` is
117
- `nola.infer()`, where the unmatched name becomes an inference profile for
125
+ the platform model (`"nola"`), where the unmatched name becomes an inference profile for
118
126
  the platform instead of an error.
119
127
 
120
128
  ### Other config sections
@@ -146,14 +154,19 @@ event at `debug`, coloured on a TTY, written to STDERR — stdout stays the
146
154
  program's), ONE observer, or an ARRAY of
147
155
  observers. An observer or an array REPLACES the terminal — nothing is
148
156
  implied, so list `terminalTrace()` to keep it; `[]` is silent. Observers:
149
- `nola.tracer()` / `nola.tracer("http://localhost:4141")` /
150
- `nola.tracer({ baseUrl, apiKey? })` (posts to a Nola-Protocol server;
151
- keyless on loopback; never gated — listed means sends), `terminalTrace({
157
+ an `http(s)` URL STRING — the tracer, PREFER this form (`telemetry:
158
+ "http://127.0.0.1:4141"`, or as an array entry; posts to a Nola-Protocol
159
+ server such as `npx nola-lang console`; keyless on loopback; never gated —
160
+ listed means sends; a single URL replaces the terminal like any single
161
+ observer, so write `["http://127.0.0.1:4141", terminalTrace()]` to keep
162
+ both; a non-URL string is NOLA3003), the call behind it for its options —
163
+ `nola.tracer()` (default target) / `nola.tracer({ baseUrl, apiKey? })` —
164
+ `terminalTrace({
152
165
  level })`, or any object with on* methods (`onAskStart`,
153
166
  `onProviderRequest`, `onProviderResponse`, `onValidationFailed`, `onRetry`,
154
167
  `onAskEnd`, `onInvocationStart`, `onInvocationEnd`; that shape is
155
- `NolaTelemetry`). The global `console` is NOT an entry. `nola.infer()` does
156
- NOT imply a tracer. `NOLA_TRACING_URL` appends `nola.tracer(url)`; a config
168
+ `NolaTelemetry`). The global `console` is NOT an entry. `model: "nola"` does
169
+ NOT imply a tracer. `NOLA_TRACING_URL` appends that URL's tracer; a config
157
170
  that lists a tracer itself wins, with a notice. Sending is fire-and-forget
158
171
  and never affects inference. The platform model is root-only: it cannot
159
172
  appear inside combinators or non-default map entries. Start the local
@@ -210,11 +223,11 @@ the providers package:
210
223
  "check": "nola check"
211
224
  },
212
225
  "dependencies": {
213
- "@nola-lang/providers": "^0.1.10",
214
- "@nola-lang/runtime": "^0.1.10"
226
+ "@nola-lang/providers": "^0.1.11",
227
+ "@nola-lang/runtime": "^0.1.11"
215
228
  },
216
229
  "devDependencies": {
217
- "nola-lang": "^0.1.10",
230
+ "nola-lang": "^0.1.11",
218
231
  "typescript": "^5.6.0"
219
232
  },
220
233
  "engines": { "node": ">=22.18" }
@@ -201,7 +201,7 @@ export infer function summarize(.text: string) {
201
201
  use `.withModel(...)` for a dynamic model.
202
202
  - The name is matched against the config at ask time, not compile time. A
203
203
  name that matches a `model` map key pins that model. When the platform
204
- serves inference (`model: nola.infer()`) an unmatched name is a
204
+ serves inference (`model: "nola"`) an unmatched name is a
205
205
  free-form inference profile sent to the platform — not an error; under a
206
206
  local default an unknown name is a runtime `NolaConfigError` (NOLA3004).
207
207
  - `ask without` is a plain ask of the identifier `without`, not a pin.
@@ -0,0 +1,10 @@
1
+ node_modules/
2
+ dist/
3
+ *.tsbuildinfo
4
+
5
+ # `nola declarations` / bundler-plugin output — generated next to sources
6
+ *.d.tsi.ts
7
+
8
+ .env
9
+ .env.*
10
+ !.env.example
@@ -1,4 +1,4 @@
1
- import { defineConfig, nola } from "@nola-lang/runtime";
1
+ import { defineConfig } from "@nola-lang/runtime";
2
2
 
3
3
  // Nola serves inference: reads NOLA_API_KEY from .env (your free trial key)
4
4
  // and picks the model. Out of runs? `npx nola-lang account` opens your Nola
@@ -7,5 +7,5 @@ import { defineConfig, nola } from "@nola-lang/runtime";
7
7
  // import { openai } from "@nola-lang/providers";
8
8
  // model: openai("gpt-5-mini"), // reads OPENAI_API_KEY
9
9
  export default defineConfig({
10
- model: nola.infer(),
10
+ model: "nola",
11
11
  });
@@ -6,6 +6,8 @@ export default defineConfig({
6
6
  // (nola.replay.jsonl), so the first `npm start` needs no API key. The
7
7
  // ledger is keyed by the exact prompt — once you edit the .tsi or add
8
8
  // asks, switch to a real model:
9
+ // model: "nola", // Nola serves inference; `npx nola-lang key` writes NOLA_API_KEY (25 free runs)
10
+ // or bring your own:
9
11
  // import { openai } from "@nola-lang/providers";
10
12
  // model: openai("gpt-5-mini"), // reads OPENAI_API_KEY
11
13
  model: replay("./nola.replay.jsonl"),
@@ -1,5 +0,0 @@
1
- node_modules/
2
- dist/
3
-
4
- .env
5
- .env.*
@@ -1,5 +0,0 @@
1
- node_modules/
2
- dist/
3
-
4
- .env
5
- .env.*