Jdlrobson has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/332926 )

Change subject: Icon moved to precompiled mobile.frontend module
......................................................................

Icon moved to precompiled mobile.frontend module

Change-Id: If9dca17ecfecc385928ba326e39134cfbdb32f72
---
R build_resources/mobile.frontend/Icon.js
M build_resources/mobile.frontend/index.js
R build_resources/mobile.frontend/templates/icon.hogan
M extension.json
M package.json
M resources/mobile.drawers/CtaDrawer.js
M resources/mobile.drawers/Drawer.js
M resources/mobile.editor.common/EditorOverlayBase.js
M resources/mobile.frontend/index.js
M resources/mobile.issues/CleanupOverlay.js
M resources/mobile.mediaViewer/ImageOverlay.js
M resources/mobile.overlays/Overlay.js
M resources/mobile.patrol.ajax/init.js
M resources/mobile.references/ReferencesDrawer.js
M resources/mobile.search/SearchOverlay.js
M resources/mobile.special.nearby.scripts/nearby.js
M resources/mobile.startup/icons.js
M resources/mobile.talk.overlays/TalkSectionAddOverlay.js
M resources/mobile.toc/TableOfContents.js
M resources/mobile.toggle/toggle.js
M resources/mobile.watchstar/Watchstar.js
M resources/skins.minerva.editor/init.js
M tests/qunit/mobile.pagelist.scripts/test_WatchstarPageList.js
M tests/qunit/mobile.watchlist/test_WatchList.js
M tests/qunit/mobile.watchstar/test_Watchstar.js
M webpack.config.js
26 files changed, 952 insertions(+), 49 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MobileFrontend 
refs/changes/26/332926/1

diff --git a/resources/mobile.startup/Icon.js 
b/build_resources/mobile.frontend/Icon.js
similarity index 93%
rename from resources/mobile.startup/Icon.js
rename to build_resources/mobile.frontend/Icon.js
index 0cdba11..15728b8 100644
--- a/resources/mobile.startup/Icon.js
+++ b/build_resources/mobile.frontend/Icon.js
@@ -1,6 +1,6 @@
 ( function ( M, $ ) {
 
-       var View = mw.mf.View;
+       var View = require( './View.js' );
 
        /**
         * A wrapper for creating an icon.
@@ -70,9 +70,9 @@
                toHtmlString: function () {
                        return $( '<div>' ).append( this.$el ).html();
                },
-               template: mw.template.get( 'mobile.startup', 'icon.hogan' )
+               template: require( './templates/icon.hogan' )
        } );
 
-       M.define( 'mobile.startup/Icon', Icon );
+       module.exports = Icon;
 
 }( mw.mobileFrontend, jQuery ) );
diff --git a/build_resources/mobile.frontend/index.js 
b/build_resources/mobile.frontend/index.js
index 08acc21..d99043d 100644
--- a/build_resources/mobile.frontend/index.js
+++ b/build_resources/mobile.frontend/index.js
@@ -1,5 +1,6 @@
 module.exports = mediaWiki.mf = {
        Browser: require( './Browser' ),
+       Icon: require( './Icon' ),
        View: require( './View' ),
        util: require( './util.js' )
 };
diff --git a/resources/mobile.startup/icon.hogan 
b/build_resources/mobile.frontend/templates/icon.hogan
similarity index 100%
rename from resources/mobile.startup/icon.hogan
rename to build_resources/mobile.frontend/templates/icon.hogan
diff --git a/extension.json b/extension.json
index 3d10e29..f95320f 100644
--- a/extension.json
+++ b/extension.json
@@ -557,7 +557,6 @@
                        ],
                        "templates": {
                                "anchor.hogan": 
"resources/mobile.startup/anchor.hogan",
-                               "icon.hogan": 
"resources/mobile.startup/icon.hogan",
                                "Section.hogan": 
"resources/mobile.startup/Section.hogan",
                                "button.hogan": 
"resources/mobile.startup/button.hogan"
                        },
@@ -574,7 +573,6 @@
                                "resources/mobile.startup/PageGateway.js",
                                "resources/mobile.startup/Anchor.js",
                                "resources/mobile.startup/Button.js",
-                               "resources/mobile.startup/Icon.js",
                                "resources/mobile.startup/icons.js",
                                "resources/mobile.startup/Panel.js",
                                "resources/mobile.startup/Section.js",
diff --git a/package.json b/package.json
index 0234171..4202945 100644
--- a/package.json
+++ b/package.json
@@ -1,24 +1,25 @@
 {
-       "private": true,
-       "scripts": {
-               "test": "grunt test && npm run doc",
-               "build": "webpack",
-               "predoc": "bundle install --path vendor/bundle",
-               "doc": "bundle exec jsduck"
-       },
-       "dependencies": {
-               "jsdoc": "3.4.2",
-               "svgo": ">=0.4.4"
-       },
-       "devDependencies": {
-               "eslint-config-wikimedia": "0.3.0",
-               "grunt": "^1.0.1",
-               "grunt-banana-checker": "^0.5.0",
-               "grunt-contrib-watch": "^1.0.0",
-               "grunt-eslint": "19.0.0",
-               "grunt-jsonlint": "^1.1.0",
-               "grunt-notify": "^0.4.5",
-               "grunt-stylelint": "^0.6.0",
-               "stylelint-config-wikimedia": "^0.3.0"
-       }
+  "private": true,
+  "scripts": {
+    "test": "grunt test && npm run doc",
+    "build": "webpack",
+    "predoc": "bundle install --path vendor/bundle",
+    "doc": "bundle exec jsduck"
+  },
+  "dependencies": {
+    "jsdoc": "3.4.2",
+    "svgo": ">=0.4.4"
+  },
+  "devDependencies": {
+    "eslint-config-wikimedia": "0.3.0",
+    "grunt": "^1.0.1",
+    "grunt-banana-checker": "^0.5.0",
+    "grunt-contrib-watch": "^1.0.0",
+    "grunt-eslint": "19.0.0",
+    "grunt-jsonlint": "^1.1.0",
+    "grunt-notify": "^0.4.5",
+    "grunt-stylelint": "^0.6.0",
+    "mustache-loader": "^0.4.1",
+    "stylelint-config-wikimedia": "^0.3.0"
+  }
 }
diff --git a/resources/mobile.drawers/CtaDrawer.js 
b/resources/mobile.drawers/CtaDrawer.js
index b57f80c..bf80694 100644
--- a/resources/mobile.drawers/CtaDrawer.js
+++ b/resources/mobile.drawers/CtaDrawer.js
@@ -1,6 +1,6 @@
 ( function ( M, $ ) {
        var Drawer = M.require( 'mobile.drawers/Drawer' ),
-               Icon = M.require( 'mobile.startup/Icon' ),
+               Icon = mw.mf.Icon,
                Button = M.require( 'mobile.startup/Button' ),
                Anchor = M.require( 'mobile.startup/Anchor' );
 
diff --git a/resources/mobile.drawers/Drawer.js 
b/resources/mobile.drawers/Drawer.js
index 2049133..db9969c 100644
--- a/resources/mobile.drawers/Drawer.js
+++ b/resources/mobile.drawers/Drawer.js
@@ -1,7 +1,7 @@
 ( function ( M, $ ) {
 
        var Panel = M.require( 'mobile.startup/Panel' ),
-               Icon = M.require( 'mobile.startup/Icon' );
+               Icon = mw.mf.Icon;
 
        /**
         * A {@link View} that pops up from the bottom of the screen.
diff --git a/resources/mobile.editor.common/EditorOverlayBase.js 
b/resources/mobile.editor.common/EditorOverlayBase.js
index 48032fd..1b6c239 100644
--- a/resources/mobile.editor.common/EditorOverlayBase.js
+++ b/resources/mobile.editor.common/EditorOverlayBase.js
@@ -2,7 +2,7 @@
        var Overlay = M.require( 'mobile.overlays/Overlay' ),
                PageGateway = M.require( 'mobile.startup/PageGateway' ),
                browser = mw.mf.Browser.getSingleton(),
-               Icon = M.require( 'mobile.startup/Icon' ),
+               Icon = mw.mf.Icon,
                toast = M.require( 'mobile.toast/toast' ),
                user = M.require( 'mobile.user/user' );
 
diff --git a/resources/mobile.frontend/index.js 
b/resources/mobile.frontend/index.js
index f657690..e7641f8 100644
--- a/resources/mobile.frontend/index.js
+++ b/resources/mobile.frontend/index.js
@@ -46,8 +46,9 @@
 
        module.exports = mediaWiki.mf = {
                Browser: __webpack_require__( 1 ),
-               View: __webpack_require__( 2 ),
-               util: __webpack_require__( 3 )
+               Icon: __webpack_require__( 2 ),
+               View: __webpack_require__( 3 ),
+               util: __webpack_require__( 8 )
        };
 
 
@@ -268,6 +269,90 @@
 
 /***/ },
 /* 2 */
+/***/ function(module, exports, __webpack_require__) {
+
+       ( function ( M, $ ) {
+
+               var View = __webpack_require__( 3 );
+
+               /**
+                * A wrapper for creating an icon.
+                * @class Icon
+                * @extends View
+                *
+                * @constructor
+                * @param {Object} options Configuration options
+                */
+               function Icon( options ) {
+                       if ( options.hasText ) {
+                               options.modifier = 'mw-ui-icon-before';
+                       }
+                       if ( options.href ) {
+                               options.tagName = 'a';
+                       }
+                       View.call( this, options );
+               }
+
+               OO.mfExtend( Icon, View, {
+                       /** @inheritdoc */
+                       isTemplateMode: true,
+                       /**
+                        * @cfg {Object} defaults Default options hash.
+                        * @cfg {boolean} defaults.hasText Whether the icon has 
text.
+                        * @cfg {boolean} defaults.isSmall Whether the icon 
should be small.
+                        * @cfg {string} [defaults.href] value of href 
attribute, when set tagName will default to anchor tag
+                        * @cfg {string} defaults.tagName The name of the tag 
in which the icon is wrapped. Defaults to 'a' when href option present.
+                        * @cfg {string} defaults.base String used as a base 
for generating class names.
+                        * Defaults to 'mw-ui-icon'.
+                        * @cfg {string} defaults.name Name of the icon.
+                        * @cfg {string} defaults.modifier Additional class 
name.
+                        * Defaults to 'mw-ui-icon-element'.
+                        * @cfg {string} defaults.title Tooltip text.
+                        */
+                       defaults: {
+                               hasText: false,
+                               href: undefined,
+                               tagName: 'div',
+                               isSmall: false,
+                               base: 'mw-ui-icon',
+                               name: '',
+                               modifier: 'mw-ui-icon-element',
+                               title: ''
+                       },
+                       /**
+                        * Return the full class name that is required for the 
icon to render
+                        * @method
+                        * @return {string}
+                        */
+                       getClassName: function () {
+                               return this.$el.attr( 'class' );
+                       },
+                       /**
+                        * Return the class that relates to the icon glyph
+                        * @method
+                        * @return {string}
+                        */
+                       getGlyphClassName: function () {
+                               return this.options.base + '-' + 
this.options.name;
+                       },
+                       /**
+                        * Return the HTML representation of this view
+                        * @method
+                        * @return {string}
+                        */
+                       toHtmlString: function () {
+                               return $( '<div>' ).append( this.$el ).html();
+                       },
+                       template: __webpack_require__( 4 )
+               } );
+
+               module.exports = Icon;
+
+       }( mw.mobileFrontend, jQuery ) );
+
+
+/***/ },
+/* 3 */
 /***/ function(module, exports) {
 
        var
@@ -630,7 +715,817 @@
 
 
 /***/ },
-/* 3 */
+/* 4 */
+/***/ function(module, exports, __webpack_require__) {
+
+       var H = __webpack_require__(5);
+       module.exports = function() { var T = new H.Template({code: function 
(c,p,i) { var t=this;t.b(i=i||"");t.b("<");t.b(t.v(t.f("tagName",c,p,0)));t.b(" 
class=\"");t.b(t.v(t.f("base",c,p,0)));t.b(" 
");t.b(t.v(t.f("base",c,p,0)));t.b("-");t.b(t.v(t.f("name",c,p,0)));t.b(" 
");t.b(t.v(t.f("modifier",c,p,0)));t.b(" 
");if(t.s(t.f("isSmall",c,p,1),c,p,0,72,88,"{{ 
}}")){t.rs(c,p,function(c,p,t){t.b("mw-ui-icon-small");});c.pop();}t.b(" 
");t.b(t.v(t.f("additionalClassNames",c,p,0)));t.b("\"");t.b("\n" + i);t.b("    
   ");if(t.s(t.f("id",c,p,1),c,p,0,135,146,"{{ 
}}")){t.rs(c,p,function(c,p,t){t.b("id=\"");t.b(t.v(t.f("id",c,p,0)));t.b("\"");});c.pop();}t.b("\n"
 + i);t.b("     ");if(t.s(t.f("href",c,p,1),c,p,0,164,179,"{{ 
}}")){t.rs(c,p,function(c,p,t){t.b("href=\"");t.b(t.v(t.f("href",c,p,0)));t.b("\"");});c.pop();}t.b("\n"
 + i);t.b("       ");if(t.s(t.f("title",c,p,1),c,p,0,200,217,"{{ 
}}")){t.rs(c,p,function(c,p,t){t.b("title=\"");t.b(t.v(t.f("title",c,p,0)));t.b("\"");});c.pop();}t.b(">");t.b(t.v(t.f("label",c,p,0)));t.b("</");t.b(t.v(t.f("tagName",c,p,0)));t.b(">");t.b("\n");return
 t.fl(); },partials: {}, subs: {  }}, "<{{tagName}} class=\"{{base}} 
{{base}}-{{name}} {{modifier}} {{#isSmall}}mw-ui-icon-small{{/isSmall}} 
{{additionalClassNames}}\"\n\t{{#id}}id=\"{{id}}\"{{/id}}\n\t{{#href}}href=\"{{href}}\"{{/href}}\n\t{{#title}}title=\"{{title}}\"{{/title}}>{{label}}</{{tagName}}>\n",
 H);return T; }();
+
+/***/ },
+/* 5 */
+/***/ function(module, exports, __webpack_require__) {
+
+       /*
+        *  Copyright 2011 Twitter, Inc.
+        *  Licensed under the Apache License, Version 2.0 (the "License");
+        *  you may not use this file except in compliance with the License.
+        *  You may obtain a copy of the License at
+        *
+        *  http://www.apache.org/licenses/LICENSE-2.0
+        *
+        *  Unless required by applicable law or agreed to in writing, software
+        *  distributed under the License is distributed on an "AS IS" BASIS,
+        *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
implied.
+        *  See the License for the specific language governing permissions and
+        *  limitations under the License.
+        */
+
+       // This file is for use with Node.js. See dist/ for browser files.
+
+       var Hogan = __webpack_require__(6);
+       Hogan.Template = __webpack_require__(7).Template;
+       Hogan.template = Hogan.Template;
+       module.exports = Hogan;
+
+
+/***/ },
+/* 6 */
+/***/ function(module, exports, __webpack_require__) {
+
+       /*
+        *  Copyright 2011 Twitter, Inc.
+        *  Licensed under the Apache License, Version 2.0 (the "License");
+        *  you may not use this file except in compliance with the License.
+        *  You may obtain a copy of the License at
+        *
+        *  http://www.apache.org/licenses/LICENSE-2.0
+        *
+        *  Unless required by applicable law or agreed to in writing, software
+        *  distributed under the License is distributed on an "AS IS" BASIS,
+        *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
implied.
+        *  See the License for the specific language governing permissions and
+        *  limitations under the License.
+        */
+
+       (function (Hogan) {
+         // Setup regex  assignments
+         // remove whitespace according to Mustache spec
+         var rIsWhitespace = /\S/,
+             rQuot = /\"/g,
+             rNewline =  /\n/g,
+             rCr = /\r/g,
+             rSlash = /\\/g,
+             rLineSep = /\u2028/,
+             rParagraphSep = /\u2029/;
+
+         Hogan.tags = {
+           '#': 1, '^': 2, '<': 3, '$': 4,
+           '/': 5, '!': 6, '>': 7, '=': 8, '_v': 9,
+           '{': 10, '&': 11, '_t': 12
+         };
+
+         Hogan.scan = function scan(text, delimiters) {
+           var len = text.length,
+               IN_TEXT = 0,
+               IN_TAG_TYPE = 1,
+               IN_TAG = 2,
+               state = IN_TEXT,
+               tagType = null,
+               tag = null,
+               buf = '',
+               tokens = [],
+               seenTag = false,
+               i = 0,
+               lineStart = 0,
+               otag = '{{',
+               ctag = '}}';
+
+           function addBuf() {
+             if (buf.length > 0) {
+               tokens.push({tag: '_t', text: new String(buf)});
+               buf = '';
+             }
+           }
+
+           function lineIsWhitespace() {
+             var isAllWhitespace = true;
+             for (var j = lineStart; j < tokens.length; j++) {
+               isAllWhitespace =
+                 (Hogan.tags[tokens[j].tag] < Hogan.tags['_v']) ||
+                 (tokens[j].tag == '_t' && tokens[j].text.match(rIsWhitespace) 
=== null);
+               if (!isAllWhitespace) {
+                 return false;
+               }
+             }
+
+             return isAllWhitespace;
+           }
+
+           function filterLine(haveSeenTag, noNewLine) {
+             addBuf();
+
+             if (haveSeenTag && lineIsWhitespace()) {
+               for (var j = lineStart, next; j < tokens.length; j++) {
+                 if (tokens[j].text) {
+                   if ((next = tokens[j+1]) && next.tag == '>') {
+                     // set indent to token value
+                     next.indent = tokens[j].text.toString()
+                   }
+                   tokens.splice(j, 1);
+                 }
+               }
+             } else if (!noNewLine) {
+               tokens.push({tag:'\n'});
+             }
+
+             seenTag = false;
+             lineStart = tokens.length;
+           }
+
+           function changeDelimiters(text, index) {
+             var close = '=' + ctag,
+                 closeIndex = text.indexOf(close, index),
+                 delimiters = trim(
+                   text.substring(text.indexOf('=', index) + 1, closeIndex)
+                 ).split(' ');
+
+             otag = delimiters[0];
+             ctag = delimiters[delimiters.length - 1];
+
+             return closeIndex + close.length - 1;
+           }
+
+           if (delimiters) {
+             delimiters = delimiters.split(' ');
+             otag = delimiters[0];
+             ctag = delimiters[1];
+           }
+
+           for (i = 0; i < len; i++) {
+             if (state == IN_TEXT) {
+               if (tagChange(otag, text, i)) {
+                 --i;
+                 addBuf();
+                 state = IN_TAG_TYPE;
+               } else {
+                 if (text.charAt(i) == '\n') {
+                   filterLine(seenTag);
+                 } else {
+                   buf += text.charAt(i);
+                 }
+               }
+             } else if (state == IN_TAG_TYPE) {
+               i += otag.length - 1;
+               tag = Hogan.tags[text.charAt(i + 1)];
+               tagType = tag ? text.charAt(i + 1) : '_v';
+               if (tagType == '=') {
+                 i = changeDelimiters(text, i);
+                 state = IN_TEXT;
+               } else {
+                 if (tag) {
+                   i++;
+                 }
+                 state = IN_TAG;
+               }
+               seenTag = i;
+             } else {
+               if (tagChange(ctag, text, i)) {
+                 tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: 
ctag,
+                              i: (tagType == '/') ? seenTag - otag.length : i 
+ ctag.length});
+                 buf = '';
+                 i += ctag.length - 1;
+                 state = IN_TEXT;
+                 if (tagType == '{') {
+                   if (ctag == '}}') {
+                     i++;
+                   } else {
+                     cleanTripleStache(tokens[tokens.length - 1]);
+                   }
+                 }
+               } else {
+                 buf += text.charAt(i);
+               }
+             }
+           }
+
+           filterLine(seenTag, true);
+
+           return tokens;
+         }
+
+         function cleanTripleStache(token) {
+           if (token.n.substr(token.n.length - 1) === '}') {
+             token.n = token.n.substring(0, token.n.length - 1);
+           }
+         }
+
+         function trim(s) {
+           if (s.trim) {
+             return s.trim();
+           }
+
+           return s.replace(/^\s*|\s*$/g, '');
+         }
+
+         function tagChange(tag, text, index) {
+           if (text.charAt(index) != tag.charAt(0)) {
+             return false;
+           }
+
+           for (var i = 1, l = tag.length; i < l; i++) {
+             if (text.charAt(index + i) != tag.charAt(i)) {
+               return false;
+             }
+           }
+
+           return true;
+         }
+
+         // the tags allowed inside super templates
+         var allowedInSuper = {'_t': true, '\n': true, '$': true, '/': true};
+
+         function buildTree(tokens, kind, stack, customTags) {
+           var instructions = [],
+               opener = null,
+               tail = null,
+               token = null;
+
+           tail = stack[stack.length - 1];
+
+           while (tokens.length > 0) {
+             token = tokens.shift();
+
+             if (tail && tail.tag == '<' && !(token.tag in allowedInSuper)) {
+               throw new Error('Illegal content in < super tag.');
+             }
+
+             if (Hogan.tags[token.tag] <= Hogan.tags['$'] || isOpener(token, 
customTags)) {
+               stack.push(token);
+               token.nodes = buildTree(tokens, token.tag, stack, customTags);
+             } else if (token.tag == '/') {
+               if (stack.length === 0) {
+                 throw new Error('Closing tag without opener: /' + token.n);
+               }
+               opener = stack.pop();
+               if (token.n != opener.n && !isCloser(token.n, opener.n, 
customTags)) {
+                 throw new Error('Nesting error: ' + opener.n + ' vs. ' + 
token.n);
+               }
+               opener.end = token.i;
+               return instructions;
+             } else if (token.tag == '\n') {
+               token.last = (tokens.length == 0) || (tokens[0].tag == '\n');
+             }
+
+             instructions.push(token);
+           }
+
+           if (stack.length > 0) {
+             throw new Error('missing closing tag: ' + stack.pop().n);
+           }
+
+           return instructions;
+         }
+
+         function isOpener(token, tags) {
+           for (var i = 0, l = tags.length; i < l; i++) {
+             if (tags[i].o == token.n) {
+               token.tag = '#';
+               return true;
+             }
+           }
+         }
+
+         function isCloser(close, open, tags) {
+           for (var i = 0, l = tags.length; i < l; i++) {
+             if (tags[i].c == close && tags[i].o == open) {
+               return true;
+             }
+           }
+         }
+
+         function stringifySubstitutions(obj) {
+           var items = [];
+           for (var key in obj) {
+             items.push('"' + esc(key) + '": function(c,p,t,i) {' + obj[key] + 
'}');
+           }
+           return "{ " + items.join(",") + " }";
+         }
+
+         function stringifyPartials(codeObj) {
+           var partials = [];
+           for (var key in codeObj.partials) {
+             partials.push('"' + esc(key) + '":{name:"' + 
esc(codeObj.partials[key].name) + '", ' + 
stringifyPartials(codeObj.partials[key]) + "}");
+           }
+           return "partials: {" + partials.join(",") + "}, subs: " + 
stringifySubstitutions(codeObj.subs);
+         }
+
+         Hogan.stringify = function(codeObj, text, options) {
+           return "{code: function (c,p,i) { " + Hogan.wrapMain(codeObj.code) 
+ " }," + stringifyPartials(codeObj) +  "}";
+         }
+
+         var serialNo = 0;
+         Hogan.generate = function(tree, text, options) {
+           serialNo = 0;
+           var context = { code: '', subs: {}, partials: {} };
+           Hogan.walk(tree, context);
+
+           if (options.asString) {
+             return this.stringify(context, text, options);
+           }
+
+           return this.makeTemplate(context, text, options);
+         }
+
+         Hogan.wrapMain = function(code) {
+           return 'var t=this;t.b(i=i||"");' + code + 'return t.fl();';
+         }
+
+         Hogan.template = Hogan.Template;
+
+         Hogan.makeTemplate = function(codeObj, text, options) {
+           var template = this.makePartials(codeObj);
+           template.code = new Function('c', 'p', 'i', 
this.wrapMain(codeObj.code));
+           return new this.template(template, text, this, options);
+         }
+
+         Hogan.makePartials = function(codeObj) {
+           var key, template = {subs: {}, partials: codeObj.partials, name: 
codeObj.name};
+           for (key in template.partials) {
+             template.partials[key] = 
this.makePartials(template.partials[key]);
+           }
+           for (key in codeObj.subs) {
+             template.subs[key] = new Function('c', 'p', 't', 'i', 
codeObj.subs[key]);
+           }
+           return template;
+         }
+
+         function esc(s) {
+           return s.replace(rSlash, '\\\\')
+                   .replace(rQuot, '\\\"')
+                   .replace(rNewline, '\\n')
+                   .replace(rCr, '\\r')
+                   .replace(rLineSep, '\\u2028')
+                   .replace(rParagraphSep, '\\u2029');
+         }
+
+         function chooseMethod(s) {
+           return (~s.indexOf('.')) ? 'd' : 'f';
+         }
+
+         function createPartial(node, context) {
+           var prefix = "<" + (context.prefix || "");
+           var sym = prefix + node.n + serialNo++;
+           context.partials[sym] = {name: node.n, partials: {}};
+           context.code += 't.b(t.rp("' +  esc(sym) + '",c,p,"' + (node.indent 
|| '') + '"));';
+           return sym;
+         }
+
+         Hogan.codegen = {
+           '#': function(node, context) {
+             context.code += 'if(t.s(t.' + chooseMethod(node.n) + '("' + 
esc(node.n) + '",c,p,1),' +
+                             'c,p,0,' + node.i + ',' + node.end + ',"' + 
node.otag + " " + node.ctag + '")){' +
+                             't.rs(c,p,' + 'function(c,p,t){';
+             Hogan.walk(node.nodes, context);
+             context.code += '});c.pop();}';
+           },
+
+           '^': function(node, context) {
+             context.code += 'if(!t.s(t.' + chooseMethod(node.n) + '("' + 
esc(node.n) + '",c,p,1),c,p,1,0,0,"")){';
+             Hogan.walk(node.nodes, context);
+             context.code += '};';
+           },
+
+           '>': createPartial,
+           '<': function(node, context) {
+             var ctx = {partials: {}, code: '', subs: {}, inPartial: true};
+             Hogan.walk(node.nodes, ctx);
+             var template = context.partials[createPartial(node, context)];
+             template.subs = ctx.subs;
+             template.partials = ctx.partials;
+           },
+
+           '$': function(node, context) {
+             var ctx = {subs: {}, code: '', partials: context.partials, 
prefix: node.n};
+             Hogan.walk(node.nodes, ctx);
+             context.subs[node.n] = ctx.code;
+             if (!context.inPartial) {
+               context.code += 't.sub("' + esc(node.n) + '",c,p,i);';
+             }
+           },
+
+           '\n': function(node, context) {
+             context.code += write('"\\n"' + (node.last ? '' : ' + i'));
+           },
+
+           '_v': function(node, context) {
+             context.code += 't.b(t.v(t.' + chooseMethod(node.n) + '("' + 
esc(node.n) + '",c,p,0)));';
+           },
+
+           '_t': function(node, context) {
+             context.code += write('"' + esc(node.text) + '"');
+           },
+
+           '{': tripleStache,
+
+           '&': tripleStache
+         }
+
+         function tripleStache(node, context) {
+           context.code += 't.b(t.t(t.' + chooseMethod(node.n) + '("' + 
esc(node.n) + '",c,p,0)));';
+         }
+
+         function write(s) {
+           return 't.b(' + s + ');';
+         }
+
+         Hogan.walk = function(nodelist, context) {
+           var func;
+           for (var i = 0, l = nodelist.length; i < l; i++) {
+             func = Hogan.codegen[nodelist[i].tag];
+             func && func(nodelist[i], context);
+           }
+           return context;
+         }
+
+         Hogan.parse = function(tokens, text, options) {
+           options = options || {};
+           return buildTree(tokens, '', [], options.sectionTags || []);
+         }
+
+         Hogan.cache = {};
+
+         Hogan.cacheKey = function(text, options) {
+           return [text, !!options.asString, !!options.disableLambda, 
options.delimiters, !!options.modelGet].join('||');
+         }
+
+         Hogan.compile = function(text, options) {
+           options = options || {};
+           var key = Hogan.cacheKey(text, options);
+           var template = this.cache[key];
+
+           if (template) {
+             var partials = template.partials;
+             for (var name in partials) {
+               delete partials[name].instance;
+             }
+             return template;
+           }
+
+           template = this.generate(this.parse(this.scan(text, 
options.delimiters), text, options), text, options);
+           return this.cache[key] = template;
+         }
+       })( true ? exports : Hogan);
+
+
+/***/ },
+/* 7 */
+/***/ function(module, exports, __webpack_require__) {
+
+       /*
+        *  Copyright 2011 Twitter, Inc.
+        *  Licensed under the Apache License, Version 2.0 (the "License");
+        *  you may not use this file except in compliance with the License.
+        *  You may obtain a copy of the License at
+        *
+        *  http://www.apache.org/licenses/LICENSE-2.0
+        *
+        *  Unless required by applicable law or agreed to in writing, software
+        *  distributed under the License is distributed on an "AS IS" BASIS,
+        *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
implied.
+        *  See the License for the specific language governing permissions and
+        *  limitations under the License.
+        */
+
+       var Hogan = {};
+
+       (function (Hogan) {
+         Hogan.Template = function (codeObj, text, compiler, options) {
+           codeObj = codeObj || {};
+           this.r = codeObj.code || this.r;
+           this.c = compiler;
+           this.options = options || {};
+           this.text = text || '';
+           this.partials = codeObj.partials || {};
+           this.subs = codeObj.subs || {};
+           this.buf = '';
+         }
+
+         Hogan.Template.prototype = {
+           // render: replaced by generated code.
+           r: function (context, partials, indent) { return ''; },
+
+           // variable escaping
+           v: hoganEscape,
+
+           // triple stache
+           t: coerceToString,
+
+           render: function render(context, partials, indent) {
+             return this.ri([context], partials || {}, indent);
+           },
+
+           // render internal -- a hook for overrides that catches partials too
+           ri: function (context, partials, indent) {
+             return this.r(context, partials, indent);
+           },
+
+           // ensurePartial
+           ep: function(symbol, partials) {
+             var partial = this.partials[symbol];
+
+             // check to see that if we've instantiated this partial before
+             var template = partials[partial.name];
+             if (partial.instance && partial.base == template) {
+               return partial.instance;
+             }
+
+             if (typeof template == 'string') {
+               if (!this.c) {
+                 throw new Error("No compiler available.");
+               }
+               template = this.c.compile(template, this.options);
+             }
+
+             if (!template) {
+               return null;
+             }
+
+             // We use this to check whether the partials dictionary has 
changed
+             this.partials[symbol].base = template;
+
+             if (partial.subs) {
+               // Make sure we consider parent template now
+               if (!partials.stackText) partials.stackText = {};
+               for (key in partial.subs) {
+                 if (!partials.stackText[key]) {
+                   partials.stackText[key] = (this.activeSub !== undefined && 
partials.stackText[this.activeSub]) ? partials.stackText[this.activeSub] : 
this.text;
+                 }
+               }
+               template = createSpecializedPartial(template, partial.subs, 
partial.partials,
+                 this.stackSubs, this.stackPartials, partials.stackText);
+             }
+             this.partials[symbol].instance = template;
+
+             return template;
+           },
+
+           // tries to find a partial in the current scope and render it
+           rp: function(symbol, context, partials, indent) {
+             var partial = this.ep(symbol, partials);
+             if (!partial) {
+               return '';
+             }
+
+             return partial.ri(context, partials, indent);
+           },
+
+           // render a section
+           rs: function(context, partials, section) {
+             var tail = context[context.length - 1];
+
+             if (!isArray(tail)) {
+               section(context, partials, this);
+               return;
+             }
+
+             for (var i = 0; i < tail.length; i++) {
+               context.push(tail[i]);
+               section(context, partials, this);
+               context.pop();
+             }
+           },
+
+           // maybe start a section
+           s: function(val, ctx, partials, inverted, start, end, tags) {
+             var pass;
+
+             if (isArray(val) && val.length === 0) {
+               return false;
+             }
+
+             if (typeof val == 'function') {
+               val = this.ms(val, ctx, partials, inverted, start, end, tags);
+             }
+
+             pass = !!val;
+
+             if (!inverted && pass && ctx) {
+               ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]);
+             }
+
+             return pass;
+           },
+
+           // find values with dotted names
+           d: function(key, ctx, partials, returnFound) {
+             var found,
+                 names = key.split('.'),
+                 val = this.f(names[0], ctx, partials, returnFound),
+                 doModelGet = this.options.modelGet,
+                 cx = null;
+
+             if (key === '.' && isArray(ctx[ctx.length - 2])) {
+               val = ctx[ctx.length - 1];
+             } else {
+               for (var i = 1; i < names.length; i++) {
+                 found = findInScope(names[i], val, doModelGet);
+                 if (found !== undefined) {
+                   cx = val;
+                   val = found;
+                 } else {
+                   val = '';
+                 }
+               }
+             }
+
+             if (returnFound && !val) {
+               return false;
+             }
+
+             if (!returnFound && typeof val == 'function') {
+               ctx.push(cx);
+               val = this.mv(val, ctx, partials);
+               ctx.pop();
+             }
+
+             return val;
+           },
+
+           // find values with normal names
+           f: function(key, ctx, partials, returnFound) {
+             var val = false,
+                 v = null,
+                 found = false,
+                 doModelGet = this.options.modelGet;
+
+             for (var i = ctx.length - 1; i >= 0; i--) {
+               v = ctx[i];
+               val = findInScope(key, v, doModelGet);
+               if (val !== undefined) {
+                 found = true;
+                 break;
+               }
+             }
+
+             if (!found) {
+               return (returnFound) ? false : "";
+             }
+
+             if (!returnFound && typeof val == 'function') {
+               val = this.mv(val, ctx, partials);
+             }
+
+             return val;
+           },
+
+           // higher order templates
+           ls: function(func, cx, partials, text, tags) {
+             var oldTags = this.options.delimiters;
+
+             this.options.delimiters = tags;
+             this.b(this.ct(coerceToString(func.call(cx, text)), cx, 
partials));
+             this.options.delimiters = oldTags;
+
+             return false;
+           },
+
+           // compile text
+           ct: function(text, cx, partials) {
+             if (this.options.disableLambda) {
+               throw new Error('Lambda features disabled.');
+             }
+             return this.c.compile(text, this.options).render(cx, partials);
+           },
+
+           // template result buffering
+           b: function(s) { this.buf += s; },
+
+           fl: function() { var r = this.buf; this.buf = ''; return r; },
+
+           // method replace section
+           ms: function(func, ctx, partials, inverted, start, end, tags) {
+             var textSource,
+                 cx = ctx[ctx.length - 1],
+                 result = func.call(cx);
+
+             if (typeof result == 'function') {
+               if (inverted) {
+                 return true;
+               } else {
+                 textSource = (this.activeSub && this.subsText && 
this.subsText[this.activeSub]) ? this.subsText[this.activeSub] : this.text;
+                 return this.ls(result, cx, partials, 
textSource.substring(start, end), tags);
+               }
+             }
+
+             return result;
+           },
+
+           // method replace variable
+           mv: function(func, ctx, partials) {
+             var cx = ctx[ctx.length - 1];
+             var result = func.call(cx);
+
+             if (typeof result == 'function') {
+               return this.ct(coerceToString(result.call(cx)), cx, partials);
+             }
+
+             return result;
+           },
+
+           sub: function(name, context, partials, indent) {
+             var f = this.subs[name];
+             if (f) {
+               this.activeSub = name;
+               f(context, partials, this, indent);
+               this.activeSub = false;
+             }
+           }
+
+         };
+
+         //Find a key in an object
+         function findInScope(key, scope, doModelGet) {
+           var val;
+
+           if (scope && typeof scope == 'object') {
+
+             if (scope[key] !== undefined) {
+               val = scope[key];
+
+             // try lookup with get for backbone or similar model data
+             } else if (doModelGet && scope.get && typeof scope.get == 
'function') {
+               val = scope.get(key);
+             }
+           }
+
+           return val;
+         }
+
+         function createSpecializedPartial(instance, subs, partials, 
stackSubs, stackPartials, stackText) {
+           function PartialTemplate() {};
+           PartialTemplate.prototype = instance;
+           function Substitutions() {};
+           Substitutions.prototype = instance.subs;
+           var key;
+           var partial = new PartialTemplate();
+           partial.subs = new Substitutions();
+           partial.subsText = {};  //hehe. substext.
+           partial.buf = '';
+
+           stackSubs = stackSubs || {};
+           partial.stackSubs = stackSubs;
+           partial.subsText = stackText;
+           for (key in subs) {
+             if (!stackSubs[key]) stackSubs[key] = subs[key];
+           }
+           for (key in stackSubs) {
+             partial.subs[key] = stackSubs[key];
+           }
+
+           stackPartials = stackPartials || {};
+           partial.stackPartials = stackPartials;
+           for (key in partials) {
+             if (!stackPartials[key]) stackPartials[key] = partials[key];
+           }
+           for (key in stackPartials) {
+             partial.partials[key] = stackPartials[key];
+           }
+
+           return partial;
+         }
+
+         var rAmp = /&/g,
+             rLt = /</g,
+             rGt = />/g,
+             rApos = /\'/g,
+             rQuot = /\"/g,
+             hChars = /[&<>\"\']/;
+
+         function coerceToString(val) {
+           return String((val === null || val === undefined) ? '' : val);
+         }
+
+         function hoganEscape(str) {
+           str = coerceToString(str);
+           return hChars.test(str) ?
+             str
+               .replace(rAmp, '&amp;')
+               .replace(rLt, '&lt;')
+               .replace(rGt, '&gt;')
+               .replace(rApos, '&#39;')
+               .replace(rQuot, '&quot;') :
+             str;
+         }
+
+         var isArray = Array.isArray || function(a) {
+           return Object.prototype.toString.call(a) === '[object Array]';
+         };
+
+       })( true ? exports : Hogan);
+
+
+/***/ },
+/* 8 */
 /***/ function(module, exports) {
 
        var util;
diff --git a/resources/mobile.issues/CleanupOverlay.js 
b/resources/mobile.issues/CleanupOverlay.js
index ec6d502..086e88e 100644
--- a/resources/mobile.issues/CleanupOverlay.js
+++ b/resources/mobile.issues/CleanupOverlay.js
@@ -1,6 +1,6 @@
 ( function ( M, $ ) {
        var Overlay = M.require( 'mobile.overlays/Overlay' ),
-               Icon = M.require( 'mobile.startup/Icon' ),
+               Icon = mw.mf.Icon,
                icon = new Icon( {
                        name: 'cleanup-gray',
                        additionalClassNames: 'issue-notice',
diff --git a/resources/mobile.mediaViewer/ImageOverlay.js 
b/resources/mobile.mediaViewer/ImageOverlay.js
index 1896763..024243b 100644
--- a/resources/mobile.mediaViewer/ImageOverlay.js
+++ b/resources/mobile.mediaViewer/ImageOverlay.js
@@ -1,6 +1,6 @@
 ( function ( M, $ ) {
        var Overlay = M.require( 'mobile.overlays/Overlay' ),
-               Icon = M.require( 'mobile.startup/Icon' ),
+               Icon = mw.mf.Icon,
                Button = M.require( 'mobile.startup/Button' ),
                ImageGateway = M.require( 'mobile.mediaViewer/ImageGateway' );
 
diff --git a/resources/mobile.overlays/Overlay.js 
b/resources/mobile.overlays/Overlay.js
index 2547357..784fe86 100644
--- a/resources/mobile.overlays/Overlay.js
+++ b/resources/mobile.overlays/Overlay.js
@@ -1,7 +1,7 @@
 ( function ( M, $ ) {
 
        var View = mw.mf.View,
-               Icon = M.require( 'mobile.startup/Icon' ),
+               Icon = mw.mf.Icon,
                Button = M.require( 'mobile.startup/Button' ),
                Anchor = M.require( 'mobile.startup/Anchor' ),
                icons = M.require( 'mobile.startup/icons' ),
diff --git a/resources/mobile.patrol.ajax/init.js 
b/resources/mobile.patrol.ajax/init.js
index 60575a9..50cab3d 100644
--- a/resources/mobile.patrol.ajax/init.js
+++ b/resources/mobile.patrol.ajax/init.js
@@ -12,7 +12,7 @@
        }
        $( function () {
                var $patrolLinks = $( '.patrollink a' ),
-                       Icon = M.require( 'mobile.startup/Icon' ),
+                       Icon = mw.mf.Icon,
                        toast = M.require( 'mobile.toast/toast' ),
                        $spinner = $( new Icon( {
                                name: 'spinner',
diff --git a/resources/mobile.references/ReferencesDrawer.js 
b/resources/mobile.references/ReferencesDrawer.js
index 3d16006..9382c83 100644
--- a/resources/mobile.references/ReferencesDrawer.js
+++ b/resources/mobile.references/ReferencesDrawer.js
@@ -1,7 +1,7 @@
 ( function ( M, $ ) {
        var Drawer = M.require( 'mobile.drawers/Drawer' ),
                icons = M.require( 'mobile.startup/icons' ),
-               Icon = M.require( 'mobile.startup/Icon' );
+               Icon = mw.mf.Icon;
 
        /**
         * Drawer for references
diff --git a/resources/mobile.search/SearchOverlay.js 
b/resources/mobile.search/SearchOverlay.js
index 7cdb52d..6cedfa5 100644
--- a/resources/mobile.search/SearchOverlay.js
+++ b/resources/mobile.search/SearchOverlay.js
@@ -3,7 +3,7 @@
        var
                Overlay = M.require( 'mobile.overlays/Overlay' ),
                Anchor = M.require( 'mobile.startup/Anchor' ),
-               Icon = M.require( 'mobile.startup/Icon' ),
+               Icon = mw.mf.Icon,
                WatchstarPageList = M.require( 
'mobile.pagelist.scripts/WatchstarPageList' ),
                SEARCH_DELAY = 300,
                $html = $( 'html' ),
diff --git a/resources/mobile.special.nearby.scripts/nearby.js 
b/resources/mobile.special.nearby.scripts/nearby.js
index 10dbaca..c3a5e61 100644
--- a/resources/mobile.special.nearby.scripts/nearby.js
+++ b/resources/mobile.special.nearby.scripts/nearby.js
@@ -1,5 +1,5 @@
 ( function ( M, $ ) {
-       var Icon = M.require( 'mobile.startup/Icon' ),
+       var Icon = mw.mf.Icon,
                endpoint = mw.config.get( 'wgMFNearbyEndpoint' ),
                router = require( 'mediawiki.router' ),
                Nearby = M.require( 'mobile.nearby/Nearby' );
diff --git a/resources/mobile.startup/icons.js 
b/resources/mobile.startup/icons.js
index 7e4d70c..3ee54b9 100644
--- a/resources/mobile.startup/icons.js
+++ b/resources/mobile.startup/icons.js
@@ -1,6 +1,6 @@
 ( function ( M, $ ) {
 
-       var Icon = M.require( 'mobile.startup/Icon' );
+       var Icon = mw.mf.Icon;
 
        /**
         * A set of shared icons.
diff --git a/resources/mobile.talk.overlays/TalkSectionAddOverlay.js 
b/resources/mobile.talk.overlays/TalkSectionAddOverlay.js
index b45e626..70cc987 100644
--- a/resources/mobile.talk.overlays/TalkSectionAddOverlay.js
+++ b/resources/mobile.talk.overlays/TalkSectionAddOverlay.js
@@ -1,7 +1,7 @@
 ( function ( M, $ ) {
        var TalkOverlayBase = M.require( 'mobile.talk.overlays/TalkOverlayBase' 
),
                toast = M.require( 'mobile.toast/toast' ),
-               Icon = M.require( 'mobile.startup/Icon' );
+               Icon = mw.mf.Icon;
 
        /**
         * Overlay for adding a talk section
diff --git a/resources/mobile.toc/TableOfContents.js 
b/resources/mobile.toc/TableOfContents.js
index 0c3754b..92f2350 100644
--- a/resources/mobile.toc/TableOfContents.js
+++ b/resources/mobile.toc/TableOfContents.js
@@ -1,6 +1,6 @@
 ( function ( M ) {
        var View = mw.mf.View,
-               Icon = M.require( 'mobile.startup/Icon' );
+               Icon = mw.mf.Icon;
 
        /**
         * View for table of contents
diff --git a/resources/mobile.toggle/toggle.js 
b/resources/mobile.toggle/toggle.js
index 3ed92da..a756d2b 100644
--- a/resources/mobile.toggle/toggle.js
+++ b/resources/mobile.toggle/toggle.js
@@ -7,7 +7,7 @@
                        name: 'arrow',
                        additionalClassNames: 'indicator'
                },
-               Icon = M.require( 'mobile.startup/Icon' );
+               Icon = mw.mf.Icon;
 
        /**
         * A class for enabling toggling
diff --git a/resources/mobile.watchstar/Watchstar.js 
b/resources/mobile.watchstar/Watchstar.js
index aa1db07..ec698c1 100644
--- a/resources/mobile.watchstar/Watchstar.js
+++ b/resources/mobile.watchstar/Watchstar.js
@@ -2,7 +2,7 @@
 
        var View = mw.mf.View,
                WatchstarGateway = M.require( 
'mobile.watchstar/WatchstarGateway' ),
-               Icon = M.require( 'mobile.startup/Icon' ),
+               Icon = mw.mf.Icon,
                watchIcon = new Icon( {
                        name: 'watch',
                        additionalClassNames: 'watch-this-article'
diff --git a/resources/skins.minerva.editor/init.js 
b/resources/skins.minerva.editor/init.js
index 046acb9..f3e5242 100644
--- a/resources/skins.minerva.editor/init.js
+++ b/resources/skins.minerva.editor/init.js
@@ -8,7 +8,7 @@
                router = require( 'mediawiki.router' ),
                overlayManager = M.require( 
'skins.minerva.scripts/overlayManager' ),
                loader = M.require( 'mobile.overlays/moduleLoader' ),
-               Icon = M.require( 'mobile.startup/Icon' ),
+               Icon = mw.mf.Icon,
                Button = M.require( 'mobile.startup/Button' ),
                Anchor = M.require( 'mobile.startup/Anchor' ),
                skin = M.require( 'skins.minerva.scripts/skin' ),
diff --git a/tests/qunit/mobile.pagelist.scripts/test_WatchstarPageList.js 
b/tests/qunit/mobile.pagelist.scripts/test_WatchstarPageList.js
index a04eb25..a45e27f 100644
--- a/tests/qunit/mobile.pagelist.scripts/test_WatchstarPageList.js
+++ b/tests/qunit/mobile.pagelist.scripts/test_WatchstarPageList.js
@@ -2,7 +2,7 @@
 
        var PageList = M.require( 'mobile.pagelist.scripts/WatchstarPageList' ),
                user = M.require( 'mobile.user/user' ),
-               Icon = M.require( 'mobile.startup/Icon' ),
+               Icon = mw.mf.Icon,
                watchIcon = new Icon( {
                        name: 'watched'
                } );
diff --git a/tests/qunit/mobile.watchlist/test_WatchList.js 
b/tests/qunit/mobile.watchlist/test_WatchList.js
index 7c2d7ae..a1da53a 100644
--- a/tests/qunit/mobile.watchlist/test_WatchList.js
+++ b/tests/qunit/mobile.watchlist/test_WatchList.js
@@ -2,7 +2,7 @@
 
        var WatchList = M.require( 'mobile.watchlist/WatchList' ),
                user = M.require( 'mobile.user/user' ),
-               Icon = M.require( 'mobile.startup/Icon' ),
+               Icon = mw.mf.Icon,
                watchIcon = new Icon( {
                        name: 'watched'
                } );
diff --git a/tests/qunit/mobile.watchstar/test_Watchstar.js 
b/tests/qunit/mobile.watchstar/test_Watchstar.js
index 76e6f9a..5004d8b 100644
--- a/tests/qunit/mobile.watchstar/test_Watchstar.js
+++ b/tests/qunit/mobile.watchstar/test_Watchstar.js
@@ -3,7 +3,7 @@
        var Watchstar = M.require( 'mobile.watchstar/Watchstar' ),
                CtaDrawer = M.require( 'mobile.drawers/CtaDrawer' ),
                toast = M.require( 'mobile.toast/toast' ),
-               Icon = M.require( 'mobile.startup/Icon' ),
+               Icon = mw.mf.Icon,
                watchIcon = new Icon( {
                        name: 'watched'
                } ),
diff --git a/webpack.config.js b/webpack.config.js
index 5b855f3..9164ed6 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -10,6 +10,14 @@
                // the "index" entry gets written to index.js.
                filename: '/[name]/index.js'
        },
+       module: {
+               loaders: [
+                       {
+                               test: /\.hogan/,
+                               loader: 'mustache?noShortcut'
+                       }
+               ]
+       },
        entry: {
                'mobile.frontend': './build_resources/mobile.frontend/index.js'
        }

-- 
To view, visit https://gerrit.wikimedia.org/r/332926
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: If9dca17ecfecc385928ba326e39134cfbdb32f72
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/MobileFrontend
Gerrit-Branch: mfui
Gerrit-Owner: Jdlrobson <jrob...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to