mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Popups
synced 2024-12-11 23:36:07 +00:00
c44fddf8cd
I6a38a261 made the eventLogging change listener count and discard duplicate events and count duplicate tokens. While we isolate the issue(s) that lead to duplication (reuse, likely) of tokens, make the eventLogging change listener discard events with duplicate tokens as well. Bug: T161769 Bug: T163198 Change-Id: I0dbb16c37814d39d7aec35c8fb7cc7309704c550
1 line
159 KiB
Plaintext
1 line
159 KiB
Plaintext
{"version":3,"sources":["/w/extensions/Popups/webpack/bootstrap 428748b32b78b4924f3e","/w/extensions/Popups/./~/redux-thunk/dist/redux-thunk.js","/w/extensions/Popups/./~/redux/dist/redux.js","/w/extensions/Popups/./src/actionTypes.js","/w/extensions/Popups/./src/actions.js","/w/extensions/Popups/./src/changeListener.js","/w/extensions/Popups/./src/changeListeners/eventLogging.js","/w/extensions/Popups/./src/changeListeners/footerLink.js","/w/extensions/Popups/./src/changeListeners/index.js","/w/extensions/Popups/./src/changeListeners/linkTitle.js","/w/extensions/Popups/./src/changeListeners/render.js","/w/extensions/Popups/./src/changeListeners/settings.js","/w/extensions/Popups/./src/changeListeners/statsv.js","/w/extensions/Popups/./src/changeListeners/syncUserSettings.js","/w/extensions/Popups/./src/constants.js","/w/extensions/Popups/./src/counts.js","/w/extensions/Popups/./src/gateway/mediawiki.js","/w/extensions/Popups/./src/gateway/rest.js","/w/extensions/Popups/./src/getTitle.js","/w/extensions/Popups/./src/index.js","/w/extensions/Popups/./src/isEnabled.js","/w/extensions/Popups/./src/preview/model.js","/w/extensions/Popups/./src/previewBehavior.js","/w/extensions/Popups/./src/processLinks.js","/w/extensions/Popups/./src/reducers/eventLogging.js","/w/extensions/Popups/./src/reducers/index.js","/w/extensions/Popups/./src/reducers/nextState.js","/w/extensions/Popups/./src/reducers/preview.js","/w/extensions/Popups/./src/reducers/settings.js","/w/extensions/Popups/./src/reducers/statsv.js","/w/extensions/Popups/./src/renderer.js","/w/extensions/Popups/./src/schema.js","/w/extensions/Popups/./src/settingsDialog.js","/w/extensions/Popups/./src/statsvInstrumentation.js","/w/extensions/Popups/./src/userSettings.js","/w/extensions/Popups/./src/wait.js"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA,mDAA2C,cAAc;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;AChEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,oCAAoC;AACpC;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAuB;AACvB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;;AAEA;;;AAGA,OAAO;AACP;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,CAAC;AACD,C;;;;;;;AC1FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,oCAAoC;AACpC;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAuB;AACvB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,uCAAuC,uCAAuC,kBAAkB;;AAEhG;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,OAAO;AACP;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,YAAY;AACxB,cAAc,SAAS;AACvB;AACA;AACA;;AAEA;AACA,mEAAmE,aAAa;AAChF;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;;AAEA,OAAO;AACP;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,uCAAuC,uCAAuC,kBAAkB;;AAEhG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA,YAAY,IAAI;AAChB;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,cAAc,MAAM;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,gBAAgB,IAAI;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,SAAS;AACvB,gBAAgB,SAAS;AACzB;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,OAAO;AACrB;AACA;AACA;AACA;AACA;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;;AAEA;AACA,oBAAoB,sBAAsB;AAC1C;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,SAAS;AACvB,gBAAgB;AAChB;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,yBAAyB;AACxC;;AAEA;AACA;AACA,gBAAgB,WAAW;AAC3B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,kBAAkB,OAAO;AACzB;AACA,oBAAoB,aAAa;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,iBAAiB;AACjB;AACA,MAAM;AACN;AACA,MAAM;AACN;;AAEA;AACA;AACA;AACA,aAAa,yBAAyB;;AAEtC;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA,OAAO;AACP;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,OAAO;AACnB,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA,OAAO;AACP;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,EAAE;AACd,cAAc,QAAQ;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,iBAAiB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;;AAGA,OAAO;AACP;AACA;;AAEA;;AAEA;;AAEA,oDAAoD,gBAAgB,sBAAsB,OAAO,2BAA2B,0BAA0B,yDAAyD,2BAA2B,EAAE,EAAE,EAAE,eAAe;;AAE/P;;AAEA;;AAEA;;AAEA,uCAAuC,uCAAuC,kBAAkB;;AAEhG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,YAAY;AACxB,cAAc,SAAS;AACvB;AACA;AACA,yEAAyE,aAAa;AACtF;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;;AAEA,yBAAyB;AACzB;AACA,QAAQ;AACR;AACA;AACA;;AAEA,OAAO;AACP;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,gBAAgB;AAC5B;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA,cAAc,gBAAgB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,kBAAkB,iBAAiB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,OAAO;AACP;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,uCAAuC,uCAAuC,kBAAkB;;AAEhG;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,oEAAoE;AACpE;;AAEA;AACA;AACA,IAAI;;AAEJ;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,4CAA4C,sCAAsC;;AAElF;AACA;AACA;;AAEA;AACA,oCAAoC,aAAa;AACjD;AACA;AACA,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,OAAO;AACnB;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,SAAS;AACvB;AACA;AACA;AACA;AACA;AACA,kBAAkB,wBAAwB;AAC1C;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA,yEAAyE;AACzE;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,oBAAoB,6BAA6B;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,OAAO;AACP;AACA;;AAEA;;AAEA;AACA;;AAEA;;;AAGA,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,EAAE;AACd,cAAc,QAAQ;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;;;AAGA,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB,YAAY,SAAS;AACrB,cAAc,SAAS;AACvB;AACA;AACA;AACA;AACA;AACA;;AAEA;;;AAGA,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,EAAE;AACd,cAAc,QAAQ;AACtB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;;AAGA,OAAO;AACP;AACA;;AAEA;;;AAGA,OAAO;AACP;AACA;;AAEA,+CAA+C;;AAE/C;AACA;AACA,EAAE;;AAEF;;AAEA;;AAEA,uCAAuC,uCAAuC,kBAAkB;;AAEhG,sBAAsB;;AAEtB;AACA;AACA,EAAE;AACF;AACA;;AAEA;AACA;AACA,6BAA6B,4BAA4B,aAAa,EAAE;;AAExE,OAAO;AACP;AACA;;AAEA;;AAEA;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;;AAEA;AACA;AACA,CAAC;AACD,C;;;;;;;ACh7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AClBA;AACA;AACA,aAAa;AACb;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,yBAAyB;;AAEzB;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,wBAAwB;AACnC,WAAW,SAAS;AACpB,WAAW,OAAO;AAClB;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,mBAAmB;AAC9B,WAAW,QAAQ;AACnB,WAAW,OAAO;AAClB;AACA,YAAY;AACZ;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA,KAAK;AACL,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,IAAI;AACJ;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,MAAM;AACjB,WAAW,mBAAmB;AAC9B,WAAW,SAAS;AACpB,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,IAAI;AACJ;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA,EAAE;AACF;;AAEA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA,EAAE;AACF;;AAEA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AChUA;AACA,aAAa,SAAS;AACtB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,YAAY;AACvB,WAAW,0BAA0B;AACrC;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,EAAE;AACF;;;;;;;;ACrCA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY,OAAO;AACnB;AACA;AACA;;AAEA;AACA;;AAEA,aAAa,mBAAmB;AAChC;AACA,qBAAqB;AACrB;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,mBAAmB;AAC9B,WAAW,wBAAwB;AACnC,YAAY;AACZ;AACA;AACA,wBAAwB;AACxB;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA,iCAAiC;AACjC;;AAEA;AACA;AACA;;;;;;;;ACpGA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,OAAO;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6DAA6D;AAC7D;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;;;;;;;;ACxEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;ACRA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;AClEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,2BAA2B;AACtC,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;;;;;;;AC5BA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AC3CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,wBAAwB;AACnC,YAAY;AACZ;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;;;;;;;ACtBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,wBAAwB;AACnC,YAAY;AACZ;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,SAAS;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AC3DA;AACA;AACA;AACA;;;;;;;;ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA,EAAE;AACF;AACA,EAAE;AACF;AACA,EAAE;AACF;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,EAAE;AACF;AACA,EAAE;AACF;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;;;;;;;AClEA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,iBAAiB;AAC5B,aAAa;AACb;AACA;;AAEA;AACA;AACA;AACA,YAAY,OAAO;AACnB,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA,YAAY,OAAO;AACnB,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY,MAAM;AAClB;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;;;;;;;ACzGA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,SAAS;AACpB,WAAW,qBAAqB;AAChC,aAAa;AACb;AACA;;AAEA;AACA;AACA;AACA,YAAY,OAAO;AACnB,aAAa;AACb;AACA;AACA;AACA;AACA;AACA,8BAA8B;AAC9B;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,OAAO;AACnB,cAAc;AACd;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,IAAI;AACf,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,MAAM,MAAM,KAAK,SAAS,GAAG,UAAU;AACvC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,IAAI;AACf,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;;;;;;;AClJA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;AACF;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;;AAEA;AACA;;AAEA;;;;;;;;AC1CA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,aAAa,SAAS;AACtB;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,YAAY;AACvB,WAAW,OAAO;AAClB,WAAW,wBAAwB;AACnC,WAAW,SAAS;AACpB,WAAW,2BAA2B;AACtC,WAAW,wBAAwB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA,IAAI;AACJ;AACA;AACA,IAAI;;AAEJ,EAAE;AACF,CAAC;;AAED;AACA;;;;;;;;ACpLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,eAAe;AAC1B;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,OAAO;AAClB,WAAW,eAAe;AAC1B;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;;;;;;;ACpEA;AACA;;AAEA;AACA,aAAa,OAAO;AACpB,cAAc,OAAO;AACrB,cAAc,OAAO;AACrB,cAAc,OAAO;AACrB,cAAc,OAAO;AACrB,cAAc,iBAAiB;AAC/B;AACA;AACA,cAAc,OAAO;AACrB,cAAc,iBAAiB;AAC/B;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,iBAAiB;AAC5B,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,iBAAiB;AAC5B,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAAS,oBAAoB;AAC7B;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;;;;;;;;ACzIA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,OAAO;AACpB,cAAc,OAAO;AACrB,cAAc,SAAS;AACvB,cAAc,SAAS;AACvB,cAAc,SAAS;AACvB,cAAc,SAAS;AACvB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,QAAQ;AACnB,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,EAAE;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AC5DA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,SAAS;AACpB;AACA,WAAW,OAAO;AAClB;AACA,YAAY;AACZ;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;;AAEA;;;;;;;;AChDA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,YAAY,OAAO;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA,KAAK;AACL,IAAI;;AAEJ;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL,IAAI;;AAEJ;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,KAAK;AACL;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,KAAK;;AAEL;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA,KAAK;AACL,IAAI;;AAEJ;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;;AAEA;AACA,KAAK;AACL,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;;;;;;;;ACnPA;AACA;AACA;AACA;AACA;AACA;;;;;;;;ACLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA,gBAAgB;AAChB;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;;;;;;ACrCA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB;AACA,YAAY,OAAO;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,KAAK;AACL,IAAI;AACJ;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;AC9FA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,YAAY,OAAO;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;;;;;;;;ACvDA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,YAAY,OAAO;AACnB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;;;;;;;;ACnDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,EAAE;AACF;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,OAAO;AACpB,cAAc,OAAO;AACrB,cAAc,QAAQ;AACtB,cAAc,OAAO;AACrB,cAAc,QAAQ;AACtB;AACA;;AAEA;AACA,0CAA0C,iCAAiC;AAC3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,wBAAwB;AACnC,YAAY;AACZ;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,MAAM;AACnB,aAAa,OAAO;AACpB;AACA;AACA,aAAa,OAAO;AACpB;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,wBAAwB;AACnC,YAAY;AACZ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA,4BAA4B;AAC5B;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,wBAAwB;AACnC,YAAY;AACZ;AACA;AACA;AACA;;AAEA,4BAA4B;AAC5B;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;;AAEA,6CAA6C;AAC7C,0CAA0C;AAC1C;;AAEA;AACA,yCAAyC;;AAEzC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,mBAAmB;AAC9B,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,2BAA2B;AACtC,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,YAAY,eAAe;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA,WAAW,mBAAmB;AAC9B,WAAW,2BAA2B;AACtC;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA,WAAW,mBAAmB;AAC9B,YAAY,eAAe;AAC3B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,EAAE;AACF;;AAEA;AACA,aAAa,OAAO;AACpB,cAAc,QAAQ;AACtB,cAAc,QAAQ;AACtB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,aAAa,OAAO;AACpB,cAAc,OAAO;AACrB,cAAc,OAAO;AACrB,cAAc,OAAO;AACrB,cAAc,QAAQ;AACtB,cAAc,QAAQ;AACtB;;AAEA;AACA,WAAW,cAAc;AACzB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,eAAe;AAC1B,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,mBAAmB;AAC9B,WAAW,yBAAyB;AACpC,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA,EAAE;AACF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,EAAE;AACF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,mBAAmB;AAC9B,WAAW,yBAAyB;AACpC,WAAW,SAAS;AACpB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB;AACA,WAAW,eAAe;AAC1B,WAAW,QAAQ;AACnB;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;AC7uBA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;;;;;;ACtBA;AACA;;AAEA;AACA;AACA;AACA,aAAa,SAAS;AACtB;AACA;;AAEA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA,YAAY,OAAO;AACnB,cAAc,OAAO;AACrB;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;AACA,cAAc,YAAY;AAC1B;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA,cAAc,QAAQ;AACtB;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,QAAQ;AACtB;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAY,OAAO;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA,WAAW,cAAc;AACzB,YAAY,OAAO;AACnB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,cAAc;AACzB,WAAW,QAAQ;AACnB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;;;;;;;;ACzMA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,OAAO;AAClB,WAAW,eAAe;AAC1B,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;;;;;;;;ACzBA;AACA,aAAa,OAAO;AACpB;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,WAAW;AACtB;AACA,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA;AACA,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;;;;;;;;AChFA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;AACA","file":"index.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/index.js\");\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 428748b32b78b4924f3e","(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ReduxThunk\"] = factory();\n\telse\n\t\troot[\"ReduxThunk\"] = factory();\n})(this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n\n\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tmodule.exports = __webpack_require__(1);\n\n\n/***/ },\n/* 1 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\n\texports.__esModule = true;\n\tfunction createThunkMiddleware(extraArgument) {\n\t return function (_ref) {\n\t var dispatch = _ref.dispatch,\n\t getState = _ref.getState;\n\t return function (next) {\n\t return function (action) {\n\t if (typeof action === 'function') {\n\t return action(dispatch, getState, extraArgument);\n\t }\n\n\t return next(action);\n\t };\n\t };\n\t };\n\t}\n\n\tvar thunk = createThunkMiddleware();\n\tthunk.withExtraArgument = createThunkMiddleware;\n\n\texports['default'] = thunk;\n\n/***/ }\n/******/ ])\n});\n;\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/redux-thunk/dist/redux-thunk.js\n// module id = ./node_modules/redux-thunk/dist/redux-thunk.js\n// module chunks = 0","(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"Redux\"] = factory();\n\telse\n\t\troot[\"Redux\"] = factory();\n})(this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n\n\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\n\texports.__esModule = true;\n\texports.compose = exports.applyMiddleware = exports.bindActionCreators = exports.combineReducers = exports.createStore = undefined;\n\n\tvar _createStore = __webpack_require__(2);\n\n\tvar _createStore2 = _interopRequireDefault(_createStore);\n\n\tvar _combineReducers = __webpack_require__(7);\n\n\tvar _combineReducers2 = _interopRequireDefault(_combineReducers);\n\n\tvar _bindActionCreators = __webpack_require__(6);\n\n\tvar _bindActionCreators2 = _interopRequireDefault(_bindActionCreators);\n\n\tvar _applyMiddleware = __webpack_require__(5);\n\n\tvar _applyMiddleware2 = _interopRequireDefault(_applyMiddleware);\n\n\tvar _compose = __webpack_require__(1);\n\n\tvar _compose2 = _interopRequireDefault(_compose);\n\n\tvar _warning = __webpack_require__(3);\n\n\tvar _warning2 = _interopRequireDefault(_warning);\n\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\n\t/*\n\t* This is a dummy function to check if the function name has been altered by minification.\n\t* If the function has been minified and NODE_ENV !== 'production', warn the user.\n\t*/\n\tfunction isCrushed() {}\n\n\tif ((\"development\") !== 'production' && typeof isCrushed.name === 'string' && isCrushed.name !== 'isCrushed') {\n\t (0, _warning2['default'])('You are currently using minified code outside of NODE_ENV === \\'production\\'. ' + 'This means that you are running a slower development build of Redux. ' + 'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' + 'or DefinePlugin for webpack (http://stackoverflow.com/questions/30030031) ' + 'to ensure you have the correct code for your production build.');\n\t}\n\n\texports.createStore = _createStore2['default'];\n\texports.combineReducers = _combineReducers2['default'];\n\texports.bindActionCreators = _bindActionCreators2['default'];\n\texports.applyMiddleware = _applyMiddleware2['default'];\n\texports.compose = _compose2['default'];\n\n/***/ },\n/* 1 */\n/***/ function(module, exports) {\n\n\t\"use strict\";\n\n\texports.__esModule = true;\n\texports[\"default\"] = compose;\n\t/**\n\t * Composes single-argument functions from right to left. The rightmost\n\t * function can take multiple arguments as it provides the signature for\n\t * the resulting composite function.\n\t *\n\t * @param {...Function} funcs The functions to compose.\n\t * @returns {Function} A function obtained by composing the argument functions\n\t * from right to left. For example, compose(f, g, h) is identical to doing\n\t * (...args) => f(g(h(...args))).\n\t */\n\n\tfunction compose() {\n\t for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) {\n\t funcs[_key] = arguments[_key];\n\t }\n\n\t if (funcs.length === 0) {\n\t return function (arg) {\n\t return arg;\n\t };\n\t }\n\n\t if (funcs.length === 1) {\n\t return funcs[0];\n\t }\n\n\t var last = funcs[funcs.length - 1];\n\t var rest = funcs.slice(0, -1);\n\t return function () {\n\t return rest.reduceRight(function (composed, f) {\n\t return f(composed);\n\t }, last.apply(undefined, arguments));\n\t };\n\t}\n\n/***/ },\n/* 2 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\n\texports.__esModule = true;\n\texports.ActionTypes = undefined;\n\texports['default'] = createStore;\n\n\tvar _isPlainObject = __webpack_require__(4);\n\n\tvar _isPlainObject2 = _interopRequireDefault(_isPlainObject);\n\n\tvar _symbolObservable = __webpack_require__(12);\n\n\tvar _symbolObservable2 = _interopRequireDefault(_symbolObservable);\n\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\n\t/**\n\t * These are private action types reserved by Redux.\n\t * For any unknown actions, you must return the current state.\n\t * If the current state is undefined, you must return the initial state.\n\t * Do not reference these action types directly in your code.\n\t */\n\tvar ActionTypes = exports.ActionTypes = {\n\t INIT: '@@redux/INIT'\n\t};\n\n\t/**\n\t * Creates a Redux store that holds the state tree.\n\t * The only way to change the data in the store is to call `dispatch()` on it.\n\t *\n\t * There should only be a single store in your app. To specify how different\n\t * parts of the state tree respond to actions, you may combine several reducers\n\t * into a single reducer function by using `combineReducers`.\n\t *\n\t * @param {Function} reducer A function that returns the next state tree, given\n\t * the current state tree and the action to handle.\n\t *\n\t * @param {any} [preloadedState] The initial state. You may optionally specify it\n\t * to hydrate the state from the server in universal apps, or to restore a\n\t * previously serialized user session.\n\t * If you use `combineReducers` to produce the root reducer function, this must be\n\t * an object with the same shape as `combineReducers` keys.\n\t *\n\t * @param {Function} enhancer The store enhancer. You may optionally specify it\n\t * to enhance the store with third-party capabilities such as middleware,\n\t * time travel, persistence, etc. The only store enhancer that ships with Redux\n\t * is `applyMiddleware()`.\n\t *\n\t * @returns {Store} A Redux store that lets you read the state, dispatch actions\n\t * and subscribe to changes.\n\t */\n\tfunction createStore(reducer, preloadedState, enhancer) {\n\t var _ref2;\n\n\t if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {\n\t enhancer = preloadedState;\n\t preloadedState = undefined;\n\t }\n\n\t if (typeof enhancer !== 'undefined') {\n\t if (typeof enhancer !== 'function') {\n\t throw new Error('Expected the enhancer to be a function.');\n\t }\n\n\t return enhancer(createStore)(reducer, preloadedState);\n\t }\n\n\t if (typeof reducer !== 'function') {\n\t throw new Error('Expected the reducer to be a function.');\n\t }\n\n\t var currentReducer = reducer;\n\t var currentState = preloadedState;\n\t var currentListeners = [];\n\t var nextListeners = currentListeners;\n\t var isDispatching = false;\n\n\t function ensureCanMutateNextListeners() {\n\t if (nextListeners === currentListeners) {\n\t nextListeners = currentListeners.slice();\n\t }\n\t }\n\n\t /**\n\t * Reads the state tree managed by the store.\n\t *\n\t * @returns {any} The current state tree of your application.\n\t */\n\t function getState() {\n\t return currentState;\n\t }\n\n\t /**\n\t * Adds a change listener. It will be called any time an action is dispatched,\n\t * and some part of the state tree may potentially have changed. You may then\n\t * call `getState()` to read the current state tree inside the callback.\n\t *\n\t * You may call `dispatch()` from a change listener, with the following\n\t * caveats:\n\t *\n\t * 1. The subscriptions are snapshotted just before every `dispatch()` call.\n\t * If you subscribe or unsubscribe while the listeners are being invoked, this\n\t * will not have any effect on the `dispatch()` that is currently in progress.\n\t * However, the next `dispatch()` call, whether nested or not, will use a more\n\t * recent snapshot of the subscription list.\n\t *\n\t * 2. The listener should not expect to see all state changes, as the state\n\t * might have been updated multiple times during a nested `dispatch()` before\n\t * the listener is called. It is, however, guaranteed that all subscribers\n\t * registered before the `dispatch()` started will be called with the latest\n\t * state by the time it exits.\n\t *\n\t * @param {Function} listener A callback to be invoked on every dispatch.\n\t * @returns {Function} A function to remove this change listener.\n\t */\n\t function subscribe(listener) {\n\t if (typeof listener !== 'function') {\n\t throw new Error('Expected listener to be a function.');\n\t }\n\n\t var isSubscribed = true;\n\n\t ensureCanMutateNextListeners();\n\t nextListeners.push(listener);\n\n\t return function unsubscribe() {\n\t if (!isSubscribed) {\n\t return;\n\t }\n\n\t isSubscribed = false;\n\n\t ensureCanMutateNextListeners();\n\t var index = nextListeners.indexOf(listener);\n\t nextListeners.splice(index, 1);\n\t };\n\t }\n\n\t /**\n\t * Dispatches an action. It is the only way to trigger a state change.\n\t *\n\t * The `reducer` function, used to create the store, will be called with the\n\t * current state tree and the given `action`. Its return value will\n\t * be considered the **next** state of the tree, and the change listeners\n\t * will be notified.\n\t *\n\t * The base implementation only supports plain object actions. If you want to\n\t * dispatch a Promise, an Observable, a thunk, or something else, you need to\n\t * wrap your store creating function into the corresponding middleware. For\n\t * example, see the documentation for the `redux-thunk` package. Even the\n\t * middleware will eventually dispatch plain object actions using this method.\n\t *\n\t * @param {Object} action A plain object representing “what changed”. It is\n\t * a good idea to keep actions serializable so you can record and replay user\n\t * sessions, or use the time travelling `redux-devtools`. An action must have\n\t * a `type` property which may not be `undefined`. It is a good idea to use\n\t * string constants for action types.\n\t *\n\t * @returns {Object} For convenience, the same action object you dispatched.\n\t *\n\t * Note that, if you use a custom middleware, it may wrap `dispatch()` to\n\t * return something else (for example, a Promise you can await).\n\t */\n\t function dispatch(action) {\n\t if (!(0, _isPlainObject2['default'])(action)) {\n\t throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.');\n\t }\n\n\t if (typeof action.type === 'undefined') {\n\t throw new Error('Actions may not have an undefined \"type\" property. ' + 'Have you misspelled a constant?');\n\t }\n\n\t if (isDispatching) {\n\t throw new Error('Reducers may not dispatch actions.');\n\t }\n\n\t try {\n\t isDispatching = true;\n\t currentState = currentReducer(currentState, action);\n\t } finally {\n\t isDispatching = false;\n\t }\n\n\t var listeners = currentListeners = nextListeners;\n\t for (var i = 0; i < listeners.length; i++) {\n\t listeners[i]();\n\t }\n\n\t return action;\n\t }\n\n\t /**\n\t * Replaces the reducer currently used by the store to calculate the state.\n\t *\n\t * You might need this if your app implements code splitting and you want to\n\t * load some of the reducers dynamically. You might also need this if you\n\t * implement a hot reloading mechanism for Redux.\n\t *\n\t * @param {Function} nextReducer The reducer for the store to use instead.\n\t * @returns {void}\n\t */\n\t function replaceReducer(nextReducer) {\n\t if (typeof nextReducer !== 'function') {\n\t throw new Error('Expected the nextReducer to be a function.');\n\t }\n\n\t currentReducer = nextReducer;\n\t dispatch({ type: ActionTypes.INIT });\n\t }\n\n\t /**\n\t * Interoperability point for observable/reactive libraries.\n\t * @returns {observable} A minimal observable of state changes.\n\t * For more information, see the observable proposal:\n\t * https://github.com/zenparsing/es-observable\n\t */\n\t function observable() {\n\t var _ref;\n\n\t var outerSubscribe = subscribe;\n\t return _ref = {\n\t /**\n\t * The minimal observable subscription method.\n\t * @param {Object} observer Any object that can be used as an observer.\n\t * The observer object should have a `next` method.\n\t * @returns {subscription} An object with an `unsubscribe` method that can\n\t * be used to unsubscribe the observable from the store, and prevent further\n\t * emission of values from the observable.\n\t */\n\t subscribe: function subscribe(observer) {\n\t if (typeof observer !== 'object') {\n\t throw new TypeError('Expected the observer to be an object.');\n\t }\n\n\t function observeState() {\n\t if (observer.next) {\n\t observer.next(getState());\n\t }\n\t }\n\n\t observeState();\n\t var unsubscribe = outerSubscribe(observeState);\n\t return { unsubscribe: unsubscribe };\n\t }\n\t }, _ref[_symbolObservable2['default']] = function () {\n\t return this;\n\t }, _ref;\n\t }\n\n\t // When a store is created, an \"INIT\" action is dispatched so that every\n\t // reducer returns their initial state. This effectively populates\n\t // the initial state tree.\n\t dispatch({ type: ActionTypes.INIT });\n\n\t return _ref2 = {\n\t dispatch: dispatch,\n\t subscribe: subscribe,\n\t getState: getState,\n\t replaceReducer: replaceReducer\n\t }, _ref2[_symbolObservable2['default']] = observable, _ref2;\n\t}\n\n/***/ },\n/* 3 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\n\texports.__esModule = true;\n\texports['default'] = warning;\n\t/**\n\t * Prints a warning in the console if it exists.\n\t *\n\t * @param {String} message The warning message.\n\t * @returns {void}\n\t */\n\tfunction warning(message) {\n\t /* eslint-disable no-console */\n\t if (typeof console !== 'undefined' && typeof console.error === 'function') {\n\t console.error(message);\n\t }\n\t /* eslint-enable no-console */\n\t try {\n\t // This error was thrown as a convenience so that if you enable\n\t // \"break on all exceptions\" in your console,\n\t // it would pause the execution at this line.\n\t throw new Error(message);\n\t /* eslint-disable no-empty */\n\t } catch (e) {}\n\t /* eslint-enable no-empty */\n\t}\n\n/***/ },\n/* 4 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar getPrototype = __webpack_require__(8),\n\t isHostObject = __webpack_require__(9),\n\t isObjectLike = __webpack_require__(11);\n\n\t/** `Object#toString` result references. */\n\tvar objectTag = '[object Object]';\n\n\t/** Used for built-in method references. */\n\tvar funcProto = Function.prototype,\n\t objectProto = Object.prototype;\n\n\t/** Used to resolve the decompiled source of functions. */\n\tvar funcToString = funcProto.toString;\n\n\t/** Used to check objects for own properties. */\n\tvar hasOwnProperty = objectProto.hasOwnProperty;\n\n\t/** Used to infer the `Object` constructor. */\n\tvar objectCtorString = funcToString.call(Object);\n\n\t/**\n\t * Used to resolve the\n\t * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n\t * of values.\n\t */\n\tvar objectToString = objectProto.toString;\n\n\t/**\n\t * Checks if `value` is a plain object, that is, an object created by the\n\t * `Object` constructor or one with a `[[Prototype]]` of `null`.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @since 0.8.0\n\t * @category Lang\n\t * @param {*} value The value to check.\n\t * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.\n\t * @example\n\t *\n\t * function Foo() {\n\t * this.a = 1;\n\t * }\n\t *\n\t * _.isPlainObject(new Foo);\n\t * // => false\n\t *\n\t * _.isPlainObject([1, 2, 3]);\n\t * // => false\n\t *\n\t * _.isPlainObject({ 'x': 0, 'y': 0 });\n\t * // => true\n\t *\n\t * _.isPlainObject(Object.create(null));\n\t * // => true\n\t */\n\tfunction isPlainObject(value) {\n\t if (!isObjectLike(value) ||\n\t objectToString.call(value) != objectTag || isHostObject(value)) {\n\t return false;\n\t }\n\t var proto = getPrototype(value);\n\t if (proto === null) {\n\t return true;\n\t }\n\t var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;\n\t return (typeof Ctor == 'function' &&\n\t Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString);\n\t}\n\n\tmodule.exports = isPlainObject;\n\n\n/***/ },\n/* 5 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\n\texports.__esModule = true;\n\n\tvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\n\texports['default'] = applyMiddleware;\n\n\tvar _compose = __webpack_require__(1);\n\n\tvar _compose2 = _interopRequireDefault(_compose);\n\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\n\t/**\n\t * Creates a store enhancer that applies middleware to the dispatch method\n\t * of the Redux store. This is handy for a variety of tasks, such as expressing\n\t * asynchronous actions in a concise manner, or logging every action payload.\n\t *\n\t * See `redux-thunk` package as an example of the Redux middleware.\n\t *\n\t * Because middleware is potentially asynchronous, this should be the first\n\t * store enhancer in the composition chain.\n\t *\n\t * Note that each middleware will be given the `dispatch` and `getState` functions\n\t * as named arguments.\n\t *\n\t * @param {...Function} middlewares The middleware chain to be applied.\n\t * @returns {Function} A store enhancer applying the middleware.\n\t */\n\tfunction applyMiddleware() {\n\t for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) {\n\t middlewares[_key] = arguments[_key];\n\t }\n\n\t return function (createStore) {\n\t return function (reducer, preloadedState, enhancer) {\n\t var store = createStore(reducer, preloadedState, enhancer);\n\t var _dispatch = store.dispatch;\n\t var chain = [];\n\n\t var middlewareAPI = {\n\t getState: store.getState,\n\t dispatch: function dispatch(action) {\n\t return _dispatch(action);\n\t }\n\t };\n\t chain = middlewares.map(function (middleware) {\n\t return middleware(middlewareAPI);\n\t });\n\t _dispatch = _compose2['default'].apply(undefined, chain)(store.dispatch);\n\n\t return _extends({}, store, {\n\t dispatch: _dispatch\n\t });\n\t };\n\t };\n\t}\n\n/***/ },\n/* 6 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\n\texports.__esModule = true;\n\texports['default'] = bindActionCreators;\n\tfunction bindActionCreator(actionCreator, dispatch) {\n\t return function () {\n\t return dispatch(actionCreator.apply(undefined, arguments));\n\t };\n\t}\n\n\t/**\n\t * Turns an object whose values are action creators, into an object with the\n\t * same keys, but with every function wrapped into a `dispatch` call so they\n\t * may be invoked directly. This is just a convenience method, as you can call\n\t * `store.dispatch(MyActionCreators.doSomething())` yourself just fine.\n\t *\n\t * For convenience, you can also pass a single function as the first argument,\n\t * and get a function in return.\n\t *\n\t * @param {Function|Object} actionCreators An object whose values are action\n\t * creator functions. One handy way to obtain it is to use ES6 `import * as`\n\t * syntax. You may also pass a single function.\n\t *\n\t * @param {Function} dispatch The `dispatch` function available on your Redux\n\t * store.\n\t *\n\t * @returns {Function|Object} The object mimicking the original object, but with\n\t * every action creator wrapped into the `dispatch` call. If you passed a\n\t * function as `actionCreators`, the return value will also be a single\n\t * function.\n\t */\n\tfunction bindActionCreators(actionCreators, dispatch) {\n\t if (typeof actionCreators === 'function') {\n\t return bindActionCreator(actionCreators, dispatch);\n\t }\n\n\t if (typeof actionCreators !== 'object' || actionCreators === null) {\n\t throw new Error('bindActionCreators expected an object or a function, instead received ' + (actionCreators === null ? 'null' : typeof actionCreators) + '. ' + 'Did you write \"import ActionCreators from\" instead of \"import * as ActionCreators from\"?');\n\t }\n\n\t var keys = Object.keys(actionCreators);\n\t var boundActionCreators = {};\n\t for (var i = 0; i < keys.length; i++) {\n\t var key = keys[i];\n\t var actionCreator = actionCreators[key];\n\t if (typeof actionCreator === 'function') {\n\t boundActionCreators[key] = bindActionCreator(actionCreator, dispatch);\n\t }\n\t }\n\t return boundActionCreators;\n\t}\n\n/***/ },\n/* 7 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\n\texports.__esModule = true;\n\texports['default'] = combineReducers;\n\n\tvar _createStore = __webpack_require__(2);\n\n\tvar _isPlainObject = __webpack_require__(4);\n\n\tvar _isPlainObject2 = _interopRequireDefault(_isPlainObject);\n\n\tvar _warning = __webpack_require__(3);\n\n\tvar _warning2 = _interopRequireDefault(_warning);\n\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\n\tfunction getUndefinedStateErrorMessage(key, action) {\n\t var actionType = action && action.type;\n\t var actionName = actionType && '\"' + actionType.toString() + '\"' || 'an action';\n\n\t return 'Given action ' + actionName + ', reducer \"' + key + '\" returned undefined. ' + 'To ignore an action, you must explicitly return the previous state.';\n\t}\n\n\tfunction getUnexpectedStateShapeWarningMessage(inputState, reducers, action, unexpectedKeyCache) {\n\t var reducerKeys = Object.keys(reducers);\n\t var argumentName = action && action.type === _createStore.ActionTypes.INIT ? 'preloadedState argument passed to createStore' : 'previous state received by the reducer';\n\n\t if (reducerKeys.length === 0) {\n\t return 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.';\n\t }\n\n\t if (!(0, _isPlainObject2['default'])(inputState)) {\n\t return 'The ' + argumentName + ' has unexpected type of \"' + {}.toString.call(inputState).match(/\\s([a-z|A-Z]+)/)[1] + '\". Expected argument to be an object with the following ' + ('keys: \"' + reducerKeys.join('\", \"') + '\"');\n\t }\n\n\t var unexpectedKeys = Object.keys(inputState).filter(function (key) {\n\t return !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key];\n\t });\n\n\t unexpectedKeys.forEach(function (key) {\n\t unexpectedKeyCache[key] = true;\n\t });\n\n\t if (unexpectedKeys.length > 0) {\n\t return 'Unexpected ' + (unexpectedKeys.length > 1 ? 'keys' : 'key') + ' ' + ('\"' + unexpectedKeys.join('\", \"') + '\" found in ' + argumentName + '. ') + 'Expected to find one of the known reducer keys instead: ' + ('\"' + reducerKeys.join('\", \"') + '\". Unexpected keys will be ignored.');\n\t }\n\t}\n\n\tfunction assertReducerSanity(reducers) {\n\t Object.keys(reducers).forEach(function (key) {\n\t var reducer = reducers[key];\n\t var initialState = reducer(undefined, { type: _createStore.ActionTypes.INIT });\n\n\t if (typeof initialState === 'undefined') {\n\t throw new Error('Reducer \"' + key + '\" returned undefined during initialization. ' + 'If the state passed to the reducer is undefined, you must ' + 'explicitly return the initial state. The initial state may ' + 'not be undefined.');\n\t }\n\n\t var type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math.random().toString(36).substring(7).split('').join('.');\n\t if (typeof reducer(undefined, { type: type }) === 'undefined') {\n\t throw new Error('Reducer \"' + key + '\" returned undefined when probed with a random type. ' + ('Don\\'t try to handle ' + _createStore.ActionTypes.INIT + ' or other actions in \"redux/*\" ') + 'namespace. They are considered private. Instead, you must return the ' + 'current state for any unknown actions, unless it is undefined, ' + 'in which case you must return the initial state, regardless of the ' + 'action type. The initial state may not be undefined.');\n\t }\n\t });\n\t}\n\n\t/**\n\t * Turns an object whose values are different reducer functions, into a single\n\t * reducer function. It will call every child reducer, and gather their results\n\t * into a single state object, whose keys correspond to the keys of the passed\n\t * reducer functions.\n\t *\n\t * @param {Object} reducers An object whose values correspond to different\n\t * reducer functions that need to be combined into one. One handy way to obtain\n\t * it is to use ES6 `import * as reducers` syntax. The reducers may never return\n\t * undefined for any action. Instead, they should return their initial state\n\t * if the state passed to them was undefined, and the current state for any\n\t * unrecognized action.\n\t *\n\t * @returns {Function} A reducer function that invokes every reducer inside the\n\t * passed object, and builds a state object with the same shape.\n\t */\n\tfunction combineReducers(reducers) {\n\t var reducerKeys = Object.keys(reducers);\n\t var finalReducers = {};\n\t for (var i = 0; i < reducerKeys.length; i++) {\n\t var key = reducerKeys[i];\n\n\t if (true) {\n\t if (typeof reducers[key] === 'undefined') {\n\t (0, _warning2['default'])('No reducer provided for key \"' + key + '\"');\n\t }\n\t }\n\n\t if (typeof reducers[key] === 'function') {\n\t finalReducers[key] = reducers[key];\n\t }\n\t }\n\t var finalReducerKeys = Object.keys(finalReducers);\n\n\t if (true) {\n\t var unexpectedKeyCache = {};\n\t }\n\n\t var sanityError;\n\t try {\n\t assertReducerSanity(finalReducers);\n\t } catch (e) {\n\t sanityError = e;\n\t }\n\n\t return function combination() {\n\t var state = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];\n\t var action = arguments[1];\n\n\t if (sanityError) {\n\t throw sanityError;\n\t }\n\n\t if (true) {\n\t var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);\n\t if (warningMessage) {\n\t (0, _warning2['default'])(warningMessage);\n\t }\n\t }\n\n\t var hasChanged = false;\n\t var nextState = {};\n\t for (var i = 0; i < finalReducerKeys.length; i++) {\n\t var key = finalReducerKeys[i];\n\t var reducer = finalReducers[key];\n\t var previousStateForKey = state[key];\n\t var nextStateForKey = reducer(previousStateForKey, action);\n\t if (typeof nextStateForKey === 'undefined') {\n\t var errorMessage = getUndefinedStateErrorMessage(key, action);\n\t throw new Error(errorMessage);\n\t }\n\t nextState[key] = nextStateForKey;\n\t hasChanged = hasChanged || nextStateForKey !== previousStateForKey;\n\t }\n\t return hasChanged ? nextState : state;\n\t };\n\t}\n\n/***/ },\n/* 8 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar overArg = __webpack_require__(10);\n\n\t/** Built-in value references. */\n\tvar getPrototype = overArg(Object.getPrototypeOf, Object);\n\n\tmodule.exports = getPrototype;\n\n\n/***/ },\n/* 9 */\n/***/ function(module, exports) {\n\n\t/**\n\t * Checks if `value` is a host object in IE < 9.\n\t *\n\t * @private\n\t * @param {*} value The value to check.\n\t * @returns {boolean} Returns `true` if `value` is a host object, else `false`.\n\t */\n\tfunction isHostObject(value) {\n\t // Many host objects are `Object` objects that can coerce to strings\n\t // despite having improperly defined `toString` methods.\n\t var result = false;\n\t if (value != null && typeof value.toString != 'function') {\n\t try {\n\t result = !!(value + '');\n\t } catch (e) {}\n\t }\n\t return result;\n\t}\n\n\tmodule.exports = isHostObject;\n\n\n/***/ },\n/* 10 */\n/***/ function(module, exports) {\n\n\t/**\n\t * Creates a unary function that invokes `func` with its argument transformed.\n\t *\n\t * @private\n\t * @param {Function} func The function to wrap.\n\t * @param {Function} transform The argument transform.\n\t * @returns {Function} Returns the new function.\n\t */\n\tfunction overArg(func, transform) {\n\t return function(arg) {\n\t return func(transform(arg));\n\t };\n\t}\n\n\tmodule.exports = overArg;\n\n\n/***/ },\n/* 11 */\n/***/ function(module, exports) {\n\n\t/**\n\t * Checks if `value` is object-like. A value is object-like if it's not `null`\n\t * and has a `typeof` result of \"object\".\n\t *\n\t * @static\n\t * @memberOf _\n\t * @since 4.0.0\n\t * @category Lang\n\t * @param {*} value The value to check.\n\t * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n\t * @example\n\t *\n\t * _.isObjectLike({});\n\t * // => true\n\t *\n\t * _.isObjectLike([1, 2, 3]);\n\t * // => true\n\t *\n\t * _.isObjectLike(_.noop);\n\t * // => false\n\t *\n\t * _.isObjectLike(null);\n\t * // => false\n\t */\n\tfunction isObjectLike(value) {\n\t return !!value && typeof value == 'object';\n\t}\n\n\tmodule.exports = isObjectLike;\n\n\n/***/ },\n/* 12 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tmodule.exports = __webpack_require__(13);\n\n\n/***/ },\n/* 13 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t/* WEBPACK VAR INJECTION */(function(global) {'use strict';\n\n\tObject.defineProperty(exports, \"__esModule\", {\n\t\tvalue: true\n\t});\n\n\tvar _ponyfill = __webpack_require__(14);\n\n\tvar _ponyfill2 = _interopRequireDefault(_ponyfill);\n\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\n\tvar root = undefined; /* global window */\n\n\tif (typeof global !== 'undefined') {\n\t\troot = global;\n\t} else if (typeof window !== 'undefined') {\n\t\troot = window;\n\t}\n\n\tvar result = (0, _ponyfill2['default'])(root);\n\texports['default'] = result;\n\t/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))\n\n/***/ },\n/* 14 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\n\tObject.defineProperty(exports, \"__esModule\", {\n\t\tvalue: true\n\t});\n\texports['default'] = symbolObservablePonyfill;\n\tfunction symbolObservablePonyfill(root) {\n\t\tvar result;\n\t\tvar _Symbol = root.Symbol;\n\n\t\tif (typeof _Symbol === 'function') {\n\t\t\tif (_Symbol.observable) {\n\t\t\t\tresult = _Symbol.observable;\n\t\t\t} else {\n\t\t\t\tresult = _Symbol('observable');\n\t\t\t\t_Symbol.observable = result;\n\t\t\t}\n\t\t} else {\n\t\t\tresult = '@@observable';\n\t\t}\n\n\t\treturn result;\n\t};\n\n/***/ }\n/******/ ])\n});\n;\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/redux/dist/redux.js\n// module id = ./node_modules/redux/dist/redux.js\n// module chunks = 0","module.exports = {\n\tBOOT: 'BOOT',\n\tLINK_DWELL: 'LINK_DWELL',\n\tABANDON_START: 'ABANDON_START',\n\tABANDON_END: 'ABANDON_END',\n\tLINK_CLICK: 'LINK_CLICK',\n\tFETCH_START: 'FETCH_START',\n\tFETCH_END: 'FETCH_END',\n\tFETCH_COMPLETE: 'FETCH_COMPLETE',\n\tFETCH_FAILED: 'FETCH_FAILED',\n\tPREVIEW_DWELL: 'PREVIEW_DWELL',\n\tPREVIEW_SHOW: 'PREVIEW_SHOW',\n\tPREVIEW_CLICK: 'PREVIEW_CLICK',\n\tSETTINGS_SHOW: 'SETTINGS_SHOW',\n\tSETTINGS_HIDE: 'SETTINGS_HIDE',\n\tSETTINGS_CHANGE: 'SETTINGS_CHANGE',\n\tEVENT_LOGGED: 'EVENT_LOGGED',\n\tSTATSV_LOGGED: 'STATSV_LOGGED'\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/actionTypes.js\n// module id = ./src/actionTypes.js\n// module chunks = 0","var $ = jQuery,\n\tmw = window.mediaWiki,\n\tactions = {},\n\ttypes = require( './actionTypes' ),\n\twait = require( './wait' ),\n\n\t// See the following for context around this value.\n\t//\n\t// * https://phabricator.wikimedia.org/T161284\n\t// * https://phabricator.wikimedia.org/T70861#3129780\n\tFETCH_START_DELAY = 150, // ms.\n\n\t// The delay after which a FETCH_COMPLETE action should be dispatched.\n\t//\n\t// If the API endpoint responds faster than 500 ms (or, say, the API\n\t// response is served from the UA's cache), then we introduce a delay of\n\t// 500 - t to make the preview delay consistent to the user.\n\tFETCH_COMPLETE_TARGET_DELAY = 500, // ms.\n\n\tABANDON_END_DELAY = 300; // ms.\n\n/**\n * Mixes in timing information to an action.\n *\n * Warning: the `baseAction` parameter is modified and returned.\n *\n * @param {Object} baseAction\n * @return {Object}\n */\nfunction timedAction( baseAction ) {\n\tbaseAction.timestamp = mw.now();\n\n\treturn baseAction;\n}\n\n/**\n * Represents Page Previews booting.\n *\n * When a Redux store is created, the `@@INIT` action is immediately\n * dispatched to it. To avoid overriding the term, we refer to booting rather\n * than initializing.\n *\n * Page Previews persists critical pieces of information to local storage.\n * Since reading from and writing to local storage are synchronous, Page\n * Previews is booted when the browser is idle (using\n * [`mw.requestIdleCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback))\n * so as not to impact latency-critical events.\n *\n * @param {Boolean} isEnabled See `isEnabled.js`\n * @param {mw.user} user\n * @param {ext.popups.UserSettings} userSettings\n * @param {Function} generateToken\n * @param {mw.Map} config The config of the MediaWiki client-side application,\n * i.e. `mw.config`\n * @returns {Object}\n */\nactions.boot = function (\n\tisEnabled,\n\tuser,\n\tuserSettings,\n\tgenerateToken,\n\tconfig\n) {\n\tvar editCount = config.get( 'wgUserEditCount' ),\n\t\tpreviewCount = userSettings.getPreviewCount();\n\n\treturn {\n\t\ttype: types.BOOT,\n\t\tisEnabled: isEnabled,\n\t\tisNavPopupsEnabled: config.get( 'wgPopupsConflictsWithNavPopupGadget' ),\n\t\tsessionToken: user.sessionId(),\n\t\tpageToken: generateToken(),\n\t\tpage: {\n\t\t\ttitle: config.get( 'wgTitle' ),\n\t\t\tnamespaceID: config.get( 'wgNamespaceNumber' ),\n\t\t\tid: config.get( 'wgArticleId' )\n\t\t},\n\t\tuser: {\n\t\t\tisAnon: user.isAnon(),\n\t\t\teditCount: editCount,\n\t\t\tpreviewCount: previewCount\n\t\t}\n\t};\n};\n\n/**\n * Represents Page Previews fetching data via the gateway.\n *\n * @param {ext.popups.Gateway} gateway\n * @param {Element} el\n * @param {String} token The unique token representing the link interaction that\n * triggered the fetch\n * @return {Redux.Thunk}\n */\nactions.fetch = function ( gateway, el, token ) {\n\tvar title = $( el ).data( 'page-previews-title' );\n\n\treturn function ( dispatch ) {\n\t\tvar request;\n\n\t\tdispatch( timedAction( {\n\t\t\ttype: types.FETCH_START,\n\t\t\tel: el,\n\t\t\ttitle: title\n\t\t} ) );\n\n\t\trequest = gateway.getPageSummary( title )\n\t\t\t.then( function ( result ) {\n\t\t\t\tdispatch( timedAction( {\n\t\t\t\t\ttype: types.FETCH_END,\n\t\t\t\t\tel: el\n\t\t\t\t} ) );\n\n\t\t\t\treturn result;\n\t\t\t} )\n\t\t\t.fail( function () {\n\t\t\t\tdispatch( {\n\t\t\t\t\ttype: types.FETCH_FAILED,\n\t\t\t\t\tel: el\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t$.when( request, wait( FETCH_COMPLETE_TARGET_DELAY - FETCH_START_DELAY ) )\n\t\t\t.then( function ( result ) {\n\t\t\t\tdispatch( timedAction( {\n\t\t\t\t\ttype: types.FETCH_COMPLETE,\n\t\t\t\t\tel: el,\n\t\t\t\t\tresult: result,\n\t\t\t\t\ttoken: token\n\t\t\t\t} ) );\n\t\t\t} );\n\t};\n};\n\n/**\n * Represents the user dwelling on a link, either by hovering over it with\n * their mouse or by focussing it using their keyboard or an assistive device.\n *\n * @param {Element} el\n * @param {Event} event\n * @param {ext.popups.Gateway} gateway\n * @param {Function} generateToken\n * @return {Redux.Thunk}\n */\nactions.linkDwell = function ( el, event, gateway, generateToken ) {\n\tvar token = generateToken();\n\n\treturn function ( dispatch, getState ) {\n\t\tvar action = timedAction( {\n\t\t\ttype: types.LINK_DWELL,\n\t\t\tel: el,\n\t\t\tevent: event,\n\t\t\ttoken: token\n\t\t} );\n\n\t\t// Has the new generated token been accepted?\n\t\tfunction isNewInteraction() {\n\t\t\treturn getState().preview.activeToken === token;\n\t\t}\n\n\t\tdispatch( action );\n\n\t\tif ( !isNewInteraction() ) {\n\t\t\treturn;\n\t\t}\n\n\t\twait( FETCH_START_DELAY )\n\t\t\t.then( function () {\n\t\t\t\tvar previewState = getState().preview;\n\n\t\t\t\tif ( previewState.enabled && isNewInteraction() ) {\n\t\t\t\t\tdispatch( actions.fetch( gateway, el, token ) );\n\t\t\t\t}\n\t\t\t} );\n\t};\n};\n\n/**\n * Represents the user abandoning a link, either by moving their mouse away\n * from it or by shifting focus to another UI element using their keyboard or\n * an assistive device, or abandoning a preview by moving their mouse away\n * from it.\n *\n * @return {Redux.Thunk}\n */\nactions.abandon = function () {\n\treturn function ( dispatch, getState ) {\n\t\tvar token = getState().preview.activeToken;\n\n\t\tif ( !token ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdispatch( timedAction( {\n\t\t\ttype: types.ABANDON_START,\n\t\t\ttoken: token\n\t\t} ) );\n\n\t\twait( ABANDON_END_DELAY )\n\t\t\t.then( function () {\n\t\t\t\tdispatch( {\n\t\t\t\t\ttype: types.ABANDON_END,\n\t\t\t\t\ttoken: token\n\t\t\t\t} );\n\t\t\t} );\n\t};\n};\n\n/**\n * Represents the user clicking on a link with their mouse, keyboard, or an\n * assistive device.\n *\n * @param {Element} el\n * @return {Object}\n */\nactions.linkClick = function ( el ) {\n\treturn timedAction( {\n\t\ttype: types.LINK_CLICK,\n\t\tel: el\n\t} );\n};\n\n/**\n * Represents the user dwelling on a preview with their mouse.\n *\n * @return {Object}\n */\nactions.previewDwell = function () {\n\treturn {\n\t\ttype: types.PREVIEW_DWELL\n\t};\n};\n\n/**\n * Represents a preview being shown to the user.\n *\n * This action is dispatched by the `./changeListeners/render.js` change\n * listener.\n *\n * @param {String} token\n * @return {Object}\n */\nactions.previewShow = function ( token ) {\n\treturn timedAction( {\n\t\ttype: types.PREVIEW_SHOW,\n\t\ttoken: token\n\t} );\n};\n\n/**\n * Represents the user clicking either the \"Enable previews\" footer menu link,\n * or the \"cog\" icon that's present on each preview.\n *\n * @return {Object}\n */\nactions.showSettings = function () {\n\treturn {\n\t\ttype: types.SETTINGS_SHOW\n\t};\n};\n\n/**\n * Represents the user closing the settings dialog and saving their settings.\n *\n * @return {Object}\n */\nactions.hideSettings = function () {\n\treturn {\n\t\ttype: types.SETTINGS_HIDE\n\t};\n};\n\n/**\n * Represents the user saving their settings.\n *\n * N.B. This action returns a Redux.Thunk not because it needs to perform\n * asynchronous work, but because it needs to query the global state for the\n * current enabled state. In order to keep the enabled state in a single\n * place (the preview reducer), we query it and dispatch it as `wasEnabled`\n * so that other reducers (like settings) can act on it without having to\n * duplicate the `enabled` state locally.\n * See doc/adr/0003-keep-enabled-state-only-in-preview-reducer.md for more\n * details.\n *\n * @param {Boolean} enabled if previews are enabled or not\n * @return {Redux.Thunk}\n */\nactions.saveSettings = function ( enabled ) {\n\treturn function ( dispatch, getState ) {\n\t\tdispatch( {\n\t\t\ttype: types.SETTINGS_CHANGE,\n\t\t\twasEnabled: getState().preview.enabled,\n\t\t\tenabled: enabled\n\t\t} );\n\t};\n};\n\n/**\n * Represents the queued event being logged `changeListeners/eventLogging.js`\n * change listener.\n *\n * @return {Object}\n */\nactions.eventLogged = function () {\n\treturn {\n\t\ttype: types.EVENT_LOGGED\n\t};\n};\n\n/**\n * Represents the queued statsv event being logged.\n * See `mw.popups.changeListeners.statsv` change listener.\n *\n * @return {Object}\n */\nactions.statsvLogged = function () {\n\treturn {\n\t\ttype: types.STATSV_LOGGED\n\t};\n};\nmodule.exports = actions;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/actions.js\n// module id = ./src/actions.js\n// module chunks = 0","/**\n * @typedef {Function} ext.popups.ChangeListener\n * @param {Object} prevState The previous state\n * @param {Object} state The current state\n */\n\n/**\n * Registers a change listener, which is bound to the\n * [store](http://redux.js.org/docs/api/Store.html).\n *\n * A change listener is a function that is only invoked when the state in the\n * [store](http://redux.js.org/docs/api/Store.html) changes. N.B. that there\n * may not be a 1:1 correspondence with actions being dispatched to the store\n * and the state in the store changing.\n *\n * See [Store#subscribe](http://redux.js.org/docs/api/Store.html#subscribe)\n * for more information about what change listeners may and may not do.\n *\n * @param {Redux.Store} store\n * @param {ext.popups.ChangeListener} callback\n */\nmodule.exports = function ( store, callback ) {\n\t// This function is based on the example in [the documentation for\n\t// Store#subscribe](http://redux.js.org/docs/api/Store.html#subscribe),\n\t// which was written by Dan Abramov.\n\n\tvar state;\n\n\tstore.subscribe( function () {\n\t\tvar prevState = state;\n\n\t\tstate = store.getState();\n\n\t\tif ( prevState !== state ) {\n\t\t\tcallback( prevState, state );\n\t\t}\n\t} );\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListener.js\n// module id = ./src/changeListener.js\n// module chunks = 0","var $ = jQuery;\n\n/**\n * Hashes the string using the 32-bit FNV-1a algorithm.\n *\n * @see http://isthe.com/chongo/tech/comp/fnv/#FNV-1a\n * @see http://isthe.com/chongo/tech/comp/fnv/#FNV-param\n *\n * @param {String} string\n * @return {Number} A 32-bit unsigned integer\n */\nfunction fnv1a32( string ) {\n\t/* eslint-disable no-bitwise */\n\n\tvar result = 2166136261, // Offset basis.\n\t\ti = 0;\n\n\tfor ( i = 0; i < string.length; ++i ) {\n\t\tresult ^= string.charCodeAt( i );\n\t\tresult *= 16777619; // Prime.\n\t}\n\n\treturn result >>> 0;\n\t/* eslint-enable no-bitwise */\n}\n\n/**\n * Creates an instance of the event logging change listener.\n *\n * When an event is enqueued it'll be logged using the schema. Since it's the\n * responsibility of Event Logging (and the UA) to deliver logged events,\n * `EVENT_LOGGED` is immediately dispatched rather than waiting for some\n * indicator of completion.\n *\n * This change listener also stores hashes of all enqueued events. If a\n * duplicate event is queued - there's a hash collision - then the\n * `PagePreviews.EventLogging.DuplicateEvent` counter is incremented via [the\n * \"StatsD timers and counters\" analytics event protocol][0].\n *\n * See the following for additional context:\n *\n * * https://phabricator.wikimedia.org/T161769\n * * https://phabricator.wikimedia.org/T163198\n *\n * [0]: https://github.com/wikimedia/mediawiki-extensions-WikimediaEvents/blob/master/modules/ext.wikimediaEvents.statsd.js\n *\n * @param {Object} boundActions\n * @param {mw.eventLog.Schema} schema\n * @param {ext.popups.EventTracker} track\n * @return {ext.popups.ChangeListener}\n */\nmodule.exports = function ( boundActions, schema, track ) {\n\tvar tokenToSeenMap = {},\n\t\thashToSeenMap = {};\n\n\treturn function ( _, state ) {\n\t\tvar eventLogging = state.eventLogging,\n\t\t\tevent = eventLogging.event,\n\t\t\ttoken,\n\t\t\thash,\n\t\t\tshouldLog = true;\n\n\t\tif ( !event ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttoken = event.linkInteractionToken;\n\n\t\tif ( tokenToSeenMap[ token ] === true ) {\n\t\t\ttrack( 'counter.PagePreviews.EventLogging.DuplicateToken', 1 );\n\n\t\t\tshouldLog = false;\n\t\t}\n\n\t\ttokenToSeenMap[ token ] = true;\n\n\t\t// Use 32-bit FNV-1a based on Ian Boyd's (incredibly detailed) analysis of\n\t\t// several algorithms designed to quickly hash a string\n\t\t// <https://softwareengineering.stackexchange.com/a/145633>.\n\t\t//\n\t\t// ...\n\t\t//\n\t\t// It's also remarkably easy to implement!!1\n\t\thash = fnv1a32( JSON.stringify( event ) ).toString( 16 );\n\n\t\t// Has the event been seen before?\n\t\tif ( hashToSeenMap[ hash ] === true ) {\n\t\t\ttrack( 'counter.PagePreviews.EventLogging.DuplicateEvent', 1 );\n\n\t\t\tshouldLog = false;\n\t\t}\n\n\t\thashToSeenMap[ hash ] = true;\n\n\t\tif ( shouldLog ) {\n\t\t\tschema.log( $.extend( true, {}, eventLogging.baseData, event ) );\n\t\t}\n\n\t\tboundActions.eventLogged();\n\t};\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/eventLogging.js\n// module id = ./src/changeListeners/eventLogging.js\n// module chunks = 0","var mw = window.mediaWiki,\n\t$ = jQuery;\n\n/**\n * Creates the link element and appends it to the footer element.\n *\n * The following elements are considered to be the footer element (highest\n * priority to lowest):\n *\n * # `#footer-places`\n * # `#f-list`\n * # The parent element of `#footer li`, which is either an `ol` or `ul`.\n *\n * @return {jQuery} The link element\n */\nfunction createFooterLink() {\n\tvar $link = $( '<li>' ).append(\n\t\t\t$( '<a>' )\n\t\t\t\t.attr( 'href', '#' )\n\t\t\t\t.text( mw.message( 'popups-settings-enable' ).text() )\n\t\t),\n\t\t$footer;\n\n\t// As yet, we don't know whether the link should be visible.\n\t$link.hide();\n\n\t// From https://en.wikipedia.org/wiki/MediaWiki:Gadget-ReferenceTooltips.js,\n\t// which was written by Yair rand <https://en.wikipedia.org/wiki/User:Yair_rand>.\n\t$footer = $( '#footer-places, #f-list' );\n\n\tif ( $footer.length === 0 ) {\n\t\t$footer = $( '#footer li' ).parent();\n\t}\n\n\t$footer.append( $link );\n\n\treturn $link;\n}\n\n/**\n * Creates an instance of the footer link change listener.\n *\n * The change listener covers the following behaviour:\n *\n * * The \"Enable previews\" link (the \"link\") is appended to the footer menu\n * (see `createFooterLink` above).\n * * When Page Previews are disabled, then the link is shown; otherwise, the\n * link is hidden.\n * * When the user clicks the link, then the `showSettings` bound action\n * creator is called.\n *\n * @param {Object} boundActions\n * @return {ext.popups.ChangeListener}\n */\nmodule.exports = function ( boundActions ) {\n\tvar $footerLink;\n\n\treturn function ( prevState, state ) {\n\t\tif ( $footerLink === undefined ) {\n\t\t\t$footerLink = createFooterLink();\n\t\t\t$footerLink.click( function ( e ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tboundActions.showSettings();\n\t\t\t} );\n\t\t}\n\n\t\tif ( state.settings.shouldShowFooterLink ) {\n\t\t\t$footerLink.show();\n\t\t} else {\n\t\t\t$footerLink.hide();\n\t\t}\n\t};\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/footerLink.js\n// module id = ./src/changeListeners/footerLink.js\n// module chunks = 0","module.exports = {\n\tfooterLink: require( './footerLink' ),\n\teventLogging: require( './eventLogging' ),\n\tlinkTitle: require( './linkTitle' ),\n\trender: require( './render' ),\n\tsettings: require( './settings' ),\n\tstatsv: require( './statsv' ),\n\tsyncUserSettings: require( './syncUserSettings' )\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/index.js\n// module id = ./src/changeListeners/index.js\n// module chunks = 0","var $ = jQuery;\n\n/**\n * Creates an instance of the link title change listener.\n *\n * While the user dwells on a link, then it becomes the active link. The\n * change listener will remove a link's `title` attribute while it's the\n * active link.\n *\n * @return {ext.popups.ChangeListener}\n */\nmodule.exports = function () {\n\tvar title;\n\n\t/**\n\t * Destroys the title attribute of the element, storing its value in local\n\t * state so that it can be restored later (see `restoreTitleAttr`).\n\t *\n\t * @param {Element} el\n\t */\n\tfunction destroyTitleAttr( el ) {\n\t\tvar $el = $( el );\n\n\t\t// Has the user dwelled on a link? If we've already removed its title\n\t\t// attribute, then NOOP.\n\t\tif ( title ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttitle = $el.attr( 'title' );\n\n\t\t$el.attr( 'title', '' );\n\t}\n\n\t/**\n\t * Restores the title attribute of the element.\n\t *\n\t * @param {Element} el\n\t */\n\tfunction restoreTitleAttr( el ) {\n\t\t$( el ).attr( 'title', title );\n\n\t\ttitle = undefined;\n\t}\n\n\treturn function ( prevState, state ) {\n\t\tvar hasPrevActiveLink = prevState && prevState.preview.activeLink;\n\n\t\tif ( !state.preview.enabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( hasPrevActiveLink ) {\n\n\t\t\t// Has the user dwelled on a link immediately after abandoning another\n\t\t\t// (remembering that the ABANDON_END action is delayed by\n\t\t\t// ~10e2 ms).\n\t\t\tif ( prevState.preview.activeLink !== state.preview.activeLink ) {\n\t\t\t\trestoreTitleAttr( prevState.preview.activeLink );\n\t\t\t}\n\t\t}\n\n\t\tif ( state.preview.activeLink ) {\n\t\t\tdestroyTitleAttr( state.preview.activeLink );\n\t\t}\n\t};\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/linkTitle.js\n// module id = ./src/changeListeners/linkTitle.js\n// module chunks = 0","var renderer = require( '../renderer' );\n\n/**\n * Creates an instance of the render change listener.\n *\n * FIXME: Remove hard coupling with renderer, inject it as a parameter\n * * Wire it up in index.js\n * * Fix tests to remove require mocking\n *\n * @param {ext.popups.PreviewBehavior} previewBehavior\n * @return {ext.popups.ChangeListener}\n */\nmodule.exports = function ( previewBehavior ) {\n\tvar preview;\n\n\treturn function ( prevState, state ) {\n\t\tif ( state.preview.shouldShow && !preview ) {\n\t\t\tpreview = renderer.render( state.preview.fetchResponse );\n\t\t\tpreview.show(\n\t\t\t\tstate.preview.activeEvent,\n\t\t\t\tpreviewBehavior,\n\t\t\t\tstate.preview.activeToken\n\t\t\t\t);\n\t\t} else if ( !state.preview.shouldShow && preview ) {\n\t\t\tpreview.hide();\n\t\t\tpreview = undefined;\n\t\t}\n\t};\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/render.js\n// module id = ./src/changeListeners/render.js\n// module chunks = 0","/**\n * Creates an instance of the settings change listener.\n *\n * @param {Object} boundActions\n * @param {Object} render function that renders a jQuery el with the settings\n * @return {ext.popups.ChangeListener}\n */\nmodule.exports = function ( boundActions, render ) {\n\tvar settings;\n\n\treturn function ( prevState, state ) {\n\t\tif ( !prevState ) {\n\t\t\t// Nothing to do on initialization\n\t\t\treturn;\n\t\t}\n\n\t\t// Update global modal visibility\n\t\tif (\n\t\t\tprevState.settings.shouldShow === false &&\n\t\t\tstate.settings.shouldShow === true\n\t\t) {\n\t\t\t// Lazily instantiate the settings UI\n\t\t\tif ( !settings ) {\n\t\t\t\tsettings = render( boundActions );\n\t\t\t\tsettings.appendTo( document.body );\n\t\t\t}\n\n\t\t\t// Update the UI settings with the current settings\n\t\t\tsettings.setEnabled( state.preview.enabled );\n\n\t\t\tsettings.show();\n\t\t} else if (\n\t\t\tprevState.settings.shouldShow === true &&\n\t\t\tstate.settings.shouldShow === false\n\t\t) {\n\t\t\tsettings.hide();\n\t\t}\n\n\t\t// Update help visibility\n\t\tif ( prevState.settings.showHelp !== state.settings.showHelp ) {\n\t\t\tsettings.toggleHelp( state.settings.showHelp );\n\t\t}\n\t};\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/settings.js\n// module id = ./src/changeListeners/settings.js\n// module chunks = 0","/**\n * Creates an instance of the statsv change listener.\n *\n * The listener will log events to StatsD via the [the \"StatsD timers and\n * counters\" analytics event protocol][0].\n *\n * [0]: https://github.com/wikimedia/mediawiki-extensions-WikimediaEvents/blob/master/modules/ext.wikimediaEvents.statsd.js\n *\n * @param {Object} boundActions\n * @param {ext.popups.EventTracker} track\n * @return {ext.popups.ChangeListener}\n */\nmodule.exports = function ( boundActions, track ) {\n\treturn function ( _, state ) {\n\t\tvar statsv = state.statsv;\n\n\t\tif ( statsv.action ) {\n\t\t\ttrack( statsv.action, statsv.data );\n\n\t\t\tboundActions.statsvLogged();\n\t\t}\n\t};\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/statsv.js\n// module id = ./src/changeListeners/statsv.js\n// module chunks = 0","/**\n * Creates an instance of the user settings sync change listener.\n *\n * This change listener syncs certain parts of the state tree to user\n * settings when they change.\n *\n * Used for:\n *\n * * Enabled state: If the previews are enabled or disabled.\n * * Preview count: When the user dwells on a link for long enough that\n * a preview is shown, then their preview count will be incremented (see\n * `reducers/eventLogging.js`, and is persisted to local storage.\n *\n * @param {ext.popups.UserSettings} userSettings\n * @return {ext.popups.ChangeListener}\n */\nmodule.exports = function ( userSettings ) {\n\n\treturn function ( prevState, state ) {\n\n\t\tsyncIfChanged(\n\t\t\tprevState, state, 'eventLogging', 'previewCount',\n\t\t\tuserSettings.setPreviewCount\n\t\t);\n\t\tsyncIfChanged(\n\t\t\tprevState, state, 'preview', 'enabled',\n\t\t\tuserSettings.setIsEnabled\n\t\t);\n\n\t};\n};\n\n/**\n * Given a state tree, reducer and property, safely return the value of the\n * property if the reducer and property exist\n * @param {Object} state tree\n * @param {String} reducer key to access on the state tree\n * @param {String} prop key to access on the reducer key of the state tree\n * @return {*}\n */\nfunction get( state, reducer, prop ) {\n\treturn state[ reducer ] && state[ reducer ][ prop ];\n}\n\n/**\n * Calls a sync function if the property prop on the property reducer on\n * the state trees has changed value.\n * @param {Object} prevState\n * @param {Object} state\n * @param {String} reducer key to access on the state tree\n * @param {String} prop key to access on the reducer key of the state tree\n * @param {Function} sync function to be called with the newest value if\n * changed\n */\nfunction syncIfChanged( prevState, state, reducer, prop, sync ) {\n\tvar current = get( state, reducer, prop );\n\tif ( prevState && ( get( prevState, reducer, prop ) !== current ) ) {\n\t\tsync( current );\n\t}\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/syncUserSettings.js\n// module id = ./src/changeListeners/syncUserSettings.js\n// module chunks = 0","module.exports = {\n\tTHUMBNAIL_SIZE: 300 * $.bracketedDevicePixelRatio(),\n\tEXTRACT_LENGTH: 525\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/constants.js\n// module id = ./src/constants.js\n// module chunks = 0","/**\n * Return count bucket for the number of edits a user has made.\n *\n * The buckets are defined as part of\n * [the Popups schema](https://meta.wikimedia.org/wiki/Schema:Popups).\n *\n * Extracted from `mw.popups.schemaPopups.getEditCountBucket`.\n *\n * @param {Number} count\n * @return {String}\n */\nfunction getEditCountBucket( count ) {\n\tvar bucket;\n\n\tif ( count === 0 ) {\n\t\tbucket = '0';\n\t} else if ( count >= 1 && count <= 4 ) {\n\t\tbucket = '1-4';\n\t} else if ( count >= 5 && count <= 99 ) {\n\t\tbucket = '5-99';\n\t} else if ( count >= 100 && count <= 999 ) {\n\t\tbucket = '100-999';\n\t} else if ( count >= 1000 ) {\n\t\tbucket = '1000+';\n\t}\n\n\treturn bucket + ' edits';\n}\n\n/**\n * Return count bucket for the number of previews a user has seen.\n *\n * If local storage isn't available - because the user has disabled it\n * or the browser doesn't support it - then then \"unknown\" is returned.\n *\n * The buckets are defined as part of\n * [the Popups schema](https://meta.wikimedia.org/wiki/Schema:Popups).\n *\n * Extracted from `mw.popups.getPreviewCountBucket`.\n *\n * @param {Number} count\n * @return {String}\n */\nfunction getPreviewCountBucket( count ) {\n\tvar bucket;\n\n\tif ( count === -1 ) {\n\t\treturn 'unknown';\n\t}\n\n\tif ( count === 0 ) {\n\t\tbucket = '0';\n\t} else if ( count >= 1 && count <= 4 ) {\n\t\tbucket = '1-4';\n\t} else if ( count >= 5 && count <= 20 ) {\n\t\tbucket = '5-20';\n\t} else if ( count >= 21 ) {\n\t\tbucket = '21+';\n\t}\n\n\treturn bucket + ' previews';\n}\n\nmodule.exports = {\n\tgetPreviewCountBucket: getPreviewCountBucket,\n\tgetEditCountBucket: getEditCountBucket\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/counts.js\n// module id = ./src/counts.js\n// module chunks = 0","// Public and private cache lifetime (5 minutes)\nvar CACHE_LIFETIME = 300,\n\tcreateModel = require( '../preview/model' ).createModel;\n\n/**\n * MediaWiki API gateway factory\n *\n * @param {mw.Api} api\n * @param {mw.ext.constants} config\n * @returns {ext.popups.Gateway}\n */\nfunction createMediaWikiApiGateway( api, config ) {\n\n\t/**\n\t * Fetch page data from the API\n\t *\n\t * @param {String} title\n\t * @return {jQuery.Promise}\n\t */\n\tfunction fetch( title ) {\n\t\treturn api.get( {\n\t\t\taction: 'query',\n\t\t\tprop: 'info|extracts|pageimages|revisions|info',\n\t\t\tformatversion: 2,\n\t\t\tredirects: true,\n\t\t\texintro: true,\n\t\t\texchars: config.EXTRACT_LENGTH,\n\n\t\t\t// There is an added geometric limit on .mwe-popups-extract\n\t\t\t// so that text does not overflow from the card.\n\t\t\texplaintext: true,\n\n\t\t\tpiprop: 'thumbnail',\n\t\t\tpithumbsize: config.THUMBNAIL_SIZE,\n\t\t\tpilicense: 'any',\n\t\t\trvprop: 'timestamp',\n\t\t\tinprop: 'url',\n\t\t\ttitles: title,\n\t\t\tsmaxage: CACHE_LIFETIME,\n\t\t\tmaxage: CACHE_LIFETIME,\n\t\t\tuselang: 'content'\n\t\t}, {\n\t\t\theaders: {\n\t\t\t\t'X-Analytics': 'preview=1'\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Get the page summary from the api and transform the data\n\t *\n\t * @param {String} title\n\t * @returns {jQuery.Promise<ext.popups.PreviewModel>}\n\t */\n\tfunction getPageSummary( title ) {\n\t\treturn fetch( title )\n\t\t\t.then( extractPageFromResponse )\n\t\t\t.then( convertPageToModel );\n\t}\n\n\treturn {\n\t\tfetch: fetch,\n\t\textractPageFromResponse: extractPageFromResponse,\n\t\tconvertPageToModel: convertPageToModel,\n\t\tgetPageSummary: getPageSummary\n\t};\n}\n\n/**\n * Extract page data from the MediaWiki API response\n *\n * @param {Object} data API response data\n * @throws {Error} Throw an error if page data cannot be extracted,\n * i.e. if the response is empty,\n * @returns {Object}\n */\nfunction extractPageFromResponse( data ) {\n\tif (\n\t\tdata.query &&\n\t\tdata.query.pages &&\n\t\tdata.query.pages.length\n\t) {\n\t\treturn data.query.pages[ 0 ];\n\t}\n\n\tthrow new Error( 'API response `query.pages` is empty.' );\n}\n\n/**\n * Transform the MediaWiki API response to a preview model\n *\n * @param {Object} page\n * @returns {ext.popups.PreviewModel}\n */\nfunction convertPageToModel( page ) {\n\treturn createModel(\n\t\tpage.title,\n\t\tpage.canonicalurl,\n\t\tpage.pagelanguagehtmlcode,\n\t\tpage.pagelanguagedir,\n\t\tpage.extract,\n\t\tpage.thumbnail\n\t);\n}\n\nmodule.exports = createMediaWikiApiGateway;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/gateway/mediawiki.js\n// module id = ./src/gateway/mediawiki.js\n// module chunks = 0","var RESTBASE_ENDPOINT = '/api/rest_v1/page/summary/',\n\tRESTBASE_PROFILE = 'https://www.mediawiki.org/wiki/Specs/Summary/1.0.0',\n\tcreateModel = require( '../preview/model' ).createModel,\n\tmw = window.mediaWiki,\n\t$ = jQuery;\n\n/**\n * RESTBase gateway factory\n *\n * @param {Function} ajax function from jQuery for example\n * @param {ext.popups.constants} config set of configuration values\n * @returns {ext.popups.Gateway}\n */\nfunction createRESTBaseGateway( ajax, config ) {\n\n\t/**\n\t * Fetch page data from the API\n\t *\n\t * @param {String} title\n\t * @return {jQuery.Promise}\n\t */\n\tfunction fetch( title ) {\n\t\treturn ajax( {\n\t\t\turl: RESTBASE_ENDPOINT + encodeURIComponent( title ),\n\t\t\theaders: {\n\t\t\t\tAccept: 'application/json; charset=utf-8' +\n\t\t\t\t\t'profile=\"' + RESTBASE_PROFILE + '\"'\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Get the page summary from the api and transform the data\n\t *\n\t * Do not treat 404 as a failure as we want to show a generic\n\t * preview for missing pages.\n\t *\n\t * @param {String} title\n\t * @returns {jQuery.Promise<ext.popups.PreviewModel>}\n\t */\n\tfunction getPageSummary( title ) {\n\t\tvar result = $.Deferred();\n\n\t\tfetch( title )\n\t\t\t.then(\n\t\t\t\tfunction ( page ) {\n\t\t\t\t\tresult.resolve(\n\t\t\t\t\t\tconvertPageToModel( page, config.THUMBNAIL_SIZE ) );\n\t\t\t\t},\n\t\t\t\tfunction ( jqXHR ) {\n\t\t\t\t\tif ( jqXHR.status === 404 ) {\n\t\t\t\t\t\tresult.resolve(\n\t\t\t\t\t\t\tconvertPageToModel( {\n\t\t\t\t\t\t\t\ttitle: title,\n\t\t\t\t\t\t\t\tlang: '',\n\t\t\t\t\t\t\t\tdir: '',\n\t\t\t\t\t\t\t\textract: ''\n\t\t\t\t\t\t\t}, 0 )\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult.reject();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t);\n\n\t\treturn result.promise();\n\t}\n\n\treturn {\n\t\tfetch: fetch,\n\t\tconvertPageToModel: convertPageToModel,\n\t\tgetPageSummary: getPageSummary\n\t};\n}\n\n/**\n * Resizes the thumbnail to the requested width, preserving its aspect ratio.\n *\n * The requested width is limited to that of the original image unless the image\n * is an SVG, which can be scaled infinitely.\n *\n * This function is only intended to mangle the pretty thumbnail URLs used on\n * Wikimedia Commons. Once [an official thumb API](https://phabricator.wikimedia.org/T66214)\n * is fully specified and implemented, this function can be made more general.\n *\n * @param {Object} thumbnail The thumbnail image\n * @param {Object} original The original image\n * @param {int} thumbSize The requested size\n * @returns {Object}\n */\nfunction generateThumbnailData( thumbnail, original, thumbSize ) {\n\tvar parts = thumbnail.source.split( '/' ),\n\t\tlastPart = parts[ parts.length - 1 ],\n\t\tfilename,\n\t\twidth,\n\t\theight;\n\n\t// The last part, the thumbnail's full filename, is in the following form:\n\t// ${width}px-${filename}.${extension}. Splitting the thumbnail's filename\n\t// makes this function resilient to the thumbnail not having the same\n\t// extension as the original image, which is definitely the case for SVG's\n\t// where the thumbnail's extension is .svg.png.\n\tfilename = lastPart.substr( lastPart.indexOf( 'px-' ) + 3 );\n\n\t\t// Scale the thumbnail's largest dimension.\n\tif ( thumbnail.width > thumbnail.height ) {\n\t\twidth = thumbSize;\n\t\theight = Math.floor( ( thumbSize / thumbnail.width ) * thumbnail.height );\n\t} else {\n\t\twidth = Math.floor( ( thumbSize / thumbnail.height ) * thumbnail.width );\n\t\theight = thumbSize;\n\t}\n\n\t// If the image isn't an SVG, then it shouldn't be scaled past its original\n\t// dimensions.\n\tif ( width >= original.width && filename.indexOf( '.svg' ) === -1 ) {\n\t\treturn original;\n\t}\n\n\tparts[ parts.length - 1 ] = width + 'px-' + filename;\n\n\treturn {\n\t\tsource: parts.join( '/' ),\n\t\twidth: width,\n\t\theight: height\n\t};\n}\n\n/**\n * Transform the rest API response to a preview model\n *\n * @param {Object} page\n * @param {int} thumbSize\n * @returns {ext.popups.PreviewModel}\n */\nfunction convertPageToModel( page, thumbSize ) {\n\treturn createModel(\n\t\tpage.title,\n\t\tnew mw.Title( page.title ).getUrl(),\n\t\tpage.lang,\n\t\tpage.dir,\n\t\tpage.extract,\n\t\tpage.thumbnail ? generateThumbnailData( page.thumbnail, page.originalimage, thumbSize ) : undefined\n\t);\n}\n\nmodule.exports = createRESTBaseGateway;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/gateway/rest.js\n// module id = ./src/gateway/rest.js\n// module chunks = 0","var mw = window.mediaWiki;\n\n/**\n * Gets the title of a local page from an href given some configuration.\n *\n * @param {String} href\n * @param {mw.Map} config\n * @return {String|undefined}\n */\nfunction getTitle( href, config ) {\n\tvar linkHref,\n\t\tmatches,\n\t\tqueryLength,\n\t\ttitleRegex = new RegExp( mw.RegExp.escape( config.get( 'wgArticlePath' ) )\n\t\t\t.replace( '\\\\$1', '(.+)' ) );\n\n\t// Skip every URI that mw.Uri cannot parse\n\ttry {\n\t\tlinkHref = new mw.Uri( href );\n\t} catch ( e ) {\n\t\treturn undefined;\n\t}\n\n\t// External links\n\tif ( linkHref.host !== location.hostname ) {\n\t\treturn undefined;\n\t}\n\n\tqueryLength = Object.keys( linkHref.query ).length;\n\n\t// No query params (pretty URL)\n\tif ( !queryLength ) {\n\t\tmatches = titleRegex.exec( linkHref.path );\n\t\treturn matches ? decodeURIComponent( matches[ 1 ] ) : undefined;\n\t} else if ( queryLength === 1 && linkHref.query.hasOwnProperty( 'title' ) ) {\n\t\t// URL is not pretty, but only has a `title` parameter\n\t\treturn linkHref.query.title;\n\t}\n\n\treturn undefined;\n}\n\nmodule.exports = getTitle;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/getTitle.js\n// module id = ./src/getTitle.js\n// module chunks = 0","var mw = mediaWiki,\n\t$ = jQuery,\n\tRedux = require( 'redux' ),\n\tReduxThunk = require( 'redux-thunk' ),\n\tconstants = require( './constants' ),\n\n\tcreateRESTBaseGateway = require( './gateway/rest' ),\n\tcreateMediaWikiApiGateway = require( './gateway/mediawiki' ),\n\tcreateUserSettings = require( './userSettings' ),\n\tcreatePreviewBehavior = require( './previewBehavior' ),\n\tcreateSchema = require( './schema' ),\n\tcreateSettingsDialogRenderer = require( './settingsDialog' ),\n\tregisterChangeListener = require( './changeListener' ),\n\tcreateIsEnabled = require( './isEnabled' ),\n\tprocessLinks = require( './processLinks' ),\n\trenderer = require( './renderer' ),\n\tstatsvInstrumentation = require( './statsvInstrumentation' ),\n\n\tchangeListeners = require( './changeListeners' ),\n\tactions = require( './actions' ),\n\treducers = require( './reducers' ),\n\n\tBLACKLISTED_LINKS = [\n\t\t'.extiw',\n\t\t'.image',\n\t\t'.new',\n\t\t'.internal',\n\t\t'.external',\n\t\t'.oo-ui-buttonedElement-button',\n\t\t'.cancelLink a'\n\t];\n\n/**\n * @typedef {Function} ext.popups.EventTracker\n *\n * An analytics event tracker like `mw.track`.\n */\n\n/**\n * Creates a gateway with sensible values for the dependencies.\n *\n * @param {mw.Map} config\n * @return {ext.popups.Gateway}\n */\nfunction createGateway( config ) {\n\tif ( config.get( 'wgPopupsAPIUseRESTBase' ) ) {\n\t\treturn createRESTBaseGateway( $.ajax, constants );\n\t}\n\treturn createMediaWikiApiGateway( new mw.Api(), constants );\n}\n\n/**\n * Gets the appropriate analytics event tracker for logging metrics to StatsD\n * via the [the \"StatsD timers and counters\" analytics event protocol][0].\n *\n * If logging metrics to StatsD is enabled for the user, then the appriopriate\n * function is `mw.track`; otherwise it's `$.noop`.\n *\n * [0]: https://github.com/wikimedia/mediawiki-extensions-WikimediaEvents/blob/master/modules/ext.wikimediaEvents.statsd.js\n *\n * @param {Object} user\n * @param {Object} config\n * @param {Object} experiments\n * @return {ext.popups.EventTracker}\n */\nfunction getStatsvTracker( user, config, experiments ) {\n\treturn statsvInstrumentation.isEnabled( user, config, experiments ) ? mw.track : $.noop;\n}\n\n/**\n * Subscribes the registered change listeners to the\n * [store](http://redux.js.org/docs/api/Store.html#store).\n *\n * @param {Redux.Store} store\n * @param {Object} actions\n * @param {ext.popups.UserSettings} userSettings\n * @param {Function} settingsDialog\n * @param {ext.popups.PreviewBehavior} previewBehavior\n * @param {ext.popups.EventTracker} statsvTracker\n */\nfunction registerChangeListeners( store, actions, userSettings, settingsDialog, previewBehavior, statsvTracker ) {\n\tregisterChangeListener( store, changeListeners.footerLink( actions ) );\n\tregisterChangeListener( store, changeListeners.linkTitle() );\n\tregisterChangeListener( store, changeListeners.render( previewBehavior ) );\n\tregisterChangeListener( store, changeListeners.statsv( actions, statsvTracker ) );\n\tregisterChangeListener( store, changeListeners.syncUserSettings( userSettings ) );\n\tregisterChangeListener( store, changeListeners.settings( actions, settingsDialog ) );\n}\n\n/*\n * Initialize the application by:\n * 1. Creating the state store\n * 2. Binding the actions to such store\n * 3. Trigger the boot action to bootstrap the system\n * 4. When the page content is ready:\n * - Process the eligible links for page previews\n * - Initialize the renderer\n * - Bind hover and click events to the eligible links to trigger actions\n */\nmw.requestIdleCallback( function () {\n\tvar compose = Redux.compose,\n\t\tstore,\n\t\tboundActions,\n\n\t\t// So-called \"services\".\n\t\tgenerateToken = mw.user.generateRandomSessionId,\n\t\tgateway = createGateway( mw.config ),\n\t\tuserSettings,\n\t\tsettingsDialog,\n\t\tstatsvTracker,\n\t\tisEnabled,\n\t\tschema,\n\t\tpreviewBehavior;\n\n\tuserSettings = createUserSettings( mw.storage );\n\tsettingsDialog = createSettingsDialogRenderer();\n\tstatsvTracker = getStatsvTracker( mw.user, mw.config, mw.experiments );\n\n\tisEnabled = createIsEnabled( mw.user, userSettings, mw.config, mw.experiments );\n\n\t// If debug mode is enabled, then enable Redux DevTools.\n\tif ( mw.config.get( 'debug' ) === true ) {\n\t\t// eslint-disable-next-line no-underscore-dangle\n\t\tcompose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;\n\t}\n\n\tstore = Redux.createStore(\n\t\tRedux.combineReducers( reducers ),\n\t\tcompose( Redux.applyMiddleware(\n\t\t\tReduxThunk.default\n\t\t) )\n\t);\n\tboundActions = Redux.bindActionCreators( actions, store.dispatch );\n\n\tpreviewBehavior = createPreviewBehavior( mw.config, mw.user, boundActions );\n\n\tregisterChangeListeners(\n\t\tstore, boundActions, userSettings, settingsDialog,\n\t\tpreviewBehavior, statsvTracker\n\t);\n\n\t// Load EventLogging schema if possible...\n\tmw.loader.using( 'ext.eventLogging.Schema' ).done( function () {\n\t\tschema = createSchema( mw.config, window );\n\t\tregisterChangeListener( store, changeListeners.eventLogging( boundActions, schema, statsvTracker ) );\n\t} );\n\n\tboundActions.boot(\n\t\tisEnabled,\n\t\tmw.user,\n\t\tuserSettings,\n\t\tgenerateToken,\n\t\tmw.config\n\t);\n\n\tmw.hook( 'wikipage.content' ).add( function ( $container ) {\n\t\tvar previewLinks =\n\t\t\tprocessLinks(\n\t\t\t\t$container,\n\t\t\t\tBLACKLISTED_LINKS,\n\t\t\t\tmw.config\n\t\t\t);\n\n\t\trenderer.init();\n\n\t\tpreviewLinks\n\t\t\t.on( 'mouseover keyup', function ( event ) {\n\t\t\t\tboundActions.linkDwell( this, event, gateway, generateToken );\n\t\t\t} )\n\t\t\t.on( 'mouseout blur', function () {\n\t\t\t\tboundActions.abandon( this );\n\t\t\t} )\n\t\t\t.on( 'click', function () {\n\t\t\t\tboundActions.linkClick( this );\n\t\t\t} );\n\n\t} );\n} );\n\nwindow.Redux = Redux;\nwindow.ReduxThunk = ReduxThunk;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/index.js\n// module id = ./src/index.js\n// module chunks = 0","/**\n * Given the global state of the application, creates a function that gets\n * whether or not the user should have Page Previews enabled.\n *\n * Page Preview is disabled when the Navigation Popups gadget is enabled.\n *\n * If Page Previews is configured as a beta feature (see\n * `$wgPopupsBetaFeature`), the user must be logged in and have enabled the\n * beta feature in order to see previews. Logged out users won't be able\n * to see the feature.\n *\n * If Page Previews is configured as a preference, then the user must either\n * be logged in and have enabled the preference or be logged out and have not\n * disabled previews via the settings modal. Logged out users who have not\n * disabled or enabled the previews via the settings modal are sampled at\n * the sampling rate defined by `wgPopupsAnonsEnabledSamplingRate`.\n *\n * @param {mw.user} user The `mw.user` singleton instance\n * @param {Object} userSettings An object returned by `userSettings.js`\n * @param {mw.Map} config\n * @param {mw.experiments} experiments The `mw.experiments` singleton instance\n *\n * @return {Boolean}\n */\nmodule.exports = function ( user, userSettings, config, experiments ) {\n\tif ( config.get( 'wgPopupsConflictsWithNavPopupGadget' ) ) {\n\t\treturn false;\n\t}\n\n\tif ( !user.isAnon() ) {\n\t\treturn config.get( 'wgPopupsShouldSendModuleToUser' );\n\t}\n\n\tif ( config.get( 'wgPopupsBetaFeature' ) ) {\n\t\treturn false;\n\t}\n\n\tif ( !userSettings.hasIsEnabled() ) {\n\t\treturn isUserSampled( user, config, experiments );\n\t}\n\n\treturn userSettings.getIsEnabled();\n};\n\n/**\n * Is the user sampled based on a sampling rate?\n *\n * The sampling rate is taken from `wgPopupsAnonsEnabledSamplingRate` and\n * defaults to 0.9.\n *\n * @param {mw.user} user The `mw.user` singleton instance\n * @param {mw.Map} config\n * @param {mw.experiments} experiments The `mw.experiments` singleton instance\n *\n * @return {Boolean}\n */\nfunction isUserSampled( user, config, experiments ) {\n\tvar samplingRate = config.get( 'wgPopupsAnonsEnabledSamplingRate', 0.9 ),\n\t\tbucket = experiments.getBucket( {\n\t\t\tname: 'ext.Popups.visibility',\n\t\t\tenabled: true,\n\t\t\tbuckets: {\n\t\t\t\tcontrol: 1 - samplingRate,\n\t\t\t\tA: samplingRate\n\t\t\t}\n\t\t}, user.sessionId() );\n\n\treturn bucket === 'A';\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/isEnabled.js\n// module id = ./src/isEnabled.js\n// module chunks = 0","var TYPE_GENERIC = 'generic',\n\tTYPE_PAGE = 'page';\n\n/**\n * @typedef {Object} ext.popups.PreviewModel\n * @property {String} title\n * @property {String} url The canonical URL of the page being previewed\n * @property {String} languageCode\n * @property {String} languageDirection Either \"ltr\" or \"rtl\"\n * @property {String|undefined} extract `undefined` if the extract isn't\n * viable, e.g. if it's empty after having ellipsis and parentheticals\n * removed\n * @property {String} type Either \"EXTRACT\" or \"GENERIC\"\n * @property {Object|undefined} thumbnail\n */\n\n/**\n * Creates a preview model.\n *\n * @param {String} title\n * @param {String} url The canonical URL of the page being previewed\n * @param {String} languageCode\n * @param {String} languageDirection Either \"ltr\" or \"rtl\"\n * @param {String} extract\n * @param {Object|undefined} thumbnail\n * @return {ext.popups.PreviewModel}\n */\nfunction createModel(\n\ttitle,\n\turl,\n\tlanguageCode,\n\tlanguageDirection,\n\textract,\n\tthumbnail\n) {\n\tvar processedExtract = processExtract( extract ),\n\t\tresult = {\n\t\t\ttitle: title,\n\t\t\turl: url,\n\t\t\tlanguageCode: languageCode,\n\t\t\tlanguageDirection: languageDirection,\n\t\t\textract: processedExtract,\n\t\t\ttype: processedExtract === undefined ? TYPE_GENERIC : TYPE_PAGE,\n\t\t\tthumbnail: thumbnail\n\t\t};\n\n\treturn result;\n}\n\n/**\n * Processes the extract returned by the TextExtracts MediaWiki API query\n * module.\n *\n * @param {String|undefined} extract\n * @return {String|undefined}\n */\nfunction processExtract( extract ) {\n\tvar result;\n\n\tif ( extract === undefined || extract === '' ) {\n\t\treturn undefined;\n\t}\n\n\tresult = extract;\n\tresult = removeParentheticals( result );\n\tresult = removeEllipsis( result );\n\n\treturn result.length > 0 ? result : undefined;\n}\n\n/**\n * Removes the trailing ellipsis from the extract, if it's there.\n *\n * This function was extracted from\n * `mw.popups.renderer.article#removeEllipsis`.\n *\n * @param {String} extract\n * @return {String}\n */\nfunction removeEllipsis( extract ) {\n\treturn extract.replace( /\\.\\.\\.$/, '' );\n}\n\n/**\n * Removes parentheticals from the extract.\n *\n * If the parenthesis are unbalanced or out of order, then the extract is\n * returned without further processing.\n *\n * This function was extracted from\n * `mw.popups.renderer.article#removeParensFromText`.\n *\n * @param {String} extract\n * @return {String}\n */\nfunction removeParentheticals( extract ) {\n\tvar\n\t\tch,\n\t\tresult = '',\n\t\tlevel = 0,\n\t\ti = 0;\n\n\tfor ( i; i < extract.length; i++ ) {\n\t\tch = extract.charAt( i );\n\n\t\tif ( ch === ')' && level === 0 ) {\n\t\t\treturn extract;\n\t\t}\n\t\tif ( ch === '(' ) {\n\t\t\tlevel++;\n\t\t\tcontinue;\n\t\t} else if ( ch === ')' ) {\n\t\t\tlevel--;\n\t\t\tcontinue;\n\t\t}\n\t\tif ( level === 0 ) {\n\t\t\t// Remove leading spaces before brackets\n\t\t\tif ( ch === ' ' && extract.charAt( i + 1 ) === '(' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresult += ch;\n\t\t}\n\t}\n\n\treturn ( level === 0 ) ? result : extract;\n}\n\nmodule.exports = {\n\t/**\n\t* @constant {String}\n\t*/\n\tTYPE_GENERIC: TYPE_GENERIC,\n\t/**\n\t* @constant {String}\n\t*/\n\tTYPE_PAGE: TYPE_PAGE,\n\tcreateModel: createModel\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/preview/model.js\n// module id = ./src/preview/model.js\n// module chunks = 0","var mw = window.mediaWiki,\n\t$ = jQuery;\n\n/**\n * A collection of event handlers specific to how the user interacts with all\n * previews. The event handlers are are agnostic to how/when they are bound\n * //but not to what they are bound//, i.e. the showSettings event handler is\n * written to be bound to either an `<a>` or `<button>` element.\n *\n * @typedef {Object} ext.popups.PreviewBehavior\n * @property {String} settingsUrl\n * @property {Function} showSettings\n * @property {Function} previewDwell\n * @property {Function} previewAbandon\n * @property {Function} click handler for the entire preview\n */\n\n/**\n * Creates an instance of `ext.popups.PreviewBehavior`.\n *\n * If the user is logged out, then clicking the cog should show the settings\n * modal.\n *\n * If the user is logged in, then clicking the cog should send them to the\n * Special:Preferences page with the \"Beta features\" tab open if Page Previews\n * is enabled as a beta feature, or the \"Appearance\" tab otherwise.\n *\n * @param {mw.Map} config\n * @param {mw.User} user\n * @param {Object} actions The action creators bound to the Redux store\n * @return {ext.popups.PreviewBehavior}\n */\nmodule.exports = function ( config, user, actions ) {\n\tvar isBetaFeature = config.get( 'wgPopupsBetaFeature' ),\n\t\trawTitle,\n\t\tsettingsUrl,\n\t\tshowSettings = $.noop;\n\n\tif ( user.isAnon() ) {\n\t\tshowSettings = function ( event ) {\n\t\t\tevent.preventDefault();\n\n\t\t\tactions.showSettings();\n\t\t};\n\t} else {\n\t\trawTitle = 'Special:Preferences#mw-prefsection-';\n\t\trawTitle += isBetaFeature ? 'betafeatures' : 'rendering';\n\n\t\tsettingsUrl = mw.Title.newFromText( rawTitle )\n\t\t\t.getUrl();\n\t}\n\n\treturn {\n\t\tsettingsUrl: settingsUrl,\n\t\tshowSettings: showSettings,\n\t\tpreviewDwell: actions.previewDwell,\n\t\tpreviewAbandon: actions.abandon,\n\t\tpreviewShow: actions.previewShow,\n\t\tclick: actions.linkClick\n\t};\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/previewBehavior.js\n// module id = ./src/previewBehavior.js\n// module chunks = 0","var mw = window.mediaWiki,\n\t$ = jQuery,\n\tgetTitle = require( './getTitle' );\n\n/**\n * Processes and returns link elements (or \"`<a>`s\") that are eligible for\n * previews in a given container.\n *\n * An `<a>` is eligible for a preview if:\n *\n * * It has an href and a title, i.e. `<a href=\"/wiki/Foo\" title=\"Foo\" />`.\n * * It doesn't have any blacklisted CSS classes.\n * * Its href is a valid URI of a page on the local wiki.\n *\n * If an `<a>` is eligible, then the title of the page on the local wiki is\n * stored in the `data-previews-page-title` attribute for later reuse.\n *\n * @param {jQuery} $container\n * @param {String[]} blacklist If an `<a>` has one or more of these CSS\n * classes, then it will be ignored.\n * @param {mw.Map} config\n *\n * @return {jQuery}\n */\nfunction processLinks( $container, blacklist, config ) {\n\tvar contentNamespaces;\n\n\tcontentNamespaces = config.get( 'wgContentNamespaces' );\n\n\treturn $container\n\t\t.find( 'a[href][title]:not(' + blacklist.join( ', ' ) + ')' )\n\t\t.filter( function () {\n\t\t\tvar title,\n\t\t\t\ttitleText = getTitle( this.href, config );\n\n\t\t\tif ( !titleText ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// Is titleText in a content namespace?\n\t\t\ttitle = mw.Title.newFromText( titleText );\n\t\t\tif ( title && ( $.inArray( title.namespace, contentNamespaces ) >= 0 ) ) {\n\t\t\t\t$( this ).data( 'page-previews-title', titleText );\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} );\n}\n\nmodule.exports = processLinks;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/processLinks.js\n// module id = ./src/processLinks.js\n// module chunks = 0","var actionTypes = require( './../actionTypes' ),\n\tnextState = require( './nextState' ),\n\tcounts = require( './../counts' );\n\n/**\n * Initialize the data that's shared between all\n * [Popups](https://meta.wikimedia.org/wiki/Schema:Popups) events.\n *\n * @param {Object} bootAction\n * @return {Object}\n */\nfunction getBaseData( bootAction ) {\n\tvar result = {\n\t\tpageTitleSource: bootAction.page.title,\n\t\tnamespaceIdSource: bootAction.page.namespaceID,\n\t\tpageIdSource: bootAction.page.id,\n\t\tisAnon: bootAction.user.isAnon,\n\t\tpopupEnabled: bootAction.isEnabled,\n\t\tpageToken: bootAction.pageToken,\n\t\tsessionToken: bootAction.sessionToken,\n\t\tpreviewCountBucket: counts.getPreviewCountBucket( bootAction.user.previewCount ),\n\t\thovercardsSuppressedByGadget: bootAction.isNavPopupsEnabled\n\t};\n\n\tif ( !bootAction.user.isAnon ) {\n\t\tresult.editCountBucket = counts.getEditCountBucket( bootAction.user.editCount );\n\t}\n\n\treturn result;\n}\n\n/**\n * Creates an event that, when mixed into the base data (see `getBaseData`),\n * represents the user abandoning a link or preview.\n *\n * Since the event should be logged when the user has either abandoned a link or\n * dwelled on a different link, we refer to these events as \"closing\" events as\n * the link interaction has finished and a new one will be created later.\n *\n * If the link interaction is finalized, i.e. if an event has already been\n * logged for the link interaction, then no closing event is created.\n *\n * @param {Object} interaction\n * @return {Object|undefined}\n */\nfunction createClosingEvent( interaction ) {\n\tvar result = {\n\t\tlinkInteractionToken: interaction.token,\n\t\ttotalInteractionTime: Math.round( interaction.finished - interaction.started )\n\t};\n\n\tif ( interaction.finalized ) {\n\t\treturn undefined;\n\t}\n\n\t// Has the preview been shown? If so, then, in the context of the\n\t// instrumentation, then the preview has been dismissed by the user\n\t// rather than the user has abandoned the link.\n\tif ( interaction.timeToPreviewShow !== undefined ) {\n\t\tresult.action = 'dismissed';\n\t\tresult.previewType = interaction.previewType;\n\t\tresult.perceivedWait = interaction.timeToPreviewShow;\n\t} else {\n\t\tresult.action = 'dwelledButAbandoned';\n\t}\n\n\treturn result;\n}\n\n/**\n * Reducer for actions that may result in an event being logged with the\n * Popups schema via Event Logging.\n *\n * TODO: For obvious reasons, this reducer and the associated change listener\n * are tightly bound to the Popups schema. This reducer must be\n * renamed/moved if we introduce additional instrumentation.\n *\n * The complexity of this reducer reflects the complexity of the\n * [Popups](https://meta.wikimedia.org/wiki/Schema:Popups) instrumentation. This\n * complexity is further increased by requiring that actions are conditionally\n * reduced rather than conditionally dispatched in order to handle two delays\n * introduced by the system in order to provide a consistent UX.\n *\n * The reducer must:\n *\n * * Accumulate the state required to log\n * [Popups](https://meta.wikimedia.org/wiki/Schema:Popups) events. This state\n * is referred to as \"the interaction state\" or \"the interaction\";\n * * Handle only logging only one event per link interaction;\n * * Defend against delayed actions being dispatched and, as a direct\n * consequence;\n * * Handle transitioning from one interaction to another at the same time.\n *\n * Furthermore, we distinguish between \"finalizing\" and \"closing\" the current\n * interaction state. Since only one\n * [Popups](https://meta.wikimedia.org/wiki/Schema:Popups) event should be\n * logged per link interaction, we say that the interaction state is\n * //finalized// when an event has been logged and is //closed// when a new\n * interaction state should be created, e.g. the interaction state is only\n * finalized when the user clicks a link or a preview.\n *\n * @param {Object} state\n * @param {Object} action\n * @return {Object} The state resulting from reducing the action with the\n * current state\n */\nmodule.exports = function ( state, action ) {\n\tvar nextCount,\n\t\tactionTypesWithTokens = [\n\t\t\tactionTypes.FETCH_COMPLETE,\n\t\t\tactionTypes.ABANDON_END,\n\t\t\tactionTypes.PREVIEW_SHOW\n\t\t];\n\n\tif ( state === undefined ) {\n\t\tstate = {\n\t\t\tpreviewCount: undefined,\n\t\t\tbaseData: {},\n\t\t\tinteraction: undefined,\n\t\t\tevent: undefined\n\t\t};\n\t}\n\n\t// Was the action delayed? Then it requires a token to be reduced. Enforce\n\t// this here to avoid repetion and reduce nesting below.\n\tif (\n\t\tactionTypesWithTokens.indexOf( action.type ) !== -1 &&\n\t\t( !state.interaction || action.token !== state.interaction.token )\n\t) {\n\t\treturn state;\n\t}\n\n\tswitch ( action.type ) {\n\t\tcase actionTypes.BOOT:\n\t\t\treturn nextState( state, {\n\t\t\t\tpreviewCount: action.user.previewCount,\n\t\t\t\tbaseData: getBaseData( action ),\n\t\t\t\tevent: {\n\t\t\t\t\taction: 'pageLoaded'\n\t\t\t\t}\n\t\t\t} );\n\n\t\tcase actionTypes.EVENT_LOGGED:\n\t\t\treturn nextState( state, {\n\t\t\t\tevent: undefined\n\t\t\t} );\n\n\t\tcase actionTypes.FETCH_COMPLETE:\n\t\t\treturn nextState( state, {\n\t\t\t\tinteraction: nextState( state.interaction, {\n\t\t\t\t\tpreviewType: action.result.type\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase actionTypes.PREVIEW_SHOW:\n\t\t\tnextCount = state.previewCount + 1;\n\n\t\t\treturn nextState( state, {\n\t\t\t\tpreviewCount: nextCount,\n\t\t\t\tbaseData: nextState( state.baseData, {\n\t\t\t\t\tpreviewCountBucket: counts.getPreviewCountBucket( nextCount )\n\t\t\t\t} ),\n\t\t\t\tinteraction: nextState( state.interaction, {\n\t\t\t\t\ttimeToPreviewShow: Math.round( action.timestamp - state.interaction.started )\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase actionTypes.LINK_DWELL:\n\n\t\t\t// Not a new interaction?\n\t\t\tif ( state.interaction && action.el === state.interaction.link ) {\n\t\t\t\treturn nextState( state, {\n\t\t\t\t\tinteraction: nextState( state.interaction, {\n\t\t\t\t\t\tisUserDwelling: true\n\t\t\t\t\t} )\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn nextState( state, {\n\n\t\t\t\t// TODO: Extract this object into a module that can be shared between\n\t\t\t\t// this and the preview reducer.\n\t\t\t\tinteraction: {\n\t\t\t\t\tlink: action.el,\n\t\t\t\t\ttoken: action.token,\n\t\t\t\t\tstarted: action.timestamp,\n\n\t\t\t\t\tisUserDwelling: true\n\t\t\t\t},\n\n\t\t\t\t// Was the user interacting with another link? If so, then log the\n\t\t\t\t// abandoned event.\n\t\t\t\tevent: state.interaction ? createClosingEvent( state.interaction ) : undefined\n\t\t\t} );\n\n\t\tcase actionTypes.PREVIEW_DWELL:\n\t\t\treturn nextState( state, {\n\t\t\t\tinteraction: nextState( state.interaction, {\n\t\t\t\t\tisUserDwelling: true\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase actionTypes.LINK_CLICK:\n\t\t\treturn nextState( state, {\n\t\t\t\tinteraction: nextState( state.interaction, {\n\t\t\t\t\tfinalized: true\n\t\t\t\t} ),\n\t\t\t\tevent: {\n\t\t\t\t\taction: 'opened',\n\t\t\t\t\tlinkInteractionToken: state.interaction.token,\n\t\t\t\t\ttotalInteractionTime: Math.round( action.timestamp - state.interaction.started )\n\t\t\t\t}\n\t\t\t} );\n\n\t\tcase actionTypes.ABANDON_START:\n\t\t\treturn nextState( state, {\n\t\t\t\tinteraction: nextState( state.interaction, {\n\t\t\t\t\tfinished: action.timestamp,\n\n\t\t\t\t\tisUserDwelling: false\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase actionTypes.ABANDON_END:\n\t\t\tif ( !state.interaction.isUserDwelling ) {\n\t\t\t\treturn nextState( state, {\n\t\t\t\t\tinteraction: undefined,\n\t\t\t\t\tevent: createClosingEvent( state.interaction )\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn state;\n\n\t\tcase actionTypes.SETTINGS_SHOW:\n\t\t\treturn nextState( state, {\n\t\t\t\tevent: {\n\t\t\t\t\taction: 'tapped settings cog'\n\t\t\t\t}\n\t\t\t} );\n\n\t\tdefault:\n\t\t\treturn state;\n\t}\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/reducers/eventLogging.js\n// module id = ./src/reducers/eventLogging.js\n// module chunks = 0","module.exports = {\n\teventLogging: require( './eventLogging' ),\n\tpreview: require( './preview' ),\n\tsettings: require( './settings' ),\n\tstatsv: require( './statsv' )\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/reducers/index.js\n// module id = ./src/reducers/index.js\n// module chunks = 0","/**\n * Creates the next state tree from the current state tree and some updates.\n *\n * N.B. OO.copy doesn't copy Element instances, whereas $.extend does.\n * However, OO.copy does copy properties whose values are undefined or null,\n * whereas $.extend doesn't. Since the state tree contains an Element instance\n * - the preview.activeLink property - and we want to copy undefined/null into\n * the state we need to manually iterate over updates and check with\n * hasOwnProperty to copy over to the new state.\n *\n * In [change listeners](/doc/change_listeners.md), for example, we talk about\n * the previous state and the current state (the `prevState` and `state`\n * parameters, respectively). Since\n * [reducers](http://redux.js.org/docs/basics/Reducers.html) take the current\n * state and an action and make updates, \"next state\" seems appropriate.\n *\n * @param {Object} state\n * @param {Object} updates\n * @return {Object}\n */\nmodule.exports = function ( state, updates ) {\n\tvar result = {},\n\t\tkey;\n\n\tfor ( key in state ) {\n\t\tif ( state.hasOwnProperty( key ) && !updates.hasOwnProperty( key ) ) {\n\t\t\tresult[ key ] = state[ key ];\n\t\t}\n\t}\n\n\tfor ( key in updates ) {\n\t\tif ( updates.hasOwnProperty( key ) ) {\n\t\t\tresult[ key ] = updates[ key ];\n\t\t}\n\t}\n\n\treturn result;\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/reducers/nextState.js\n// module id = ./src/reducers/nextState.js\n// module chunks = 0","var actionTypes = require( './../actionTypes' ),\n\tnextState = require( './nextState' );\n\n/**\n * Reducer for actions that modify the state of the preview model\n *\n * @param {Object} state before action\n * @param {Object} action Redux action that modified state.\n * Must have `type` property.\n * @return {Object} state after action\n */\nmodule.exports = function ( state, action ) {\n\tif ( state === undefined ) {\n\t\tstate = {\n\t\t\tenabled: undefined,\n\t\t\tactiveLink: undefined,\n\t\t\tactiveEvent: undefined,\n\t\t\tactiveToken: '',\n\t\t\tshouldShow: false,\n\t\t\tisUserDwelling: false\n\t\t};\n\t}\n\n\tswitch ( action.type ) {\n\t\tcase actionTypes.BOOT:\n\t\t\treturn nextState( state, {\n\t\t\t\tenabled: action.isEnabled\n\t\t\t} );\n\t\tcase actionTypes.SETTINGS_CHANGE:\n\t\t\treturn nextState( state, {\n\t\t\t\tenabled: action.enabled\n\t\t\t} );\n\t\tcase actionTypes.LINK_DWELL:\n\t\t\t// New interaction\n\t\t\tif ( action.el !== state.activeLink ) {\n\t\t\t\treturn nextState( state, {\n\t\t\t\t\tactiveLink: action.el,\n\t\t\t\t\tactiveEvent: action.event,\n\t\t\t\t\tactiveToken: action.token,\n\n\t\t\t\t\t// When the user dwells on a link with their keyboard, a preview is\n\t\t\t\t\t// renderered, and then dwells on another link, the ABANDON_END\n\t\t\t\t\t// action will be ignored.\n\t\t\t\t\t//\n\t\t\t\t\t// Ensure that all the preview is hidden.\n\t\t\t\t\tshouldShow: false,\n\n\t\t\t\t\tisUserDwelling: true\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\t// Dwelling back into the same link\n\t\t\t\treturn nextState( state, {\n\t\t\t\t\tisUserDwelling: true\n\t\t\t\t} );\n\t\t\t}\n\n\t\tcase actionTypes.ABANDON_END:\n\t\t\tif ( action.token === state.activeToken && !state.isUserDwelling ) {\n\t\t\t\treturn nextState( state, {\n\t\t\t\t\tactiveLink: undefined,\n\t\t\t\t\tactiveToken: undefined,\n\t\t\t\t\tactiveEvent: undefined,\n\t\t\t\t\tfetchResponse: undefined,\n\t\t\t\t\tshouldShow: false\n\t\t\t\t} );\n\t\t\t}\n\t\t\treturn state;\n\n\t\tcase actionTypes.PREVIEW_DWELL:\n\t\t\treturn nextState( state, {\n\t\t\t\tisUserDwelling: true\n\t\t\t} );\n\n\t\tcase actionTypes.ABANDON_START:\n\t\t\treturn nextState( state, {\n\t\t\t\tisUserDwelling: false\n\t\t\t} );\n\n\t\tcase actionTypes.FETCH_START:\n\t\t\treturn nextState( state, {\n\t\t\t\tfetchResponse: undefined\n\t\t\t} );\n\t\tcase actionTypes.FETCH_COMPLETE:\n\t\t\tif ( action.token === state.activeToken ) {\n\t\t\t\treturn nextState( state, {\n\t\t\t\t\tfetchResponse: action.result,\n\t\t\t\t\tshouldShow: state.isUserDwelling\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t/* falls through */\n\t\tdefault:\n\t\t\treturn state;\n\t}\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/reducers/preview.js\n// module id = ./src/reducers/preview.js\n// module chunks = 0","var actionTypes = require( './../actionTypes' ),\n\tnextState = require( './nextState' );\n\n/**\n * Reducer for actions that modify the state of the settings\n *\n * @param {Object} state\n * @param {Object} action\n * @return {Object} state after action\n */\nmodule.exports = function ( state, action ) {\n\tif ( state === undefined ) {\n\t\tstate = {\n\t\t\tshouldShow: false,\n\t\t\tshowHelp: false,\n\t\t\tshouldShowFooterLink: false\n\t\t};\n\t}\n\n\tswitch ( action.type ) {\n\t\tcase actionTypes.SETTINGS_SHOW:\n\t\t\treturn nextState( state, {\n\t\t\t\tshouldShow: true,\n\t\t\t\tshowHelp: false\n\t\t\t} );\n\t\tcase actionTypes.SETTINGS_HIDE:\n\t\t\treturn nextState( state, {\n\t\t\t\tshouldShow: false,\n\t\t\t\tshowHelp: false\n\t\t\t} );\n\t\tcase actionTypes.SETTINGS_CHANGE:\n\t\t\treturn action.wasEnabled === action.enabled ?\n\t\t\t\t// If the setting is the same, just hide the dialogs\n\t\t\t\tnextState( state, {\n\t\t\t\t\tshouldShow: false\n\t\t\t\t} ) :\n\t\t\t\t// If the settings have changed...\n\t\t\t\tnextState( state, {\n\t\t\t\t\t// If we enabled, we just hide directly, no help\n\t\t\t\t\t// If we disabled, keep it showing and let the ui show the help.\n\t\t\t\t\tshouldShow: !action.enabled,\n\t\t\t\t\tshowHelp: !action.enabled,\n\n\t\t\t\t\t// Since the footer link is only ever shown to anonymous users (see\n\t\t\t\t\t// the BOOT case below), state.userIsAnon is always truthy here.\n\t\t\t\t\tshouldShowFooterLink: !action.enabled\n\t\t\t\t} );\n\n\t\tcase actionTypes.BOOT:\n\t\t\treturn nextState( state, {\n\t\t\t\tshouldShowFooterLink: action.user.isAnon && !action.isEnabled\n\t\t\t} );\n\t\tdefault:\n\t\t\treturn state;\n\t}\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/reducers/settings.js\n// module id = ./src/reducers/settings.js\n// module chunks = 0","var actionTypes = require( './../actionTypes' ),\n\tnextState = require( './nextState' );\n\n/**\n * Reducer for actions that may result in an event being logged via statsv.\n *\n * @param {Object} state\n * @param {Object} action\n * @return {Object} state after action\n */\nmodule.exports = function ( state, action ) {\n\tstate = state || {};\n\n\tswitch ( action.type ) {\n\t\tcase actionTypes.FETCH_START:\n\t\t\treturn nextState( state, {\n\t\t\t\tfetchStartedAt: action.timestamp\n\t\t\t} );\n\n\t\tcase actionTypes.FETCH_END:\n\t\t\treturn nextState( state, {\n\t\t\t\taction: 'timing.PagePreviewsApiResponse',\n\t\t\t\tdata: action.timestamp - state.fetchStartedAt\n\t\t\t} );\n\n\t\tcase actionTypes.FETCH_FAILED:\n\t\t\treturn nextState( state, {\n\t\t\t\taction: 'counter.PagePreviewsApiFailure',\n\t\t\t\tdata: 1\n\t\t\t} );\n\n\t\tcase actionTypes.LINK_DWELL:\n\t\t\treturn nextState( state, {\n\t\t\t\tlinkDwellStartedAt: action.timestamp\n\t\t\t} );\n\n\t\tcase actionTypes.PREVIEW_SHOW:\n\t\t\treturn nextState( state, {\n\t\t\t\taction: 'timing.PagePreviewsPreviewShow',\n\t\t\t\tdata: action.timestamp - state.linkDwellStartedAt\n\t\t\t} );\n\n\t\tcase actionTypes.STATSV_LOGGED:\n\t\t\treturn nextState( state, {\n\t\t\t\taction: null,\n\t\t\t\tdata: null\n\t\t\t} );\n\n\t\tdefault:\n\t\t\treturn state;\n\t}\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/reducers/statsv.js\n// module id = ./src/reducers/statsv.js\n// module chunks = 0","var mw = window.mediaWiki,\n\t$ = jQuery,\n\twait = require( './wait' ),\n\tSIZES = {\n\t\tportraitImage: {\n\t\t\th: 250, // Exact height\n\t\t\tw: 203 // Max width\n\t\t},\n\t\tlandscapeImage: {\n\t\t\th: 200, // Max height\n\t\t\tw: 300 // Exact Width\n\t\t},\n\t\tlandscapePopupWidth: 450,\n\t\tportraitPopupWidth: 300,\n\t\tpokeySize: 8 // Height of the pokey.\n\t},\n\t$window = $( window );\n\n/**\n * Extracted from `mw.popups.createSVGMasks`.\n * @private\n * @param {Object} container DOM object to which pokey masks are appended\n */\nfunction createPokeyMasks( container ) {\n\t$( '<div>' )\n\t\t.attr( 'id', 'mwe-popups-svg' )\n\t\t.html(\n\t\t\t'<svg width=\"0\" height=\"0\">' +\n\t\t\t\t'<defs>' +\n\t\t\t\t\t'<clippath id=\"mwe-popups-mask\">' +\n\t\t\t\t\t\t'<polygon points=\"0 8, 10 8, 18 0, 26 8, 1000 8, 1000 1000, 0 1000\"/>' +\n\t\t\t\t\t'</clippath>' +\n\t\t\t\t\t'<clippath id=\"mwe-popups-mask-flip\">' +\n\t\t\t\t\t\t'<polygon points=\"0 8, 274 8, 282 0, 290 8, 1000 8, 1000 1000, 0 1000\"/>' +\n\t\t\t\t\t'</clippath>' +\n\t\t\t\t\t'<clippath id=\"mwe-popups-landscape-mask\">' +\n\t\t\t\t\t\t'<polygon points=\"0 8, 174 8, 182 0, 190 8, 1000 8, 1000 1000, 0 1000\"/>' +\n\t\t\t\t\t'</clippath>' +\n\t\t\t\t\t'<clippath id=\"mwe-popups-landscape-mask-flip\">' +\n\t\t\t\t\t\t'<polygon points=\"0 0, 1000 0, 1000 242, 190 242, 182 250, 174 242, 0 242\"/>' +\n\t\t\t\t\t'</clippath>' +\n\t\t\t\t'</defs>' +\n\t\t\t'</svg>'\n\t\t)\n\t\t.appendTo( container );\n}\n\n/**\n * Initializes the renderer.\n */\nfunction init() {\n\tcreatePokeyMasks( document.body );\n}\n\n/**\n * The model of how a view is rendered, which is constructed from a response\n * from the gateway.\n *\n * TODO: Rename `isTall` to `isPortrait`.\n *\n * @typedef {Object} ext.popups.Preview\n * @property {jQuery} el\n * @property {Boolean} hasThumbnail\n * @property {Object} thumbnail\n * @property {Boolean} isTall Sugar around\n * `preview.hasThumbnail && thumbnail.isTall`\n */\n\n/**\n * Renders a preview given data from the {@link gateway ext.popups.Gateway}.\n * The preview is rendered and added to the DOM but will remain hidden until\n * the `show` method is called.\n *\n * Previews are rendered at:\n *\n * # The position of the mouse when the user dwells on the link with their\n * mouse.\n * # The centermost point of the link when the user dwells on the link with\n * their keboard or other assistive device.\n *\n * Since the content of the preview doesn't change but its position might, we\n * distinguish between \"rendering\" - generating HTML from a MediaWiki API\n * response - and \"showing/hiding\" - positioning the layout and changing its\n * orientation, if necessary.\n *\n * @param {ext.popups.PreviewModel} model\n * @return {ext.popups.Preview}\n */\nfunction render( model ) {\n\tvar preview = model.extract === undefined ? createEmptyPreview( model ) : createPreview( model );\n\n\treturn {\n\n\t\t/**\n\t\t * Shows the preview given an event representing the user's interaction\n\t\t * with the active link, e.g. an instance of\n\t\t * [MouseEvent](https://developer.mozilla.org/en/docs/Web/API/MouseEvent).\n\t\t *\n\t\t * See `show` for more detail.\n\t\t *\n\t\t * @param {Event} event\n\t\t * @param {Object} boundActions The\n\t\t * [bound action creators](http://redux.js.org/docs/api/bindActionCreators.html)\n\t\t * that were (likely) created in [boot.js](./boot.js).\n\t\t * @param {String} token The unique token representing the link interaction\n\t\t * that resulted in showing the preview\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tshow: function ( event, boundActions, token ) {\n\t\t\treturn show(\n\t\t\t\tpreview, event, $( event.target ), boundActions, token,\n\t\t\t\tdocument.body\n\t\t\t);\n\t\t},\n\n\t\t/**\n\t\t * Hides the preview.\n\t\t *\n\t\t * See `hide` for more detail.\n\t\t *\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\thide: function () {\n\t\t\treturn hide( preview );\n\t\t}\n\t};\n}\n\n/**\n * Creates an instance of the DTO backing a preview.\n *\n * @param {ext.popups.PreviewModel} model\n * @return {ext.popups.Preview}\n */\nfunction createPreview( model ) {\n\tvar templateData,\n\t\tthumbnail = createThumbnail( model.thumbnail ),\n\t\thasThumbnail = thumbnail !== null,\n\n\t\t// FIXME: This should probably be moved into the gateway as we'll soon be\n\t\t// fetching HTML from the API. See\n\t\t// https://phabricator.wikimedia.org/T141651 for more detail.\n\t\textract = renderExtract( model.extract, model.title ),\n\n\t\t$el;\n\n\ttemplateData = $.extend( {}, model, {\n\t\thasThumbnail: hasThumbnail\n\t} );\n\n\t$el = mw.template.get( 'ext.popups', 'preview.mustache' )\n\t\t.render( templateData );\n\n\tif ( hasThumbnail ) {\n\t\t$el.find( '.mwe-popups-discreet' ).append( thumbnail.el );\n\t}\n\n\tif ( extract.length ) {\n\t\t$el.find( '.mwe-popups-extract' ).append( extract );\n\t}\n\n\treturn {\n\t\tel: $el,\n\t\thasThumbnail: hasThumbnail,\n\t\tthumbnail: thumbnail,\n\t\tisTall: hasThumbnail && thumbnail.isTall\n\t};\n}\n\n/**\n * Creates an instance of the DTO backing a preview. In this case the DTO\n * represents a generic preview, which covers the following scenarios:\n *\n * * The page doesn't exist, i.e. the user hovered over a redlink or a\n * redirect to a page that doesn't exist.\n * * The page doesn't have a viable extract.\n *\n * @param {ext.popups.PreviewModel} model\n * @return {ext.popups.Preview}\n */\nfunction createEmptyPreview( model ) {\n\tvar templateData,\n\t\t$el;\n\n\ttemplateData = $.extend( {}, model, {\n\t\textractMsg: mw.msg( 'popups-preview-no-preview' ),\n\t\treadMsg: mw.msg( 'popups-preview-footer-read' )\n\t} );\n\n\t$el = mw.template.get( 'ext.popups', 'preview-empty.mustache' )\n\t\t.render( templateData );\n\n\treturn {\n\t\tel: $el,\n\t\thasThumbnail: false,\n\t\tisTall: false\n\t};\n}\n\n/**\n * Converts the extract into a list of elements, which correspond to fragments\n * of the extract. Fragements that match the title verbatim are wrapped in a\n * `<b>` element.\n *\n * Using the bolded elements of the extract of the page directly is covered by\n * [T141651](https://phabricator.wikimedia.org/T141651).\n *\n * Extracted from `mw.popups.renderer.article.getProcessedElements`.\n *\n * @param {String} extract\n * @param {String} title\n * @return {Array}\n */\nfunction renderExtract( extract, title ) {\n\tvar regExp, escapedTitle,\n\t\telements = [],\n\t\tboldIdentifier = '<bi-' + Math.random() + '>',\n\t\tsnip = '<snip-' + Math.random() + '>';\n\n\ttitle = title.replace( /\\s+/g, ' ' ).trim(); // Remove extra white spaces\n\tescapedTitle = mw.RegExp.escape( title ); // Escape RegExp elements\n\tregExp = new RegExp( '(^|\\\\s)(' + escapedTitle + ')(|$)', 'i' );\n\n\t// Remove text in parentheses along with the parentheses\n\textract = extract.replace( /\\s+/, ' ' ); // Remove extra white spaces\n\n\t// Make title bold in the extract text\n\t// As the extract is html escaped there can be no such string in it\n\t// Also, the title is escaped of RegExp elements thus can't have \"*\"\n\textract = extract.replace( regExp, '$1' + snip + boldIdentifier + '$2' + snip + '$3' );\n\textract = extract.split( snip );\n\n\t$.each( extract, function ( index, part ) {\n\t\tif ( part.indexOf( boldIdentifier ) === 0 ) {\n\t\t\telements.push( $( '<b>' ).text( part.substring( boldIdentifier.length ) ) );\n\t\t} else {\n\t\t\telements.push( document.createTextNode( part ) );\n\t\t}\n\t} );\n\n\treturn elements;\n}\n\n/**\n * Shows the preview.\n *\n * Extracted from `mw.popups.render.openPopup`.\n *\n * TODO: From the perspective of the client, there's no need to distinguish\n * between renderering and showing a preview. Merge #render and Preview#show.\n *\n * @param {ext.popups.Preview} preview\n * @param {Event} event\n * @param {jQuery} $link event target\n * @param {ext.popups.PreviewBehavior} behavior\n * @param {String} token\n * @param {Object} container DOM object to which pokey masks are appended\n * @return {jQuery.Promise} A promise that resolves when the promise has faded\n * in\n */\nfunction show( preview, event, $link, behavior, token, container ) {\n\tvar layout = createLayout(\n\t\tpreview.isTall,\n\t\t{\n\t\t\tpageX: event.pageX,\n\t\t\tpageY: event.pageY,\n\t\t\tclientY: event.clientY\n\t\t},\n\t\t{\n\t\t\tclientRects: $link.get( 0 ).getClientRects(),\n\t\t\toffset: $link.offset(),\n\t\t\twidth: $link.width(),\n\t\t\theight: $link.height()\n\t\t},\n\t\t{\n\t\t\tscrollTop: $window.scrollTop(),\n\t\t\twidth: $window.width(),\n\t\t\theight: $window.height()\n\t\t},\n\t\tSIZES.pokeySize\n\t);\n\n\tpreview.el.appendTo( container );\n\n\tlayoutPreview(\n\t\tpreview, layout, getClasses( preview, layout ),\n\t\tSIZES.landscapeImage.h, SIZES.pokeySize\n\t);\n\n\tpreview.el.show();\n\n\treturn wait( 200 )\n\t\t.then( function () {\n\t\t\tbindBehavior( preview, behavior );\n\t\t} )\n\t\t.then( function () {\n\t\t\tbehavior.previewShow( token );\n\t\t} );\n}\n\n/**\n * Binds the behavior to the interactive elements of the preview.\n *\n * @param {ext.popups.Preview} preview\n * @param {ext.popups.PreviewBehavior} behavior\n */\nfunction bindBehavior( preview, behavior ) {\n\tpreview.el.hover( behavior.previewDwell, behavior.previewAbandon );\n\n\tpreview.el.click( behavior.click );\n\n\tpreview.el.find( '.mwe-popups-settings-icon' )\n\t\t.attr( 'href', behavior.settingsUrl )\n\t\t.click( function ( event ) {\n\t\t\tevent.stopPropagation();\n\n\t\t\tbehavior.showSettings( event );\n\t\t} );\n}\n\n/**\n * Extracted from `mw.popups.render.closePopup`.\n *\n * @param {ext.popups.Preview} preview\n * @return {jQuery.Promise} A promise that resolves when the preview has faded\n * out\n */\nfunction hide( preview ) {\n\tvar fadeInClass,\n\t\tfadeOutClass;\n\n\t// FIXME: This method clearly needs access to the layout of the preview.\n\tfadeInClass = ( preview.el.hasClass( 'mwe-popups-fade-in-up' ) ) ?\n\t\t'mwe-popups-fade-in-up' :\n\t\t'mwe-popups-fade-in-down';\n\n\tfadeOutClass = ( fadeInClass === 'mwe-popups-fade-in-up' ) ?\n\t\t'mwe-popups-fade-out-down' :\n\t\t'mwe-popups-fade-out-up';\n\n\tpreview.el\n\t\t.removeClass( fadeInClass )\n\t\t.addClass( fadeOutClass );\n\n\treturn wait( 150 ).then( function () {\n\t\tpreview.el.remove();\n\t} );\n}\n\n/**\n * @typedef {Object} ext.popups.Thumbnail\n * @property {Element} el\n * @property {Boolean} isTall Whether or not the thumbnail is portrait\n */\n\n/**\n * Creates a thumbnail from the representation of a thumbnail returned by the\n * PageImages MediaWiki API query module.\n *\n * If there's no thumbnail, the thumbnail is too small, or the thumbnail's URL\n * contains characters that could be used to perform an\n * [XSS attack via CSS](https://www.owasp.org/index.php/Testing_for_CSS_Injection_(OTG-CLIENT-005)),\n * then `null` is returned.\n *\n * Extracted from `mw.popups.renderer.article.createThumbnail`.\n *\n * @param {Object} rawThumbnail\n * @return {ext.popups.Thumbnail|null}\n */\nfunction createThumbnail( rawThumbnail ) {\n\tvar tall, thumbWidth, thumbHeight,\n\t\tx, y, width, height, clipPath,\n\t\tdevicePixelRatio = $.bracketedDevicePixelRatio();\n\n\tif ( !rawThumbnail ) {\n\t\treturn null;\n\t}\n\n\ttall = rawThumbnail.width < rawThumbnail.height;\n\tthumbWidth = rawThumbnail.width / devicePixelRatio;\n\tthumbHeight = rawThumbnail.height / devicePixelRatio;\n\n\tif (\n\t\t// Image too small for landscape display\n\t\t( !tall && thumbWidth < SIZES.landscapeImage.w ) ||\n\t\t// Image too small for portrait display\n\t\t( tall && thumbHeight < SIZES.portraitImage.h ) ||\n\t\t// These characters in URL that could inject CSS and thus JS\n\t\t(\n\t\t\trawThumbnail.source.indexOf( '\\\\' ) > -1 ||\n\t\t\trawThumbnail.source.indexOf( '\\'' ) > -1 ||\n\t\t\trawThumbnail.source.indexOf( '\\\"' ) > -1\n\t\t)\n\t) {\n\t\treturn null;\n\t}\n\n\tif ( tall ) {\n\t\tx = ( thumbWidth > SIZES.portraitImage.w ) ?\n\t\t\t( ( thumbWidth - SIZES.portraitImage.w ) / -2 ) :\n\t\t\t( SIZES.portraitImage.w - thumbWidth );\n\t\ty = ( thumbHeight > SIZES.portraitImage.h ) ?\n\t\t\t( ( thumbHeight - SIZES.portraitImage.h ) / -2 ) : 0;\n\t\twidth = SIZES.portraitImage.w;\n\t\theight = SIZES.portraitImage.h;\n\t} else {\n\t\tx = 0;\n\t\ty = ( thumbHeight > SIZES.landscapeImage.h ) ?\n\t\t\t( ( thumbHeight - SIZES.landscapeImage.h ) / -2 ) : 0;\n\t\twidth = SIZES.landscapeImage.w + 3;\n\t\theight = ( thumbHeight > SIZES.landscapeImage.h ) ?\n\t\t\tSIZES.landscapeImage.h : thumbHeight;\n\t\tclipPath = 'mwe-popups-mask';\n\t}\n\n\treturn {\n\t\tel: createThumbnailElement(\n\t\t\ttall ? 'mwe-popups-is-tall' : 'mwe-popups-is-not-tall',\n\t\t\trawThumbnail.source,\n\t\t\tx,\n\t\t\ty,\n\t\t\tthumbWidth,\n\t\t\tthumbHeight,\n\t\t\twidth,\n\t\t\theight,\n\t\t\tclipPath\n\t\t),\n\t\tisTall: tall,\n\t\twidth: thumbWidth,\n\t\theight: thumbHeight\n\t};\n}\n\n/**\n * Creates the SVG image element that represents the thumbnail.\n *\n * This function is distinct from `createThumbnail` as it abstracts away some\n * browser issues that are uncovered when manipulating elements across\n * namespaces.\n *\n * @param {String} className\n * @param {String} url\n * @param {Number} x\n * @param {Number} y\n * @param {Number} thumbnailWidth\n * @param {Number} thumbnailHeight\n * @param {Number} width\n * @param {Number} height\n * @param {String} clipPath\n * @return {jQuery}\n */\nfunction createThumbnailElement( className, url, x, y, thumbnailWidth, thumbnailHeight, width, height, clipPath ) {\n\tvar $thumbnailSVGImage, $thumbnail,\n\t\tnsSvg = 'http://www.w3.org/2000/svg',\n\t\tnsXlink = 'http://www.w3.org/1999/xlink';\n\n\t$thumbnailSVGImage = $( document.createElementNS( nsSvg, 'image' ) );\n\t$thumbnailSVGImage[ 0 ].setAttributeNS( nsXlink, 'href', url );\n\t$thumbnailSVGImage\n\t\t.addClass( className )\n\t\t.attr( {\n\t\t\tx: x,\n\t\t\ty: y,\n\t\t\twidth: thumbnailWidth,\n\t\t\theight: thumbnailHeight,\n\t\t\t'clip-path': 'url(#' + clipPath + ')'\n\t\t} );\n\n\t$thumbnail = $( document.createElementNS( nsSvg, 'svg' ) )\n\t\t.attr( {\n\t\t\txmlns: nsSvg,\n\t\t\twidth: width,\n\t\t\theight: height\n\t\t} )\n\t\t.append( $thumbnailSVGImage );\n\n\treturn $thumbnail;\n}\n\n/**\n * Represents the layout of a preview, which consists of a position (`offset`)\n * and whether or not the preview should be flipped horizontally or\n * vertically (`flippedX` and `flippedY` respectively).\n *\n * @typedef {Object} ext.popups.PreviewLayout\n * @property {Object} offset\n * @property {number} offset.top\n * @property {number} offset.left\n * @property {Boolean} flippedX\n * @property {Boolean} flippedY\n */\n\n/**\n * @param {isPreviewTall} isPreviewTall\n * @param {Object} eventData Data related to the event that triggered showing a popup\n * @param {number} eventData.pageX\n * @param {number} eventData.pageY\n * @param {number} eventData.clientY\n * @param {Object} linkData Data related to the link that’s used for showing a popup\n * @param {ClientRectList} linkData.clientRects list of rectangles defined by four edges\n * @param {Object} linkData.offset\n * @param {number} linkData.width\n * @param {number} linkData.height\n * @param {Object} windowData Data related to the window\n * @param {number} windowData.scrollTop\n * @param {number} windowData.width\n * @param {number} windowData.height\n * @param {number} pokeySize Space reserved for the pokey\n * @return {ext.popups.PreviewLayout}\n */\nfunction createLayout( isPreviewTall, eventData, linkData, windowData, pokeySize ) {\n\tvar flippedX = false,\n\t\tflippedY = false,\n\t\toffsetTop = ( eventData.pageY ) ? // If it was a mouse event\n\t\t\t// Position according to mouse\n\t\t\t// Since client rectangles are relative to the viewport,\n\t\t\t// take scroll position into account.\n\t\t\tgetClosestYPosition(\n\t\t\t\teventData.pageY - windowData.scrollTop,\n\t\t\t\tlinkData.clientRects,\n\t\t\t\tfalse\n\t\t\t) + windowData.scrollTop + pokeySize :\n\t\t\t// Position according to link position or size\n\t\t\tlinkData.offset.top + linkData.height + pokeySize,\n\t\tclientTop = ( eventData.clientY ) ?\n\t\t\teventData.clientY :\n\t\t\toffsetTop,\n\t\toffsetLeft = ( eventData.pageX ) ?\n\t\t\teventData.pageX :\n\t\t\tlinkData.offset.left;\n\n\t// X Flip\n\tif ( offsetLeft > ( windowData.width / 2 ) ) {\n\t\toffsetLeft += ( !eventData.pageX ) ? linkData.width : 0;\n\t\toffsetLeft -= !isPreviewTall ?\n\t\t\tSIZES.portraitPopupWidth :\n\t\t\tSIZES.landscapePopupWidth;\n\t\tflippedX = true;\n\t}\n\n\tif ( eventData.pageX ) {\n\t\toffsetLeft += ( flippedX ) ? 20 : -20;\n\t}\n\n\t// Y Flip\n\tif ( clientTop > ( windowData.height / 2 ) ) {\n\t\tflippedY = true;\n\n\t\t// Mirror the positioning of the preview when there's no \"Y flip\": rest\n\t\t// the pokey on the edge of the link's bounding rectangle. In this case\n\t\t// the edge is the top-most.\n\t\toffsetTop = linkData.offset.top;\n\n\t\t// Change the Y position to the top of the link\n\t\tif ( eventData.pageY ) {\n\t\t\t// Since client rectangles are relative to the viewport,\n\t\t\t// take scroll position into account.\n\t\t\toffsetTop = getClosestYPosition(\n\t\t\t\teventData.pageY - windowData.scrollTop,\n\t\t\t\tlinkData.clientRects,\n\t\t\t\ttrue\n\t\t\t) + windowData.scrollTop;\n\t\t}\n\n\t\toffsetTop -= pokeySize;\n\t}\n\n\treturn {\n\t\toffset: {\n\t\t\ttop: offsetTop,\n\t\t\tleft: offsetLeft\n\t\t},\n\t\tflippedX: flippedX,\n\t\tflippedY: flippedY\n\t};\n}\n\n/**\n * Generates a list of declarative CSS classes that represent the layout of\n * the preview.\n *\n * @param {ext.popups.Preview} preview\n * @param {ext.popups.PreviewLayout} layout\n * @return {String[]}\n */\nfunction getClasses( preview, layout ) {\n\tvar classes = [];\n\n\tif ( layout.flippedY ) {\n\t\tclasses.push( 'mwe-popups-fade-in-down' );\n\t} else {\n\t\tclasses.push( 'mwe-popups-fade-in-up' );\n\t}\n\n\tif ( layout.flippedY && layout.flippedX ) {\n\t\tclasses.push( 'flipped_x_y' );\n\t}\n\n\tif ( layout.flippedY && !layout.flippedX ) {\n\t\tclasses.push( 'flipped_y' );\n\t}\n\n\tif ( layout.flippedX && !layout.flippedY ) {\n\t\tclasses.push( 'flipped_x' );\n\t}\n\n\tif ( ( !preview.hasThumbnail || preview.isTall ) && !layout.flippedY ) {\n\t\tclasses.push( 'mwe-popups-no-image-tri' );\n\t}\n\n\tif ( ( preview.hasThumbnail && !preview.isTall ) && !layout.flippedY ) {\n\t\tclasses.push( 'mwe-popups-image-tri' );\n\t}\n\n\tif ( preview.isTall ) {\n\t\tclasses.push( 'mwe-popups-is-tall' );\n\t} else {\n\t\tclasses.push( 'mwe-popups-is-not-tall' );\n\t}\n\n\treturn classes;\n}\n\n/**\n * Lays out the preview given the layout.\n *\n * If the preview should be oriented differently, then the pokey is updated,\n * e.g. if the preview should be flipped vertically, then the pokey is\n * removed.\n *\n * If the thumbnail is landscape and isn't the full height of the thumbnail\n * container, then pull the extract up to keep whitespace consistent across\n * previews.\n *\n * @param {ext.popups.Preview} preview\n * @param {ext.popups.PreviewLayout} layout\n * @param {string[]} classes class names used for layout out the preview\n * @param {number} predefinedLandscapeImageHeight landscape image height\n * @param {number} pokeySize\n */\nfunction layoutPreview( preview, layout, classes, predefinedLandscapeImageHeight, pokeySize ) {\n\tvar popup = preview.el,\n\t\tisTall = preview.isTall,\n\t\thasThumbnail = preview.hasThumbnail,\n\t\tthumbnail = preview.thumbnail,\n\t\tflippedY = layout.flippedY,\n\t\tflippedX = layout.flippedX,\n\t\toffsetTop = layout.offset.top;\n\n\tif (\n\t\t!flippedY && !isTall && hasThumbnail &&\n\t\t\tthumbnail.height < predefinedLandscapeImageHeight\n\t) {\n\t\tpopup.find( '.mwe-popups-extract' ).css(\n\t\t\t'margin-top',\n\t\t\tthumbnail.height - pokeySize\n\t\t);\n\t}\n\n\tpopup.addClass( classes.join( ' ' ) );\n\n\tif ( flippedY ) {\n\t\toffsetTop -= popup.outerHeight();\n\t}\n\n\tpopup.css( {\n\t\ttop: offsetTop,\n\t\tleft: layout.offset.left + 'px'\n\t} );\n\n\tif ( flippedY && hasThumbnail ) {\n\t\tpopup.find( 'image' )[ 0 ]\n\t\t\t.removeAttribute( 'clip-path' );\n\t}\n\n\tif ( flippedY && flippedX && hasThumbnail && isTall ) {\n\t\tpopup.find( 'image' )[ 0 ]\n\t\t\t.setAttribute( 'clip-path', 'url(#mwe-popups-landscape-mask-flip)' );\n\t}\n\n\tif ( flippedX && !flippedY && hasThumbnail && !isTall ) {\n\t\tpopup.find( 'image' )[ 0 ]\n\t\t\t.setAttribute( 'clip-path', 'url(#mwe-popups-mask-flip)' );\n\t}\n\n\tif ( flippedX && !flippedY && hasThumbnail && isTall ) {\n\t\tpopup.removeClass( 'mwe-popups-no-image-tri' )\n\t\t\t.find( 'image' )[ 0 ]\n\t\t\t.setAttribute( 'clip-path', 'url(#mwe-popups-landscape-mask)' );\n\t}\n}\n\n/**\n * Given the rectangular box(es) find the 'y' boundary of the closest\n * rectangle to the point 'y'. The point 'y' is the location of the mouse\n * on the 'y' axis and the rectangular box(es) are the borders of the\n * element over which the mouse is located. There will be more than one\n * rectangle in case the element spans multiple lines.\n *\n * In the majority of cases the mouse pointer will be inside a rectangle.\n * However, some browsers (i.e. Chrome) trigger a hover action even when\n * the mouse pointer is just outside a bounding rectangle. That's why\n * we need to look at all rectangles and not just the rectangle that\n * encloses the point.\n *\n * @private\n * @param {Number} y the point for which the closest location is being\n * looked for\n * @param {ClientRectList} rects list of rectangles defined by four edges\n * @param {Boolean} [isTop] should the resulting rectangle's top 'y'\n * boundary be returned. By default the bottom 'y' value is returned.\n * @return {Number}\n */\nfunction getClosestYPosition( y, rects, isTop ) {\n\tvar result,\n\t\tdeltaY,\n\t\tminY = null;\n\n\t$.each( rects, function ( i, rect ) {\n\t\tdeltaY = Math.abs( y - rect.top + y - rect.bottom );\n\n\t\tif ( minY === null || minY > deltaY ) {\n\t\t\tminY = deltaY;\n\t\t\t// Make sure the resulting point is at or outside the rectangle\n\t\t\t// boundaries.\n\t\t\tresult = ( isTop ) ? Math.floor( rect.top ) : Math.ceil( rect.bottom );\n\t\t}\n\t} );\n\n\treturn result;\n}\n\nmodule.exports = {\n\trender: render,\n\tinit: init,\n\t// The following are exposed for teseting purposes only\n\tcreatePokeyMasks: createPokeyMasks,\n\tcreatePreview: createPreview,\n\tcreateEmptyPreview: createEmptyPreview,\n\tbindBehavior: bindBehavior,\n\tshow: show,\n\thide: hide,\n\tcreateThumbnail: createThumbnail,\n\tcreateThumbnailElement: createThumbnailElement,\n\trenderExtract: renderExtract,\n\tcreateLayout: createLayout,\n\tgetClasses: getClasses,\n\tlayoutPreview: layoutPreview,\n\tgetClosestYPosition: getClosestYPosition\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/renderer.js\n// module id = ./src/renderer.js\n// module chunks = 0","var mw = window.mediaWiki,\n\t$ = jQuery;\n\n/**\n * Creates an instance of an EventLogging schema that can be used to log\n * Popups events.\n *\n * @param {mw.Map} config\n * @param {Window} window\n * @return {mw.eventLog.Schema}\n */\nmodule.exports = function ( config, window ) {\n\tvar samplingRate = config.get( 'wgPopupsSchemaSamplingRate', 0 );\n\n\tif (\n\t\t!window.navigator ||\n\t\t!$.isFunction( window.navigator.sendBeacon )\n\t) {\n\t\tsamplingRate = 0;\n\t}\n\n\treturn new mw.eventLog.Schema( 'Popups', samplingRate );\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/schema.js\n// module id = ./src/schema.js\n// module chunks = 0","var mw = window.mediaWiki,\n\t$ = jQuery;\n\n/**\n * Creates a render function that will create the settings dialog and return\n * a set of methods to operate on it\n * @returns {Function} render function\n */\nmodule.exports = function () {\n\n\t/**\n\t * Cached settings dialog\n\t *\n\t * @type {jQuery}\n\t */\n\tvar $dialog,\n\t\t/**\n\t\t * Cached settings overlay\n\t\t *\n\t\t * @type {jQuery}\n\t\t */\n\t\t$overlay;\n\n\t/**\n\t * Renders the relevant form and labels in the settings dialog\n\t * @param {Object} boundActions\n\t * @returns {Object} object with methods to affect the rendered UI\n\t */\n\treturn function ( boundActions ) {\n\n\t\tif ( !$dialog ) {\n\t\t\t$dialog = createSettingsDialog();\n\t\t\t$overlay = $( '<div>' ).addClass( 'mwe-popups-overlay' );\n\n\t\t\t// Setup event bindings\n\n\t\t\t$dialog.find( '.save' ).click( function () {\n\t\t\t\t// Find the selected value (simple|advanced|off)\n\t\t\t\tvar selected = getSelectedSetting( $dialog ),\n\t\t\t\t\t// Only simple means enabled, advanced is disabled in favor of\n\t\t\t\t\t// NavPops and off means disabled.\n\t\t\t\t\tenabled = selected === 'simple';\n\n\t\t\t\tboundActions.saveSettings( enabled );\n\t\t\t} );\n\t\t\t$dialog.find( '.close, .okay' ).click( boundActions.hideSettings );\n\t\t}\n\n\t\treturn {\n\t\t\t/**\n\t\t\t * Append the dialog and overlay to a DOM element\n\t\t\t * @param {HTMLElement} el\n\t\t\t */\n\t\t\tappendTo: function ( el ) {\n\t\t\t\t$overlay.appendTo( el );\n\t\t\t\t$dialog.appendTo( el );\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Show the settings element and position it correctly\n\t\t\t */\n\t\t\tshow: function () {\n\t\t\t\tvar h = $( window ).height(),\n\t\t\t\t\tw = $( window ).width();\n\n\t\t\t\t$overlay.show();\n\n\t\t\t\t// FIXME: Should recalc on browser resize\n\t\t\t\t$dialog\n\t\t\t\t\t.show()\n\t\t\t\t\t.css( 'left', ( w - $dialog.outerWidth( true ) ) / 2 )\n\t\t\t\t\t.css( 'top', ( h - $dialog.outerHeight( true ) ) / 2 );\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Hide the settings dialog.\n\t\t\t */\n\t\t\thide: function () {\n\t\t\t\t$overlay.hide();\n\t\t\t\t$dialog.hide();\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Toggle the help dialog on or off\n\t\t\t * @param {Boolean} visible if you want to show or hide the help dialog\n\t\t\t */\n\t\t\ttoggleHelp: function ( visible ) {\n\t\t\t\ttoggleHelp( $dialog, visible );\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Update the form depending on the enabled flag\n\t\t\t *\n\t\t\t * If false and no navpops, then checks 'off'\n\t\t\t * If true, then checks 'on'\n\t\t\t * If false, and there are navpops, then checks 'advanced'\n\t\t\t *\n\t\t\t * @param {Boolean} enabled if page previews are enabled\n\t\t\t */\n\t\t\tsetEnabled: function ( enabled ) {\n\t\t\t\tvar name = 'off';\n\t\t\t\tif ( enabled ) {\n\t\t\t\t\tname = 'simple';\n\t\t\t\t} else if ( isNavPopupsEnabled() ) {\n\t\t\t\t\tname = 'advanced';\n\t\t\t\t}\n\n\t\t\t\t// Check the appropiate radio button\n\t\t\t\t$dialog.find( '#mwe-popups-settings-' + name )\n\t\t\t\t\t.prop( 'checked', true );\n\t\t\t}\n\t\t};\n\t};\n};\n\n/**\n * Create the settings dialog\n *\n * @return {jQuery} settings dialog\n */\nfunction createSettingsDialog() {\n\tvar $el,\n\t\tpath = mw.config.get( 'wgExtensionAssetsPath' ) + '/Popups/resources/ext.popups/images/',\n\t\tchoices = [\n\t\t\t{\n\t\t\t\tid: 'simple',\n\t\t\t\tname: mw.msg( 'popups-settings-option-simple' ),\n\t\t\t\tdescription: mw.msg( 'popups-settings-option-simple-description' ),\n\t\t\t\timage: path + 'hovercard.svg',\n\t\t\t\tisChecked: true\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'advanced',\n\t\t\t\tname: mw.msg( 'popups-settings-option-advanced' ),\n\t\t\t\tdescription: mw.msg( 'popups-settings-option-advanced-description' ),\n\t\t\t\timage: path + 'navpop.svg'\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'off',\n\t\t\t\tname: mw.msg( 'popups-settings-option-off' )\n\t\t\t}\n\t\t];\n\n\tif ( !isNavPopupsEnabled() ) {\n\t\t// remove the advanced option\n\t\tchoices.splice( 1, 1 );\n\t}\n\n\t// render the template\n\t$el = mw.template.get( 'ext.popups', 'settings.mustache' ).render( {\n\t\theading: mw.msg( 'popups-settings-title' ),\n\t\tcloseLabel: mw.msg( 'popups-settings-cancel' ),\n\t\tsaveLabel: mw.msg( 'popups-settings-save' ),\n\t\thelpText: mw.msg( 'popups-settings-help' ),\n\t\tokLabel: mw.msg( 'popups-settings-help-ok' ),\n\t\tdescriptionText: mw.msg( 'popups-settings-description' ),\n\t\tchoices: choices\n\t} );\n\n\treturn $el;\n}\n\n/**\n * Get the selected value on the radio button\n *\n * @param {jQuery.Object} $el the element to extract the setting from\n * @return {String} Which should be (simple|advanced|off)\n */\nfunction getSelectedSetting( $el ) {\n\treturn $el.find(\n\t\t'input[name=mwe-popups-setting]:checked, #mwe-popups-settings'\n\t).val();\n}\n\n/**\n * Toggles the visibility between a form and the help\n * @param {jQuery.Object} $el element that contains form and help\n * @param {Boolean} visible if the help should be visible, or the form\n */\nfunction toggleHelp( $el, visible ) {\n\tvar $dialog = $( '#mwe-popups-settings' ),\n\t\tformSelectors = 'main, .save, .close',\n\t\thelpSelectors = '.mwe-popups-settings-help, .okay';\n\n\tif ( visible ) {\n\t\t$dialog.find( formSelectors ).hide();\n\t\t$dialog.find( helpSelectors ).show();\n\t} else {\n\t\t$dialog.find( formSelectors ).show();\n\t\t$dialog.find( helpSelectors ).hide();\n\t}\n}\n\n/**\n * Checks if the NavigationPopups gadget is enabled by looking at the global\n * variables\n * @returns {Boolean} if navpops was found to be enabled\n */\nfunction isNavPopupsEnabled() {\n\t/* global pg: false*/\n\treturn typeof pg !== 'undefined' && pg.fn.disablePopups !== undefined;\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/settingsDialog.js\n// module id = ./src/settingsDialog.js\n// module chunks = 0","/**\n * Whether statsv logging is enabled\n *\n * @param {mw.user} user The `mw.user` singleton instance\n * @param {mw.Map} config The `mw.config` singleton instance\n * @param {mw.experiments} experiments The `mw.experiments` singleton instance\n * @returns {bool} Whether the statsv logging is enabled for the user\n * given the sampling rate.\n */\nfunction isEnabled( user, config, experiments ) {\n\tvar samplingRate = config.get( 'wgPopupsStatsvSamplingRate', 0 ),\n\t\tbucket = experiments.getBucket( {\n\t\t\tname: 'ext.Popups.statsv',\n\t\t\tenabled: true,\n\t\t\tbuckets: {\n\t\t\t\tcontrol: 1 - samplingRate,\n\t\t\t\tA: samplingRate\n\t\t\t}\n\t\t}, user.sessionId() );\n\n\treturn bucket === 'A';\n}\n\nmodule.exports = {\n\tisEnabled: isEnabled\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/statsvInstrumentation.js\n// module id = ./src/statsvInstrumentation.js\n// module chunks = 0","/**\n * @typedef {Object} ext.popups.UserSettings\n */\n\nvar IS_ENABLED_KEY = 'mwe-popups-enabled',\n\tPREVIEW_COUNT_KEY = 'ext.popups.core.previewCount';\n\n/**\n * Given the global state of the application, creates an object whose methods\n * encapsulate all interactions with the given User Agent's storage.\n *\n * @param {mw.storage} storage The `mw.storage` singleton instance\n *\n * @return {ext.popups.UserSettings}\n */\nmodule.exports = function ( storage ) {\n\treturn {\n\n\t\t/**\n\t\t * Gets whether or not the user has previously enabled Page Previews.\n\t\t *\n\t\t * N.B. that if the user hasn't previously enabled or disabled Page\n\t\t * Previews, i.e. userSettings.setIsEnabled(true), then they are treated as\n\t\t * if they have enabled them.\n\t\t *\n\t\t * @return {Boolean}\n\t\t */\n\t\tgetIsEnabled: function () {\n\t\t\treturn storage.get( IS_ENABLED_KEY ) !== '0';\n\t\t},\n\n\t\t/**\n\t\t * Sets whether or not the user has enabled Page Previews.\n\t\t *\n\t\t * @param {Boolean} isEnabled\n\t\t */\n\t\tsetIsEnabled: function ( isEnabled ) {\n\t\t\tstorage.set( IS_ENABLED_KEY, isEnabled ? '1' : '0' );\n\t\t},\n\n\t\t/**\n\t\t * Gets whether or not the user has previously enabled **or disabled**\n\t\t * Page Previews.\n\t\t *\n\t\t * @return {Boolean}\n\t\t */\n\t\thasIsEnabled: function () {\n\t\t\tvar value = storage.get( IS_ENABLED_KEY );\n\n\t\t\treturn Boolean( value ) !== false;\n\t\t},\n\n\t\t/**\n\t\t * Gets the number of Page Previews that the user has seen.\n\t\t *\n\t\t * If the storage isn't available, then -1 is returned.\n\t\t *\n\t\t * @return {Number}\n\t\t */\n\t\tgetPreviewCount: function () {\n\t\t\tvar result = storage.get( PREVIEW_COUNT_KEY );\n\n\t\t\tif ( result === false ) {\n\t\t\t\treturn -1;\n\t\t\t} else if ( result === null ) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn parseInt( result, 10 );\n\t\t},\n\n\t\t/**\n\t\t * Sets the number of Page Previews that the user has seen.\n\t\t *\n\t\t * @param {Number} count\n\t\t */\n\t\tsetPreviewCount: function ( count ) {\n\t\t\tstorage.set( PREVIEW_COUNT_KEY, count.toString() );\n\t\t}\n\t};\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/userSettings.js\n// module id = ./src/userSettings.js\n// module chunks = 0","var $ = jQuery;\n\n/**\n * Sugar around `window.setTimeout`.\n *\n * @example\n * function continueProcessing() {\n * // ...\n * }\n *\n * wait( 150 ).then( continueProcessing );\n *\n * @param {Number} delay The number of milliseconds to wait\n * @return {jQuery.Promise}\n */\nmodule.exports = function ( delay ) {\n\tvar result = $.Deferred();\n\n\tsetTimeout( function () {\n\t\tresult.resolve();\n\t}, delay );\n\n\treturn result.promise();\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/wait.js\n// module id = ./src/wait.js\n// module chunks = 0"],"sourceRoot":""} |