Friday, May 29, 2015

Chromebookery II - Chromebook harder

Continuing from history leading to Chromebooks.

Chromebooks have much the same hardware as any other laptop - most are based on standard x86 CPUs which are also used in other Windows and even Android based systems. Some run ARM - initially this was cheaper, but Intel responded to the competition, and Atom derived CPUs pushed lower pricepoints till sub-$200 devices appeared with x86 hardware.

So now we have cheap as hell laptop like devices with ChromeOSChromeOS has made huge strides and now there's some real offline software available - HTML5/CSS/Javascript based apps - that run offline, but it's still limited. There's no really capable photo app (yet?). Offline storage is limited. There's no Skype. Skype sounds trivial, but it's a big deal since it provides popular free cross platform video chats. Google's hangouts work well too, but the microphone seems to pick up a lot of feedback by comparison, and in todays world no company seems to want to be compatible with another's messaging app.


So - what can I actually do with a Chromebook offline? Well it's perfectly fine for viewing pictures. It's good for several video formats. There's more than a few games available. There's calculators, note taking, word processors, spreadsheet applications, slide show presentation apps, code editors, educational applications, diagram apps, finance...


Hmm, seems like an awful lot is actually already present. Most people are going to be able to get by quite well. 

Let's take a look at a Chromebook:


Here's a new model - the Acer CB3-111. 11.6" 1366x768 matte screen, 16GB EMMC storage and 2GB RAM with a Celeron N2840 (dual core, up to 2.58GHz, Silvermont). This laptop weighs ~2.75lbs and has excellent battery life - it depends on your use but over 6 hours playing videos is pretty good. I've gotten over 8 hours with loads of battery life to spare working on python/shell scripts/browsing taking a few breaks leaving it in sleep mode. This set me back $150 new and has been pleasant enough to work with to become my main computing device on the go.


Simple is beautiful.
Small unobtrusive branding areas and little LED lights are all that mar the surface.


One USB port on either side (one 3.0, one 2.0).
I have my mini PQI drive in this one (3.0).
It's adding another 64GB.


The rear has a charging port and HDMI port.


Headset port on this side, along with the other USB (2.0) port and security slot.


Next to a pencil and penny to illustrate the thickness.


Here's the chicklet keyboard. The Keyboard is actually quite nice, with good feel.
The mic and camera (1.3MP) are actualy quite decent for video calls.


The base of the laptop isn't as unsightly as most regular laptops.
12 screws hold in the base which we'll be popping out later :D

Hardware wise this feels quite solid. Matte plastic throughout add to it's aesthetic. WiFi card is dual channel AC with bluetooth. It's pleasant to type on. Battery lasts a long time. Had adequate power for most applications. There's little flex, and the low weight makes it comfortable to keep on your lap for a long time.


There's NO fan. This runs dead silent. It does not get hot.


So far so good (really good) - but for many people, specific software will be missed (such as skype). Software with more advanced features will be missed (Open Office/Microsoft Office/Gimp/Photoshop/Eclipse  etc), many popular games that exist on several platforms will be missed (browse gog.com or HumbleBundle.com some time...).
ChromeOS is also lacking VPN connectivity options and can't access network shares.

 


So what can be done about that?



2 options - Replace the OS, or add to the OS.

Replacing the OS involves putting the machine into a radically different state - wiping out the harddrive contents, getting drivers that will work with the system etc. It's good, if you know your laptop's components are supported. This is also more difficult to undo.

I'm being vague saying "Add to the OS". To expand, ChromeOS is a custom Linux distribution. The GUI may be Google's browser but the core of the OS is simply 
Linux. That makes very easy to manipulate once you have access to the innards. What we'll do is make a chroot in this host Linux.

Putting the laptop in developer mode will give the necessary access. Once that's done, running the Crouton script will let us download and install our choice of Linux kernel, along with GUI (gnome, KDE, XFCE etc) and we'll run this other Linux setup in parallel with ChromeOS. The other Linux install will run in a chroot - i.e. the environment of that other Linux will see the installed location as the file-system root. Once it's running, it will also be able to access all devices that ChromeOS already connects to - i.e. the video drivers, audio drivers, touchpad, USB etcetera that ChromeOS has access to will just work.


Step 1: Put the laptop in developer mode:

  1. Press and hold escape and refresh. While holding those, press the power button and your laptop will boot into recovery mode.
  2. When the recovery mode screen comes up, press ctrl+D for the developer mode prompt.
  3. Press Enter to continue and give it a little while as the laptop will wipe all local data, and refresh ChromeOS.
  4. On boot, the laptop will show a warning that developer mode is on. Skip it by pressing ctrl+D or wait 30 seconds. We'll make a change to skip that later.
Step 2: Download and run Crouton
  1. Just click on installer and download crouton to your download folder on the Chromebook.
  2. Press ctrl+alt+T in the chrome browser to open a crosh prompt.
  3. Enter "shell" to open bash.
  4. Navigate to the downloaded crouton script (cd ~/Downloads/)
  5. Run crouton (sudo sh ./crouton). If it's not executable, make it so by running chmod +x crouton. Note the options.
    Run sudo sh ./crouton -t help to list supported GUIs. Run sudo sh ./crouton -r help to list supported kernels.
  6. Assuming you're going with gnome on trusty, you can also specify where to install the new Linux install. I installed mines on the USB drive that you can see in the previous pictures. The drive was formatted with ext4 and named OS_DRIVE. I made the "trustychroot" folder to keep the drive organized.
    sudo sh ./crouton -t gnome-desktop -r trusty -p /media/removable/OS_DRIVE/trustychroot/
    Of course, if you're using the default location, it's just
    sudo sh ./crouton -t gnome-desktop -r trusty
  7. Now give it some time (couple hours). This will install Linux on that USB drive if you specified location as above. If you don't specify the location, the default is on the laptop itself (much faster). With only 16GB available on this model, space can be an issue.
  8. Once done, you can open your Linux install by running
    sudo startgnome -c /media/removable/OS_DRIVE/trustychroot/chroots

    Note - if the install didn't specify the location, just run sudo startgnome.
  9. That's it. You're running Ubuntu on your Chromebook. You can copy the files in the chroot folder off tar them up to backup your intall, move them etc. You can have multiple Linux installs as well.
    To switch to
    ChromeOS from Linux - press ctrl+alt+back.
    To switch to Linux from
    ChromeOS -press ctrl+alt+forward. On x86 systems, you also need to press alt+forward again.


Next - get rid of the damn developer mode warning. Undoing all this work just takes an easy keypress in the boot sequence, so let's get rid of that option.

Start by opening up the Chromebook.


The insides look pretty sparse. The only device that can be removed is the wireless module. To the upper right of that module is a screw with what looks like solder contact points all around.



Unscrew it, and put back on the bottom (don't screw it on).

Boot up the Chromebook and open a shell prompt.
run the following:
sudo /usr/share/vboot/bin/set_gbb_flags.sh 0x1  (shorten the bios delay)
sudo /usr/share/vboot/bin/set_gbb_flags.sh 0x8  (force developer mode on)

Or - just use 0x9 for both at once.

That will make it much safer against booting chromebook and accidentally wiping it.

Put back the write protect screw, and screw on the bottom - you're done. Booting now just takes a couple seconds at the BIOS screen.


The Linux/Ubuntu experience is quite good. I've often had problems with drivers on other laptops where Ubuntu was the host OS, but absolutely no problems here. Ubuntu is running with the existing OS sharing the compiled modules and drivers of the ChromeOS host.

The most impressive aspect of this as a linux laptop is the backup and restore functionality.

Backup:
If you did not specify a specific location to install, then backup is just:
sudo edit-chroot -b trusty
Where "trusty" is the chroot default name.
I installed on a USB drive, so the below command specifies the chroot location.
sudo edit-chroot -c /media/removable/OS_DRIVE/trustychroot/chroots -b trusty

Restore:
A basic restore is simply 
sudo edit-chroot -r chrootname
If you haven't specified a location but your laptop is new, or powerwashed, crouton can install directly from the zip file generated:
sudo sh ~/Downloads/crouton -f mybackup.tar.gz
If you did like me and installed to a specific location:
sudo sh ~/Downloads/crouton -p /media/removable/OS_DRIVE/trustychroot/ -f mybackup.tar.gz 

This can be done in the background while using ChromeOS to get work done. It's by far my favorite aspect of using a chromebook to host Linux.

TIP:
Consider putting shell scripts in /usr/local/bin/ to speed up entering Linux, backup/restore scripts etc.
Bottom line:



The Acer CB3-111 Chromebook is light, small, feels well put together and has decent battery life. ChromeOS starts in seconds from off, and standby is done by simply closing the lid. The OS can repair itself of modification easily, has functions for making recovery usb drive, and as of today has enough offline applications for most people. It's unlikely to have virus problems as well. That makes it really good for a casual user.


With Crouton The CB3 Chromebook becomes a rather nice Linux laptop - albeit one with mediocre storage options. The best alternative to using the internal EMMC storage (which can't be upgraded) is using a tiny USB drive (mine is a 64GB PQI [U603V]). Though these drives are USB 3.0 with fast 120MBps+ read speeds but the write speeds are quite slow - perhaps 10-12MBps sustained, so some pauses in multitasking can occur. No ultra tiny USB 3.0 drive currently does any better yet.

Getting into Linux is fast - just open chrome, press ctrl+alt+T for a shell tab, and run your one line command to start - put it in a shell script to automate your life :)


The price and features are an incredible combination, even without Crouton. I'd love a 32GB version where I can use the internal space instead of a slower USB drive, but maybe in the future.

Verdict: A nice laptop for $150. A little elbow grease really makes it shine.

Wednesday, May 27, 2015

Chromebookery and history,

A little history on cheap computing...

At some point, manufacturers decided to start making really cheap personal computing devices- not a capability they always possessed (or maybe did, but to a poor extent). About the mid to late 90's computing power had really started to become noticeably cheaper for it's time. Computing power was always getting cheaper but now we had simple GUIs for the general public and sub-$1000 PCs were slowly appearing. Major manufacturers even started selling "internet PCs" (aka internet appliance) - simple x86 computers with weak-middle class CPUs, small hard-drives, and minimal RAM in a low profile package.

Notoriously under-powered, these (internet)PCs were cheap for its time (probably driven by cheaper net appliances - TV, game consoles etc that were web capable) and sold fairly well managing to push the internet a little faster towards mainstream. A good thing too, because if movies and television had their way, people would continue to believe that being connected to a network was like looking at swirling vortexes of equations (Hackers) or caught up in a virtual reality world (Nowhere Man). As a secondary side effect, it pushed the general cost of computing down.


Source: http://www.bls.gov/opub/ted/2000/Oct/wk1/art01.htm

Back then Internet explorer 4 was the de facto browsing experience coming packaged on most machines with Windows 98. Browsing standards were far from uniform then, so even if Netscape was more potent, its presence fell with Microsoft packaging Internet Explorer with it's operating system.

Webpages were a static display at this time. HTML was coming from it's infancy, having basic functionality, and many major websites had strict support for Internet Explorer being the most common browser at the time, failing to work on alternatives when more complex designs and functions were needed.

As the years passed, Webpages became more dynamic - with the use of Java, Flash, iFrames, ActiveX(bleh), javascript, Ajax, HTML5 etc. The structure of the web moved forward into the capable platform it is today. For the past few years the web has been capable of a full application like experience. The dynamic nature of webpages today reaching full application like experiences is driven by a mix of client side and server side processing, with server side storage (aka "the cloud").

For the increased capability, more power at lower prices became necessary. Meeting the requirements of "enough processing power", low power consumption, and cheap manufacturing, Intel created the "Atom" processor. The Atom made it's way into the first netbooks - the eeePC - from ASUS in 2007 (a low powered Celeron went in the first model). Netbooks weren't the first push into this level (relative at the time) of portable computing. The Toshiba Libretto was a cute little laptop with fair power (though expensive) and the OLPC XO-1 project spawned a strange looking laptop with a specific goal of being cheap (though not very available). Several ARM based alternatives also existed, though most felt slow and plodding and just weren't popular. The netbook however was a truly successful project gaining momentum over the years as the size, price, and power were a hit. With popularity, the price kept falling, until even the OLPC was not as good a deal. Sales routinely dropped the price under $200, and the popularity even ate into sales of full laptops, driving standard laptop prices down.

The netbook's processor was good enough for most webpages and basic applications. For web use, Flash generally slowed it down (and it's still a resource hog at times today). When cheap tablets became mainstream, the netbook adoption slowed quite a bit, but the ideal of a very low cost laptop computer with enough power stayed. Enter Google Chromebooks in 2011.

The initial Chromebook was much like a netbook in hardware (small and cheap with "enough" power). Netbooks had evolved over time from the initial 7" screen to a near standard 11.6". You could say the research into popular form-factors had been done already, though Chromebooks are pushing larger formfactors today. Acer and Samsung brought their Chromebooks to market in mid 2011, and much of the public looked on with curiosity, early adopters with interest, and many a tech-geek turned up their nose in disgust.

The operating system(ChromeOS) was based on Linux, but the front end user experience was just a browser. Therein lay the buzz surrounding this OS. If the operating system was only good when online, then what was the point if you were offline? Not everyone would have access to internet all the time. While it held similar internals to netbooks for it's time, netbooks seemed capable, simply because of the OS. Most netbooks ran Windows and some ran Linux. Either one gave the user access to regular installed desktop applications. Plus you could always just run a browser for online web-app services. Netbooks did run a heavier OS, so on slower harddrive bearing netbooks, they did tend to feel sluggish.

Towards the end of 2013, Google released an update for ChromeOS where a webapp could run offline, store it's data locally and in general act like an installed application. This was big for the OS, but still restrictive. The apps that can be installed and used offline are web based HTML5 applications. It does open up the usage quite a bit, but not to those dependent on existing software for Windows/Linux/Mac. The current batch of offline apps is still rather limited, and not as efficient as proper compiled applications - for example, doing photo editing. Not much high end variety exists either so we're currently stuck with Pixlr now (May 2015) vs Photoshop, Gimp, RawTherapee, Aperture etc.

As most Linux based systems go Chromebooks were quite interesting to those that liked the hardware, and wanted to open up the OS to being more useful. In ~2012, a project called Crouton started giving people a fairly easy way to making a Chromebook work more like a regular Linux laptop.

Thanks to Crouton, adventurous souls can enable developer mode and have ChromeOS act as a fancy loader to a secondary guest OS. Crouton is a script that manages downloading, installing, entering and managing chroots. A chroot is a change in the environment setup such that all running apps see the root folder specified in the new chroot setup and in general doesn't see the actual root folder and system folders. What this means is you can boot your Chromebook into ChromeOS and enter a chroot which can be a standard Linux install. 

Chromebooks can be found new for $150 these days - an astounding price for a decent laptop. While the default OS is still limiting, the use of Crouton can greatly extend the use, by turning the Chromebook into a decent proper Linux laptop (without driver problems since ChromeOloaded it for you!). In 1998, the Toshiba Libretto cost $2500. Hardly in the same affordability class, but it was a notable attempt at small and light. The eeePC started at $400. Chromebooks started at a similar price, but the price as fallen faster than netbooks, while maintaining a more comfortable level of processing power.

Sunday, April 12, 2015

Mandelbrot Set Rendering

Benoit Mandelbrot was a Polish-born mathematician. His most well known work is in the field of fractals. He came up with a function describing a set of complex numbers called the Mandelbrot Set.
The Mandlebrot set describes a set of numbers "c" such that the sequence (c1, c2 .... cx) where cn+1 = (cn*cn)+cn does not approach infinity.
So you're looking at c, c²+c, (c²+c)²+c, ((c²+c)²+c)²+c...

A complex number has two parts. It's a sum of real an imaginary components. Let's say we're looking at A + Bi.
A is the real component.
Bi is the imaginary component.
'i' is a symbol representing the √-1 (square root of -1)
i.e., (Bi)² would be -B².

Mandelbrot's equation for describing the model is z'=z²+c.
Let z be our A + Bi from above.
The next element of the sequence is 
If z=(A+Bi)² then z=A²-B²+2*A*Bi


If plotting, we can us X, Y in place of A, and B.
so, z=X²-Y²+2*X*Y(i)
We have real and imaginary components here.
So Xnew=X²-Y², and Ynew=2*X*Y
the "c" is the starting point for Mandelbrot's equation.
Z=Z²+c, so we need to add X0 and Y0 to the above:

Xnew=X²-Y²+X0
Ynew=2*X*Y+Y0
And from here, we keep iterating on this till we hit set limits to number of iterations, or if X/Y are sufficiently large.

So, for a point X, Y,
Repeat the following until x0²+y0²>4 or until set max iterations

Until (max iterations, or x0²+y0²>4)
  x0=0 and y0=0
  x1=x0*x0-y0*y0+X
  y1=2*x0*y0+Y
  x0=x1
  y0=y1
Color point X,Y based on iterations.




Point X,Y is then associated with the number of iterations to break out of that loop.

Using this we can construct a basic Mandelbrot generator. I did this using Javascript, since it's easy to use any browser to display a canvas element. This works in Firefox and Chrome (has worked for a while) and I've tested it in IE11 and it works there too.




<!DOCTYPE HTML>
<html>
<script language="javascript">
  function rgbToHex(r, g, b) { //thanks stackoverflow
    return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
  }
  function putpixel(x,y,r,g,b,ctx){
    ctx.fillStyle = rgbToHex(r,g,b);
    ctx.fillRect(x,y,1,1);
  }
  function paint(cnvname){
    mcanvas = document.getElementById(cnvname);
    ctx = mcanvas.getContext('2d');
    ctx.clearRect(0, 0, 799, 599);
    for (x = 0; x < 799; x++) {
      for (y = 0; y < 599; y++) {
        tx=(x-400)/(200); // tx is "translated x" for graph centering"
        ty=(300-y)/(200); // ty is "translated y" for graph centering"
        xtmp=0;
        ytmp=0;
        xtmp2=0;
        iter=0
        maxiter=1000;
        for (; (iter<maxiter) && (xtmp*xtmp+ytmp*ytmp < 4);) {
          xtmp2=xtmp*xtmp-ytmp*ytmp+tx;
          ytmp=2*xtmp*ytmp+ty;
          xtmp=xtmp2;
          iter++;
        }
        contrast=0.15
        color=Math.floor( (Math.pow(iter,contrast)*255)/Math.pow(maxiter,contrast));
        putpixel(x,y,0,255-color,255-color,ctx);
      }
    }
  }
</script>
<body onload='paint("mcanvas")'>
  <div>
    <canvas id="mcanvas" width="800" height="600"></canvas>
  </div>
</body>
</html>


This is a simple bit of javascript that iterates over the pixels of the canvas created in the body. It applies the function described earlier to determine the max number of iterations to the set.



Pretty right? Of course there's much more to mandelbrot than just the bulb.
We can zoom in on a portion of this by applying a zoom and x/y offset to the above code.

We can add a zoom and offset feature to explore the set.


  for (x = 0; x < 799; x++) {
    for (y = 0; y < 599; y++) {
      zoom=20; xoff=0.6; yoff=0.6;
      tx=-xoff+(x-400)/(zoom*200); // tx is "translated x" for graph centering"
      ty=yoff+(300-y)/(zoom*200); // ty is "translated y" for graph centering"

The above change will produce the following:

This is zoomed in 20x onto the small bulb in the top left portion of the largest bulb. Note the pattern replicates, and there are several tiny bulbs that look a lot like the main one (with slight variations).

Now the fun part - we can color based on x, y or iterations. Apply a sinusoidal function to iterations for red, blue and green, and you can have a never ending palette of color.

e.g.
From the contrast and color line:

//contrast=0.25
//color=Math.floor( (Math.pow(iter,contrast)*255)/Math.pow(maxiter,contrast));
cycle=(maxiter)/(3.14159265359*100);
cr=Math.floor(128+127*Math.sin(0.00+iter/(cycle*1.5000)));
cg=Math.floor(128+127*Math.sin(1.57+iter/(cycle*1.6000)));
cb=Math.floor(128+127*Math.sin(3.14+iter/(cycle*1.5666)));
putpixel(x,y,cr,cg,cb,ctx);

So, what are we saying? A cycle is 2*pi. We're dividing the iterations by 100*pi, so we're looking at at 50 cycles. Red, green and blue values are sinusoidal cycles with different start points - red starts at 128+127*sin(0) (so 128, and increasing). Green is 128+127*sin(1.57) (so 255, 1.57 being half pi, sin(pi/2) is 1) - i.e. max green and heading down to 0. Blue is starting at 128+sin(pi), which means middle intensity and getting darker.
Each sinusoidal cycle has it's own multiplier so each cycle has it's own rate, giving many more colors ans each cycle creates a new palette.

Here's the result:


We're looking at integers since we're only counting max iterations. We can smoothen this by looking at how far past our boundary condition each iteration went.

My script was based on methods described in wikipedia.


log2=Math.log(2)
if (iter<maxiter){ //smoother transitions
  zn=Math.sqrt(xtmp*xtmp+ytmp*ytmp);
  zl=Math.log(Math.log(zn)/log2)/log2;
  iter+=1-zl;
} 






Now consider the interior of the bulb. It's what happens when the iterations have been maxed. We can color the interior by using the same palette. I haven't quite figured out the how to map distance, but we can use the existing xtmp and ytmp variables. Since iterating more doesn't get us greater than the boundary condition, we can assume xtmp and ytmp are small. 

What I tried was several permutations of setting iter to 1/xtmp and 1/ytmp. I settled on using iter=Math.log( (1/(xtmp*xtmp+ytmp*ytmp)) )/(log2);
The idea is that if my values aren't going to break out of the boundary, then they're converging. So I'm using the inverse of the values to dictate what they will be against the existing palette. Not all sub-bulbs show this though.


Here's the overall code for this basic mandelbrot renderer...



<!DOCTYPE HTML>
<html>
<script language="javascript">
  function rgbToHex(r, g, b) { //thanks stackoverflow
    return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
  }
  function putpixel(x,y,r,g,b,ctx){
    ctx.fillStyle = rgbToHex(r,g,b);
    ctx.fillRect(x,y,1,1);
  }
  function paint(cnvname){
    mcanvas = document.getElementById(cnvname);
    ctx = mcanvas.getContext('2d');
    ctx.clearRect(0, 0, 799, 599);
    log2=Math.log(2)
    for (x = 0; x < 799; x++) {
      for (y = 0; y < 599; y++) {
        zoom=20; xoff=0.6; yoff=0.6;
        tx=-xoff+(x-400)/(zoom*200); // tx is "translated x" for graph centering"
        ty=yoff+(300-y)/(zoom*200); // ty is "translated y" for graph centering"
        xtmp=0;
        ytmp=0;
        xtmp2=0;
        iter=0
        maxiter=1000; // increase with larger zoom values
        totes=0;
        for (; (iter<maxiter) && (xtmp*xtmp+ytmp*ytmp < 4);) {
          xtmp2=xtmp*xtmp-ytmp*ytmp+tx;
          ytmp=2*xtmp*ytmp+ty;
          xtmp=xtmp2;
          iter++;
        }
        if (iter<maxiter){ //smoother transitions
          zn=Math.sqrt(xtmp*xtmp+ytmp*ytmp);
          zl=Math.log(Math.log(zn)/log2)/log2;
          iter+=1-zl;
        } else { // for internal color of Mandelbulb
          iter=Math.log( (1/(xtmp*xtmp+ytmp*ytmp)) )/(log2);
        }
        cycle=(maxiter)/(3.14159265359*100); //50 cycles from 0-maxiter
        cr=Math.floor(128+127*Math.sin(0.00+iter/(cycle*1.5000)));
        cg=Math.floor(128+127*Math.sin(1.57+iter/(cycle*1.6000)));
        cb=Math.floor(128+127*Math.sin(3.14+iter/(cycle*1.5666)));
        putpixel(x,y,cr,cg,cb,ctx);
      }
    }
  }
</script>
<body onload='paint("mcanvas")'>
  <div>
    <canvas id="mcanvas" width="800" height="600"></canvas>
  </div>
</body>
</html>


Manipulation of the color palette constants, zoom, offsets, and even the equation can produce some beautiul results.

For example,
Set the initial xtmp to tx and ytmp to ty.

change:
xtmp2=xtmp*xtmp-ytmp*ytmp+tx;
ytmp=2*xtmp*ytmp+ty;


to:
xtmp2=xtmp*xtmp-ytmp*ytmp-0.32;
ytmp=2*xtmp*ytmp+0.6575;


Now you're making a Julia plot.
This is another fractal you can zoom in continuously.

Let's look at zooming in on a portion of the Mandelbrot set.
zoom=1.00; xoff=0; yoff=0;


zoom=5; xoff=0.7348; yoff=0.1798;

zoom=25; xoff=0.8; yoff=0.2;



zoom=125; xoff=0.79; yoff=0.158;


zoom=625; xoff=0.79; yoff=0.162;

zoom=3125; xoff=0.7893; yoff=0.163;


At this point we need to increase the maxiter constant. I raised this to 10000.
zoom=9125; xoff=0.78937; yoff=0.16307;


 zoom=15625; xoff=0.78940; yoff=0.163055;


zoom=78225; xoff=0.78940; yoff=0.163055;
Note the zoom - we're at almost 80000x and as you can see there's a lot more structures here!