Merge branch 'devel' into auth

Conflicts:
	packages/livedata/livedata_common.js
	packages/livedata/livedata_connection.js
	packages/livedata/livedata_server.js
	packages/mongo-livedata/collection.js
This commit is contained in:
David Glasser
2012-09-17 14:42:10 -07:00
40 changed files with 240 additions and 224 deletions

View File

@@ -1,4 +1,4 @@
if (Meteor.is_client) {
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to ~name~.";
};
@@ -12,7 +12,7 @@ if (Meteor.is_client) {
};
}
if (Meteor.is_server) {
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});

View File

@@ -10,8 +10,8 @@ available just on the client, just on the server, or *Anywhere*.
<h2 id="core"><span>Meteor Core</span></h2>
{{> api_box is_client}}
{{> api_box is_server}}
{{> api_box isClient}}
{{> api_box isServer}}
{{> api_box startup}}
On a server, the function will run as soon as the server process is
@@ -20,7 +20,7 @@ is ready and any `<body>` templates from your `.html` files have been
put on the screen.
// On server startup, if the database is empty, create some initial data.
if (Meteor.is_server) {
if (Meteor.isServer) {
Meteor.startup(function () {
if (Rooms.find().count() === 0) {
Rooms.insert({name: "Initial room"});
@@ -46,7 +46,7 @@ will publish that cursor's documents.
// server: publish the rooms collection, minus secret info.
Meteor.publish("rooms", function () {
return Rooms.find({}, {fields: {secret_info: false}});
return Rooms.find({}, {fields: {secretInfo: false}});
});
Otherwise, the publish function can <i>set</i> and <i>unset</i>
@@ -68,7 +68,7 @@ Example:
var uuid = Meteor.uuid();
var count = 0;
var handle = Messages.find({room_id: roomId}).observe({
var handle = Messages.find({roomId: roomId}).observe({
added: function (doc, idx) {
count++;
self.set("counts", uuid, {roomId: roomId, count: count});
@@ -197,7 +197,7 @@ remotely by clients. They should return a value or throw an exception.
Inside your method invocation, `this` is bound to a method invocation
object, which provides the following:
* `is_simulation`: a boolean value, true if this invocation is a stub.
* `isSimulation`: a boolean value, true if this invocation is a stub.
* `unblock`: when called, allows the next method from this client to
begin running.
@@ -214,7 +214,7 @@ intended to *simulate* the result of what the server's method will do,
but without waiting for the round trip delay. If a stub throws an
exception it will be logged to the console.
{{> api_box method_invocation_is_simulation}}
{{> api_box method_invocation_isSimulation}}
{{> api_box method_invocation_unblock}}
@@ -309,16 +309,16 @@ the server. The return value is an object with the following fields:
new connection), and <code>waiting</code> (failed to connect and
waiting to try to reconnect).</dd>
<dt><span class="name">retry_count</span>
<dt><span class="name">retryCount</span>
<span class="type">Number</span></dt>
<dd>The number of times the client has tried to reconnect since the
connection was lost. 0 when connected.</dd>
<dt><span class="name">retry_time</span>
<dt><span class="name">retryTime</span>
<span class="type">Number or undefined</span></dt>
<dd>The estimated time of the next reconnection attempt. To turn this
into an interval until the next reconnection, use
<code>retry_time - (new Date()).getTime()</code>. This key will
<code>retryTime - (new Date()).getTime()</code>. This key will
be set only when <code>status</code> is <code>waiting</code>.
</dd>
</dl>
@@ -396,13 +396,13 @@ compatible with the popular Mongo database API. The same database API
works on both the client and the server (see below).
// return array of my messages
var my_messages = Messages.find({user_id:Session.get('my_user_id')}).fetch();
var myMessages = Messages.find({userId: Session.get('myUserId')}).fetch();
// create a new message
Messages.insert({text: "Hello, world!"});
// mark my first message as "important"
Messages.update(my_messages[0].id, {$set: {important: true}});
Messages.update(myMessages[0].id, {$set: {important: true}});
If you pass a `name` when you create the collection, then you are
declaring a persistent collection &mdash; one that is stored on the
@@ -552,9 +552,9 @@ undefined. If the insert is successful, `error` is undefined and
Example:
var groceries_id = Lists.insert({name: "Groceries"});
Items.insert({list: groceries_id, name: "Watercress"});
Items.insert({list: groceries_id, name: "Persimmons"});
var groceriesId = Lists.insert({name: "Groceries"});
Items.insert({list: groceriesId, name: "Watercress"});
Items.insert({list: groceriesId, name: "Persimmons"});
{{> api_box update}}
@@ -635,9 +635,9 @@ the matching documents.
Examples:
// Print the titles of the five top-scoring posts
var top_posts = Posts.find({}, {sort: {score: -1}, limit: 5});
var topPosts = Posts.find({}, {sort: {score: -1}, limit: 5});
var count = 0;
top_posts.forEach(function (post) {
topPosts.forEach(function (post) {
console.log("Title of post " + count + ": " + post.title);
count += 1;
});
@@ -663,8 +663,8 @@ the matching documents.
// Display a count of posts matching certain criteria. Automatically
// keep it updated as the database changes.
var frag = Meteor.render(function () {
var high_scoring = Posts.find({score: {$gt: 10}});
return "<p>There are " + high_scoring.count() + " posts with " +
var highScoring = Posts.find({score: {$gt: 10}});
return "<p>There are " + highScoring.count() + " posts with " +
"scores greater than 10</p>";
});
document.body.appendChild(frag);
@@ -687,29 +687,29 @@ query result.
`callbacks` may have the following functions as properties:
<dl class="callbacks">
{{#dtdd "added(document, before_index)"}}
{{#dtdd "added(document, beforeIndex)"}}
A new document entered the result set. It was inserted
immediately before the document currently at the
position `before_index`. Or if it was inserted at the end
of the list, `before_index` will be equal to the (prior)
position `beforeIndex`. Or if it was inserted at the end
of the list, `beforeIndex` will be equal to the (prior)
length of the list.
{{/dtdd}}
{{#dtdd "changed(new_document, at_index, old_document)"}}
The contents of the document at position `at_index`
changed to `new_document`, was previously `old_document`.
{{#dtdd "changed(newDocument, atIndex, oldDocument)"}}
The contents of the document at position `atIndex`
changed to `newDocument`, was previously `oldDocument`.
{{/dtdd}}
{{#dtdd "moved(document, old_index, new_index)"}}
{{#dtdd "moved(document, oldIndex, newIndex)"}}
A document changed its position in the result set,
from `old_index` to `new_index`. For your
from `oldIndex` to `newIndex`. For your
convenience, its current contents is `document`. (This will
only fire immediately after `changed`.
{{/dtdd}}
{{#dtdd "removed(old_document, at_index)"}}
The document at position `at_index`, which was previously
`old_document`, is no longer in the result set.
{{#dtdd "removed(oldDocument, atIndex)"}}
The document at position `atIndex`, which was previously
`oldDocument`, is no longer in the result set.
{{/dtdd}}
</dl>
@@ -725,7 +725,7 @@ Example:
// Keep track of how many administrators are online.
var count = 0;
var query = Users.find({admin: true, online_now: true});
var query = Users.find({admin: true, onlineNow: true});
var handle = query.observe({
added: function (user) {
count++;
@@ -836,9 +836,9 @@ store an arbitrary set of key-value pairs. Use it to store things like
the currently selected item in a list.
What's special about `Session` is that it's reactive. If
you call [`Session.get`](#session_get)`("current_list")`
you call [`Session.get`](#session_get)`("currentList")`
from inside a template, the template will automatically be rerendered
whenever [`Session.set`](#session_set) is called.
whenever [`Session.set`](#session_set)`("currentList", x)` is called.
{{> api_box set}}
@@ -882,33 +882,33 @@ These two expressions do the same thing:
Example:
<template name="posts_view">
<template name="postsView">
{{dstache}}! Show a dynamically updating list of items. Let the user click on an
item to select it. The selected item is given a CSS class so it
can be rendered differently. }}
{{dstache}}#each posts}}
{{dstache}}> post_item }}
{{dstache}}> postItem }}
{{dstache}}/each}}
</{{! }}template>
<template name="post_item">
<div class="{{dstache}}post_class}}">{{dstache}}title}}</div>
<template name="postItem">
<div class="{{dstache}}postClass}}">{{dstache}}title}}</div>
</{{! }}template>
///// in JS file
Template.posts_view.posts = function() {
Template.postsView.posts = function() {
return Posts.find();
};
Template.post_item.post_class = function() {
return Session.equals("selected_post", this._id) ?
Template.postItem.postClass = function() {
return Session.equals("selectedPost", this._id) ?
"selected" : "";
};
Template.post_item.events({
Template.postItem.events({
'click': function() {
Session.set("selected_post", this._id);
Session.set("selectedPost", this._id);
}
});
@@ -1486,7 +1486,7 @@ sources.
Create an invalidation context by calling this constructor, then run
some code inside the context with [`run`](#run). Finally, register a
callback with [`on_invalidate`](#on_invalidate) that will get called
callback with [`onInvalidate`](#oninvalidate) that will get called
when the code you run wants to signal that it should be rerun.
Code can see if it's running inside an invalidation context by reading
@@ -1496,7 +1496,7 @@ from inside a context. If it wants to participate in the reactivity
system, it should save this context away, and later call the
[`invalidate`](#invalidate) method on the context when it wants to
signal that something has changed. If it does this, it should also use
[`on_invalidate`](#on_invalidate) to set up a cleanup function so that
[`onInvalidate`](#oninvalidate) to set up a cleanup function so that
it can know when to stop listening for changes.
Invalidation contexts have an attribute `id` which is a unique positive
@@ -1513,7 +1513,7 @@ previous value. It returns the result of calling `func`.
It's fine for `run` to be called recursively. `current` will return the
innermost context.
{{> api_box on_invalidate }}
{{> api_box onInvalidate }}
If this context hasn't been invalidated yet, adds `callback` to the list
of callbacks that will be called when [`invalidate`](#invalidate) is
@@ -1523,25 +1523,25 @@ immediately.
Typically this function will have two kinds of callers:
* The function that creates the invalidation context will use the
`on_invalidate` callback as a signal to rerun the code in the context,
`onInvalidate` callback as a signal to rerun the code in the context,
to see what new value it returns. In order to rerun the code, it'll
create a fresh invalidation context and reregister its `on_invalidate`
create a fresh invalidation context and reregister its `onInvalidate`
callback on that new context. When that context is invalidated the
cycle will repeat.
* Functions that are sources of reactive data will save
[`Meteor.deps.Context.current`](#current) into some kind of list of
listeners. They'll use the `on_invalidate` callback to remove the
listeners. They'll use the `onInvalidate` callback to remove the
context from their listener list.
Example:
// Print the current username to the console. Will re-run every time
// the username changes.
var log_current_username = function () {
var logCurrentUsername = function () {
var update = function () {
var ctx = new Meteor.deps.Context(); // invalidation context
ctx.on_invalidate(update); // rerun update() on invalidation
ctx.onInvalidate(update); // rerun update() on invalidation
ctx.run(function () {
var username = Session.get("username");
console.log("The current username is now", username);
@@ -1551,10 +1551,10 @@ Example:
};
// Example use. Since Session is reactive (meaning that it knows how
// to use Meteor.deps to record its dependencies), log_current_username
// to use Meteor.deps to record its dependencies), logCurrentUsername
// will be re-run whenever Session.set is called for "username".
Session.set("username", "matt");
log_current_username(); // prints matt
logCurrentUsername(); // prints matt
Session.set("username", "geoff"); // immediately prints geoff
Session.set("username", "geoff"); // won't print: Session won't trigger
// invalidation if the value is the same.
@@ -1563,7 +1563,7 @@ Example:
If this function has already been called on this context, it does
nothing (a mathematician would say that it is "idempotent.") Otherwise
it calls each [`on_invalidate`](#on_invalidate) function registered on
it calls each [`onInvalidate`](#oninvalidate) function registered on
the context.
The functions aren't called immediately &mdash; instead, they will be
@@ -1586,7 +1586,7 @@ Example:
// Function to get the temperature (and, if called in a reactive
// context, start listening for changes to the temperature.)
Weather.prototype.get_temp = function () {
Weather.prototype.getTemp = function () {
var context = Meteor.deps.Context.current;
// If we're inside a context, and it's not yet listening to
@@ -1597,7 +1597,7 @@ Example:
// .. and remember to take it off our list when it goes away.
var self = this;
context.on_invalidate(function () {
context.onInvalidate(function () {
delete self.listeners[context.id];
});
}
@@ -1608,20 +1608,20 @@ Example:
// Function to set the temperature, and notify anyone that might be
// listening for temperature updates.
Weather.prototype.set_temp = function (new_temp) {
if (this.temperature === new_temp)
Weather.prototype.setTemp = function (newTemp) {
if (this.temperature === newTemp)
return; // don't want to trigger invalidation if there's no change.
// Set the temperature
this.temperature = new_temp;
this.temperature = newTemp;
// Notify any contexts that care about temperature changes
for (var context_id in this.listeners)
// This will trigger the on_invalidate function above, but not
for (var contextId in this.listeners)
// This will trigger the onInvalidate function above, but not
// immediately -- only when Meteor.flush() is called, or at the end
// of the event loop. So we know that this.listeners will be
// emptied, but it won't change while we're trying to loop over it.
this.listeners[context_id].invalidate();
this.listeners[contextId].invalidate();
};
{{> api_box current }}
@@ -1658,7 +1658,7 @@ that any auto-updating elements that you have created by calling
DOM tree.
Technically speaking, `flush` calls the [invalidation
callbacks](#on_invalidate) on every [reactive context](#context) that
callbacks](#oninvalidate) on every [reactive context](#context) that
has been [invalidated](#invalidate), but hasn't yet has its callbacks
called. If the invalidation callbacks invalidate still more contexts,
flush keeps flushing until everything is totally settled. The DOM
@@ -1742,10 +1742,10 @@ Contents of the result object:
Example server method:
Meteor.methods({check_twitter: function (user_id) {
Meteor.methods({checkTwitter: function (userId) {
this.unblock();
var result = Meteor.http.call("GET", "http://api.twitter.com/xxx",
{params: {user: user_id}});
{params: {user: userId}});
if (result.statusCode === 200)
return true
return false;

View File

@@ -1,13 +1,13 @@
Template.api.is_client = {
id: "meteor_is_client",
name: "Meteor.is_client",
Template.api.isClient = {
id: "meteor_isclient",
name: "Meteor.isClient",
locus: "Anywhere",
descr: ["Boolean variable. True if running in client environment."]
};
Template.api.is_server = {
id: "meteor_is_server",
name: "Meteor.is_server",
Template.api.isServer = {
id: "meteor_isserver",
name: "Meteor.isServer",
locus: "Anywhere",
descr: ["Boolean variable. True if running in server environment."]
};
@@ -164,9 +164,9 @@ Template.api.method_invocation_unblock = {
descr: ["Call inside method invocation. Allow subsequent method from this client to begin running in a new fiber."]
};
Template.api.method_invocation_is_simulation = {
id: "method_is_simulation",
name: "<i>this</i>.is_simulation",
Template.api.method_invocation_isSimulation = {
id: "method_issimulation",
name: "<i>this</i>.isSimulation",
locus: "Anywhere",
descr: ["Access inside method invocation. Boolean value, true if this invocation is a stub."]
};
@@ -478,7 +478,7 @@ Template.api.Context = {
id: "context",
name: "new Meteor.deps.Context",
locus: "Client",
descr: ["Create an invalidation context. Invalidation contexts are used to run a piece of code, and record its dependencies so it can be rerun later if one of its inputs changes.", "An invalidation context is basically just a list of callbacks for an event that can fire only once. The [`on_invalidate`](#on_invalidate) method adds a callback to the list, and the [`invalidate`](#invalidate) method fires the event."]
descr: ["Create an invalidation context. Invalidation contexts are used to run a piece of code, and record its dependencies so it can be rerun later if one of its inputs changes.", "An invalidation context is basically just a list of callbacks for an event that can fire only once. The [`onInvalidate`](#oninvalidate) method adds a callback to the list, and the [`invalidate`](#invalidate) method fires the event."]
};
Template.api.run = {
@@ -493,9 +493,9 @@ Template.api.run = {
]
};
Template.api.on_invalidate = {
id: "on_invalidate",
name: "<em>context</em>.on_invalidate(callback)",
Template.api.onInvalidate = {
id: "oninvalidate",
name: "<em>context</em>.onInvalidate(callback)",
locus: "Client",
descr: ["Registers `callback` to be called when this context is invalidated. `callback` will be run exactly once."],
args: [
@@ -509,7 +509,7 @@ Template.api.invalidate = {
id: "invalidate",
name: "<em>context</em>.invalidate()",
locus: "Client",
descr: ["Add this context to the list of contexts that will have their `on_invalidate|on_invalidate` callbacks called by the next call to [`Meteor.flush`](#meteor_flush)."]
descr: ["Add this context to the list of contexts that will have their [`onInvalidate`](#oninvalidate) callbacks called by the next call to [`Meteor.flush`](#meteor_flush)."]
};
Template.api.current = {
@@ -700,7 +700,7 @@ Template.api.set = {
args: [
{name: "key",
type: "String",
descr: "The key to set, eg, `selected_item`"},
descr: "The key to set, eg, `selectedItem`"},
{name: "value",
type: "Any type",
descr: "The new value for `key`"}

View File

@@ -46,7 +46,7 @@ create a nested tree of separate files, or anything in between.
Files outside the `client` and `server`
subdirectories are loaded on both the client and the server! That's
the place for model definitions and other functions. Meteor provides
the variables [`is_client` and `is_server`](#meteor_is_client) so that
the variables [`isClient` and `isServer`](#meteor_isclient) so that
your code can alter its behavior depending on whether it's running
on the client or the server.
@@ -115,8 +115,8 @@ queries and updates.
// server: publish all room documents, and per-room messages
Meteor.publish("chatrooms");
Meteor.publish("messages", function (room_id) {
return Messages.find({room: room_id});
Meteor.publish("messages", function (roomId) {
return Messages.find({room: roomId});
});
// client: subscribe to all rooms, and messages in the first room
@@ -339,15 +339,15 @@ functions in JavaScript. Just add the helper functions directly on the
`Template.[template name]` object. For example, in this template:
<template name="players">
{{dstache}}#each top_scorers}}
{{dstache}}#each topScorers}}
<div>{{dstache}}name}}</div>
{{dstache}}/each}}
</{{! }}template>
instead of passing in `top_scorers` as data when we call the
instead of passing in `topScorers` as data when we call the
template function, we could define a function on `Template.players`:
Template.players.top_scorers = function () {
Template.players.topScorers = function () {
return Users.find({score: {$gt: 100}}, {sort: {score: -1}});
};
@@ -360,28 +360,28 @@ Helpers can take arguments, and they receive the current template data
in `this`:
// in a JavaScript file
Template.players.league_is = function (league) {
Template.players.leagueIs = function (league) {
return this.league === league;
};
<!-- in a HTML file -->
<template name="players">
{{dstache}}#each top_scorers}}
{{dstache}}#if league_is "junior"}}
{{dstache}}#each topScorers}}
{{dstache}}#if leagueIs "junior"}}
<div>Junior: {{dstache}}name}}</div>
{{dstache}}/if}}
{{dstache}}#if league_is "senior"}}
{{dstache}}#if leagueIs "senior"}}
<div>Senior: {{dstache}}name}}</div>
{{dstache}}/if}}
{{dstache}}/each}}
</{{! }}template>
{{#note}}
Handlebars note: `{{dstache}}#if league_is "junior"}}` is
Handlebars note: `{{dstache}}#if leagueIs "junior"}}` is
allowed because of a Meteor extension that allows nesting a helper
in a block helper. (Both `if` and `league_is` are
in a block helper. (Both `if` and `leagueIs` are
technically helpers, and stock Handlebars would not invoke
`league_is` here.)
`leagueIs` here.)
{{/note}}
Helpers can also be used to pass in constant data.
@@ -397,19 +397,19 @@ the data context of the element that triggered the event.
<!-- myapp.html -->
<template name="scores">
{{dstache}}#each player}}
{{dstache}}> player_score}}
{{dstache}}> playerScore}}
{{dstache}}/each}}
</{{! }}template>
<template name="player_score">
<template name="playerScore">
<div>{{dstache}}name}}: {{dstache}}score}}
<span class="give_points">Give points</span>
<span class="givePoints">Give points</span>
</div>
</{{! }}template>
<!-- myapp.js -->
Template.player_score.events({
'click .give_points': function () {
Template.playerScore.events({
'click .givePoints': function () {
Users.update({_id: this._id}, {$inc: {score: 2}});
}
});

View File

@@ -80,8 +80,8 @@ var toc = [
"API", [
"Core", [
"Meteor.is_client",
"Meteor.is_server",
"Meteor.isClient",
"Meteor.isServer",
"Meteor.startup"
],
@@ -100,7 +100,7 @@ var toc = [
{name: "Methods", id: "methods_header"}, [
"Meteor.methods", [
{instance: "this", name: "is_simulation", id: "method_is_simulation"},
{instance: "this", name: "isSimulation", id: "method_issimulation"},
{instance: "this", name: "unblock", id: "method_unblock"}
],
"Meteor.Error",
@@ -177,7 +177,7 @@ var toc = [
"Meteor.deps", [
{name: "Meteor.deps.Context", id: "context"}, [
{instance: "context", name: "run"},
{instance: "context", name: "on_invalidate"},
{instance: "context", name: "onInvalidate", id: "oninvalidate"},
{instance: "context", name: "invalidate"}
],
{name: "Meteor.deps.Context.current", id: "current"},

View File

@@ -1,26 +0,0 @@
<template name="projects">
<div>
{{#markdown}}
# Projects
XXX
<!-- XXX this is not the right place for this! I'm just putting it here
so it is _somewhere_. Move it later. -->
You can use the Meteor.startup() method on the server to run code once all
your javascript as finished loading.
<pre class="prettyprint">
Meteor.startup(function () { do_something_once_all_code_is_loaded() });
</pre>
This only works on the server. On the client, use jQuery.ready() or an
equivalent method.
{{/markdown}}
</div>
</template>

View File

@@ -3,7 +3,7 @@
Players = new Meteor.Collection("players");
if (Meteor.is_client) {
if (Meteor.isClient) {
Template.leaderboard.players = function () {
return Players.find({}, {sort: {score: -1, name: 1}});
};
@@ -31,7 +31,7 @@ if (Meteor.is_client) {
}
// On server startup, create some players if the database is empty.
if (Meteor.is_server) {
if (Meteor.isServer) {
Meteor.startup(function () {
if (Players.find().count() === 0) {
var names = ["Ada Lovelace",

View File

@@ -152,7 +152,7 @@ var autorun = function (f) {
return;
ctx = new Meteor.deps.Context;
ctx.run(f);
ctx.on_invalidate(rerun);
ctx.onInvalidate(rerun);
};
rerun();
return {

View File

@@ -9,7 +9,7 @@ Chat.schema({room: String, message: String,
username: String, created: Number});
*/
if (Meteor.is_server) {
if (Meteor.isServer) {
Meteor.publish('rooms', function () {
return Rooms.find();
});

View File

@@ -1,7 +1,7 @@
Todos = new Meteor.Collection("todos");
//Todos.schema({text: String, done: Boolean, order: Number});
if (Meteor.is_server) {
if (Meteor.isServer) {
Meteor.publish('todos', function () {
return Todos.find();
});

View File

@@ -11,7 +11,7 @@ Todos.schema({text: String,
tags: [String]});
*/
if (Meteor.is_server) {
if (Meteor.isServer) {
Meteor.publish('lists', function () {
return Lists.find();
});

View File

@@ -109,7 +109,7 @@ Meteor.methods({
}
// now only on the server, check against dictionary and score it.
if (Meteor.is_server) {
if (Meteor.isServer) {
if (DICTIONARY.indexOf(word.word.toLowerCase()) === -1) {
Words.update(word._id, {$set: {score: 0, state: 'bad'}});
} else {
@@ -121,7 +121,7 @@ Meteor.methods({
});
if (Meteor.is_server) {
if (Meteor.isServer) {
// publish all the non-idle players.
Meteor.publish('players', function () {
return Players.find({idle: false});

View File

@@ -37,7 +37,7 @@
// calls f immediately if this context was already
// invalidated. receives one argument, the context.
on_invalidate: function (f) {
onInvalidate: function (f) {
if (this._invalidated)
f(this);
else

View File

@@ -3,7 +3,7 @@
// URL prefix for tests to talk to
var _XHR_URL_PREFIX = "/http_test_responder";
var url_prefix = function () {
if (Meteor.is_server && _XHR_URL_PREFIX.indexOf("http") !== 0) {
if (Meteor.isServer && _XHR_URL_PREFIX.indexOf("http") !== 0) {
var address = __meteor_bootstrap__.app.address();
_XHR_URL_PREFIX = "http://127.0.0.1:" + address.port + _XHR_URL_PREFIX;
}
@@ -36,7 +36,7 @@ testAsyncMulti("httpcall - basic", [
Meteor.http.call("GET", url_prefix()+url, options, expect(callback));
if (Meteor.is_server) {
if (Meteor.isServer) {
// test sync version
var result = Meteor.http.call("GET", url_prefix()+url, options);
callback(result.error, result);
@@ -160,7 +160,7 @@ testAsyncMulti("httpcall - redirect", [
}
}));
};
if (Meteor.is_client && ! followRedirects) {
if (Meteor.isClient && ! followRedirects) {
// not supported, should fail
test.throws(do_it);
} else {
@@ -187,7 +187,7 @@ testAsyncMulti("httpcall - methods", [
test.equal(data.url, "/foo");
// IE <= 8 turns seems to turn POSTs with no body into
// GETs, inexplicably.
if (Meteor.is_client && $.browser.msie && $.browser.version <= 8
if (Meteor.isClient && $.browser.msie && $.browser.version <= 8
&& meth === "POST")
meth = "GET";
test.equal(data.method, meth);

View File

@@ -1,6 +1,6 @@
// XXX namespacing
Meteor._MethodInvocation = function (is_simulation, userId,
Meteor._MethodInvocation = function (isSimulation, userId,
globallySetUserId, unblock) {
var self = this;
@@ -8,10 +8,13 @@ Meteor._MethodInvocation = function (is_simulation, userId,
// if we're on a client (which may be a browser, or in the future a
// server connecting to another server) and presently running a
// simulation of a server-side method for latency compensation
// purposes). not current true except in a client such as a browser,
// purposes). not currently true except in a client such as a browser,
// since there's usually no point in running stubs unless you have a
// zero-latency connection to the user.
this.is_simulation = is_simulation;
this.isSimulation = isSimulation;
// XXX Backwards compatibility only. Remove this before 1.0.
this.is_simulation = isSimulation;
// call this function to allow other method invocations (from the
// same client) to continue running without waiting for this one to

View File

@@ -1,4 +1,4 @@
if (Meteor.is_server) {
if (Meteor.isServer) {
// XXX namespacing
var Future = __meteor_bootstrap__.require('fibers/future');
}
@@ -291,7 +291,7 @@ _.extend(Meteor._LivedataConnection.prototype, {
});
}
if (Meteor.is_client) {
if (Meteor.isClient) {
// If on a client, run the stub, if we have one. The stub is
// supposed to make some temporary writes to the database to
// give the user a smooth experience until the actual result of
@@ -310,7 +310,7 @@ _.extend(Meteor._LivedataConnection.prototype, {
self.setUserId(userId);
};
var invocation = new Meteor._MethodInvocation(
true /* is_simulation */, self.userId(), setUserId);
true /* isSimulation */, self.userId(), setUserId);
try {
var ret = Meteor._CurrentInvocation.withValue(invocation,function () {
return stub.apply(invocation, args);
@@ -325,8 +325,8 @@ _.extend(Meteor._LivedataConnection.prototype, {
// rather than going on to do an RPC. If there was no stub,
// we'll end up returning undefined.
var enclosing = Meteor._CurrentInvocation.get();
var is_simulation = enclosing && enclosing.is_simulation;
if (is_simulation) {
var isSimulation = enclosing && enclosing.isSimulation;
if (isSimulation) {
if (callback) {
callback(exception, ret);
return;
@@ -352,7 +352,7 @@ _.extend(Meteor._LivedataConnection.prototype, {
// If the caller didn't give a callback, decide what to do.
if (!callback) {
if (Meteor.is_client)
if (Meteor.isClient)
// On the client, we don't have fibers, so we can't block. The
// only thing we can do is to return undefined and discard the
// result of the RPC.
@@ -782,7 +782,7 @@ _.extend(Meteor, {
var local_subs = [];
var context = new Meteor.deps.Context();
context.on_invalidate(function () {
context.onInvalidate(function () {
// recurse.
Meteor.autosubscribe(sub_func);
// unsub after re-subbing, to avoid bouncing.

View File

@@ -81,6 +81,8 @@ Tinytest.add("livedata stub - this", function (test) {
startAndConnect(test, stream);
conn.methods({test_this: function() {
test.isTrue(this.isSimulation);
// XXX Backwards compatibility only. Remove this before 1.0.
test.isTrue(this.is_simulation);
this.unblock(); // should be a no-op
}});
@@ -568,4 +570,4 @@ Tinytest.add("livedata connection - onReconnect prepends messages correctly with
// - reconnect, with session resume.
// - restart on update flag
// - on_update event
// - reloading when the app changes, including session migration
// - reloading when the app changes, including session migration

View File

@@ -282,7 +282,7 @@ _.extend(Meteor._LivedataSession.prototype, {
};
var invocation = new Meteor._MethodInvocation(
false /* is_simulation */, self.userId, setUserId, unblock);
false /* isSimulation */, self.userId, setUserId, unblock);
try {
var ret =
Meteor._CurrentWriteFence.withValue(fence, function () {
@@ -868,7 +868,7 @@ _.extend(Meteor._LivedataServer.prototype, {
}
var invocation = new Meteor._MethodInvocation(
false /* is_simulation */, userId, setUserId);
false /* isSimulation */, userId, setUserId);
try {
var ret = Meteor._CurrentInvocation.withValue(invocation, function () {
return handler.apply(invocation, args);

View File

@@ -6,8 +6,8 @@ Meteor.methods({
},
exception: function (where, intended) {
var shouldThrow =
(Meteor.is_server && where === "server") ||
(Meteor.is_client && where === "client") ||
(Meteor.isServer && where === "server") ||
(Meteor.isClient && where === "client") ||
where === "both";
if (shouldThrow) {
@@ -63,11 +63,11 @@ Ledger.allow({
});
Meteor.startup(function () {
if (Meteor.is_server)
if (Meteor.isServer)
Ledger.remove({}); // XXX can this please be Ledger.remove()?
});
if (Meteor.is_server)
if (Meteor.isServer)
Meteor.publish('ledger', function (world) {
return Ledger.find({world: world}, {key: {collection: 'ledger',
world: world}});
@@ -78,7 +78,7 @@ Meteor.methods({
var from = Ledger.findOne({name: from_name, world: world});
var to = Ledger.findOne({name: to_name, world: world});
if (Meteor.is_server)
if (Meteor.isServer)
cheat = false;
if (!from)

View File

@@ -41,7 +41,7 @@ Tinytest.add("livedata - methods with colliding names", function (test) {
testAsyncMulti("livedata - basic method invocation", [
// Unknown methods
function (test, expect) {
if (Meteor.is_server) {
if (Meteor.isServer) {
// On server, with no callback, throws exception
try {
var ret = Meteor.call("unknown method");
@@ -53,7 +53,7 @@ testAsyncMulti("livedata - basic method invocation", [
test.equal(ret, undefined);
}
if (Meteor.is_client) {
if (Meteor.isClient) {
// On client, with no callback, just returns undefined
var ret = Meteor.call("unknown method");
test.equal(ret, undefined);
@@ -69,36 +69,36 @@ testAsyncMulti("livedata - basic method invocation", [
// make sure 'undefined' is preserved as such, instead of turning
// into null (JSON does not have 'undefined' so there is special
// code for this)
if (Meteor.is_server)
if (Meteor.isServer)
test.equal(Meteor.call("nothing"), undefined);
if (Meteor.is_client)
if (Meteor.isClient)
test.equal(Meteor.call("nothing"), undefined);
test.equal(Meteor.call("nothing", expect(undefined, undefined)), undefined);
},
function (test, expect) {
if (Meteor.is_server)
if (Meteor.isServer)
test.equal(Meteor.call("echo"), []);
if (Meteor.is_client)
if (Meteor.isClient)
test.equal(Meteor.call("echo"), undefined);
test.equal(Meteor.call("echo", expect(undefined, [])), undefined);
},
function (test, expect) {
if (Meteor.is_server)
if (Meteor.isServer)
test.equal(Meteor.call("echo", 12), [12]);
if (Meteor.is_client)
if (Meteor.isClient)
test.equal(Meteor.call("echo", 12), undefined);
test.equal(Meteor.call("echo", 12, expect(undefined, [12])), undefined);
},
function (test, expect) {
if (Meteor.is_server)
if (Meteor.isServer)
test.equal(Meteor.call("echo", 12, {x: 13}), [12, {x: 13}]);
if (Meteor.is_client)
if (Meteor.isClient)
test.equal(Meteor.call("echo", 12, {x: 13}), undefined);
test.equal(Meteor.call("echo", 12, {x: 13},
@@ -128,7 +128,7 @@ testAsyncMulti("livedata - basic method invocation", [
function (test, expect) {
// No callback
if (Meteor.is_server) {
if (Meteor.isServer) {
test.throws(function () {
Meteor.call("exception", "both");
});
@@ -139,7 +139,7 @@ testAsyncMulti("livedata - basic method invocation", [
test.equal(Meteor.call("exception", "client"), undefined);
}
if (Meteor.is_client) {
if (Meteor.isClient) {
// The client exception is thrown away because it's in the
// stub. The server exception is throw away because we didn't
// give a callback.
@@ -150,7 +150,7 @@ testAsyncMulti("livedata - basic method invocation", [
// With callback
if (Meteor.is_client) {
if (Meteor.isClient) {
test.equal(
Meteor.call("exception", "both",
expect(failure(test, 500, "Internal server error"))),
@@ -162,7 +162,7 @@ testAsyncMulti("livedata - basic method invocation", [
test.equal(Meteor.call("exception", "client"), undefined);
}
if (Meteor.is_server) {
if (Meteor.isServer) {
test.equal(
Meteor.call("exception", "both",
expect(failure(test, "Test method throwing an exception"))),
@@ -176,7 +176,7 @@ testAsyncMulti("livedata - basic method invocation", [
},
function (test, expect) {
if (Meteor.is_server) {
if (Meteor.isServer) {
var threw = false;
try {
Meteor.call("exception", "both", true);
@@ -188,7 +188,7 @@ testAsyncMulti("livedata - basic method invocation", [
test.isTrue(threw);
}
if (Meteor.is_client) {
if (Meteor.isClient) {
test.equal(
Meteor.call("exception", "both", true,
expect(failure(test, 999,
@@ -214,7 +214,7 @@ var checkBalances = function (test, a, b) {
};
var onQuiesce = function (f) {
if (Meteor.is_server)
if (Meteor.isServer)
f();
else
Meteor.default_connection.onQuiesce(f);
@@ -224,7 +224,7 @@ var onQuiesce = function (f) {
// this is a big hack (and XXX pollutes the global test namespace)
testAsyncMulti("livedata - compound methods", [
function (test) {
if (Meteor.is_client)
if (Meteor.isClient)
Meteor.subscribe("ledger", test.runId());
Ledger.insert({name: "alice", balance: 100, world: test.runId()});
@@ -246,7 +246,7 @@ testAsyncMulti("livedata - compound methods", [
Meteor.call('ledger/transfer', test.runId(), "alice", "bob", 100, true,
expect(failure(test, 409)));
if (Meteor.is_client)
if (Meteor.isClient)
// client can fool itself by cheating, but only until the sync
// finishes
checkBalances(test, -10, 160);

View File

@@ -1,4 +1,4 @@
Meteor = {
is_client: true,
is_server: false
isClient: true,
isServer: false
};

View File

@@ -1,4 +1,4 @@
Tinytest.add("environment - client basics", function (test) {
test.isTrue(Meteor.is_client);
test.isFalse(Meteor.is_server);
test.isTrue(Meteor.isClient);
test.isFalse(Meteor.isServer);
});

View File

@@ -1,4 +1,4 @@
Meteor = {
is_client: false,
is_server: true
isClient: false,
isServer: true
};

View File

@@ -1,4 +1,4 @@
Tinytest.add("environment - server basics", function (test) {
test.isFalse(Meteor.is_client);
test.isTrue(Meteor.is_server);
test.isFalse(Meteor.isClient);
test.isTrue(Meteor.isServer);
});

View File

@@ -5,7 +5,7 @@ _.extend(Meteor, {
setTimeout: function (f, duration) {
if (Meteor._CurrentInvocation) {
if (Meteor._CurrentInvocation.get() && Meteor._CurrentInvocation.get().is_simulation)
if (Meteor._CurrentInvocation.get() && Meteor._CurrentInvocation.get().isSimulation)
throw new Error("Can't set timers inside simulations");
var f_with_ci = f;
@@ -20,7 +20,7 @@ _.extend(Meteor, {
setInterval: function (f, duration) {
if (Meteor._CurrentInvocation) {
if (Meteor._CurrentInvocation.get() && Meteor._CurrentInvocation.get().is_simulation)
if (Meteor._CurrentInvocation.get() && Meteor._CurrentInvocation.get().isSimulation)
throw new Error("Can't set timers inside simulations");
var f_with_ci = f;

View File

@@ -258,7 +258,7 @@ LocalCollection.Cursor.prototype._markAsReactive = function (options) {
// recreated. so we might want to let it linger for a little
// while and repurpose it if it comes back. this will save us
// work because we won't have to redo the initial find.
context.on_invalidate(handle.stop);
context.onInvalidate(handle.stop);
}
};

View File

@@ -12,7 +12,7 @@ Meteor.Collection = function (name, manager, driver, preventAutopublish) {
// note: nameless collections never have a manager
manager = name && (manager ||
(Meteor.is_client ?
(Meteor.isClient ?
Meteor.default_connection : Meteor.default_server));
if (!driver) {
@@ -402,7 +402,7 @@ _.each(["insert", "update", "remove"], function (name) {
if (args.length && args[args.length - 1] instanceof Function)
callback = args.pop();
if (Meteor.is_client && !callback) {
if (Meteor.isClient && !callback) {
// Client can't block, so it can't report errors by exception,
// only by callback. If they forget the callback, give them a
// default one that logs the error, so they aren't totally

View File

@@ -14,7 +14,7 @@ testAsyncMulti("mongo-livedata - database failure reporting", [
};
_.each(["insert", "remove", "update"], function (op) {
if (Meteor.is_server) {
if (Meteor.isServer) {
test.throws(function () {
ftc[op]({fail: true});
});
@@ -22,7 +22,7 @@ testAsyncMulti("mongo-livedata - database failure reporting", [
ftc[op]({fail: true}, expect(exception));
}
if (Meteor.is_client) {
if (Meteor.isClient) {
ftc[op]({fail: true}, expect(exception));
// This would log to console in normal operation.
@@ -37,7 +37,7 @@ testAsyncMulti("mongo-livedata - database failure reporting", [
Tinytest.addAsync("mongo-livedata - basics", function (test, onComplete) {
var run = test.runId();
var coll, coll2;
if (Meteor.is_client) {
if (Meteor.isClient) {
coll = new Meteor.Collection(null); // local, unmanaged
coll2 = new Meteor.Collection(null); // local, unmanaged
} else {
@@ -62,7 +62,7 @@ Tinytest.addAsync("mongo-livedata - basics", function (test, onComplete) {
});
var captureObserve = function (f) {
if (Meteor.is_client) {
if (Meteor.isClient) {
f();
} else {
var fence = new Meteor._WriteFence;
@@ -119,7 +119,7 @@ Tinytest.addAsync("mongo-livedata - basics", function (test, onComplete) {
var total = 0;
cur.forEach(function (doc) {
total *= 10;
if (Meteor.is_server) {
if (Meteor.isServer) {
// Verify that the callbacks from forEach run sequentially and that
// forEach waits for them to complete (issue# 321). If they do not run
// sequentially, then the second callback could execute during the first
@@ -173,7 +173,7 @@ Tinytest.addAsync("mongo-livedata - fuzz test", function(test, onComplete) {
var run = test.runId();
var coll;
if (Meteor.is_client) {
if (Meteor.isClient) {
coll = new Meteor.Collection(null); // local, unmanaged
} else {
coll = new Meteor.Collection("livedata_test_collection_"+run);
@@ -219,7 +219,7 @@ Tinytest.addAsync("mongo-livedata - fuzz test", function(test, onComplete) {
};
var finishObserve = function (f) {
if (Meteor.is_client) {
if (Meteor.isClient) {
f();
} else {
var fence = new Meteor._WriteFence;
@@ -238,7 +238,7 @@ Tinytest.addAsync("mongo-livedata - fuzz test", function(test, onComplete) {
var max_counters = _.clone(counters);
finishObserve(function () {
if (Meteor.is_server)
if (Meteor.isServer)
obs._suspendPolling();
// Do a batch of 1-10 operations
@@ -271,7 +271,7 @@ Tinytest.addAsync("mongo-livedata - fuzz test", function(test, onComplete) {
max_counters.remove++;
}
}
if (Meteor.is_server)
if (Meteor.isServer)
obs._resumePolling();
});
@@ -297,14 +297,14 @@ Tinytest.addAsync("mongo-livedata - fuzz test", function(test, onComplete) {
Tinytest.addAsync("mongo-livedata - scribbling", function (test, onComplete) {
var run = test.runId();
var coll;
if (Meteor.is_client) {
if (Meteor.isClient) {
coll = new Meteor.Collection(null); // local, unmanaged
} else {
coll = new Meteor.Collection("livedata_test_collection_"+run);
}
var runInFence = function (f) {
if (Meteor.is_client) {
if (Meteor.isClient) {
f();
} else {
var fence = new Meteor._WriteFence;

View File

@@ -0,0 +1,4 @@
Tinytest.add("past - client", function (test) {
test.isTrue(Meteor.is_client);
test.isFalse(Meteor.is_server);
});

View File

@@ -4,5 +4,14 @@ Package.describe({
});
Package.on_use(function (api) {
api.use('deps');
api.add_files('past.js', ['client', 'server']);
});
Package.on_test(function (api) {
api.use('past');
api.use('tinytest');
api.add_files('client_past_test.js', 'client');
api.add_files('server_past_test.js', 'server');
});

View File

@@ -1,3 +1,8 @@
// for a little while, accept Sky as an alias for Meteor.
// remove this once people have transitioned.
if (typeof Sky === "undefined") Sky = Meteor;
// Old under_score version of camelCase public API names.
Meteor.is_client = Meteor.isClient;
Meteor.is_server = Meteor.isServer;
Meteor.deps.Context.prototype.on_invalidate =
Meteor.deps.Context.prototype.onInvalidate;
// See also the "this.is_simulation" assignment in livedata/livedata_common.js
// and the retry_count and retry_time fields of self.current_status in
// stream/stream_client.js.

View File

@@ -0,0 +1,4 @@
Tinytest.add("past - server", function (test) {
test.isFalse(Meteor.is_client);
test.isTrue(Meteor.is_server);
});

View File

@@ -54,7 +54,7 @@ Session = _.extend({}, {
if (context && !(context.id in self.key_deps[key])) {
self.key_deps[key][context.id] = context;
context.on_invalidate(function () {
context.onInvalidate(function () {
delete self.key_deps[key][context.id];
});
}
@@ -79,7 +79,7 @@ Session = _.extend({}, {
if (!(context.id in self.key_value_deps[key][value])) {
self.key_value_deps[key][value][context.id] = context;
context.on_invalidate(function () {
context.onInvalidate(function () {
delete self.key_value_deps[key][value][context.id];
// clean up [key][value] if it's now empty, so we don't use

View File

@@ -324,7 +324,7 @@ var scheduleOnscreenSetup = function (frag, landmarkRanges) {
};
var ctx = new Meteor.deps.Context;
ctx.on_invalidate(function () {
ctx.onInvalidate(function () {
if (finalized)
return;
@@ -783,10 +783,10 @@ Spark.isolate = function (htmlFunc) {
Spark.renderToRange(range, function () {
return ctx.run(htmlFunc);
});
ctx.on_invalidate(refresh);
ctx.onInvalidate(refresh);
};
ctx.on_invalidate(refresh);
ctx.onInvalidate(refresh);
});
};
@@ -807,7 +807,7 @@ var atFlushTime = function (f) {
if (! atFlushContext) {
atFlushContext = new Meteor.deps.Context;
atFlushContext.on_invalidate(function () {
atFlushContext.onInvalidate(function () {
var f;
while ((f = atFlushQueue.shift())) {
// Since atFlushContext is truthy, if f() calls atFlushTime

View File

@@ -42,7 +42,9 @@ Meteor._Stream = function (url) {
//// Reactive status
self.current_status = {
status: "connecting", connected: false, retry_count: 0
status: "connecting", connected: false, retryCount: 0,
// XXX Backwards compatibility only. Remove this before 1.0.
retry_count: 0
};
self.status_listeners = {}; // context.id -> context
@@ -119,7 +121,7 @@ _.extend(Meteor._Stream.prototype, {
var context = Meteor.deps && Meteor.deps.Context.current;
if (context && !(context.id in self.status_listeners)) {
self.status_listeners[context.id] = context;
context.on_invalidate(function () {
context.onInvalidate(function () {
delete self.status_listeners[context.id];
});
}
@@ -146,7 +148,9 @@ _.extend(Meteor._Stream.prototype, {
if (self.retry_timer)
clearTimeout(self.retry_timer);
self.retry_timer = null;
self.current_status.retry_count -= 1; // don't count manual retries
self.current_status.retryCount -= 1; // don't count manual retries
// XXX Backwards compatibility only. Remove this before 1.0.
self.current_status.retry_count = self.current_status.retryCount;
self._retry_now();
},
@@ -197,7 +201,9 @@ _.extend(Meteor._Stream.prototype, {
// update status
self.current_status.status = "connected";
self.current_status.connected = true;
self.current_status.retry_count = 0;
self.current_status.retryCount = 0;
// XXX Backwards compatibility only. Remove before 1.0.
self.current_status.retry_count = self.current_status.retryCount;
self.status_changed();
// fire resets. This must come after status change so that clients
@@ -275,14 +281,16 @@ _.extend(Meteor._Stream.prototype, {
_retry_later: function () {
var self = this;
var timeout = self._retry_timeout(self.current_status.retry_count);
var timeout = self._retry_timeout(self.current_status.retryCount);
if (self.retry_timer)
clearTimeout(self.retry_timer);
self.retry_timer = setTimeout(_.bind(self._retry_now, self), timeout);
self.current_status.status = "waiting";
self.current_status.connected = false;
self.current_status.retry_time = (new Date()).getTime() + timeout;
self.current_status.retryTime = (new Date()).getTime() + timeout;
// XXX Backwards compatibility only. Remove this before 1.0.
self.current_status.retry_time = self.current_status.retryTime;
self.status_changed();
},
@@ -292,9 +300,13 @@ _.extend(Meteor._Stream.prototype, {
if (self.force_fail)
return;
self.current_status.retry_count += 1;
self.current_status.retryCount += 1;
// XXX Backwards compatibility only. Remove this before 1.0.
self.current_status.retry_count = self.current_status.retryCount;
self.current_status.status = "connecting";
self.current_status.connected = false;
delete self.current_status.retryTime;
// XXX Backwards compatibility only. Remove this before 1.0.
delete self.current_status.retry_time;
self.status_changed();

View File

@@ -4,6 +4,9 @@ Tinytest.add("stream - status", function (test) {
var status = Meteor.status();
test.equal(typeof status, "object");
test.isTrue(status.status);
// Make sure backward-compatiblity names are defined.
test.equal(status.retryCount, status.retry_count);
test.equal(status.retryTime, status.retry_time);
});
testAsyncMulti("stream - reconnect", [

View File

@@ -51,7 +51,7 @@ OnscreenDiv.prototype.kill = function() {
self.div.parentNode.removeChild(self.div);
var cx = new Meteor.deps.Context;
cx.on_invalidate(function() {
cx.onInvalidate(function() {
Spark.finalize(self.div);
});
cx.invalidate();

View File

@@ -27,7 +27,7 @@ ReactiveVar.prototype.get = function() {
if (context && !(context.id in this._deps)) {
this._deps[context.id] = context;
var self = this;
context.on_invalidate(function() {
context.onInvalidate(function() {
delete self._deps[context.id];
});
}

View File

@@ -32,7 +32,7 @@ WrappedFrag.prototype.release = function() {
// Clean up on flush, if hits 0. Wait to decrement
// so no one else cleans it up first.
var cx = new Meteor.deps.Context;
cx.on_invalidate(function() {
cx.onInvalidate(function() {
if (! --frag["_protect"]) {
Spark.finalize(frag);
}

View File

@@ -38,7 +38,7 @@ _.extend(TestCaseResults.prototype, {
var self = this;
if (self.stop_at_offset === 0) {
if (Meteor.is_client) {
if (Meteor.isClient) {
// Only supported on the browser for now..
var now = (+new Date);
debugger;
@@ -351,7 +351,7 @@ _.extend(TestRun.prototype, {
var testGroups = _.values(
_.groupBy(self.manager.ordered_tests,
function(t) {
if (Meteor.is_server)
if (Meteor.isServer)
return "SERVER";
if (t.async)
return "ASYNC";