(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
(function (global){
/**
* JavaScript BlinkUp
*
* @version <packageVersion>
* @copyright Electric Imp Inc. 2016
* @website https://electricimp.com
* @license Closed
*/
module.exports = require('./lib/blinkup/blinkupSDK');
/**
* Global accessor for blinkupSDK module if needed
* @global
*/
global.BU = module.exports;
/**
* Global accessor for a NetworkConfig class if not using modules
* @deprecated Please use BU.NetworkConfig if not using modules
* @global
*/
global.BUNetworkConfig = require('./lib/blinkup/NetworkConfig');
/**
* Global accessor for a StaticAddressing class if not using modules
* @deprecated Please use BU.StaticAddressing if not using modules
* @global
*/
global.BUStaticAddressing = require('./lib/blinkup/StaticAddressing');
/**
* Global accessor for a NetworkProxy class if not using modules
* @deprecated Please use BU.NetworkProxy if not using modules
* @global
*/
global.BUNetworkProxy = require('./lib/blinkup/NetworkProxy');
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./lib/blinkup/NetworkConfig":10,"./lib/blinkup/NetworkProxy":11,"./lib/blinkup/StaticAddressing":12,"./lib/blinkup/blinkupSDK":13}],2:[function(require,module,exports){
var Base64 = {_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}; // eslint-disable-line
module.exports = Base64;
},{}],3:[function(require,module,exports){
'use strict';
module.exports = exports = {};
var ByteOperations = {
utf8: function (s) {
return unescape(encodeURIComponent(s));
},
hexStringToLEBytes: function (hexstring) {
// Convert a hex string to a little-endian byte string
var bytes = [];
while (hexstring.length) {
bytes = String.fromCharCode(parseInt(hexstring.slice(0, 2), 16)) + bytes;
hexstring = hexstring.slice(2);
}
return bytes;
},
dottedQuadToLEBytes: function (quad) {
// Convert a dotted quad string to a little-endian byte string
var buf = '';
quad.split('.').forEach(function (part) {
// Make sure it's zero-padded to two digits
buf += ('0' + parseInt(part, 10).toString(16)).slice(-2);
});
return this.hexStringToLEBytes(buf);
},
dottedQuadToBytes: function (quad) {
// Convert a dotted quad string to a big-endian byte string
var bytes = [];
quad.split('.').forEach(function (part) {
bytes += String.fromCharCode(parseInt(part, 10));
});
return bytes;
}
};
exports.utf8 = ByteOperations.utf8;
exports.hexStringToLEBytes = ByteOperations.hexStringToLEBytes;
exports.dottedQuadToLEBytes = ByteOperations.dottedQuadToLEBytes;
exports.dottedQuadToBytes = ByteOperations.dottedQuadToBytes;
},{}],4:[function(require,module,exports){
'use strict';
/**
* Represents a ConfigId returned by the Electric Imp API corresponding to a BlinkUp attempt.
* This object is created by the module:blinkupSDK.getConfigId method.
* You should never have to create it yourself.
* @class
* @memberof module:blinkupSDK~
* @param {object} params Initialization parameters
* @example
* var blinkup = require('blinkup/blinkupSDK');
* blinkup.getConfigId('myElectricImpAPIKey', null, 'production', function (err, configId) {
* if (err) {
* // Handle error
* } else {
* // The configId has been retrieved.
* // Generally it should be passed to the startNetworkFlash function
* var theConfigId = configId;
* }
* });
*/
function ConfigId (params) {
/**
* The ID of the token
* @member {string} token
* @memberof ConfigId
*/
this.token = params.token;
/**
* @memberof module:blinkkupSDK~ConfigId
* The plan ID if available
*/
this.planId = params.planId;
/**
* @instance
* Your API key from ElectricImp
*
*/
this.apiKey = params.apiKey;
/**
* Production environment for API calls
* Ensure the correlating apiKey is used
* Values: 'production'
*/
this.environment = params.environment || 'production';
};
module.exports = ConfigId;
},{}],5:[function(require,module,exports){
'use strict';
/**
* Represents the results of a device poll event.
* @class
* @memberof module:blinkupSDK~
* @param {object} params Initialization parameters
* This object is created by the function module:blinkupSDK.pollForDeviceInfo as part of the polling process.
* A device will only be returned if the flash was successful.
* You should never have to create it yourself.
* @example
* var blinkup = require('blinkup/blinkupSDK');
* blinkup.pollForDeviceInfo (configId, function(err, deviceInfo) {
* if (err) {
* // Handle error
* // (device rejected or server connection timed out)
* } else if (deviceInfo) {
* // Do something with deviceInfo data
* }
* });
*/
function DeviceInfo (params) {
/** The URL of the agent for the device that connected */
this.agentURL = params.agentURL;
/** The deviceId of the device that connected */
this.deviceId = params.deviceId;
/** The planId of the device that connected */
this.planId = params.planId;
/** The date when the device connected to the server */
this.verificationDate = params.verificationDate;
};
module.exports = DeviceInfo;
},{}],6:[function(require,module,exports){
'use strict';
var exports = {};
exports.isOnMobile = function (userAgent) {
userAgent = userAgent || navigator.userAgent;
return (/tablet|pad|mobile|phone|symbian|android|ipod|ios|blackberry|webos/i.test(userAgent));
};
exports.isOnIOS = function (userAgent) {
userAgent = userAgent || navigator.userAgent;
return (/(iPhone|iPod|iPod touch|iPad)/i.test(userAgent) && !exports.isOnIE(userAgent));
};
exports.iOSMajorVersion = function (global, userAgent) {
if (exports.isOnIOS(userAgent)) {
global = global || window;
/* eslint-disable */
if (!!global.indexedDB) { return 8; }
if (!!global.SpeechSynthesisUtterance) { return 7; }
if (!!global.webkitAudioContext) { return 6; }
if (!!global.matchMedia) { return 5; }
if (!!global.history && 'pushState' in global.history) { return 4; }
/* eslint-enable */
return 3;
}
return null;
};
exports.isOnChrome = function (userAgent) {
userAgent = userAgent || navigator.userAgent;
return (/chrome|crios/i.test(userAgent) && !exports.isOnIE(userAgent));
};
exports.isOnIE = function (userAgent) {
userAgent = userAgent || navigator.userAgent;
return (/msie|trident|edge/i.test(userAgent));
};
exports.isOnFirefox = function (userAgent) {
userAgent = userAgent || navigator.userAgent;
return (/firefox|seamonkey/i.test(userAgent));
};
module.exports = exports;
},{}],7:[function(require,module,exports){
'use strict';
function FlashData (params) {
params = params || {};
this.byteArray = params.byteArray || [];
};
var translate = function (bytes) {
// handle empty case
if (bytes.length === 0) {
return '';
}
var string = '';
var holder = 0x00;
var mask = 0x01;
var shiftSize = -1;
for (var i = 0, len = bytes.length; i < len; i++) {
// Move old value in case it is needed (for 3 bits)
// OR in new byte
shiftSize += 8; // Add on 8 more bytes
holder = (holder << 8) | bytes[i];
// Process the lower 8 bits that we can
while (shiftSize >= 0) {
// Find the value
var value = (holder >>> shiftSize) & mask;
// Add 1 as 0 is clock
value += 1;
// Prepend clock and now we are in bitsPerFlash^2 + 1 radix system
string += '0' + value.toString(17);
// Shift less next time
shiftSize -= 1;
}
}
return string;
};
FlashData.prototype.preambleByteArray = function () {
// sync header; this is just the 01 pattern (ie trilevel 0x00 gives
// the pattern "0101010101010101". This should go on for ~1s to ensure
// that the imp is listening.
var preamble = [0x00, 0x00, 0x00];
// Magic number (2a) header which signifies end of sync and start of packet
preamble.push(0x2a);
return preamble;
};
FlashData.prototype.asciiEncodePreamble = function () {
var dataString = translate(this.preambleByteArray());
return dataString;
};
FlashData.prototype.asciiEncode = function () {
var dataString = translate(this.byteArray);
return dataString;
};
module.exports = FlashData;
},{}],8:[function(require,module,exports){
'use strict';
var Bytes = require('./ByteOperations');
var FlashData = require('./FlashData');
var FlashPacket = {
_mCRC: 0,
flashData: null,
PACKET_ID: {
WIFI_SSID: 1,
ENROLMENT: 5,
DISCONNECT: 7,
CLEAR_TEXT_PASSWORD: 6,
NETWORK_STATIC_CONFIG: 11,
HTTP_PROXY_SETTINGS: 13
},
init: function (configId, networkConfig, options) {
// Constants
var HEADER_LEN = 2;
var TOKEN_PLAN_LEN = 16;
var STATIC_IP_1_DNS_LEN = 16;
var STATIC_IP_2_DNS_LEN = 20;
// Build a packet
this._mCRC = 0;
this.flashData = new FlashData(options);
// Length byte
var wifiLength = 0;
if (Bytes.utf8(networkConfig.ssid).length > 0) {
wifiLength = HEADER_LEN + Bytes.utf8(networkConfig.ssid).length +
HEADER_LEN + Bytes.utf8(networkConfig.password).length;
}
var length = wifiLength +
HEADER_LEN + TOKEN_PLAN_LEN;
if (networkConfig.addressing) {
length += HEADER_LEN + (networkConfig.addressing.dns2 ? STATIC_IP_2_DNS_LEN : STATIC_IP_1_DNS_LEN);
}
if (networkConfig.proxy) {
length += HEADER_LEN + 3 + Bytes.utf8(networkConfig.proxy.server).length;
if (networkConfig.proxy.username) {
length += 1 + Bytes.utf8(networkConfig.proxy.username).length;
}
if (networkConfig.proxy.password) {
length += 1 + Bytes.utf8(networkConfig.proxy.password).length;
}
}
this.appendByte(length);
if (wifiLength > 0) {
this.blinkupWifiCredentials(Bytes.utf8(networkConfig.ssid), Bytes.utf8(networkConfig.password));
}
if (networkConfig.addressing) {
var sn = networkConfig.addressing;
this.blinkupStaticIPConfig(sn.ip, sn.netmask, sn.gateway, sn.dns1, sn.dns2);
}
if (networkConfig.proxy) {
var proxy = networkConfig.proxy;
this.blinkupProxySettings(proxy.port, Bytes.utf8(proxy.server), Bytes.utf8(proxy.username), Bytes.utf8(proxy.password));
}
this.blinkupEnrolCredentials(configId.planId, configId.token);
// Append CRC
this.appendByteNoCRC(this._mCRC >> 8);
this.appendByteNoCRC(this._mCRC & 0xff);
return this;
},
initForClearWirelessConfiguration: function (options) {
// Build a packet
this._mCRC = 0;
this.flashData = new FlashData(options);
// Length of entire packet: 2 byte headers plus fields
this.appendByte(0x02);
this.appendByte(0x07);
this.appendByte(0x00);
// Append CRC
this.appendByteNoCRC(this._mCRC >> 8);
this.appendByteNoCRC(this._mCRC & 0xff);
return this;
},
initForTest: function (options) {
// Build a packet
this._mCRC = 0;
this.flashData = new FlashData(options);
return this;
},
addToCRC: function (b) {
this._mCRC = ((this._mCRC << 8) & 0xffff) ^ this.crc16Table[((this._mCRC >> 8) ^ b) & 0xff];
},
// Append bit by bit
appendByteNoCRC: function (b) {
this.flashData.byteArray.push(b);
},
// Append a byte and add it to the CRC
appendByte: function (b) {
this.appendByteNoCRC(b);
this.addToCRC(b);
},
// Append an entry
appendEntry: function (t, s) {
this.appendByte(t);
this.appendByte(s.length);
// console.log("append type:"+t+" length:"+s.length);
for (var b = 0; b < s.length; b++) {
// console.log("b:"+b+":"+s.charCodeAt(b));
this.appendByte(s.charCodeAt(b));
}
},
blinkupEnrolCredentials: function (plan, token) {
plan = Bytes.hexStringToLEBytes(plan);
token = Bytes.hexStringToLEBytes(token);
this.appendEntry(this.PACKET_ID.ENROLMENT, plan + token);
},
blinkupWifiCredentials: function (ssid, password) {
this.appendEntry(this.PACKET_ID.WIFI_SSID, ssid);
this.appendEntry(this.PACKET_ID.CLEAR_TEXT_PASSWORD, password);
},
blinkupStaticIPConfig: function (ip, netmask, gateway, dns1, dns2) {
var buf = '';
buf += Bytes.dottedQuadToBytes(ip);
buf += Bytes.dottedQuadToBytes(netmask);
buf += Bytes.dottedQuadToBytes(gateway);
buf += Bytes.dottedQuadToBytes(dns1);
if (dns2) {
buf += Bytes.dottedQuadToBytes(dns2);
}
this.appendEntry(this.PACKET_ID.NETWORK_STATIC_CONFIG, buf);
},
blinkupProxySettings: function (port, address, uid, pwd) {
var buf = '';
buf += String.fromCharCode(port & 255);
buf += String.fromCharCode(port >> 8 & 255);
buf += String.fromCharCode(address.length);
buf += address;
if (uid) {
buf += String.fromCharCode(uid.length);
buf += uid;
}
if (pwd) {
buf += String.fromCharCode(pwd.length);
buf += pwd;
}
this.appendEntry(this.PACKET_ID.HTTP_PROXY_SETTINGS, buf);
},
crc16Table: [
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 ]
};
module.exports = FlashPacket;
},{"./ByteOperations":3,"./FlashData":7}],9:[function(require,module,exports){
(function (global){
'use strict';
var env = require('./Environment');
var FlashPacket = require('./FlashPacket');
var flasher = {
flashBits: null,
preambleFlashBits: null,
mPos: 0,
mPreamblePos: 0,
mWidth: 0,
mHeight: 0,
stopFlashing: false,
cb: null,
animator: null,
drawNextFrame: null,
alphaDiv: null,
useAlphaFlash: false,
currentProgress: 0,
lastframeTime: 0,
minFPSInterval: 50.0, // minimum interval between frames,
maxFPS: 60,
drawValues: null,
preambleDrawValues: null,
generateDrawValueArray: function (alphaFlash) {
var values = [0x00, 0xbf, 0xff];
var output = values.map(function (byte) {
if (alphaFlash) {
return 1.0 - byte / 255;
} else {
var str = ('0' + byte.toString(16)).slice(-2);
return '#' + str + str + str;
}
});
return output;
},
findAnimationMethod: function () {
var nativeRAF = global.requestAnimationFrame;
var vendors = ['Webkit', 'Moz', 'ms', 'O'];
for (var i = 0; i < vendors.length && !nativeRAF; i++) {
nativeRAF = global[vendors[i] + 'RequestAnimationFrame'];
}
if (!nativeRAF) {
this.animator = global.AnimationFrame(this.maxFPS);
this.drawNextFrame = this.animator.request;
} else {
this.animator = null;
this.drawNextFrame = nativeRAF;
}
},
forceToNewLayer: function (element) {
var transform = 'translate3d(0,0,0)';
element.style.webkitTransform = transform;
element.style.MozTransform = transform;
element.style.msTransform = transform;
element.style.OTransform = transform;
element.style.transform = transform;
element.style.willChange = 'transform, opacity';
},
getAlphaDiv: function (box) {
var backColor = global.getComputedStyle(box.parentElement).getPropertyValue('background-color');
if (backColor !== 'rgb(255, 255, 255)') {
box.parentElement.style.backgroundColor = '#FFFFFF';
console.log('BU: BU-canvas must be placed in a parent that has a white background color.'); // eslint-disable-line no-console
}
return box;
},
getBox: function () {
// Set stuff up to be hopefully faster
var box = document.getElementById('BU-canvas');
this.mWidth = box.width;
this.mHeight = box.height;
this.forceToNewLayer(box);
box.style.zIndex = 0;
var box_c = box.getContext('2d');
box_c.imageSmoothingEnabled = false;
box_c.msImageSmoothingEnabled = false;
this.useAlphaFlash = env.isOnChrome();
if (this.useAlphaFlash) {
this.alphaDiv = this.getAlphaDiv(box);
}
box_c.fillStyle = this.black;
box_c.fillRect(0, 0, this.mWidth, this.mHeight);
// We set a global variable for the internal flash state
// Although this isn't ideal, it is needed for performance
global.BUInteralFlashState = this;
return box_c;
},
// Should contain the same processing code as sendbit to return
// the list of color or opacity data that will actually be outputted
testSendBitData: function (self) {
var output = [];
var keepGoing = true;
while (keepGoing) {
var bitValue = 0;
var drawValue = 0;
if (self.mPreamblePos < self.preambleFlashBits.length) {
// Draw the flashing box
bitValue = parseInt(self.preambleFlashBits[self.mPreamblePos], 17);
// Could be opacity or hex color
drawValue = self.preambleDrawValues[bitValue];
// Onto the next bit
self.mPreamblePos++;
} else {
// Draw the flashing box
bitValue = parseInt(self.flashBits[self.mPos], 17);
// Could be opacity or hex color
drawValue = self.drawValues[bitValue];
// Onto the next bit
self.mPos++;
}
output.push(drawValue);
// Reschedule if there's anything left
if (self.mPos < self.flashBits.length) {
// Keep going
} else {
keepGoing = false;
}
}
return output;
},
// use an internal object as memory so we never have to allocate during the run loop
sendBitMem: {delta: 0, bitValue: 0, drawValue: 0, progress: 0.0},
sendbit: function (time) { // DOMHighResTimeStamp
var self = global.BUInteralFlashState;
if (self._stopFlashing) {
return;
}
self.sendBitMem.delta = time - self.lastframeTime;
if (self.sendBitMem.delta > self.minFPSInterval) {
// Get ready for next frame by setting lastDrawTime=now, but...
// Also, adjust for fpsInterval not being multiple of 16.67
self.lastframeTime = time - (self.sendBitMem.delta % self.minFPSInterval);
if (self.mPreamblePos < self.preambleFlashBits.length) {
// Draw the flashing box
self.sendBitMem.bitValue = parseInt(self.preambleFlashBits[self.mPreamblePos], 17);
// Could be opacity or hex color
self.sendBitMem.drawValue = self.preambleDrawValues[self.sendBitMem.bitValue];
// Onto the next bit
self.mPreamblePos++;
} else {
// Draw the flashing box
self.sendBitMem.bitValue = parseInt(self.flashBits[self.mPos], 17);
// Could be opacity or hex color
self.sendBitMem.drawValue = self.drawValues[self.sendBitMem.bitValue];
// Onto the next bit
self.mPos++;
}
if (self.useAlphaFlash) {
self.alphaDiv.style.opacity = self.sendBitMem.drawValue;
} else {
self.mBox.fillStyle = self.sendBitMem.drawValue;
self.mBox.fillRect(0, 0, self.mWidth, self.mHeight);
}
// Show progress bar
self.sendBitMem.progress = parseInt(((self.mPos + self.mPreamblePos) / (self.flashBits.length + self.preambleFlashBits.length)) * 100, 10);
if (self.currentProgress !== self.sendBitMem.progress) {
self.currentProgress = self.sendBitMem.progress;
self.progressCallback(self.sendBitMem.progress);
}
}
// Reschedule if there's anything left
if (self.mPos < self.flashBits.length) {
self.drawNextFrame.call(self.animator, global.BUInteralFlashState.sendbit);
} else {
self.cb();
}
},
// Reset the counters associated with sending bits
resetFlashState: function () {
this.mPos = 0;
this.mPreamblePos = 0;
this.currentProgress = 0;
this.minFPSInterval = 1000.0 / this.maxFPS;
this.progressCallback(0);
this.lastframe = 0;
this._stopFlashing = false;
},
start: function (configId, networkConfig, options, cb) {
// Cache box
this.mBox = this.getBox();
this.cb = cb;
var flashData = FlashPacket.init(configId, networkConfig, options).flashData;
this.flashBits = flashData.asciiEncode();
this.flashBits += '000000'; // Add some black to the end
this.drawValues = this.generateDrawValueArray(this.useAlphaFlash);
this.preambleFlashBits = flashData.asciiEncodePreamble();
this.preambleDrawValues = this.generateDrawValueArray(this.useAlphaFlash);
this.findAnimationMethod();
this.resetFlashState();
this.sendbit(this.lastframe);
},
startDisconnect: function (options, cb) {
// Cache box
this.mBox = this.getBox();
this.cb = cb;
var flashData = FlashPacket.initForClearWirelessConfiguration(options).flashData;
this.flashBits = flashData.asciiEncode();
this.flashBits += '000000'; // Add some black to the end
this.drawValues = this.generateDrawValueArray(this.useAlphaFlash);
this.preambleFlashBits = flashData.asciiEncodePreamble();
this.preambleDrawValues = this.generateDrawValueArray(this.useAlphaFlash);
this.findAnimationMethod();
this.resetFlashState();
this.sendbit(this.lastframe);
},
testDisconnect: function (options, useAlphaFlash) {
var flashData = FlashPacket.initForClearWirelessConfiguration(options).flashData;
this.flashBits = flashData.asciiEncode();
this.flashBits += '000000'; // Add some black to the end
this.drawValues = this.generateDrawValueArray(this.useAlphaFlash);
this.preambleFlashBits = flashData.asciiEncodePreamble();
this.preambleDrawValues = this.generateDrawValueArray(this.useAlphaFlash);
this.resetFlashState();
return this.testSendBitData(this);
},
stop: function () {
this._stopFlashing = true;
},
// use a mem cache to prevent object allocation
progressCallbackMem: {scale: '', element: null},
progressCallback: function (progress) {
if (this.maxFPS > 29 || env.isOnFirefox()) {
return;
}
// Can be overwritten in exports
// We use scale as it is a very fast gpu operation
this.progressCallbackMem.scale = 'translateZ(0) scale(' + progress / 100.0 + ',1)';
this.progressCallbackMem.element = document.getElementById('BU-progress');
this.progressCallbackMem.element.style.webkitTransform = this.progressCallbackMem.scale;
this.progressCallbackMem.element.style.MozTransform = this.progressCallbackMem.scale;
this.progressCallbackMem.element.style.msTransform = this.progressCallbackMem.scale;
this.progressCallbackMem.element.style.OTransform = this.progressCallbackMem.scale;
this.progressCallbackMem.element.style.transform = this.progressCallbackMem.scale;
}
};
module.exports = flasher;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./Environment":6,"./FlashPacket":8}],10:[function(require,module,exports){
'use strict';
var StaticAddressing = require('./StaticAddressing');
var NetworkProxy = require('./NetworkProxy');
/**
* Represents the configuration for a network connection.
* @class
* @classdesc Represents the configuration for a network connection.
* @memberof module:blinkupSDK~
* @static
* @param {object} params Initialization parameters
* @param {string} [params.ssid] The SSID of the network
* @param {string} [params.password] The password for the network
* @param {StaticAddressing} [params.addressing] The static IP information for the network
* @param {NetworkProxy} [params.proxy] The proxy information for the network
* @see module:blinkupSDK~StaticAddressing
* @see module:blinkupSDK~NetworkProxy
* @example
* // Network with SSID and password
* var blinkup = require('blinkup/blinkupSDK');
* var networkConfig = new blinkup.NetworkConfig({ssid: 'myWifi', password: 'secret'});
* @example
* // Network with SSID, password, static network, and proxy
* var blinkup = require('blinkup/blinkupSDK');
* var addressing = new blinkup.StaticAddressing({ip: '192.168.1.200', netmask: '255.255.0.0', gateway: '192.168.1.1', dns1: '8.8.8.8'});
* var proxy = new blinkup.NetworkProxy({server: 'proxyServer2.local', port: '8000'});
* var networkConfig = new blinkup.NetworkConfig({ssid: 'myWifi', password: 'secret', addressing: addressing, proxy: proxy});
* @example
* // Use Globals rather than modules
* // Network with SSID, password, static network, and proxy
* var networkConfig = new BU.NetworkConfig({ssid: 'myWifi', password: 'secret'});
* @example
* // Ethernet Network (no SSID or password)
* var networkConfig = new BU.NetworkConfig({});
* @example
* // Ethernet Network with static ip and proxy (no SSID or password)
* var blinkup = require('blinkup/blinkupSDK');
* var addressing = new blinkup.StaticAddressing({ip: '192.168.1.200', netmask: '255.255.0.0', gateway: '192.168.1.1', dns1: '8.8.8.8'});
* var proxy = new blinkup.NetworkProxy({server: 'proxyServer2.local', port: '8000'});
* var networkConfig = new blinkup.NetworkConfig({addressing: addressing, proxy: proxy});
*/
function NetworkConfig (params) {
/** (Optional) The SSID of the wifi network (not required for ethernet) */
this.ssid = params.ssid || '';
/** (Optional) The password for the wifi network (not required for ethernet) */
this.password = params.password || '';
/** (Optional) The static IP information for the wifi network */
this.addressing = params.addressing ? new StaticAddressing(params.addressing) : null;
/** (Optional) The proxy information for the wifi network */
this.proxy = params.proxy ? new NetworkProxy(params.proxy) : null;
};
/** Validates that the object represents a valid network configuration */
// if password is set and ssid is set, this is a wifi network
// if password is set and ssid is not set, this is not a valid network
// if password is not set and ssid is set, this is a wifi network
// if password is not set and ssid is not set, this is an ethernet network
NetworkConfig.prototype.isComplete = function () {
return typeof this.ssid === 'string' && (this.ssid !== '' || this.password === '');
};
module.exports = NetworkConfig;
},{"./NetworkProxy":11,"./StaticAddressing":12}],11:[function(require,module,exports){
'use strict';
/**
* Represents the server proxy information for the device
* @class
* @classdesc Represents the server proxy information for the device
* @memberof module:blinkupSDK~
* @static
* @param {object} params Initialization parameters
* @param {string} params.server The server IP or hostname of the proxy
* @param {string} params.port The server port running the proxy
* @param {string} [params.username] The username of the proxy
* @param {string} [params.password] The password of the proxy
* @example
* // Proxy without authentication
* var blinkup = require('blinkup/blinkupSDK');
* var proxy = new blinkup.NetworkProxy({server: 'proxyServer2.local', port: '8000'});
* @example
* // Proxy with authentication
* var blinkup = require('blinkup/blinkupSDK');
* var proxy = new blinkup.NetworkProxy({server: 'proxyServer2.local', port: '8000', username: 'user23', password: 'p@ssw0rd'});
* @example
* // Proxy using globals rather than modules
* var proxy = new BU.NetworkProxy({server: 'proxyServer2.local', port: '8000', username: 'user23', password: 'p@ssw0rd'});
*/
function NetworkProxy (params) {
/** (Required) The server IP or hostname of the proxy */
this.server = params.server;
/** (Required) The server port running the proxy */
this.port = params.port;
/** (Optional) The username of the proxy */
this.username = params.username || '';
/** (Optional) The password of the proxy */
this.password = params.password || '';
};
/** Validates that the object represents a valid network configuration */
NetworkProxy.prototype.isComplete = function () {
if (this.server !== '' || this.port !== '' || this.username !== '' || this.password !== '') {
return (this.server !== '' && this.port !== '' && !isNaN(parseInt(this.port, 10)));
} else {
return true;
}
};
module.exports = NetworkProxy;
},{}],12:[function(require,module,exports){
'use strict';
/**
* @class
* @classdesc Configure static networking information for imp configuration.
* @memberof module:blinkupSDK~
* @static
* @param {object} params Initialization parameters
* @param {string} params.ip The IP of the device to be configured
* @param {string} params.netmask The netmask of the device to be configured
* @param {string} params.gateway The gateway of the device to be configured
* @param {string} params.dns1 The seconday dns of the device to be configured
* @param {string} [params.dns2] The seconday dns of the device to be configured
* @example
* // Use static network addressing with a single DNS
* var blinkup = require('blinkup/blinkupSDK');
* var addressing = new blinkup.StaticAddressing({ip: '192.168.1.200', netmask: '255.255.0.0', gateway: '192.168.1.1', dns1: '8.8.8.8'});
* @example
* // Use static network addressing with a two DNS servers
* var blinkup = require('blinkup/blinkupSDK');
* var addressing = new blinkup.StaticAddressing({ip: '192.168.1.200', netmask: '255.255.0.0', gateway: '192.168.1.1', dns1: '8.8.8.8', dns2: '8.8.4.4'});
* @example
* // Using globals rather than modules
* var addressing = new BU.StaticAddressing({ip: '192.168.1.200', netmask: '255.255.0.0', gateway: '192.168.1.1', dns1: '8.8.8.8'});
*/
function StaticAddressing (params) {
/** (Required) The IP of the device to be configured */
this.ip = params.ip;
/** (Required) The netmask of the device to be configured */
this.netmask = params.netmask;
/** (Required) The gateway of the device to be configured */
this.gateway = params.gateway;
/** (Required) The dns of the device to be configured */
this.dns1 = params.dns1;
/** (Optional) The seconday dns of the device to be configured */
this.dns2 = params.dns2 || '';
};
/** Validates that the object represents a valid network configuration */
StaticAddressing.prototype.isComplete = function () {
if (this.ip !== '' || this.netmask !== '' || this.gateway !== '' || this.dns1 !== '' || this.dns2 !== '') {
return (!(this.ip === '' || this.netmask === '' || this.gateway === '' || this.dns1 === ''));
} else {
return true;
}
};
module.exports = StaticAddressing;
},{}],13:[function(require,module,exports){
/**
* JavaScript BlinkUp version <packageVersion>
* blinkupSDK module.
* @module blinkupSDK
*/
'use strict';
var ConfigId = require('./ConfigId');
var DeviceInfo = require('./DeviceInfo');
var flasher = require('./Flasher');
var env = require('./Environment');
var Base64 = require('./Base64');
var _apiBaseURL = 'https://api.electricimp.com';
var _stopPolling = false;
/** StaticAddressing class constructor for static addressing */
module.exports.StaticAddressing = require('./StaticAddressing');
/** NetworkConfig class constructor for imp network configuration */
module.exports.NetworkConfig = require('./NetworkConfig');
/** NetworkProxy class constructor for routing imp traffic through a proxy */
module.exports.NetworkProxy = require('./NetworkProxy');
/** Max time to poll for a device after flash in whole seconds */
module.exports.pollTimeout = 60;
/** If true, prevents the default behavior where a faster flasher is used on mobile devices */
module.exports.preventFastFlashing = false;
var estimatedFrameRate = function () {
if (!(exports.preventFastFlashing) && env.isOnMobile()) {
// return 30;
if (env.isOnIOS()) {
var iOSVersion = env.iOSMajorVersion();
var isRetina = (window.devicePixelRatio >= 2);
if (iOSVersion !== null && iOSVersion < 7) {
// 30 FPS for iOS Safari less than 7
return 30;
} else if (!isRetina) {
// 30 FPS for non-Retina devices, likely older
return 30;
}
}
// 60 FPS for general mobile
return 60;
} else {
// 20 FPS for Desktop
return 20;
}
};
/**
* During the flashing process this function is called with the progress percentage.
*
* Setting this property will override the default progress bar behaviour.
* Care should be taken when creating the callback as any screen updates may cause
* the BlinkUp to fail on various devices. The SDK will call this method on each
* percentage point change in progress regardless of FPS.
*
* @param {Number} progress Specifies progress of the flash process
* @example
* var blinkup = require('blinkup/blinkupSDK');
* blinkup.progressCallback = function (progress) {
* // Perform a very fast ui update.
* // object.style = 'translateZ(0) scale(' + progress / 100.0 + ',1)'
* };
*/
module.exports.progressCallback = null;
/**
* Evaluate if the default progressCallback function will update the progress
* bar. If the progressCalback has been manually set the returned value isn't
* valid.
*
* @param {Number} [overrideFPS] FPS if you will be overridding the default fps
* @returns {Boolean} true if the default progress callback function will update the
* progress bar, false otherwise.
*/
module.exports.progressCallbackWillOccurr = function (overrideFPS) {
var fps = estimatedFrameRate();
if (typeof overrideFPS === 'number') {
fps = overrideFPS;
}
if (fps > 29 || env.isOnFirefox()) {
return false;
} else {
return true;
}
};
/**
* Get a ConfigId from the Electric Imp API.
*
* @param {string} apiKey Your apiKey from Electric Imp
* @param {string} existingPlanId For production environment, existing Id previously generated by Electric Imp, or null to auto-generate a new plan Id.
* @param {string} environment `production` environment
* @param {module:blinkupSDK~getConfigIdCompletion} callback Called on completion
* @example
* var blinkup = require('blinkup/blinkupSDK');
* blinkup.getConfigId('myElectricImpAPIKey', null, 'production', function (err, configId) {
* if (err) {
* // Handle error
* } else {
* // The configId has been retrieved.
* // Generally it should be passed to the startNetworkFlash function
* var theConfigId = configId;
* }
* });
*/
module.exports.getConfigId = function (apiKey, existingPlanId, environment, callback) {
if (apiKey === null) {
console.log('BU: No API key provided.'); // eslint-disable-line no-console
return callback('No API key provided.', null);
}
if (environment !== 'production') {
console.log('BU: environment must be production'); // eslint-disable-line no-console
return callback('Environment must be production', null);
}
var encodedKey = Base64.encode(apiKey);
var url = _apiBaseURL;
var data = {};
if (environment === 'production') {
url += '/v1/setup_tokens';
if (existingPlanId !== null && typeof existingPlanId === 'string') {
data.plan_id = existingPlanId;
}
} else {
url += '/enrol';
data.api_key = apiKey;
}
$.ajax({
type: 'POST',
url: url,
data: data,
crossDomain: true,
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization',
'Basic ' + encodedKey);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
},
error: function (jqXHR, textStatus, errorThrown) {
// 400 is returned by production, 403 is from development
if (jqXHR.statusCode().status === 403 || jqXHR.statusCode().status === 400) {
return callback('Your API key is invalid for this environment!', null);
} else if (jqXHR.statusCode().status === 401) {
return callback('The provided API key must be valid and at least 32 alphanumeric characters long.', null);
} else if (errorThrown !== null && errorThrown !== '') {
return callback(errorThrown, null);
} else {
return callback('Possible API Key Error', null);
}
},
success: function (token_info) {
if (token_info.valid_token === false) {
return callback('Invalid API key', null);
}
var planId = token_info.plan_id || token_info.siteids[0];
var token = token_info.id || token_info.token;
var configId = new ConfigId({
token: token,
planId: planId,
apiKey: apiKey,
environment: environment
});
return callback(null, configId);
}
});
};
/**
* Callback used by getConfigId.
*
* @callback getConfigIdCompletion
* @param {string} error Specifies error, null on success
* @param {module:blinkupSDK~ConfigId} configId ConfigId object containing token and planId information returned by API (null on failure)
*/
/**
* Starts the BlinkUp flash process by targeting the BU-canvas element in the DOM.
*
* @param {module:blinkupSDK~ConfigId} configId The ConfigId with token, planId, apiKey, and type (retrieved by getConfigId)
* @param {module:blinkupSDK~NetworkConfig} networkConfig The network configuration for the wireless network to use
* @param {Object} Flashing parameters {fps: [10-60] (default:60 mobile, 20 browser)}
* @param {callback} callback Callback function for after the BlinkUp flash finishes (with success parameter)
* @example
* var blinkup = require('blinkup/blinkupSDK');
* // configId, networkConfig created elsewhere
* var options = {
* };
* blinkup.startNetworkFlash(configId, networkConfig, options, function () {
* // Hide the canvas and progress bar now that BlinkUp is complete
* // hideFlashingElements();
*
* // Show status of device polling
* // setInstruction('Gathering device data (' + blinkup.pollTimeout + 's max)');
* // document.getElementById('status').style.display = 'block';
* // showPolling();
*
* // Poll the device for results of the BlinkUp process
* // getDeviceStatus(configId);
* });
*/
module.exports.startNetworkFlash = function (configId, networkConfig, options, callback) {
if (typeof callback === 'undefined') {
callback = options;
options = {};
}
options = options || {};
if (typeof options.fps === 'number') {
flasher.maxFPS = options.fps;
} else {
flasher.maxFPS = estimatedFrameRate();
}
if (typeof exports.progressCallback === 'function') {
flasher.progressCallback = exports.progressCallback;
}
flasher.start(configId, networkConfig, options, function () {
return callback();
});
};
/**
* Starts the BlinkUp disconnect process by targeting the BU-canvas element in the DOM.
* @param {Object} options Flashing parameters {fps: [10-60] (default:60 mobile, 20 browser)}
* @param {callback} callback Callback function for after the BlinkUp flash finishes (no parameters)
* @example
* var blinkup = require('blinkup/blinkupSDK');
* blinkup.startDisconnectFlash({}, function () {
* // Hide the canvas and progress bar now that BlinkUp is complete
* // hideFlashingElements();
* });
*/
module.exports.startDisconnectFlash = function (options, callback) {
if (typeof callback === 'undefined') {
callback = options;
options = {};
}
options = options || {};
if (typeof options.fps === 'number') {
flasher.maxFPS = options.fps;
} else {
flasher.maxFPS = estimatedFrameRate();
}
if (typeof exports.progressCallback === 'function') {
flasher.progressCallback = exports.progressCallback;
}
flasher.startDisconnect(options, function () {
return callback();
});
};
/**
* Cancel any active Device Polling
*
*/
module.exports.stopPolling = function () {
_stopPolling = true;
};
/**
* Cancel any active BlinkUp flashing
*
*/
module.exports.stopFlash = function () {
flasher.stop();
};
/**
* Polls the Electric Imp server to gather information about the recently flashed
* device.
*
* @param {module:blinkupSDK~ConfigId} configId The ConfigId used during present
* @param {module:blinkupSDK~pollForDeviceInfoCompletion} callback Callback function for after device has been polled
* @example
* var blinkup = require('blinkup/blinkupSDK');
* blinkup.pollForDeviceInfo (configId, function(err, deviceInfo) {
* if (err) {
* // Handle error
* // (device rejected or server connection timed out)
* } else if (deviceInfo) {
* // Do something with deviceInfo data
* }
* });
*/
module.exports.pollForDeviceInfo = function (configId, callback) {
var encodedKey = Base64.encode(configId.apiKey);
var url = _apiBaseURL;
if (configId.environment === 'production') {
url += '/v1/setup_tokens/' + configId.token;
}
_stopPolling = false;
var timedOut = false;
// If we are using the dev endpoint, discard the first result if
// it returns valid data as it is almost surely old data
var discardBecauseFirstDev = true;
var pollTimeoutId = setTimeout(function () {
timedOut = true;
}, exports.pollTimeout * 1000);
var pollIntervalId = setInterval(function () {
if (_stopPolling === true) {
clearTimeout(pollTimeoutId);
clearInterval(pollIntervalId);
return;
} else if (timedOut) {
clearInterval(pollIntervalId);
return callback('Timeout waiting for device to connect', null);
} else {
$.ajax({
type: 'GET',
url: url,
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization',
'Basic ' + encodedKey);
},
error: function (jqXHR, textStatus, errorThrown) {
return callback(errorThrown, null);
},
success: function (data) {
if (_stopPolling === true || timedOut === true) {
clearInterval(pollIntervalId);
return;
}
if (configId.environment === 'production') {
if (data.impee_id !== '') {
clearInterval(pollIntervalId);
clearTimeout(pollTimeoutId);
var deviceInfo = new DeviceInfo({ // eslint-disable-line no-redeclare
agentURL: data.agent_url,
deviceId: data.impee_id,
planId: data.plan_id,
verificationDate: data.claimed_at
});
return callback(null, deviceInfo);
}
}
}
});
}
}, 1000);
};
/**
* Callback used by pollForDeviceInfo.
*
* @callback pollForDeviceInfoCompletion
* @param {string} error Specifies error, null on success
* @param {module:blinkupSDK~DeviceInfo} data Device information for successfully Blinked Up device (null on failure)
*/
},{"./Base64":2,"./ConfigId":4,"./DeviceInfo":5,"./Environment":6,"./Flasher":9,"./NetworkConfig":10,"./NetworkProxy":11,"./StaticAddressing":12}]},{},[1]);