<> <> <> <> <> DIRECTORY CursorDefs, Directory USING [Error], <> Graphics USING [ Box, CopyContext, DrawChar, Context, DrawRope, DrawBox, FontRef, GetBounds, MakeFont, Map, NewContext, PaintMode, RopeBox, RopeWidth, ClipBox, SetCP, SetDefaultFont, SetFat, SetPaintMode, SetStipple, Translate, WorldToUser], Heap USING [MakeMDSString, FreeMDSString], MusicDefs USING [AnyBug, black, BlueBug, Control, grey, RedBug, Shift, ScorePTR, white, YellowBug], <> Piece USING [Free, Overflow], Real USING [FixI], <> Screen USING [commands, CommandProcs], String USING [AppendChar, AppendString, InvalidNumber], TerminalMultiplex USING [RegisterNotifier, TerminalSwapNotifier], TTY USING [CharsAvailable, Create, GetChar, Handle, Rubout, SetEcho], UserTerminal USING [mouse, GetCursorPattern, SetCursorPattern, WaitForScanLine]; ScreenImpl: CEDAR MONITOR IMPORTS Directory, Graphics, Heap, MusicDefs, -- Music: MusicProcess, -- Piece, Real, Screen, String, TerminalMultiplex, TTY, UserTerminal EXPORTS Screen = BEGIN OPEN Graphics, CursorDefs, MusicDefs, Screen, UserTerminal; keyboard: TTY.Handle; font: Graphics.FontRef; <<******************************************************************>> <> <<******************************************************************>> running: BOOL _ TRUE; WaitRunning: ENTRY PROC = INLINE {WHILE ~running DO UserTerminal.WaitForScanLine[0]; ENDLOOP}; Notifier: TerminalMultiplex.TerminalSwapNotifier = { SELECT action FROM coming => running _ TRUE; going => running _ FALSE; ENDCASE; }; <<******************************************************************>> <> <<******************************************************************>> main: PROCESS _ NIL; Initialize: PROC = { TerminalMultiplex.RegisterNotifier[Notifier]; <> <> [] _ TTY.SetEcho[keyboard, FALSE]; keyboard _ TTY.Create[NIL]; screen _ NewContext[NIL]; [] _ SetFat[screen, TRUE]; windows[0] _ [screen, , , command, @commandProcs, 800, 740]; DefaultWindow[1, 740, 0]; font _ MakeFont["TimesRoman12"]; SetDefaultFont[screen, font]; commandProcs.display _ DisplayCommandWindow; <> <> DrawScreen[]; <> SetCursorPattern[textCursor]; main _ FORK Main[]; }; ForkMain: PROC = {main _ FORK Main[]}; Main: PROC = { ENABLE { Piece.Overflow => {DisplayMessage["Piece.Overflow"]; RESUME}; ANY => DisplayMessage["UNCAUGHT SIGNAL"]}; DisplayMessage["Mockingbird of November 22, 1983"]; DO IF badCommand THEN { WHILE TTY.GetChar[keyboard] # 177C DO NULL; ENDLOOP; EraseMessage[]; badCommand _ FALSE; }; badCommand _ FALSE; WaitRunning[]; SELECT TRUE FROM RedBug[] => HandleRed[]; BlueBug[] => HandleBlue[FindWindow[ScreenPY]]; YellowBug[] => HandleYellow[]; TTY.CharsAvailable[keyboard] # 0 => ReadKeyboard[]; ENDCASE => ChangeCursor[]; FOR w: CARDINAL IN [1..noWindows) DO IF windows[w].command.count > 50 THEN BackUp[w]; ENDLOOP; ENDLOOP; }; badCommand: BOOL _ FALSE; Command: PROC RETURNS[BOOL] = { image: Image; EraseMessage[]; MousePoint[]; [ScreenPX, ScreenPY] _ WorldToUser[screen, MousePX, 808 - MousePY]; image _ FindCommand[ScreenPX, ScreenPY]; IF image.command # NullProc THEN { image.command[image.rect]; WHILE AnyBug[] DO NULL; ENDLOOP; RETURN[TRUE]}; RETURN[FALSE]; }; HandleRed: PROC = { w: CARDINAL; top: REAL; IF Command[] THEN RETURN; w _ FindWindow[ScreenPY]; IF w = 0 THEN RETURN; Select[w]; top _ windows[w].top-header-40; IF ScreenPX > 606 THEN RETURN; SELECT TRUE FROM Control[] => windows[w].command.redbug[windows[w].score]; Shift[] => windows[w].command.redbug[windows[w].score]; ScreenPX < leftMargin => Scroll[w, Real.FixI[top-ScreenPY]]; ScreenPX > rightMargin => NULL; -- MoveWindow[ScreenPY]; ENDCASE => windows[w].command.redbug[windows[w].score]; }; HandleBlue: PROC[w: CARDINAL] = { ENABLE Piece.Overflow => IF windows[w].score = old THEN windows[w].score _ new; top: REAL; IF Command[] THEN RETURN; IF w = 0 THEN RETURN; Select[w]; IF ScreenPX > 606 THEN RETURN; top _ windows[w].top-header-40; SELECT TRUE FROM Control[] => windows[w].command.bluebug[windows[w].score]; Shift[] => windows[w].command.bluebug[windows[w].score]; ScreenPX < leftMargin => Scroll[w, Real.FixI[ScreenPY-top]]; ScreenPX > rightMargin => NULL; -- NewWindow[w, ScreenPY]; ENDCASE => windows[w].command.bluebug[windows[w].score]; }; HandleYellow: PROC = { w: CARDINAL; IF Command[] THEN RETURN; w _ FindWindow[ScreenPY]; IF w = 0 THEN RETURN; Select[w]; IF ScreenPX > 606 THEN RETURN; SELECT TRUE FROM Control[] => windows[w].command.yellowbug[windows[w].score]; Shift[] => windows[w].command.yellowbug[windows[w].score]; ScreenPX < leftMargin => windows[w].command.thumb[windows[w].score]; ScreenPX > rightMargin => NULL; -- SubWindow[w, ScreenPY]; ENDCASE => windows[w].command.yellowbug[windows[w].score]; }; ReadKeyboard: PROC = { ENABLE { String.InvalidNumber => { DisplayMessage["illegal number- type DEL to continue"]; badCommand _ TRUE; CONTINUE; }; TTY.Rubout => { DisplayMessage["command terminated"]; CONTINUE; }; Piece.Overflow => IF windows[selectedWindow].score = old THEN windows[selectedWindow].score _ new; }; EraseMessage[]; windows[selectedWindow].command.keyboard[windows[selectedWindow].score]; }; ChangeCursor: PROC = { newState: CursorState; MousePoint[]; [ScreenPX, ScreenPY] _ WorldToUser[screen, MousePX, 808 - MousePY]; IF ScreenPX > 606 THEN RETURN; SELECT TRUE FROM FindCommand[ScreenPX, ScreenPY].command # NullProc => newState _ command; ScreenPY > windows[0].bottom => newState _ commandwindow; ScreenPX > rightMargin => newState _ window; ScreenPX < leftMargin => newState _ scroll; ENDCASE => newState _ screen; IF newState = currentState THEN RETURN; IF currentState = screen THEN oldCursor _ GetCursorPattern[]; SELECT newState FROM window => SetCursorPattern[windowCursor]; command => SetCursorPattern[bullseyeCursor]; scroll => SetCursorPattern[scrollUpDownCursor]; commandwindow => SetCursorPattern[textCursor]; ENDCASE => SetCursorPattern[oldCursor]; currentState _ newState; }; oldCursor: Cursor _ textCursor; CursorState: TYPE = {window, scroll, command, screen, commandwindow}; currentState: CursorState _ screen; Scroll: PROC[w: CARDINAL, y: INTEGER] = { IF y > 0 THEN SetCursorPattern[scrollUpCursor]; IF y < 0 THEN SetCursorPattern[scrollDownCursor]; windows[w].command.scroll[windows[w].score, y]; SetCursorPattern[scrollUpDownCursor]; }; MousePoint: PROC = { x, y: REAL = 1; MousePX _ x*mouse.x; MousePY _ y*mouse.y; }; MousePX, MousePY: REAL; ScreenPX, ScreenPY: REAL; <<******************************************************************>> <> <<******************************************************************>> DrawScreen: PROC = { i: CARDINAL; FOR i IN [0..noWindows) DO windows[i].command.display[windows[i].score, TRUE] ENDLOOP; }; MoveWindow: PROC[y: REAL] = { i, a, w: CARDINAL _ 0; dist, last: REAL _ 1000; SetCursorPattern[moveWindowCursor]; FOR i IN [1..noWindows) DO IF (windows[i].top-y < dist OR y-windows[i].top < dist) AND FindWindow[windows[i].top +1] # 0 THEN { dist _ ABS[windows[i].top-y]; w _ i; }; ENDLOOP; IF w = 0 THEN RETURN; a _ FindWindow[windows[w].top +1]; DisplayHeader[white, w]; WHILE RedBug[] DO NULL; ENDLOOP; MousePoint[]; [ScreenPX, ScreenPY] _ WorldToUser[screen, MousePX, 808 - MousePY]; y _ ScreenPY; last _ windows[w].top; IF y > windows[a].top - 16 THEN y _ windows[a].top - 16; IF y < windows[w].bottom + 16 THEN y _ windows[w].bottom + 16; MoveContext[w, y]; windows[a].bottom _ y; windows[w].top _ y; SetClipper[a]; SetClipper[w]; DisplayHeader[black, w]; IF last > windows[w].top THEN windows[a].command.display[windows[a].score, TRUE]; windows[w].command.display[windows[w].score, TRUE]; Select[w]; }; NewWindow: PROC[w: CARDINAL, y: REAL] = { <> SetCursorPattern[newWindowCursor]; WHILE BlueBug[] AND NOT YellowBug[] DO NULL; ENDLOOP; IF YellowBug[] THEN { DeleteWindow[w]; RETURN; }; DefaultWindow[noWindows, y, windows[w].bottom]; windows[w].bottom _ y; Select[noWindows]; DisplayHeader[black, noWindows]; SetClipper[w]; SetClipper[noWindows]; noWindows _ noWindows + 1; }; SubWindow: PROC[w: CARDINAL, y: REAL] = { <> SetCursorPattern[subWindowCursor]; WHILE NOT BlueBug[] AND YellowBug[] DO NULL; ENDLOOP; IF BlueBug[] THEN { DeleteWindow[w]; RETURN; }; Flash[NIL]; }; FindWindow: PROC[y: REAL] RETURNS[CARDINAL] = { i: CARDINAL; FOR i IN [0..noWindows) DO IF y < windows[i].top AND y > windows[i].bottom THEN RETURN[i]; ENDLOOP; RETURN[0]; }; DeleteWindow: PROC[w: CARDINAL] = { neighbor: CARDINAL; SetCursorPattern[windowCursor]; Invert[windows[w].context]; WHILE BlueBug[] AND YellowBug[] DO NULL; ENDLOOP; Wait[1]; Invert[windows[w].context]; IF BlueBug[] OR YellowBug[] THEN RETURN; neighbor _ FindWindow[windows[w].top + 1]; IF neighbor # 0 THEN { windows[neighbor].bottom _ windows[w].bottom; DisplayHeader[white, w]; } ELSE { neighbor _ FindWindow[windows[w].bottom - 1]; IF neighbor # 0 THEN { MoveContext[neighbor, windows[w].top]; DisplayHeader[white, neighbor]; windows[neighbor].top _ windows[w].top; DisplayHeader[black, neighbor]; }; }; IF neighbor = 0 THEN { DisplayMessage["cannot delete that window"]; RETURN; }; noWindows _ noWindows - 1; Heap.FreeMDSString[, windows[w].file]; windows[w] _ windows[noWindows]; SetClipper[neighbor]; Select[neighbor]; windows[neighbor].command.display[windows[neighbor].score, TRUE]; }; Invert: PROC[dc: Context] = { SetStipple[dc, black]; [] _ SetPaintMode[dc, invert]; DrawBox[dc, [0, 0, 1024, 808]]; [] _ SetPaintMode[dc, opaque]; }; MoveContext: PROC[w: CARDINAL, y: REAL] = { siy, soy, tiy, toy: REAL; siy _ y; tiy _ windows[w].top; [, soy] _ Map[screen, windows[w].context, 0, siy]; [, toy] _ Map[screen, windows[w].context, 0, tiy]; Translate[windows[w].context, 0, soy- toy]; }; Select: PROC[w: CARDINAL] = { SetBrush[black, transparent]; DrawBox[screen, [20, windows[selectedWindow].top- header- 10, 28, windows[selectedWindow].top- header]]; SetBrush[grey, opaque]; DrawBox[screen, [20, windows[w].top- header- 10, 28, windows[w].top- header]]; selectedWindow _ w; }; selectedWindow: CARDINAL _ 1; listenWindow: CARDINAL _ 1; DefaultWindow: PROC[w: CARDINAL, top, bottom: REAL] = { windows[w] _ [, , , unknown, @unknownProcs, top, bottom]; windows[w].context _ CopyContext[screen]; windows[w].file _ Heap.MakeMDSString[, 40]; Translate[windows[w].context, 30, top - header - 40]; -- 30 regular, 45 for videotaping SetClipper[w]; SetStipple[windows[w].context, black]; [] _ SetPaintMode[windows[w].context, opaque]; DrawBox[windows[w].context, GetBounds[windows[w].context]]; windows[w].type _ logical; windows[w].command _ @Screen.commands; windows[w].score _ windows[w].command.initialize[windows[w].context]; }; <<******************************************************************>> <> <<******************************************************************>> DisplayCommandWindow: PROC[score: ScorePTR, erase: BOOL] = { i: CARDINAL; Erase[NIL, TRUE]; SetBrush[black, opaque]; ClearManager[]; DisplayCommand["FileIn", 30, 750, FileIn]; DisplayCommand["PlayBack", 110, 750, Play]; DisplayCommand["Print", 215, 750, Hardcopy]; DisplayCommand["Quit", 300, 750, Quit]; DisplayCommand["Record", 385, 750, Listen]; DisplayCommand["FileOut", 480, 750, FileOut]; FOR i IN [1..noWindows) DO DisplayHeader[black, i] ENDLOOP; Select[1]; }; DisplayCommand: PROC[s: LONG STRING, x, y: REAL, proc: PROC[r: Box]] = { box: Box; SetCP[screen, x, y]; SetBrush[black, invert]; DrawRope[screen, LOOPHOLE[s]]; [box.xmin, box.ymin, box.xmax, box.ymax] _ RopeBox[font, LOOPHOLE[s]]; box.xmin _ box.xmin + x; box.ymin _ box.ymin + y; box.xmax _ box.xmax + x; box.ymax _ box.ymax + y; IF box.xmax - box.xmin < 30 THEN box.xmax _ box.xmin + 30; IF box.ymax - box.ymin < 10 THEN box.ymax _ box.ymin + 10; AddCommand[box, proc]; }; DisplayHeader: PROC[color: CARDINAL, w: CARDINAL] = { top: REAL _ windows[w].top; px, py: REAL; px _ 30; py _ windows[w].top - 16; SetBrush[color, opaque]; DrawBox[screen, [0, top-header, 620, top]]; DeleteCommand[px, py]; IF color = grey THEN SetBrush[grey, invert]; IF color = black THEN SetBrush[black, invert]; IF color = white THEN RETURN; DisplayCommand[windows[w].file, 30, top-12, EditFileName]; }; EraseMessage: PROC = { SetBrush[white, opaque]; DrawBox[screen, [0, 763, 620, 780]]; SetBrush[black, invert]; }; DisplayMessage: PUBLIC PROC[s: STRING] = { ls: LONG STRING _ s; IF s = NIL THEN {EraseMessage[]; RETURN}; SetBrush[black, opaque]; DrawBox[screen, [0, 765, 620, 780]]; SetBrush[black, invert]; SetCP[screen, 300 - RopeWidth[font, LOOPHOLE[ls]].xw/2, 767]; DrawRope[screen, LOOPHOLE[ls]]; }; AddCommand: PROC[r: Box, proc: PROC[r: Box]] = { FOR i: CARDINAL IN [0..mIndex) DO IF manager[i].command = proc THEN RETURN; ENDLOOP; manager[mIndex] _ [r, proc]; IF proc = Play THEN playIndex _ mIndex; IF proc = Listen THEN listenIndex _ mIndex; mIndex _ mIndex + 1; }; DeleteCommand: PROC[x, y: REAL] = { i: CARDINAL; FOR i IN [0..mIndex) DO IF manager[i].rect.xmin = x THEN { mIndex _ mIndex - 1; manager[i] _ manager[mIndex]; }; ENDLOOP; }; FindCommand: PROC[x, y: REAL] RETURNS[m: Image] = { i: CARDINAL; FOR i IN [0..mIndex) DO { m _ manager[i]; IF x > m.rect.xmin AND x < m.rect.xmax AND y > m.rect.ymin AND y < m.rect.ymax THEN RETURN[m]; }; ENDLOOP; m.command _ NullProc; RETURN[m]; }; Flash: PROC[score: ScorePTR] = { Invert[windows[selectedWindow].context]; Invert[windows[selectedWindow].context]; }; Erase: PROC[score: ScorePTR, erase: BOOL] = { SetStipple[screen, white]; [] _ SetPaintMode[screen, opaque]; DrawBox[screen, GetBounds[screen]]; SetStipple[screen, black]; [] _ SetPaintMode[screen, transparent]; }; <<******************************************************************>> <> <<******************************************************************>> Confirm: PROC[w: CARDINAL, s: STRING] RETURNS[BOOL] = { confirm: BOOL; IF windows[w].command.count = 0 THEN RETURN[TRUE]; DisplayMessage[s]; confirm _ TTY.GetChar[keyboard] = CR; EraseMessage[]; RETURN[confirm]; }; FileIn: PROC[r: Box] = { ENABLE Directory.Error => { DisplayMessage["no such file"]; DrawBox[screen, r]; CONTINUE; }; s: CARDINAL _ selectedWindow; SetBrush[black, invert]; DrawBox[screen, r]; IF Confirm[s, "the current file has not been filed out-- type CR to confirm"] THEN { IF windows[s].score # NIL THEN Piece.Free[windows[s].score]; windows[s].score _ windows[s].command.fileIn[windows[s].file]; EraseMessage[]; windows[s].command.display[windows[s].score, TRUE]; windows[s].command.count _ 0; }; DrawBox[screen, r]; }; FileOut: PROC[r: Box] = { ENABLE Directory.Error => { DisplayMessage["illegal file name"]; DrawBox[screen, r]; CONTINUE; }; s: CARDINAL _ selectedWindow; SetBrush[black, invert]; DrawBox[screen, r]; windows[s].command.fileOut[windows[s].score, windows[s].file]; windows[s].command.count _ 0; DrawBox[screen, r]; }; BackUp: PROC[w: CARDINAL] = { DisplayMessage["Please wait... storing file on backup.music"]; windows[w].command.fileOut[windows[w].score, "backup.music"]; windows[w].command.count _ 1; -- so it will look dirty EraseMessage[]; }; Play: PROC[r: Box] = { ENABLE Piece.Overflow => IF windows[selectedWindow].score = old THEN windows[selectedWindow].score _ new; windows[selectedWindow].command.play[windows[selectedWindow].score]; }; InvertPlay: PUBLIC PROC = { r: Box = manager[playIndex].rect; SetBrush[black, invert]; DrawBox[screen, r]; }; Listen: PROC[r: Box] = { ENABLE Piece.Overflow => IF windows[listenWindow].score = old THEN windows[listenWindow].score _ new; windows[listenWindow].command.listen[windows[listenWindow].score]; listenWindow _ selectedWindow; }; InvertListen: PUBLIC PROC = { r: Box = manager[listenIndex].rect; SetBrush[black, invert]; DrawBox[screen, r]; }; playIndex: CARDINAL _ 0; listenIndex: CARDINAL _ 0; Hardcopy: PROC[r: Box] = { SetBrush[black, invert]; DrawBox[screen, r]; DisplayMessage["Please wait... printing screen on music.press"]; windows[selectedWindow].command.hardcopy[windows[selectedWindow].score, "music.press"]; DrawBox[screen, r]; EraseMessage[]; }; EditFileName: PROC[r: Box] = { w: CARDINAL _ FindWindow[ScreenPY]; c, last: CHARACTER _ 040C; CR: CHARACTER _ 015C; IF w = 0 THEN RETURN; windows[w].file.length _ 0; DisplayMessage["Please enter filename."]; DisplayHeader[white, w]; DisplayHeader[black, w]; DO { c _ TTY.GetChar[keyboard]; IF c = 177C OR c = 010C THEN { IF windows[w].file.length = 0 THEN LOOP; windows[w].file.length _ windows[w].file.length- 1; DisplayHeader[black, w]; LOOP; }; IF c = ' THEN { windows[w].file.length _ 0; DisplayHeader[black, w]; LOOP; }; IF c # CR AND c # '. AND c # 033C THEN { String.AppendChar[windows[w].file, c]; DrawChar[screen, c]; LOOP; }; String.AppendString[windows[w].file, ".music"]; windows[w].type _ logical; EXIT; }; ENDLOOP; DisplayHeader[black, w]; EraseMessage[]; Select[w]; }; Quit: PROC[r: Box] = { IF NOT Confirm[1, "type CR to confirm Quit"] THEN RETURN; <> <> }; ClearManager: PROC = { mIndex _ 0; }; manager: ARRAY [0..20) OF Image; Image: TYPE = RECORD[rect: Box, command: PROC[r: Box]]; mIndex: CARDINAL _ 0; mMax: CARDINAL = 20; <<******************************************************************>> <> <<******************************************************************>> SetBrush: PROC[tex: CARDINAL, pnt: Graphics.PaintMode] = INLINE {Graphics.SetStipple[screen, tex]; [] _ Graphics.SetPaintMode[screen, pnt]}; SetClipper: PROC[w: CARDINAL] = { box: Box; [box.xmin, box.ymin] _ Map[screen, windows[w].context, 0, windows[w].bottom]; [box.xmax, box.ymax] _ Map[screen, windows[w].context, 650, windows[w].top - header]; ClipBox[windows[w].context, box]; }; Wait: PROC[t: CARDINAL] = { <> <> }; screen: PUBLIC Context; leftMargin: CARDINAL = 5; rightMargin: CARDINAL = 585; header: CARDINAL = 15; CR: CHARACTER = 015C; windows: ARRAY [0..10) OF Window; noWindows: CARDINAL _ 2; Window: TYPE = RECORD[ context: Context, file: STRING, score: ScorePTR _ NIL, type: WType, command: POINTER TO CommandProcs, top, bottom: REAL ]; WType: TYPE = {physical, graphical, logical, command, unknown}; commandProcs: CommandProcs; unknownProcs: CommandProcs _ [ Flash, Flash, Flash, Flash, Flash, Flash, , Flash, Erase, , , , , 0]; NullProc: PROC[r: Box] = { }; Initialize[]; END. ReadCommandLine: PROC = { ENABLE Directory.Error => { DisplayMessage["no such file"]; CONTINUE; }; char: CHARACTER; CR: CHARACTER = 015C; filename: STRING _ [40]; ending: STRING _ [12]; test, error: BOOL _ FALSE; hardcopy: BOOL _ FALSE; command, second, period: BOOL _ FALSE; inputStream: DiskHandle; inputStream _ NewByteStream["com.cm", Read]; inputStream.reset[inputStream]; DO IF inputStream.endof[inputStream] THEN EXIT; char _ inputStream.get[inputStream]; <> IF command THEN SELECT char FROM '/ => EXIT; 'n => NULL; 't => test _ TRUE; 'h => hardcopy _ TRUE; ' => command _ FALSE; ENDCASE => NULL; IF char = '/ THEN command _ TRUE; IF command THEN LOOP; <> SELECT TRUE FROM char = CR OR char = ' => NULL; inputStream.endof[inputStream] => NULL; char = '. => IF period THEN EXIT ELSE {period _ TRUE; LOOP}; period => {AppendChar[ending, char]; LOOP}; ENDCASE => {AppendChar[filename, char]; LOOP}; <> IF filename.length # 0 AND ~EqualString[ending, "image"] AND ~EqualString[ending, "bcd"] THEN { AppendString[filename, ".music"]; windows[1].file.length _ 0; AppendString[windows[1].file, filename]; DisplayHeader[black, 1]; DisplayMessage["Please wait-- retrieving file"]; <> windows[1].command.fileIn[filename, second]; EraseMessage[]; windows[1].command.display[windows[1].score, TRUE]; <> IF test AND Score.Test[] THEN {error _ TRUE; EXIT}; IF hardcopy THEN Hardcopy[[[215, 747], [249, 761]]]; second _ TRUE}; filename.length _ 0; ending.length _ 0; period _ FALSE; ENDLOOP; inputStream.destroy[inputStream]; <> IF test AND ~error THEN Quit[[[0, 0], [0, 0]]]; IF hardcopy THEN Quit[[[0, 0], [0, 0]]]; };