Join us on Discord!
You can help CodeWalrus stay online by donating here.

[nspire] nSquirrel : Squirrel programming language on Ti-Nspire

Started by Duke "Tape" Eiyeron, March 30, 2016, 08:31:51 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Duke "Tape" Eiyeron

nSquirrel
Squirrel on Ti-Nspire

Last release version (v1.0.1) : https://github.com/Eiyeron/squirrel/releases/tag/nsquirrel_1.0.1 (includes documentation, which the binary linked to this post doesn't)
Project repository : https://github.com/Eiyeron/squirrel/
nSquirrel (interpreter + n2SDLib) branch : https://github.com/Eiyeron/squirrel/tree/nSquirrel


"Squirrel is a high level imperative, object-oriented programming language, designed to be a light-weight scripting language that fits in the size, memory bandwidth, and real-time requirements of applications like video games."

(Translation : it's a lightweight script language destined to be embedded in programs like Lua does.)

[spoiler=Base language features]
Although Squirrel offers a wide range of features like:

  • - Open Source MIT licence
  • dynamic typing
  • delegation
  • classes & inheritance
  • higher order functions
  • lexical scoping
  • generators
  • cooperative threads(coroutines)
  • tail recursion
  • exception handling
  • automatic memory management (CPU bursts free; mixed approach ref counting/GC)
  • both compiler and virtual machine fit together in about 7k lines of C++ code and add only around 100kb-150kb the executable size.
  • optional 16bits characters strings
  • powerful embedding api

    • eg. function/classes can be defined by scripts or in C
    • eg. objects can fully exist in the VM or be bound to native code
    • eg. classes created in C can be extended by scripts or vice-versa
    • and more
[/spoiler]

nSquirrel is a fork of this language destined for Ti-Nspires. The core language will be easily embeddable into Ndless projects as the project offers libraries and API to mess with it. Thus, it's included with bindings to n2DLib to allow playing with the screen and the keyboard.

Instructions :
- Download the archive containing the program (sq.tns) and if wanted, the example scripts.
- Install your sq.tns on your calc's nspire folder
- Now you can launch the interpreter for an interactive session ( quit() to exit it) or launch a .nut script (only after running the exectuable once). NOte that thanks to nspireio, you have to press twice Enter to validate your input.
- The interpreter registering itself to open .nut files, to execute such scripts, you will just have to click on them.

Notes
- For further versions, I'll probably provide two versions of the binaries, ones to compile nSquirrel's interpreter (which uses Nspire-IO) and one to be included in projects.
  • Calculators owned: A lot.

novenary

Awesome, now you should be able to make bindings for Nspire specific things besides Nspire-IO (which isn't hard to integrate by the way).

Dream of Omnimaga

Awesome Eiyeron. If this gets completed and allow everyone to launch the binary directly without much hassle, then this will be a great addition to other Nspire languages. Now we have BASIC, Lua, ASM, C, Python, Javascript and Squirrel. :)
  • Calculators owned: TI-82 Advanced Edition Python TI-84+ TI-84+CSE TI-84+CE TI-84+CEP TI-86 TI-89T cfx-9940GT fx-7400G+ fx 1.0+ fx-9750G+ fx-9860G fx-CG10 HP 49g+ HP 39g+ HP 39gs (bricked) HP 39gII HP Prime G1 HP Prime G2 Sharp EL-9600C
  • Consoles, mobile devices and vintage computers owned: Huawei P30 Lite, Moto G 5G, Nintendo 64 (broken), Playstation, Wii U

Ivoah

Quote from: DJ Omnimaga on March 30, 2016, 03:10:36 PM
Awesome Eiyeron. If this gets completed and allow everyone to launch the binary directly without much hassle, then this will be a great addition to other Nspire languages. Now we have BASIC, Lua, ASM, C, Python, Javascript and Squirrel. :)
Don't forget C++
  • Calculators owned: TI-86 (now broken), TI SR-56, TI-Nspire CX CAS, TI-84+ SE, TI-84+ SE, TI-85, TI-73 Explorer VS, ViewScreen, TI-84+ CSE, TI-83+ SE

Dream of Omnimaga

Ah yeah, true. I always forget which of the C-compatible calculators (68K, Nspire, 83+, 84+CSE, 84+CE, PRIZM, 9860G, etc) supports C++, C# or not >.<.
  • Calculators owned: TI-82 Advanced Edition Python TI-84+ TI-84+CSE TI-84+CE TI-84+CEP TI-86 TI-89T cfx-9940GT fx-7400G+ fx 1.0+ fx-9750G+ fx-9860G fx-CG10 HP 49g+ HP 39g+ HP 39gs (bricked) HP 39gII HP Prime G1 HP Prime G2 Sharp EL-9600C
  • Consoles, mobile devices and vintage computers owned: Huawei P30 Lite, Moto G 5G, Nintendo 64 (broken), Playstation, Wii U

Duke "Tape" Eiyeron

#5
I had to cheat my way but it uses now nspireio to show and require input data. The biggest slowing thing is probably nspireio itself for now. The linked build should be working (at least on emulator. I need to find an USB cable).
I need to find a way to avoid the lib using it also. I mostly hacked the binary, but the runtime library uses printf at one place and would probably need another function instead.
  • Calculators owned: A lot.

Dream of Omnimaga

That's good to hear. I assume that sprites and such graphics cannot be displayed yet? Also, will this be compatible with the newer TI-Nspire CX CR4 hardware (the one with 240x320 screens flipped sideways instead of an actual 320x240 LCD)?
  • Calculators owned: TI-82 Advanced Edition Python TI-84+ TI-84+CSE TI-84+CE TI-84+CEP TI-86 TI-89T cfx-9940GT fx-7400G+ fx 1.0+ fx-9750G+ fx-9860G fx-CG10 HP 49g+ HP 39g+ HP 39gs (bricked) HP 39gII HP Prime G1 HP Prime G2 Sharp EL-9600C
  • Consoles, mobile devices and vintage computers owned: Huawei P30 Lite, Moto G 5G, Nintendo 64 (broken), Playstation, Wii U

Duke "Tape" Eiyeron

#7
IIRC nspireio has been updated to support the newer hardware. Though I don't really know how it works from Ndless' side and I probably suppose that a version check is done at every pixel acces (where one-time funptr selection would probably make up for the loss.)

EDIT : tested on calc and it works.
  • Calculators owned: A lot.

Dream of Omnimaga

There is a compatibility layer in Ndless 4.2, but if something updates the entire LCD every frame rather than just parts of it, then it will run 50 times slower, while stuff that does partial screen redraw will run 3 times slower. However, there is a way to achieve almost the same speed on newer hardware than older one. Basically, don't rely entirely on the Ndless 4.2 CR4 compatibility layer. :P
  • Calculators owned: TI-82 Advanced Edition Python TI-84+ TI-84+CSE TI-84+CE TI-84+CEP TI-86 TI-89T cfx-9940GT fx-7400G+ fx 1.0+ fx-9750G+ fx-9860G fx-CG10 HP 49g+ HP 39g+ HP 39gs (bricked) HP 39gII HP Prime G1 HP Prime G2 Sharp EL-9600C
  • Consoles, mobile devices and vintage computers owned: Huawei P30 Lite, Moto G 5G, Nintendo 64 (broken), Playstation, Wii U

gameblabla

That's an interesting project and all but i still think that the Shakespeare Programming Language is better.
I'm guessing though that you are not planning on supporting nSDL or any graphics library with Squirrel ?
  • Calculators owned: None (used to own an Nspire and TI-89)

Duke "Tape" Eiyeron

#10
That'd mean integrating with the source, as there isn't any dynamic libraries on ndless. THat's something more or less envisaged. Gotta take some time for it.

Note : Saved yesterday my calc from the weirdest brick : anything editing the flash (editing, creating, deleting files) would be automatically rollbacked. Had to reinstall the OS. >.>

Small latenight update : integrating n2Dlib. Every drawing functions are done, I need to figure what to do to store and manage sprites (blobs or sprites?...), but the rest seems to work
  • Calculators owned: A lot.

Duke "Tape" Eiyeron

#11
Pushed a new version containing n2DLib and bindings to every drawing function with n2d as prefix (minus drawPolygon), which means :


initBuffering
deinitBuffering
updateScreen
clearBuffer
clearBufferB
clearBufferW
getPixel
setPixelUnsafe
setPixel
setPixelRGB
drawHLine
fillRect
drawSprite
drawSpritePart
drawSpriteScaled
drawSpriteRotated
drawLine
fillRect
fillCircle
fillEllipse
drawString
drawDecimal
drawChar


Note that every function that asks for Rect asks for the four variables instead of said rect.

extern void drawSpriteScaled(const unsigned short*, const Rect*, int, unsigned short);

=> n2d.drawSpriteScaled(sprite, 0, 0, i, i, 0, 0)


For now, to draw a sprite, you need to convert your picture into a n2D sprite, and convert it with this function :

function array_to_blob(array)
{
   local b = blob(array[0]*array[1])
   foreach(v in array)
      b.writen(v, 'w')
   return b
}


Sample program:
[spoiler]

function array_to_blob(array)
{
local b = blob(array[0]*array[1])
foreach(v in array)
b.writen(v, 'w')
return b
}

local sprite = array_to_blob([
32, 32, 0x0000,
0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x181f,0x181f,0x181f,0x181f,0x181f,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,
0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x181f,0x181d,0x181d,0x181b,0x181d,0x181b,0x181d,0x181b,0x181d,0x181d,0x181f,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,
0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x181d,0x181d,0x181b,0x181b,0x1819,0x1819,0x1817,0x1817,0x1817,0x1819,0x1819,0x181b,0x181b,0x181d,0x181d,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,
0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x181f,0x181d,0x181b,0x1819,0x1819,0x1817,0x1817,0x1815,0x1815,0x1813,0x1815,0x1815,0x1817,0x1817,0x1819,0x1819,0x181b,0x181d,0x181f,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,
0x0e60,0x0e60,0x0e60,0x0e60,0x0e60,0x181f,0x181b,0x181b,0x1817,0x1817,0x1813,0x1813,0x1811,0x1811,0x1811,0x1811,0x1811,0x1811,0x1811,0x1813,0x1813,0x1817,0x1817,0x181b,0x181b,0x181f,0x0e60,0x0e60,0x0e60,0x0e60,0x0e60,0x0e60,
0x0dc0,0x0dc0,0x0dc0,0x0dc0,0x181f,0x181b,0x181b,0x1817,0x1815,0x1813,0x1813,0x100e,0x100e,0x100e,0x100e,0x100c,0x100e,0x100e,0x100e,0x100e,0x1813,0x1813,0x1815,0x1817,0x181b,0x181b,0x181f,0x0dc0,0x0dc0,0x0dc0,0x0dc0,0x0dc0,
0x0d40,0x0d40,0x0d40,0x181f,0x181b,0x1819,0x1815,0x1815,0x1811,0x1811,0x100e,0x100c,0x100a,0x100c,0x100a,0x100a,0x100a,0x100c,0x100a,0x100c,0x100e,0x1811,0x1811,0x1815,0x1815,0x1819,0x181b,0x181f,0x0d40,0x0d40,0x0d40,0x0d40,
0x0cc0,0x0cc0,0x0cc0,0x181d,0x181b,0x1817,0x1815,0x1811,0x1811,0x100c,0x100c,0x100a,0x100a,0x1008,0x1008,0x1008,0x1008,0x1008,0x100a,0x100a,0x100c,0x100c,0x1811,0x1811,0x1815,0x1817,0x181b,0x181d,0x0cc0,0x0cc0,0x0cc0,0x0cc0,
0x0c40,0x0c40,0x181d,0x181b,0x1817,0x1815,0x1811,0x1811,0x100c,0x100c,0x1008,0x1008,0x1006,0x1006,0x1006,0x1006,0x1006,0x1006,0x1006,0x1008,0x1008,0x100c,0x100c,0x1811,0x1811,0x1815,0x1817,0x181b,0x181d,0x0c40,0x0c40,0x0c40,
0x03a0,0x03a0,0x181d,0x1819,0x1817,0x1813,0x1811,0x100c,0x100c,0x1008,0x1008,0x1006,0x1006,0x1004,0x1004,0x1004,0x1004,0x1004,0x1006,0x1006,0x1008,0x1008,0x100c,0x100c,0x1811,0x1813,0x1817,0x1819,0x181d,0x03a0,0x03a0,0x03a0,
0x0320,0x181f,0x181b,0x1817,0x1813,0x1811,0x100e,0x100c,0x1008,0x1008,0x1006,0x1004,0x1002,0x1004,0x1002,0x1002,0x1002,0x1004,0x1002,0x1004,0x1006,0x1008,0x1008,0x100c,0x100e,0x1811,0x1813,0x1817,0x181b,0x181f,0x0320,0x0320,
0x02a0,0x181d,0x181b,0x1817,0x1813,0x100e,0x100e,0x100a,0x1008,0x1006,0x1006,0x1004,0x1004,0x1002,0x1002,0x1000,0x1002,0x1002,0x1004,0x1004,0x1006,0x1006,0x1008,0x100a,0x100e,0x100e,0x1813,0x1817,0x181b,0x181d,0x02a0,0x02a0,
0x0220,0x181d,0x1819,0x1815,0x1811,0x100e,0x100a,0x100a,0x1006,0x1006,0x1002,0x1002,0x1000,0x1002,0x1000,0x1000,0x1000,0x1002,0x1000,0x1002,0x1002,0x1006,0x1006,0x100a,0x100a,0x100e,0x1811,0x1815,0x1819,0x181d,0x0220,0x0220,
0x181f,0x181b,0x1819,0x1815,0x1813,0x100e,0x100c,0x1008,0x1008,0x1004,0x1004,0x1002,0x1002,0x1000,0x1000,0x1000,0x1000,0x1000,0x1002,0x1002,0x1004,0x1004,0x1008,0x1008,0x100c,0x100e,0x1813,0x1815,0x1819,0x181b,0x181f,0x0180,
0x181f,0x181b,0x1817,0x1815,0x1811,0x100e,0x100a,0x1008,0x1006,0x1004,0x1002,0x1002,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1002,0x1002,0x1004,0x1006,0x1008,0x100a,0x100e,0x1811,0x1815,0x1817,0x181b,0x181f,0x0100,
0x181f,0x181b,0x1819,0x1813,0x1811,0x100c,0x100c,0x1008,0x1006,0x1004,0x1004,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1004,0x1004,0x1006,0x1008,0x100c,0x100c,0x1811,0x1813,0x1819,0x181b,0x181f,0x0080,
0x181f,0x181b,0x1817,0x1815,0x1811,0x100e,0x100a,0x1008,0x1006,0x1004,0x1002,0x1002,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1002,0x1002,0x1004,0x1006,0x1008,0x100a,0x100e,0x1811,0x1815,0x1817,0x181b,0x181f,0x0000,
0x181f,0x181b,0x1819,0x1815,0x1813,0x100e,0x100c,0x1008,0x1008,0x1004,0x1004,0x1002,0x1002,0x1000,0x1000,0x1000,0x1000,0x1000,0x1002,0x1002,0x1004,0x1004,0x1008,0x1008,0x100c,0x100e,0x1813,0x1815,0x1819,0x181b,0x181f,0x0080,
0x0100,0x181d,0x1819,0x1815,0x1811,0x100e,0x100a,0x100a,0x1006,0x1006,0x1002,0x1002,0x1000,0x1002,0x1000,0x1000,0x1000,0x1002,0x1000,0x1002,0x1002,0x1006,0x1006,0x100a,0x100a,0x100e,0x1811,0x1815,0x1819,0x181d,0x0100,0x0100,
0x0180,0x181d,0x181b,0x1817,0x1813,0x100e,0x100e,0x100a,0x1008,0x1006,0x1006,0x1004,0x1004,0x1002,0x1002,0x1000,0x1002,0x1002,0x1004,0x1004,0x1006,0x1006,0x1008,0x100a,0x100e,0x100e,0x1813,0x1817,0x181b,0x181d,0x0180,0x0180,
0x0220,0x181f,0x181b,0x1817,0x1813,0x1811,0x100e,0x100c,0x1008,0x1008,0x1006,0x1004,0x1002,0x1004,0x1002,0x1002,0x1002,0x1004,0x1002,0x1004,0x1006,0x1008,0x1008,0x100c,0x100e,0x1811,0x1813,0x1817,0x181b,0x181f,0x0220,0x0220,
0x02a0,0x02a0,0x181d,0x1819,0x1817,0x1813,0x1811,0x100c,0x100c,0x1008,0x1008,0x1006,0x1006,0x1004,0x1004,0x1004,0x1004,0x1004,0x1006,0x1006,0x1008,0x1008,0x100c,0x100c,0x1811,0x1813,0x1817,0x1819,0x181d,0x02a0,0x02a0,0x02a0,
0x0320,0x0320,0x181d,0x181b,0x1817,0x1815,0x1811,0x1811,0x100c,0x100c,0x1008,0x1008,0x1006,0x1006,0x1006,0x1006,0x1006,0x1006,0x1006,0x1008,0x1008,0x100c,0x100c,0x1811,0x1811,0x1815,0x1817,0x181b,0x181d,0x0320,0x0320,0x0320,
0x03a0,0x03a0,0x03a0,0x181d,0x181b,0x1817,0x1815,0x1811,0x1811,0x100c,0x100c,0x100a,0x100a,0x1008,0x1008,0x1008,0x1008,0x1008,0x100a,0x100a,0x100c,0x100c,0x1811,0x1811,0x1815,0x1817,0x181b,0x181d,0x03a0,0x03a0,0x03a0,0x03a0,
0x0c40,0x0c40,0x0c40,0x181f,0x181b,0x1819,0x1815,0x1815,0x1811,0x1811,0x100e,0x100c,0x100a,0x100c,0x100a,0x100a,0x100a,0x100c,0x100a,0x100c,0x100e,0x1811,0x1811,0x1815,0x1815,0x1819,0x181b,0x181f,0x0c40,0x0c40,0x0c40,0x0c40,
0x0cc0,0x0cc0,0x0cc0,0x0cc0,0x181f,0x181b,0x181b,0x1817,0x1815,0x1813,0x1813,0x100e,0x100e,0x100e,0x100e,0x100c,0x100e,0x100e,0x100e,0x100e,0x1813,0x1813,0x1815,0x1817,0x181b,0x181b,0x181f,0x0cc0,0x0cc0,0x0cc0,0x0cc0,0x0cc0,
0x0d40,0x0d40,0x0d40,0x0d40,0x0d40,0x181f,0x181b,0x181b,0x1817,0x1817,0x1813,0x1813,0x1811,0x1811,0x1811,0x1811,0x1811,0x1811,0x1811,0x1813,0x1813,0x1817,0x1817,0x181b,0x181b,0x181f,0x0d40,0x0d40,0x0d40,0x0d40,0x0d40,0x0d40,
0x0dc0,0x0dc0,0x0dc0,0x0dc0,0x0dc0,0x0dc0,0x181f,0x181d,0x181b,0x1819,0x1819,0x1817,0x1817,0x1815,0x1815,0x1813,0x1815,0x1815,0x1817,0x1817,0x1819,0x1819,0x181b,0x181d,0x181f,0x0dc0,0x0dc0,0x0dc0,0x0dc0,0x0dc0,0x0dc0,0x0dc0,
0x0e60,0x0e60,0x0e60,0x0e60,0x0e60,0x0e60,0x0e60,0x0e60,0x181d,0x181d,0x181b,0x181b,0x1819,0x1819,0x1817,0x1817,0x1817,0x1819,0x1819,0x181b,0x181b,0x181d,0x181d,0x0e60,0x0e60,0x0e60,0x0e60,0x0e60,0x0e60,0x0e60,0x0e60,0x0e60,
0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x181f,0x181d,0x181d,0x181b,0x181d,0x181b,0x181d,0x181b,0x181d,0x181d,0x181f,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,0x0ee0,
0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x181f,0x181f,0x181f,0x181f,0x181f,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,0x0f60,
0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0,0x0fe0
])

n2d.initBuffering()

n2d.clearBuffer(0xf000)

for(local i = 1; i < 200; i++)
{
n2d.drawSpriteScaled(sprite, 160, 120, i, i, 0, 0)
n2d.drawLine(i, i, i*2, 240, 0x0000)
n2d.updateScreen()

}

for(local i = 0; i < 480; i++)
n2d.updateScreen()

n2d.deinitBuffering()

[/spoiler]
  • Calculators owned: A lot.

Duke "Tape" Eiyeron

#12
Update time : Added N2DLib's fixed functions, fixed a few (useless) warnings and some functions. I included in the zip a script I did from scratch to show pretty things on the screen

Small edit : I found how to make libs from the script side:

Let's say you have a file a.nut, right? HEre's its content :
local function func()
{
return 42
}

# Explicit root table setting. I'm setting a global variable called a which contains the function func at the index f.
::a <- {"f" : f}


So I can do from another script (or from the interpreter)

dofile("test.nut") // Loads file
print(a.f()) // a is now in the root table (::), so you can call its function f.
// And it'll print '42'


So yeah, I'm happily saying that Squirrel already allows user-scripted libraries :D So now, the biggest issue is organizing your libraries : Ndless doesn't allow relative paths IIRC (I need correction on this point but it was an issue on WRPG), like "subfolder/script.tns" but only absolutes path ("/documents/<path to your script>/subfolder/script.tns") which isn't really cool if you ever move your scripts not in the right place... I'll see what I can do to emulate this behaviour.
  • Calculators owned: A lot.

Dream of Omnimaga

  • Calculators owned: TI-82 Advanced Edition Python TI-84+ TI-84+CSE TI-84+CE TI-84+CEP TI-86 TI-89T cfx-9940GT fx-7400G+ fx 1.0+ fx-9750G+ fx-9860G fx-CG10 HP 49g+ HP 39g+ HP 39gs (bricked) HP 39gII HP Prime G1 HP Prime G2 Sharp EL-9600C
  • Consoles, mobile devices and vintage computers owned: Huawei P30 Lite, Moto G 5G, Nintendo 64 (broken), Playstation, Wii U

Dudeman313

That creature in the picture doesn't exactly look like a squirrel...?
  • Calculators owned: TI-84 PCE
  • Consoles, mobile devices and vintage computers owned: Android O Phone
Does this qualify as a signature? 
The answer is "Sure."


Powered by EzPortal