(function () {

/* Imports */
var Meteor = Package.meteor.Meteor;
var RoutePolicy = Package.routepolicy.RoutePolicy;
var WebApp = Package.webapp.WebApp;
var main = Package.webapp.main;
var WebAppInternals = Package.webapp.WebAppInternals;
var EJSON = Package.ejson.EJSON;
var _ = Package.underscore._;

/* Package-scope variables */
var Inject, id;

(function(){

///////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                   //
// packages/meteorhacks_inject-initial/lib/inject-server.js                                          //
//                                                                                                   //
///////////////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                     //
function escapeReplaceString(str) {                                                                  // 1
  /*                                                                                                 // 2
   * When using string.replace(str, newSubStr), the dollar sign ("$") is                             // 3
   * considered a special character in newSubStr, and needs to be escaped                            // 4
   * as "$$".  We have to do this twice, for escaping the newSubStr in                               // 5
   * this function, and for the resulting string which is passed back.                               // 6
   * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace
   */                                                                                                // 8
   return str.replace(/\$/g, '$$$$');                                                                // 9
}                                                                                                    // 10
                                                                                                     // 11
Inject = {                                                                                           // 12
  // stores in a script type=application/ejson tag, accessed with Injected.obj('id')                 // 13
  obj: function(id, data, res) {                                                                     // 14
    this._checkForObjOrFunction(data,                                                                // 15
      'Inject.obj(id, data [,res]) expects `data` to be an Object or Function');                     // 16
                                                                                                     // 17
    if (res) {                                                                                       // 18
      this._resAssign(res, 'objList', id, data);                                                     // 19
    } else {                                                                                         // 20
      this.objList[id] = data;                                                                       // 21
    }                                                                                                // 22
  },                                                                                                 // 23
  objList: {},                                                                                       // 24
                                                                                                     // 25
  // Inserts a META called `id`, whose `content` can be accessed with Injected.meta()                // 26
  meta: function(id, data, res) {                                                                    // 27
    this._checkForTextOrFunction(data,                                                               // 28
      'Inject.meta(id, data [,res]) expects `data` to be an String or Function');                    // 29
                                                                                                     // 30
    if (res) {                                                                                       // 31
      this._resAssign(res, 'metaList', id, data);                                                    // 32
    } else {                                                                                         // 33
      this.metaList[id] = data;                                                                      // 34
    }                                                                                                // 35
  },                                                                                                 // 36
  metaList: {},                                                                                      // 37
                                                                                                     // 38
  rawHead: function(id, textOrFunc, res) {                                                           // 39
    this._checkForTextOrFunction(textOrFunc,                                                         // 40
      'Inject.rawHead(id, content [,res]) expects `content` to be an String or Function');           // 41
                                                                                                     // 42
    if (res) {                                                                                       // 43
      this._resAssign(res, 'rawHeads', id, textOrFunc);                                              // 44
    } else {                                                                                         // 45
      this.rawHeads[id] = textOrFunc;                                                                // 46
    }                                                                                                // 47
  },                                                                                                 // 48
  rawHeads: {},                                                                                      // 49
                                                                                                     // 50
  rawBody: function(id, textOrFunc, res) {                                                           // 51
    this._checkForTextOrFunction(textOrFunc,                                                         // 52
      'Inject.rawBody(id, content [,res]) expects `content` to be an String or Function');           // 53
                                                                                                     // 54
    if (res) {                                                                                       // 55
      this._resAssign(res, 'rawBodies', id, textOrFunc);                                             // 56
    } else {                                                                                         // 57
      this.rawBodies[id] = textOrFunc;                                                               // 58
    }                                                                                                // 59
  },                                                                                                 // 60
  rawBodies: {},                                                                                     // 61
                                                                                                     // 62
  // The callback receives the entire HTML page and must return a modified version                   // 63
  rawModHtml: function(id, func) {                                                                   // 64
    if (!_.isFunction(func)) {                                                                       // 65
      var message = 'Inject func id "' + id + '" should be a function, not ' + typeof(func);         // 66
      throw new Error(message);                                                                      // 67
    }                                                                                                // 68
                                                                                                     // 69
    this.rawModHtmlFuncs[id] = func;                                                                 // 70
  },                                                                                                 // 71
  rawModHtmlFuncs: {},                                                                               // 72
                                                                                                     // 73
  _injectObjects: function(html, res) {                                                              // 74
    var objs = _.extend({}, Inject.objList, res.Inject && res.Inject.objList);                       // 75
    if (_.isEmpty(objs)) {                                                                           // 76
      return html;                                                                                   // 77
    }                                                                                                // 78
                                                                                                     // 79
    var obj, injectHtml = '';                                                                        // 80
    for (id in objs) {                                                                               // 81
      obj = _.isFunction(objs[id]) ? objs[id](res) : objs[id];                                       // 82
      injectHtml += "  <script id='" + id.replace("'", '&apos;')                                     // 83
        + "' type='application/ejson'>" + EJSON.stringify(obj)                                       // 84
        + "</script>\n";                                                                             // 85
    }                                                                                                // 86
                                                                                                     // 87
    return html.replace('<head>', '<head>\n' + escapeReplaceString(injectHtml));                     // 88
  },                                                                                                 // 89
                                                                                                     // 90
  _injectMeta: function(html, res) {                                                                 // 91
    var metas = _.extend({}, Inject.metaList, res.Inject && res.Inject.metaList);                    // 92
    if (_.isEmpty(metas))                                                                            // 93
      return html;                                                                                   // 94
                                                                                                     // 95
    var injectHtml = '';                                                                             // 96
    for (id in metas) {                                                                              // 97
      var meta = this._evalToText(metas[id], res, html);                                             // 98
      injectHtml += "  <meta id='" + id.replace("'", '&apos;')                                       // 99
        + "' content='" + meta.replace("'", '&apos;') + "'>\n", res;                                 // 100
    }                                                                                                // 101
                                                                                                     // 102
    return html.replace('<head>', '<head>\n' + escapeReplaceString(injectHtml));                     // 103
  },                                                                                                 // 104
                                                                                                     // 105
  _injectHeads: function(html, res) {                                                                // 106
    var heads = _.extend({}, Inject.rawHeads, res.Inject && res.Inject.rawHeads);                    // 107
    if (_.isEmpty(heads))                                                                            // 108
      return html;                                                                                   // 109
                                                                                                     // 110
    var injectHtml = '';                                                                             // 111
    for (id in heads) {                                                                              // 112
      var head = this._evalToText(heads[id], res, html);                                             // 113
      injectHtml += head + '\n';                                                                     // 114
    }                                                                                                // 115
                                                                                                     // 116
    return html.replace('<head>', '<head>\n' + escapeReplaceString(injectHtml));                     // 117
  },                                                                                                 // 118
                                                                                                     // 119
  _injectBodies: function(html, res) {                                                               // 120
    var bodies = _.extend({}, Inject.rawBodies, res.Inject && res.Inject.rawBodies);                 // 121
    if (_.isEmpty(bodies))                                                                           // 122
      return html;                                                                                   // 123
                                                                                                     // 124
    var injectHtml = '';                                                                             // 125
    for (id in bodies) {                                                                             // 126
      var body = this._evalToText(bodies[id], res, html);                                            // 127
      injectHtml += body + '\n';                                                                     // 128
    }                                                                                                // 129
                                                                                                     // 130
    return html.replace('<body>', '<body>\n' + escapeReplaceString(injectHtml));                     // 131
  },                                                                                                 // 132
                                                                                                     // 133
  // ensure object exists and store there                                                            // 134
  _resAssign: function(res, key, id, value) {                                                        // 135
    if (!res.Inject)                                                                                 // 136
      res.Inject = {};                                                                               // 137
    if (!res.Inject[key])                                                                            // 138
      res.Inject[key] = {};                                                                          // 139
    res.Inject[key][id] = value;                                                                     // 140
  },                                                                                                 // 141
                                                                                                     // 142
  _checkForTextOrFunction: function (arg, message) {                                                 // 143
    if(!(_.isString(arg) || _.isFunction(arg))) {                                                    // 144
      throw new Error(message);                                                                      // 145
    }                                                                                                // 146
  },                                                                                                 // 147
                                                                                                     // 148
  _checkForObjOrFunction: function (arg, message) {                                                  // 149
    if(!(_.isObject(arg) || _.isFunction(arg))) {                                                    // 150
      throw new Error(message);                                                                      // 151
    }                                                                                                // 152
  },                                                                                                 // 153
                                                                                                     // 154
  // we don't handle errors here. Let them to handle in a higher level                               // 155
  _evalToText: function(textOrFunc, res, html) {                                                     // 156
    if(_.isFunction(textOrFunc)) {                                                                   // 157
      return textOrFunc(res, html);                                                                  // 158
    } else {                                                                                         // 159
      return textOrFunc;                                                                             // 160
    }                                                                                                // 161
  }                                                                                                  // 162
};                                                                                                   // 163
                                                                                                     // 164
Inject.rawModHtml('injectHeads', Inject._injectHeads.bind(Inject));                                  // 165
Inject.rawModHtml('injectMeta', Inject._injectMeta.bind(Inject));                                    // 166
Inject.rawModHtml('injectBodies', Inject._injectBodies.bind(Inject));                                // 167
Inject.rawModHtml('injectObjects', Inject._injectObjects.bind(Inject));                              // 168
                                                                                                     // 169
///////////////////////////////////////////////////////////////////////////////////////////////////////

}).call(this);






(function(){

///////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                   //
// packages/meteorhacks_inject-initial/lib/inject-core.js                                            //
//                                                                                                   //
///////////////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                     //
// Hijack core node API and attach data to the response dynamically                                  // 1
// We are simply using this hack because, there is no way to alter                                   // 2
// Meteor's html content on the server side                                                          // 3
                                                                                                     // 4
Inject._hijackWrite = function(res) {                                                                // 5
  var originalWrite = res.write;                                                                     // 6
  res.write = function(chunk, encoding) {                                                            // 7
    //prevent hijacking other http requests                                                          // 8
    if(!res.iInjected &&                                                                             // 9
      encoding === undefined && /^<!DOCTYPE html>/.test(chunk)) {                                    // 10
      chunk = chunk.toString();                                                                      // 11
                                                                                                     // 12
      for (id in Inject.rawModHtmlFuncs) {                                                           // 13
        chunk = Inject.rawModHtmlFuncs[id](chunk, res);                                              // 14
        if (!_.isString(chunk)) {                                                                    // 15
          throw new Error('Inject func id "' + id + '" must return HTML, not '                       // 16
            + typeof(chunk) + '\n' + JSON.stringify(chunk, null, 2));                                // 17
        }                                                                                            // 18
      }                                                                                              // 19
                                                                                                     // 20
      res.iInjected = true;                                                                          // 21
    }                                                                                                // 22
                                                                                                     // 23
    originalWrite.call(res, chunk, encoding);                                                        // 24
  };                                                                                                 // 25
}                                                                                                    // 26
                                                                                                     // 27
WebApp.connectHandlers.use(function(req, res, next) {                                                // 28
  // We only separate this to make testing easier                                                    // 29
  Inject._hijackWrite(res);                                                                          // 30
                                                                                                     // 31
  next();                                                                                            // 32
});                                                                                                  // 33
                                                                                                     // 34
//meteor algorithm to check if this is a meteor serving http request or not                          // 35
Inject.appUrl = function(url) {                                                                      // 36
  if (url === '/favicon.ico' || url === '/robots.txt')                                               // 37
    return false;                                                                                    // 38
                                                                                                     // 39
  // NOTE: app.manifest is not a web standard like favicon.ico and                                   // 40
  // robots.txt. It is a file id we have chosen to use for HTML5                                     // 41
  // appcache URLs. It is included here to prevent using an appcache                                 // 42
  // then removing it from poisoning an app permanently. Eventually,                                 // 43
  // once we have server side routing, this won't be needed as                                       // 44
  // unknown URLs with return a 404 automatically.                                                   // 45
  if (url === '/app.manifest')                                                                       // 46
    return false;                                                                                    // 47
                                                                                                     // 48
  // Avoid serving app HTML for declared routes such as /sockjs/.                                    // 49
  if (typeof(RoutePolicy) != 'undefined' && RoutePolicy.classify(url))                               // 50
    return false;                                                                                    // 51
                                                                                                     // 52
  // we currently return app HTML on all URLs by default                                             // 53
  return true;                                                                                       // 54
};                                                                                                   // 55
                                                                                                     // 56
///////////////////////////////////////////////////////////////////////////////////////////////////////

}).call(this);


/* Exports */
if (typeof Package === 'undefined') Package = {};
Package['meteorhacks:inject-initial'] = {
  Inject: Inject
};

})();

//# sourceMappingURL=meteorhacks_inject-initial.js.map
