<commit_before>/**
 * @fileoverview About this file
 */

/**
 * @type {Object}
 * @const
 */
var SugarCrm = {};

/**
 * Represents SugarCRM field boolean value.
 * @enum {string}
 */
SugarCrm.Boolean = {
  '0': '0',
  '1': '1'
};

/**
 * Represents SugarCRM name value list pair.
 * @constructor
 */
SugarCrm.NameValue = function() {};

/**
 * @type {string}
 */
SugarCrm.NameValue.prototype.name;

/**
 * @type {string}
 */
SugarCrm.NameValue.prototype.value;

/**
 * Represents SugarCRM name value list entry.
 * @constructor
 */
SugarCrm.NameValueEntry = function() {};

/**
 * @type {string}
 */
SugarCrm.NameValueEntry.prototype.id;

/**
 * @type {string}
 */
SugarCrm.NameValueEntry.prototype.module_name;

/**
 * @type {Object.<SugarCrm.NameValue>}
 */
SugarCrm.NameValueEntry.prototype.name_value_list;

/**
 * Represents SugarCRM email field.
 * @constructor
 */
SugarCrm.EmailField = function() {};

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.bean_id;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.bean_module;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.date_created;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.date_modified;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.deleted;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address_caps;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address_id;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.id;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.invalid_email;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.opt_out;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.primary_address;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.reply_to_address;

/**
 * CRUD Request result.
 * @interface
 */
SugarCrm.CrudResult = function() {};

/**
 * @type {number}
 */
SugarCrm.CrudResult.prototype.created;

/**
 * @type {number}
 */
SugarCrm.CrudResult.prototype.failed;

/**
 * @type {number}
 */
SugarCrm.CrudResult.prototype.deleted;

/**
 * Represents SugarCRM entry.
 * @constructor
 */
SugarCrm.Record = function() {};

/**
 * @type {string}
 */
SugarCrm.Record.prototype.id;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.name;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.date_entered;

/**
 * @type {string}
 */
SugarCrm.Record.prototype.date_modified;

/**
 * This field include in v10 REST result, but not in v4.
 * @type {string} module name.
 */
SugarCrm.Record.prototype._module;

/**
 * @type {string} either '1' or '0'
 */
SugarCrm.Record.prototype.deleted;

/**
 * Result record from query with scoring.
 * @constructor
 * @extends {SugarCrm.Record}
 */
SugarCrm.ScoredRecord = function() {};

/**
 * @type {number}
 */
SugarCrm.ScoredRecord.prototype._score;

/**
 * Record in login respond.
 * @constructor
 * @extends {SugarCrm.Record}
 */
SugarCrm.LoginRecord = function() {};

/**
 * @type {string} "-99"
 */
SugarCrm.LoginRecord.prototype.user_currency_id;

/**
 * @type {string} "US Dollars"
 */
SugarCrm.LoginRecord.prototype.user_currency_name;

/**
 * @type {string} "."
 */
SugarCrm.LoginRecord.prototype.user_decimal_seperator;

/**
 * @type {string} "m/d/Y"
 */
SugarCrm.LoginRecord.prototype.user_default_dateformat;

/**
 * @type {?string}
 */
SugarCrm.LoginRecord.prototype.user_default_team_id;

/**
 * @type {string} "h:ia"
 */
SugarCrm.LoginRecord.prototype.user_default_timeformat;

/**
 * @type {string}
 */
SugarCrm.LoginRecord.prototype.user_id;

/**
 * @type {boolean}
 */
SugarCrm.LoginRecord.prototype.user_is_admin;

/**
 * Represents SugarCRM ModuleField.
 * @constructor
 */
SugarCrm.ModuleField = function() {};

/**
 * @type {boolean}
 */
SugarCrm.ModuleField.prototype.calculated;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.group;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.id_name;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.label;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.len;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.name;

/**
 * @type {Object.<SugarCrm.NameValue>|undefined}
 */
SugarCrm.ModuleField.prototype.options;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.related_module;

/**
 * @type {number}
 */
SugarCrm.ModuleField.prototype.required;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.type;

/**
 * Represents SugarCRM LinkField.
 * @constructor
 */
SugarCrm.LinkField = function() {};

/**
 * @type {string} this is always 'link' ?
 */
SugarCrm.LinkField.prototype.type;

/**
 * @type {string} Module name
 */
SugarCrm.LinkField.prototype.module;

/**
 * @type {string} Link name. Same as its object hash key.
 */
SugarCrm.LinkField.prototype.name;

/**
 * Represents meta data for ModuleInfo.
 * @constructor
 */
SugarCrm.ModuleMeta = function() {};

/**
 * Color hex for module.
 * @type {string}
 */
SugarCrm.ModuleMeta.prototype.color;

/**
 * List of email fields.
 * @type {Array.<string>}
 */
SugarCrm.ModuleMeta.prototype.email_fields;

/**
 * Represents SugarCRM Acl.
 * @constructor
 */
SugarCrm.Acl = function() {};

/**
 * @type {boolean}
 */
SugarCrm.Acl.prototype.access;

/**
 * Enum of 'edit', 'delete', 'list', 'view', 'import', 'export'
 * @type {string}
 */
SugarCrm.Acl.prototype.action;

/**
 * Represents SugarCRM AvailableModule.
 * @constructor
 */
SugarCrm.AvailableModule = function() {};

/**
 * @type {boolean}
 */
SugarCrm.AvailableModule.prototype.favorite_enabled;

/**
 * @type {string}
 */
SugarCrm.AvailableModule.prototype.module_key;

/**
 * @type {string}
 */
SugarCrm.AvailableModule.prototype.module_label;

/**
 * @type {Array.<SugarCrm.Acl>}
 */
SugarCrm.AvailableModule.prototype.acls;

/**
 * Represents SugarCRM ModuleInfo.
 * @constructor
 */
SugarCrm.ModuleInfo = function() {};

/**
 * @type {SugarCrm.ModuleMeta}
 */
SugarCrm.ModuleInfo.prototype._meta;

/**
 * @type {string}
 */
SugarCrm.ModuleInfo.prototype.module_name;

/**
 * @type {string}
 */
SugarCrm.ModuleInfo.prototype.table_name;

/**
 * @type {!Object.<SugarCrm.ModuleField>|!Array.<SugarCrm.ModuleField>}
 */
SugarCrm.ModuleInfo.prototype.module_fields;

/**
 * @type {!Object.<SugarCrm.LinkField>}
 */
SugarCrm.ModuleInfo.prototype.link_fields;

/**
 * Represents query format in channel.
 * @constructor
 * @extends {CrmApp.ReqQuery}
 */
SugarCrm.Query = function() {};

/**
 * @type {Array.<SugarCrm.Record>} result of query.
 */
SugarCrm.Query.prototype.result;

/**
 * @interface
 */
SugarCrm.ServerInfo = function() {};

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.flavor;

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.version;

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.uptime;

/**
 * @constructor
 */
SugarCrm.About = function() {};

/**
 * @type {(string|undefined)}
 */
SugarCrm.About.prototype.baseUrl;

/**
 * @type {string}
 */
SugarCrm.About.prototype.domain;

/**
 * @type {(string|undefined)}
 */
SugarCrm.About.prototype.userName;

/**
 * @type {(boolean|undefined)}
 */
SugarCrm.About.prototype.hostPermission;

/**
 * @type {(string|undefined)} authentication provider.
 */
SugarCrm.About.prototype.provider;

/**
 * @type {(boolean|undefined)}
 */
SugarCrm.About.prototype.isLogin;

/**
 * @constructor
 * @extends {SugarCrm.About}
 */
CrmApp.Credential = function() {};

/**
 * @type {string}
 */
CrmApp.Credential.prototype.password;

/**
 * @type {string|undefined}
 */
CrmApp.Credential.prototype.provider;

/**
 * @type {boolean|undefined}
 */
CrmApp.Credential.prototype.hashed;

/**
 * @constructor
 */
SugarCrm.Details = function() {};

/**
 * @type {SugarCrm.About}
 */
SugarCrm.Details.prototype.about = null;

/**
 * @type {SugarCrm.ServerInfo}
 */
SugarCrm.Details.prototype.serverInfo = null;

/**
 * @type {?SugarCrm.LoginRecord}
 */
SugarCrm.Details.prototype.loginInfo = null;

/**
 * @type {?CrmApp.Credential}
 */
SugarCrm.Details.prototype.credential = null;

/**
 * @type {Array.<SugarCrm.AvailableModule>}
 */
SugarCrm.Details.prototype.availableModules = [];

/**
 * @type {Array.<SugarCrm.ModuleInfo>}
 */
SugarCrm.Details.prototype.modulesInfo = [];

/**
 * Query result for GData contact to SugarCRM records.
 * @interface
 */
SugarCrm.ContactSimilarityResult = function() {};

/**
 * @type {string}
 */
SugarCrm.ContactSimilarityResult.prototype.module;

/**
 * @type {string}
 */
SugarCrm.ContactSimilarityResult.prototype.index;

/**
 * @type {string}
 */
SugarCrm.ContactSimilarityResult.prototype.key;

/**
 * @type {Array<SugarCrm.Record>}
 */
SugarCrm.ContactSimilarityResult.prototype.result;

/**
 * Module name and id pair in relationship result.
 * @constructor
 */
SugarCrm.ModuleNameIdPair = function() {};

/**
 * @type {string}
 */
SugarCrm.ModuleNameIdPair.prototype.module_name;

/**
 * @type {string}
 */
SugarCrm.ModuleNameIdPair.prototype.id;

/**
 * Record format for relationships cache.
 * @constructor
 */
SugarCrm.Relationships = function() {};

/**
 * @type {number}
 */
SugarCrm.Relationships.prototype.modified;

/**
 * @type {SugarCrm.ModuleNameIdPair}
 */
SugarCrm.Relationships.prototype.to;

/**
 * @type {SugarCrm.ModuleNameIdPair}
 */
SugarCrm.Relationships.prototype.from;

/**
 * Represents SugarCRM entry.
 * @constructor
 */
SugarCrm.SyncCheckpoint = function() {};

/**
 * Lower value of updated timestamp.
 * @type {string}
 */
SugarCrm.SyncCheckpoint.prototype.lower = '';

/**
 * Upper value of updated timestamp.
 * @type {string}
 */
SugarCrm.SyncCheckpoint.prototype.upper = '';

/**
 * Updated timestamp.
 * @type {number}
 */
SugarCrm.SyncCheckpoint.prototype.updated = 0;
<commit_msg>add sync with domain shared contact<commit_after>/**
 * @fileoverview About this file
 */

/**
 * @type {Object}
 * @const
 */
var SugarCrm = {};

/**
 * Represents SugarCRM field boolean value.
 * @enum {string}
 */
SugarCrm.Boolean = {
  '0': '0',
  '1': '1'
};

/**
 * Represents SugarCRM name value list pair.
 * @constructor
 */
SugarCrm.NameValue = function() {};

/**
 * @type {string}
 */
SugarCrm.NameValue.prototype.name;

/**
 * @type {string}
 */
SugarCrm.NameValue.prototype.value;

/**
 * Represents SugarCRM name value list entry.
 * @constructor
 */
SugarCrm.NameValueEntry = function() {};

/**
 * @type {string}
 */
SugarCrm.NameValueEntry.prototype.id;

/**
 * @type {string}
 */
SugarCrm.NameValueEntry.prototype.module_name;

/**
 * @type {Object.<SugarCrm.NameValue>}
 */
SugarCrm.NameValueEntry.prototype.name_value_list;

/**
 * Represents SugarCRM email field.
 * @constructor
 */
SugarCrm.EmailField = function() {};

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.bean_id;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.bean_module;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.date_created;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.date_modified;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.deleted;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address_caps;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.email_address_id;

/**
 * @type {string}
 */
SugarCrm.EmailField.prototype.id;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.invalid_email;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.opt_out;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.primary_address;

/**
 * @type {SugarCrm.Boolean}
 */
SugarCrm.EmailField.prototype.reply_to_address;

/**
 * CRUD Request result.
 * @interface
 */
SugarCrm.CrudResult = function() {};

/**
 * @type {number}
 */
SugarCrm.CrudResult.prototype.created;

/**
 * @type {number}
 */
SugarCrm.CrudResult.prototype.failed;

/**
 * @type {number}
 */
SugarCrm.CrudResult.prototype.deleted;

/**
 * Represents SugarCRM entry.
 * @constructor
 */
SugarCrm.Record = function() {};

/**
 * @type {string}
 */
SugarCrm.Record.prototype.id = '';

/**
 * @type {string}
 */
SugarCrm.Record.prototype.name = '';

/**
 * @type {string}
 */
SugarCrm.Record.prototype.date_entered = '';

/**
 * @type {string}
 */
SugarCrm.Record.prototype.date_modified = '';

/**
 * This field include in v10 REST result, but not in v4.
 * @type {string} module name.
 */
SugarCrm.Record.prototype._module = '';

/**
 * @type {string} either '1' or '0'
 */
SugarCrm.Record.prototype.deleted = '';

/**
 * Result record from query with scoring.
 * @constructor
 * @extends {SugarCrm.Record}
 */
SugarCrm.ScoredRecord = function() {};

/**
 * @type {number}
 */
SugarCrm.ScoredRecord.prototype._score;

/**
 * Record in login respond.
 * @constructor
 * @extends {SugarCrm.Record}
 */
SugarCrm.LoginRecord = function() {};

/**
 * @type {string} "-99"
 */
SugarCrm.LoginRecord.prototype.user_currency_id;

/**
 * @type {string} "US Dollars"
 */
SugarCrm.LoginRecord.prototype.user_currency_name;

/**
 * @type {string} "."
 */
SugarCrm.LoginRecord.prototype.user_decimal_seperator;

/**
 * @type {string} "m/d/Y"
 */
SugarCrm.LoginRecord.prototype.user_default_dateformat;

/**
 * @type {?string}
 */
SugarCrm.LoginRecord.prototype.user_default_team_id;

/**
 * @type {string} "h:ia"
 */
SugarCrm.LoginRecord.prototype.user_default_timeformat;

/**
 * @type {string}
 */
SugarCrm.LoginRecord.prototype.user_id;

/**
 * @type {boolean}
 */
SugarCrm.LoginRecord.prototype.user_is_admin;

/**
 * Represents SugarCRM ModuleField.
 * @constructor
 */
SugarCrm.ModuleField = function() {};

/**
 * @type {boolean}
 */
SugarCrm.ModuleField.prototype.calculated;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.group;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.id_name;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.label;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.len;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.name;

/**
 * @type {Object.<SugarCrm.NameValue>|undefined}
 */
SugarCrm.ModuleField.prototype.options;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.related_module;

/**
 * @type {number}
 */
SugarCrm.ModuleField.prototype.required;

/**
 * @type {string}
 */
SugarCrm.ModuleField.prototype.type;

/**
 * Represents SugarCRM LinkField.
 * @constructor
 */
SugarCrm.LinkField = function() {};

/**
 * @type {string} this is always 'link' ?
 */
SugarCrm.LinkField.prototype.type;

/**
 * @type {string} Module name
 */
SugarCrm.LinkField.prototype.module;

/**
 * @type {string} Link name. Same as its object hash key.
 */
SugarCrm.LinkField.prototype.name;

/**
 * Represents meta data for ModuleInfo.
 * @constructor
 */
SugarCrm.ModuleMeta = function() {};

/**
 * Color hex for module.
 * @type {string}
 */
SugarCrm.ModuleMeta.prototype.color;

/**
 * List of email fields.
 * @type {Array.<string>}
 */
SugarCrm.ModuleMeta.prototype.email_fields;

/**
 * Represents SugarCRM Acl.
 * @constructor
 */
SugarCrm.Acl = function() {};

/**
 * @type {boolean}
 */
SugarCrm.Acl.prototype.access;

/**
 * Enum of 'edit', 'delete', 'list', 'view', 'import', 'export'
 * @type {string}
 */
SugarCrm.Acl.prototype.action;

/**
 * Represents SugarCRM AvailableModule.
 * @constructor
 */
SugarCrm.AvailableModule = function() {};

/**
 * @type {boolean}
 */
SugarCrm.AvailableModule.prototype.favorite_enabled;

/**
 * @type {string}
 */
SugarCrm.AvailableModule.prototype.module_key;

/**
 * @type {string}
 */
SugarCrm.AvailableModule.prototype.module_label;

/**
 * @type {Array.<SugarCrm.Acl>}
 */
SugarCrm.AvailableModule.prototype.acls;

/**
 * Represents SugarCRM ModuleInfo.
 * @constructor
 */
SugarCrm.ModuleInfo = function() {};

/**
 * @type {SugarCrm.ModuleMeta}
 */
SugarCrm.ModuleInfo.prototype._meta;

/**
 * @type {string}
 */
SugarCrm.ModuleInfo.prototype.module_name;

/**
 * @type {string}
 */
SugarCrm.ModuleInfo.prototype.table_name;

/**
 * @type {!Object.<SugarCrm.ModuleField>|!Array.<SugarCrm.ModuleField>}
 */
SugarCrm.ModuleInfo.prototype.module_fields;

/**
 * @type {!Object.<SugarCrm.LinkField>}
 */
SugarCrm.ModuleInfo.prototype.link_fields;

/**
 * Represents query format in channel.
 * @constructor
 * @extends {CrmApp.ReqQuery}
 */
SugarCrm.Query = function() {};

/**
 * @type {Array.<SugarCrm.Record>} result of query.
 */
SugarCrm.Query.prototype.result;

/**
 * @interface
 */
SugarCrm.ServerInfo = function() {};

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.flavor;

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.version;

/**
 * @type {(string|undefined)}
 */
SugarCrm.ServerInfo.prototype.uptime;

/**
 * @constructor
 */
SugarCrm.About = function() {};

/**
 * @type {(string|undefined)}
 */
SugarCrm.About.prototype.baseUrl;

/**
 * @type {string}
 */
SugarCrm.About.prototype.domain;

/**
 * @type {(string|undefined)}
 */
SugarCrm.About.prototype.userName;

/**
 * @type {(boolean|undefined)}
 */
SugarCrm.About.prototype.hostPermission;

/**
 * @type {(string|undefined)} authentication provider.
 */
SugarCrm.About.prototype.provider;

/**
 * @type {(boolean|undefined)}
 */
SugarCrm.About.prototype.isLogin;

/**
 * @constructor
 * @extends {SugarCrm.About}
 */
CrmApp.Credential = function() {};

/**
 * @type {string}
 */
CrmApp.Credential.prototype.password;

/**
 * @type {string|undefined}
 */
CrmApp.Credential.prototype.provider;

/**
 * @type {boolean|undefined}
 */
CrmApp.Credential.prototype.hashed;

/**
 * @constructor
 */
SugarCrm.Details = function() {};

/**
 * @type {SugarCrm.About}
 */
SugarCrm.Details.prototype.about = null;

/**
 * @type {SugarCrm.ServerInfo}
 */
SugarCrm.Details.prototype.serverInfo = null;

/**
 * @type {?SugarCrm.LoginRecord}
 */
SugarCrm.Details.prototype.loginInfo = null;

/**
 * @type {?CrmApp.Credential}
 */
SugarCrm.Details.prototype.credential = null;

/**
 * @type {Array.<SugarCrm.AvailableModule>}
 */
SugarCrm.Details.prototype.availableModules = [];

/**
 * @type {Array.<SugarCrm.ModuleInfo>}
 */
SugarCrm.Details.prototype.modulesInfo = [];

/**
 * Query result for GData contact to SugarCRM records.
 * @interface
 */
SugarCrm.ContactSimilarityResult = function() {};

/**
 * @type {string}
 */
SugarCrm.ContactSimilarityResult.prototype.module;

/**
 * @type {string}
 */
SugarCrm.ContactSimilarityResult.prototype.index;

/**
 * @type {string}
 */
SugarCrm.ContactSimilarityResult.prototype.key;

/**
 * @type {Array<SugarCrm.Record>}
 */
SugarCrm.ContactSimilarityResult.prototype.result;

/**
 * Module name and id pair in relationship result.
 * @constructor
 */
SugarCrm.ModuleNameIdPair = function() {};

/**
 * @type {string}
 */
SugarCrm.ModuleNameIdPair.prototype.module_name;

/**
 * @type {string}
 */
SugarCrm.ModuleNameIdPair.prototype.id;

/**
 * Record format for relationships cache.
 * @constructor
 */
SugarCrm.Relationships = function() {};

/**
 * @type {number}
 */
SugarCrm.Relationships.prototype.modified;

/**
 * @type {SugarCrm.ModuleNameIdPair}
 */
SugarCrm.Relationships.prototype.to;

/**
 * @type {SugarCrm.ModuleNameIdPair}
 */
SugarCrm.Relationships.prototype.from;

/**
 * Represents SugarCRM entry.
 * @constructor
 */
SugarCrm.SyncCheckpoint = function() {};

/**
 * Lower value of updated timestamp.
 * @type {string}
 */
SugarCrm.SyncCheckpoint.prototype.lower = '';

/**
 * Upper value of updated timestamp.
 * @type {string}
 */
SugarCrm.SyncCheckpoint.prototype.upper = '';

/**
 * Updated timestamp.
 * @type {number}
 */
SugarCrm.SyncCheckpoint.prototype.updated = 0;
<|endoftext|>


<commit_before>// ==UserScript==
// @name        pixivblocker
// @namespace   commies.pixivblocker
// @description nuke shit
// @include     /http://.*pixiv\.net/.*/
// @include     /https?://.*pixiv\.net/.*/
// @version     1.1.6
// @grant       none
// ==/UserScript==
function PB_CFG_CREATE() {
    return {
        'settings' : {
            'shitusers': [],
            'weaddedshitusers': false
        },
        getArray: function (myvar)
        {
            if ((localStorage.getItem(myvar) === null) || (localStorage.getItem(myvar) === ''))
            {
                console.log(myvar);
                return this.settings[myvar];
            }
            else
            {
                return localStorage.getItem(myvar).split(',');
            }
        },
        setArray: function (usersetting, settingvar)
        {
            try {
                return localStorage.setItem(usersetting, settingvar.toString());
            } catch (e) {
                console.log('Error: ' + e);
            }
        },
        nukeSetting: function(settvar){
            try {
                if(confirm('Really unblock all users??')){
                    localStorage.removeItem(settvar);
                }
            } catch (e) {
                console.log('Error: ' + e);
            }
        },
        exportSetting: function (settvar){
            alert("Copy the following:\r\n\r\n" + localStorage.getItem(settvar));
        },
        importSetting: function (settvar){
            try {
                var wef = prompt("Paste your blocked users separated by comma:");
                if(wef){
                   localStorage.setItem(settvar, wef);
                }
            } catch (e) {
                console.log('Error: ' + e);
            }
        },
        arrayContains: function (needle, arrhaystack)
        {
            return (arrhaystack.indexOf(needle) > - 1);
        },
        listManage: function(thelist, theuser){
            var realshitlist = this.getArray(thelist);
            if (!theuser) {
                theuser = prompt("Enter Username Here", "Type here");
            }
            var willyou = false;

            //check if user is already in the list
            for (var x=0; x<realshitlist.length; x++) {
                var thisblistitem = realshitlist[x];
                if ( theuser === thisblistitem ) {
                    willyou = confirm('Are you sure you want to unblock this user?');
                    if (willyou){
                        realshitlist.splice(x,1);
                        this.setArray(thelist, realshitlist );
                    }
                    return false;
                }
            }

            //user wasn't in list
            willyou = confirm('Add to Filterlist?');
            if (willyou){
                realshitlist[realshitlist.length] = theuser;
                this.setArray(thelist, realshitlist );

                return true;
            }
            return false;
        },
        nukeThumbs: function(username){
            var allElements = document.getElementsByClassName('image-item');
            for (var i = 0, n = allElements.length; i < n; i++)
            {
                console.log(allElements[i].childNodes);
                if (this.sescape(allElements[i].childNodes[2].attributes['data-user_name'].value) === username)
                {
                    // Element exists with attribute. Add to array.
                    allElements[i].parentNode.removeChild(allElements[i--]);
                }
            }
        },
        sescape: function(v){
            return v.replace(/&/, "&").replace(/'/g, "'").replace(/"/g, """);
        },
        addShitUserList: function(){
            if(!this.settings['weaddedshitusers']){
                alert('Loading the list of shit users. This may take a while if you have a ton!\r\nKeep hovering over that area to show them after it\'s done.');
                var shitusers = PB_CFG.getArray('shitusers');
                var ourdiv = document.getElementsByClassName('pixivblocker_shitdiv')[0];
                var coollist = document.createElement('ul');
                coollist.className = "pixivblocker_shitusers";

                for(var v = 0; v < shitusers.length; v++){
                    var coolitem = document.createElement('li');

                    coolspan = document.createElement('span');
                    coolspan.className = "pixivblocker_minus";
                    coolspan.setAttribute("onclick", "PB_CFG.listManage('shitusers','"+shitusers[v]+"');");
                    coolspan.innerHTML = "❤";
                    coolspan.title = "Remove from pixivblocker";

                    coolitem.innerHTML = shitusers[v] + " " + coolspan.outerHTML;
                    coollist.innerHTML = coolitem.outerHTML + "\r\n" + coollist.innerHTML;
                }

                ourdiv.appendChild(coollist);
            }
            this.settings['weaddedshitusers'] = true;
        },
        init: function ()
        {
            var shitusers = PB_CFG.getArray('shitusers');
            console.log("[PixivBlocker] Currently blocking " + shitusers.length + " shit users.");
            var testElements = document.getElementsByClassName('image-item');
            var testDivs = Array.prototype.filter.call(testElements, function (testElement) {
                return testElement.nodeName === 'LI';
            });
            var coolspan;
            //go through list of thumbnails and add stuff to them
            for (var v = 0, u = null; v < testElements.length; v++, u = null) {
                if(testElements.item(v).childNodes[2].attributes['data-user_name'].value !== 'undefined'){
                    u = testElements.item(v).childNodes[2].attributes['data-user_name'].value;
                    u = this.sescape(u);

                    //add +/- next to names
                    coolspan = document.createElement('span');

                    //if shit users
                    if (PB_CFG.arrayContains(u, shitusers)) {
                        testElements.item(v).parentNode.removeChild(testElements.item(v));
                        v--;
                        //testElements.item(v).childNodes[0].innerHTML = 'This user is shit
';

                        /*coolspan.className = "pixivblocker_minus";
                        coolspan.setAttribute("onclick", "PB_CFG.listManage('shitusers','"+u+"');");
                        coolspan.innerHTML = "❤";
                        coolspan.title = "Remove from pixivblocker";*/
                    }
                    else{
                        coolspan.className = "pixivblocker_plus";
                        coolspan.setAttribute("onclick", "if(PB_CFG.listManage('shitusers','"+u+"')) PB_CFG.nukeThumbs('"+u+"');");
                        coolspan.innerHTML = "🚫";
                        coolspan.title = "Add user to pixivblocker";
                        testElements.item(v).insertBefore(coolspan, testElements.item(v).childNodes[2].nextSibling);
                    }
               }
            }

            //add list of shitusers at bottom of page
            var cooldiv = document.createElement('div');
            cooldiv.className = "pixivblocker_shitdiv";
            cooldiv.id = "pixivblocker_shitdiv";

            var coolheader = document.createElement('h3');
            coolheader.innerHTML = "Shit users you've blocked: (click/hover me)";
            coolheader.setAttribute("onclick", "PB_CFG.addShitUserList();");
            cooldiv.innerHTML += coolheader.outerHTML;

            var coolbutton = document.createElement('button');
            coolbutton.type = "button";
            coolbutton.innerHTML += "!! Unblock all users !!";
            coolbutton.setAttribute("onclick", "PB_CFG.nukeSetting('shitusers');");
            cooldiv.innerHTML += coolbutton.outerHTML;

            coolbutton = document.createElement('button');
            coolbutton.type = "button";
            coolbutton.innerHTML += "EXPORT";
            coolbutton.setAttribute("onclick", "PB_CFG.exportSetting('shitusers');");
            cooldiv.innerHTML += coolbutton.outerHTML;

            coolbutton = document.createElement('button');
            coolbutton.type = "button";
            coolbutton.innerHTML += "IMPORT";
            coolbutton.setAttribute("onclick", "PB_CFG.importSetting('shitusers');");
            cooldiv.innerHTML += coolbutton.outerHTML;

            var targetcontainer = document.getElementsByClassName('layout-body')[0];
            var num = 0;
            if(!targetcontainer) {
               targetcontainer = document.getElementsByClassName('contents-main')[0];
               num = 2;
            }
            targetcontainer.childNodes[num].appendChild(cooldiv);
        }
    };
}

function populateCSS(){
    var ourcss = "";

    ourcss += ".image-item { height:auto !important; }"; //fixes heights being cut off
    ourcss += ".popular-introduction { position:relative !important; top: 0px !important; left: 0px !important; }"; //fixes popular thing being in the way terribly
    ourcss += ".pixivblocker_minus { padding:0px 4px; background: #77FF88; color:#FFF; cursor:pointer;}";
    ourcss += ".pixivblocker_plus { padding:0px 4px; background: #FF7788; color:#FFF; cursor:pointer; margin-left:5px;}";
    ourcss += ".pixivblocker_shitdiv {width:95%; margin:auto; margin-bottom: 15px; border-bottom: 2px dashed rgba(0,0,0,.2);}";
    ourcss += ".pixivblocker_shitdiv ul {max-height: 0; transition: max-height 1s ease-out .4s; overflow: hidden; list-style: none; display:block;}";
    ourcss += ".pixivblocker_shitdiv:hover ul {max-height:9999px; transition: max-height 1s ease-in .4s;}";
    ourcss += ".pixivblocker_shitdiv h3 { font-weight: bolder; font-size: 110%; margin-bottom: 5px;}";
    ourcss += ".pixivblocker_shitdiv h3 small { font-size: 70%;}";
    ourcss += ".pixivblocker_shitdiv ul li { padding-left:3px; display:inline-block; background: rgba(0,0,0,.1); margin:5px;}";
    //ourcss += ".pixivblocker_shitusers li:after { content: ', '}";
    //ourcss += ".pixivblocker_shitusers li:last-child:after {content: ''; }";

    //now we actually add our CSS to the page
    if (document.getElementById("PB_CSS") !== null){
        document.getElementById("PB_CSS").innerHTML = ourcss;
    } else {
        var head = document.getElementsByTagName('head')[0];
        if (!head) { return; }
        var style = document.createElement('style');
        style.type = 'text/css';
        style.id = "PB_CSS";
        style.innerHTML = ourcss;
        head.appendChild(style);
    }
}

function addJS (str){
    if (document.getElementById("pixivblockerscript") !== null)
    {
        document.getElementById("pixivblockerscript").innerHTML = str;
    }
    else
    {
        var head = document.getElementsByTagName('head')[0];
        if (!head) { return; }
        var style = document.createElement('script');
        style.id = "pixivblockerscript";
        style.innerHTML = str;
        head.appendChild(style);
    }
}

var cooljs = ''+
PB_CFG_CREATE.toString()+
'var PB_CFG = new PB_CFG_CREATE();'+
'PB_CFG.init();';

    addJS(cooljs);
    populateCSS();
<commit_msg>Update pixivblocker.user.js<commit_after>// ==UserScript==
// @name        pixivblocker
// @namespace   commies.pixivblocker
// @description nuke shit
// @include     /http://.*pixiv\.net/.*/
// @include     /https?://.*pixiv\.net/.*/
// @version     1.2.0
// @grant       none
// ==/UserScript==
function PB_CFG_CREATE() {
    return {
        'settings' : {
            'shitusers': [],
            'weaddedshitusers': false
        },
        getArray: function (myvar)
        {
            if ((localStorage.getItem(myvar) === null) || (localStorage.getItem(myvar) === ''))
            {
                console.log(myvar);
                return this.settings[myvar];
            }
            else
            {
                return localStorage.getItem(myvar).split(',');
            }
        },
        setArray: function (usersetting, settingvar)
        {
            try {
                return localStorage.setItem(usersetting, settingvar.toString());
            } catch (e) {
                console.log('Error: ' + e);
            }
        },
        nukeSetting: function(settvar){
            try {
                if(confirm('Really unblock all users??')){
                    localStorage.removeItem(settvar);
                }
            } catch (e) {
                console.log('Error: ' + e);
            }
        },
        exportSetting: function (settvar){
            alert("Copy the following:\r\n\r\n" + localStorage.getItem(settvar));
        },
        importSetting: function (settvar){
            try {
                var wef = prompt("Paste your blocked users separated by comma:");
                if(wef){
                   localStorage.setItem(settvar, wef);
                }
            } catch (e) {
                console.log('Error: ' + e);
            }
        },
        arrayContains: function (needle, arrhaystack)
        {
            return (arrhaystack.indexOf(needle) > - 1);
        },
        listManage: function(thelist, theuser){
            var realshitlist = this.getArray(thelist);
            if (!theuser) {
                theuser = prompt("Enter Username Here", "Type here");
            }
            var willyou = false;

            //check if user is already in the list
            for (var x=0; x<realshitlist.length; x++) {
                var thisblistitem = realshitlist[x];
                if ( theuser === thisblistitem ) {
                    willyou = confirm('Are you sure you want to unblock this user?');
                    if (willyou){
                        realshitlist.splice(x,1);
                        this.setArray(thelist, realshitlist );
                    }
                    return false;
                }
            }

            //user wasn't in list
            willyou = confirm('Add to Filterlist?');
            if (willyou){
                realshitlist[realshitlist.length] = theuser;
                this.setArray(thelist, realshitlist );

                return true;
            }
            return false;
        },
        nukeThumbs: function(username){
            var allElements = document.getElementsByClassName('image-item');
            for (var i = 0, n = allElements.length; i < n; i++)
            {
                console.log(allElements[i].childNodes);
                if (this.sescape(allElements[i].childNodes[2].attributes['data-user_name'].value) === username)
                {
                    // Element exists with attribute. Add to array.
                    allElements[i].parentNode.removeChild(allElements[i--]);
                }
            }
        },
        findAnimationURL: function(){
            var ourshit = $("#wrapper script").html();
            var ourlocation = ourshit.indexOf("pixiv.context.ugokuIllustFullscreenData");
            if(ourlocation !== -1){

               //basically jump to fullscreen data
               // then find the first open bracket
               // then trim off everything after the semicolon
               // then parse as json
               ourshit = ourshit.substr(ourlocation);
               ourshit = ourshit.substr(ourshit.indexOf("{"));
               ourshit = ourshit.substr(0, ourshit.indexOf(";"));
               return JSON.parse(ourshit).src;
            }
            return false;
        },
        sescape: function(v){
            return v.replace(/&/, "&").replace(/'/g, "'").replace(/"/g, """);
        },
        addShitUserList: function(){
            if(!this.settings['weaddedshitusers']){
                alert('Loading the list of shit users. This may take a while if you have a ton!\r\nKeep hovering over that area to show them after it\'s done.');
                var shitusers = PB_CFG.getArray('shitusers');
                var ourdiv = document.getElementsByClassName('pixivblocker_shitdiv')[0];
                var coollist = document.createElement('ul');
                coollist.className = "pixivblocker_shitusers";

                for(var v = 0; v < shitusers.length; v++){
                    var coolitem = document.createElement('li');

                    coolspan = document.createElement('span');
                    coolspan.className = "pixivblocker_minus";
                    coolspan.setAttribute("onclick", "PB_CFG.listManage('shitusers','"+shitusers[v]+"');");
                    coolspan.innerHTML = "❤";
                    coolspan.title = "Remove from pixivblocker";

                    coolitem.innerHTML = shitusers[v] + " " + coolspan.outerHTML;
                    coollist.innerHTML = coolitem.outerHTML + "\r\n" + coollist.innerHTML;
                }

                ourdiv.appendChild(coollist);
            }
            this.settings['weaddedshitusers'] = true;
        },
        init: function ()
        {
            var shitusers = PB_CFG.getArray('shitusers');
            console.log("[PixivBlocker] Currently blocking " + shitusers.length + " shit users.");
            var testElements = document.getElementsByClassName('image-item');
            var testDivs = Array.prototype.filter.call(testElements, function (testElement) {
                return testElement.nodeName === 'LI';
            });
            var coolspan;
            //go through list of thumbnails and add stuff to them
            for (var v = 0, u = null; v < testElements.length; v++, u = null) {
                if(testElements.item(v).childNodes[2].attributes['data-user_name'].value !== 'undefined'){
                    u = testElements.item(v).childNodes[2].attributes['data-user_name'].value;
                    u = this.sescape(u);

                    //add +/- next to names
                    coolspan = document.createElement('span');

                    //if shit users
                    if (PB_CFG.arrayContains(u, shitusers)) {
                        testElements.item(v).parentNode.removeChild(testElements.item(v));
                        v--;
                        //testElements.item(v).childNodes[0].innerHTML = 'This user is shit
';

                        /*coolspan.className = "pixivblocker_minus";
                        coolspan.setAttribute("onclick", "PB_CFG.listManage('shitusers','"+u+"');");
                        coolspan.innerHTML = "❤";
                        coolspan.title = "Remove from pixivblocker";*/
                    }
                    else{
                        coolspan.className = "pixivblocker_plus";
                        coolspan.setAttribute("onclick", "if(PB_CFG.listManage('shitusers','"+u+"')) PB_CFG.nukeThumbs('"+u+"');");
                        coolspan.innerHTML = "🚫";
                        coolspan.title = "Add user to pixivblocker";
                        testElements.item(v).insertBefore(coolspan, testElements.item(v).childNodes[2].nextSibling);
                    }
               }
            }

            //add list of shitusers at bottom of page
            var cooldiv = document.createElement('div');
            cooldiv.className = "pixivblocker_shitdiv";
            cooldiv.id = "pixivblocker_shitdiv";

            var coolheader = document.createElement('h3');
            coolheader.innerHTML = "Shit users you've blocked: (click/hover me)";
            coolheader.setAttribute("onclick", "PB_CFG.addShitUserList();");
            cooldiv.innerHTML += coolheader.outerHTML;

            var coolbutton = document.createElement('button');
            coolbutton.type = "button";
            coolbutton.innerHTML += "!! Unblock all users !!";
            coolbutton.setAttribute("onclick", "PB_CFG.nukeSetting('shitusers');");
            cooldiv.innerHTML += coolbutton.outerHTML;

            coolbutton = document.createElement('button');
            coolbutton.type = "button";
            coolbutton.innerHTML += "EXPORT";
            coolbutton.setAttribute("onclick", "PB_CFG.exportSetting('shitusers');");
            cooldiv.innerHTML += coolbutton.outerHTML;

            coolbutton = document.createElement('button');
            coolbutton.type = "button";
            coolbutton.innerHTML += "IMPORT";
            coolbutton.setAttribute("onclick", "PB_CFG.importSetting('shitusers');");
            cooldiv.innerHTML += coolbutton.outerHTML;

            //animation shit
            var animcontain = $("._ugoku-illust-player-container");

            if(animcontain !== undefined){
               var coolbutton = document.createElement('a');
               coolbutton.setAttribute("href", this.findAnimationURL());
               coolbutton.setAttribute("class", "_button");
               coolbutton.innerHTML += "Download Animation As .ZIP";
               $("._work-detail-unit .action").first().prepend(coolbutton);
            }

            var targetcontainer = document.getElementsByClassName('layout-body')[0];
            var num = 0;
            if(!targetcontainer) {
               targetcontainer = document.getElementsByClassName('contents-main')[0];
               num = 2;
            }
            targetcontainer.childNodes[num].appendChild(cooldiv);
        }
    };
}

function populateCSS(){
    var ourcss = "";

    ourcss += ".image-item { height:auto !important; }"; //fixes heights being cut off
    ourcss += ".popular-introduction { position:relative !important; top: 0px !important; left: 0px !important; }"; //fixes popular thing being in the way terribly
    ourcss += ".pixivblocker_minus { padding:0px 4px; background: #77FF88; color:#FFF; cursor:pointer;}";
    ourcss += ".pixivblocker_plus { padding:0px 4px; background: #FF7788; color:#FFF; cursor:pointer; margin-left:5px;}";
    ourcss += ".pixivblocker_shitdiv {width:95%; margin:auto; margin-bottom: 15px; border-bottom: 2px dashed rgba(0,0,0,.2);}";
    ourcss += ".pixivblocker_shitdiv ul {max-height: 0; transition: max-height 1s ease-out .4s; overflow: hidden; list-style: none; display:block;}";
    ourcss += ".pixivblocker_shitdiv:hover ul {max-height:9999px; transition: max-height 1s ease-in .4s;}";
    ourcss += ".pixivblocker_shitdiv h3 { font-weight: bolder; font-size: 110%; margin-bottom: 5px;}";
    ourcss += ".pixivblocker_shitdiv h3 small { font-size: 70%;}";
    ourcss += ".pixivblocker_shitdiv ul li { padding-left:3px; display:inline-block; background: rgba(0,0,0,.1); margin:5px;}";
    //ourcss += ".pixivblocker_shitusers li:after { content: ', '}";
    //ourcss += ".pixivblocker_shitusers li:last-child:after {content: ''; }";

    //now we actually add our CSS to the page
    if (document.getElementById("PB_CSS") !== null){
        document.getElementById("PB_CSS").innerHTML = ourcss;
    } else {
        var head = document.getElementsByTagName('head')[0];
        if (!head) { return; }
        var style = document.createElement('style');
        style.type = 'text/css';
        style.id = "PB_CSS";
        style.innerHTML = ourcss;
        head.appendChild(style);
    }
}

function addJS (str){
    if (document.getElementById("pixivblockerscript") !== null)
    {
        document.getElementById("pixivblockerscript").innerHTML = str;
    }
    else
    {
        var head = document.getElementsByTagName('head')[0];
        if (!head) { return; }
        var style = document.createElement('script');
        style.id = "pixivblockerscript";
        style.innerHTML = str;
        head.appendChild(style);
    }
}

var cooljs = ''+
PB_CFG_CREATE.toString()+
'var PB_CFG = new PB_CFG_CREATE();'+
'PB_CFG.init();';

    addJS(cooljs);
    populateCSS();
<|endoftext|>


<commit_before>import _ from 'lodash';
import { parse as parsePlatform } from 'platform';
import { makeElementScreenshot, makeDocumentScreenshot, makeViewportScreenshot } from 'wdio-screenshot';

import getUserAgent from './scripts/getUserAgent';
import { mapViewports, mapOrientations } from './modules/mapViewports';

export default class VisualRegressionLauncher {

  /**
   * Gets executed once before all workers get launched.
   * @param {Object} config wdio configuration object
   * @param {Array.<Object>} capabilities list of capabilities details
   */
  async onPrepare(config) {
    this.validateConfig(config);
    this.compare = config.visualRegression.compare;
    await this.runHook('onPrepare');
  }

  /**
   * Gets executed before test execution begins. At this point you can access
   * all global variables, such as `browser`.
   * It is the perfect place to define custom commands.
   * @param  {object} capabilities desiredCapabilities
   * @param  {[type]} specs        [description]
   * @return {Promise}
   */
  async before(capabilities, specs) {
    this.validateConfig(browser.options);

    this.compare = browser.options.visualRegression.compare;
    this.viewportChangePause = _.get(browser.options, 'visualRegression.viewportChangePause', 100);
    this.viewports = _.get(browser.options, 'visualRegression.viewports');
    this.orientations = _.get(browser.options, 'visualRegression.orientations');
    const userAgent = (await browser.execute(getUserAgent)).value;
    const { name, version, ua } = parsePlatform(userAgent);

    this.context = {
      browser: {
        name,
        version,
        userAgent: ua
      },
      desiredCapabilities: capabilities,
      specs: specs
    };

    browser.addCommand('checkElement', this.wrapCommand(browser, 'element', makeElementScreenshot));
    browser.addCommand('checkDocument', this.wrapCommand(browser, 'document', makeDocumentScreenshot));
    browser.addCommand('checkViewport', this.wrapCommand(browser, 'viewport', makeViewportScreenshot));

    await this.runHook('before', this.context);
  }

  /**
   * Function to be executed before a test (in Mocha/Jasmine) or a
   * step (in Cucumber) starts.
   * @param  {[type]} test [description]
   * @return {Promise}
   */
  async beforeTest(test) {
    this.currentTest = test;
  }

  /**
   * Gets executed after all tests are done. You still have access to all global
   * variables from the test.
   * @param  {object} capabilities desiredCapabilities
   * @param  {[type]} specs        [description]
   * @return {Promise}
   */
  async after(capabilities, specs) {
    await this.runHook('after', capabilities, specs);
  }

  /**
   * Gets executed after all workers got shut down and the process is about to exit.
   * @param {Object} exitCode 0 - success, 1 - fail
   * @param {Object} config wdio configuration object
   * @param {Array.<Object>} capabilities list of capabilities details
   */
  async onComplete(exitCode, config, capabilities) {
    await this.runHook('onComplete');
  }

  async runHook(hookName, ...args) {
    if (typeof this.compare[hookName] === 'function') {
      return await this.compare[hookName](...args)
    }
  }

  validateConfig(config) {
    if(!_.isPlainObject(config.visualRegression) || !_.has(config.visualRegression, 'compare')) {
      throw new Error('Please provide a visualRegression configuration with a compare method in your wdio-conf.js!');
    }
  }

  wrapCommand(browser, type, command) {
    const baseContext = {
      type,
      browser: this.context.browser,
      desiredCapabilities: this.context.desiredCapabilities,
    };

    const runHook = this.runHook.bind(this);

    const getTest = () => {
      return _.pick(this.currentTest, ['title', 'parent', 'file']);
    };

    const resolutionKeySingle = browser.isMobile ? 'orientation' : 'viewport';
    const resolutionKeyPlural = browser.isMobile ? 'orientations' : 'viewports';
    const resolutionMap = browser.isMobile ? mapOrientations : mapViewports;

    const viewportChangePauseDefault = this.viewportChangePause;
    const resolutionDefault = browser.isMobile ? this.orientations : this.viewports;

    return async function async(...args) {
      const url = await browser.getUrl();

      const elementSelector = type === 'element' ? args[0] : undefined;
      const options = _.isPlainObject(args[args.length - 1]) ? args[args.length - 1] : {};

      const {
        exclude,
        hide,
        remove,
      } = options;

      const resolutions = _.get(options, resolutionKeyPlural, resolutionDefault);
      const viewportChangePause = _.get(options, 'viewportChangePause', viewportChangePauseDefault);

      const results = await resolutionMap(browser, viewportChangePause, resolutions, async function(resolution) {
        const meta = _.pickBy({
          url,
          element: elementSelector,
          exclude,
          hide,
          remove,
          [resolutionKeySingle]: resolution
        }, _.identity);

        const screenshotContext = {
          ...baseContext,
          test: getTest(),
          meta,
          options
        };

        const screenshotContextCleaned = _.pickBy(screenshotContext, _.identity);

        await runHook('beforeScreenshot', screenshotContextCleaned);

        const base64Screenshot = await command(browser, ...args);

        return await runHook('afterScreenshot', screenshotContextCleaned, base64Screenshot);
      });

      return results;

    }
  }

}
<commit_msg>Provide all test information in context object. (#47)<commit_after>import _ from 'lodash';
import { parse as parsePlatform } from 'platform';
import { makeElementScreenshot, makeDocumentScreenshot, makeViewportScreenshot } from 'wdio-screenshot';

import getUserAgent from './scripts/getUserAgent';
import { mapViewports, mapOrientations } from './modules/mapViewports';

export default class VisualRegressionLauncher {

  /**
   * Gets executed once before all workers get launched.
   * @param {Object} config wdio configuration object
   * @param {Array.<Object>} capabilities list of capabilities details
   */
  async onPrepare(config) {
    this.validateConfig(config);
    this.compare = config.visualRegression.compare;
    await this.runHook('onPrepare');
  }

  /**
   * Gets executed before test execution begins. At this point you can access
   * all global variables, such as `browser`.
   * It is the perfect place to define custom commands.
   * @param  {object} capabilities desiredCapabilities
   * @param  {[type]} specs        [description]
   * @return {Promise}
   */
  async before(capabilities, specs) {
    this.validateConfig(browser.options);

    this.compare = browser.options.visualRegression.compare;
    this.viewportChangePause = _.get(browser.options, 'visualRegression.viewportChangePause', 100);
    this.viewports = _.get(browser.options, 'visualRegression.viewports');
    this.orientations = _.get(browser.options, 'visualRegression.orientations');
    const userAgent = (await browser.execute(getUserAgent)).value;
    const { name, version, ua } = parsePlatform(userAgent);

    this.context = {
      browser: {
        name,
        version,
        userAgent: ua
      },
      desiredCapabilities: capabilities,
      specs: specs
    };

    browser.addCommand('checkElement', this.wrapCommand(browser, 'element', makeElementScreenshot));
    browser.addCommand('checkDocument', this.wrapCommand(browser, 'document', makeDocumentScreenshot));
    browser.addCommand('checkViewport', this.wrapCommand(browser, 'viewport', makeViewportScreenshot));

    await this.runHook('before', this.context);
  }

  /**
   * Function to be executed before a test (in Mocha/Jasmine) or a
   * step (in Cucumber) starts.
   * @param  {[type]} test [description]
   * @return {Promise}
   */
  async beforeTest(test) {
    this.currentTest = test;
  }

  /**
   * Gets executed after all tests are done. You still have access to all global
   * variables from the test.
   * @param  {object} capabilities desiredCapabilities
   * @param  {[type]} specs        [description]
   * @return {Promise}
   */
  async after(capabilities, specs) {
    await this.runHook('after', capabilities, specs);
  }

  /**
   * Gets executed after all workers got shut down and the process is about to exit.
   * @param {Object} exitCode 0 - success, 1 - fail
   * @param {Object} config wdio configuration object
   * @param {Array.<Object>} capabilities list of capabilities details
   */
  async onComplete(exitCode, config, capabilities) {
    await this.runHook('onComplete');
  }

  async runHook(hookName, ...args) {
    if (typeof this.compare[hookName] === 'function') {
      return await this.compare[hookName](...args)
    }
  }

  validateConfig(config) {
    if(!_.isPlainObject(config.visualRegression) || !_.has(config.visualRegression, 'compare')) {
      throw new Error('Please provide a visualRegression configuration with a compare method in your wdio-conf.js!');
    }
  }

  wrapCommand(browser, type, command) {
    const baseContext = {
      type,
      browser: this.context.browser,
      desiredCapabilities: this.context.desiredCapabilities,
    };

    const runHook = this.runHook.bind(this);

    const getTest = () => this.currentTest;

    const resolutionKeySingle = browser.isMobile ? 'orientation' : 'viewport';
    const resolutionKeyPlural = browser.isMobile ? 'orientations' : 'viewports';
    const resolutionMap = browser.isMobile ? mapOrientations : mapViewports;

    const viewportChangePauseDefault = this.viewportChangePause;
    const resolutionDefault = browser.isMobile ? this.orientations : this.viewports;

    return async function async(...args) {
      const url = await browser.getUrl();

      const elementSelector = type === 'element' ? args[0] : undefined;
      const options = _.isPlainObject(args[args.length - 1]) ? args[args.length - 1] : {};

      const {
        exclude,
        hide,
        remove,
      } = options;

      const resolutions = _.get(options, resolutionKeyPlural, resolutionDefault);
      const viewportChangePause = _.get(options, 'viewportChangePause', viewportChangePauseDefault);

      const results = await resolutionMap(browser, viewportChangePause, resolutions, async function(resolution) {
        const meta = _.pickBy({
          url,
          element: elementSelector,
          exclude,
          hide,
          remove,
          [resolutionKeySingle]: resolution
        }, _.identity);

        const screenshotContext = {
          ...baseContext,
          test: getTest(),
          meta,
          options
        };

        const screenshotContextCleaned = _.pickBy(screenshotContext, _.identity);

        await runHook('beforeScreenshot', screenshotContextCleaned);

        const base64Screenshot = await command(browser, ...args);

        return await runHook('afterScreenshot', screenshotContextCleaned, base64Screenshot);
      });

      return results;

    }
  }

}
<|endoftext|>


<commit_before>'use strict';

const Format = require('util').format;

const EPOCH_OFFSET = 978307200;

const TYPE_ENERGY  = 'energy',
      TYPE_ROOM    = 'room',
      TYPE_WEATHER = 'weather';

var homebridge;
var Characteristic, Service;

module.exports = function(pHomebridge) {
    if (pHomebridge && !homebridge) {
        homebridge = pHomebridge;
        Characteristic = homebridge.hap.Characteristic;
        Service = homebridge.hap.Service;
    }

    var hexToBase64 = function(val) {
        return new Buffer((''+val).replace(/[^0-9A-F]/ig, ''), 'hex').toString('base64');
    }, base64ToHex = function(val) {
        if(!val) return val;
        return new Buffer(val, 'base64').toString('hex');
    }, swap16 = function (val) {
        return ((val & 0xFF) << 8)
            | ((val >>> 8) & 0xFF);
    }, swap32 = function (val) {
        return ((val & 0xFF) << 24)
           | ((val & 0xFF00) << 8)
           | ((val >>> 8) & 0xFF00)
           | ((val >>> 24) & 0xFF);
    }, hexToHPA = function(val) {
        return parseInt(swap16(val), 10);
    }, hPAtoHex = function(val) {
        return swap16(Math.round(val)).toString(16);
    }, numToHex = function(val, len) {
        var s = Number(val >>> 0).toString(16);
        if(s.length % 2 != 0) {
            s = '0' + s;
        }
        if(len) {
            return ('0000000000000' + s).slice(-1 * len);
        }
    return s;
}

    class S2R1Characteristic extends Characteristic {
        constructor() {
            super('S2R1', 'E863F116-079E-48FF-8F27-9C2605A29F52');
            this.setProps({
                format: Characteristic.Formats.DATA,
                perms: [
                    Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.HIDDEN
                ]
            });
        }
    }

    S2R1Characteristic.UUID = 'E863F116-079E-48FF-8F27-9C2605A29F52';

    class S2R2Characteristic extends Characteristic {
        constructor() {
            super('S2R2', 'E863F117-079E-48FF-8F27-9C2605A29F52');
            this.setProps({
                format: Characteristic.Formats.DATA,
                perms: [
                    Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.HIDDEN
                ]
            });
        }
    }

    S2R2Characteristic.UUID = 'E863F117-079E-48FF-8F27-9C2605A29F52';

    class S2W1Characteristic extends Characteristic {
        constructor() {
            super('S2W1', 'E863F11C-079E-48FF-8F27-9C2605A29F52');
            this.setProps({
                format: Characteristic.Formats.DATA,
                perms: [
                    Characteristic.Perms.WRITE, Characteristic.Perms.HIDDEN
                ]
            });
        }
    }

    S2W1Characteristic.UUID = 'E863F11C-079E-48FF-8F27-9C2605A29F52';

    class S2W2Characteristic extends Characteristic {
        constructor() {
            super('S2W2', 'E863F121-079E-48FF-8F27-9C2605A29F52');
            this.setProps({
                format: Characteristic.Formats.DATA,
                perms: [
                    Characteristic.Perms.WRITE, Characteristic.Perms.HIDDEN
                ]
            });
        }
    }

    S2W2Characteristic.UUID = 'E863F121-079E-48FF-8F27-9C2605A29F52';

    class FakeGatoHistoryService extends Service {
        constructor(accessoryType, accessory, size) {
            if (typeof size === 'undefined') { size = 4032; }

            super(accessory.displayName + " History", 'E863F007-079E-48FF-8F27-9C2605A29F52');

            var entry2address = function(val) {
                var temp = val % this.memorySize;
                return temp;
            }.bind(this);

            this.log = accessory.log;
            switch (accessoryType) {
                case TYPE_WEATHER:
                    this.accessoryType116 = "03";
                    this.accessoryType117 = "07";
                    break;
                case TYPE_ENERGY:
                    this.accessoryType116 = "07";
                    this.accessoryType117 = "1f";
                    break;
                case TYPE_ROOM:
                    this.accessoryType116 = "04";
                    this.accessoryType117 = "0f";
                    break;
            }

            this.accessoryType = accessoryType;
            this.firstEntry = 0;
            this.lastEntry = 0;
            this.history = [];
            this.memorySize = size;
            this.usedMemory = 0;
            this.currentEntry = 1;
            this.transfer = false;
            this.setTime = true;
            this.refTime = 0;
            this.memoryAddress = 0;
            this.dataStream = '';

            this.addCharacteristic(S2R1Characteristic);

            this.addCharacteristic(S2R2Characteristic)
                .on('get', (callback) => {
                    if ((this.currentEntry < this.lastEntry) && (this.transfer == true)) {
                        this.memoryAddress = entry2address(this.currentEntry);

                        if ((this.history[this.memoryAddress].temp == 0 &&
                            this.history[this.memoryAddress].pressure == 0 &&
                            this.history[this.memoryAddress].humidity == 0) || (this.history[this.memoryAddress].power == 0xFFFF) || (this.setTime == true)) {

                            var val = Format(
                                '15%s0000 0000 0000 81%s0000 0000 00 0000',
                                numToHex(swap16(this.currentEntry),4),
                                numToHex(swap32(this.refTime),8)
                            );

                            this.log.debug("Data %s: %s", this.accessoryType, val);
                            callback(null, hexToBase64(val));
                            this.setTime=false;
                            this.currentEntry++;
                        }
                        else {
                            for (var i = 0;i < 11;i++) {
                                switch (this.accessoryType) {
                                    case TYPE_WEATHER:
                                        this.log.debug("%s Entry: %s, Address: %s", this.accessoryType, this.currentEntry, this.memoryAddress);
                                        this.dataStream += Format(
                                            " 10 %s 0000 %s%s%s%s%s",
                                            numToHex(swap16(this.currentEntry), 4),
                                            numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8),
                                            this.accessoryType117,
                                            numToHex(swap16(this.history[this.memoryAddress].temp * 100), 4),
                                            numToHex(swap16(this.history[this.memoryAddress].humidity*100), 4),
                                            numToHex(swap16(this.history[this.memoryAddress].pressure*10), 4)
                                        );
                                        break;
                                    case TYPE_ENERGY:
                                        this.log.debug("%s Entry: %s, Address: %s", this.accessoryType, this.currentEntry, this.memoryAddress);
                                        this.dataStream += Format(
                                            " 14 %s 0000 %s%s0000 0000%s0000 0000",
                                            numToHex(swap16(this.currentEntry),4),
                                            numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8),
                                            this.accessoryType117,
                                            numToHex(swap16(this.history[this.memoryAddress].power * 10), 4)
                                        );
                                        break;
                                }
                                this.currentEntry++;
                                this.memoryAddress = entry2address(this.currentEntry);
                                if (this.currentEntry > this.lastEntry) {
                                    break;
                                }
                            }
                            this.log.debug("Data %s: %s", this.accessoryType, this.dataStream);
                            callback(null, hexToBase64(this.dataStream));
                            this.dataStream = '';
                        }
                    }
                    else {
                        this.transfer = false;
                        callback(null, hexToBase64('00'));
                    }
            });

            this.addCharacteristic(S2W1Characteristic)
                .on('set', this.setCurrentS2W1.bind(this));

            this.addCharacteristic(S2W2Characteristic)
                .on('set', this.setCurrentS2W2.bind(this));
        }

        sendHistory(address){
            var hexAddress= address.toString('16');
            if (address != 0) {
                this.currentEntry = address;
            }
            else {
                this.currentEntry = 1;
            }
            this.transfer=true;
        }

        //in order to be consistent with Eve, entry address start from 1
        addEntry(entry){

            var entry2address = function(val) {
                return val % this.memorySize;
            }.bind(this);

            if (this.usedMemory < this.memorySize) {
                this.usedMemory++;
                this.firstEntry = 0;
                this.lastEntry = this.usedMemory;
            }
            else {
                this.firstEntry++;
                this.lastEntry = this.firstEntry + this.usedMemory;
            }

            if (this.refTime == 0) {
                this.refTime = entry.time - EPOCH_OFFSET;
                switch (this.accessoryType)
                    {
                        case TYPE_WEATHER:
                            this.history[this.lastEntry]= {time: entry.time, temp: 0, pressure: 0, humidity: 0};
                            break;
                        case TYPE_ENERGY:
                            this.history[this.lastEntry]= {time: entry.time, power: 0xFFFF};
                            break;
                    }
                this.lastEntry++;
                this.usedMemory++;
            }

            this.history[entry2address(this.lastEntry)] = (entry);

            var val = Format(
                '%s00000000%s0401020202%s020f03%s%s%s000000000101',
                numToHex(swap32(entry.time - this.refTime - EPOCH_OFFSET), 8),
                numToHex(swap32(this.refTime), 8), this.accessoryType116,
                numToHex(swap16(this.usedMemory), 4),
                numToHex(swap16(this.memorySize), 4),
                numToHex(swap32(this.firstEntry), 8)
            );

            this.getCharacteristic(S2R1Characteristic).setValue(hexToBase64(val));

            this.log.debug("First entry %s: %s", this.accessoryType, this.firstEntry.toString(16));
            this.log.debug("Last entry %s: %s", this.accessoryType, this.lastEntry.toString(16));
            this.log.debug("Used memory %s: %s", this.accessoryType, this.usedMemory.toString(16));
            this.log.debug("116 %s: %s", this.accessoryType, val);
        }

        setCurrentS2W1(val, callback) {
            callback(null,val);
            this.log.debug("Data request %s: %s", this.accessoryType, base64ToHex(val));
            var valHex = base64ToHex(val);
            var substring = valHex.substring(4, 12);
            var valInt = parseInt(substring, 16);
            var address = swap32(valInt);
            var hexAddress= address.toString('16');

            this.log.debug("Address requested %s: %s", this.accessoryType, hexAddress);
            //if (this.transfer==false)
            //{
                //this.transfer=true;
                this.sendHistory(address);
            //}
        }

        setCurrentS2W2(val, callback) {
            this.log.debug("Clock adjust: %s", base64ToHex(val));
            callback(null, val);
        }

    }

    FakeGatoHistoryService.UUID = 'E863F007-079E-48FF-8F27-9C2605A29F52';

    return FakeGatoHistoryService;
}
<commit_msg>remove duplicate UUID strings<commit_after>'use strict';

const Format = require('util').format;

const EPOCH_OFFSET = 978307200;

const TYPE_ENERGY  = 'energy',
      TYPE_ROOM    = 'room',
      TYPE_WEATHER = 'weather';

var homebridge;
var Characteristic, Service;

module.exports = function(pHomebridge) {
    if (pHomebridge && !homebridge) {
        homebridge = pHomebridge;
        Characteristic = homebridge.hap.Characteristic;
        Service = homebridge.hap.Service;
    }

    var hexToBase64 = function(val) {
        return new Buffer((''+val).replace(/[^0-9A-F]/ig, ''), 'hex').toString('base64');
    }, base64ToHex = function(val) {
        if(!val) return val;
        return new Buffer(val, 'base64').toString('hex');
    }, swap16 = function (val) {
        return ((val & 0xFF) << 8)
            | ((val >>> 8) & 0xFF);
    }, swap32 = function (val) {
        return ((val & 0xFF) << 24)
           | ((val & 0xFF00) << 8)
           | ((val >>> 8) & 0xFF00)
           | ((val >>> 24) & 0xFF);
    }, hexToHPA = function(val) {
        return parseInt(swap16(val), 10);
    }, hPAtoHex = function(val) {
        return swap16(Math.round(val)).toString(16);
    }, numToHex = function(val, len) {
        var s = Number(val >>> 0).toString(16);
        if(s.length % 2 != 0) {
            s = '0' + s;
        }
        if(len) {
            return ('0000000000000' + s).slice(-1 * len);
        }
    return s;
}

    class S2R1Characteristic extends Characteristic {
        constructor() {
            super('S2R1', S2R1Characteristic.UUID);
            this.setProps({
                format: Characteristic.Formats.DATA,
                perms: [
                    Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.HIDDEN
                ]
            });
        }
    }

    S2R1Characteristic.UUID = 'E863F116-079E-48FF-8F27-9C2605A29F52';

    class S2R2Characteristic extends Characteristic {
        constructor() {
            super('S2R2', S2R2Characteristic.UUID);
            this.setProps({
                format: Characteristic.Formats.DATA,
                perms: [
                    Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.HIDDEN
                ]
            });
        }
    }

    S2R2Characteristic.UUID = 'E863F117-079E-48FF-8F27-9C2605A29F52';

    class S2W1Characteristic extends Characteristic {
        constructor() {
            super('S2W1', S2W1Characteristic.UUID);
            this.setProps({
                format: Characteristic.Formats.DATA,
                perms: [
                    Characteristic.Perms.WRITE, Characteristic.Perms.HIDDEN
                ]
            });
        }
    }

    S2W1Characteristic.UUID = 'E863F11C-079E-48FF-8F27-9C2605A29F52';

    class S2W2Characteristic extends Characteristic {
        constructor() {
            super('S2W2', S2W2Characteristic.UUID);
            this.setProps({
                format: Characteristic.Formats.DATA,
                perms: [
                    Characteristic.Perms.WRITE, Characteristic.Perms.HIDDEN
                ]
            });
        }
    }

    S2W2Characteristic.UUID = 'E863F121-079E-48FF-8F27-9C2605A29F52';

    class FakeGatoHistoryService extends Service {
        constructor(accessoryType, accessory, size) {
            if (typeof size === 'undefined') { size = 4032; }

            super(accessory.displayName + " History", FakeGatoHistoryService.UUID);

            var entry2address = function(val) {
                var temp = val % this.memorySize;
                return temp;
            }.bind(this);

            this.log = accessory.log;
            switch (accessoryType) {
                case TYPE_WEATHER:
                    this.accessoryType116 = "03";
                    this.accessoryType117 = "07";
                    break;
                case TYPE_ENERGY:
                    this.accessoryType116 = "07";
                    this.accessoryType117 = "1f";
                    break;
                case TYPE_ROOM:
                    this.accessoryType116 = "04";
                    this.accessoryType117 = "0f";
                    break;
            }

            this.accessoryType = accessoryType;
            this.firstEntry = 0;
            this.lastEntry = 0;
            this.history = [];
            this.memorySize = size;
            this.usedMemory = 0;
            this.currentEntry = 1;
            this.transfer = false;
            this.setTime = true;
            this.refTime = 0;
            this.memoryAddress = 0;
            this.dataStream = '';

            this.addCharacteristic(S2R1Characteristic);

            this.addCharacteristic(S2R2Characteristic)
                .on('get', (callback) => {
                    if ((this.currentEntry < this.lastEntry) && (this.transfer == true)) {
                        this.memoryAddress = entry2address(this.currentEntry);

                        if ((this.history[this.memoryAddress].temp == 0 &&
                            this.history[this.memoryAddress].pressure == 0 &&
                            this.history[this.memoryAddress].humidity == 0) || (this.history[this.memoryAddress].power == 0xFFFF) || (this.setTime == true)) {

                            var val = Format(
                                '15%s0000 0000 0000 81%s0000 0000 00 0000',
                                numToHex(swap16(this.currentEntry),4),
                                numToHex(swap32(this.refTime),8)
                            );

                            this.log.debug("Data %s: %s", this.accessoryType, val);
                            callback(null, hexToBase64(val));
                            this.setTime=false;
                            this.currentEntry++;
                        }
                        else {
                            for (var i = 0;i < 11;i++) {
                                switch (this.accessoryType) {
                                    case TYPE_WEATHER:
                                        this.log.debug("%s Entry: %s, Address: %s", this.accessoryType, this.currentEntry, this.memoryAddress);
                                        this.dataStream += Format(
                                            " 10 %s 0000 %s%s%s%s%s",
                                            numToHex(swap16(this.currentEntry), 4),
                                            numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8),
                                            this.accessoryType117,
                                            numToHex(swap16(this.history[this.memoryAddress].temp * 100), 4),
                                            numToHex(swap16(this.history[this.memoryAddress].humidity*100), 4),
                                            numToHex(swap16(this.history[this.memoryAddress].pressure*10), 4)
                                        );
                                        break;
                                    case TYPE_ENERGY:
                                        this.log.debug("%s Entry: %s, Address: %s", this.accessoryType, this.currentEntry, this.memoryAddress);
                                        this.dataStream += Format(
                                            " 14 %s 0000 %s%s0000 0000%s0000 0000",
                                            numToHex(swap16(this.currentEntry),4),
                                            numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8),
                                            this.accessoryType117,
                                            numToHex(swap16(this.history[this.memoryAddress].power * 10), 4)
                                        );
                                        break;
                                }
                                this.currentEntry++;
                                this.memoryAddress = entry2address(this.currentEntry);
                                if (this.currentEntry > this.lastEntry) {
                                    break;
                                }
                            }
                            this.log.debug("Data %s: %s", this.accessoryType, this.dataStream);
                            callback(null, hexToBase64(this.dataStream));
                            this.dataStream = '';
                        }
                    }
                    else {
                        this.transfer = false;
                        callback(null, hexToBase64('00'));
                    }
            });

            this.addCharacteristic(S2W1Characteristic)
                .on('set', this.setCurrentS2W1.bind(this));

            this.addCharacteristic(S2W2Characteristic)
                .on('set', this.setCurrentS2W2.bind(this));
        }

        sendHistory(address){
            var hexAddress= address.toString('16');
            if (address != 0) {
                this.currentEntry = address;
            }
            else {
                this.currentEntry = 1;
            }
            this.transfer=true;
        }

        //in order to be consistent with Eve, entry address start from 1
        addEntry(entry){

            var entry2address = function(val) {
                return val % this.memorySize;
            }.bind(this);

            if (this.usedMemory < this.memorySize) {
                this.usedMemory++;
                this.firstEntry = 0;
                this.lastEntry = this.usedMemory;
            }
            else {
                this.firstEntry++;
                this.lastEntry = this.firstEntry + this.usedMemory;
            }

            if (this.refTime == 0) {
                this.refTime = entry.time - EPOCH_OFFSET;
                switch (this.accessoryType)
                    {
                        case TYPE_WEATHER:
                            this.history[this.lastEntry]= {time: entry.time, temp: 0, pressure: 0, humidity: 0};
                            break;
                        case TYPE_ENERGY:
                            this.history[this.lastEntry]= {time: entry.time, power: 0xFFFF};
                            break;
                    }
                this.lastEntry++;
                this.usedMemory++;
            }

            this.history[entry2address(this.lastEntry)] = (entry);

            var val = Format(
                '%s00000000%s0401020202%s020f03%s%s%s000000000101',
                numToHex(swap32(entry.time - this.refTime - EPOCH_OFFSET), 8),
                numToHex(swap32(this.refTime), 8), this.accessoryType116,
                numToHex(swap16(this.usedMemory), 4),
                numToHex(swap16(this.memorySize), 4),
                numToHex(swap32(this.firstEntry), 8)
            );

            this.getCharacteristic(S2R1Characteristic).setValue(hexToBase64(val));

            this.log.debug("First entry %s: %s", this.accessoryType, this.firstEntry.toString(16));
            this.log.debug("Last entry %s: %s", this.accessoryType, this.lastEntry.toString(16));
            this.log.debug("Used memory %s: %s", this.accessoryType, this.usedMemory.toString(16));
            this.log.debug("116 %s: %s", this.accessoryType, val);
        }

        setCurrentS2W1(val, callback) {
            callback(null,val);
            this.log.debug("Data request %s: %s", this.accessoryType, base64ToHex(val));
            var valHex = base64ToHex(val);
            var substring = valHex.substring(4, 12);
            var valInt = parseInt(substring, 16);
            var address = swap32(valInt);
            var hexAddress= address.toString('16');

            this.log.debug("Address requested %s: %s", this.accessoryType, hexAddress);
            //if (this.transfer==false)
            //{
                //this.transfer=true;
                this.sendHistory(address);
            //}
        }

        setCurrentS2W2(val, callback) {
            this.log.debug("Clock adjust: %s", base64ToHex(val));
            callback(null, val);
        }

    }

    FakeGatoHistoryService.UUID = 'E863F007-079E-48FF-8F27-9C2605A29F52';

    return FakeGatoHistoryService;
}
<|endoftext|>


<commit_before>/*!
 * Backbone.js ajaxRetry
 * https://github.com/gdibble/backbone-ajaxretry
 * Copyright 2014 Gabriel Dibble; Licensed MIT
 */
(function (define) { define(function (require, exports, module) { 'use strict';

var _$ajax;
var Backbone = require('backbone');
var _        = require('underscore');
//Defaults that can be overridden via set
var settings = {
  base:         2.718281828,
  y:            0.25,
  retryCount:   3,
  onlyBackbone: false
};

//-----------------------------------------------------------------------------

// Helpers:
//  some console.logs have been left (as to be enabled) for those curious minds

//Update current settings, overriding defaults
function setOptions(options) {
  _.defaults(options, settings);
  settings = options;
}

//returns delay in milliseconds
function exponentialDelay(x) {
  return (Math.pow(settings.base, x) - settings.y) * 1000;
}

//hit retry limit
function exhausted() {
  var args = Array.prototype.slice.call(arguments, 0);
  _.extend(args[0], this);
  // console.log('exhausted', this.url);
  if (this.hasOwnProperty('exhaust')) {
    // console.log('>>> called this.exhaust', this.exhaust);
    this.exhaust.apply(this, args);
  }
}

//recurse the ajax request
function ajaxRetry(jqXHR) {
  var self = this;
  if (this.hasOwnProperty('retries')) {
    this.recursed = this.recursed === undefined ? 0 : this.recursed + 1;
    if ((jqXHR && jqXHR.status < 500) || this.recursed >= this.retries) {
      exhausted.apply(self, arguments);
    } else if (this.recursed < this.retries) {
      setTimeout(function () {
        $.ajax(self);
        // console.log('recursed', self.url, self.recursed, 'in ' + exponentialDelay(self.recursed) + 'ms');
      }, exponentialDelay(this.recursed));
    }
  } else {
    exhausted.apply(self, arguments);
  }
}

function extender(args, options) {
  _.extend(args[0], options ? options : {}, {
    retries: settings.retryCount,
    error:   function () { ajaxRetry.apply(this, arguments); }
  });
}

function sliceArguments() {
  return Array.prototype.slice.call(arguments, 0);
}

//-----------------------------------------------------------------------------

//extend for retry functionality:
if (!settings.onlyBackbone) {
  //retry regular $.ajax thus also Backbone ajax requests
  _$ajax = $.ajax;
  $.ajax = function (options) {
    var args = sliceArguments(arguments);
    extender(args, options);
    return _$ajax.apply($, args);
  };
} else {
  //retry only Backbone ajax requests422
  Backbone.ajax = function (options) {
    var args = sliceArguments(arguments);
    extender(args, options);
    return Backbone.$.ajax.apply(Backbone.$, args);
  };
}

module.exports = { set: setOptions };

}); }(typeof define == 'function' && define.amd ? define : function (factory) { factory(require, exports, module); })); //end UDM CommonJS wrapper
<commit_msg>closes #12: bug in extender fn<commit_after>/*!
 * Backbone.js ajaxRetry
 * https://github.com/gdibble/backbone-ajaxretry
 * Copyright 2014 Gabriel Dibble; Licensed MIT
 */
(function (define) { define(function (require, exports, module) { //'use strict';

var _$ajax;
var Backbone = require('backbone');
var _        = require('underscore');
//Defaults that can be overridden via set
var settings = {
  base:         2.718281828,
  y:            0.25,
  retryCount:   3,
  onlyBackbone: false
};

//-----------------------------------------------------------------------------

// Helpers:
//  some console.logs have been left (as to be enabled) for those curious minds

//Update current settings, overriding defaults
function setOptions(options) {
  _.defaults(options, settings);
  settings = options;
}

//returns delay in milliseconds
function exponentialDelay(x) {
  return (Math.pow(settings.base, x) - settings.y) * 1000;
}

//hit retry limit
function exhausted() {
  var args = Array.prototype.slice.call(arguments, 0);
  _.extend(args[0], this);
  // console.log('exhausted', this.url);
  if (this.hasOwnProperty('exhaust')) {
    // console.log('>>> called this.exhaust', this.exhaust);
    this.exhaust.apply(this, args);
  }
}

//recurse the ajax request
function ajaxRetry(jqXHR) {
  var self = this;
  if (this.hasOwnProperty('retries')) {
    this.recursed = this.recursed === undefined ? 0 : this.recursed + 1;
    if ((jqXHR && jqXHR.status < 500) || this.recursed >= this.retries) {
      exhausted.apply(self, arguments);
    } else if (this.recursed < this.retries) {
      setTimeout(function () {
        $.ajax(self);
        // console.log('recursed', self.url, self.recursed, 'in ' + exponentialDelay(self.recursed) + 'ms');
      }, exponentialDelay(this.recursed));
    }
  } else {
    exhausted.apply(self, arguments);
  }
}

function extender(args, options) {
  _.extend(args[0], options && typeof options === 'object' ? options : {}, {
    retries: settings.retryCount,
    error:   function () { ajaxRetry.apply(this, arguments); }
  });
}

function sliceArguments() {
  return Array.prototype.slice.call(arguments, 0);
}

//-----------------------------------------------------------------------------

//extend for retry functionality:
if (!settings.onlyBackbone) {
  //retry regular $.ajax thus also Backbone ajax requests
  _$ajax = $.ajax;
  $.ajax = function (options) {
    var args;
    if (typeof options === 'string') {
      arguments[1].url = options; //in this case, options is actually the url passed to $.get/$.post
      args = sliceArguments(arguments[1]);
      extender(args, options);
    } else {
      args = sliceArguments(arguments);
      extender(args, options);
    }
    return _$ajax.apply($, args);
  };
} else {
  //retry only Backbone ajax requests422
  Backbone.ajax = function (options) {
    var args = sliceArguments(arguments);
    extender(args, options);
    return Backbone.$.ajax.apply(Backbone.$, args);
  };
}

module.exports = { set: setOptions };

}); }(typeof define === 'function' && define.amd ? define : function (factory) { factory(require, exports, module); })); //end UMD CommonJS wrapper
<|endoftext|>


<commit_before>(function(factory) {

  'use strict';

  if (typeof define === 'function' && define.amd) {
    define(['backbone'], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require('backbone'));
  } else {
    factory(window.Backbone);
  }
})(function(Backbone) {

  'use strict';

  var loadUrl = Backbone.History.prototype.loadUrl;

  Backbone.History.prototype.loadUrl = function(fragmentOverride) {
    var matched = loadUrl.apply(this, arguments),
        gaFragment = this.fragment;

    if (!this.options.silent) {
      this.options.silent = true;
      return matched;
    }

    if (!/^\//.test(gaFragment)) {
      gaFragment = '/' + gaFragment;
    }

    // legacy version
    if (typeof window._gaq !== "undefined") {
      window._gaq.push(['_trackPageview', gaFragment]);
    }

    // Analytics.js
    var ga;
    if (window.GoogleAnalyticsObject && window.GoogleAnalyticsObject !== 'ga') {
      ga = window.GoogleAnalyticsObject;
    } else {
      ga = window.ga;
    }

    if (typeof ga !== 'undefined') {
      ga('send', 'pageview', gaFragment);
    }
    return matched;
  };

});
<commit_msg>Update pageview sending<commit_after>(function(factory) {

  'use strict';

  if (typeof define === 'function' && define.amd) {
    define(['backbone'], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require('backbone'));
  } else {
    factory(window.Backbone);
  }
})(function(Backbone) {

  'use strict';

  var loadUrl = Backbone.History.prototype.loadUrl;

  Backbone.History.prototype.loadUrl = function(fragmentOverride) {
    var matched = loadUrl.apply(this, arguments),
        gaFragment = this.fragment;

    if (!this.options.silent) {
      this.options.silent = true;
      return matched;
    }

    if (!/^\//.test(gaFragment)) {
      gaFragment = '/' + gaFragment;
    }

    // legacy version
    if (typeof window._gaq !== "undefined") {
      window._gaq.push(['_trackPageview', gaFragment]);
    }

    // Analytics.js
    var ga;
    if (window.GoogleAnalyticsObject && window.GoogleAnalyticsObject !== 'ga') {
      ga = window.GoogleAnalyticsObject;
    } else {
      ga = window.ga;
    }

    if (typeof ga !== 'undefined') {
      ga('set', page: gaFragment);
      ga('send', 'pageview');
    }
    return matched;
  };

});
<|endoftext|>


<commit_before>"use strict";

// Many of these are only referenced now inside a singe component, find out which ones, and remove them from here
// global vars
var base_layer_dict = null;
var raster_dict = {};
var overlay_dict = {};
var map = null;
var organization;

// list of layers which automatically become overlay rasters instead of regular rasters
var overlay_list = ['WINDVEC', 'WINDVEC1000FT', 'WINDVEC4000FT', 'WINDVEC6000FT', 'SMOKE1000FT', 'SMOKE4000FT', 'SMOKE6000FT', 'FIRE_AREA', 'SMOKE_INT', 'FGRNHFX', 'FLINEINT'];

// Variables containing input data
var rasters = null;
var sorted_timestamps = null;
var raster_base = null;

// Display context
var layer_ctrl = null;
var current_display = {}; // dictionary of layer name -> layer of currently displayed data
var current_timestamp = null; // currently displayed timestamp
var preloaded = {}; // dictionary containing information on what frames have been preloaded for which rasters/layers
var displayed_colorbar = null; // name of layer currently displaying its colorbar (maybe display multiple cbs?)
var displayed_colorbars = [];

function initialize_fdds() {

  //  initialize base layers & build map
  base_layer_dict = {
  /*
    'MapQuest': L.tileLayer('http://{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png', {
                            attribution: 'Data and imagery by MapQuest',
                            subdomains: ['otile1', 'otile2', 'otile3', 'otile4']}),
  */
    'MapQuest' : MQ.mapLayer(),
  /*	'MQ Satellite': L.tileLayer('http://{s}.mqcdn.com/tiles/1.0.0/sat/{z}/{x}/{y}.png', {
                                attribution: 'Data and imagery by MapQuest',
                                subdomains: ['otile1', 'otile2', 'otile3', 'otile4']}),*/
    'OSM': L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
                      attribution: '© OpenStreetMap contributors'})
  };

  // construct map with the base layers
  map = L.map('map-fd', {
    center: [37.34, -121.89],
    zoom: 7,
    layers: [base_layer_dict['OSM']],
    zoomControl: false,
    minZoom: 3
  });

  const layerController = document.querySelector('layer-controller');
  layerController.buildMapBase();

  loadConfig();

  // add scale & zoom controls to the map
  L.control.scale({ position: 'bottomright' }).addTo(map);
}

function loadConfig() {
  fetch('conf.json').then(response => response.json()).then(function(configData) {
    if (configData.organization) {
      organization = configData.organization;
      if (!organization.includes("SJSU")) {
          map.panTo([39.7392, -104.9903]);
      }
      document.title = organization;
    }

    if (configData.flags) {
      let flags = configData.flags;
      const simulationFlags = document.querySelector("#simulation-flags");
      flags.map(flag => {
          var spanElement = document.createElement("span");
          spanElement.className = "displayTest";
          spanElement.innerText = flag;
          simulationFlags.appendChild(spanElement);
      });
    }
  }).catch(error => {
    console.error(error);
  });
}

/** Makes given element draggable from sub element with id "subID" */
function dragElement(elmnt, subID) {
  var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  var elmntRight = 0;
  document.getElementById(elmnt.id + subID).onpointerdown = dragMouseDown;

  function dragMouseDown(e) {
    e = e || window.event;
    e.preventDefault();
    e.stopPropagation();
    // get the mouse cursor position at startup:
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onpointerup = closeDragElement;
    // call a function whenever the cursor moves:
    document.onpointermove = elementDrag;
  }

  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    e.stopPropagation();
    // calculate the new cursor position:
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    var windowWidth = document.body.clientWidth;
    var windowHeight = document.body.clientHeight;
    let calculatedRight = windowWidth - (getOffsetLeft(elmnt) + elmnt.clientWidth);
    if (Math.abs(elmntRight  - calculatedRight) > 40) {
      elmntRight = windowWidth - (elmnt.offsetLeft + elmnt.clientWidth);
    }
    // console.log(windowWidth + " " + elmntRight + " " + calculatedRight);
    let elmntBottom = windowHeight - (elmnt.offsetTop + elmnt.clientHeight);
    // set the element's new position:
    if (Math.abs(pos1) >= 1 && elmntRight + pos1 > 0 && elmnt.offsetLeft - pos1 > 0) {
      elmntRight += pos1;
      if (elmnt.offsetLeft + (elmnt.clientWidth / 2) < (windowWidth / 2)) {
        elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
      } else {
        elmnt.style.left = "";
        elmnt.style.right = elmntRight + "px";
      }
    }
    if (pos2 != 0 && elmntBottom + pos2 > 0 && elmnt.offsetTop - pos2 > 0) {
      elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
    }
  }

  function closeDragElement() {
    // stop moving when mouse button is released:
    document.onpointerup = null;
    document.onpointermove = null;
  }
}

function getOffsetLeft(element) {
  let offsetLeft = 0;
  while (element) {
    offsetLeft += element.offsetLeft;
    element = element.offsetParent;
  }
  return offsetLeft;
}

<commit_msg>cleans up code a bit<commit_after>"use strict";

// Many of these are only referenced now inside a singe component, find out which ones, and remove them from here
// global vars
var base_layer_dict = null;
var raster_dict = {};
var overlay_dict = {};
var map = null;
var organization;

// list of layers which automatically become overlay rasters instead of regular rasters
var overlay_list = ['WINDVEC', 'WINDVEC1000FT', 'WINDVEC4000FT', 'WINDVEC6000FT', 'SMOKE1000FT', 'SMOKE4000FT', 'SMOKE6000FT', 'FIRE_AREA', 'SMOKE_INT', 'FGRNHFX', 'FLINEINT'];

// Variables containing input data
var rasters = null;
var sorted_timestamps = null;
var raster_base = null;

// Display context
var layer_ctrl = null;
var current_display = {}; // dictionary of layer name -> layer of currently displayed data
var current_timestamp = null; // currently displayed timestamp
var preloaded = {}; // dictionary containing information on what frames have been preloaded for which rasters/layers
var displayed_colorbar = null; // name of layer currently displaying its colorbar (maybe display multiple cbs?)
var displayed_colorbars = [];

function initialize_fdds() {

  //  initialize base layers & build map
  base_layer_dict = {
  /*
    'MapQuest': L.tileLayer('http://{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png', {
                            attribution: 'Data and imagery by MapQuest',
                            subdomains: ['otile1', 'otile2', 'otile3', 'otile4']}),
  */
    'MapQuest' : MQ.mapLayer(),
  /*	'MQ Satellite': L.tileLayer('http://{s}.mqcdn.com/tiles/1.0.0/sat/{z}/{x}/{y}.png', {
                                attribution: 'Data and imagery by MapQuest',
                                subdomains: ['otile1', 'otile2', 'otile3', 'otile4']}),*/
    'OSM': L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
                      attribution: '© OpenStreetMap contributors'})
  };

  // construct map with the base layers
  map = L.map('map-fd', {
    center: [37.34, -121.89],
    zoom: 7,
    layers: [base_layer_dict['OSM']],
    zoomControl: false,
    minZoom: 3
  });

  const layerController = document.querySelector('layer-controller');
  layerController.buildMapBase();

  loadConfig();

  // add scale & zoom controls to the map
  L.control.scale({ position: 'bottomright' }).addTo(map);
}

function loadConfig() {
  fetch('conf.json').then(response => response.json()).then(function(configData) {
    if (configData.organization) {
      organization = configData.organization;
      if (!organization.includes("SJSU")) {
          map.panTo([39.7392, -104.9903]);
      }
      document.title = organization;
    }

    if (configData.flags) {
      let flags = configData.flags;
      const simulationFlags = document.querySelector("#simulation-flags");
      flags.map(flag => {
          var spanElement = document.createElement("span");
          spanElement.className = "displayTest";
          spanElement.innerText = flag;
          simulationFlags.appendChild(spanElement);
      });
    }
  }).catch(error => {
    console.error(error);
  });
}

/** Makes given element draggable from sub element with id "subID" */
function dragElement(elmnt, subID) {
  var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  var elmntRight = 0;
  document.getElementById(elmnt.id + subID).onpointerdown = dragMouseDown;

  function dragMouseDown(e) {
    e = e || window.event;
    e.preventDefault();
    e.stopPropagation();
    // get the mouse cursor position at startup:
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onpointerup = closeDragElement;
    // call a function whenever the cursor moves:
    document.onpointermove = elementDrag;
  }

  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    e.stopPropagation();
    // calculate the new cursor position:
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    var windowWidth = document.body.clientWidth;
    var windowHeight = document.body.clientHeight;
    let calculatedRight = windowWidth - (getOffsetLeft(elmnt) + elmnt.clientWidth);
    if (Math.abs(elmntRight  - calculatedRight) > 40) {
      elmntRight = windowWidth - (elmnt.offsetLeft + elmnt.clientWidth);
    }
    let elmntBottom = windowHeight - (elmnt.offsetTop + elmnt.clientHeight);
    // set the element's new position:
    if (Math.abs(pos1) >= 1 && elmntRight + pos1 > 0 && elmnt.offsetLeft - pos1 > 0) {
      elmntRight += pos1;
      if (elmnt.offsetLeft + (elmnt.clientWidth / 2) < (windowWidth / 2)) {
        elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
      } else {
        elmnt.style.left = "";
        elmnt.style.right = elmntRight + "px";
      }
    }
    if (pos2 != 0 && elmntBottom + pos2 > 0 && elmnt.offsetTop - pos2 > 0) {
      elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
    }
  }

  function closeDragElement() {
    // stop moving when mouse button is released:
    document.onpointerup = null;
    document.onpointermove = null;
  }
}

/** Calculates the left offset of given element by going up the elements parents and summing offsets. */
function getOffsetLeft(element) {
  let offsetLeft = 0;
  while (element) {
    offsetLeft += element.offsetLeft;
    element = element.offsetParent;
  }
  return offsetLeft;
}

<|endoftext|>