Announcing Cockatrice III

Well I was shuffling files back and forth into Shoebill, and with the advent of Ethernet support, I decided I wanted to build an AppleTalk network.  This endeavor seems to have taken a life of it’s own.

So, the first thing I did was tear into minivmac, as I figured it would be the easiest to modify, as ‘mini’ is in it’s name.  But it’s more geared to LocalTalk.  From it’s readme:

It does this by converting the LocalTalk packets between SDLC frames in the virtual machine to LocalTalk Over Ethernet (LTOE) packets.  These LTOE packets will be sent out the host machines Ethernet interface and will reach any other machine on the LAN.  LTOE packets are not routable and not recognized by EtherTalk devices.

Which is pretty creative, but I want to talk to A/UX, Windows NT and Cisco routers.  So this isn’t going to work out for me.

The next other ‘big’ names in Macintosh emulation are Basilisk II and SheepShaver.  Both of which are from Christian Bauer which is a sizable download (or so I thought) and has a very confusing release versions for Windows. So I went ahead and tried BasiliskII, which only does some native networking via a TUN/TAP & bridge solution (which is really popular solution for plenty of UNIX based stuff), which personally I don’t really care for.  The Windows version does support SLiRP, but for some strange and annoying reason it always crashes when I try to download anything big.  As a matter of fact, the Windows version crashes, a lot!

While digging around for various builds of Basilisk II, I found the defunct sourceforge page, which is thankfully still up.  And there I found the 0.8 and 0.9 release source code, which weighs in at a tiny 350kb in size.  This is something I could probably dive into.  So I went ahead and tried to build it on a Debian 7 x86 VM.  And much to my surprise, after altering configure to accept GCC 4.7, and forcing it to turn X11 on (I don’t know why it kept failing to detect it), I was able to build a binary in no time.  Even better, it worked!

So the first few goals were simple, I wanted to take 0.8 and remove it’s dependency on X11,and make it use SDL 1.2.  Why not SDL 2.0?  Well 2.0 is more about 3d space, and even to render a flat framebuffer it uses streaming textures.  Which is too heavy for me, so I’m sticking with 1.2.  I took a bunch of code from SDLQuake, and after a while of bashing it around, I was able to open a window, and capture some ouput from the framebuffer.  With even more bashing around I got it to work correctly.  I did make some small tweaks though, it only supports 8bit depth.  But I’m interested in networking, so 256 colours is fine by me.  Now that i could see what I was doing, I was able to then re-compile on OS X, and I was greeted with the Mac Boot screen.  The harder part was Windows, as the system code written by Lauri Pesonen who did an excellent job of porting BasiliskII to Windows, but to say their code took 100% advantage of the Win32 API would be an understatement.. And I wanted something more pure to being SDL so I really couldn’t use much of that code.  And what code I could find it was for far later versions.  However with enough pushing I did finally get BasiliskII to boot up on Windows.  I was once more again bitten by the fact that open on Windows defaults to being in ASCII mode.

The next thing to add was SDL input for the keyboard and mouse.  And at this point googling around for an example of an input loop for SDL that is appropriate for an emulator I stumbled uppon the fact that there already was a SDL support built into the more current version of Basilisk II.  But for some strange reason I kept going ahead, and incorporated some of the code into my 0.8 branch.  And then I could finally send some keystrokes, move the mouse, and click on things!  Things were looking up!

While looking at the SDL code, I did see they also have audio support, so I went ahead and borrowed the skeleton framework from there, although the initialization didn’t work at all as BasiliskII had drifted in how it hooked into the native sound support.  So I once more again turned to SDLQuake, and I was able to initialize sound, and Even get QuickTime to play the old Quadra quicktime video, which was the first QuickTime thing I’d ever seen, back when they were still making Quadras.

So now with video and sound in place, it was finally time to tackle the networking.  At first this seemed quite easy to do, and using SIMH for inspiration I was able to quickly replace the tun/tap code with some pcap code to open the interface, send packets, and receive packets.  One more again I started on Linux, made it build on OS X, although my MacBook air doesn’t have anything I can really inject packets into so I don’t know if it actually works.  The bigger test for me was on Windows with a GNS3 network, and with a few more minor changes I was happily sending AppleTalk to both Shoebill and Windows NT.

The next thing I wanted to tackle was SLiRP support.  Ironically to bring SLiRP to Shoebill I used the SLiRP from the github of Basilisk II.  At this point I figured this would be very simple, and I could wrap up later that day.  It ended up taking me three days.  Once more again my build would crash all the time, just like the later Basilisk II builds.  Using Internet Explorer 4.0.1 would seemingly crash the whole system within seconds with faults in SLiRP’s slirp_select_fill, and slirp_select_poll functions.  Now if you don’t call these functions SLiRP doesn’t process it’s TCP state and you end up with barely functioning UDP to only SLiRP which isn’t great beyond DHCP and DNS.  First I tried semaphores which only made things worse as the nature of Basilisk II’s threaded nature just made the requests stack up deadlocking within seconds.  I tried a mutex, timed mutexes and various other locking methods insdide of SLiRP and Basilisk II to no end.  Netscape would kind of work, but IE would crash the whole thing out after a few pages. Then a better solution hit me as I was playing with the system clock on the Windows build.  There is a 60Hz timer that calls a 1Hz timer once every 60 ticks.  What if I had the clock drive SLiRP?  And to my amazement not only did that work, but it worked great until I hit another problem that I had with Shoebill (that needs to be fixed now that I found away around it here).  There is a static buffer that passes data between SLiRP’s callback when it is going to send a packet to BasiliskII and when Basilisk II then feeds the packet to MacOS.  With enough traffic it will overwrite part of itself as they are on two different threads.  Once more again I tried semaphores, which of course is the wrong tool here as if something is stacking waiting for it to unstack is just crazy, and more mutexes.  The mutexes kind of worked but performance was horrible, as in 1992 dialup speed horrible.  And I didn’t want to simulate a 1992 internet experience 100%

So the obvious solution as a queue.  I took a simple queue implementation, added the ability to peek, changed it to accept a packet structure and I was set.  Now I only needed a mutex when I queued items, and dequeued them.  But I could hold 100 packets easily.

So with all that in place I can finally download files greater than 10MB, and even with Internet Explorer!


124MB in 8 minutes!

So the next was to make Pcap dynamically loaded, which for C++ is a bit of fun with __cdecl, GetProcAddress and all that fun.  But I had it working after a bit so now if the user doesn’t have WinPcap installed they don’t get an error message, and I don’t have to maintain two builds.  Nobody likes doing that kind of stuff.  Ever.

Multitasking.. Kind of.

Multitasking.. Kind of.

There is still plenty of things broken afterall I’m using an ancient version of Basilisk to base this off of. I’ve also removed a bunch of features as I wanted to make this more of a ‘core’ product with again a focus on networking.

Will this interest the majority of people? Probably not.  But for anyone who wants to actually download a file this may be somewhat useful.

Where to go from here?

Well there is still a lot of OS specific stuff in the code that I want to convert to SDL.  I’d like to build from a 100% more generic code tree rather than having private files here and there.  The CPU optimization programs that re-read GCC’s assembly output don’t do anything.  I want to try it through an older version of GCC and see if there is any difference in speed.  I also recently received the source code to vc5opti.cpp and I’d like to try that to see if it speeds up the Windows Visual C++ based build.  Long term I’d love to patch in the UAE CPU code from the newer versions that have a far more solid 68030/68881 and 68040 emulation.  The price of standing on so many tall shoulders is that when I fall off I don’t know if the CPU exceptions I see are faults in the CPU emulation, Basilisk II or just plain crashes in MacOS which was certainly not the most stablest thing once you mixed in multimedia and networking.  It was par with Windows 3.1, which honestly both of them were ‘saved’ with help from the older generation, ala BSD Unix for MacOS, and the VMS team for Windows.

So after all this I’m ready to release some binaries, and code.  Although the last thing I wanted to do is add more confusion by calling this Basillisk II v0.8.SOMETHING … A quick google search on Basilisk gave me this:

As for some reason I actually never did look up what a Basilisk was.  So seeing that this project is basically the same thing I chose Cockatrice.

The Cockatrice III source forge page is here, Windows binaries, Mac OS X binaries, and source code here.

There are plenty of bugs, and plenty of things not working, but it works well enough to do things, and that is a credit to everyone who worked on Basilisk II before me.

37 thoughts on “Announcing Cockatrice III

  1. Couldn’t help myself! Had a go with it just now, using SLIRP on my MBA Wifi.
    I could connect to AppleShares via TCP on my Windows 2003 VM and a Netatalk share on a Ubuntu VM. Obviously Netscape works, and Internet Explorer 3 ran quite well too.

    • Awesome glad to hear it! Unfortunatly AFS won’t work behind (nat) so I’ve heard. I’m pretty sure I can cook up a solution in the future, probably along the lines of what HecNET does or SoftPC did back in the day with a reflector program that you’d point to and it’ll decap the packets and put them on the wire.

      But if you use a ‘wired’ connection it should work. I have some more fixes that include some more stability for SLiRP, and a disk mounting feature that’s driven me insane since I can remember. Oh and a better ‘null’ serial driver that hopefully doesn’t get wrapped up in some C++ virtual void constructer issues.

      • I’ll give the wired part a go tonight. It’d be great just to see the Apple Talk shares appear in Chooser without having to enter the IP in.

        What is the disk mounting feature you’re thinking of?

  2. Hmm, I could have some fun with this, mostly because my local network already has some EtherTalk speaking devices and a LocalTalk bridge.

    If you need more Appletalking “stuff” to play with, check out the A2SERVER virtual machine, it runs netatalk and supports Apple II netbooting… which leads to GSport 0.31, which has Appletalk AFP/printer client support (it does the SDLC to Ethernet thing similar to what minivmac does) and can even net boot from a real Mac running Appleshare 3.0 or A2SERVER.

    • What I still dont understand is why tools like macping can find my router, all the zones, and even devices in other zones, but things like Doom or nettrek cannot find other nodes… I know it has something to do with the broadcasting.

      • I got this up and running on Win32. My System 7.1.1 (Pro) install likes to crash and burn when I switch networking from Localtalk to the Built-In Ethertalk. I got a ton of Illegal Instructions in the console window and either the emulator crashes completely or it just sits at the “Switching your Appletalk Connection” dialog. Naturally this is with “Classic Networking” and not Open Transport.

        • What ROM/settings are you using? I’ve installed 7.1.1 (pro) off floppies..

          I’ve found that AppleTalk really introduces quite a bit of overhead, while something that doesn’t have AppleTalk in ROM, say the Quadra 700 seems much faster.

    • Fixed the problem, it was the ROM I was using. Switched to a Quadra 650 ROM and winpcap networking works. Open Transport is VERY grumpy about joining an Ethertalk network with a router created named zone and basically doesn’t connect at all
      (it stays in the “*” zone). It might be clashing because I’m running netatalk 2.2.4 on a VirtualBox VM on the same machine. TCP/IP works fine and OT pulls an address via DHCP.

      Classic Networking does seem to join named zones without a problem. Neither network stack can see the netatalk server’s AFP services, but the HP printer on my network works fine.

      I need to play with this more using actual hardware. I have plenty of Macs laying around and a physical Appletalk router that can create named zones. Whats odd is GSport seems to have no problem talking to a VirtualBox hosted netatalk install on the same machine.

      • I’m using the same method that SIMH uses, and that too has issues talking to the host machine. What I’ve done is installed VMWare Player, added a bunch of it’s network interfaces, then I use GNS3 setup a cisco router and use that to access it.

        I would suppose the ‘sane’ version would be to install the Microsoft loopback adapter, and connect the EMU into that… You could try to bridge your Ethernet and the loop and it may work.

        I made some more changes with slirp as it was crashing hard with VC.. Which it doesn’t now but some things get ‘stuck’. QuickTime just stammers and quits, while it works ok on GCC based stuff. More diving around required.

      • OK, the issues are with running netatalk on a VM on the same machine. Setting up a real Powermac G3 with OS 9.2.2 I was able to connect to and share between the emulated Mac and the real one in both directions. Whats weird is the G3 was able to connect and use both the netatalk shares and the Basilisk II machine’s shares at the same time! The loopback device or emulated network setup would likely resolve these problems.

    • I wanted a good ‘client’ to Shoebill’s server side. And looking at the source here, what they do if you try to close BasiliskII is that it hits the power button on the keyboard.. Maybe a better option for Shoebill?

      I’ve started to implement the sleep stuff so this ancient client won’t soak 2 cores on anything I run it on. I even managed to find my old 10.6 stuff and built a PowerPC binary which runs on rosetta… Although I don’t know if there are any G5 users still out there.

        • I used to have a quad G5 that I got on ebay for a couple hundred.. It was an awesome box, 4xG5’s at 2Ghz with 8GB of ram. Although the box ran fine, when everyone jumped ship that was pretty much the end of it. But compared to the intel stuff, that G5 was HOT and LOUD. I kind of don’t miss it that much.

  3. Sorry to break it to you, but you completely wasted your time. A 68k Mac emulator – an actual emulator, not a simulator like Basilisk which doesn’t even emulate any of the low-level hardware – with SDL 1.2 and pcap support already existed on OS X. It’s called MESS. Basilisk II is a complete hack-job and pretty much traps all toolbox ROM calls into its own high-level emulation rather than bothering to emulate the actual chipsets, as MESS does.

    • Moving data in and out of MESS is a nightmare. I wouldn’t call it a waste of time. The fact that Basilisk could barely transfer a file without crashing, and sheepshaver is barely more stable than that I’d hardly call this a waste of time.

      My primary purpose was to build something that I could use as an AppleTalk client on a cisco network with NT servers, and A/UX via ShoeBill. The secondary purpose was to write to hard files with an Apple Partition table.

      I can pretty much do what I wanted to do, I just want to put in more SDL, take out as much of the system dependant stuff as I can and try to update the CPU core.

      I know MESS strives for accuracy, but usability has been a nightmare for me.

    • I had typed up a long reply but then my cat took care of that.

      The GUI only edits a simple text file. Once you see that you realize the GUI really isn’t all that interesting or important. What would be more interesting is a way to add disks at runtime.

      I want to import the WinUAE CPU core, which is no doubt more solid, and it impliments 68881/68882 along with MMu’s and of course 68020, 68030 and 68040. It’s good enough on the Amiga it’ll run NetBSD, Linux and AMIX. A port is used in Previous which allows NeXTSTEP to boot with it’s 68030 and 68040 support.

      If you want A/UX use shoebill. My major goal in doing this is for a MacOS client for ShoeBill, and to see an AppleTalk network in action.

      • Would be nice if you could importe scsi.c from Lauri’s BasiliskII and uspate to support Windows SPTI device interface. 0.9 executable versions are already showing his age, and since their SCSI emulation module was built with ASPI in mind, it doesn’t work at all in modern windows versions starting Vista (FrogASPI doesn’t work well with Win7 SPTI and the updates that MS did to the storage stack, tested days ago)

        • I haven’t even looked at the scsi stuff. I was hoping at some point to move the disk stuff into there, so it wouldn’t be a bunch of floppies.

          I guess people use it for a passthru? There is a bunch of NT code in there, along with Windows 2000, but the only build package I could compile was the Windows 98 target.

          give me an application scenario as this may sound funny but I never really used MacOS, and BasiliskII just crashed so easily I never really got into it. It’s Shoebill that sparked this interest as I started building a client using MESS, but it can’t use high density disks so you have to feed it from Basilisk II, and MESS just wouldn’t recognize my imported hfv, so that is when I started to look to see if I could just fix Basilisk II to fit my needs.

      • Well, i used the SCSI support for 2 specific things.

        1. Image HFS and hybrid HFS/ISO or HFS/Audio (mostly games) commercial CDs with Toast, when things like ImageBurn, Alcohol or such utilies where in very early phase and didn’t liked MacOS CD’s.

        2.- Burn data and bootable pre-OSX MacOS cd’s for some old macs that one of my friends had at home, also with Toast.

        3.- Install MacOS to Apple Partition Map based HDD images when the SCSI image support was still not available in any emulator. Most people thinks that Basilisk could be only installed in style superfloppy images, and probably that’s true for *nix versions, but Lauri’s BasiliskII SCSI support allows to connect a external HDD to emulator via ASPI interface. If you install a software that emulates an HBA and SCSI Disks, like Total Mounter or Win7 VHD image mount support, is possible instruct Basilisk to use the emulated scsi disks exposed by those software packages (tested with TotalMounter in WinXP, doesn’t work with win7 VHD because FrogASPI, the only ASPI emulator which can team with Basilisk, doesn’t like Win7 SPTI implementation, due a bug)

        Amazing enough, those HDD bootable images can be DDed to real scsi disks to boot old mac systems without CD or floppy drives.

        Lauri’s version 0.9pre-NT was enough stable to allow me to do that. Probably there are other applications, like connect old SCSI based samplers to MacOS to drive them with their native software that was only built for those older MacOS versions and such.

        • Wow that is pretty intense! I see here that there is some support for SCSI passthru in NT, and always has been there.

          When you plug in a hard disk, was it possible to partition/format it with Basilisk II, and boot from it?

          I think it may be kind of interesting to try to write a SCSI back end that passes down to virtual CD’s or disk images directly so I don’t have to load stuff with more device drivers on my system.

          And it’d be cool to have ‘real’ disks and CD’s unlike the giant floppy thing which I don’t think anyone has ever liked.

      • “When you plug in a hard disk, was it possible to partition/format it with Basilisk II, and boot from it?”

        Yes, with Lauri’s windows port was completely possible, assuming that you’re using an extra HDD for MacOS, and the disk is completely dismounted from windows (no disk partitions mounted from windows).

        This will work well for both IDE and SCSI drives in XP, assuming that you’re using FrogASPI as SCSI interface, or Adaptec drivers with ATAPI.sys miniport whitelisted in the registry.

        And yeah, would be nice to have both SCSI passthough support and virtual scsi hdd image support, like the one found in Previous NextStep emulator.

        • Well looking at the previous code for SCSI, it looks quite dooable.

          I know I’m already getting SCSI commands from the Apple ROM so it is just a matter of passing in and out correctly.

          Can you give me pointers to working binaries and or source to a version of Basilisk II that worked with SCSI passthru? 98 or NT is ok, I preferably want source so I can see exactly what is going on.

          Also do you have any Apple SCSI disks? I know Mac’s are pretty picky about their disks as I spent far too long the first time I did an A/UX install trying to partition the disk to find out that the Apple tool only works with their OEM’d disks…. Unless you ‘patch’ it, although I’d rather just return the information that it is looking for so we don’t have to go through that nonsense.

    • “I see here that there is some support for SCSI passthru in NT, and always has been there.”

      In effect, FrogASPI is an ASPI/STPI layer translator, like NeroASPI and other similar wrappers built on top of STPI. The difference is that Basilisk doesn’t work at all with NeroASPI, while FrogASPI teams pretty well with it even for devices that aren’t disks, like cd/dvd burners, scanners and such.

      FrogASPI was a pretty ASPI/STPI wrapper, but doesn’t work with windows vista/7 due that bug i mentioned earlier.

      • Well I started to take a look at the SCSI and it really is a passthru.

        B2: 10/13/14 08:26:58:295 SCSISelect 1
        B2: 10/13/14 08:26:58:295 SCSICmd len 6, cmd 080000000100032300010001
        dummy: set cmd len 60 command 8 0 0 0 1 0
        dummy: scsi_set_target 1 0
        B2: 10/13/14 08:26:58:295 SCSIRead TIB 0400f974
        B2: 10/13/14 08:26:58:295 1 0400f990 512
        B2: 10/13/14 08:26:58:295 7 20144080 1939603556
        B2: 10/13/14 08:26:58:295 SCSIComplete wait 60, msg 000009fc, stat 000009fa
        dummy: scsi_send_cmd lenght 512, reading 1(bool) sg_size 1, sg_ptr, sg_len, 2686
        302 stat, 60 timeout
        B2: 10/13/14 08:26:58:295 SCSIGet

        Here is the ROM attempting to do a command 8, aka READ_6 . So it looks like it can even boot from SCSI devices.

        And here later on, the disk tool is doing this:

        B2: 10/13/14 08:34:38:181 SCSICmd len 6, cmd 000000000000000000000000
        dummy: set cmd len 932 command 0 0 0 0 0 0
        dummy: scsi_set_target 1 0

        B2: 10/13/14 08:34:38:181 SCSICmd len 6, cmd 120000002400000000000000
        dummy: set cmd len 120 command 12 0 0 0 24 0

        With commands 0 being TEST_UNIT_READY and command 12 INQUIRY.

        I was my understanding that IDE CD-ROM’s respond to SCSI commands? Or that is what I remember with linux and the scsi bridge thing along with using the old SCSI tools to write discs and whatnot.

      • Yes, CDROMs and CD/DVD burners can respond to SCSI commands in a direct way, because ATAPI isn’t a “proper” IDE implementation.

        In effect, ATAPI is practically SCSI over IDE. But windows ATAPI.sys can also emulate IDE (ATA) HDDs as SCSI devices by traslating SCSI commands to IDE (ATA) commands, but that’s a whole different thing that isn’t necessary for ATAPI devices, and that englobes CD/DVD readers and burners, ZIP IDE drives, LS-120 IDE drives and WORM/MO IDE units.

  4. This. Is. Brilliant.
    It took me a while to get AppleTalk up and running… I had originally attempted to get it talking to the real BasiliskII and then BasiliskII inside VirtualBox running Windows7 with the ethernet drivers working… but the routing didn’t seem to work properly.
    I was then going to write a note asking why I couldn’t have more than one emulated machine on a single physical host… until I tried to spin up two CockatriceIIIs. (Tough name to pluralise?) … all worked perfectly.

    This is all to support a Quadra 950 that I recently acquired. The CD drive and LAN card are in the mail, so I’m setting up an AppleTalk network for it to join.

    Now, the questions:
    1) Are we really limited to 256 colours?
    2) What extra work would be required to get WinPCap to work with WIFI adapters? Is this a Cockatrice thing? or WinPCap thing?
    3) Don’t install the Spanish text-to-speech… Simpletext throws an error using any voice afterwards. Meanwhile standard text-to-speech is ultra choppy.

    Am currently setting up a dev environment. VS2012 seems to have broken the project as it can no longer find m68k.h. Will work on that in my spare time.


    • Wow glad you got it to work! I keep meaning to push this project forward but … life + distractions. And I got the impression that 2-3 people were actually using it.

      1) Im basing this off of BasiliskII version 0.8.. So yes for now. I found later versions were so touchy and finicky I started with an older version which I found was surprisingly more stable, especially when I turned off anything that looked like a feature. I havent looked far enough into what is involved with doing different depth displays, or even changing depth.

      2) Wincap + wifi is an architectural thing. It’s basically a limitation of your wifi adapter. You would require one that will allow you to forge packets, AKA one of those hacker wifi adapters that can spoof other station addresses, which is basically exactly how I drive winpcap.
      3) The audio…Yeah basically this was my first ever attempt at getting audio out of SDL, and honestly I’m more amazed it makes any sound. There is some pitch matching issues that I tried to correct, and I know it’s wrong so I downsampled until it seemed to match although it then sounds like it’s under water. Sim City 2000 was still recognizable to me, so that was my ‘good enough’ test.

      Somewhere along the line VS support stopped working correctly. I believe it’s an issue with the CPU code, and how it handles packed structures. Somewhere, somehow in the neckbeard conferences of various compiler groups the MS & GNU people decided that their stuff shouldn’t interoperate, and should infact break each other for the sake of being ‘correct’ and damn the user. Older versions did build and run with VS, and felt much faster than GCC, but overall they were buggier, and later versions just stopped building properly all together. I had been meaning to try to keep it VC5 compatible but kind of gave up in the great drive to SDL+OS X/Linux. Try one of the older source versions and see if you can get that one to build. Although running for any extended amount of time is kind futile, but see if that builds.

      Idealy of course, is to mash in the pervious+hatari CPU core, and run with that but you know, life.

  5. So far this fork of Basilisk II takes the cake at being the most stable at networking. Basilisk II’s 32-bit only network driver enabled builds crash WAY too much.

    Cockatrice has been invaluable in testing/debugging the changes I have been making to netatalk’s PAP server. Whoever wrote it never bothered to test it with pre-LaserWriter 8.0 printer drivers or read the developer docs from Apple. People with 68k Macs running System 6 could never print using netatalk because of this! I don’t have an Ethernet equipped 68k Mac handy, so this works quite well for running client drivers and to run actual Mac based PAP servers (to see how others, including Apple, implemented a printer spooler) for packet capture and tracing.

    All I have to say is printing stuff is way easier on Windows. Just open up a port (network or parallel) and dump the raw print job data. None of this interactive two-way communication or queries about the printer’s features!

    • I’m glad you found it useful! I initially was interested in being able to mount Apple shares from a NT server as I was tired of messing with hfs disk utilities.

      I pushed the scsi backend to raw hard files, so I could partition and format images suitable for a/ux using shoebill.

      After gutting so many “features” I’m surprised how much more stable it is.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.