mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Popups
synced 2024-11-14 19:25:33 +00:00
35cfc38b0b
Per the Popups schema [0], the "dismissed" action expects the perceivedWait property to be set. Happily, the time until the preview was shown is already recorded and used to determine whether or not to create a "dismissed" or "dwelledButAbandoned" event. Reducer changes: * When creating the "dismissed" event, set the perceivedWait property to the already accumulated timeToPreviewShow. [0] https://meta.wikimedia.org/wiki/Schema:Popups Bug: T164256 Change-Id: I3fd253f1c2ff5fa8e24c9225060d728ffd8dfd27
1 line
158 KiB
Plaintext
1 line
158 KiB
Plaintext
{"version":3,"sources":["/w/extensions/Popups/webpack/bootstrap c636bbfd1c15919caa9d","/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;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;;AAEA,iCAAiC;AACjC;;AAEA;AACA;AACA;;;;;;;;AC7FA;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,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,2BAA2B;AACtC,WAAW,OAAO;AAClB,YAAY,eAAe;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;;AAEA;;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;;;;;;;AC9tBA;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 c636bbfd1c15919caa9d","(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\tkey;\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\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\tkey = fnv1a32( JSON.stringify( event ) ).toString( 16 );\n\n\t\t// Has the event been seen before?\n\t\tif ( hashToSeenMap[ key ] === true ) {\n\t\t\ttrack( 'counter.PagePreviews.EventLogging.DuplicateEvent', 1 );\n\t\t} else {\n\t\t\thashToSeenMap[ key ] = true;\n\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: 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( preview, event, boundActions, token );\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 {ext.popups.PreviewBehavior} behavior\n * @param {String} token\n * @return {jQuery.Promise} A promise that resolves when the promise has faded\n * in\n */\nfunction show( preview, event, behavior, token ) {\n\tvar $link = $( event.target ),\n\t\tlayout = createLayout(\n\t\t\tpreview.isTall,\n\t\t\t{\n\t\t\t\tpageX: event.pageX,\n\t\t\t\tpageY: event.pageY,\n\t\t\t\tclientY: event.clientY\n\t\t\t},\n\t\t\t{\n\t\t\t\tclientRects: $link.get( 0 ).getClientRects(),\n\t\t\t\toffset: $link.offset(),\n\t\t\t\twidth: $link.width(),\n\t\t\t\theight: $link.height()\n\t\t\t},\n\t\t\t{\n\t\t\t\tscrollTop: $window.scrollTop(),\n\t\t\t\twidth: $window.width(),\n\t\t\t\theight: $window.height()\n\t\t\t},\n\t\t\tSIZES.pokeySize\n\t\t);\n\n\tpreview.el.appendTo( document.body );\n\n\tlayoutPreview( preview, layout );\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 */\nfunction layoutPreview( preview, layout ) {\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 ( !flippedY && !isTall && hasThumbnail && thumbnail.height < SIZES.landscapeImage.h ) {\n\t\t$( '.mwe-popups-extract' ).css(\n\t\t\t'margin-top',\n\t\t\tthumbnail.height - SIZES.pokeySize\n\t\t);\n\t}\n\n\tpopup.addClass( getClasses( preview, layout ).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\thide: hide,\n\tcreateThumbnail: createThumbnail,\n\tcreateThumbnailElement: createThumbnailElement,\n\trenderExtract: renderExtract,\n\tcreateLayout: createLayout,\n\tgetClasses: getClasses,\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":""} |