redscript-mc 1.2.29 → 1.2.30

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/README.md CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  <img src="./logo.png" alt="RedScript Logo" width="64" />
4
4
 
5
- <img src="https://img.shields.io/badge/RedScript-1.2.27-red?style=for-the-badge&logo=minecraft&logoColor=white" alt="RedScript" />
5
+ <img src="https://img.shields.io/badge/RedScript-1.2.29-red?style=for-the-badge&logo=minecraft&logoColor=white" alt="RedScript" />
6
6
 
7
7
  **A typed scripting language that compiles to Minecraft datapacks.**
8
8
 
9
9
  Write clean game logic. RedScript handles the scoreboard spaghetti.
10
10
 
11
11
  [![CI](https://github.com/bkmashiro/redscript/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/bkmashiro/redscript/actions/workflows/ci.yml)
12
- [![Tests](https://img.shields.io/badge/tests-918%20passing-brightgreen)](https://github.com/bkmashiro/redscript)
12
+ [![Tests](https://img.shields.io/badge/tests-920%20passing-brightgreen)](https://github.com/bkmashiro/redscript)
13
13
  [![npm](https://img.shields.io/npm/v/redscript-mc?color=cb3837)](https://www.npmjs.com/package/redscript-mc)
14
14
  [![npm downloads](https://img.shields.io/npm/dm/redscript-mc?color=cb3837)](https://www.npmjs.com/package/redscript-mc)
15
15
  [![VSCode](https://img.shields.io/badge/VSCode-Extension-007ACC?logo=visualstudiocode)](https://marketplace.visualstudio.com/items?itemName=bkmashiro.redscript-vscode)
@@ -20,9 +20,11 @@ Write clean game logic. RedScript handles the scoreboard spaghetti.
20
20
 
21
21
  ### 🚀 [Try it online — no install needed!](https://redscript-ide.pages.dev)
22
22
 
23
- <img src="./demo.gif" alt="RedScript Demo" width="400" />
23
+ <img src="./demo.gif" alt="RedScript Demo — math curves drawn with particles in Minecraft" width="520" />
24
24
 
25
- *↑ Particles spawning at player position every tick — 100% vanilla, no mods! Just 30 lines of RedScript with full control flow: `if`, `foreach`, `@tick`, f-strings, and more.*
25
+ *↑ Five mathematical curves rendered in real-time with particles — 100% vanilla, no mods!*
26
+ *`y = x·sin(x)` · `y = sin(x) + ½sin(2x)` · `y = e⁻ˣsin(4x)` · `y = tanh(2x)` · `r = cos(2θ)` rose curve*
27
+ *Each curve is computed tick-by-tick using RedScript's fixed-point math stdlib.*
26
28
 
27
29
  </div>
28
30
 
@@ -32,34 +34,33 @@ Write clean game logic. RedScript handles the scoreboard spaghetti.
32
34
 
33
35
  RedScript is a typed scripting language that compiles to vanilla Minecraft datapacks. Write clean code with variables, functions, loops, and events — RedScript handles the scoreboard commands and `.mcfunction` files for you.
34
36
 
35
- **The demo above?** Just 30 lines:
37
+ **The demo above?** Five math curves drawn with 64 sample points each. The core logic:
36
38
 
37
39
  ```rs
38
- let counter: int = 0;
39
- let running: bool = false;
40
-
41
- @tick fn demo_tick() {
42
- if (!running) { return; }
43
- counter = counter + 1;
44
-
45
- foreach (p in @a) at @s {
46
- particle("minecraft:end_rod", ~0, ~1, ~0, 0.5, 0.5, 0.5, 0.1, 5);
47
- }
48
-
49
- if (counter % 20 == 0) {
50
- say(f"Running for {counter} ticks");
51
- }
52
- }
40
+ import "stdlib/math.mcrs"
53
41
 
54
- fn start() {
55
- running = true;
56
- counter = 0;
57
- say(f"Demo started!");
58
- }
42
+ let phase: int = 0;
43
+ let frame: int = 0;
44
+
45
+ // 5 curves cycle every 128 ticks (~6.5 s each)
46
+ @tick fn _wave_tick() {
47
+ phase = (phase + 4) % 360;
48
+ frame = frame + 1;
49
+
50
+ let curve_id: int = (frame / 128) % 5;
51
+
52
+ // Compute sin at 9 column offsets (40° apart = full sine wave span)
53
+ let s0: int = sin_fixed((phase + 0) % 360);
54
+ let s1: int = sin_fixed((phase + 40) % 360);
55
+ // ... s2 through s8 ...
56
+
57
+ // Draw bar chart: each column height = sin value
58
+ // (64 fixed particle positions per curve, all respawned each tick)
59
+ if (curve_id == 0) { _draw_xsinx(); }
60
+ if (curve_id == 1) { _draw_harmonic(); }
61
+ // ...
59
62
 
60
- fn stop() {
61
- running = false;
62
- say(f"Demo stopped at {counter} ticks.");
63
+ actionbar(@a, f"§e y = x·sin(x) phase: {phase}° center: {s0}‰");
63
64
  }
64
65
  ```
65
66
 
package/README.zh.md CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  <img src="./logo.png" alt="RedScript Logo" width="64" />
4
4
 
5
- <img src="https://img.shields.io/badge/RedScript-1.2.27-red?style=for-the-badge&logo=minecraft&logoColor=white" alt="RedScript" />
5
+ <img src="https://img.shields.io/badge/RedScript-1.2.29-red?style=for-the-badge&logo=minecraft&logoColor=white" alt="RedScript" />
6
6
 
7
7
  **一个编译到 Minecraft Datapack 的类型化脚本语言。**
8
8
 
9
9
  写干净的游戏逻辑,把记分板的面条代码交给 RedScript 处理。
10
10
 
11
11
  [![CI](https://github.com/bkmashiro/redscript/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/bkmashiro/redscript/actions/workflows/ci.yml)
12
- [![Tests](https://img.shields.io/badge/tests-918%20passing-brightgreen)](https://github.com/bkmashiro/redscript)
12
+ [![Tests](https://img.shields.io/badge/tests-920%20passing-brightgreen)](https://github.com/bkmashiro/redscript)
13
13
  [![npm](https://img.shields.io/npm/v/redscript-mc?color=cb3837)](https://www.npmjs.com/package/redscript-mc)
14
14
  [![npm downloads](https://img.shields.io/npm/dm/redscript-mc?color=cb3837)](https://www.npmjs.com/package/redscript-mc)
15
15
  [![VSCode](https://img.shields.io/badge/VSCode-插件-007ACC?logo=visualstudiocode)](https://marketplace.visualstudio.com/items?itemName=bkmashiro.redscript-vscode)
@@ -20,9 +20,11 @@
20
20
 
21
21
  ### 🚀 [在线试用 — 无需安装!](https://redscript-ide.pages.dev)
22
22
 
23
- <img src="./demo.gif" alt="RedScript Demo" width="400" />
23
+ <img src="./demo.gif" alt="RedScript Demo — 用粒子在 Minecraft 中绘制数学曲线" width="520" />
24
24
 
25
- *↑ tick 在玩家位置生成粒子 — 纯原版,无需 MOD!仅 30 行 RedScript,包含完整控制流:`if`、`foreach`、`@tick`、f-strings 等。*
25
+ *↑ 五条数学函数图像实时粒子渲染 — 纯原版,无需 MOD!*
26
+ *`y = x·sin(x)` · `y = sin(x) + ½sin(2x)` · `y = e⁻ˣsin(4x)` · `y = tanh(2x)` · 玫瑰曲线 `r = cos(2θ)`*
27
+ *每条曲线由 RedScript 定点数学库逐 tick 计算,64 个采样点动态绘制。*
26
28
 
27
29
  </div>
28
30
 
@@ -32,34 +34,32 @@
32
34
 
33
35
  RedScript 是一门编译到原版 Minecraft 数据包的脚本语言。用变量、函数、循环、事件写代码,RedScript 帮你生成记分板命令和 `.mcfunction` 文件。
34
36
 
35
- **上面的演示?** 只有 30 行:
37
+ **上面的演示?** 五条数学曲线,每条 64 个采样点,核心逻辑:
36
38
 
37
39
  ```rs
38
- let counter: int = 0;
39
- let running: bool = false;
40
-
41
- @tick fn demo_tick() {
42
- if (!running) { return; }
43
- counter = counter + 1;
44
-
45
- foreach (p in @a) at @s {
46
- particle("minecraft:end_rod", ~0, ~1, ~0, 0.5, 0.5, 0.5, 0.1, 5);
47
- }
48
-
49
- if (counter % 20 == 0) {
50
- say(f"已运行 {counter} ticks");
51
- }
52
- }
40
+ import "stdlib/math.mcrs"
53
41
 
54
- @keep fn start() {
55
- running = true;
56
- counter = 0;
57
- say(f"Demo 已启动!");
58
- }
42
+ let phase: int = 0;
43
+ let frame: int = 0;
44
+
45
+ // 5 条曲线每 128 tick (~6.5 ) 自动切换
46
+ @tick fn _wave_tick() {
47
+ phase = (phase + 4) % 360;
48
+ frame = frame + 1;
49
+
50
+ let curve_id: int = (frame / 128) % 5;
51
+
52
+ // 计算 9 列的 sin 值(每列相差 40°,刚好覆盖完整周期)
53
+ let s0: int = sin_fixed((phase + 0) % 360);
54
+ let s1: int = sin_fixed((phase + 40) % 360);
55
+ // ... s2 到 s8 ...
56
+
57
+ // 绘制图像:每条曲线有 64 个固定坐标粒子,每 tick 全部重绘
58
+ if (curve_id == 0) { _draw_xsinx(); }
59
+ if (curve_id == 1) { _draw_harmonic(); }
60
+ // ...
59
61
 
60
- @keep fn stop() {
61
- running = false;
62
- say(f"Demo 已停止,共运行 {counter} ticks。");
62
+ actionbar(@a, f"§e y = x·sin(x) phase: {phase}° center: {s0}‰");
63
63
  }
64
64
  ```
65
65
 
package/demo.gif CHANGED
Binary file
@@ -236,9 +236,17 @@ class Lexer {
236
236
  this.addToken('rel_coord', value, startLine, startCol);
237
237
  return;
238
238
  }
239
- // Local coordinate: ^ or ^5 or ^-3 or ^0.5
239
+ // Local coordinate: ^ or ^5 or ^-3 or ^0.5 or ^varname (macro variable)
240
240
  if (char === '^') {
241
241
  let value = '^';
242
+ // Check for identifier (variable name for macro substitution, e.g. ^px, ^height)
243
+ if (/[a-zA-Z_]/.test(this.peek())) {
244
+ while (/[a-zA-Z0-9_]/.test(this.peek())) {
245
+ value += this.advance();
246
+ }
247
+ this.addToken('local_coord', value, startLine, startCol);
248
+ return;
249
+ }
242
250
  // Check for optional sign
243
251
  if (this.peek() === '-' || this.peek() === '+') {
244
252
  value += this.advance();
@@ -495,16 +495,31 @@ class Lowering {
495
495
  }
496
496
  }
497
497
  // Set up NBT storage for each macro param
498
+ // float-typed params are stored as `double 0.01` so that an integer value N
499
+ // becomes N/100.0 in the command (e.g. scoreboard value 975 → NBT 9.75d → ^9.75)
498
500
  for (const macroParam of macroParamNames) {
499
501
  const paramIdx = params.findIndex(p => p.name === macroParam);
500
502
  if (paramIdx < 0 || paramIdx >= loweredArgs.length)
501
503
  continue;
502
504
  const operand = loweredArgs[paramIdx];
505
+ const paramType = params[paramIdx]?.type;
506
+ const isFloat = paramType?.kind === 'named' && paramType.name === 'float';
503
507
  if (operand.kind === 'const') {
504
- this.builder.emitRaw(`data modify storage rs:macro_args ${macroParam} set value ${operand.value}`);
508
+ if (isFloat) {
509
+ const floatVal = (operand.value / 100).toFixed(6);
510
+ this.builder.emitRaw(`data modify storage rs:macro_args ${macroParam} set value ${floatVal}d`);
511
+ }
512
+ else {
513
+ this.builder.emitRaw(`data modify storage rs:macro_args ${macroParam} set value ${operand.value}`);
514
+ }
505
515
  }
506
516
  else if (operand.kind === 'var') {
507
- this.builder.emitRaw(`execute store result storage rs:macro_args ${macroParam} int 1 run scoreboard players get ${operand.name} ${exports.LOWERING_OBJ}`);
517
+ if (isFloat) {
518
+ this.builder.emitRaw(`execute store result storage rs:macro_args ${macroParam} double 0.01 run scoreboard players get ${operand.name} ${exports.LOWERING_OBJ}`);
519
+ }
520
+ else {
521
+ this.builder.emitRaw(`execute store result storage rs:macro_args ${macroParam} int 1 run scoreboard players get ${operand.name} ${exports.LOWERING_OBJ}`);
522
+ }
508
523
  }
509
524
  }
510
525
  // Call with macro storage
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "redscript-vscode",
3
- "version": "1.0.37",
3
+ "version": "1.2.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "redscript-vscode",
9
- "version": "1.0.37",
9
+ "version": "1.2.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "redscript": "file:../../"
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "../..": {
25
25
  "name": "redscript-mc",
26
- "version": "1.2.28",
26
+ "version": "1.2.29",
27
27
  "license": "MIT",
28
28
  "bin": {
29
29
  "redscript": "dist/cli.js",
@@ -2,7 +2,7 @@
2
2
  "name": "redscript-vscode",
3
3
  "displayName": "RedScript for Minecraft",
4
4
  "description": "Syntax highlighting, error diagnostics, and language support for RedScript — a compiler targeting Minecraft Java Edition",
5
- "version": "1.0.37",
5
+ "version": "1.2.0",
6
6
  "publisher": "bkmashiro",
7
7
  "icon": "icon.png",
8
8
  "license": "MIT",
@@ -1,92 +1,70 @@
1
- // readme-demo.mcrs — RedScript v1.2.27 README visual showcase
2
- // What 55 lines of RedScript can do on a vanilla Minecraft server.
1
+ // readme-demo.mcrs — real-time 2D sine wave
2
+ // Uses sin_fixed() to compute y = sin(x + t) at runtime.
3
+ // _draw(px, py) is a macro function: float params are stored as double×0.01
4
+ // so an integer value N → coordinate N/100 blocks (e.g. 975 → 9.75 blocks).
5
+ // No lookup tables. No precomputed positions. Pure runtime computation.
3
6
  //
4
- // Compile: node dist/cli.js compile examples/readme-demo.mcrs -o <datapack> --namespace rsdemo
5
- // In-game: /function rsdemo:start (then record your gif)
6
- // /function rsdemo:stop
7
+ // Compile:
8
+ // node dist/cli.js compile examples/readme-demo.mcrs \
9
+ // -o <out> --namespace rsdemo
10
+ // In-game:
11
+ // /function rsdemo:start (face forward, stand ~10 blocks back)
12
+ // /function rsdemo:stop
7
13
 
8
14
  import "../src/stdlib/math.mcrs"
9
15
 
10
- let t: int = 0; // 0..359 degrees, 4° per tick = full cycle every 1.5 s
11
- let frame: int = 0;
16
+ let phase: int = 0;
17
+ let t: int = 0;
12
18
  let on: bool = false;
13
19
 
14
- @load fn _init() {
15
- t = 0;
16
- frame = 0;
20
+ // Macro function: place one particle at (^px/100, ^py/100, ^5).
21
+ // RedScript stores float params as `double 0.01` in rs:macro_args,
22
+ // so integer values become sub-block coordinates at call time.
23
+ fn _draw(px: float, py: float) {
24
+ particle("minecraft:end_rod", ^px, ^py, ^5, 0.02, 0.02, 0.02, 0.0, 10);
17
25
  }
18
26
 
27
+ @load fn _init() { phase = 0; t = 0; }
28
+
19
29
  @tick fn _wave_tick() {
20
30
  if (!on) { return; }
21
31
 
22
- t = (t + 4) % 360;
23
- frame = frame + 1;
24
-
25
- let s: int = sin_fixed(t); // -1000 .. 1000
26
- let c: int = cos_fixed(t); // -1000 .. 1000
27
- let mag: int = abs(s); // 0 .. 1000
32
+ // Advance: 4 new points this tick, phase scrolls at 1°/tick
33
+ t = (t + 4) % 40;
34
+ phase = (phase + 1) % 360;
28
35
 
29
- // ── Particle rings: spread values scale with sin(t) ─────────────────
30
- // Inner ring — always visible, small tight shimmer
31
36
  foreach (p in @a) at @s {
32
- particle("minecraft:end_rod", ~0, ~1, ~0, 0.25, 0.08, 0.25, 0.02, 6);
33
- }
37
+ // Draw 4 consecutive points (loop-unrolled)
38
+ // px: index 0..39 → -975..975 (÷100 = -9.75..9.75 blocks)
39
+ // py: sin_fixed → -1000..1000 → ÷4 → -250..250 (÷100 = -2.5..2.5 blocks)
34
40
 
35
- // Mid ring appears when sin > 0 (upper half of cycle)
36
- if (s > 0) {
37
- foreach (p in @a) at @s {
38
- particle("minecraft:end_rod", ~0, ~1, ~0, 0.9, 0.25, 0.9, 0.02, 12);
39
- }
40
- }
41
+ let i0: int = t;
42
+ let s0: int = sin_fixed((i0 * 9 + phase) % 360);
43
+ _draw(i0 * 50 - 975, s0 / 4);
41
44
 
42
- // Outer ring + soul fire sin > 600
43
- if (s > 600) {
44
- foreach (p in @a) at @s {
45
- particle("minecraft:end_rod", ~0, ~1, ~0, 1.8, 0.4, 1.8, 0.02, 18);
46
- particle("minecraft:soul_fire_flame", ~0, ~2, ~0, 0.9, 0.3, 0.9, 0.03, 8);
47
- }
48
- }
45
+ let i1: int = (t + 1) % 40;
46
+ let s1: int = sin_fixed((i1 * 9 + phase) % 360);
47
+ _draw(i1 * 50 - 975, s1 / 4);
49
48
 
50
- // Peak flash fires ~4 ticks per cycle
51
- if (s > 940) {
52
- foreach (p in @a) at @s {
53
- particle("minecraft:flash", ~0, ~3, ~0, 0.4, 0.3, 0.4, 0.1, 3);
54
- }
55
- }
49
+ let i2: int = (t + 2) % 40;
50
+ let s2: int = sin_fixed((i2 * 9 + phase) % 360);
51
+ _draw(i2 * 50 - 975, s2 / 4);
56
52
 
57
- // Negative trough ground portal swirl
58
- if (s < -700) {
59
- foreach (p in @a) at @s {
60
- particle("minecraft:portal", ~0, ~0.5, ~0, 1.2, 0.4, 1.2, 0.05, 12);
61
- }
62
- }
63
-
64
- // ── Actionbar: live math rotating every 3 s ──────────────────────────
65
- let seg: int = (frame / 45) % 4;
66
- if (seg == 0) {
67
- actionbar(@a, f"§3⚡ §bsin({t}°) = §e{s}‰ cos({t}°) = §e{c}‰");
68
- }
69
- if (seg == 1) {
70
- actionbar(@a, f"§3⚡ §bsmoothstep(|sin|) = §e{smoothstep(0, 1000, mag)}‰ isqrt({frame}) = §e{isqrt(frame)}");
71
- }
72
- if (seg == 2) {
73
- actionbar(@a, f"§3⚡ §bgcd(360, {t + 1}) = §e{gcd(360, t + 1)} log2({mag + 1}) = §e{log2_int(mag + 1)}");
74
- }
75
- if (seg == 3) {
76
- actionbar(@a, f"§3⚡ §bpow(2, {(frame / 30) % 10 + 1}) = §e{pow_int(2, (frame / 30) % 10 + 1)} clamp(sin) = §e{clamp(s, -500, 500)}");
53
+ let i3: int = (t + 3) % 40;
54
+ let s3: int = sin_fixed((i3 * 9 + phase) % 360);
55
+ _draw(i3 * 50 - 975, s3 / 4);
77
56
  }
78
57
  }
79
58
 
80
59
  fn start() {
81
- on = true;
82
- t = 0;
83
- frame = 0;
84
- title(@a, f"§e §bRedScript§e ", f7trig-driven particle rings");
85
- say("§a▶ readme-demo started /function rsdemo:stop to end");
60
+ on = true;
61
+ phase = 0;
62
+ t = 0;
63
+ title(@a, "§e y = sin(x + t)", "§7sin_fixed · macro · real-time");
64
+ say("§a▶ sine wave face forward, stand back ~10 blocks");
86
65
  }
87
66
 
88
67
  fn stop() {
89
68
  on = false;
90
- actionbar(@a, f7[ demo stopped ]");
91
- say("§c■ readme-demo stopped");
69
+ say("§c■ stopped");
92
70
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "redscript-mc",
3
- "version": "1.2.29",
3
+ "version": "1.2.30",
4
4
  "description": "A high-level programming language that compiles to Minecraft datapacks",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -313,9 +313,17 @@ export class Lexer {
313
313
  return
314
314
  }
315
315
 
316
- // Local coordinate: ^ or ^5 or ^-3 or ^0.5
316
+ // Local coordinate: ^ or ^5 or ^-3 or ^0.5 or ^varname (macro variable)
317
317
  if (char === '^') {
318
318
  let value = '^'
319
+ // Check for identifier (variable name for macro substitution, e.g. ^px, ^height)
320
+ if (/[a-zA-Z_]/.test(this.peek())) {
321
+ while (/[a-zA-Z0-9_]/.test(this.peek())) {
322
+ value += this.advance()
323
+ }
324
+ this.addToken('local_coord', value, startLine, startCol)
325
+ return
326
+ }
319
327
  // Check for optional sign
320
328
  if (this.peek() === '-' || this.peek() === '+') {
321
329
  value += this.advance()
@@ -515,17 +515,33 @@ export class Lowering {
515
515
  }
516
516
 
517
517
  // Set up NBT storage for each macro param
518
+ // float-typed params are stored as `double 0.01` so that an integer value N
519
+ // becomes N/100.0 in the command (e.g. scoreboard value 975 → NBT 9.75d → ^9.75)
518
520
  for (const macroParam of macroParamNames) {
519
521
  const paramIdx = params.findIndex(p => p.name === macroParam)
520
522
  if (paramIdx < 0 || paramIdx >= loweredArgs.length) continue
521
523
 
522
524
  const operand = loweredArgs[paramIdx]
525
+ const paramType = params[paramIdx]?.type
526
+ const isFloat = paramType?.kind === 'named' && (paramType as any).name === 'float'
527
+
523
528
  if (operand.kind === 'const') {
524
- this.builder.emitRaw(`data modify storage rs:macro_args ${macroParam} set value ${operand.value}`)
529
+ if (isFloat) {
530
+ const floatVal = (operand.value / 100).toFixed(6)
531
+ this.builder.emitRaw(`data modify storage rs:macro_args ${macroParam} set value ${floatVal}d`)
532
+ } else {
533
+ this.builder.emitRaw(`data modify storage rs:macro_args ${macroParam} set value ${operand.value}`)
534
+ }
525
535
  } else if (operand.kind === 'var') {
526
- this.builder.emitRaw(
527
- `execute store result storage rs:macro_args ${macroParam} int 1 run scoreboard players get ${operand.name} ${LOWERING_OBJ}`
528
- )
536
+ if (isFloat) {
537
+ this.builder.emitRaw(
538
+ `execute store result storage rs:macro_args ${macroParam} double 0.01 run scoreboard players get ${operand.name} ${LOWERING_OBJ}`
539
+ )
540
+ } else {
541
+ this.builder.emitRaw(
542
+ `execute store result storage rs:macro_args ${macroParam} int 1 run scoreboard players get ${operand.name} ${LOWERING_OBJ}`
543
+ )
544
+ }
529
545
  }
530
546
  }
531
547