{"version":3,"sources":["webpack:///js/core.6be85d8b1f3d9c47bc1b.js","webpack:////~/@buzzfeed/buzzblocks/js/services/metrics/index.js","webpack:////app/static/js/modules/bounce-policy.js","webpack:////app/static/js/modules/buzzfeed-login.js","webpack:////app/static/js/tracking/sentry.js","webpack:////~/@buzzfeed/buzzblocks/img/apple-touch-icon.png","webpack:////~/@buzzfeed/buzzblocks/img/buzzfeed-webapp-logo.png","webpack:////~/@buzzfeed/buzzblocks/img/favicon.ico","webpack:////app/static/js/core-entry.js","webpack:////~/@buzzfeed/buzzblocks/js/services/ajax/index.js","webpack:////~/@buzzfeed/buzzblocks/js/services/cookies/index.js","webpack:////~/@buzzfeed/buzzblocks/js/services/metrics/mapping.js","webpack:////~/@buzzfeed/buzzblocks/js/services/sentry/index.js","webpack:////~/@buzzfeed/buzzblocks/js/services/util/index.js"],"names":["webpackJsonp","19","module","exports","__webpack_require__","instrument","target","value","tags","options","window","bfa","raven","captureException","Error","VALID_OPTIONS","some","opt","hasOwnProperty","samplingRate","trackingData","data","BZFD","Config","env","console","error","Object","assign","opts","instrumentationPath","defineProperty","36","_classCallCheck","instance","Constructor","TypeError","_createClass","defineProperties","props","i","length","descriptor","enumerable","configurable","writable","key","protoProps","staticProps","prototype","_cookies2","obj","__esModule","default","_cookies","BouncePolicy","context","this","_element","getElement","_bouncePolicyCookie","getIsClosed","classList","remove","cookies","get","isClosed","set","name","days","domain","location","hostname","add","setTimeout","e","elem","elemType","preventDefault","setIsClosed","closeAnimated","Application","addModule","37","_ajax2","_ajax","BuzzFeedLogin","_fieldset","querySelector","_feedbackLabel","_usernameField","_passwordField","_csrfField","_onSubmitLock","errorMsg","_setError","innerText","innerHTML","resetFeedback","successMsg","onSubmit","Promise","resolve","setLoading","username","encodeURIComponent","password","csrf","ajax","post","type","then","response","setLoaded","html","setHTMLError","setError","success","setSuccess","redirectUri","catch","38","_sentry","canary","canaryDeploy","url","sentryUrl","sampleRate","ignoreErrors","39","40","41","42","43","App","startT3","config","init","debug","document","readyState","documentElement","doScroll","addEventListener","getService","bind","on","off","broadcast","startAll","start","44","_interopRequireDefault","rejectOnTimeout","timeout","_","reject","msg","errorHandler","err","status","fetchWithJsonp","requestUrl","ok","statusText","toJson","json","toText","text","_unfetch2","_unfetch","_jsonp2","_jsonp","_util2","_util","params","skipAuth","result","credentials","util","prepareUrl","authBypassWrapper","race","raw","headers","method","body","toQueryString","45","getFullMatch","pattern","matches","match","getCurrentHostname","getCookieDomain","getBuzzfeedSubdomainOrWildcard","subdomainMatch","defaultValue","nameEQ","ca","cookie","split","c","charAt","substring","indexOf","exp","date","Date","setTime","getTime","toGMTString","46","map","mapper","mapping","getOrCreateMap","path","addMapTo","mapFrom","src","JSON","stringify","undefined","_get2","_get3","47","PROD_SAMPLE_RATE","whitelistUrls","defaultWhitelistUrls","dataCallback","sentryDebugMode","shouldSendCallback","Math","random","setTagsContext","install","_ravenJs2","_ravenJs","search","48","_possibleConstructorReturn","self","call","ReferenceError","_inherits","subClass","superClass","create","constructor","setPrototypeOf","__proto__","bfaTrack","bfaRoute","bfaData","Function","bfaBinder","getScreenOrientation","screen","orientation","replace","abs","matchMedia","isIOS","_isFunction2","_isFunction3","_typeof","Symbol","iterator","getKeys","res","keys","push","getUniqueEventName","origName","moduleEl","id","capitalize","str","a","toUpperCase","substr","toLowerCase","char","hasQueryString","removeHash","removeQueryString","getQueryString","querystring","getHash","queryStringToObject","qs","pair","each","val","objectToQueryString","join","getBaseUrl","addParams","keyvals","hash","keyval","removeParams","base","redirect","href","openPopup","wparams","height","width","sTop","sLeft","open","iterable","callback","Array","isArray","forEach","item","idx","extend","require","getQueryParams","param","p","decodeURIComponent","slice","addQueryParam","largeNumberNotation","toString","toFixed","numberWithCommas","num","min","apply","filter","arguments","n","isNaN","k","v","getMessageHandler","handlerMap","handler","getEventHandler","ev","el","elType","padLeft","sym","len","targetLength","acc","freeFormFormat","timeSince","interval","baseFormat","seconds","floor","year","month","day","hour","minute","justNow","bulkDelete","fields","object","isIOSIPad","navigator","userAgent","isIOSMobile","createScript","script","createElement","onload","onerror","evt","async","head","appendChild","stripHTML","strip","stripped","div","textContent","decorateWithMixins","Cls","mixins","mixin","chain","Parent","Wrapper","unshift","idGenerator","addService"],"mappings":"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","file":"js/core.6be85d8b1f3d9c47bc1b.js","sourcesContent":["webpackJsonp([1],{\n\n/***/ 19:\n/* no static exports found */\n/* all exports used */\n/*!************************************************************!*\\\n !*** /~/@buzzfeed/buzzblocks/js/services/metrics/index.js ***!\n \\************************************************************/\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.instrument = instrument;\n\nvar _mapping = __webpack_require__(/*! ../mapping */ 46);\n\nvar VALID_OPTIONS = ['samplingRate'];\n\n/**\n * Increments metric on DataDog.\n * Metric name is constructed from target and value parameters (i.e. 'image.error').\n * @see https://github.com/buzzfeed/mono/blob/master/qr_website_metrics for available metrics and tags.\n * @export\n * @param {String} target - describes what caused metric report.\n * @param {String} value - describes what happened to the metric target.\n * @param {Object?} [tags] - keys and values are metric tag names and values respectively.\n * @param {Object?} [options] - tracking options.\n * @param {Boolean} [options.samplingRate] - forces event to be tracked regardless of sampling configuration.\n * @returns {void}\n * @example instrument('chunk', 'timeout', { name: 'quiz' })\n */\nfunction instrument(target, value) {\n var tags = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};\n\n if (typeof window.bfa !== 'function') {\n if (typeof window.raven !== 'undefined') {\n window.raven.captureException(new Error('Instrumentation tracking issue: BFA is not available'));\n }\n return;\n }\n\n if (VALID_OPTIONS.some(function (opt) {\n return tags.hasOwnProperty(opt);\n })) {\n options = tags;\n tags = {};\n }\n\n var _options = options,\n samplingRate = _options.samplingRate;\n\n var trackingData = {\n data: { target: target, value: value, tags: tags }\n };\n\n if (samplingRate) {\n if (samplingRate > 1) {\n if (window.BZFD.Config.env === 'dev') {\n console.error('Your sampling rate is above 100%.');\n }\n } else {\n Object.assign(trackingData, { opts: { samplingRate: samplingRate } });\n }\n }\n\n window.bfa(_mapping.path, trackingData);\n}\n\n/***/ }),\n\n/***/ 36:\n/* no static exports found */\n/* all exports used */\n/*!***********************************************!*\\\n !*** /app/static/js/modules/bounce-policy.js ***!\n \\***********************************************/\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _t3js = __webpack_require__(/*! t3js */ 5);\n\nvar _cookies = __webpack_require__(/*! @buzzfeed/buzzblocks/js/services/cookies */ 45);\n\nvar _cookies2 = _interopRequireDefault(_cookies);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n/**\n * Handles interaction and state storage for the bounce policy\n * (the bar that appears in the top of the site)\n *\n * This is 'visible unless the user hides' (I.e. it'll show\n * without JavaScript enabled and is therefore opt-out to hide)\n */\nvar BouncePolicy = function () {\n /**\n * @constructor\n * @param context\n */\n function BouncePolicy(context) {\n _classCallCheck(this, BouncePolicy);\n\n this._element = context.getElement();\n this._bouncePolicyCookie = 'bounce_policy_closed';\n\n if (!this.getIsClosed()) {\n this._element.classList.remove('js-hidden');\n }\n }\n\n /**\n * Finds out if this has been closed already\n * @returns bool\n */\n\n\n _createClass(BouncePolicy, [{\n key: 'getIsClosed',\n value: function getIsClosed() {\n return !!_cookies2.default.get(this._bouncePolicyCookie, false);\n }\n\n /**\n * Sets the isClosed state on a cookie for a year\n */\n\n }, {\n key: 'setIsClosed',\n value: function setIsClosed(isClosed) {\n if (isClosed) {\n _cookies2.default.set({\n name: this._bouncePolicyCookie,\n value: 'opt-out',\n days: 365,\n domain: window.location.hostname\n });\n } else {\n _cookies2.default.remove(this._bouncePolicyCookie, window.location.hostname);\n }\n }\n\n /**\n * Triggers UI animation to close\n */\n\n }, {\n key: 'closeAnimated',\n value: function closeAnimated() {\n var _this = this;\n\n this._element.classList.add('bounce-policy--animation');\n setTimeout(function () {\n return _this._element.classList.add('js-hidden');\n }, 1000);\n }\n\n /**\n * Handles the on-click behavior\n */\n\n }, {\n key: 'onclick',\n value: function onclick(e, elem, elemType) {\n if (elemType === 'bounce-close') {\n e.preventDefault();\n this.setIsClosed(true);\n this.closeAnimated();\n }\n return false;\n }\n }]);\n\n return BouncePolicy;\n}();\n\n_t3js.Application.addModule('bounce-policy', function (context) {\n return new BouncePolicy(context);\n});\n\n/***/ }),\n\n/***/ 37:\n/* no static exports found */\n/* all exports used */\n/*!************************************************!*\\\n !*** /app/static/js/modules/buzzfeed-login.js ***!\n \\************************************************/\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _t3js = __webpack_require__(/*! t3js */ 5);\n\nvar _ajax = __webpack_require__(/*! @buzzfeed/buzzblocks/js/services/ajax */ 44);\n\nvar _ajax2 = _interopRequireDefault(_ajax);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n/**\n * Handles interaction with the buzzfeed login endpoint to provide\n * a more seamless authentication experience\n */\nvar BuzzFeedLogin = function () {\n /**\n * @constructor\n * @param context\n */\n function BuzzFeedLogin(context) {\n _classCallCheck(this, BuzzFeedLogin);\n\n this._element = context.getElement();\n this._fieldset = this._element.querySelector('.fieldset');\n this._feedbackLabel = this._element.querySelector('.form-feedback');\n this._usernameField = this._element.querySelector('[name=username]');\n this._passwordField = this._element.querySelector('[name=password]');\n this._csrfField = this._element.querySelector('[name=\"gorilla.csrf.Token\"]');\n this._onSubmitLock = false;\n }\n\n /**\n * Sets a text error on the form\n * @param errorMsg (string) the message to display\n */\n\n\n _createClass(BuzzFeedLogin, [{\n key: 'setError',\n value: function setError(errorMsg) {\n this._setError();\n this._feedbackLabel.innerText = errorMsg;\n }\n\n /**\n * Sets an HTML error on the form\n * @param errorMsg (string) the HTML template of the message to display\n */\n\n }, {\n key: 'setHTMLError',\n value: function setHTMLError(errorMsg) {\n this._setError();\n this._feedbackLabel.innerHTML = errorMsg;\n }\n\n /**\n * Shows the error on the form\n */\n\n }, {\n key: '_setError',\n value: function _setError() {\n this.resetFeedback();\n this._feedbackLabel.classList.remove('js-hidden');\n this._fieldset.classList.add('form-fieldset--error');\n }\n\n /**\n * Sets an success message on the form\n * @param successMsg (string) the message to display\n */\n\n }, {\n key: 'setSuccess',\n value: function setSuccess(successMsg) {\n this.resetFeedback();\n this._feedbackLabel.innerText = successMsg;\n this._feedbackLabel.classList.remove('js-hidden');\n this._fieldset.classList.add('form-fieldset--success');\n }\n\n /**\n * Set Loading\n */\n\n }, {\n key: 'setLoading',\n value: function setLoading() {\n this.resetFeedback();\n this._fieldset.classList.add('form-fieldset--loading');\n }\n\n /**\n * Set Loaded\n */\n\n }, {\n key: 'setLoaded',\n value: function setLoaded() {\n this.resetFeedback();\n this._fieldset.classList.remove('form-fieldset--loading');\n }\n\n /**\n * Removes error/success messages from the form\n */\n\n }, {\n key: 'resetFeedback',\n value: function resetFeedback() {\n this._feedbackLabel.innerText = '';\n this._feedbackLabel.classList.add('js-hidden');\n this._fieldset.classList.remove('form-fieldset--error');\n this._fieldset.classList.remove('form-fieldset--success');\n }\n\n /**\n * Listens to all module click events, if it is a click on the\n * button login then trigger onSubmit\n */\n\n }, {\n key: 'onclick',\n value: function onclick(e, elem, elemType) {\n if (elemType === 'login') {\n e.preventDefault();\n this.onSubmit();\n }\n return false;\n }\n\n /**\n * Triggered when the form button is clicked via onclick\n * Handles the XHR\n */\n\n }, {\n key: 'onSubmit',\n value: function onSubmit() {\n var _this = this;\n\n if (this._onSubmitLock) {\n return Promise.resolve();\n }\n this._onSubmitLock = true;\n this.setLoading();\n\n var username = encodeURIComponent(this._usernameField.value);\n var password = encodeURIComponent(this._passwordField.value);\n var csrf = encodeURIComponent(this._csrfField.value);\n var buzzfeedLoginEndpoint = '/auth/login/buzzfeed';\n\n return _ajax2.default.post(buzzfeedLoginEndpoint, {\n type: 'json',\n data: {\n 'gorilla.csrf.Token': csrf,\n username: username,\n password: password\n }\n }).then(function (response) {\n _this.setLoaded();\n _this._onSubmitLock = false;\n if (response.error) {\n if (response.html) {\n _this.setHTMLError(response.html);\n } else {\n _this.setError(response.error);\n }\n return;\n }\n if (response.success) {\n _this.setSuccess(response.success);\n window.location = window.redirectUri || '/';\n return;\n }\n }).catch(function () {\n _this._onSubmitLock = false;\n _this.setLoaded();\n _this.setError('unexpected error occurred');\n });\n }\n }]);\n\n return BuzzFeedLogin;\n}();\n\n_t3js.Application.addModule('buzzfeed-login', function (context) {\n return new BuzzFeedLogin(context);\n});\n\n/***/ }),\n\n/***/ 38:\n/* no static exports found */\n/* all exports used */\n/*!*****************************************!*\\\n !*** /app/static/js/tracking/sentry.js ***!\n \\*****************************************/\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _sentry = __webpack_require__(/*! @buzzfeed/buzzblocks/js/services/sentry */ 47);\n\nvar _sentry2 = _interopRequireDefault(_sentry);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n(0, _sentry2.default)({\n env: window.Config.env,\n canary: window.Config.canaryDeploy,\n url: window.Config.sentryUrl,\n sampleRate: 0.05,\n ignoreErrors: []\n});\n\n/***/ }),\n\n/***/ 39:\n/* no static exports found */\n/* all exports used */\n/*!**************************************!*\\\n !*** /app/static/sass/critical.scss ***!\n \\**************************************/\n/***/ (function(module, exports) {\n\n// removed by extract-text-webpack-plugin\n\n/***/ }),\n\n/***/ 40:\n/* no static exports found */\n/* all exports used */\n/*!********************************************************!*\\\n !*** /~/@buzzfeed/buzzblocks/img/apple-touch-icon.png ***!\n \\********************************************************/\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__.p + \"img/apple-touch-icon.186faa454878ee0d6582ba33b41d2044.png\";\n\n/***/ }),\n\n/***/ 41:\n/* no static exports found */\n/* all exports used */\n/*!************************************************************!*\\\n !*** /~/@buzzfeed/buzzblocks/img/buzzfeed-webapp-logo.png ***!\n \\************************************************************/\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__.p + \"img/buzzfeed-webapp-logo.0ea3c59fd2aeb164cfdfe77e74ab3aa2.png\";\n\n/***/ }),\n\n/***/ 42:\n/* no static exports found */\n/* all exports used */\n/*!***********************************************!*\\\n !*** /~/@buzzfeed/buzzblocks/img/favicon.ico ***!\n \\***********************************************/\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__.p + \"img/favicon.5a0c77a8815cfcc67c710199054a55c6.ico\";\n\n/***/ }),\n\n/***/ 43:\n/* no static exports found */\n/* all exports used */\n/*!************************************!*\\\n !*** /app/static/js/core-entry.js ***!\n \\************************************/\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _t3js = __webpack_require__(/*! t3js */ 5);\n\n__webpack_require__(/*! .../sass/critical.scss */ 39);\n\n__webpack_require__(/*! @buzzfeed/buzzblocks/img/favicon.ico */ 42);\n\n__webpack_require__(/*! @buzzfeed/buzzblocks/img/apple-touch-icon.png */ 40);\n\n__webpack_require__(/*! @buzzfeed/buzzblocks/img/buzzfeed-webapp-logo.png */ 41);\n\n__webpack_require__(/*! ../tracking/sentry */ 38);\n\n__webpack_require__(/*! ../modules/buzzfeed-login.js */ 37);\n\n__webpack_require__(/*! ../modules/bounce-policy.js */ 36);\n\n/**\n * @fileoverview\n * Webpack entry for enhanced-ux version only.\n * Loads all components and initializes the application.\n */\nfunction App() {\n var startT3 = function startT3(config) {\n _t3js.Application.init(config);\n };\n\n return {\n init: function init() {\n var config = {\n debug: true\n };\n if (document.readyState === 'complete' || document.readyState !== 'loading' && !document.documentElement.doScroll) {\n startT3(config);\n } else {\n document.addEventListener('DOMContentLoaded', function () {\n startT3(config);\n });\n }\n },\n getService: _t3js.Application.getService.bind(_t3js.Application),\n on: _t3js.Application.on.bind(_t3js.Application),\n off: _t3js.Application.off.bind(_t3js.Application),\n broadcast: _t3js.Application.broadcast.bind(_t3js.Application),\n startAll: _t3js.Application.startAll.bind(_t3js.Application),\n start: _t3js.Application.start.bind(_t3js.Application)\n };\n}\n\n// start app\nwindow.App = new App();\nwindow.App.init();\n\n/***/ }),\n\n/***/ 44:\n/* no static exports found */\n/* all exports used */\n/*!*********************************************************!*\\\n !*** /~/@buzzfeed/buzzblocks/js/services/ajax/index.js ***!\n \\*********************************************************/\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _unfetch = __webpack_require__(/*! unfetch */ 136);\n\nvar _unfetch2 = _interopRequireDefault(_unfetch);\n\nvar _metrics = __webpack_require__(/*! .../metrics */ 19);\n\nvar _jsonp = __webpack_require__(/*! jsonp */ 51);\n\nvar _jsonp2 = _interopRequireDefault(_jsonp);\n\nvar _util = __webpack_require__(/*! .../util */ 48);\n\nvar _util2 = _interopRequireDefault(_util);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n/**\n * Creates a promise, which is rejected after a specified timeout.\n * @param {Number} timeout - number of milliseconds to wait until promise is rejected.\n */\n\n/**\n * A simple JSONP implementation\n * @see https://github.com/webmodules/jsonp\n */\n/**\n * Bare minimum fetch polyfill in 500 bytes.\n * @see https://github.com/developit/unfetch\n */\nfunction rejectOnTimeout(timeout) {\n return new Promise(function (_, reject) {\n setTimeout(function () {\n return reject({ type: 'timeout', msg: timeout + 'ms timeout exceeded' });\n }, timeout);\n });\n}\n\nfunction errorHandler(_ref) {\n var url = _ref.url;\n\n return function (err) {\n (0, _metrics.instrument)('xhr', err.type || 'error', { url: url, status: err.status || 0 });\n return Promise.reject(err);\n };\n}\n\n/**\n * Promisifies the jsonp implementation\n * @param {String} requestUrl - the request url to be passed to jsonp.\n * @return {Promise} - a promise resolved with the response.\n */\nfunction fetchWithJsonp(requestUrl) {\n return new Promise(function (resolve, reject) {\n (0, _jsonp2.default)(requestUrl, function (err, response) {\n if (err) {\n return reject(err);\n }\n return resolve(response);\n });\n });\n}\n\n/**\n * Checks response status code.\n * Resolves when status code is within 200-300 range.\n * Rejects otherwise.\n * @param {Response} response - response object.\n */\nfunction status(response) {\n if (response.ok) {\n return Promise.resolve(response);\n } else {\n return Promise.reject({ type: 'error', status: response.status, statusText: response.statusText });\n }\n}\n\n/**\n * Converts response to JSON.\n * @param {Response} response - response object.\n */\nfunction toJson(response) {\n return response.json();\n}\n\n/**\n * Converts response to plain text.\n * @param {Response} response - response object.\n */\nfunction toText(response) {\n return response.text();\n}\n\nexports.default = {\n /**\n * Performs a GET request to a specified endpoint.\n * @param {String} url - resource URL.\n * @param {Object} options - request options.\n * @param {Object} [options.data={}] - request parameters, are being included in the URL.\n * @param {String} [options.type=json] - expected response type.\n * @param {Object} [options.params={}] - additional fetch parameters.\n * @param {Boolean} [options.skipAuth=false] - flag to add basic auth bypass token to the resource URL.\n * @param {Number} [options.timeout] - maximum time in milliseconds for a request to complete.\n * @return {Promise} - a promise resolved with the response body.\n */\n get: function get(url) {\n var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n _ref2$type = _ref2.type,\n type = _ref2$type === undefined ? 'json' : _ref2$type,\n _ref2$data = _ref2.data,\n data = _ref2$data === undefined ? {} : _ref2$data,\n _ref2$params = _ref2.params,\n params = _ref2$params === undefined ? {} : _ref2$params,\n skipAuth = _ref2.skipAuth,\n timeout = _ref2.timeout;\n\n if (!url) {\n return Promise.reject('URL parameter is required');\n }\n\n var result = void 0;\n var options = Object.assign({\n credentials: 'same-origin'\n }, params);\n\n var requestUrl = _util2.default.prepareUrl(url, data);\n\n if (skipAuth) {\n // @todo remove from util.js service once ajax.js is deprecated\n requestUrl = _util2.default.authBypassWrapper(requestUrl);\n }\n\n switch (type) {\n case 'json':\n result = (0, _unfetch2.default)(requestUrl, options).then(status).then(toJson);\n break;\n case 'text':\n result = (0, _unfetch2.default)(requestUrl, options).then(status).then(toText);\n break;\n case 'jsonp':\n result = fetchWithJsonp(requestUrl);\n break;\n default:\n result = Promise.reject('Unsupported type ' + type);\n }\n\n return (timeout ? Promise.race([rejectOnTimeout(timeout), result]) : result).catch(errorHandler({ url: url }));\n },\n\n\n /**\n * Performs a POST request to a specified endpoint.\n * @param {String} url - resource URL.\n * @param {Object} options - request options.\n * @param {Object} options.data - request parameters, are being included in the request body.\n * @param {String} [options.type=json] - expected response type.\n * @param {String} [options.params={}] - additional fetch parameters.\n * @param {Boolean} [options.raw=false] - flag to disable converting request parameters to query string key value pairs.\n * @param {Number} [options.timeout] - maximum time in milliseconds for a request to complete.\n * @return {Promise} - a promise resolved with the response body.\n */\n post: function post(url) {\n var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n data = _ref3.data,\n _ref3$type = _ref3.type,\n type = _ref3$type === undefined ? 'json' : _ref3$type,\n _ref3$params = _ref3.params,\n params = _ref3$params === undefined ? {} : _ref3$params,\n _ref3$raw = _ref3.raw,\n raw = _ref3$raw === undefined ? false : _ref3$raw,\n timeout = _ref3.timeout;\n\n if (!url) {\n return Promise.reject('URL parameter is required');\n }\n\n if (!data) {\n return Promise.reject('Can not send POST request without data');\n }\n\n var result = void 0;\n var options = Object.assign({\n headers: {\n 'Content-type': 'application/x-www-form-urlencoded'\n },\n credentials: 'same-origin'\n }, params);\n\n options.method = 'POST';\n options.body = raw ? data : _util2.default.toQueryString(data);\n\n switch (type) {\n case 'json':\n result = (0, _unfetch2.default)(url, options).then(status).then(toJson);\n break;\n case 'text':\n result = (0, _unfetch2.default)(url, options).then(status).then(toText);\n break;\n default:\n result = Promise.reject('Unsupported type ' + type);\n }\n\n return (timeout ? Promise.race([rejectOnTimeout(timeout), result]) : result).catch(errorHandler({ url: url }));\n }\n};\n\n/***/ }),\n\n/***/ 45:\n/* no static exports found */\n/* all exports used */\n/*!************************************************************!*\\\n !*** /~/@buzzfeed/buzzblocks/js/services/cookies/index.js ***!\n \\************************************************************/\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n/**\n * Returns full regex match, or null if no match\n * @param {String} value, the string which may match *pattern*\n * @param {String} pattern, regex string\n * @returns {String?}\n */\nfunction getFullMatch(value, pattern) {\n var matches = value.match(pattern);\n return matches && matches.length ? matches[0] : null;\n}\n\n/**\n * Gives the current hostname, good for mocking purposes\n * @returns {String} hostname\n */\nfunction getCurrentHostname() {\n return window.location.hostname;\n}\n\n/**\n * Gives the domain based on the environment\n * @returns {String} domain\n */\nfunction getCookieDomain() {\n return window.BZFD.Config.env === 'prod' ? 'buzzfeed.com' : getCurrentHostname();\n}\n\nexports.default = {\n\n /**\n * Returns domain based on *hostname*.\n * Prefers buzzfeed.com subdomain.\n * Returns generic domain if not a buzzfeed dev|stage|www subdomain.\n * @param hostname {String}\n * @returns {String}\n */\n getBuzzfeedSubdomainOrWildcard: function getBuzzfeedSubdomainOrWildcard(hostname) {\n var subdomainMatch = getFullMatch(hostname, '(dev|stage|www).buzzfeed.(com|io)$');\n if (subdomainMatch) {\n return subdomainMatch;\n }\n\n return getFullMatch(hostname, '.?[a-z]+.[a-z]+$');\n },\n\n\n /**\n * Gets cookie value by name.\n * @param {String} name - cookie name.\n * @param {Object} [defaultValue] - value to return if cookie is not presented.\n * @returns {?Object} - value of the specified cookie or default.\n */\n get: function get(name) {\n var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n\n var nameEQ = name + '=';\n var ca = document.cookie.split(';');\n\n for (var i = 0; i < ca.length; i++) {\n var c = ca[i];\n while (c.charAt(0) === ' ') {\n c = c.substring(1, c.length);\n }\n if (c.indexOf(nameEQ) === 0) {\n return c.substring(nameEQ.length, c.length);\n }\n }\n return defaultValue;\n },\n\n\n /**\n * Creates cookie with specified properties.\n * @param {Object} args - options for creating a cookie.\n * @param {String} args.name - cookie name.\n * @param {Object} args.value - cookie value.\n * @param {Number} [args.days] - number of days until cookie expires.\n * @param {String} args.domain - the domain to set cookie on\n * @returns {String} document.cookie to be set\n */\n set: function set(_ref) {\n var name = _ref.name,\n value = _ref.value,\n days = _ref.days,\n domain = _ref.domain;\n\n domain = domain || getCookieDomain();\n var exp = '';\n if (days) {\n var date = new Date();\n date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);\n exp = '; expires=' + date.toGMTString();\n }\n\n return document.cookie = name + '=' + value + exp + '; path=/; domain=' + domain;\n },\n\n\n /**\n * Removes cookie by name.\n * Sets expiration date on yesterday.\n * @param {String} name - cookie name.\n * @param {String} domain - the hostname of the cookie.\n * @returns {void}\n */\n remove: function remove(name) {\n var domain = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCookieDomain();\n\n return this.set({\n name: name,\n value: '',\n days: -1,\n domain: domain\n });\n }\n};\n\n/***/ }),\n\n/***/ 46:\n/* no static exports found */\n/* all exports used */\n/*!**************************************************************!*\\\n !*** /~/@buzzfeed/buzzblocks/js/services/metrics/mapping.js ***!\n \\**************************************************************/\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.path = undefined;\n\nvar _get2 = __webpack_require__(/*! lodash/get */ 28);\n\nvar _get3 = _interopRequireDefault(_get2);\n\nexports.map = map;\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar target = 'target';\nvar value = 'value';\nvar tags = 'tags';\n\nvar path = exports.path = 'track/website/instrumentation';\n\nfunction map(mapper) {\n var mapping = mapper.getOrCreateMap(path);\n mapping.addMapTo('type', 'instrumentation');\n mapping.addMapTo('platform', '').mapFrom('data.page.platform');\n mapping.addMapTo('edition', '').mapFrom('data.page.country');\n mapping.addMapTo('category', '').mapFrom(function (src) {\n return (0, _get3.default)(src, 'data.page.category') || 'home';\n });\n mapping.addMapTo(target, '').mapFrom('data.' + target);\n mapping.addMapTo(value, '').mapFrom('data.' + value);\n mapping.addMapTo(tags, '').mapFrom(function (src) {\n return JSON.stringify((0, _get3.default)(src, 'data.' + tags, ''));\n });\n\n return mapping;\n};\n\n/***/ }),\n\n/***/ 47:\n/* no static exports found */\n/* all exports used */\n/*!***********************************************************!*\\\n !*** /~/@buzzfeed/buzzblocks/js/services/sentry/index.js ***!\n \\***********************************************************/\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nexports.default = function (_ref) {\n var url = _ref.url,\n _ref$env = _ref.env,\n env = _ref$env === undefined ? window.BZFD.Config.env : _ref$env,\n _ref$canary = _ref.canary,\n canary = _ref$canary === undefined ? window.BZFD.Config.canaryDeploy : _ref$canary,\n _ref$sampleRate = _ref.sampleRate,\n sampleRate = _ref$sampleRate === undefined ? PROD_SAMPLE_RATE : _ref$sampleRate,\n _ref$whitelistUrls = _ref.whitelistUrls,\n whitelistUrls = _ref$whitelistUrls === undefined ? defaultWhitelistUrls : _ref$whitelistUrls,\n _ref$ignoreErrors = _ref.ignoreErrors,\n ignoreErrors = _ref$ignoreErrors === undefined ? [] : _ref$ignoreErrors,\n _ref$dataCallback = _ref.dataCallback,\n dataCallback = _ref$dataCallback === undefined ? function (data) {\n return data;\n } : _ref$dataCallback;\n\n\n if (!url && env === 'dev') {\n throw new Error('Missing sentry url. More info: http://bit.ly/2v9diir');\n }\n\n if (env !== 'prod' && !sentryDebugMode) {\n return;\n }\n\n _ravenJs2.default.config(url, {\n whitelistUrls: whitelistUrls,\n ignoreErrors: ignoreErrors,\n shouldSendCallback: function shouldSendCallback() {\n if (sentryDebugMode) {\n return true;\n }\n return Math.random() <= sampleRate;\n },\n dataCallback: dataCallback\n }).setTagsContext({ canary: canary }).install();\n\n window.raven = _ravenJs2.default;\n return _ravenJs2.default; // eslint-disable-line consistent-return\n};\n\nvar _ravenJs = __webpack_require__(/*! raven-js */ 133);\n\nvar _ravenJs2 = _interopRequireDefault(_ravenJs);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar PROD_SAMPLE_RATE = 0.2;\nvar defaultWhitelistUrls = [/\\/static-assets\\//];\nvar sentryDebugMode = window.location.search.indexOf('sentrydebug') > -1;\n\n/**\n * Initialize Sentry for JS error reporting.\n * Sentry is only initialized in production.\n * This also sets raven as a global for access by embeds etc.\n * @export\n * @param {Object} params\n * @param {string} params.url - The sentry unique url\n * @param {string} params.env? - The runtime environment\n * @param {string} params.canary? - Is the deployment type canary?\n * @param {string} params.sampleRate? - The rate at which you sample errors (0 - 1)\n * @param {array} params.whitelistUrls? - An array of URL strings that you want to collect errors on\n * @param {array} params.ignoreErrors? - An array of strings or regexes that you want to ignore\n * @param {array} params.dataCallback? - A transformation function to be run before sending\n * @returns {raven} - the raven-js library\n * @example sentry({ url: 'https://some.url', env: 'dev' })\n */\n\n/***/ }),\n\n/***/ 48:\n/* no static exports found */\n/* all exports used */\n/*!*********************************************************!*\\\n !*** /~/@buzzfeed/buzzblocks/js/services/util/index.js ***!\n \\*********************************************************/\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.isIOS = undefined;\n\nvar _isFunction2 = __webpack_require__(/*! lodash/isFunction */ 11);\n\nvar _isFunction3 = _interopRequireDefault(_isFunction2);\n\nvar _get2 = __webpack_require__(/*! lodash/get */ 28);\n\nvar _get3 = _interopRequireDefault(_get2);\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; /* global BZFD */\n\nexports.bfaTrack = bfaTrack;\nexports.getScreenOrientation = getScreenOrientation;\n\nvar _t3js = __webpack_require__(/*! t3js */ 5);\n\nvar _metrics = __webpack_require__(/*! .../metrics */ 19);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\n/**\n * Service with some general widely used functions\n */\nvar util = {};\n\n/**\n * Gets a list of object's enumerable property names.\n * @param {Object} obj - target object.\n * @return {Array} - list of object's keys.\n */\nutil.getKeys = function (obj) {\n var res;\n if (Object.keys) {\n return Object.keys(obj);\n } else {\n res = [];\n for (var key in obj) {\n if (obj.hasOwnProperty(key)) {\n res.push(key);\n }\n }\n return res;\n }\n};\n\n/**\n * Adds module's element id attribute value to the event name.\n * @param {String} origName - original event name.\n * @param {HTMLElement} moduleEl - module's DOM element.\n * @return {String} - name with id value.\n */\nutil.getUniqueEventName = function (origName, moduleEl) {\n return origName + '-' + moduleEl.id;\n};\n\nutil.capitalize = function (str) {\n if (typeof str !== 'string') {\n return str;\n } else {\n return str.replace(/\\w+/g, function (a) {\n return a.charAt(0).toUpperCase() + a.substr(1).toLowerCase();\n });\n }\n};\n\nutil.authBypassWrapper = function (url) {\n if (BZFD.Config.env === 'dev') {\n var hash = 'eca385331012a621bc93fcda0a953a97';\n var char = '?';\n\n if (util.hasQueryString(url)) {\n char = '&';\n }\n\n url += char + hash;\n }\n\n return url;\n};\n\nutil.hasQueryString = function (url) {\n return url.indexOf('?') > -1;\n};\n\nutil.removeHash = function (url) {\n url = url + ''; // Convert object to string, if necessary\n if (url.indexOf('#') > -1) {\n return url.substr(0, url.indexOf('#'));\n }\n return url;\n};\n\nutil.removeQueryString = function (url) {\n url = url + ''; // Convert object to string, if necessary\n if (url.indexOf('?') > -1) {\n if (url.indexOf('#') === -1) {\n return url.substr(0, url.indexOf('?'));\n }\n return url.substr(0, url.indexOf('?')) + url.substr('#', url.length);\n }\n return url;\n};\n\nutil.getQueryString = function (url) {\n url = util.removeHash(url);\n var querystring = '';\n if (url.indexOf('?') > -1) {\n querystring = url.substr(url.indexOf('?'), url.length); // Contains '?'\n }\n return querystring;\n};\n\nutil.getHash = function (url) {\n url = url + ''; // Convert object to string, if necessary\n if (url.indexOf('#') > -1) {\n return url.substr(url.indexOf('#'), url.length);\n }\n return '';\n};\n\nutil.queryStringToObject = function (qs) {\n // Without '?'\n if (qs === '' || qs === undefined || qs === null) {\n return {};\n }\n var params = qs.split('&');\n var pair;\n var obj = {};\n\n util.each(params, function (i, val) {\n pair = val.split('=');\n if (pair[1] === '') {\n pair[1] = null;\n }\n obj[pair[0]] = pair[1];\n });\n return obj;\n};\n\nutil.objectToQueryString = function (qs) {\n var str = [];\n util.each(qs, function (key, val) {\n str.push(key + '=' + val);\n });\n return '?' + str.join('&');\n};\n\nutil.getBaseUrl = function (url) {\n url = util.removeHash(url);\n url = util.removeQueryString(url);\n return url;\n};\n\nutil.addParams = function (url, keyvals) {\n var qs = util.getQueryString(url); // Contains '?'\n var hash = util.getHash(url); // Contains '#'\n var key;\n var val;\n\n url = util.removeHash(url);\n url = util.removeQueryString(url);\n\n qs = util.queryStringToObject(qs.substr(1, qs.length)); // no '?'\n\n util.each(keyvals, function (i, keyval) {\n key = keyval[0];\n val = keyval[1];\n qs[key] = val;\n });\n\n return url + util.objectToQueryString(qs) + hash;\n};\n\n/**\n * Remove given parameters from a URL string.\n * @param {string} url - a url\n * @param {Array} keys - an array of keys to be deleted\n * @return {string} url - the url without the given params\n */\nutil.removeParams = function (url, keys) {\n var base = util.getBaseUrl(url);\n var qs = util.getQueryString(url);\n var hash = util.getHash(url);\n var params = util.queryStringToObject(qs.substr(1, qs.length));\n\n util.each(keys, function (i, key) {\n delete params[key];\n });\n\n return base + util.objectToQueryString(params) + hash;\n};\n\nutil.prepareUrl = function (url, data) {\n // Append parameter(s) to url\n var keyvals = [];\n\n util.each(data, function (key, val) {\n if (typeof val === 'undefined') {\n return;\n }\n keyvals.push([key, encodeURIComponent(val)]);\n });\n\n return util.addParams(url, keyvals);\n};\n\nutil.redirect = function (url) {\n if (typeof url === 'string' && url) {\n window.location.href = url;\n }\n};\n\nutil.openPopup = function (url, options) {\n if (typeof url === 'string' && url) {\n var name = '_blank';\n var wparams = '';\n\n if (options && options.height && options.width) {\n var sTop = window.screen.height / 2 - options.height / 2;\n var sLeft = window.screen.width / 2 - options.width / 2;\n wparams = 'scrollbars=yes, toolbar=0, status=0, width=' + options.width + ', height=' + options.height + ', top=' + sTop + ', left=' + sLeft;\n name = options.name ? options.name : name;\n }\n window.open(url, name, wparams);\n }\n};\n\n/**\n * A generic iterator function, which can be used to seamlessly iterate over both objects\n * and arrays.\n * @todo reorder arguments when iterating an array to match Array.prototype.forEach behavior\n */\nutil.each = function (iterable, callback) {\n if (Array.isArray(iterable)) {\n iterable.forEach(function (item, idx) {\n return callback(idx, item);\n });\n } else {\n for (var key in iterable) {\n if (iterable.hasOwnProperty(key)) {\n callback(key, iterable[key]);\n }\n }\n }\n};\n\nutil.extend = __webpack_require__(/*! lodash/merge */ 124);\n\n/**\n *\n * @return {Object} - map of query parameters keys and values\n */\nutil.getQueryParams = function () {\n var search = window.location.search.substring(1);\n var result = {};\n if (search) {\n search.split('&').forEach(function (param) {\n var p = param.split('=');\n var key = decodeURIComponent(p[0]);\n var value = decodeURIComponent(p.slice(1).join('='));\n result[key] = value;\n });\n }\n\n return result;\n};\n\n/**\n * Adds query parameter to the end of provided URL string.\n * @param {String} [url=location.href] - target URL string.\n * @param {String} key - parameter name.\n * @param {String} val - parameter value.\n * @return {String} - url with specified parameter at the end.\n */\nutil.addQueryParam = function (url, key, val) {\n url = url || window.location.href;\n return url + (url.split('?')[1] ? '&' : '?') + (key + '=' + val);\n};\n\n/* eslint-disable max-len */\n/**\n * Change number into shortened format.\n * Example: 125 -> 125; 3456 -> 3,456; 10355 -> 10,4K; 1100123 -> 1.1M;\n * Adapted from\n * https://stackoverflow.com/questions/3177855/how-to-format-numbers-similar-to-stack-overflow-reputation-format\n * @param {Number} val - number to be formatted\n * @returns {String} shortened number\n */\n/* eslint-enable max-len */\nutil.largeNumberNotation = function (val) {\n if (val < 1000) {\n return val;\n } else if (val < 10000) {\n return val.toString().charAt(0) + ',' + val.toString().substring(1);\n } else if (val >= 1000000) {\n return (val / 1000000).toFixed(val % 1000000 !== 0) + 'M';\n }\n return (val / 1000).toFixed(val % 1000 !== 0) + 'K';\n};\n\n/* eslint-disable max-len */\n/**\n * Splits number with comma by thousands\n * @param {Number} num - number to be formatted\n * @returns {String} - number with commas\n * eslint-disable max-len\n * @see http://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript\n * eslint-enable max-len\n */\nutil.numberWithCommas = function (num) {\n return num.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n};\n\n/**\n * Returns the smallest of numbers.\n * @return {Number} - smallest number.\n */\nutil.min = function () /*[value1[, value2[, ...]]]*/{\n return Math.min.apply(Math, Array.prototype.filter.call(arguments, function (n) {\n return !isNaN(+n);\n }));\n};\n\n/**\n * Converts object to query string params.\n * @param {Object} obj - target object.\n * @return {string} - query string.\n */\nutil.toQueryString = function (obj) {\n var res = [];\n this.each(obj, function (k, v) {\n if (v !== null && v !== '' && typeof v !== 'undefined') {\n res.push(k + '=' + v);\n }\n });\n return res.join('&');\n};\n\n/**\n * Gets a handler for internal events for T3 modules and behaviors.\n * @param {Object} handlerMap - handlers map (key is a message name, value is a handler).\n * @return {Function} - handler for T3 onmessage method.\n */\nutil.getMessageHandler = function (handlerMap) {\n return function (name, data) {\n var handler = handlerMap[name];\n if (typeof handler === 'function') {\n handler.call(this, data);\n }\n };\n};\n\n/**\n * Gets a handler for DOM events for T3 modules and behaviors.\n * @param {Object} handlerMap - handlers map\n * (key is a dataType attribute of the target element, value is a handler).\n * @return {Function} - handler for native DOM events in T3.\n */\nutil.getEventHandler = function (handlerMap) {\n return function (ev, el, elType) {\n var handler = handlerMap[elType];\n if (typeof handler === 'function') {\n handler.call(this, ev, el);\n }\n };\n};\n\n/**\n * Adds leading symbols to a string.\n * @param {String} src - string to pad.\n * @param {String} sym - symbol to add to the src string.\n * @param {Number} len - required result string length.\n * @return {String} - padded src string.\n */\nutil.padLeft = function (src, sym, len) {\n var str = src.toString();\n var targetLength = len - str.length;\n var acc = '';\n\n for (var i = 0; i < targetLength; i++) {\n acc += sym;\n }\n\n return acc + src;\n};\n\n/**\n * Converts string into small caps\n * @param {String} str - string to convert.\n * @return {String} - converted string.\n */\nutil.freeFormFormat = function (str) {\n var uglyStr = str.replace(/[\"'\"“’ ]/g, '').toLowerCase();\n\n return uglyStr;\n};\n\n/**\n * Returns time since text\n * @param {String} date - date string in UTC format `yy:mm:ddThh:mm:ssZ`\n * @return {Object} time since object {'type': '', 'value': '', 'text': ''}\n */\nutil.timeSince = function (date) {\n var baseFormat = {\n 'year': ['year', 'years'],\n 'month': ['month', 'months'],\n 'day': ['day', 'days'],\n 'hour': ['hour', 'hours'],\n 'minute': ['minute', 'minutes'],\n 'justNow': ['just now']\n };\n var interval;\n var seconds = Math.floor((new Date().getTime() - new Date(date).getTime()) / 1000);\n\n interval = Math.floor(seconds / 31536000);\n\n if (interval >= 1) {\n return {\n 'type': 'year',\n 'value': interval,\n 'text': interval + ' ' + (interval === 1 ? baseFormat.year[0] : baseFormat.year[1]) + ' ago'\n };\n }\n\n interval = Math.floor(seconds / 2592000);\n\n if (interval >= 1) {\n return {\n 'type': 'month',\n 'value': interval,\n 'text': interval + ' ' + (interval === 1 ? baseFormat.month[0] : baseFormat.month[1]) + ' ago'\n };\n }\n\n interval = Math.floor(seconds / 86400);\n\n if (interval >= 1) {\n return {\n 'type': 'day',\n 'value': interval,\n 'text': interval + ' ' + (interval === 1 ? baseFormat.day[0] : baseFormat.day[1]) + ' ago'\n };\n }\n\n interval = Math.floor(seconds / 3600);\n\n if (interval >= 1) {\n return {\n 'type': 'hour',\n 'value': interval,\n 'text': interval + ' ' + (interval === 1 ? baseFormat.hour[0] : baseFormat.hour[1]) + ' ago'\n };\n }\n\n interval = Math.floor(seconds / 60);\n\n if (interval > 1) {\n return {\n 'type': 'minute',\n 'value': interval,\n 'text': interval + ' ' + (interval === 1 ? baseFormat.minute[0] : baseFormat.minute[1]) + ' ago'\n };\n }\n\n return {\n 'type': 'now',\n 'value': '',\n 'text': baseFormat.justNow[0]\n };\n};\n\nutil.bulkDelete = function (fields, object) {\n util.each(fields, function (i, val) {\n delete object[val];\n });\n};\n\n/**\n * Send data to BF Analytics\n * Example:\n * @param {String} bfaRoute - the route for bfa ex. 'track/click/share'\n * @param {Object} bfaData - formatted object ex. {t:'click:share-button', d:'Facebook'}\n * @returns void\n */\nfunction bfaTrack(bfaRoute) {\n var bfaData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n if (!window.bfa || !(window.bfa instanceof Function) || !window.bfaBinder) {\n return;\n }\n\n window.bfa(bfaRoute, bfaData);\n};\nutil.bfaTrack = bfaTrack;\n\n/**\n * Checks for screen orientation\n * @return {String} `portrait` or '`landscape`\n */\nfunction getScreenOrientation() {\n if (screen.orientation && screen.orientation.type) {\n return screen.orientation.type.replace('-primary', '');\n } else if (window.orientation) {\n if (Math.abs(window.orientation) === 90) {\n return 'landscape';\n } else {\n return 'portrait';\n }\n } else if (window.matchMedia) {\n if (window.matchMedia('(orientation: portrait)').matches) {\n return 'portrait';\n } else if (window.matchMedia('(orientation: landscape)').matches) {\n return 'landscape';\n }\n }\n\n return 'landscape';\n};\nutil.getScreenOrientation = getScreenOrientation;\n\n/**\n * Checks browser user agent to detect ipad device\n * @return {Boolean} `true` if ipad device detected, `false` otherwise\n */\nutil.isIOSIPad = function () {\n var agent = navigator.userAgent.toLowerCase();\n\n if (agent.match(/ipad/)) {\n return true;\n }\n\n return false;\n}();\n\n/**\n * Checks browser user agent to detect iphone|ipod device\n * @return {Boolean} `true` if iphone|ipod device detected, `false` otherwise\n */\nutil.isIOSMobile = function () {\n var agent = navigator.userAgent.toLowerCase();\n\n if (agent.match(/iphone|ipod/)) {\n return true;\n }\n\n return false;\n}();\n\n/**\n * Checks browser user agent to detect iOS device.\n * This is not a reliable long-term method for detecting iOS and should be used sparingly.\n * @return {Boolean} `true` if iOS device detected, `false` otherwise\n */\nvar isIOS = exports.isIOS = function () {\n return util.isIOSIPad || util.isIOSMobile;\n}();\nutil.isIOS = isIOS;\n\n/**\n * Creates a script tag with the specified URL and appends it to the .\n * @param {String} url - resource URL.\n * @return {Promise} - resolves with the script element when it has loaded.\n */\nutil.createScript = function (url) {\n return new Promise(function (resolve, reject) {\n var script = document.createElement('script');\n script.onload = function () {\n return resolve(script);\n };\n script.onerror = function (evt) {\n (0, _metrics.instrument)('script', 'error', { url: (0, _get3.default)(evt, 'currentTarget.src', '').split('?')[0] });\n reject('Script failed to load');\n };\n script.src = url;\n script.async = true;\n document.head.appendChild(script);\n });\n};\n\n/**\n * Recursively strip html tags\n * @param {Object|Array|String} strip - string or object to be stripped\n * @returns {Object|Array|String} - stripped string or object\n */\nutil.stripHTML = function (strip) {\n var stripped = Array.isArray(strip) ? [] : {};\n var div = document.createElement('div');\n\n switch (typeof strip === 'undefined' ? 'undefined' : _typeof(strip)) {\n case 'string':\n div.innerHTML = strip;\n return div.textContent || '';\n case 'object':\n util.each(strip, function (key, val) {\n return stripped[key] = util.stripHTML(val);\n });\n return stripped;\n }\n return strip;\n};\n\n/**\n * @param {Function} Cls - class that should be extended with mixins\n * @param {...Object|Function} mixin - mixin object or mixin factory;\n * if it's a factory, a parent prototype is passed to it to allow calling parent methods\n * @returns A class that is a descendant of Cls and is extended with methods defined in the mixins\n * Examples of usage: see the unit tests\n */\nutil.decorateWithMixins = function (Cls) {\n if (!(0, _isFunction3.default)(Cls)) {\n throw new TypeError(Cls + ' is not a function');\n }\n\n for (var _len = arguments.length, mixins = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n mixins[_key - 1] = arguments[_key];\n }\n\n mixins.forEach(function (mixin, idx) {\n if (mixin === undefined) {\n throw new TypeError('Mixin at position ' + idx + ' is undefined');\n }\n });\n\n var chain = [Cls];\n\n mixins.forEach(function (mixin) {\n var Parent = chain[0];\n\n var Wrapper = function (_Parent) {\n _inherits(Wrapper, _Parent);\n\n function Wrapper() {\n _classCallCheck(this, Wrapper);\n\n return _possibleConstructorReturn(this, (Wrapper.__proto__ || Object.getPrototypeOf(Wrapper)).apply(this, arguments));\n }\n\n return Wrapper;\n }(Parent);\n\n ;\n\n if ((0, _isFunction3.default)(mixin)) {\n mixin = mixin(Parent.prototype);\n }\n Object.assign(Wrapper.prototype, mixin);\n\n chain.unshift(Wrapper);\n });\n\n return chain[0];\n};\n\n/**\n * Returns instance of unique id generator\n * @param {Number} [start=1] - initial value to increment\n * @return {Function} function that increments its counter on each call and returns that value\n */\nutil.idGenerator = function () {\n var start = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;\n\n var id = start;\n return function () {\n return id++;\n };\n};\n\n/**\n * Make `util` service available in external code via `BZFD.App.getService('util')`.\n * This is used in games, @see https://buzzfeed.atlassian.net/browse/SITE-4776\n*/\n_t3js.Application.addService('util', function () {\n return util;\n});\n\nexports.default = util;\n\n/***/ })\n\n},[43]);\n\n\n// WEBPACK FOOTER //\n// js/core.6be85d8b1f3d9c47bc1b.js","import { path as instrumentationPath } from './mapping';\n\nconst VALID_OPTIONS = ['samplingRate'];\n\n/**\n * Increments metric on DataDog.\n * Metric name is constructed from target and value parameters (i.e. 'image.error').\n * @see https://github.com/buzzfeed/mono/blob/master/qr_website_metrics for available metrics and tags.\n * @export\n * @param {String} target - describes what caused metric report.\n * @param {String} value - describes what happened to the metric target.\n * @param {Object?} [tags] - keys and values are metric tag names and values respectively.\n * @param {Object?} [options] - tracking options.\n * @param {Boolean} [options.samplingRate] - forces event to be tracked regardless of sampling configuration.\n * @returns {void}\n * @example instrument('chunk', 'timeout', { name: 'quiz' })\n */\nexport function instrument(target, value, tags = {}, options = {}) {\n if (typeof window.bfa !== 'function') {\n if (typeof window.raven !== 'undefined') {\n window.raven.captureException(new Error('Instrumentation tracking issue: BFA is not available'));\n }\n return;\n }\n\n if (VALID_OPTIONS.some(opt => tags.hasOwnProperty(opt))) {\n options = tags;\n tags = {};\n }\n\n const { samplingRate } = options;\n const trackingData = {\n data: { target, value, tags }\n };\n\n if (samplingRate) {\n if (samplingRate > 1) {\n if (window.BZFD.Config.env === 'dev') {\n console.error('Your sampling rate is above 100%.');\n }\n } else {\n Object.assign(trackingData, { opts: { samplingRate } });\n }\n }\n\n window.bfa(instrumentationPath, trackingData);\n}\n\n\n\n// WEBPACK FOOTER //\n// /~/@buzzfeed/buzzblocks/js/services/metrics/index.js","import { Application } from 't3js';\nimport cookies from '@buzzfeed/buzzblocks/js/services/cookies';\n\n/**\n * Handles interaction and state storage for the bounce policy\n * (the bar that appears in the top of the site)\n *\n * This is 'visible unless the user hides' (I.e. it'll show\n * without JavaScript enabled and is therefore opt-out to hide)\n */\nclass BouncePolicy {\n /**\n * @constructor\n * @param context\n */\n constructor(context) {\n this._element = context.getElement();\n this._bouncePolicyCookie = 'bounce_policy_closed';\n\n if (!this.getIsClosed()) {\n this._element.classList.remove('js-hidden');\n }\n }\n\n /**\n * Finds out if this has been closed already\n * @returns bool\n */\n getIsClosed() {\n return !!cookies.get(this._bouncePolicyCookie, false);\n }\n\n /**\n * Sets the isClosed state on a cookie for a year\n */\n setIsClosed(isClosed) {\n if (isClosed) {\n cookies.set({\n name: this._bouncePolicyCookie,\n value: 'opt-out',\n days: 365,\n domain: window.location.hostname\n });\n } else {\n cookies.remove(this._bouncePolicyCookie, window.location.hostname);\n }\n }\n\n /**\n * Triggers UI animation to close\n */\n closeAnimated() {\n this._element.classList.add('bounce-policy--animation');\n setTimeout(() => this._element.classList.add('js-hidden'), 1000);\n }\n\n /**\n * Handles the on-click behavior\n */\n onclick(e, elem, elemType) {\n if (elemType === 'bounce-close') {\n e.preventDefault();\n this.setIsClosed(true);\n this.closeAnimated();\n }\n return false;\n }\n}\n\nApplication.addModule('bounce-policy', (context) => {\n return new BouncePolicy(context);\n});\n\n\n\n// WEBPACK FOOTER //\n// /app/static/js/modules/bounce-policy.js","import { Application } from 't3js';\nimport ajax from '@buzzfeed/buzzblocks/js/services/ajax';\n\n/**\n * Handles interaction with the buzzfeed login endpoint to provide\n * a more seamless authentication experience\n */\nclass BuzzFeedLogin {\n /**\n * @constructor\n * @param context\n */\n constructor(context) {\n this._element = context.getElement();\n this._fieldset = this._element.querySelector('.fieldset');\n this._feedbackLabel = this._element.querySelector('.form-feedback');\n this._usernameField = this._element.querySelector('[name=username]');\n this._passwordField = this._element.querySelector('[name=password]');\n this._csrfField = this._element.querySelector('[name=\"gorilla.csrf.Token\"]');\n this._onSubmitLock = false;\n }\n\n /**\n * Sets a text error on the form\n * @param errorMsg (string) the message to display\n */\n setError(errorMsg) {\n this._setError();\n this._feedbackLabel.innerText = errorMsg;\n }\n\n /**\n * Sets an HTML error on the form\n * @param errorMsg (string) the HTML template of the message to display\n */\n setHTMLError(errorMsg) {\n this._setError();\n this._feedbackLabel.innerHTML = errorMsg;\n }\n\n /**\n * Shows the error on the form\n */\n _setError() {\n this.resetFeedback();\n this._feedbackLabel.classList.remove('js-hidden');\n this._fieldset.classList.add('form-fieldset--error');\n }\n\n /**\n * Sets an success message on the form\n * @param successMsg (string) the message to display\n */\n setSuccess(successMsg) {\n this.resetFeedback();\n this._feedbackLabel.innerText = successMsg;\n this._feedbackLabel.classList.remove('js-hidden');\n this._fieldset.classList.add('form-fieldset--success');\n }\n\n /**\n * Set Loading\n */\n setLoading() {\n this.resetFeedback();\n this._fieldset.classList.add('form-fieldset--loading');\n }\n\n /**\n * Set Loaded\n */\n setLoaded() {\n this.resetFeedback();\n this._fieldset.classList.remove('form-fieldset--loading');\n }\n\n /**\n * Removes error/success messages from the form\n */\n resetFeedback() {\n this._feedbackLabel.innerText = '';\n this._feedbackLabel.classList.add('js-hidden');\n this._fieldset.classList.remove('form-fieldset--error');\n this._fieldset.classList.remove('form-fieldset--success');\n }\n\n /**\n * Listens to all module click events, if it is a click on the\n * button login then trigger onSubmit\n */\n onclick(e, elem, elemType) {\n if (elemType === 'login') {\n e.preventDefault();\n this.onSubmit();\n }\n return false;\n }\n\n /**\n * Triggered when the form button is clicked via onclick\n * Handles the XHR\n */\n onSubmit() {\n if (this._onSubmitLock) {\n return Promise.resolve();\n }\n this._onSubmitLock = true;\n this.setLoading();\n\n const username = encodeURIComponent(this._usernameField.value);\n const password = encodeURIComponent(this._passwordField.value);\n const csrf = encodeURIComponent(this._csrfField.value);\n const buzzfeedLoginEndpoint = '/auth/login/buzzfeed';\n\n return ajax.post(buzzfeedLoginEndpoint, {\n type: 'json',\n data: {\n 'gorilla.csrf.Token': csrf,\n username,\n password,\n },\n })\n .then(response => {\n this.setLoaded();\n this._onSubmitLock = false;\n if (response.error) {\n if (response.html) {\n this.setHTMLError(response.html);\n } else {\n this.setError(response.error);\n }\n return;\n }\n if (response.success) {\n this.setSuccess(response.success);\n window.location = window.redirectUri || '/';\n return;\n }\n })\n .catch(() => {\n this._onSubmitLock = false;\n this.setLoaded();\n this.setError('unexpected error occurred');\n });\n };\n}\n\nApplication.addModule('buzzfeed-login', (context) => {\n return new BuzzFeedLogin(context);\n});\n\n\n\n// WEBPACK FOOTER //\n// /app/static/js/modules/buzzfeed-login.js","import getSentry from '@buzzfeed/buzzblocks/js/services/sentry';\n\ngetSentry({\n env: window.Config.env,\n canary: window.Config.canaryDeploy,\n url: window.Config.sentryUrl,\n sampleRate: 0.05,\n ignoreErrors: []\n});\n\n\n\n// WEBPACK FOOTER //\n// /app/static/js/tracking/sentry.js","module.exports = __webpack_public_path__ + \"img/apple-touch-icon.186faa454878ee0d6582ba33b41d2044.png\";\n\n\n//////////////////\n// WEBPACK FOOTER\n// /~/@buzzfeed/buzzblocks/img/apple-touch-icon.png\n// module id = 40\n// module chunks = 1","module.exports = __webpack_public_path__ + \"img/buzzfeed-webapp-logo.0ea3c59fd2aeb164cfdfe77e74ab3aa2.png\";\n\n\n//////////////////\n// WEBPACK FOOTER\n// /~/@buzzfeed/buzzblocks/img/buzzfeed-webapp-logo.png\n// module id = 41\n// module chunks = 1","module.exports = __webpack_public_path__ + \"img/favicon.5a0c77a8815cfcc67c710199054a55c6.ico\";\n\n\n//////////////////\n// WEBPACK FOOTER\n// /~/@buzzfeed/buzzblocks/img/favicon.ico\n// module id = 42\n// module chunks = 1","/**\n * @fileoverview\n * Webpack entry for enhanced-ux version only.\n * Loads all components and initializes the application.\n */\nimport { Application } from 't3js';\n\nimport '../sass/critical.scss';\n\nimport '@buzzfeed/buzzblocks/img/favicon.ico';\nimport '@buzzfeed/buzzblocks/img/apple-touch-icon.png';\nimport '@buzzfeed/buzzblocks/img/buzzfeed-webapp-logo.png';\n\nimport './tracking/sentry';\n\nimport './modules/buzzfeed-login.js';\nimport './modules/bounce-policy.js';\n\nfunction App() {\n const startT3 = function(config) {\n Application.init(config);\n };\n\n return {\n init: function() {\n const config = {\n debug: true\n };\n if (document.readyState === 'complete' ||\n (document.readyState !== 'loading' && !document.documentElement.doScroll)) {\n startT3(config);\n } else {\n document.addEventListener('DOMContentLoaded', function() {\n startT3(config);\n });\n }\n },\n getService: Application.getService.bind(Application),\n on: Application.on.bind(Application),\n off: Application.off.bind(Application),\n broadcast: Application.broadcast.bind(Application),\n startAll: Application.startAll.bind(Application),\n start: Application.start.bind(Application)\n };\n}\n\n// start app\nwindow.App = new App();\nwindow.App.init();\n\n\n\n// WEBPACK FOOTER //\n// /app/static/js/core-entry.js","/**\n * Bare minimum fetch polyfill in 500 bytes.\n * @see https://github.com/developit/unfetch\n */\nimport fetch from 'unfetch';\nimport { instrument } from '../metrics';\n/**\n * A simple JSONP implementation\n * @see https://github.com/webmodules/jsonp\n */\nimport jsonp from 'jsonp';\nimport util from '../util';\n\n/**\n * Creates a promise, which is rejected after a specified timeout.\n * @param {Number} timeout - number of milliseconds to wait until promise is rejected.\n */\nfunction rejectOnTimeout(timeout) {\n return new Promise((_, reject) => {\n setTimeout(() => reject({ type: 'timeout', msg: `${timeout}ms timeout exceeded` }), timeout);\n });\n}\n\nfunction errorHandler({ url }) {\n return err => {\n instrument('xhr', err.type || 'error', { url, status: err.status || 0 });\n return Promise.reject(err);\n };\n}\n\n/**\n * Promisifies the jsonp implementation\n * @param {String} requestUrl - the request url to be passed to jsonp.\n * @return {Promise} - a promise resolved with the response.\n */\nfunction fetchWithJsonp(requestUrl) {\n return new Promise((resolve, reject) => {\n jsonp(requestUrl, (err, response) => {\n if (err) {\n return reject(err);\n }\n return resolve(response);\n });\n });\n}\n\n/**\n * Checks response status code.\n * Resolves when status code is within 200-300 range.\n * Rejects otherwise.\n * @param {Response} response - response object.\n */\nfunction status(response) {\n if (response.ok) {\n return Promise.resolve(response);\n } else {\n return Promise.reject({ type: 'error', status: response.status, statusText: response.statusText });\n }\n}\n\n/**\n * Converts response to JSON.\n * @param {Response} response - response object.\n */\nfunction toJson(response) {\n return response.json();\n}\n\n/**\n * Converts response to plain text.\n * @param {Response} response - response object.\n */\nfunction toText(response) {\n return response.text();\n}\n\nexport default {\n /**\n * Performs a GET request to a specified endpoint.\n * @param {String} url - resource URL.\n * @param {Object} options - request options.\n * @param {Object} [options.data={}] - request parameters, are being included in the URL.\n * @param {String} [options.type=json] - expected response type.\n * @param {Object} [options.params={}] - additional fetch parameters.\n * @param {Boolean} [options.skipAuth=false] - flag to add basic auth bypass token to the resource URL.\n * @param {Number} [options.timeout] - maximum time in milliseconds for a request to complete.\n * @return {Promise} - a promise resolved with the response body.\n */\n get(url, { type = 'json', data = {}, params = {}, skipAuth, timeout } = {}) {\n if (!url) {\n return Promise.reject('URL parameter is required');\n }\n\n let result;\n const options = Object.assign({\n credentials: 'same-origin'\n }, params);\n\n let requestUrl = util.prepareUrl(url, data);\n\n if (skipAuth) {\n // @todo remove from util.js service once ajax.js is deprecated\n requestUrl = util.authBypassWrapper(requestUrl);\n }\n\n switch(type) {\n case 'json':\n result = fetch(requestUrl, options).then(status).then(toJson);\n break;\n case 'text':\n result = fetch(requestUrl, options).then(status).then(toText);\n break;\n case 'jsonp':\n result = fetchWithJsonp(requestUrl);\n break;\n default:\n result = Promise.reject(`Unsupported type ${type}`);\n }\n\n return (timeout ? Promise.race([rejectOnTimeout(timeout), result]) : result)\n .catch(errorHandler({ url }));\n },\n\n /**\n * Performs a POST request to a specified endpoint.\n * @param {String} url - resource URL.\n * @param {Object} options - request options.\n * @param {Object} options.data - request parameters, are being included in the request body.\n * @param {String} [options.type=json] - expected response type.\n * @param {String} [options.params={}] - additional fetch parameters.\n * @param {Boolean} [options.raw=false] - flag to disable converting request parameters to query string key value pairs.\n * @param {Number} [options.timeout] - maximum time in milliseconds for a request to complete.\n * @return {Promise} - a promise resolved with the response body.\n */\n post(url, { data, type = 'json', params = {}, raw = false, timeout } = {}) {\n\n if (!url) {\n return Promise.reject('URL parameter is required');\n }\n\n if (!data) {\n return Promise.reject('Can not send POST request without data');\n }\n\n let result;\n const options = Object.assign({\n headers: {\n 'Content-type': 'application/x-www-form-urlencoded'\n },\n credentials: 'same-origin'\n }, params);\n\n options.method = 'POST';\n options.body = raw ? data : util.toQueryString(data);\n\n switch(type) {\n case 'json':\n result = fetch(url, options).then(status).then(toJson);\n break;\n case 'text':\n result = fetch(url, options).then(status).then(toText);\n break;\n default:\n result = Promise.reject(`Unsupported type ${type}`);\n }\n\n return (timeout ? Promise.race([rejectOnTimeout(timeout), result]) : result)\n .catch(errorHandler({ url }));\n }\n};\n\n\n\n// WEBPACK FOOTER //\n// /~/@buzzfeed/buzzblocks/js/services/ajax/index.js","/**\n * Returns full regex match, or null if no match\n * @param {String} value, the string which may match *pattern*\n * @param {String} pattern, regex string\n * @returns {String?}\n */\nfunction getFullMatch(value, pattern) {\n const matches = value.match(pattern);\n return (matches && matches.length) ? matches[0] : null;\n}\n\n/**\n * Gives the current hostname, good for mocking purposes\n * @returns {String} hostname\n */\nfunction getCurrentHostname() {\n return window.location.hostname;\n}\n\n/**\n * Gives the domain based on the environment\n * @returns {String} domain\n */\nfunction getCookieDomain() {\n return window.BZFD.Config.env === 'prod' ? 'buzzfeed.com' : getCurrentHostname();\n}\n\nexport default {\n\n /**\n * Returns domain based on *hostname*.\n * Prefers buzzfeed.com subdomain.\n * Returns generic domain if not a buzzfeed dev|stage|www subdomain.\n * @param hostname {String}\n * @returns {String}\n */\n getBuzzfeedSubdomainOrWildcard(hostname) {\n const subdomainMatch = getFullMatch(hostname, '(dev|stage|www).buzzfeed.(com|io)$');\n if (subdomainMatch) {\n return subdomainMatch;\n }\n\n return getFullMatch(hostname, '.?[a-z]+.[a-z]+$');\n },\n\n /**\n * Gets cookie value by name.\n * @param {String} name - cookie name.\n * @param {Object} [defaultValue] - value to return if cookie is not presented.\n * @returns {?Object} - value of the specified cookie or default.\n */\n get(name, defaultValue = null) {\n const nameEQ = `${name}=`;\n const ca = document.cookie.split(';');\n\n for (let i = 0; i < ca.length; i++) {\n let c = ca[i];\n while (c.charAt(0) === ' ') {\n c = c.substring(1, c.length);\n }\n if (c.indexOf(nameEQ) === 0) {\n return c.substring(nameEQ.length, c.length);\n }\n }\n return defaultValue;\n },\n\n /**\n * Creates cookie with specified properties.\n * @param {Object} args - options for creating a cookie.\n * @param {String} args.name - cookie name.\n * @param {Object} args.value - cookie value.\n * @param {Number} [args.days] - number of days until cookie expires.\n * @param {String} args.domain - the domain to set cookie on\n * @returns {String} document.cookie to be set\n */\n set({ name, value, days, domain }) {\n domain = domain || getCookieDomain();\n let exp = '';\n if (days) {\n let date = new Date();\n date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);\n exp = `; expires=${date.toGMTString()}`;\n }\n\n return document.cookie = `${name}=${value}${exp}; path=/; domain=${domain}`;\n },\n\n /**\n * Removes cookie by name.\n * Sets expiration date on yesterday.\n * @param {String} name - cookie name.\n * @param {String} domain - the hostname of the cookie.\n * @returns {void}\n */\n remove(name, domain = getCookieDomain()) {\n return this.set({\n name,\n value: '',\n days: -1,\n domain: domain\n });\n }\n};\n\n\n\n// WEBPACK FOOTER //\n// /~/@buzzfeed/buzzblocks/js/services/cookies/index.js","import { get } from 'lodash';\nconst target = 'target';\nconst value = 'value';\nconst tags = 'tags';\n\nexport const path = 'track/website/instrumentation';\n\nexport function map(mapper) {\n const mapping = mapper.getOrCreateMap(path);\n mapping.addMapTo('type', 'instrumentation');\n mapping.addMapTo('platform', '').mapFrom('data.page.platform');\n mapping.addMapTo('edition', '').mapFrom('data.page.country');\n mapping.addMapTo('category', '').mapFrom(src => get(src, 'data.page.category') || 'home');\n mapping.addMapTo(target, '').mapFrom(`data.${target}`);\n mapping.addMapTo(value, '').mapFrom(`data.${value}`);\n mapping.addMapTo(tags, '').mapFrom(src => JSON.stringify(get(src, `data.${tags}`, '')));\n\n return mapping;\n};\n\n\n\n// WEBPACK FOOTER //\n// /~/@buzzfeed/buzzblocks/js/services/metrics/mapping.js","import raven from 'raven-js';\n\nconst PROD_SAMPLE_RATE = 0.2;\nconst defaultWhitelistUrls = [ /\\/static-assets\\// ];\nconst sentryDebugMode = window.location.search.indexOf('sentrydebug') > -1;\n\n/**\n * Initialize Sentry for JS error reporting.\n * Sentry is only initialized in production.\n * This also sets raven as a global for access by embeds etc.\n * @export\n * @param {Object} params\n * @param {string} params.url - The sentry unique url\n * @param {string} params.env? - The runtime environment\n * @param {string} params.canary? - Is the deployment type canary?\n * @param {string} params.sampleRate? - The rate at which you sample errors (0 - 1)\n * @param {array} params.whitelistUrls? - An array of URL strings that you want to collect errors on\n * @param {array} params.ignoreErrors? - An array of strings or regexes that you want to ignore\n * @param {array} params.dataCallback? - A transformation function to be run before sending\n * @returns {raven} - the raven-js library\n * @example sentry({ url: 'https://some.url', env: 'dev' })\n */\nexport default function({\n url,\n env = window.BZFD.Config.env,\n canary = window.BZFD.Config.canaryDeploy,\n sampleRate = PROD_SAMPLE_RATE,\n whitelistUrls = defaultWhitelistUrls,\n ignoreErrors = [],\n dataCallback = data => data\n }) {\n\n if (!url && env === 'dev') {\n throw new Error('Missing sentry url. More info: http://bit.ly/2v9diir');\n }\n\n if (env !== 'prod' && !sentryDebugMode) {\n return;\n }\n\n raven.config(url, {\n whitelistUrls,\n ignoreErrors,\n shouldSendCallback: () => {\n if (sentryDebugMode) {\n return true;\n }\n return (Math.random() <= sampleRate);\n },\n dataCallback\n })\n .setTagsContext({ canary })\n .install();\n\n window.raven = raven;\n return raven; // eslint-disable-line consistent-return\n}\n\n\n\n// WEBPACK FOOTER //\n// /~/@buzzfeed/buzzblocks/js/services/sentry/index.js","/* global BZFD */\n\nimport { Application } from 't3js';\nimport { get, isFunction } from 'lodash';\nimport { instrument } from '../metrics';\n\n/**\n * Service with some general widely used functions\n */\nvar util = {};\n\n/**\n * Gets a list of object's enumerable property names.\n * @param {Object} obj - target object.\n * @return {Array} - list of object's keys.\n */\nutil.getKeys = function(obj) {\n var res;\n if (Object.keys) {\n return Object.keys(obj);\n } else {\n res = [];\n for (var key in obj) {\n if (obj.hasOwnProperty(key)) {\n res.push(key);\n }\n }\n return res;\n }\n};\n\n/**\n * Adds module's element id attribute value to the event name.\n * @param {String} origName - original event name.\n * @param {HTMLElement} moduleEl - module's DOM element.\n * @return {String} - name with id value.\n */\nutil.getUniqueEventName = function(origName, moduleEl) {\n return origName + '-' + moduleEl.id;\n};\n\nutil.capitalize = function(str) {\n if (typeof str !== 'string') {\n return str;\n } else {\n return str.replace(/\\w+/g, function(a) {\n return a.charAt(0).toUpperCase() + a.substr(1).toLowerCase();\n });\n }\n};\n\nutil.authBypassWrapper = function(url) {\n if (BZFD.Config.env === 'dev') {\n var hash = 'eca385331012a621bc93fcda0a953a97';\n var char = '?';\n\n if (util.hasQueryString(url)) {\n char = '&';\n }\n\n url += (char + hash);\n }\n\n return url;\n};\n\nutil.hasQueryString = function(url) {\n return url.indexOf('?') > -1;\n};\n\nutil.removeHash = function(url) {\n url = url + ''; // Convert object to string, if necessary\n if (url.indexOf('#') > -1) {\n return url.substr(0, url.indexOf('#'));\n }\n return url;\n};\n\nutil.removeQueryString = function(url) {\n url = url + ''; // Convert object to string, if necessary\n if (url.indexOf('?') > -1) {\n if (url.indexOf('#') === -1) {\n return url.substr(0, url.indexOf('?'));\n }\n return url.substr(0, url.indexOf('?')) + url.substr('#', url.length);\n }\n return url;\n};\n\nutil.getQueryString = function(url) {\n url = util.removeHash(url);\n var querystring = '';\n if (url.indexOf('?') > -1) {\n querystring = url.substr(url.indexOf('?'), url.length); // Contains '?'\n }\n return querystring;\n};\n\nutil.getHash = function(url) {\n url = url + ''; // Convert object to string, if necessary\n if (url.indexOf('#') > -1) {\n return url.substr(url.indexOf('#'), url.length);\n }\n return '';\n};\n\nutil.queryStringToObject = function(qs) { // Without '?'\n if (qs === '' || qs === undefined || qs === null) {\n return {};\n }\n var params = qs.split('&');\n var pair;\n var obj = {};\n\n util.each(params, function(i, val) {\n pair = val.split('=');\n if (pair[1] === '') {\n pair[1] = null;\n }\n obj[pair[0]] = pair[1];\n });\n return obj;\n};\n\nutil.objectToQueryString = function(qs) {\n var str = [];\n util.each(qs, function(key, val) {\n str.push(key + '=' + val);\n });\n return '?' + str.join('&');\n};\n\nutil.getBaseUrl = function(url) {\n url = util.removeHash(url);\n url = util.removeQueryString(url);\n return url;\n};\n\nutil.addParams = function(url, keyvals) {\n var qs = util.getQueryString(url); // Contains '?'\n var hash = util.getHash(url); // Contains '#'\n var key;\n var val;\n\n url = util.removeHash(url);\n url = util.removeQueryString(url);\n\n qs = util.queryStringToObject(qs.substr(1, qs.length)); // no '?'\n\n util.each(keyvals, function(i, keyval) {\n key = keyval[0];\n val = keyval[1];\n qs[key] = val;\n });\n\n return url + util.objectToQueryString(qs) + hash;\n};\n\n/**\n * Remove given parameters from a URL string.\n * @param {string} url - a url\n * @param {Array} keys - an array of keys to be deleted\n * @return {string} url - the url without the given params\n */\nutil.removeParams = function(url, keys) {\n var base = util.getBaseUrl(url);\n var qs = util.getQueryString(url);\n var hash = util.getHash(url);\n var params = util.queryStringToObject(qs.substr(1, qs.length));\n\n util.each(keys, function(i, key) {\n delete params[key];\n });\n\n return base + util.objectToQueryString(params) + hash;\n};\n\nutil.prepareUrl = function(url, data) {\n // Append parameter(s) to url\n var keyvals = [];\n\n util.each(data, function(key, val) {\n if (typeof val === 'undefined') {\n return;\n }\n keyvals.push([\n key,\n encodeURIComponent(val),\n ]);\n });\n\n return util.addParams(url, keyvals);\n};\n\nutil.redirect = function(url) {\n if (typeof url === 'string' && url) {\n window.location.href = url;\n }\n};\n\nutil.openPopup = function(url, options) {\n if (typeof url === 'string' && url) {\n var name = '_blank';\n var wparams = '';\n\n if (options && options.height && options.width) {\n var sTop = (window.screen.height / 2) - (options.height / 2);\n var sLeft = (window.screen.width / 2) - (options.width / 2);\n wparams = 'scrollbars=yes, toolbar=0, status=0, width=' + options.width + ', height=' + options.height + ', top=' + sTop + ', left=' + sLeft;\n name = options.name ? options.name : name;\n }\n window.open(url, name, wparams);\n }\n};\n\n/**\n * A generic iterator function, which can be used to seamlessly iterate over both objects\n * and arrays.\n * @todo reorder arguments when iterating an array to match Array.prototype.forEach behavior\n */\nutil.each = (iterable, callback) => {\n if (Array.isArray(iterable)) {\n iterable.forEach((item, idx) => callback(idx, item));\n } else {\n for (let key in iterable) {\n if (iterable.hasOwnProperty(key)) {\n callback(key, iterable[key]);\n }\n }\n }\n};\n\nutil.extend = require('lodash/merge');\n\n/**\n *\n * @return {Object} - map of query parameters keys and values\n */\nutil.getQueryParams = function() {\n var search = window.location.search.substring(1);\n var result = {};\n if (search) {\n search.split('&').forEach(function(param) {\n var p = param.split('=');\n var key = decodeURIComponent(p[0]);\n var value = decodeURIComponent(p.slice(1).join('='));\n result[key] = value;\n });\n }\n\n return result;\n};\n\n/**\n * Adds query parameter to the end of provided URL string.\n * @param {String} [url=location.href] - target URL string.\n * @param {String} key - parameter name.\n * @param {String} val - parameter value.\n * @return {String} - url with specified parameter at the end.\n */\nutil.addQueryParam = function(url, key, val) {\n url = url || window.location.href;\n return url + (url.split('?')[1] ? '&' : '?') + (key + '=' + val);\n};\n\n/* eslint-disable max-len */\n/**\n * Change number into shortened format.\n * Example: 125 -> 125; 3456 -> 3,456; 10355 -> 10,4K; 1100123 -> 1.1M;\n * Adapted from\n * https://stackoverflow.com/questions/3177855/how-to-format-numbers-similar-to-stack-overflow-reputation-format\n * @param {Number} val - number to be formatted\n * @returns {String} shortened number\n */\n/* eslint-enable max-len */\nutil.largeNumberNotation = function(val) {\n if (val < 1000) {\n return val;\n } else if (val < 10000) {\n return val.toString().charAt(0) + ',' + val.toString().substring(1);\n } else if (val >= 1000000) {\n return (val / 1000000).toFixed(val % 1000000 !== 0) + 'M';\n }\n return (val / 1000).toFixed(val % 1000 !== 0) + 'K';\n};\n\n/* eslint-disable max-len */\n/**\n * Splits number with comma by thousands\n * @param {Number} num - number to be formatted\n * @returns {String} - number with commas\n * eslint-disable max-len\n * @see http://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript\n * eslint-enable max-len\n */\nutil.numberWithCommas = function(num) {\n return num.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n};\n\n/**\n * Returns the smallest of numbers.\n * @return {Number} - smallest number.\n */\nutil.min = function(/*[value1[, value2[, ...]]]*/) {\n return Math.min.apply(Math, Array.prototype.filter.call(arguments, function(n) {\n return !isNaN(+n);\n }));\n};\n\n/**\n * Converts object to query string params.\n * @param {Object} obj - target object.\n * @return {string} - query string.\n */\nutil.toQueryString = function(obj) {\n var res = [];\n this.each(obj, function(k, v) {\n if (v !== null && v !== '' && typeof v !== 'undefined') {\n res.push(k + '=' + v);\n }\n });\n return res.join('&');\n};\n\n/**\n * Gets a handler for internal events for T3 modules and behaviors.\n * @param {Object} handlerMap - handlers map (key is a message name, value is a handler).\n * @return {Function} - handler for T3 onmessage method.\n */\nutil.getMessageHandler = function(handlerMap) {\n return function(name, data) {\n var handler = handlerMap[name];\n if (typeof handler === 'function') {\n handler.call(this, data);\n }\n };\n};\n\n/**\n * Gets a handler for DOM events for T3 modules and behaviors.\n * @param {Object} handlerMap - handlers map\n * (key is a dataType attribute of the target element, value is a handler).\n * @return {Function} - handler for native DOM events in T3.\n */\nutil.getEventHandler = function(handlerMap) {\n return function(ev, el, elType) {\n var handler = handlerMap[elType];\n if (typeof handler === 'function') {\n handler.call(this, ev, el);\n }\n };\n};\n\n/**\n * Adds leading symbols to a string.\n * @param {String} src - string to pad.\n * @param {String} sym - symbol to add to the src string.\n * @param {Number} len - required result string length.\n * @return {String} - padded src string.\n */\nutil.padLeft = function(src, sym, len) {\n var str = src.toString();\n var targetLength = len - str.length;\n var acc = '';\n\n for (var i = 0; i < targetLength; i++) {\n acc += sym;\n }\n\n return acc + src;\n};\n\n\n/**\n * Converts string into small caps\n * @param {String} str - string to convert.\n * @return {String} - converted string.\n */\nutil.freeFormFormat = function(str) {\n var uglyStr = str\n .replace(/[\"'\"“’ ]/g, '')\n .toLowerCase();\n\n return uglyStr;\n};\n\n/**\n * Returns time since text\n * @param {String} date - date string in UTC format `yy:mm:ddThh:mm:ssZ`\n * @return {Object} time since object {'type': '', 'value': '', 'text': ''}\n */\nutil.timeSince = function(date) {\n var baseFormat = {\n 'year': ['year', 'years', ],\n 'month': ['month', 'months', ],\n 'day': ['day', 'days', ],\n 'hour': ['hour', 'hours', ],\n 'minute': ['minute', 'minutes', ],\n 'justNow': ['just now', ],\n };\n var interval;\n var seconds = Math.floor(((new Date()).getTime() - (new Date(date)).getTime()) / 1000);\n\n interval = Math.floor(seconds / 31536000);\n\n if (interval >= 1) {\n return {\n 'type': 'year',\n 'value': interval,\n 'text': interval + ' ' + (interval === 1 ? baseFormat.year[0] : baseFormat.year[1]) + ' ago'\n };\n }\n\n interval = Math.floor(seconds / 2592000);\n\n if (interval >= 1) {\n return {\n 'type': 'month',\n 'value': interval,\n 'text': interval + ' ' + (interval === 1 ? baseFormat.month[0] : baseFormat.month[1]) + ' ago'\n };\n }\n\n interval = Math.floor(seconds / 86400);\n\n if (interval >= 1) {\n return {\n 'type': 'day',\n 'value': interval,\n 'text': interval + ' ' + (interval === 1 ? baseFormat.day[0] : baseFormat.day[1]) + ' ago'\n };\n }\n\n interval = Math.floor(seconds / 3600);\n\n if (interval >= 1) {\n return {\n 'type': 'hour',\n 'value': interval,\n 'text': interval + ' ' + (interval === 1 ? baseFormat.hour[0] : baseFormat.hour[1]) + ' ago'\n };\n }\n\n interval = Math.floor(seconds / 60);\n\n if (interval > 1) {\n return {\n 'type': 'minute',\n 'value': interval,\n 'text': interval + ' ' + (interval === 1 ? baseFormat.minute[0] : baseFormat.minute[1]) + ' ago'\n };\n }\n\n return {\n 'type': 'now',\n 'value': '',\n 'text': baseFormat.justNow[0]\n };\n};\n\nutil.bulkDelete = function(fields, object) {\n util.each(fields, function(i, val) {\n delete object[val];\n });\n};\n\n/**\n * Send data to BF Analytics\n * Example:\n * @param {String} bfaRoute - the route for bfa ex. 'track/click/share'\n * @param {Object} bfaData - formatted object ex. {t:'click:share-button', d:'Facebook'}\n * @returns void\n */\nexport function bfaTrack(bfaRoute, bfaData = {}) {\n if (!window.bfa || !(window.bfa instanceof Function) || !window.bfaBinder) {\n return;\n }\n\n window.bfa(bfaRoute, bfaData);\n};\nutil.bfaTrack = bfaTrack;\n\n/**\n * Checks for screen orientation\n * @return {String} `portrait` or '`landscape`\n */\nexport function getScreenOrientation() {\n if (screen.orientation && screen.orientation.type) {\n return screen.orientation.type.replace('-primary', '');\n } else if (window.orientation) {\n if (Math.abs(window.orientation) === 90) {\n return 'landscape';\n } else {\n return 'portrait';\n }\n } else if (window.matchMedia) {\n if (window.matchMedia('(orientation: portrait)').matches) {\n return 'portrait';\n } else if (window.matchMedia('(orientation: landscape)').matches) {\n return 'landscape';\n }\n }\n\n return 'landscape';\n};\nutil.getScreenOrientation = getScreenOrientation;\n\n/**\n * Checks browser user agent to detect ipad device\n * @return {Boolean} `true` if ipad device detected, `false` otherwise\n */\nutil.isIOSIPad = (function() {\n var agent = navigator.userAgent.toLowerCase();\n\n if (agent.match(/ipad/)) {\n return true;\n }\n\n return false;\n})();\n\n/**\n * Checks browser user agent to detect iphone|ipod device\n * @return {Boolean} `true` if iphone|ipod device detected, `false` otherwise\n */\nutil.isIOSMobile = (function() {\n var agent = navigator.userAgent.toLowerCase();\n\n if (agent.match(/iphone|ipod/)) {\n return true;\n }\n\n return false;\n})();\n\n/**\n * Checks browser user agent to detect iOS device.\n * This is not a reliable long-term method for detecting iOS and should be used sparingly.\n * @return {Boolean} `true` if iOS device detected, `false` otherwise\n */\nexport const isIOS = (() => util.isIOSIPad || util.isIOSMobile)();\nutil.isIOS = isIOS;\n\n/**\n * Creates a script tag with the specified URL and appends it to the .\n * @param {String} url - resource URL.\n * @return {Promise} - resolves with the script element when it has loaded.\n */\nutil.createScript = url => {\n return new Promise((resolve, reject) => {\n let script = document.createElement('script');\n script.onload = () => resolve(script);\n script.onerror = evt => {\n instrument('script', 'error', { url: get(evt, 'currentTarget.src', '').split('?')[0] });\n reject('Script failed to load');\n };\n script.src = url;\n script.async = true;\n document.head.appendChild(script);\n });\n};\n\n/**\n * Recursively strip html tags\n * @param {Object|Array|String} strip - string or object to be stripped\n * @returns {Object|Array|String} - stripped string or object\n */\nutil.stripHTML = strip => {\n var stripped = Array.isArray(strip) ? [] : {};\n var div = document.createElement('div');\n\n switch (typeof strip) {\n case 'string':\n div.innerHTML = strip;\n return div.textContent || '';\n case 'object':\n util.each(strip, (key, val) => stripped[key] = util.stripHTML(val));\n return stripped;\n }\n return strip;\n};\n\n/**\n * @param {Function} Cls - class that should be extended with mixins\n * @param {...Object|Function} mixin - mixin object or mixin factory;\n * if it's a factory, a parent prototype is passed to it to allow calling parent methods\n * @returns A class that is a descendant of Cls and is extended with methods defined in the mixins\n * Examples of usage: see the unit tests\n */\nutil.decorateWithMixins = function(Cls, ...mixins) {\n if (!isFunction(Cls)) {\n throw new TypeError(`${Cls} is not a function`);\n }\n mixins.forEach((mixin, idx) => {\n if (mixin === undefined) {\n throw new TypeError(`Mixin at position ${idx} is undefined`);\n }\n });\n\n const chain = [Cls];\n\n mixins.forEach((mixin) => {\n const Parent = chain[0];\n\n class Wrapper extends Parent {};\n\n if (isFunction(mixin)) {\n mixin = mixin(Parent.prototype);\n }\n Object.assign(Wrapper.prototype, mixin);\n\n chain.unshift(Wrapper);\n });\n\n return chain[0];\n};\n\n/**\n * Returns instance of unique id generator\n * @param {Number} [start=1] - initial value to increment\n * @return {Function} function that increments its counter on each call and returns that value\n */\nutil.idGenerator = function(start = 1) {\n let id = start;\n return () => id++;\n};\n\n\n/**\n * Make `util` service available in external code via `BZFD.App.getService('util')`.\n * This is used in games, @see https://buzzfeed.atlassian.net/browse/SITE-4776\n*/\nApplication.addService('util', () => util);\n\nexport default util;\n\n\n\n// WEBPACK FOOTER //\n// /~/@buzzfeed/buzzblocks/js/services/util/index.js"],"sourceRoot":""}