docs: function analyzePrimitiveArray( encoder, array ) {
  
  	var DEBUG_THIS = 0;
  
  	var TEST_NUMBER = 0,
  		  TEST_PLAIN = 1,
  		  TEST_OBJECT = 2,
  		  TEST_PRIMITIVE = 3,
  		  TEST_DOM = 4;
  
  	var BF_PRIM 	= 0x01,
  		  BF_REP	= 0x02,
  		  BF_NUM 	= 0x04,
  		  BF_PLAIN 	= 0x08,	
  		  BF_KNOWN  = 0x10;
  
  	var v, v_type, handled, id, ans, debug_str, enc,
  		
  		t_mode, t_numtype, t_constr, t_keys,
  
  		new_keys, old_keys, some_overlap, n_repeat=0,
  
  		is_numeric=true, num_type=-1,
  
  		b_prim = null, 	blocks_prim = [],
  		b_rep = null,	blocks_rep = [],
  		b_num = null,	blocks_num = [],
  		b_plain = null,	blocks_plain = [],
  		b_known = null,	blocks_known = [];
  
  	// Start scanning array elements
  	for (var i=0, l=array.length; i<l; ++i) {
  
  		// Reset test flags
  		t_numtype = NUMTYPE.NAN;
  
  		// Get test mode of the current value
  		v = array[i];
  		switch (typeof v) {
  
  			case 'number':
  				t_mode = TEST_NUMBER;
  				t_numtype = getNumType( v, v, ((v % 1) !== 0) );
  				if (DEBUG_THIS) debug_str = 'NUM';
  
  				// Keep track of biggest num type encountered
  				if (t_numtype < NUMTYPE.NUMERIC) {
  					if (num_type === -1) num_type=t_numtype;
  					else if (isNumericSubclass(num_type, v, v, t_numtype))
  						num_type=t_numtype;
  				}
  
  				break;
  
  			case 'string':
  			case 'boolean':
  			case 'undefined':
  				is_numeric = false;
  				t_mode = TEST_PRIMITIVE;
  				if (DEBUG_THIS) debug_str = 'PRM';
  				break;
  
  			case 'object':
  				is_numeric = false;
  				if (v === null) {
  					t_mode = TEST_PRIMITIVE;
  					if (DEBUG_THIS) debug_str = 'PRM';
  				} else if (v.constructor === ({}).constructor) {
  					t_mode = TEST_PLAIN;
  					if (DEBUG_THIS) debug_str = 'PLN';
  				} else if ((v instanceof Uint8Array) || (v instanceof Int8Array) ||
  					(v instanceof Uint16Array) || (v instanceof Int16Array) ||
  					(v instanceof Uint32Array) || (v instanceof Int32Array) ||
  					(v instanceof Float32Array) || (v instanceof Float64Array) ||
  					(v instanceof Array)) {
  					t_mode = TEST_PRIMITIVE;
  					if (DEBUG_THIS) debug_str = 'ARR';
  				} else if (v instanceof DOMElement) {
  					t_constr = v.constructor;
  					t_mode = TEST_DOM;
  					if (DEBUG_THIS) debug_str = 'DOM';
  				} else { /* Other objects */
  					t_constr = v.constructor;
  					t_mode = TEST_OBJECT;
  					if (DEBUG_THIS) debug_str = 'OBJ';
  				}
  				break;
  
  		}
  
  		//
  		// [BLOCK #1] - Test for same value
  		//
  
  		if (b_rep === null) {
  			b_rep = [i, 1, ARR_CHUNK.REPEAT, v, NUMTYPE.UNKNOWN];
  			if (DEBUG_THIS) debug_str += ', rep[new]';
  		} else {
  			if (v===b_rep[3]) {
  				b_rep[1]++;
  				if (DEBUG_THIS) debug_str += ', rep[++](ref)';
  			} else if (encoder.optimize.cfwa_object_byval
  				&& ((t_mode === TEST_OBJECT) || (t_mode === TEST_PLAIN))
  				&& deepEqual(b_rep[3], v, {strict:true})) {
  				b_rep[1]++;
  				if (DEBUG_THIS) debug_str += ', rep[++](val)';
  			} else if ((t_mode === TEST_DOM)
  				&& (v.src !== undefined)
  				&& (b_rep[3].src === v.src)) {
  				b_rep[1]++;
  				if (DEBUG_THIS) debug_str += ', rep[.src](val)';
  			} else {
  				if (b_rep[1]>1) {
  					n_repeat += b_rep[1];
  					blocks_rep.push(b_rep);
  				}
  				b_rep = [i, 1, ARR_CHUNK.REPEAT, v, NUMTYPE.UNKNOWN];
  				if (DEBUG_THIS) debug_str += ', rep[new]';
  			}
  		}
  
  		//
  		// [BLOCK #2] - Test for numbers
  		//
  		if (t_mode !== TEST_NUMBER) {
  			// Stopped being a number
  			if (b_num !== null) {
  				if (b_num[1]>1) {
  					blocks_num.push( b_num );
  				}
  				b_num = null;
  			} 
  		} else {
  
  			// Check for first encounter
  			if (b_num === null) {
  				if (DEBUG_THIS) debug_str += ', num[new]';
  				b_num = [i, 1, ARR_CHUNK.NUMERIC, t_numtype, v, v];
  
  			} else {
  				handled = false;
  
  				// Check for numeric subclass
  				if (!isFloatMixing(b_num[3], t_numtype)) {
  
  					// Allow type upscale of numtype
  					if (isNumericSubclass(b_num[3], b_num[4], b_num[5], t_numtype)) {
  						// console.log(">> " + ("Expanding numeric class from "+_NUMTYPE[b_num[3]]+" to "+_NUMTYPE[t_numtype]).cyan);
  						b_num[3] = t_numtype;
  						if (DEBUG_THIS) debug_str += ', num[upscale]';
  					}
  
  					// Accept only numeric subclasses
  					if (isNumericSubclass(t_numtype, v, v, b_num[3])) {
  						handled = true;
  						b_num[1]++;
  						if (DEBUG_THIS) debug_str += ', num[++]';
  
  						// Update bounds (for subclass testing)
  						if (v < b_num[4]) b_num[4] = v;
  						if (v > b_num[5]) b_num[5] = v;
  					}
  				}
  
  				// Stopped being an acceptable number (but still a number)
  				if (!handled) {
  					if (DEBUG_THIS) debug_str += ', num[new]';
  					if (b_num[1]>1) {
  						blocks_num.push( b_num );
  					}
  					b_num = [i, 1, ARR_CHUNK.NUMERIC, t_numtype, v, v];
  				}
  
  			}
  		}
  
  		//
  		// [BLOCK #3] - Test for plain objects
  		//
  
  		if (t_mode !== TEST_PLAIN) {
  			// Stopped being a plain object
  			if (b_plain !== null) {
  				if (b_plain[1]>1) {
  					blocks_plain.push( b_plain );
  				}
  				b_plain = null;
  			}
  		} else {
  
  			// Check for first encounter
  			if (b_plain===null) {
  				if (DEBUG_THIS) debug_str += ', blk[new]';
  				b_plain = [i, 1, ARR_CHUNK.BULK_PLAIN, Object.keys(v).sort()];
  
  			} else {
  
  				// Calculate key differences
  				t_keys = Object.keys( v ).sort();
  				new_keys = 0; some_overlap = false;
  				old_keys = b_plain[3].length;
  				for (var ja=0, jb=0, jl=b_plain[3].length; (ja<jl) && (jb<jl) ;) {
  					if (t_keys[ja] < b_plain[3][jb]) {
  						jb++;
  						new_keys++;
  						b_plain[3].push( t_keys[ja] )
  					} else if (t_keys[ja] > b_plain[3][jb]) {
  						ja++;
  					} else {
  						ja++;
  						jb++;
  						some_overlap = true;
  					}
  				}
  
  				// Allow up to 25% extension of the key set
  				if (some_overlap && (new_keys === 0) /*|| (new_keys < old_keys * 0.25)*/) {
  					b_plain[1]++;
  					if (DEBUG_THIS) debug_str += ', blk[++]';
  				} else {
  
  					// Stopped being a compatible plain object number (but still a plain object)
  					if (!handled) {
  						if (DEBUG_THIS) debug_str += ', blk[new]';
  						if (b_plain[1]>1) {
  							blocks_plain.push( b_plain );
  						}
  						b_plain = [i, 1, ARR_CHUNK.BULK_PLAIN, Object.keys(v).sort()];
  					}
  
  				}
  
  			}
  		}
  
  		//
  		// [BLOCK #4] - Test for possibly known objects
  		//
  
  		if (t_mode !== TEST_OBJECT) {
  			// Stopped being a known object
  			if (b_known !== null) {
  				if (b_known[1]>1) {
  					blocks_known.push( b_known );
  				}
  				b_known = null;
  			}
  		} else {
  
  			// Check for first encounter
  			if (b_known===null) {
  
  				// Lookup constructor
  				id = -1;
  				enc = encoder.profile.encode(v);
  				if (enc) {
  					id = enc[0];
  				}
  
  				// Check if this is a known object
  				if (id > -1) {
  					b_known = [i, 1, ARR_CHUNK.BULK_KNOWN, enc, v.constructor];
  					if (DEBUG_THIS) debug_str += ', obj[new]';
  				} else {
  					// Make this behave like a primitive
  					t_mode = TEST_PRIMITIVE;
  				}
  
  			} else {
  
  				// Check if we remain the same object
  				if (v.constructor === b_known[4]) {
  					b_known[1]++;
  					if (DEBUG_THIS) debug_str += ', obj[++]';
  				} else {
  
  					// Stopped being a compatible known object number (but still a known object)
  					blocks_known.push( b_known );
  
  					// Lookup constructor
  					id = -1;
  					enc = encoder.profile.encode(v);
  					if (enc) {
  						id = enc[0];
  					}
  
  					// Check if we are indeed a known object
  					if (id > -1) {
  						b_known = [i, 1, ARR_CHUNK.BULK_KNOWN, enc, v.constructor];
  						if (DEBUG_THIS) debug_str += ', obj[new]';
  					} else {
  						// Make this behave like a primitive
  						t_mode = TEST_PRIMITIVE;
  					}
  
  				}
  
  			}
  
  		}
  
  		//
  		// [BLOCK #5] - Test for primitives
  		//
  
  		if (t_mode !== TEST_PRIMITIVE) {
  			// Stopped being a known object
  			if (b_prim !== null) {
  				blocks_prim.push( b_prim );
  				b_prim = null;
  			}
  		} else {
  
  			// Collect block
  			if (b_prim === null) {
  				b_prim = [i, 1, ARR_CHUNK.PRIMITIVES, null];
  				if (DEBUG_THIS) debug_str += ', prm[new]';
  			} else {
  				b_prim[1]++;
  				if (DEBUG_THIS) debug_str += ', prm[++]';
  			}
  		}
  
  		if (DEBUG_THIS) console.log("### v=",v,":",debug_str);
  
  	}
  
  	// Finalize blocks
  	if (b_rep && (b_rep[1]>1)) {
  		n_repeat += b_rep[1];
  		blocks_rep.push(b_rep);
  	}
  	if (b_plain && (b_plain[1]>1)) blocks_plain.push(b_plain);
  	if (b_known && (b_known[1]>1)) blocks_known.push(b_known);
  	if (b_num) blocks_num.push(b_num);
  	if (b_prim) blocks_prim.push(b_prim);
  
  	// Calculate repeat ratio
  	var rep_ratio = n_repeat / array.length;
  	// console.log("==== Percent:", rep_ratio*100)
  
  	// Check if we have a complete block
  	if ((blocks_plain.length === 1) && (blocks_plain[0][1] === array.length)) {
  		// If repeat isn't going to help us, dont increase complexity
  		if ( rep_ratio < encoder.optimize.repeat_thresshold ) {
  			return blocks_plain;
  		}
  	} else if ((blocks_known.length === 1) && (blocks_known[0][1] === array.length)) {
  		// If repeat isn't going to help us, dont increase complexity
  		if ( rep_ratio < encoder.optimize.repeat_thresshold ) {
  			return blocks_known;
  		}
  	} else if ((blocks_num.length === 1) && (blocks_num[0][1] === array.length)) {
  		// If repeat isn't going to help us, dont increase complexity
  		if ( rep_ratio < encoder.optimize.repeat_thresshold ) {
  			return blocks_num;
  		}
  	} else if ((blocks_prim.length === 1) && (blocks_prim[0][1] === array.length)) {
  		// If repeat isn't going to help us, dont increase complexity
  		if ( rep_ratio < encoder.optimize.repeat_thresshold ) {
  			return blocks_prim;
  		}
  	}
  
  	// Perform bucket-fitting in order to use the smallest
  	// number of different combinations, ordered by priority
  	ans = arrangeBlocks( 0, array.length, [
  		blocks_rep, blocks_num, blocks_prim, blocks_plain, blocks_known
  	] );
  
  	// Unify numeric types to the same typed array
  	if (is_numeric) {
  		for (var i=0, l=ans.length; i<l; ++i) {
  			if (ans[i][2] === ARR_CHUNK.NUMERIC) {
  				ans[i][3] = num_type;
  			} else if (ans[i][2] === ARR_CHUNK.REPEAT) {
  				ans[i][4] = num_type;
  			} else if (ans[i][2] == ARR_CHUNK.PRIMITIVES) {
  				ans[i][2] = ARR_CHUNK.NUMERIC;
  				ans[i][3] = num_type;
  			} else {
  				throw new Errors.AssertError("Trying to unify non-numeric type="+_ARR_CHUNK[ans[i][2]]);
  			}
  		}
  	}
  
  	// Merge consecutive bocks of exact type
  	for (var i=1, l=ans.length; i<l; ++i) {
  		if ( (ans[i-1][2] === ans[i][2]) &&  // Same Type
  			 (ans[i-1][3] === ans[i][3]) ) { // Same Sub-Type
  			
  			// Left engulfs right
  			ans[i-1][1] += ans[i][1];
  			ans.splice(i,1);
  			i--; l--;
  
  		}
  	}
  
  	if (DEBUG_THIS) {
  		// console.log("-----------------------");
  		// console.log("IN: ", array);
  		console.log("-----------------------");
  		console.log("B[REP]  :", blocks_rep);
  		console.log("B[NUM]  :", blocks_num);
  		console.log("B[PRIM] :", blocks_prim);
  		console.log("B[PLAIN]:", blocks_plain);
  		console.log("B[KNOWN]:", blocks_known);
  		console.log("-----------------------");
  		console.log("PICK:", ans);
  		console.log("-----------------------");
  	}
  
  	// Expose is_numeric indicator
  	ans.is_numeric = is_numeric;
  
  	// Return
  	return ans;
  
  }