\n \n '),s=n.t,i=s?s.call(e,"jobs.allowed_failures",{hash:{},contexts:[e],data:t}):m.call(e,"t","jobs.allowed_failures",{hash:{},contexts:[e],data:t}),t.buffer.push(g(i)+'\n \n \n "),r}function a(e,t){var r="",i;return t.buffer.push("\n "),i=n._triageMustache.call(e,"key",{hash:{},contexts:[e],data:t}),t.buffer.push(g(i)+" \n "),r}function f(e,t){var r="",i;return t.buffer.push("\n "),i={},i.contextBinding="job",i=n.view.call(e,"Travis.JobsItemView",{hash:i,inverse:y.noop,fn:y.program(9,l,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n "),r}function l(e,t){var r="",i,s;return t.buffer.push('\n \n \n '),i=n["if"].call(e,"job.id",{hash:{},inverse:y.noop,fn:y.program(10,c,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push('\n \n \n "),s=n.formatDuration,i=s?s.call(e,"duration",{hash:{},contexts:[e],data:t}):m.call(e,"formatDuration","duration",{hash:{},contexts:[e],data:t}),t.buffer.push(g(i)+'\n \n \n "),s=n.formatTime,i=s?s.call(e,"finishedAt",{hash:{},contexts:[e],data:t}):m.call(e,"formatTime","finishedAt",{hash:{},contexts:[e],data:t}),t.buffer.push(g(i)+"\n \n "),i=n.each.call(e,"value","in","configValues",{hash:{},inverse:y.noop,fn:y.program(12,h,t),contexts:[e,e,e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n "),r}function c(e,t){var r="",i;return t.buffer.push("\n "),i=n._triageMustache.call(e,"number",{hash:{},contexts:[e],data:t}),t.buffer.push(g(i)+" \n "),r}function h(e,t){var r="",i;return t.buffer.push("\n "),i=n._triageMustache.call(e,"value",{hash:{},contexts:[e],data:t}),t.buffer.push(g(i)+" \n "),r}function p(e,t){var r="",i,s;return t.buffer.push('\n \n "),r}n=n||Ember.Handlebars.helpers;var d="",v,m=n.helperMissing,g=this.escapeExpression,y=this;return v=n["if"].call(t,"view.jobs.length",{hash:{},inverse:y.noop,fn:y.program(1,s,i),contexts:[t],data:i}),(v||v===0)&&i.buffer.push(v),i.buffer.push("\n\n"),d}),Ember.TEMPLATES["jobs/log"]=Ember.Handlebars.template(function(e,t,n,r,i){function s(e,t){var r="",i,s;return t.buffer.push('\n \n \n Follow logs \n '),s=n.formatLog,i=s?s.call(e,"log.body",{hash:{},contexts:[e],data:t}):l.call(e,"formatLog","log.body",{hash:{},contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push(" \n\n "),i=n["if"].call(e,"sponsor.name",{hash:{},inverse:h.noop,fn:h.program(2,o,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n\n To top \n"),r}function o(e,t){var r="",i,s;return t.buffer.push('\n \n "),r}function u(e,t){t.buffer.push('\n \n Loading \n
\n')}n=n||Ember.Handlebars.helpers;var a="",f,l=n.helperMissing,c=this.escapeExpression,h=this;return f=n._triageMustache.call(t,"view.logSubscriber",{hash:{},contexts:[t],data:i}),i.buffer.push(c(f)+"\n\n"),f=n["if"].call(t,"log.isLoaded",{hash:{},inverse:h.program(4,u,i),fn:h.program(1,s,i),contexts:[t],data:i}),(f||f===0)&&i.buffer.push(f),i.buffer.push("\n\n"),a}),Ember.TEMPLATES["jobs/show"]=Ember.Handlebars.template(function(e,t,n,r,i){function s(e,t){var r="",i;return t.buffer.push("\n "),i=n["if"].call(e,"job.isLoaded",{hash:{},inverse:m.program(11,c,t),fn:m.program(2,o,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n"),r}function o(e,t){var r="",i,s;return t.buffer.push("\n \n
\n \n
Job \n \n \n '),i=n["if"].call(e,"job.id",{hash:{},inverse:m.noop,fn:m.program(3,u,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push('\n \n '),s=n.t,i=s?s.call(e,"jobs.finished_at",{hash:{},contexts:[e],data:t}):v.call(e,"t","jobs.finished_at",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+' \n "),s=n.formatTime,i=s?s.call(e,"job.finishedAt",{hash:{},contexts:[e],data:t}):v.call(e,"formatTime","job.finishedAt",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+" \n "),s=n.t,i=s?s.call(e,"jobs.duration",{hash:{},contexts:[e],data:t}):v.call(e,"t","jobs.duration",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+' \n "),s=n.formatDuration,i=s?s.call(e,"job.duration",{hash:{},contexts:[e],data:t}):v.call(e,"formatDuration","job.duration",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+' \n \n\n \n
'),s=n.t,i=s?s.call(e,"jobs.commit",{hash:{},contexts:[e],data:t}):v.call(e,"t","jobs.commit",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+' \n
"),s=n.formatCommit,i=s?s.call(e,"commit",{hash:{},contexts:[e],data:t}):v.call(e,"formatCommit","commit",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+" \n "),i=n["if"].call(e,"commit.compareUrl",{hash:{},inverse:m.noop,fn:m.program(5,a,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n "),i=n["if"].call(e,"commit.authorName",{hash:{},inverse:m.noop,fn:m.program(7,f,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n "),i=n["if"].call(e,"commit.committerName",{hash:{},inverse:m.noop,fn:m.program(9,l,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n
\n\n "),s=n.t,i=s?s.call(e,"jobs.message",{hash:{},contexts:[e],data:t}):v.call(e,"t","jobs.message",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+' \n '),s=n.formatMessage,i=s?s.call(e,"commit.message",{hash:{},contexts:[e],data:t}):v.call(e,"formatMessage","commit.message",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+" \n "),s=n.t,i=s?s.call(e,"jobs.config",{hash:{},contexts:[e],data:t}):v.call(e,"t","jobs.config",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+' \n '),s=n.formatConfig,i=s?s.call(e,"job.config",{hash:{},contexts:[e],data:t}):v.call(e,"formatConfig","job.config",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+" \n \n\n "),i={},i.contextBinding="job",i=n.view.call(e,"Travis.LogView",{hash:i,contexts:[e],data:t}),t.buffer.push(d(i)+"\n
\n "),r}function u(e,t){var r="",i;return t.buffer.push("\n "),i=n._triageMustache.call(e,"job.number",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+" \n "),r}function a(e,t){var r="",i,s;return t.buffer.push("\n "),s=n.t,i=s?s.call(e,"jobs.compare",{hash:{},contexts:[e],data:t}):v.call(e,"t","jobs.compare",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+' \n "),s=n.pathFrom,i=s?s.call(e,"commit.compareUrl",{hash:{},contexts:[e],data:t}):v.call(e,"pathFrom","commit.compareUrl",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+" \n "),r}function f(e,t){var r="",i,s;return t.buffer.push("\n "),s=n.t,i=s?s.call(e,"jobs.author",{hash:{},contexts:[e],data:t}):v.call(e,"t","jobs.author",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+' \n "),i=n._triageMustache.call(e,"commit.authorName",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+" \n "),r}function l(e,t){var r="",i,s;return t.buffer.push("\n "),s=n.t,i=s?s.call(e,"jobs.committer",{hash:{},contexts:[e],data:t}):v.call(e,"t","jobs.committer",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+' \n "),i=n._triageMustache.call(e,"commit.committerName",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+" \n "),r}function c(e,t){t.buffer.push('\n \n Loading \n
\n ')}n=n||Ember.Handlebars.helpers;var h="",p,d=this.escapeExpression,v=n.helperMissing,m=this;return p=n["with"].call(t,"view",{hash:{},inverse:m.noop,fn:m.program(1,s,i),contexts:[t],data:i}),(p||p===0)&&i.buffer.push(p),i.buffer.push("\n\n"),h}),Ember.TEMPLATES["layouts/home"]=Ember.Handlebars.template(function(e,t,n,r,i){n=n||Ember.Handlebars.helpers;var s="",o,u,a=n.helperMissing,f=this.escapeExpression;return i.buffer.push('\n '),u=n.outlet,o=u?u.call(t,"top",{hash:{},contexts:[t],data:i}):a.call(t,"outlet","top",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+'\n
\n\n\n
\n '),u=n.outlet,o=u?u.call(t,"left",{hash:{},contexts:[t],data:i}):a.call(t,"outlet","left",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+'\n
\n\n
\n '),u=n.outlet,o=u?u.call(t,"main",{hash:{},contexts:[t],data:i}):a.call(t,"outlet","main",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+'\n
\n\n
\n '),u=n.outlet,o=u?u.call(t,"right",{hash:{},contexts:[t],data:i}):a.call(t,"outlet","right",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+"\n
\n
\n\n"),s}),Ember.TEMPLATES["layouts/profile"]=Ember.Handlebars.template(function(e,t,n,r,i){n=n||Ember.Handlebars.helpers;var s="",o,u,a=n.helperMissing,f=this.escapeExpression;return i.buffer.push('\n '),u=n.outlet,o=u?u.call(t,"top",{hash:{},contexts:[t],data:i}):a.call(t,"outlet","top",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+'\n
\n\n\n
\n '),u=n.outlet,o=u?u.call(t,"left",{hash:{},contexts:[t],data:i}):a.call(t,"outlet","left",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+'\n
\n\n
\n '),u=n.outlet,o=u?u.call(t,"main",{hash:{},contexts:[t],data:i}):a.call(t,"outlet","main",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+'\n
\n\n
\n
\n '
-),u=n.t,o=u?u.call(t,"layouts.application.fork_me",{hash:{},contexts:[t],data:i}):a.call(t,"t","layouts.application.fork_me",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+'\n \n\n
\n\n
\n
Getting started? \n
\n Please read our guide .\n It will only take a few minutes :)\n
\n
\n You can find detailled docs on our about site.\n
\n
\n If you need help please don\'t hesitate to join\n #travis on irc.freenode.net\n or our mailinglist .\n
\n
\n
\n
\n\n'),s}),Ember.TEMPLATES["layouts/sidebar"]=Ember.Handlebars.template(function(e,t,n,r,i){n=n||Ember.Handlebars.helpers;var s="",o,u,a=n.helperMissing,f=this.escapeExpression;return i.buffer.push('\n '),u=n.t,o=u?u.call(t,"layouts.application.fork_me",{hash:{},contexts:[t],data:i}):a.call(t,"t","layouts.application.fork_me",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+'\n \n\n\n\n"),o=n.view.call(t,"view.DecksView",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+"\n"),o=n.view.call(t,"view.WorkersView",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+"\n"),o=n.view.call(t,"view.QueuesView",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+"\n"),o=n.view.call(t,"view.LinksView",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+'\n\n\n
'),u=n.t,o=u?u.call(t,"layouts.about.join",{hash:{},contexts:[t],data:i}):a.call(t,"t","layouts.about.join",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+" \n
\n "),u=n.t,o=u?u.call(t,"layouts.about.repository",{hash:{},contexts:[t],data:i}):a.call(t,"t","layouts.about.repository",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+': Github \n '),u=n.t,o=u?u.call(t,"layouts.about.twitter",{hash:{},contexts:[t],data:i}):a.call(t,"t","layouts.about.twitter",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+': @travisci \n '),u=n.t,o=u?u.call(t,"layouts.about.mailing_list",{hash:{},contexts:[t],data:i}):a.call(t,"t","layouts.about.mailing_list",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+': travis-ci \n irc.freenode.net#travis \n \n
\n\n'),s}),Ember.TEMPLATES["layouts/simple"]=Ember.Handlebars.template(function(e,t,n,r,i){n=n||Ember.Handlebars.helpers;var s="",o,u,a=n.helperMissing,f=this.escapeExpression;return i.buffer.push('\n '),u=n.outlet,o=u?u.call(t,"top",{hash:{},contexts:[t],data:i}):a.call(t,"outlet","top",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+'\n
\n\n\n
\n '),u=n.outlet,o=u?u.call(t,"main",{hash:{},contexts:[t],data:i}):a.call(t,"outlet","main",{hash:{},contexts:[t],data:i}),i.buffer.push(f(o)+"\n
\n
\n\n\n"),s}),Ember.TEMPLATES["layouts/top"]=Ember.Handlebars.template(function(e,t,n,r,i){n=n||Ember.Handlebars.helpers;var s="",o,u,a=this.escapeExpression,f=n.helperMissing;return i.buffer.push("\n Travis \n \n\n\n \n Home \n \n \n Stats \n \n \n Blog \n \n \n Docs \n \n \n \n "),u=n.t,o=u?u.call(t,"layouts.top.github_login",{hash:{},contexts:[t],data:i}):f.call(t,"t","layouts.top.github_login",{hash:{},contexts:[t],data:i}),i.buffer.push(a(o)+' \n "),o=n._triageMustache.call(t,"user.name",{hash:{},contexts:[t],data:i}),i.buffer.push(a(o)+' \n Signing in \n
\n \n \n "),u=n.t,o=u?u.call(t,"layouts.top.profile",{hash:{},contexts:[t],data:i}):f.call(t,"t","layouts.top.profile",{hash:{},contexts:[t],data:i}),i.buffer.push(a(o)+' \n \n \n "),u=n.t,o=u?u.call(t,"layouts.top.sign_out",{hash:{},contexts:[t],data:i}):f.call(t,"t","layouts.top.sign_out",{hash:{},contexts:[t],data:i}),i.buffer.push(a(o)+" \n \n \n \n \n\n"),s}),Ember.TEMPLATES["profile/accounts"]=Ember.Handlebars.template(function(e,t,n,r,i){function s(e,t){var r="",i;return t.buffer.push("\n '),i=n._triageMustache.call(e,"view.name",{hash:{},contexts:[e],data:t}),t.buffer.push(f(i)+' \n \n Repositories: \n '),i=n._triageMustache.call(e,"view.content.reposCount",{hash:{},contexts:[e],data:t}),t.buffer.push(f(i)+" \n
\n "),r}n=n||Ember.Handlebars.helpers;var o="",u,a,f=this.escapeExpression,l=this,c=n.helperMissing;return i.buffer.push('\n
\n\n\n\n\n '),u={},u.contentBinding="controller",a=n.collection,u=a?a.call(t,"Travis.AccountsListView",{hash:u,inverse:l.noop,fn:l.program(1,s,i),contexts:[t],data:i}):c.call(t,"collection","Travis.AccountsListView",{hash:u,inverse:l.noop,fn:l.program(1,s,i),contexts:[t],data:i}),(u||u===0)&&i.buffer.push(u),i.buffer.push("\n
\n\n"),o}),Ember.TEMPLATES["profile/show"]=Ember.Handlebars.template(function(e,t,n,r,i){n=n||Ember.Handlebars.helpers;var s="",o,u,a=this.escapeExpression,f=n.helperMissing;return i.buffer.push(""),o=n._triageMustache.call(t,"view.name",{hash:{},contexts:[t],data:i}),i.buffer.push(a(o)+" \n\n"),o=n.view.call(t,"Travis.ProfileTabsView",{hash:{},contexts:[t],data:i}),i.buffer.push(a(o)+'\n\n\n '),u=n.outlet,o=u?u.call(t,"pane",{hash:{},contexts:[t],data:i}):f.call(t,"outlet","pane",{hash:{},contexts:[t],data:i}),i.buffer.push(a(o)+"\n
\n\n\n"),s}),Ember.TEMPLATES["profile/tabs"]=Ember.Handlebars.template(function(e,t,n,r,i){function s(e,t){var r="",i;return t.buffer.push('\n \n \n \n "),r}n=n||Ember.Handlebars.helpers;var o="",u,a=this.escapeExpression,f=this;return i.buffer.push('\n \n \n \n "),u=n["if"].call(t,"view.displayUser",{hash:{},inverse:f.noop,fn:f.program(1,s,i),contexts:[t],data:i}),(u||u===0)&&i.buffer.push(u),i.buffer.push("\n \n\n"),o}),Ember.TEMPLATES["profile/tabs/hooks"]=Ember.Handlebars.template(function(e,t,n,r,i){function s(e,t){var r="",i;return t.buffer.push("\n "),i=n["if"].call(e,"user.isSyncing",{hash:{},inverse:m.program(4,u,t),fn:m.program(2,o,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n"),r}function o(e,t){t.buffer.push('\n \n Please wait while we sync from GitHub \n
\n ')}function u(e,t){var r="",i,s;return t.buffer.push('\n \n Last synchronized from GitHub: '),s=n.formatTime,i=s?s.call(e,"user.syncedAt",{hash:{},contexts:[e],data:t}):v.call(e,"formatTime","user.syncedAt",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+'\n \n Sync now\n \n
\n\n \n '),i=n.each.call(e,"hook","in","hooks",{hash:{},inverse:m.program(7,f,t),fn:m.program(5,a,t),contexts:[e,e,e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n \n "),r}function a(e,t){var r="",i;return t.buffer.push("\n \n '),i=n._triageMustache.call(e,"hook.slug",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+' \n '),i=n._triageMustache.call(e,"hook.description",{hash:{},contexts:[e],data:t}),t.buffer.push(d(i)+'
\n\n \n \n '),r}function f(e,t){t.buffer.push("\n \n You do not seem to have any repositories that we could sync.\n \n ")}function l(e,t){t.buffer.push('\n \n Loading \n
\n')}n=n||Ember.Handlebars.helpers;var c="",h,p,d=this.escapeExpression,v=n.helperMissing,m=this;return i.buffer.push('\n '),p=n.t,h=p?p.call(t,"profiles.show.message.your_repos",{hash:{},contexts:[t],data:i}):v.call(t,"t","profiles.show.message.your_repos",{hash:{},contexts:[t],data:i}),(h||h===0)&&i.buffer.push(h),i.buffer.push("\n
\n\n"),h=n["if"].call(t,"hooks.isLoaded",{hash:{},inverse:m.program(9,l,i),fn:m.program(1,s,i),contexts:[t],data:i}),(h||h===0)&&i.buffer.push(h),i.buffer.push("\n\n\n\n"),c}),Ember.TEMPLATES["profile/tabs/user"]=Ember.Handlebars.template(function(e,t,n,r,i){n=n||Ember.Handlebars.helpers;var s="",o,u,a=this.escapeExpression,f=n.helperMissing;return i.buffer.push(" \n\n\n \n '),u=n.t,o=u?u.call(t,"profiles.show.github",{hash:{},contexts:[t],data:i}):f.call(t,"t","profiles.show.github",{hash:{},contexts:[t],data:i}),i.buffer.push(a(o)+":\n \n \n "),o=n._triageMustache.call(t,"user.login",{hash:{},contexts:[t],data:i}),i.buffer.push(a(o)+" \n \n \n "),u=n.t,o=u?u.call(t,"profiles.show.email",{hash:{},contexts:[t],data:i}):f.call(t,"t","profiles.show.email",{hash:{},contexts:[t],data:i}),i.buffer.push(a(o)+":\n \n \n "),o=n._triageMustache.call(t,"user.email",{hash:{},contexts:[t],data:i}),i.buffer.push(a(o)+"\n \n \n "),u=n.t,o=u?u.call(t,"profiles.show.token",{hash:{},contexts:[t],data:i}):f.call(t,"t","profiles.show.token",{hash:{},contexts:[t],data:i}),i.buffer.push(a(o)+":\n \n \n "),o=n._triageMustache.call(t,"user.token",{hash:{},contexts:[t],data:i}),i.buffer.push(a(o)+"\n \n \n\n\n\n\n\n"),s}),Ember.TEMPLATES["queues/list"]=Ember.Handlebars.template(function(e,t,n,r,i){function s(e,t){var r="",i,s;return t.buffer.push('\n \n '),s=n.t,i=s?s.call(e,"queue",{hash:{},contexts:[e],data:t}):p.call(e,"t","queue",{hash:{},contexts:[e],data:t}),t.buffer.push(c(i)+": "),i=n._triageMustache.call(e,"queue.name",{hash:{},contexts:[e],data:t}),t.buffer.push(c(i)+" \n \n "),i=n.each.call(e,"job","in","queue",{hash:{},inverse:h.program(5,a,t),fn:h.program(2,o,t),contexts:[e,e,e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n \n \n"),r}function o(e,t){var r="",i;return t.buffer.push("\n "),i={},i.jobBinding="job",i=n.view.call(e,"Travis.QueueItemView",{hash:i,inverse:h.noop,fn:h.program(3,u,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n "),r}function u(e,t){var r="",i;return t.buffer.push("\n \n \n '),i=n._triageMustache.call(e,"job.repository.slug",{hash:{},contexts:[e],data:t}),t.buffer.push(c(i)+"\n \n #"),i=n._triageMustache.call(e,"job.number",{hash:{},contexts:[e],data:t}),t.buffer.push(c(i)+"\n \n "),r}function a(e,t){var r="",i,s;return t.buffer.push("\n "),s=n.t,i=s?s.call(e,"no_job",{hash:{},contexts:[e],data:t}):p.call(e,"t","no_job",{hash:{},contexts:[e],data:t}),t.buffer.push(c(i)+"\n "),r}n=n||Ember.Handlebars.helpers;var f="",l,c=this.escapeExpression,h=this,p=n.helperMissing;return i.buffer.push('\n'),l=n.each.call(t,"queue","in","controller",{hash:{},inverse:h.noop,fn:h.program(1,s,i),contexts:[t,t,t],data:i}),(l||l===0)&&i.buffer.push(l),i.buffer.push("\n \n\n"),f}),Ember.TEMPLATES["repos/list"]=Ember.Handlebars.template(function(e,t,n,r,i){function s(e,t){var r="",i;return t.buffer.push("\n "),i=n["with"].call(e,"view.repository",{hash:{},inverse:d.noop,fn:d.program(2,o,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n "),r}function o(e,t){var r="",i,s;return t.buffer.push('\n \n \n '),i=n["if"].call(e,"slug",{hash:{},inverse:d.noop,fn:d.program(3,u,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n
\n "),i=n["if"].call(e,"lastBuildId",{hash:{},inverse:d.noop,fn:d.program(5,a,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push('\n\n \n '),s=n.t,i=s?s.call(e,"repositories.duration",{hash:{},contexts:[e],data:t}):v.call(e,"t","repositories.duration",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+': \n "),s=n.formatDuration,i=s?s.call(e,"lastBuildDuration",{hash:{},contexts:[e],data:t}):v.call(e,"formatDuration","lastBuildDuration",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+' ,\n '),s=n.t,i=s?s.call(e,"repositories.finished_at",{hash:{},contexts:[e],data:t}):v.call(e,"t","repositories.finished_at",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+': \n "),s=n.formatTime,i=s?s.call(e,"lastBuildFinishedAt",{hash:{},contexts:[e],data:t}):v.call(e,"formatTime","lastBuildFinishedAt",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+' \n
\n\n
\n\n '),i=n["if"].call(e,"description",{hash:{},inverse:d.noop,fn:d.program(7,f,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n "),r}function u(e,t){var r="",i;return t.buffer.push("\n '),i=n._triageMustache.call(e,"slug",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+" \n "),r}function a(e,t){var r="",i;return t.buffer.push("\n '),i=n._triageMustache.call(e,"lastBuildNumber",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+" \n "),r}function f(e,t){var r="",i;return t.buffer.push('\n \n
'),i=n._triageMustache.call(e,"description",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+"
\n
\n "),r}n=n||Ember.Handlebars.helpers;var l="",c,h,p=this.escapeExpression,d=this,v=n.helperMissing;return i.buffer.push('\n '),c={},c.valueBinding="controller.search",c=n.view.call(t,"Ember.TextField",{hash:c,contexts:[t],data:i}),i.buffer.push(p(c)+"\n
\n\n"),c=n.view.call(t,"Travis.ReposListTabsView",{hash:{},contexts:[t],data:i}),i.buffer.push(p(c)+"\n\n \n\n\n '),c={},c.contentBinding="controller",h=n.collection,c=h?h.call(t,"Travis.RepositoriesListView",{hash:c,inverse:d.noop,fn:d.program(1,s,i),contexts:[t],data:i}):v.call(t,"collection","Travis.RepositoriesListView",{hash:c,inverse:d.noop,fn:d.program(1,s,i),contexts:[t],data:i}),(c||c===0)&&i.buffer.push(c),i.buffer.push("\n
\n\n"),l}),Ember.TEMPLATES["repos/list/tabs"]=Ember.Handlebars.template(function(e,t,n,r,i){n=n||Ember.Handlebars.helpers;var s="",o,u,a=this.escapeExpression,f=n.helperMissing;return i.buffer.push('\n \n \n \n \n \n \n \n \n \n \n\n\n"),s}),Ember.TEMPLATES["repos/show"]=Ember.Handlebars.template(function(e,t,n,r,i){function s(e,t){var r="",i;return t.buffer.push("\n "),i=n["with"].call(e,"view.repository",{hash:{},inverse:h.noop,fn:h.program(2,o,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n\n "),r}function o(e,t){var r="",i;return t.buffer.push("\n \n\n '),i=n._triageMustache.call(e,"description",{hash:{},contexts:[e],data:t}),t.buffer.push(c(i)+'
\n\n \n \n '),i=n._triageMustache.call(e,"lastBuildLanguage",{hash:{},contexts:[e],data:t}),t.buffer.push(c(i)+'\n \n \n \n "),i=n._triageMustache.call(e,"stats.watchers",{hash:{},contexts:[e],data:t}),t.buffer.push(c(i)+'\n \n \n \n \n "),i=n._triageMustache.call(e,"stats.forks",{hash:{},contexts:[e],data:t}),t.buffer.push(c(i)+"\n \n \n \n\n "),i=n.view.call(e,"Travis.RepoShowTabsView",{hash:{},contexts:[e],data:t}),t.buffer.push(c(i)+"\n "),i=n.view.call(e,"Travis.RepoShowToolsView",{hash:{},contexts:[e],data:t}),t.buffer.push(c(i)+"\n "),r}function u(e,t){t.buffer.push("\n Loading \n ")}n=n||Ember.Handlebars.helpers;var a="",f,l,c=this.escapeExpression,h=this,p=n.helperMissing;return i.buffer.push('\n "),f=n["if"].call(t,"view.repository.isLoaded",{hash:{},inverse:h.program(4,u,i),fn:h.program(1,s,i),contexts:[t],data:i}),(f||f===0)&&i.buffer.push(f),i.buffer.push('\n\n
\n '),l=n.outlet,f=l?l.call(t,"pane",{hash:{},contexts:[t],data:i}):p.call(t,"outlet","pane",{hash:{},contexts:[t],data:i}),i.buffer.push(c(f)+"\n
\n
\n\n\n"),a}),Ember.TEMPLATES["repos/show/tabs"]=Ember.Handlebars.template(function(e,t,n,r,i){function s(e,t){var r="",i,s;return t.buffer.push("\n \n "),s=n.t,i=s?s.call(e,"repositories.tabs.current",{hash:{},contexts:[e],data:t}):d.call(e,"t","repositories.tabs.current",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+"\n \n "),r}function o(e,t){var r="",i,s;return t.buffer.push("\n \n "),s=n.t,i=s?s.call(e,"repositories.tabs.build_history",{hash:{},contexts:[e],data:t}):d.call(e,"t","repositories.tabs.build_history",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+"\n \n "),r}function u(e,t){var r="",i,s;return t.buffer.push("\n \n "),s=n.t,i=s?s.call(e,"repositories.tabs.pull_requests",{hash:{},contexts:[e],data:t}):d.call(e,"t","repositories.tabs.pull_requests",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+"\n \n "),r}function a(e,t){var r="",i,s;return t.buffer.push("\n \n "),s=n.t,i=s?s.call(e,"repositories.tabs.branches",{hash:{},contexts:[e],data:t}):d.call(e,"t","repositories.tabs.branches",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+"\n \n "),r}function f(e,t){var r="",i,s;return t.buffer.push("\n \n "),s=n.t,i=s?s.call(e,"repositories.tabs.build",{hash:{},contexts:[e],data:t}):d.call(e,"t","repositories.tabs.build",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+" #"),i=n._triageMustache.call(e,"view.build.number",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+"\n \n "),r}function l(e,t){var r="",i,s;return t.buffer.push("\n \n "),s=n.t,i=s?s.call(e,"repositories.tabs.job",{hash:{},contexts:[e],data:t}):d.call(e,"t","repositories.tabs.job",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+" #"),i=n._triageMustache.call(e,"view.job.number",{hash:{},contexts:[e],data:t}),t.buffer.push(p(i)+"\n \n "),r}n=n||Ember.Handlebars.helpers;var c="",h,p=this.escapeExpression,d=n.helperMissing,v=this;return i.buffer.push('\n \n \n "),h=n["if"].call(t,"view.repository.slug",{hash:{},inverse:v.noop,fn:v.program(1,s,i),contexts:[t],data:i}),(h||h===0)&&i.buffer.push(h),i.buffer.push('\n \n \n \n \n "),h=n["if"].call(t,"view.repository.slug",{hash:{},inverse:v.noop,fn:v.program(3,o,i),contexts:[t],data:i}),(h||h===0)&&i.buffer.push(h),i.buffer.push('\n \n \n \n \n "),h=n["if"].call(t,"view.repository.slug",{hash:{},inverse:v.noop,fn:v.program(5,u,i),contexts:[t],data:i}),(h||h===0)&&i.buffer.push(h),i.buffer.push('\n \n \n \n \n "),h=n["if"].call(t,"view.repository.slug",{hash:{},inverse:v.noop,fn:v.program(7,a,i),contexts:[t],data:i}),(h||h===0)&&i.buffer.push(h),i.buffer.push('\n \n \n \n \n "),h=n["if"].call(t,"view.build.id",{hash:{},inverse:v.noop,fn:v.program(9,f,i),contexts:[t],data:i}),(h||h===0)&&i.buffer.push(h),i.buffer.push('\n \n \n \n \n "),h=n["if"].call(t,"view.job.id",{hash:{},inverse:v.noop,fn:v.program(11,l,i),contexts:[t],data:i}),(h||h===0)&&i.buffer.push(h),i.buffer.push("\n \n \n \n\n"),c}),Ember.TEMPLATES["repos/show/tools"]=Ember.Handlebars.template(function(e,t,n,r,i){function s(e,t){var r="",i;return t.buffer.push("\n "),i={},i.contentBinding="view.branches",i.selectionBinding="view.branch",i.optionLabelPath="content.commit.branch",i.optionValuePath="content.commit.branch",i=n.view.call(e,"Ember.Select",{hash:i,contexts:[e],data:t}),t.buffer.push(l(i)+"\n "),r}function o(e,t){t.buffer.push('\n \n ')}n=n||Ember.Handlebars.helpers;var u="",a,f,l=this.escapeExpression,c=n.helperMissing,h=this;return i.buffer.push('\n
\n
\n
\n '),f=n.t,a=f?f.call(t,"repositories.branch",{hash:{},contexts:[t],data:i}):c.call(t,"t","repositories.branch",{hash:{},contexts:[t],data:i}),i.buffer.push(l(a)+": \n "),a=n["if"].call(t,"view.branches.isLoaded",{hash:{},inverse:h.program(3,o,i),fn:h.program(1,s,i),contexts:[t],data:i}),(a||a===0)&&i.buffer.push(a),i.buffer.push("\n
\n
\n "),f=n.t,a=f?f.call(t,"repositories.image_url",{hash:{},contexts:[t],data:i}):c.call(t,"t","repositories.image_url",{hash:{},contexts:[t],data:i}),i.buffer.push(l(a)+': \n \n
\n
\n "),f=n.t,a=f?f.call(t,"repositories.markdown",{hash:{},contexts:[t],data:i}):c.call(t,"t","repositories.markdown",{hash:{},contexts:[t],data:i}),i.buffer.push(l(a)+': \n \n
\n
\n "),f=n.t,a=f?f.call(t,"repositories.textile",{hash:{},contexts:[t],data:i}):c.call(t,"t","repositories.textile",{hash:{},contexts:[t],data:i}),i.buffer.push(l(a)+': \n \n
\n
\n "),f=n.t,a=f?f.call(t,"repositories.rdoc",{hash:{},contexts:[t],data:i}):c.call(t,"t","repositories.rdoc",{hash:{},contexts:[t],data:i}),i.buffer.push(l(a)+': \n \n
\n
\n
\n\n"),u}),Ember.TEMPLATES["sponsors/decks"]=Ember.Handlebars.template(function(e,t,n,r,i){function s(e,t){var r="",i;return t.buffer.push("\n "),i=n.each.call(e,"deck",{hash:{},inverse:c.noop,fn:c.program(2,o,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n "),r}function o(e,t){var r="",i;return t.buffer.push("\n \n \n \n \n \n "),r}n=n||Ember.Handlebars.helpers;var u="",a,f,l=this.escapeExpression,c=this,h=n.helperMissing;return i.buffer.push(""),f=n.t,a=f?f.call(t,"layouts.application.sponsers",{hash:{},contexts:[t],data:i}):h.call(t,"t","layouts.application.sponsers",{hash:{},contexts:[t],data:i}),i.buffer.push(l(a)+' \n\n\n\n\n \n '),f=n.t,a=f?f.call(t,"layouts.application.sponsors_link",{hash:{},contexts:[t],data:i}):h.call(t,"t","layouts.application.sponsors_link",{hash:{},contexts:[t],data:i}),(a||a===0)&&i.buffer.push(a),i.buffer.push("\n \n
\n\n"),u}),Ember.TEMPLATES["sponsors/links"]=Ember.Handlebars.template(function(e,t,n,r,i){function s(e,t){var r="",i;return t.buffer.push("\n \n "),i={},i.unescaped="true",i=n._triageMustache.call(e,"link",{hash:i,contexts:[e],data:t
-}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n \n "),r}n=n||Ember.Handlebars.helpers;var o="",u,a,f=n.helperMissing,l=this.escapeExpression,c=this;return i.buffer.push('\n
'),a=n.t,u=a?a.call(t,"layouts.application.sponsers",{hash:{},contexts:[t],data:i}):f.call(t,"t","layouts.application.sponsers",{hash:{},contexts:[t],data:i}),i.buffer.push(l(u)+' \n\n \n\n
\n \n '),a=n.t,u=a?a.call(t,"layouts.application.sponsors_link",{hash:{},contexts:[t],data:i}):f.call(t,"t","layouts.application.sponsors_link",{hash:{},contexts:[t],data:i}),(u||u===0)&&i.buffer.push(u),i.buffer.push("\n \n
\n
\n\n\n"),o}),Ember.TEMPLATES["stats/show"]=Ember.Handlebars.template(function(e,t,n,r,i){n=n||Ember.Handlebars.helpers,i.buffer.push('
\n
\n\n')}),Ember.TEMPLATES["workers/list"]=Ember.Handlebars.template(function(e,t,n,r,i){function s(e,t){var r="",i,s;return t.buffer.push("\n \n "),s=n.t,i=s?s.call(e,"workers",{hash:{},contexts:[e],data:t}):y.call(e,"t","workers",{hash:{},contexts:[e],data:t}),t.buffer.push(m(i)+'\n \n \n \n '),i=n.each.call(e,"group","in","controller.groups",{hash:{},inverse:g.program(11,p,t),fn:g.program(2,o,t),contexts:[e,e,e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n \n"),r}function o(e,t){var r="",i;return t.buffer.push("\n "),i=n.view.call(e,"Travis.WorkersListView",{hash:{},inverse:g.noop,fn:g.program(3,u,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n "),r}function u(e,t){var r="",i;return t.buffer.push('\n \n \n "),i=n._triageMustache.call(e,"group.firstObject.host",{hash:{},contexts:[e],data:t}),t.buffer.push(m(i)+"\n \n \n "),i=n.each.call(e,"worker","in","group",{hash:{},inverse:g.noop,fn:g.program(4,a,t),contexts:[e,e,e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n \n \n "),r}function a(e,t){var r="",i;return t.buffer.push("\n "),i={},i.workerBinding="worker",i=n.view.call(e,"Travis.WorkersItemView",{hash:i,inverse:g.noop,fn:g.program(5,f,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n "),r}function f(e,t){var r="",i;return t.buffer.push('\n \n
\n '),i=n["if"].call(e,"worker.isWorking",{hash:{},inverse:g.program(9,h,t),fn:g.program(6,l,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n \n "),r}function l(e,t){var r="",i;return t.buffer.push("\n "),i=n["if"].call(e,"worker.job_id",{hash:{},inverse:g.noop,fn:g.program(7,c,t),contexts:[e],data:t}),(i||i===0)&&t.buffer.push(i),t.buffer.push("\n "),r}function c(e,t){var r="",i;return t.buffer.push("\n \n "),i=n._triageMustache.call(e,"view.display",{hash:{},contexts:[e],data:t}),t.buffer.push(m(i)+"\n \n "),r}function h(e,t){var r="",i;return t.buffer.push("\n "),i=n._triageMustache.call(e,"view.display",{hash:{},contexts:[e],data:t}),t.buffer.push(m(i)+"\n "),r}function p(e,t){t.buffer.push("\n No workers\n ")}n=n||Ember.Handlebars.helpers;var d="",v,m=this.escapeExpression,g=this,y=n.helperMissing;return v=n.view.call(t,"Travis.WorkersView",{hash:{},inverse:g.noop,fn:g.program(1,s,i),contexts:[t],data:i}),(v||v===0)&&i.buffer.push(v),i.buffer.push("\n\n"),d})}),minispade.register("config/locales",function(){window.I18n=window.I18n||{},window.I18n.translations={ca:{locales:{en:"English",es:"Español",fr:"Français",ja:"日本語",nb:"Norsk Bokmål",nl:"Nederlands",pl:"Polski","pt-BR":"português brasileiro",ru:"Русский"}},en:{errors:{messages:{not_found:"not found",already_confirmed:"was already confirmed",not_locked:"was not locked"}},devise:{failure:{unauthenticated:"You need to sign in or sign up before continuing.",unconfirmed:"You have to confirm your account before continuing.",locked:"Your account is locked.",invalid:"Invalid email or password.",invalid_token:"Invalid authentication token.",timeout:"Your session expired, please sign in again to continue.",inactive:"Your account was not activated yet."},sessions:{signed_in:"Signed in successfully.",signed_out:"Signed out successfully."},passwords:{send_instructions:"You will receive an email with instructions about how to reset your password in a few minutes.",updated:"Your password was changed successfully. You are now signed in."},confirmations:{send_instructions:"You will receive an email with instructions about how to confirm your account in a few minutes.",confirmed:"Your account was successfully confirmed. You are now signed in."},registrations:{signed_up:"You have signed up successfully. If enabled, a confirmation was sent to your e-mail.",updated:"You updated your account successfully.",destroyed:"Bye! Your account was successfully cancelled. We hope to see you again soon."},unlocks:{send_instructions:"You will receive an email with instructions about how to unlock your account in a few minutes.",unlocked:"Your account was successfully unlocked. You are now signed in."},mailer:{confirmation_instructions:{subject:"Confirmation instructions"},reset_password_instructions:{subject:"Reset password instructions"},unlock_instructions:{subject:"Unlock Instructions"}}},datetime:{distance_in_words:{hours_exact:{one:"%{count} hour",other:"%{count} hours"},minutes_exact:{one:"%{count} minute",other:"%{count} minutes"},seconds_exact:{one:"%{count} second",other:"%{count} seconds"}}},workers:"Workers",queue:"Queue",no_job:"There are no jobs",repositories:{branch:"Branch",image_url:"Image URL",markdown:"Markdown",textile:"Textile",rdoc:"RDOC",commit:"Commit",message:"Message",started_at:"Started",duration:"Duration",finished_at:"Finished",tabs:{current:"Current",build_history:"Build History",branches:"Branch Summary",pull_requests:"Pull Requests",build:"Build",job:"Job"}},build:{job:"Job",duration:"Duration",finished_at:"Finished"},jobs:{messages:{sponsored_by:"This test suite was run on a worker box sponsored by"},build_matrix:"Build Matrix",allowed_failures:"Allowed Failures",author:"Author",config:"Config",compare:"Compare",committer:"Committer",branch:"Branch",commit:"Commit",message:"Message",started_at:"Started",duration:"Duration",finished_at:"Finished"},builds:{name:"Build",messages:{sponsored_by:"This test suite was run on a worker box sponsored by"},build_matrix:"Build Matrix",allowed_failures:"Allowed Failures",author:"Author",config:"Config",compare:"Compare",committer:"Committer",branch:"Branch",commit:"Commit",message:"Message",started_at:"Started",duration:"Duration",finished_at:"Finished",show_more:"Show more"},layouts:{top:{home:"Home",blog:"Blog",docs:"Docs",stats:"Stats",github_login:"Sign in with Github",profile:"Profile",sign_out:"Sign Out",admin:"Admin"},application:{fork_me:"Fork me on Github",recent:"Recent",search:"Search",sponsers:"Sponsors",sponsors_link:"See all of our amazing sponsors →",my_repositories:"My Repositories"},about:{alpha:"This stuff is alpha.",messages:{alpha:"Please do not consider this a stable service. We're still far from that! More info here. "},join:"Join us and help!",mailing_list:"Mailing List",repository:"Repository",twitter:"Twitter"},mobile:{author:"Author",build:"Build",build_matrix:"Build Matrix",commit:"Commit",committer:"Committer",compare:"Compare",config:"Config",duration:"Duration",finished_at:"Finished at",job:"Job",log:"Log"}},profiles:{show:{email:"Email",github:"Github",message:{your_repos:" Flick the switches below to turn on the Travis service hook for your projects, then push to GitHub.",config:"how to configure custom build options"},messages:{notice:'To get started, please read our Getting Started guide .\n It will only take a couple of minutes. '},token:"Token",your_repos:"Your Repositories",update:"Update",update_locale:"Update",your_locale:"Your Locale"}},statistics:{index:{count:"Count",repo_growth:"Repository Growth",total_projects:"Total Projects/Repositories",build_count:"Build Count",last_month:"last month",total_builds:"Total Builds"}},locales:{en:"English",es:"Español",fr:"Français",ja:"日本語",nb:"Norsk Bokmål",pl:"Polski",ru:"Русский",nl:"Nederlands","pt-BR":"português brasileiro"}},es:{datetime:{distance_in_words:{hours_exact:{one:"%{count} hora",other:"%{count} horas"},minutes_exact:{one:"%{count} minuto",other:"%{count} minutos"},seconds_exact:{one:"%{count} segundo",other:"%{count} segundos"}}},workers:"Procesos",queue:"Cola",no_job:"No hay trabajos",repositories:{branch:"Rama",image_url:"Imagen URL",markdown:"Markdown",textile:"Textile",rdoc:"RDOC",commit:"Commit",message:"Mensaje",started_at:"Iniciado",duration:"Duración",finished_at:"Finalizado",tabs:{current:"Actual",build_history:"Histórico",branches:"Ramas",build:"Builds",job:"Trabajo"}},build:{job:"Trabajo",duration:"Duración",finished_at:"Finalizado"},jobs:{messages:{sponsored_by:"Esta serie de tests han sido ejecutados en una caja de Proceso patrocinada por"},build_matrix:"Matriz de Builds",allowed_failures:"Fallos Permitidos",author:"Autor",config:"Configuración",compare:"Comparar",committer:"Committer",branch:"Rama",commit:"Commit",message:"Mensaje",started_at:"Iniciado",duration:"Duración",finished_at:"Finalizado",sponsored_by:"Patrocinado por"},builds:{name:"Build",messages:{sponsored_by:"Esta serie de tests han sido ejecutados en una caja de Proceso patrocinada por"},build_matrix:"Matriz de Builds",allowed_failures:"Fallos Permitidos",author:"Autor",config:"Configuración",compare:"Comparar",committer:"Committer",branch:"Rama",commit:"Commit",message:"Mensaje",started_at:"Iniciado",duration:"Duración",finished_at:"Finalizado"},layouts:{top:{home:"Inicio",blog:"Blog",docs:"Documentación",stats:"Estadísticas",github_login:"Iniciar sesión con Github",profile:"Perfil",sign_out:"Desconectar",admin:"Admin"},application:{fork_me:"Hazme un Fork en Github",recent:"Reciente",search:"Buscar",sponsers:"Patrocinadores",sponsors_link:"Ver todos nuestros patrocinadores →",my_repositories:"Mis Repositorios"},about:{alpha:"Esto es alpha.",messages:{alpha:"Por favor no considereis esto un servicio estable. Estamos estamos aún lejos de ello! Más información aquí. "},join:"Únetenos y ayudanos!",mailing_list:"Lista de Correos",repository:"Repositorio",twitter:"Twitter"}},profiles:{show:{email:"Correo electrónico",github:"Github",message:{your_repos:" Activa los interruptores para inicial el Travis service hook para tus proyectos, y haz un Push en GitHub. \n Para probar varias versiones de ruby, mira",config:"como configurar tus propias opciones para el Build"},messages:{notice:'Para comenzar, por favor lee nuestra Guía de Inicio .\n Solo tomará unos pocos minutos. '},token:"Token",your_repos:"Tus repositorios",update:"Actualizar",update_locale:"Actualizar",your_locale:"Tu Idioma"}},statistics:{index:{count:"Número",repo_growth:"Crecimiento de Repositorios",total_projects:"Total de Proyectos/Repositorios",build_count:"Número de Builds",last_month:"mes anterior",total_builds:"Total de Builds"}},locales:{en:"English",es:"Español",fr:"Français",ja:"日本語",nb:"Norsk Bokmål",pl:"Polski",ru:"Русский",nl:"Nederlands","pt-BR":"português brasileiro"}},fr:{datetime:{distance_in_words:{hours_exact:{one:"%{count} heure",other:"%{count} heures"},minutes_exact:{one:"%{count} minute",other:"%{count} minutes"},seconds_exact:{one:"%{count} seconde",other:"%{count} secondes"}}},workers:"Processus",queue:"File",no_job:"Pas de tâches",repositories:{branch:"Branche",image_url:"Image",markdown:"Markdown",textile:"Textile",rdoc:"RDOC",commit:"Commit",message:"Message",started_at:"Commencé",duration:"Durée",finished_at:"Terminé",tabs:{current:"Actuel",build_history:"Historique des tâches",branches:"Résumé des branches",build:"Construction",job:"Tâche"}},build:{job:"Tâche",duration:"Durée",finished_at:"Terminé"},jobs:{messages:{sponsored_by:"Cette série de tests a été exécutée sur une machine sponsorisée par"},build_matrix:"Matrice des versions",allowed_failures:"Échecs autorisés",author:"Auteur",config:"Config",compare:"Comparer",committer:"Committeur",branch:"Branche",commit:"Commit",message:"Message",started_at:"Commencé",duration:"Durée",finished_at:"Terminé",sponsored_by:"Cette série de tests a été exécutée sur une machine sponsorisée par"},builds:{name:"Version",messages:{sponsored_by:"Cette série de tests a été exécutée sur une machine sponsorisée par"},build_matrix:"Matrice des versions",allowed_failures:"Échecs autorisés",author:"Auteur",config:"Config",compare:"Comparer",committer:"Committeur",branch:"Branche",commit:"Commit",message:"Message",started_at:"Commencé",duration:"Durée",finished_at:"Terminé"},layouts:{top:{home:"Accueil",blog:"Blog",docs:"Documentation",stats:"Statistiques",github_login:"Connection Github",profile:"Profil",sign_out:"Déconnection",admin:"Admin"},application:{fork_me:"Faites un Fork sur Github",recent:"Récent",search:"Chercher",sponsers:"Sponsors",sponsors_link:"Voir tous nos extraordinaire sponsors →",my_repositories:"Mes dépôts"},about:{alpha:"Ceci est en alpha.",messages:{alpha:"S'il vous plaît ne considérez pas ce service comme étant stable. Nous sommes loin de ça! Plus d'infos ici. "},join:"Joignez-vous à nous et aidez-nous!",mailing_list:"Liste de distribution",repository:"Dépôt",twitter:"Twitter"},mobile:{author:"Auteur",build:"Version",build_matrix:"Matrice des versions",commit:"Commit",committer:"Committeur",compare:"Comparer",config:"Config",duration:"Durée",finished_at:"Terminé à",job:"Tâche",log:"Journal"}},profiles:{show:{github:"Github",message:{your_repos:"Utilisez les boutons ci-dessous pour activer Travis sur vos projets puis déployez sur GitHub. \nPour tester sur plus de versions de ruby, voir",config:"comment configurer des options de version personnalisées"},messages:{notice:'Pour commencer, veuillez lire notre guide de démarrage .\n Cela ne vous prendra que quelques minutes. '},token:"Jeton",your_repos:"Vos dépôts",email:"Courriel",update:"Modifier",update_locale:"Modifier",your_locale:"Votre langue"}},statistics:{index:{count:"Décompte",repo_growth:"Croissance de dépôt",total_projects:"Total des projets/dépôts",build_count:"Décompte des versions",last_month:"mois dernier",total_builds:"Total des versions"}},admin:{actions:{create:"créer",created:"créé","delete":"supprimer",deleted:"supprimé",update:"mise à jour",updated:"mis à jour"},credentials:{log_out:"Déconnection"},"delete":{confirmation:"Oui, je suis sure",flash_confirmation:"%{name} a été détruit avec succès"},flash:{error:"%{name} n'a pas pu être %{action}",noaction:"Aucune action n'a été entreprise",successful:"%{name} a réussi à %{action}"},history:{name:"Historique",no_activity:"Aucune activité",page_name:"Historique pour %{name}"},list:{add_new:"Ajouter un nouveau",delete_action:"Supprimer",delete_selected:"Supprimer la sélection",edit_action:"Modifier",search:"Rechercher",select:"Sélectionner le %{name} à modifier",select_action:"Sélectionner",show_all:"Montrer tout"},"new":{basic_info:"Information de base",cancel:"Annuler",chosen:"%{name} choisi",chose_all:"Choisir tout",clear_all:"Déselectionner tout",many_chars:"caractères ou moins",one_char:"caractère.",optional:"Optionnel",required:"Requis",save:"Sauvegarder",save_and_add_another:"Sauvegarder et en ajouter un autre",save_and_edit:"Sauvegarder et modifier",select_choice:"Faites vos choix et cliquez"},dashboard:{add_new:"Ajouter un nouveau",last_used:"Dernière utilisation",model_name:"Nom du modèle",modify:"Modification",name:"Tableau de bord",pagename:"Administration du site",records:"Enregistrements",show:"Voir",ago:"plus tôt"}},home:{name:"accueil"},repository:{duration:"Durée"},devise:{confirmations:{confirmed:"Votre compte a été crée avec succès. Vous être maintenant connecté.",send_instructions:"Vous allez recevoir un courriel avec les instructions de confirmation de votre compte dans quelques minutes."},failure:{inactive:"Votre compte n'a pas encore été activé.",invalid:"Adresse courriel ou mot de passe invalide.",invalid_token:"Jeton d'authentification invalide.",locked:"Votre compte est bloqué.",timeout:"Votre session est expirée, veuillez vous reconnecter pour continuer.",unauthenticated:"Vous devez vous connecter ou vous enregistrer afin de continuer",unconfirmed:"Vous devez confirmer votre compte avant de continuer."},mailer:{confirmation_instructions:{subject:"Instructions de confirmations"},reset_password_instructions:{subject:"Instruction de remise à zéro du mot de passe"},unlock_instructions:{subject:"Instruction de débloquage"}},passwords:{send_instructions:"Vous recevrez un courriel avec les instructions de remise à zéro du mot de passe dans quelques minutes.",updated:"Votre mot de passe a été changé avec succès. Vous êtes maintenant connecté."},registrations:{destroyed:"Au revoir! Votre compte a été annulé avec succès. Nous espérons vous revoir bientôt.",signed_up:"Vous êtes enregistré avec succès. Si activé, une confirmation vous a été envoyé par courriel.",updated:"Votre compte a été mis a jour avec succès"},sessions:{signed_in:"Connecté avec succès",signed_out:"Déconnecté avec succès"},unlocks:{send_instructions:"Vous recevrez un courriel contenant les instructions pour débloquer votre compte dans quelques minutes.",unlocked:"Votre compte a été débloqué avec succès."}},errors:{messages:{already_confirmed:"étais déja confirmé",not_found:"n'a pas été trouvé",not_locked:"n'étais pas bloqué"}},locales:{en:"English",es:"Español",ja:"日本語",ru:"Русский",fr:"Français",nb:"Norsk Bokmål",pl:"Polski",nl:"Nederlands","pt-BR":"português brasileiro"}},ja:{workers:"ワーカー",queue:"キュー",no_job:"ジョブはありません",repositories:{branch:"ブランチ",image_url:"画像URL",markdown:".md",textile:".textile",rdoc:".rdoc",commit:"コミット",message:"メッセージ",started_at:"開始時刻",duration:"処理時間",finished_at:"終了時刻",tabs:{current:"最新",build_history:"ビルド履歴",branches:"ブランチまとめ",build:"ビルド",job:"ジョブ"}},build:{job:"ジョブ",duration:"処理時間",finished_at:"終了時刻"},jobs:{messages:{sponsored_by:"このテストは以下のスポンサーの協力で行いました。"},build_matrix:"ビルドマトリクス",allowed_failures:"失敗許容範囲内",author:"制作者",config:"設定",compare:"比較",committer:"コミット者",branch:"ブランチ",commit:"コミット",message:"メッセージ",started_at:"開始時刻",duration:"処理時間",finished_at:"終了時刻"},builds:{name:"ビルド",messages:{sponsored_by:"このテストは以下のスポンサーの協力で行いました。"},build_matrix:"失敗許容範囲外",allowed_failures:"失敗許容範囲内",author:"制作者",config:"設定",compare:"比較",committer:"コミット者",branch:"ブランチ",commit:"コミット",message:"メッセージ",started_at:"開始時刻",duration:"処理時間",finished_at:"終了時刻"},layouts:{about:{alpha:"まだアルファですよ!",join:"参加してみよう!",mailing_list:"メールリスト",messages:{alpha:"Travis-ciは安定したサービスまで後一歩!詳しくはこちら "},repository:"リポジトリ",twitter:"ツイッター"},application:{fork_me:"Githubでフォークしよう",my_repositories:"マイリポジトリ",recent:"最近",search:"検索",sponsers:"スポンサー",sponsors_link:"スポンサーをもっと見る →"},top:{blog:"ブログ",docs:"Travisとは?",github_login:"Githubでログイン",home:"ホーム",profile:"プロフィール",sign_out:"ログアウト",stats:"統計",admin:"管理"},mobile:{author:"制作者",build:"ビルド",build_matrix:"ビルドマトリクス",commit:"コミット",committer:"コミット者",compare:"比較",config:"設定",duration:"処理時間",finished_at:"終了時刻",job:"ジョブ",log:"ログ"}},profiles:{show:{github:"Github",email:"メール",message:{config:"詳細設定",your_repos:"以下のスイッチを設定し、Travis-ciを有効にします。Githubへプッシュしたらビルドは自動的に開始します。複数バーションや細かい設定はこちらへ:"},messages:{notice:'まずはTravisのはじめ方 を参照してください。'},token:"トークン",your_repos:"リポジトリ",update:"更新",update_locale:"更新",your_locale:"言語設定"}},statistics:{index:{build_count:"ビルド数",count:"数",last_month:"先月",repo_growth:"リポジトリ",total_builds:"合計ビルド数",total_projects:"合計リポジトリ"}},locales:{en:"English",es:"Español",fr:"Français",ja:"日本語",nb:"Norsk Bokmål",pl:"Polski",ru:"Русский",nl:"Nederlands","pt-BR":"português brasileiro"}},nb:{admin:{actions:{create:"opprett",created:"opprettet","delete":"slett",deleted:"slettet",update:"oppdater",updated:"oppdatert"},credentials:{log_out:"Logg ut"},dashboard:{add_new:"Legg til ny",ago:"siden",last_used:"Sist brukt",model_name:"Modell",modify:"Rediger",name:"Dashbord",pagename:"Nettstedsadministrasjon",records:"Oppføringer",show:"Vis"},"delete":{confirmation:"Ja, jeg er sikker",flash_confirmation:"%{name} ble slettet"},flash:{error:"%{name} kunne ikke bli %{action}",noaction:"Ingen handlinger ble utført",successful:"%{name} ble %{action}"},history:{name:"Logg",no_activity:"Ingen aktivitet",page_name:"Logg for %{name}"},list:{add_new:"Legg til ny",delete_action:"Slett",delete_selected:"Slett valgte",edit_action:"Rediger",search:"Søk",select:"Velg %{name} for å redigere",select_action:"Velg",show_all:"Vis alle "},"new":{basic_info:"Basisinformasjon",cancel:"Avbryt",chosen:"Valgt %{name}",chose_all:"Velg alle",clear_all:"Fjern alle",many_chars:"eller færre tegn.",one_char:"tegn.",optional:"Valgfri",required:"Påkrevd",save:"Lagre",save_and_add_another:"Lagre og legg til ny",save_and_edit:"Lagre og rediger",select_choice:"Kryss av for dine valg og klikk"}},build:{duration:"Varighet",finished_at:"Fullført",job:"Jobb"},builds:{allowed_failures:"Tillatte feil",author:"Forfatter",branch:"Gren",build_matrix:"Jobbmatrise",commit:"Innsending",committer:"Innsender",compare:"Sammenlign",config:"Oppsett",duration:"Varighet",finished_at:"Fullført",message:"Beskrivelse",messages:{sponsored_by:"Denne testen ble kjørt på en maskin sponset av"},name:"Jobb",started_at:"Startet"},datetime:{distance_in_words:{hours_exact:{one:"%{count} time",other:"%{count} timer"},minutes_exact:{one:"%{count} minutt",other:"%{count} minutter"},seconds_exact:{one:"%{count} sekund",other:"%{count} sekunder"}}},devise:{confirmations:{confirmed:"Din konto er aktivert og du er nå innlogget.",send_instructions:"Om noen få minutter så vil du få en e-post med informasjon om hvordan du bekrefter kontoen din."},failure:{inactive:"Kontoen din har ikke blitt aktivert enda.",invalid:"Ugyldig e-post eller passord.",invalid_token:"Ugyldig autentiseringskode.",locked:"Kontoen din er låst.",timeout:"Du ble logget ut siden på grunn av mangel på aktivitet, vennligst logg inn på nytt.",unauthenticated:"Du må logge inn eller registrere deg for å fortsette.",unconfirmed:"Du må bekrefte kontoen din før du kan fortsette."},mailer:{confirmation_instructions:{subject:"Bekreftelsesinformasjon"},reset_password_instructions:{subject:"Instruksjoner for å få nytt passord"},unlock_instructions:{subject:"Opplåsningsinstruksjoner"}},passwords:{send_instructions:"Om noen få minutter så vil du få en epost med informasjon om hvordan du kan få et nytt passord.",updated:"Passordet ditt ble endret, og du er logget inn."},registrations:{destroyed:"Adjø! Kontoen din ble kansellert. Vi håper vi ser deg igjen snart.",signed_up:"Du er nå registrert.",updated:"Kontoen din ble oppdatert."},sessions:{signed_in:"Du er nå logget inn.",signed_out:"Du er nå logget ut."},unlocks:{send_instructions:"Om noen få minutter så kommer du til å få en e-post med informasjon om hvordan du kan låse opp kontoen din.",unlocked:"Kontoen din ble låst opp, og du er nå logget inn igjen."}},errors:{messages:{already_confirmed:"har allerede blitt bekreftet",not_found:"ikke funnnet",not_locked:"var ikke låst"}},home:{name:"hjem"},jobs:{allowed_failures:"Tillatte feil",author:"Forfatter",branch:"Gren",build_matrix:"Jobbmatrise",commit:"Innsending",committer:"Innsender",compare:"Sammenlign",config:"Oppsett",duration:"Varighet",finished_at:"Fullført",message:"Beskrivelse",messages:{sponsored_by:"Denne testserien ble kjørt på en maskin sponset av"},started_at:"Startet"},layouts:{about:{alpha:"Dette er alfa-greier.",join:"Bli med og hjelp oss!",mailing_list:"E-postliste",messages:{alpha:'Dette er ikke en stabil tjeneste. Vi har fremdeles et stykke igjen! Mer informasjon finner du her .'},repository:"Kodelager",twitter:"Twitter."},application:{fork_me:"Se koden på Github",my_repositories:"Mine kodelagre",recent:"Nylig",search:"Søk",sponsers:"Sponsorer",sponsors_link:"Se alle de flotte sponsorene våre →"},mobile:{author:"Forfatter",build:"Jobb",build_matrix:"Jobbmatrise",commit:"Innsending",committer:"Innsender",compare:"Sammenlign",config:"Oppsett",duration:"Varighet",finished_at:"Fullført",job:"Jobb",log:"Logg"},top:{admin:"Administrator",blog:"Blogg",docs:"Dokumentasjon",github_login:"Logg inn med Github",home:"Hjem",profile:"Profil",sign_out:"Logg ut",stats:"Statistikk"}},no_job:"Ingen jobber finnnes",profiles:{show:{email:"E-post",github:"Github",message:{config:"hvordan sette opp egne jobbinnstillinger",your_repos:"Slå på Travis for prosjektene dine ved å dra i bryterne under, og send koden til Github. \nFor å teste mot flere ruby-versjoner, se dokumentasjonen for"},messages:{notice:'For å komme i gang, vennligst les kom-i-gang-veivisereren vår. Det tar bare et par minutter. '},token:"Kode",update:"Oppdater",update_locale:"Oppdater",your_locale:"Ditt språk",your_repos:"Dine kodelagre"}},queue:"Kø",repositories:{branch:"Gren",commit:"Innsender",duration:"Varighet",finished_at:"Fullført",image_url:"Bilde-URL",markdown:"Markdown",message:"Beskrivelse",rdoc:"RDOC",started_at:"Startet",tabs:{branches:"Grensammendrag",build:"Jobb",build_history:"Jobblogg",current:"Siste",job:"Jobb"},textile:"Textile"},repository:{duration:"Varighet"},statistics:{index:{build_count:"Antall jobber",count:"Antall",last_month:"siste måned",repo_growth:"Vekst i kodelager",total_builds:"Totale jobber",total_projects:"Antall prosjekter/kodelagre"}},workers:"Arbeidere",locales:{en:"English",es:"Español",ja:"日本語",ru:"Русский",fr:"Français",nb:"Norsk Bokmål",pl:"Polski",nl:"Nederlands","pt-BR":"português brasileiro"}},nl:{admin:{actions:{create:"aanmaken",created:"aangemaakt","delete":"verwijderen",deleted:"verwijderd",update:"bijwerken",updated:"bijgewerkt"},credentials:{log_out:"Afmelden"},dashboard:{add_new:"Nieuwe toevoegen",ago:"geleden",last_used:"Laatst gebruikt",model_name:"Model naam",modify:"Wijzigen",pagename:"Site administratie",show:"Laten zien",records:"Gegevens"},"delete":{confirmation:"Ja, ik ben zeker",flash_confirmation:"%{name} is vernietigd"},flash:{error:"%{name} kon niet worden %{action}",noaction:"Er zijn geen acties genomen",successful:"%{name} is %{action}"},history:{name:"Geschiedenis",no_activity:"Geen activiteit",page_name:"Geschiedenis van %{name}"},list:{add_new:"Nieuwe toevoegen",delete_action:"Verwijderen",delete_selected:"Verwijder geselecteerden",edit_action:"Bewerken",search:"Zoeken",select:"Selecteer %{name} om te bewerken",select_action:"Selecteer",show_all:"Laat allen zien"},"new":{basic_info:"Basisinfo",cancel:"Annuleren",chosen:"%{name} gekozen",chose_all:"Kies allen",clear_all:"Deselecteer allen",many_chars:"tekens of minder.",one_char:"teken.",optional:"Optioneel",required:"Vereist",save:"Opslaan",save_and_add_another:"Opslaan en een nieuwe toevoegen",save_and_edit:"Opslaan en bewerken",select_choice:"Selecteer uw keuzes en klik"}},build:{duration:"Duur",finished_at:"Voltooid",job:"Taak"},builds:{allowed_failures:"Toegestane mislukkingen",author:"Auteur",branch:"Tak",build_matrix:"Bouw Matrix",compare:"Vergelijk",config:"Configuratie",duration:"Duur",finished_at:"Voltooid",message:"Bericht",messages:{sponsored_by:"Deze tests zijn gedraaid op een machine gesponsord door"},name:"Bouw",started_at:"Gestart",commit:"Commit",committer:"Committer"},datetime:{distance_in_words:{hours_exact:{one:"%{count} uur",other:"%{count} uren"},minutes_exact:{one:"%{count} minuut",other:"%{count} minuten"},seconds_exact:{one:"%{count} seconde",other:"%{count} seconden"}}},devise:{confirmations:{confirmed:"Uw account is bevestigd. U wordt nu ingelogd.",send_instructions:"Binnen enkele minuten zal u een email ontvangen met instructies om uw account te bevestigen."},failure:{inactive:"Uw account is nog niet geactiveerd.",invalid:"Ongeldig email adres of wachtwoord.",invalid_token:"Ongeldig authenticatie token.",locked:"Uw account is vergrendeld.",timeout:"Uw sessie is verlopen, gelieve opnieuw in te loggen om verder te gaan.",unauthenticated:"U moet inloggen of u registeren voordat u verder gaat.",unconfirmed:"U moet uw account bevestigen voordat u verder gaat."},mailer:{confirmation_instructions:{subject:"Bevestigings-instructies"},reset_password_instructions:{subject:"Wachtwoord herstel instructies"},unlock_instructions:{subject:"Ontgrendel-instructies"}},passwords:{send_instructions:"Binnen enkele minuten zal u een email krijgen met instructies om uw wachtwoord opnieuw in te stellen.",updated:"Uw wachtwoord is veranderd. U wordt nu ingelogd."},registrations:{destroyed:"Dag! Uw account is geannuleerd. We hopen u vlug terug te zien.",signed_up:"Uw registratie is voltooid. Als het ingeschakeld is wordt een bevestiging naar uw email adres verzonden.",updated:"Het bijwerken van uw account is gelukt."},sessions:{signed_in:"Inloggen gelukt.",signed_out:"Uitloggen gelukt."},unlocks:{send_instructions:"Binnen enkele minuten zal u een email krijgen met instructies om uw account te ontgrendelen.",unlocked:"Uw account is ontgrendeld. U wordt nu ingelogd."}},errors:{messages:{already_confirmed:"was al bevestigd",not_found:"niet gevonden",not_locked:"was niet vergrendeld"}},jobs:{allowed_failures:"Toegestane mislukkingen",author:"Auteur",branch:"Tak",build_matrix:"Bouw matrix",compare:"Vergelijk",config:"Configuratie",duration:"Duur",finished_at:"Voltooid",message:"Bericht",messages:{sponsored_by:"Deze testen zijn uitgevoerd op een machine gesponsord door"},started_at:"Gestart",commit:"Commit",committer:"Committer"},layouts:{about:{alpha:"Dit is in alfa-stadium.",join:"Doe met ons mee en help!",mailing_list:"Mailing lijst",messages:{alpha:"Gelieve deze service niet te beschouwen als stabiel. Daar zijn we nog lang niet! Meer info hier. "},repository:"Repository",twitter:"Twitter"},application:{fork_me:"Maak een fork op Github",my_repositories:"Mijn repositories",recent:"Recent",search:"Zoeken",sponsers:"Sponsors",sponsors_link:"Bekijk al onze geweldige sponsors →"},mobile:{author:"Auteur",build:"Bouw",build_matrix:"Bouw matrix",compare:"Vergelijk",config:"Configuratie",duration:"Duur",finished_at:"Voltooid op",job:"Taak",commit:"Commit",committer:"Committer",log:"Logboek"},top:{admin:"Administratie",blog:"Blog",docs:"Documentatie",github_login:"Inloggen met Github",home:"Home",profile:"Profiel",sign_out:"Uitloggen",stats:"Statistieken"}},locales:{en:"English",es:"Español",fr:"Français",ja:"日本語",nb:"Norsk Bokmål",nl:"Nederlands",pl:"Polski",ru:"Русский","pt-BR":"português brasileiro"},no_job:"Er zijn geen taken",profiles:{show:{email:"Email adres",github:"Github",message:{config:"hoe eigen bouw-opties in te stellen",your_repos:"Zet de schakelaars hieronder aan om de Travis hook voor uw projecten te activeren en push daarna naar Github \nOm te testen tegen meerdere rubies, zie"},messages:{notice:'Om te beginnen kunt u onze startersgids lezen.\\n Het zal maar enkele minuten van uw tijd vergen. '},update:"Bijwerken",update_locale:"Bijwerken",your_locale:"Uw taal",your_repos:"Uw repositories",token:"Token"}},queue:"Wachtrij",repositories
-:{branch:"Tak",duration:"Duur",finished_at:"Voltooid",image_url:"Afbeeldings URL",message:"Bericht",started_at:"Gestart",tabs:{branches:"Tak samenvatting",build:"Bouw",build_history:"Bouw geschiedenis",current:"Huidig",job:"Taak"},commit:"Commit",markdown:"Markdown",rdoc:"RDOC",textile:"Textile"},repository:{duration:"Duur"},statistics:{index:{build_count:"Bouw aantal",count:"Aantal",last_month:"voorbije maand",repo_growth:"Repository groei",total_builds:"Bouw totaal",total_projects:"Projecten/Repository totaal"}},workers:"Machines",home:{name:"Hoofdpagina"}},pl:{datetime:{distance_in_words:{hours_exact:{one:"%{count} godzina",other:"%{count} godziny"},minutes_exact:{one:"%{count} minuta",other:"%{count} minuty"},seconds_exact:{one:"%{count} sekunda",other:"%{count} sekundy"}}},workers:"Workers",queue:"Kolejka",no_job:"Brak zadań",repositories:{branch:"Gałąź",image_url:"URL obrazka",markdown:"Markdown",textile:"Textile",rdoc:"RDOC",commit:"Commit",message:"Opis",started_at:"Rozpoczęto",duration:"Czas trwania",finished_at:"Zakończono",tabs:{current:"Aktualny",build_history:"Historia Buildów",branches:"Wszystkie Gałęzie",build:"Build",job:"Zadanie"}},build:{job:"Zadanie",duration:"Czas trwania",finished_at:"Zakończono"},jobs:{messages:{sponsored_by:"Te testy zostały uruchomione na maszynie sponsorowanej przez"},build_matrix:"Macierz Buildów",allowed_failures:"Dopuszczalne Niepowodzenia",author:"Autor",config:"Konfiguracja",compare:"Porównanie",committer:"Committer",branch:"Gałąź",commit:"Commit",message:"Opis",started_at:"Rozpoczęto",duration:"Czas trwania",finished_at:"Zakończono",sponsored_by:"Te testy zostały uruchomione na maszynie sponsorowanej przez"},builds:{name:"Build",messages:{sponsored_by:"Te testy zostały uruchomione na maszynie sponsorowanej przez"},build_matrix:"Macierz Buildów",allowed_failures:"Dopuszczalne Niepowodzenia",author:"Autor",config:"Konfiguracja",compare:"Porównanie",committer:"Komitujący",branch:"Gałąź",commit:"Commit",message:"Opis",started_at:"Rozpoczęto",duration:"Czas trwania",finished_at:"Zakończono"},layouts:{top:{home:"Start",blog:"Blog",docs:"Dokumentacja",stats:"Statystki",github_login:"Zaloguj się przy pomocy Githuba",profile:"Profil",sign_out:"Wyloguj się"},application:{fork_me:"Fork me on Github",recent:"Ostatnie",search:"Wyniki",sponsers:"Sponsorzy",sponsors_link:"Zobacz naszych wszystkich wspaniałych sponsorów →",my_repositories:"Moje repozytoria"},about:{alpha:"To wciąż jest wersja alpha.",messages:{alpha:"Proszę nie traktuj tego jako stabilnej usługi. Wciąż nam wiele do tego brakuje! Więcej informacji znajdziesz tutaj. "},join:"Pomóż i dołącz do nas!",mailing_list:"Lista mailingowa",repository:"Repozytorium",twitter:"Twitter"},mobile:{author:"Autor",build:"Build",build_matrix:"Macierz Buildów",commit:"Commit",committer:"Komitujący",compare:"Porównianie",config:"Konfiguracja",duration:"Czas trwania",finished_at:"Zakończono",job:"Zadanie",log:"Log"}},profiles:{show:{email:"Email",github:"Github",message:{your_repos:" Przesuń suwak poniżej, aby włączyć Travisa, dla twoich projektów, a następnie umieść swój kod na GitHubie. \n Aby testować swój kod przy użyciu wielu wersji Rubiego, zobacz",config:"jak skonfigurować niestandardowe opcje builda"},messages:{notice:'Aby zacząć, przeczytaj nasz Przewodnik .\n Zajmie ci to tylko kilka minut. '},token:"Token",your_repos:"Twoje repozytoria"}},statistics:{index:{count:"Ilość",repo_growth:"Przyrost repozytoriów",total_projects:"Łącznie projektów/repozytoriów",build_count:"Liczba buildów",last_month:"ostatni miesiąc",total_builds:"Łącznie Buildów"}},date:{abbr_day_names:["nie","pon","wto","śro","czw","pią","sob"],abbr_month_names:["sty","lut","mar","kwi","maj","cze","lip","sie","wrz","paź","lis","gru"],day_names:["niedziela","poniedziałek","wtorek","środa","czwartek","piątek","sobota"],formats:{"default":"%d-%m-%Y","long":"%B %d, %Y","short":"%d %b"},month_names:["styczeń","luty","marzec","kwiecień","maj","czerwiec","lipiec","sierpień","wrzesień","październik","listopad","grudzień"],order:["day","month","year"]},errors:{format:"%{attribute} %{message}",messages:{accepted:"musi zostać zaakceptowane",blank:"nie może być puste"}},locales:{en:"English",es:"Español",ja:"日本語",ru:"Русский",fr:"Français",nb:"Norsk Bokmål",pl:"Polski",nl:"Nederlands","pt-BR":"português brasileiro"}},"pt-BR":{admin:{actions:{create:"criar",created:"criado","delete":"deletar",deleted:"deletado",update:"atualizar",updated:"atualizado"},credentials:{log_out:"Deslogar"},dashboard:{add_new:"Adicionar novo",ago:"atrás",last_used:"Última utilização",model_name:"Nome do modelo",modify:"Modificar",name:"Dashboard",pagename:"Administração do site",records:"Registros",show:"Mostrar"},"delete":{confirmation:"Sim, tenho certeza",flash_confirmation:"%{name} foi destruído com sucesso"},flash:{error:"%{name} falhou ao %{action}",noaction:"Nenhuma ação foi tomada",successful:"%{name} foi %{action} com sucesso"},history:{name:"Histórico",no_activity:"Nenhuma Atividade",page_name:"Histórico para %{name}"},list:{add_new:"Adicionar novo",delete_action:"Deletar",delete_selected:"Deletar selecionados",edit_action:"Editar",search:"Buscar",select:"Selecionar %{name} para editar",select_action:"Selecionar",show_all:"Mostrar todos"},"new":{basic_info:"Informações básicas",cancel:"Cancelar",chosen:"Escolhido %{name}",chose_all:"Escolher todos",clear_all:"Limpar todos",many_chars:"caracteres ou menos.",one_char:"caractere.",optional:"Opcional",required:"Requerido",save:"Salvar",save_and_add_another:"Salvar e adicionar outro",save_and_edit:"Salvar e alterar",select_choice:"Selecione e clique"}},build:{duration:"Duração",finished_at:"Concluído em",job:"Trabalho"},builds:{allowed_failures:"Falhas Permitidas",author:"Autor",branch:"Branch",build_matrix:"Matriz de Build",commit:"Commit",committer:"Committer",compare:"Comparar",config:"Config",duration:"Duração",finished_at:"Concluído em",message:"Mensagem",messages:{sponsored_by:"Esta série de testes foi executada em uma caixa de processos patrocinada por"},name:"Build",started_at:"Iniciou em"},datetime:{distance_in_words:{hours_exact:{one:"%{count} hora",other:"%{count} horas"},minutes_exact:{one:"%{count} minuto",other:"%{count} minutos"},seconds_exact:{one:"%{count} segundo",other:"%{count} segundos"}}},devise:{confirmations:{confirmed:"Sua conta foi confirmada com sucesso. Você agora está logado.",send_instructions:"Você receberá um email com instruções de como confirmar sua conta em alguns minutos."},failure:{inactive:"Sua conta ainda não foi ativada.",invalid:"Email ou senha inválidos.",invalid_token:"Token de autenticação inválido.",locked:"Sua conta está trancada.",timeout:"Sua sessão expirou, por favor faça seu login novamente.",unauthenticated:"Você precisa fazer o login ou cadastrar-se antes de continuar.",unconfirmed:"Você precisa confirmar sua conta antes de continuar."},mailer:{confirmation_instructions:{subject:"Instruções de confirmação"},reset_password_instructions:{subject:"Instruções de atualização de senha"},unlock_instructions:{subject:"Instruções de destrancamento"}},passwords:{send_instructions:"Você receberá um email com instruções de como atualizar sua senha em alguns minutos.",updated:"Sua senha foi alterada com sucesso. Você agora está logado."},registrations:{destroyed:"Tchau! Sua conta foi cancelada com sucesso. Esperamos vê-lo novamente em breve!",signed_up:"Você se cadastrou com sucesso. Se ativada, uma confirmação foi enviada para seu email.",updated:"Você atualizou sua conta com sucesso."},sessions:{signed_in:"Logado com sucesso.",signed_out:"Deslogado com sucesso."},unlocks:{send_instructions:"Você receberá um email com instruções de como destrancar sua conta em alguns minutos.",unlocked:"Sua conta foi destrancada com sucesso. Você agora está logado."}},errors:{messages:{already_confirmed:"já foi confirmado",not_found:"não encontrado",not_locked:"não estava trancado"}},home:{name:"home"},jobs:{allowed_failures:"Falhas Permitidas",author:"Autor",branch:"Branch",build_matrix:"Matriz de Build",commit:"Commit",committer:"Committer",compare:"Comparar",config:"Config",duration:"Duração",finished_at:"Concluído em",message:"Mensagem",messages:{sponsored_by:"Esta série de testes foi executada em uma caixa de processos patrocinada por"},started_at:"Iniciou em"},layouts:{about:{alpha:"Isto é um alpha.",join:"Junte-se à nós e ajude!",mailing_list:"Lista de email",messages:{alpha:"Por favor, não considere isto um serviço estável. Estamos muito longe disso! Mais informações aqui. "},repository:"Repositório",twitter:"Twitter"},application:{fork_me:"Faça fork no Github",my_repositories:"Meus Repositórios",recent:"Recentes",search:"Buscar",sponsers:"Patrocinadores",sponsors_link:"Conheça todos os nossos patrocinadores →"},mobile:{author:"Autor",build:"Build",build_matrix:"Matriz de Build",commit:"Commit",committer:"Committer",compare:"Comparar",config:"Config",duration:"Duração",finished_at:"Concluído em",job:"Trabalho",log:"Log"},top:{admin:"Admin",blog:"Blog",docs:"Documentação",github_login:"Logue com o Github",home:"Home",profile:"Perfil",sign_out:"Sair",stats:"Estatísticas"}},locales:{en:"English",es:"Español",fr:"Français",ja:"日本語",nb:"Norsk Bokmål",nl:"Nederlands",pl:"Polski",ru:"Русский","pt-BR":"português brasileiro"},no_job:"Não há trabalhos",profiles:{show:{email:"Email",github:"Github",message:{config:"como configurar opções de build",your_repos:"Use os botões abaixo para ligar ou desligar o hook de serviço do Travis para seus projetos, e então, faça um push para o Github. Para testar com múltiplas versões do Ruby, leia"},messages:{notice:'Para começar, leia nosso Guia de início . Só leva alguns minutinhos. '},token:"Token",update:"Atualizar",update_locale:"Atualizar",your_locale:"Sua língua",your_repos:"Seus Repositórios"}},queue:"Fila",repositories:{branch:"Branch",commit:"Commit",duration:"Duração",finished_at:"Concluído em",image_url:"URL da imagem",markdown:"Markdown",message:"Mensagem",rdoc:"RDOC",started_at:"Iniciou em",tabs:{branches:"Sumário do Branch",build:"Build",build_history:"Histórico de Build",current:"Atual",job:"Trabalho"},textile:"Textile"},repository:{duration:"Duração"},statistics:{index:{build_count:"Número de Builds",count:"Número",last_month:"último mês",repo_growth:"Crescimento de Repositório",total_builds:"Total de Builds",total_projects:"Total de Projetos/Repositórios"}},workers:"Processos"},ru:{admin:{actions:{create:"создать",created:"создано","delete":"удалить",deleted:"удалено",update:"обновить",updated:"обновлено"},credentials:{log_out:"Выход"},dashboard:{add_new:"Добавить",ago:"назад",last_used:"Использовалось в последний раз",model_name:"Имя модели",modify:"Изменить",name:"Панель управления",pagename:"Управление сайтом",records:"Записи",show:"Показать"},"delete":{confirmation:"Да, я уверен",flash_confirmation:"%{name} успешно удалено"},history:{name:"История",no_activity:"Нет активности",page_name:"История %{name}"},list:{add_new:"Добавить",delete_action:"Удалить",delete_selected:"Удалить выбранные",edit_action:"Редактировать",search:"Поиск",select:"Для редактирования выберите %{name}",select_action:"Выбрать",show_all:"Показать все"},"new":{basic_info:"Основная информация",cancel:"Отмена",chosen:"Выбрано %{name}",chose_all:"Выбрать все",clear_all:"Очистить все",one_char:"символ.",optional:"Необязательно",required:"Обязательно",save:"Сохранить",save_and_add_another:"Сохранить и добавить другое",save_and_edit:"Сохранить и продолжить редактирование",select_choice:"Выберите и кликните",many_chars:"символов или меньше."},flash:{error:"%{name} не удалось %{action}",noaction:"Никаких действий не произведено",successful:"%{name} было успешно %{action}"}},build:{duration:"Длительность",finished_at:"Завершен",job:"Задача"},builds:{allowed_failures:"Допустимые неудачи",author:"Автор",branch:"Ветка",build_matrix:"Матрица",commit:"Коммит",committer:"Коммитер",compare:"Дифф",config:"Конфигурация",duration:"Длительность",finished_at:"Завершен",message:"Комментарий",messages:{sponsored_by:"Эта серия тестов была запущена на машине, спонсируемой"},name:"Билд",started_at:"Начало"},datetime:{distance_in_words:{hours_exact:{one:"%{count} час",few:"%{count} часа",many:"%{count} часов",other:"%{count} часа"},minutes_exact:{one:"%{count} минута",few:"%{count} минуты",many:"%{count} минут",other:"%{count} минуты"},seconds_exact:{one:"%{count} секунда",few:"%{count} секунды",many:"%{count} секунд",other:"%{count} секунды"}}},devise:{confirmations:{confirmed:"Ваш аккаунт успешно подтвержден. Приветствуем!",send_instructions:"В течении нескольких минут вы получите электронное письмо с инструкциями для прохождения процедуры подтверждения аккаунта."},failure:{inactive:"Ваш аккаунт еще не активирован.",invalid:"Ошибка в адресе почты или пароле.",invalid_token:"Неправильный токен аутентификации.",locked:"Ваш аккаунт заблокирован.",timeout:"Сессия окончена. Для продолжения работы войдите снова.",unauthenticated:"Вам нужно войти или зарегистрироваться.",unconfirmed:"Вы должны сначала подтвердить свой аккаунт."},mailer:{confirmation_instructions:{subject:"Инструкции для подтверждению аккаунта"},reset_password_instructions:{subject:"Инструкции для сброса пароля"},unlock_instructions:{subject:"Инструкции для разблокирования аккаунта"}},passwords:{send_instructions:"В течении нескольких минут вы получите электронное письмо с инструкциями для сброса пароля.",updated:"Ваш пароль успешно изменен. Приветствуем!"},registrations:{destroyed:"Ваш аккаунт был успешно удален. Живите долго и процветайте!",signed_up:"Вы успешно прошли регистрацию. Инструкции для подтверждения аккаунта отправлены на ваш электронный адрес.",updated:"Аккаунт успешно обновлен."},sessions:{signed_in:"Приветствуем!",signed_out:"Удачи!"},unlocks:{send_instructions:"В течении нескольких минут вы получите электронное письмо с инструкциям для разблокировния аккаунта.",unlocked:"Ваш аккаунт успешно разблокирован. Приветствуем!"}},errors:{messages:{already_confirmed:"уже подтвержден",not_found:"не найден",not_locked:"не заблокирован"}},home:{name:"Главная"},jobs:{allowed_failures:"Допустимые неудачи",author:"Автор",branch:"Ветка",build_matrix:"Матрица",commit:"Коммит",committer:"Коммитер",compare:"Сравнение",config:"Конфигурация",duration:"Длительность",finished_at:"Завершен",message:"Комментарий",messages:{sponsored_by:"Эта серия тестов была запущена на машине спонсируемой"},started_at:"Начало"},layouts:{about:{alpha:"Это альфа-версия",join:"Присоединяйтесь к нам и помогайте!",mailing_list:"Лист рассылки",messages:{alpha:"Пожалуйста, не считайте данный сервис стабильным. Мы еще очень далеки от стабильности! Подробности "},repository:"Репозиторий",twitter:"Twitter"},application:{fork_me:"Fork me on Github",my_repositories:"Мои репозитории",recent:"Недавние",search:"Поиск",sponsers:"Спонсоры",sponsors_link:"Список всех наших замечательных спонсоров →"},mobile:{author:"Автор",build:"Сборка",build_matrix:"Матрица сборок",commit:"Коммит",committer:"Коммитер",compare:"Сравнение",config:"Конфигурация",duration:"Длительность",finished_at:"Завершен",job:"Задача",log:"Журнал"},top:{admin:"Управление",blog:"Блог",docs:"Документация",github_login:"Войти через Github",home:"Главная",profile:"Профиль",sign_out:"Выход",stats:"Статистика"}},no_job:"Очередь пуста",profiles:{show:{email:"Электронная почта",github:"Github",message:{config:"как настроить специальные опции билда",your_repos:"Используйте переключатели, чтобы включить Travis service hook для вашего проекта, а потом отправьте код на GitHub. \nДля тестирования на нескольких версиях Ruby смотрите"},messages:{notice:'Перед началом, пожалуйста, прочтите Руководство для быстрого старта . Это займет всего несколько минут. '},token:"Токен",update:"Обновить",update_locale:"Обновить",your_locale:"Ваш язык",your_repos:"Ваши репозитории"}},queue:"Очередь",repositories:{branch:"Ветка",commit:"Коммит",duration:"Длительность",finished_at:"Завершен",image_url:"URL изображения",markdown:"Markdown",message:"Комментарий",rdoc:"RDOC",started_at:"Начало",tabs:{branches:"Статус веток",build:"Билд",build_history:"История",current:"Текущий",job:"Задача"},textile:"Textile"},repository:{duration:"Длительность"},statistics:{index:{build_count:"Количество билдов",count:"Количество",last_month:"прошлый месяц",repo_growth:"Рост числа репозиториев",total_builds:"Всего билдов",total_projects:"Всего проектов/репозиториев"}},workers:"Машины",locales:{en:"English",es:"Español",ja:"日本語",ru:"Русский",fr:"Français",nb:"Norsk Bokmål",pl:"Polski",nl:"Nederlands","pt-BR":"português brasileiro"}}}}),minispade.register("ext/ember/bound_helper",function(){var e=Ember.View.extend(Ember._Metamorph,{context:null,options:null,property:null,propertyPaths:[],value:Ember.K,valueForRender:function(){var e=this.value(Ember.get(this.context,this.property),this.options);return this.options.escaped&&(e=Handlebars.Utils.escapeExpression(e)),e},render:function(e){e.push(this.valueForRender())},valueDidChange:function(){if(this.morph.isRemoved())return;this.morph.html(this.valueForRender())},didInsertElement:function(){this.valueDidChange()},init:function(){this._super(),Ember.addObserver(this.context,this.property,this,"valueDidChange"),this.get("propertyPaths").forEach(function(e){Ember.addObserver(this.context,this.property+"."+e,this,"valueDidChange")},this)},destroy:function(){Ember.removeObserver(this.context,this.property,this,"valueDidChange"),this.get("propertyPaths").forEach(function(e){this.context.removeObserver(this.property+"."+e,this,"valueDidChange")},this),this._super()}});Ember.registerBoundHelper=function(t,n){var r=Array.prototype.slice.call(arguments,2);Ember.Handlebars.registerHelper(t,function(t,i){var s=i.data,o=s.view,u=this,a=o.createChildView(e,{property:t,propertyPaths:r,context:u,options:i.hash,value:n});o.appendChild(a)})}}),minispade.register("ext/ember/namespace",function(){Em.Namespace.reopen=Em.Namespace.reopenClass});
\ No newline at end of file
diff --git a/public/scripts/min/app.js b/public/scripts/min/app.js
index 06b21d5d..40adecf5 100644
--- a/public/scripts/min/app.js
+++ b/public/scripts/min/app.js
@@ -29619,4 +29619,4 @@ var _require=function(){function c(a,c){document.addEventListener?a.addEventList
++g&&setTimeout(c,0)})}}();
(function(){!window.WebSocket&&window.MozWebSocket&&(window.WebSocket=window.MozWebSocket);if(window.WebSocket)Pusher.Transport=window.WebSocket,Pusher.TransportType="native";var c=(document.location.protocol=="http:"?Pusher.cdn_http:Pusher.cdn_https)+Pusher.VERSION,a=[];window.JSON||a.push(c+"/json2"+Pusher.dependency_suffix+".js");if(!window.WebSocket)window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION=!0,a.push(c+"/flashfallback"+Pusher.dependency_suffix+".js");var b=function(){return window.WebSocket?function(){Pusher.ready()}:
function(){window.WebSocket?(Pusher.Transport=window.WebSocket,Pusher.TransportType="flash",window.WEB_SOCKET_SWF_LOCATION=c+"/WebSocketMain.swf",WebSocket.__addTask(function(){Pusher.ready()}),WebSocket.__initialize()):(Pusher.Transport=null,Pusher.TransportType="none",Pusher.ready())}}(),e=function(a){var b=function(){document.body?a():setTimeout(b,0)};b()},g=function(){e(b)};a.length>0?_require(a,g):g()})();
-;minispade.register('app', "(function() {(function() {\nminispade.require('auth');\nminispade.require('controllers');\nminispade.require('helpers');\nminispade.require('models');\nminispade.require('pusher');\nminispade.require('routes');\nminispade.require('slider');\nminispade.require('store');\nminispade.require('tailing');\nminispade.require('templates');\nminispade.require('views');\nminispade.require('config/locales');\nminispade.require('data/sponsors');\n\n Travis.reopen({\n App: Em.Application.extend({\n autoinit: false,\n currentUserBinding: 'auth.user',\n authStateBinding: 'auth.state',\n init: function() {\n this._super.apply(this, arguments);\n this.store = Travis.Store.create();\n this.store.loadMany(Travis.Sponsor, Travis.SPONSORS);\n this.set('auth', Travis.Auth.create({\n app: this,\n endpoint: Travis.config.api_endpoint\n }));\n this.slider = new Travis.Slider();\n this.pusher = new Travis.Pusher(Travis.config.pusher_key);\n return this.tailing = new Travis.Tailing();\n },\n signIn: function() {\n return this.get('auth').signIn();\n },\n autoSignIn: function() {\n return this.get('auth').autoSignIn();\n },\n signOut: function() {\n this.get('auth').signOut();\n return this.get('router').send('afterSignOut');\n },\n receive: function() {\n return this.store.receive.apply(this.store, arguments);\n },\n toggleSidebar: function() {\n var element;\n $('body').toggleClass('maximized');\n element = $(' ');\n $('#top .profile').append(element);\n Em.run.later((function() {\n return element.remove();\n }), 10);\n element = $(' ');\n $('#repo').append(element);\n return Em.run.later((function() {\n return element.remove();\n }), 10);\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=app");minispade.register('auth', "(function() {(function() {\n\n this.Travis.Auth = Ember.Object.extend({\n iframe: $('').hide(),\n timeout: 5000,\n state: 'signed-out',\n receivingEnd: \"\" + location.protocol + \"//\" + location.host,\n init: function() {\n var _this = this;\n this.iframe.appendTo('body');\n window.addEventListener('message', function(e) {\n return _this.receiveMessage(e);\n });\n return this.loadUser();\n },\n accessToken: (function() {\n return sessionStorage.getItem('travis.token');\n }).property(),\n loadUser: function() {\n var user;\n if (user = sessionStorage.getItem('travis.user')) {\n return this.setData({\n user: JSON.parse(user)\n });\n } else {\n return this.autoSignIn();\n }\n },\n signIn: function() {\n this.set('state', 'signing-in');\n this.trySignIn();\n return Ember.run.later(this, this.checkSignIn.bind(this), this.timeout);\n },\n autoSignIn: function() {\n if (localStorage.getItem('travis.auto_signin')) {\n return this.signIn();\n }\n },\n signOut: function() {\n localStorage.clear();\n sessionStorage.clear();\n return this.setData();\n },\n trySignIn: function() {\n return this.iframe.attr('src', \"\" + this.endpoint + \"/auth/post_message?origin=\" + this.receivingEnd);\n },\n checkSignIn: function() {\n if (this.get('state') === 'signing-in') {\n return this.forceSignIn();\n }\n },\n forceSignIn: function() {\n localStorage.setItem('travis.auto_signin', 'true');\n return window.location = \"\" + this.endpoint + \"/auth/handshake?redirect_uri=\" + location;\n },\n setData: function(data) {\n var router, user, _ref;\n if (typeof data === 'string') {\n data = JSON.parse(data);\n }\n if (data != null ? data.token : void 0) {\n this.storeToken(data.token);\n }\n if (data != null ? data.user : void 0) {\n user = this.storeUser(data.user);\n }\n this.set('state', user ? 'signed-in' : 'signed-out');\n this.set('user', user ? user : void 0);\n if (router = (_ref = Travis.app) != null ? _ref.get('router') : void 0) {\n return router.send('afterSignIn');\n }\n },\n storeToken: function(token) {\n sessionStorage.setItem('travis.token', token);\n return this.notifyPropertyChange('accessToken');\n },\n storeUser: function(user) {\n localStorage.setItem('travis.auto_signin', 'true');\n sessionStorage.setItem('travis.user', JSON.stringify(user));\n this.app.store.load(Travis.User, user);\n user = this.app.store.find(Travis.User, user.id);\n user.get('permissions');\n return user;\n },\n receiveMessage: function(event) {\n if (event.origin === this.expectedOrigin()) {\n this.setData(event.data);\n return console.log(\"signed in as \" + event.data.user.login);\n } else {\n return console.log(\"unexpected message \" + event.origin + \": \" + event.data);\n }\n },\n expectedOrigin: function() {\n if (this.endpoint[0] === '/') {\n return this.receivingEnd;\n } else {\n return this.endpoint;\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=auth");minispade.register('controllers', "(function() {(function() {\nminispade.require('helpers');\nminispade.require('travis/ticker');\n\n Travis.reopen({\n Controller: Em.Controller.extend({\n connectOutlet: function() {\n var view, _connectedOutletViews;\n view = this._super.apply(this, arguments);\n if (view) {\n _connectedOutletViews = Travis.app.get('_connectedOutletViews');\n if (!_connectedOutletViews) {\n _connectedOutletViews = [];\n }\n _connectedOutletViews.pushObject(view);\n Travis.app.set('_connectedOutletViews', _connectedOutletViews);\n }\n return view;\n }\n }),\n TopController: Em.Controller.extend({\n userBinding: 'Travis.app.currentUser'\n }),\n ApplicationController: Em.Controller.extend(),\n MainController: Em.Controller.extend(),\n StatsLayoutController: Em.Controller.extend(),\n ProfileLayoutController: Em.Controller.extend(),\n AuthLayoutController: Em.Controller.extend()\n });\nminispade.require('controllers/accounts');\nminispade.require('controllers/builds');\nminispade.require('controllers/flash');\nminispade.require('controllers/home');\nminispade.require('controllers/profile');\nminispade.require('controllers/repos');\nminispade.require('controllers/repo');\nminispade.require('controllers/sidebar');\nminispade.require('controllers/stats');\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers");minispade.register('controllers/accounts', "(function() {(function() {\n\n Travis.AccountsController = Ember.ArrayController.extend({\n tab: 'accounts',\n init: function() {\n return this._super();\n },\n findByLogin: function(login) {\n return this.find(function(account) {\n return account.get('login') === login;\n });\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/accounts");minispade.register('controllers/builds', "(function() {(function() {\n\n Travis.BuildsController = Em.ArrayController.extend({\n repo: 'parent.repo',\n contentBinding: 'parent.builds'\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/builds");minispade.register('controllers/flash', "(function() {(function() {\n\n Travis.FlashController = Ember.ArrayController.extend({\n init: function() {\n this._super.apply(this, arguments);\n return this.set('content', Ember.A());\n },\n pushObjects: function(objects) {\n Ember.run.later(this, (function() {\n return this.removeObjects(objects);\n }), 10000);\n return this._super(objects);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/flash");minispade.register('controllers/home', "(function() {(function() {\n\n Travis.HomeLayoutController = Travis.Controller.extend();\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/home");minispade.register('controllers/profile', "(function() {(function() {\n\n Travis.ProfileController = Travis.Controller.extend({\n name: 'profile',\n userBinding: 'Travis.app.currentUser',\n accountsBinding: 'Travis.app.router.accountsController',\n account: (function() {\n var account, login;\n login = this.get('params.login') || Travis.app.get('currentUser.login');\n account = this.get('accounts').filter(function(account) {\n if (account.get('login') === login) {\n return account;\n }\n })[0];\n if (account) {\n account.select();\n }\n return account;\n }).property('accounts.length', 'params.login'),\n activate: function(action, params) {\n this.setParams(params || this.get('params'));\n return this[\"view\" + ($.camelize(action))]();\n },\n viewHooks: function() {\n this.connectTab('hooks');\n return this.set('hooks', Travis.Hook.find({\n owner_name: this.get('params.login') || Travis.app.get('currentUser.login')\n }));\n },\n viewUser: function() {\n return this.connectTab('user');\n },\n connectTab: function(tab) {\n var viewClass;\n viewClass = Travis[\"\" + ($.camelize(tab)) + \"View\"];\n this.set('tab', tab);\n return this.connectOutlet({\n outletName: 'pane',\n controller: this,\n viewClass: viewClass\n });\n },\n setParams: function(params) {\n var key, value, _results;\n this.set('params', {});\n _results = [];\n for (key in params) {\n value = params[key];\n _results.push(this.set(\"params.\" + key, params[key]));\n }\n return _results;\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/profile");minispade.register('controllers/repo', "(function() {(function() {\n\n Travis.RepoController = Travis.Controller.extend({\n bindings: [],\n init: function() {\n this._super.apply(this, arguments);\n return Ember.run.later(this.updateTimes.bind(this), Travis.INTERVALS.updateTimes);\n },\n updateTimes: function() {\n var build, builds, jobs;\n if (builds = this.get('builds')) {\n builds.forEach(function(b) {\n return b.updateTimes();\n });\n }\n if (build = this.get('build')) {\n build.updateTimes();\n }\n if (build && (jobs = build.get('jobs'))) {\n jobs.forEach(function(j) {\n return j.updateTimes();\n });\n }\n return Ember.run.later(this.updateTimes.bind(this), Travis.INTERVALS.updateTimes);\n },\n activate: function(action) {\n this._unbind();\n return this[\"view\" + ($.camelize(action))]();\n },\n viewIndex: function() {\n this._bind('repo', 'controllers.reposController.firstObject');\n this._bind('build', 'repo.lastBuild');\n return this.connectTab('current');\n },\n viewCurrent: function() {\n this.connectTab('current');\n return this._bind('build', 'repo.lastBuild');\n },\n viewBuilds: function() {\n this.connectTab('builds');\n return this._bind('builds', 'repo.builds');\n },\n viewPullRequests: function() {\n this.connectTab('pull_requests');\n return this._bind('builds', 'repo.pullRequests');\n },\n viewBranches: function() {\n this.connectTab('branches');\n return this._bind('builds', 'repo.branches');\n },\n viewEvents: function() {\n this.connectTab('events');\n return this._bind('events', 'repo.events');\n },\n viewBuild: function() {\n return this.connectTab('build');\n },\n viewJob: function() {\n this._bind('build', 'job.build');\n return this.connectTab('job');\n },\n repoObserver: (function() {\n var repo;\n repo = this.get('repo');\n if (repo) {\n return repo.select();\n }\n }).observes('repo.id'),\n connectTab: function(tab) {\n var name, viewClass;\n name = tab === 'current' ? 'build' : tab;\n viewClass = name === 'builds' || name === 'branches' || name === 'pull_requests' ? Travis.BuildsView : Travis[\"\" + ($.camelize(name)) + \"View\"];\n this.set('tab', tab);\n return this.connectOutlet({\n outletName: 'pane',\n controller: this,\n viewClass: viewClass\n });\n },\n _bind: function(to, from) {\n return this.bindings.push(Ember.oneWay(this, to, from));\n },\n _unbind: function() {\n var binding, _i, _len, _ref;\n _ref = this.bindings;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n binding = _ref[_i];\n binding.disconnect(this);\n }\n return this.bindings.length = 0;\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/repo");minispade.register('controllers/repos', "(function() {(function() {\nminispade.require('travis/limited_array');\n\n Travis.ReposController = Ember.ArrayController.extend({\n defaultTab: 'recent',\n sortProperties: ['sortOrder'],\n init: function() {\n this.activate(this.defaultTab);\n return Ember.run.later(this.updateTimes.bind(this), Travis.INTERVALS.updateTimes);\n },\n updateTimes: function() {\n var content;\n if (content = this.get('content')) {\n content.forEach(function(r) {\n return r.updateTimes();\n });\n }\n return Ember.run.later(this.updateTimes.bind(this), Travis.INTERVALS.updateTimes);\n },\n activate: function(tab, params) {\n this.set('tab', tab);\n return this[\"view\" + ($.camelize(tab))](params);\n },\n viewRecent: function() {\n var content;\n content = Travis.LimitedArray.create({\n content: Travis.Repo.find(),\n limit: 30\n });\n return this.set('content', content);\n },\n viewOwned: function() {\n return this.set('content', Travis.Repo.accessibleBy(Travis.app.get('currentUser.login')));\n },\n viewSearch: function(params) {\n return this.set('content', Travis.Repo.search(params.search));\n },\n searchObserver: (function() {\n var search;\n search = this.get('search');\n if (search) {\n return this.searchFor(search);\n } else {\n this.activate('recent');\n return 'recent';\n }\n }).observes('search'),\n searchFor: function(phrase) {\n if (this.searchLater) {\n Ember.run.cancel(this.searchLater);\n }\n return this.searchLater = Ember.run.later(this, (function() {\n return this.activate('search', {\n search: phrase\n });\n }), 500);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/repos");minispade.register('controllers/sidebar', "(function() {(function() {\n\n Travis.reopen({\n SidebarController: Em.ArrayController.extend({\n init: function() {\n this.tickables = [];\n return Travis.Ticker.create({\n target: this,\n interval: Travis.INTERVALS.sponsors\n });\n },\n tick: function() {\n var tickable, _i, _len, _ref, _results;\n _ref = this.tickables;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n tickable = _ref[_i];\n _results.push(tickable.tick());\n }\n return _results;\n }\n }),\n QueuesController: Em.ArrayController.extend(),\n WorkersController: Em.ArrayController.extend({\n groups: (function() {\n var content, groups, host, worker, _i, _len, _ref;\n if (content = this.get('arrangedContent')) {\n groups = {};\n _ref = content.toArray();\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n worker = _ref[_i];\n host = worker.get('host');\n if (!groups[host]) {\n groups[host] = Em.ArrayProxy.create(Em.SortableMixin, {\n content: [],\n sortProperties: ['nameForSort']\n });\n }\n groups[host].addObject(worker);\n }\n return $.values(groups);\n }\n }).property('length')\n }),\n SponsorsController: Em.ArrayController.extend({\n page: 0,\n arrangedContent: (function() {\n return this.get('shuffled').slice(this.start(), this.end());\n }).property('shuffled.length', 'page'),\n shuffled: (function() {\n var content;\n if (content = this.get('content')) {\n return $.shuffle(content);\n } else {\n return [];\n }\n }).property('content.length'),\n tick: function() {\n return this.set('page', this.isLast() ? 0 : this.get('page') + 1);\n },\n pages: (function() {\n var length;\n length = this.get('content.length');\n if (length) {\n return parseInt(length / this.get('perPage') + 1);\n } else {\n return 1;\n }\n }).property('length'),\n isLast: function() {\n return this.get('page') === this.get('pages') - 1;\n },\n start: function() {\n return this.get('page') * this.get('perPage');\n },\n end: function() {\n return this.start() + this.get('perPage');\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/sidebar");minispade.register('controllers/stats', "(function() {(function() {\n\n Travis.StatsController = Travis.Controller.extend({\n name: 'stats',\n init: function() {\n return this._super('top');\n },\n activate: function(action, params) {}\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/stats");minispade.register('helpers', "(function() {(function() {\nminispade.require('helpers/handlebars');\nminispade.require('helpers/helpers');\nminispade.require('helpers/urls');\n\n}).call(this);\n\n})();\n//@ sourceURL=helpers");minispade.register('helpers/handlebars', "(function() {(function() {\n var safe;\nminispade.require('ext/ember/bound_helper');\n\n safe = function(string) {\n return new Handlebars.SafeString(string);\n };\n\n Handlebars.registerHelper('tipsy', function(text, tip) {\n return safe('' + text + ' ');\n });\n\n Handlebars.registerHelper('t', function(key) {\n return safe(I18n.t(key));\n });\n\n Ember.registerBoundHelper('formatTime', function(value, options) {\n return safe(Travis.Helpers.timeAgoInWords(value) || '-');\n });\n\n Ember.registerBoundHelper('formatDuration', function(duration, options) {\n return safe(Travis.Helpers.timeInWords(duration));\n });\n\n Ember.registerBoundHelper('formatCommit', function(commit, options) {\n if (commit) {\n return safe(Travis.Helpers.formatCommit(commit.get('sha'), commit.get('branch')));\n }\n });\n\n Ember.registerBoundHelper('formatSha', function(sha, options) {\n return safe(Travis.Helpers.formatSha(sha));\n });\n\n Ember.registerBoundHelper('pathFrom', function(url, options) {\n return safe(Travis.Helpers.pathFrom(url));\n });\n\n Ember.registerBoundHelper('formatMessage', function(message, options) {\n return safe(Travis.Helpers.formatMessage(message, options));\n });\n\n Ember.registerBoundHelper('formatConfig', function(config, options) {\n return safe(Travis.Helpers.formatConfig(config));\n });\n\n Ember.registerBoundHelper('formatLog', function(log, options) {\n var item, parentView, repo;\n parentView = this.get('parentView');\n repo = parentView.get(options.repo);\n item = parentView.get(options.item);\n return Travis.Helpers.formatLog(log, repo, item) || '';\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=helpers/handlebars");minispade.register('helpers/helpers', "(function() {(function() {\nminispade.require('travis/log');\nminispade.require('config/emoij');\n\n this.Travis.Helpers = {\n compact: function(object) {\n var key, result, value, _ref;\n result = {};\n _ref = object || {};\n for (key in _ref) {\n value = _ref[key];\n if (!$.isEmpty(value)) {\n result[key] = value;\n }\n }\n return result;\n },\n safe: function(string) {\n return new Handlebars.SafeString(string);\n },\n colorForResult: function(result) {\n if (result === 0) {\n return 'green';\n } else {\n if (result === 1) {\n return 'red';\n } else {\n return null;\n }\n }\n },\n formatCommit: function(sha, branch) {\n return Travis.Helpers.formatSha(sha) + (branch ? \" (\" + branch + \")\" : '');\n },\n formatSha: function(sha) {\n return (sha || '').substr(0, 7);\n },\n formatConfig: function(config) {\n var values;\n config = $.only(config, 'rvm', 'gemfile', 'env', 'otp_release', 'php', 'node_js', 'scala', 'jdk', 'python', 'perl');\n values = $.map(config, function(value, key) {\n value = (value && value.join ? value.join(', ') : value) || '';\n return '%@: %@'.fmt($.camelize(key), value);\n });\n if (values.length === 0) {\n return '-';\n } else {\n return values.join(', ');\n }\n },\n formatMessage: function(message, options) {\n message = message || '';\n if (options.short) {\n message = message.split(/\\n/)[0];\n }\n return this._emojize(this._escape(message)).replace(/\\n/g, ' ');\n },\n formatLog: function(log, repo, item) {\n var event, url;\n event = item.constructor === Travis.Build ? 'showBuild' : 'showJob';\n url = Travis.app.get('router').urlForEvent(event, repo, item);\n return Travis.Log.filter(log, url);\n },\n pathFrom: function(url) {\n return (url || '').split('/').pop();\n },\n timeAgoInWords: function(date) {\n return $.timeago.distanceInWords(date);\n },\n durationFrom: function(started, finished) {\n started = started && this._toUtc(new Date(this._normalizeDateString(started)));\n finished = finished ? this._toUtc(new Date(this._normalizeDateString(finished))) : this._nowUtc();\n if (started && finished) {\n return Math.round((finished - started) / 1000);\n } else {\n return 0;\n }\n },\n timeInWords: function(duration) {\n var days, hours, minutes, result, seconds;\n days = Math.floor(duration / 86400);\n hours = Math.floor(duration % 86400 / 3600);\n minutes = Math.floor(duration % 3600 / 60);\n seconds = duration % 60;\n if (days > 0) {\n return 'more than 24 hrs';\n } else {\n result = [];\n if (hours === 1) {\n result.push(hours + ' hr');\n }\n if (hours > 1) {\n result.push(hours + ' hrs');\n }\n if (minutes > 0) {\n result.push(minutes + ' min');\n }\n if (seconds > 0) {\n result.push(seconds + ' sec');\n }\n if (result.length > 0) {\n return result.join(' ');\n } else {\n return '-';\n }\n }\n },\n _normalizeDateString: function(string) {\n if (window.JHW) {\n string = string.replace('T', ' ').replace(/-/g, '/');\n string = string.replace('Z', '').replace(/\\..*$/, '');\n }\n return string;\n },\n _nowUtc: function() {\n return this._toUtc(new Date());\n },\n _toUtc: function(date) {\n return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());\n },\n _emojize: function(text) {\n var emojis;\n emojis = text.match(/:\\S+?:/g);\n if (emojis !== null) {\n $.each(emojis.uniq(), function(ix, emoji) {\n var image, strippedEmoji;\n strippedEmoji = emoji.substring(1, emoji.length - 1);\n if (EmojiDictionary.indexOf(strippedEmoji) !== -1) {\n image = ' ';\n return text = text.replace(new RegExp(emoji, 'g'), image);\n }\n });\n }\n return text;\n },\n _escape: function(text) {\n return text.replace(/&/g, '&').replace(//g, '>');\n }\n };\n\n}).call(this);\n\n})();\n//@ sourceURL=helpers/helpers");minispade.register('helpers/urls', "(function() {(function() {\n\n this.Travis.Urls = {\n repo: function(slug) {\n return \"/\" + slug;\n },\n builds: function(slug) {\n return \"/\" + slug + \"/builds\";\n },\n pullRequests: function(slug) {\n return \"/\" + slug + \"/pull_requests\";\n },\n branches: function(slug) {\n return \"/\" + slug + \"/branches\";\n },\n build: function(slug, id) {\n return \"/\" + slug + \"/builds/\" + id;\n },\n job: function(slug, id) {\n return \"/\" + slug + \"/jobs/\" + id;\n },\n githubCommit: function(slug, sha) {\n return \"http://github.com/\" + slug + \"/commit/\" + sha;\n },\n githubRepo: function(slug) {\n return \"http://github.com/\" + slug;\n },\n githubWatchers: function(slug) {\n return \"http://github.com/\" + slug + \"/watchers\";\n },\n githubNetwork: function(slug) {\n return \"http://github.com/\" + slug + \"/network\";\n },\n githubAdmin: function(slug) {\n return \"http://github.com/\" + slug + \"/admin/hooks#travis_minibucket\";\n },\n statusImage: function(slug, branch) {\n return (\"https://secure.travis-ci.org/\" + slug + \".png\") + (branch ? \"?branch=\" + branch : '');\n },\n email: function(email) {\n return \"mailto:\" + email;\n },\n account: function(login) {\n return \"/profile/\" + login;\n },\n user: function(login) {\n return \"/profile/\" + login + \"/me\";\n }\n };\n\n}).call(this);\n\n})();\n//@ sourceURL=helpers/urls");minispade.register('models', "(function() {(function() {\nminispade.require('models/extensions');\nminispade.require('models/account');\nminispade.require('models/artifact');\nminispade.require('models/branch');\nminispade.require('models/build');\nminispade.require('models/commit');\nminispade.require('models/event');\nminispade.require('models/hook');\nminispade.require('models/job');\nminispade.require('models/repo');\nminispade.require('models/sponsor');\nminispade.require('models/user');\nminispade.require('models/worker');\n\n}).call(this);\n\n})();\n//@ sourceURL=models");minispade.register('models/account', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Account = Travis.Model.extend({\n primaryKey: 'login',\n login: DS.attr('string'),\n name: DS.attr('string'),\n type: DS.attr('string'),\n reposCount: DS.attr('number'),\n urlGithub: (function() {\n return \"http://github.com/\" + (this.get('login'));\n }).property()\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/account");minispade.register('models/artifact', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Artifact = Travis.Model.extend({\n body: DS.attr('string'),\n init: function() {\n this._super.apply(this, arguments);\n this.set('queue', Ember.A([]));\n this.addObserver('body', this.fetchWorker);\n return this.fetchWorker();\n },\n append: function(body) {\n if (this.get('isLoaded')) {\n return this.set('body', this.get('body') + body);\n } else {\n return this.get('queue').pushObject(body);\n }\n },\n recordDidLoad: (function() {\n var queue;\n if (this.get('isLoaded')) {\n queue = this.get('queue');\n if (queue.get('length') > 0) {\n return this.append(queue.toArray().join(''));\n }\n }\n }).observes('isLoaded'),\n fetchWorker: function() {\n var body, line, match, worker;\n if (body = this.get('body')) {\n line = body.split(\"\\n\")[0];\n if (line && (match = line.match(/Using worker: (.*)/))) {\n if (worker = match[1]) {\n worker = worker.trim().split(':')[0];\n this.set('workerName', worker);\n return this.removeObserver('body', this.fetchWorker);\n }\n }\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/artifact");minispade.register('models/branch', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Branch = Travis.Model.extend(Travis.Helpers, {\n repoId: DS.attr('number', {\n key: 'repository_id'\n }),\n commitId: DS.attr('number'),\n number: DS.attr('number'),\n branch: DS.attr('string'),\n message: DS.attr('string'),\n result: DS.attr('number'),\n duration: DS.attr('number'),\n startedAt: DS.attr('string'),\n finishedAt: DS.attr('string'),\n commit: DS.belongsTo('Travis.Commit'),\n repo: (function() {\n if (this.get('repoId')) {\n return Travis.Repo.find(this.get('repoId'));\n }\n }).property('repoId'),\n updateTimes: function() {\n this.notifyPropertyChange('started_at');\n return this.notifyPropertyChange('finished_at');\n }\n });\n\n this.Travis.Branch.reopenClass({\n byRepoId: function(id) {\n return this.find({\n repository_id: id\n });\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/branch");minispade.register('models/build', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Build = Travis.Model.extend(Travis.DurationCalculations, {\n eventType: DS.attr('string'),\n repoId: DS.attr('number', {\n key: 'repository_id'\n }),\n commitId: DS.attr('number'),\n state: DS.attr('string'),\n number: DS.attr('number'),\n branch: DS.attr('string'),\n message: DS.attr('string'),\n result: DS.attr('number'),\n _duration: DS.attr('number', {\n key: 'duration'\n }),\n startedAt: DS.attr('string', {\n key: 'started_at'\n }),\n finishedAt: DS.attr('string', {\n key: 'finished_at'\n }),\n repo: DS.belongsTo('Travis.Repo', {\n key: 'repository_id'\n }),\n commit: DS.belongsTo('Travis.Commit'),\n jobs: DS.hasMany('Travis.Job', {\n key: 'job_ids'\n }),\n config: (function() {\n return Travis.Helpers.compact(this.get('data.config'));\n }).property('data.config'),\n isMatrix: (function() {\n return this.get('data.job_ids.length') > 1;\n }).property('data.job_ids.length'),\n isFinished: (function() {\n return this.get('state') === 'finished';\n }).property('state'),\n requiredJobs: (function() {\n return this.get('jobs').filter(function(data) {\n return !data.get('allowFailure');\n });\n }).property('jobs.@each.allowFailure'),\n allowedFailureJobs: (function() {\n return this.get('jobs').filter(function(data) {\n return data.get('allowFailure');\n });\n }).property('jobs.@each.allowFailure'),\n configKeys: (function() {\n var config, headers, key, keys;\n if (!(config = this.get('config'))) {\n return [];\n }\n keys = $.intersect($.keys(config), Travis.CONFIG_KEYS);\n headers = (function() {\n var _i, _len, _ref, _results;\n _ref = ['build.job', 'build.duration', 'build.finished_at'];\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n key = _ref[_i];\n _results.push(I18n.t(key));\n }\n return _results;\n })();\n return $.map(headers.concat(keys), function(key) {\n return $.camelize(key);\n });\n }).property('config'),\n requeue: (function() {\n return Travis.ajax.post('/requests', {\n build_id: this.get('id')\n });\n })\n });\n\n this.Travis.Build.reopenClass({\n byRepoId: function(id, parameters) {\n return this.find($.extend(parameters || {}, {\n repository_id: id\n }));\n },\n olderThanNumber: function(id, build_number) {\n return this.find({\n url: \"/builds\",\n repository_id: id,\n after_number: build_number\n });\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/build");minispade.register('models/commit', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Commit = Travis.Model.extend({\n buildId: DS.attr('number'),\n sha: DS.attr('string'),\n branch: DS.attr('string'),\n message: DS.attr('string'),\n compareUrl: DS.attr('string'),\n authorName: DS.attr('string'),\n authorEmail: DS.attr('string'),\n committerName: DS.attr('string'),\n committerEmail: DS.attr('string'),\n build: DS.belongsTo('Travis.Build', {\n key: 'buildId'\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/commit");minispade.register('models/event', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Event = Travis.Model.extend({\n event: DS.attr('string'),\n repoId: DS.attr('number', {\n key: 'repository_id'\n }),\n createdAt: DS.attr('string', {\n key: 'created_at'\n }),\n message: (function() {\n var message;\n message = \"\" + (this.get('event')) + \": \" + (this.get('_data.result'));\n message = \"\" + message + \": \" + (this.get('_data.message'));\n return message;\n }).property('_data.result', '_data.message'),\n _data: (function() {\n return this.get('data.data');\n }).property('data.data')\n });\n\n this.Travis.Event.reopenClass({\n byRepoId: function(id) {\n return this.find({\n repository_id: id\n });\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/event");minispade.register('models/extensions', "(function() {(function() {\n\n Travis.DurationCalculations = Ember.Mixin.create({\n duration: (function() {\n var duration;\n if (duration = this.get('_duration')) {\n return duration;\n } else {\n return Travis.Helpers.durationFrom(this.get('startedAt'), this.get('finishedAt'));\n }\n }).property('_duration', 'finishedAt', 'startedAt'),\n updateTimes: function() {\n this.notifyPropertyChange('_duration');\n return this.notifyPropertyChange('finished_at');\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/extensions");minispade.register('models/hook', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Hook = Travis.Model.extend({\n name: DS.attr('string'),\n ownerName: DS.attr('string'),\n description: DS.attr('string'),\n active: DS.attr('boolean'),\n account: (function() {\n return this.get('slug').split('/')[0];\n }).property('slug'),\n slug: (function() {\n return \"\" + (this.get('ownerName')) + \"/\" + (this.get('name'));\n }).property('ownerName', 'name'),\n urlGithub: (function() {\n return \"http://github.com/\" + (this.get('slug'));\n }).property(),\n urlGithubAdmin: (function() {\n return \"http://github.com/\" + (this.get('slug')) + \"/admin/hooks#travis_minibucket\";\n }).property(),\n toggle: function() {\n var transaction;\n transaction = this.get('store').transaction();\n transaction.add(this);\n this.set('active', !this.get('active'));\n return transaction.commit();\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/hook");minispade.register('models/job', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Job = Travis.Model.extend(Travis.DurationCalculations, {\n repoId: DS.attr('number', {\n key: 'repository_id'\n }),\n buildId: DS.attr('number'),\n commitId: DS.attr('number'),\n logId: DS.attr('number'),\n queue: DS.attr('string'),\n state: DS.attr('string'),\n number: DS.attr('string'),\n result: DS.attr('number'),\n _duration: DS.attr('number', {\n key: 'duration'\n }),\n startedAt: DS.attr('string'),\n finishedAt: DS.attr('string'),\n allowFailure: DS.attr('boolean', {\n key: 'allow_failure'\n }),\n repo: DS.belongsTo('Travis.Repo', {\n key: 'repository_id'\n }),\n build: DS.belongsTo('Travis.Build', {\n key: 'build_id'\n }),\n commit: DS.belongsTo('Travis.Commit', {\n key: 'commit_id'\n }),\n log: DS.belongsTo('Travis.Artifact', {\n key: 'log_id'\n }),\n config: (function() {\n return Travis.Helpers.compact(this.get('data.config'));\n }).property('data.config'),\n sponsor: (function() {\n var worker;\n worker = this.get('log.workerName');\n if (worker && worker.length) {\n return Travis.WORKERS[worker] || {\n name: \"Travis Pro\",\n url: \"http://travis-ci.com\"\n };\n }\n }).property('log.workerName'),\n configValues: (function() {\n var config;\n if (config = this.get('config')) {\n return $.values($.only.apply(config, Travis.CONFIG_KEYS));\n } else {\n return [];\n }\n }).property('config'),\n appendLog: function(text) {\n var log;\n if (log = this.get('log')) {\n return log.append(text);\n }\n },\n subscribe: function() {\n var id;\n if (id = this.get('id')) {\n return Travis.app.pusher.subscribe(\"job-\" + id);\n }\n },\n onStateChange: (function() {\n if (this.get('state') === 'finished') {\n return Travis.app.pusher.unsubscribe(\"job-\" + (this.get('id')));\n }\n }).observes('state')\n });\n\n this.Travis.Job.reopenClass({\n queued: function(queue) {\n this.find();\n return Travis.app.store.filter(this, function(job) {\n var queued;\n queued = ['created', 'queued'].indexOf(job.get('state')) !== -1;\n return queued && (!queue || job.get('queue') === (\"builds.\" + queue));\n });\n },\n findMany: function(ids) {\n return Travis.app.store.findMany(this, ids);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/job");minispade.register('models/repo', "(function() {(function() {\nminispade.require('travis/expandable_record_array');\nminispade.require('travis/model');\n\n this.Travis.Repo = Travis.Model.extend({\n slug: DS.attr('string'),\n description: DS.attr('string'),\n lastBuildId: DS.attr('number'),\n lastBuildNumber: DS.attr('string'),\n lastBuildResult: DS.attr('number'),\n lastBuildStartedAt: DS.attr('string'),\n lastBuildFinishedAt: DS.attr('string'),\n lastBuild: DS.belongsTo('Travis.Build'),\n builds: (function() {\n var array, builds, id;\n id = this.get('id');\n builds = Travis.Build.byRepoId(id, {\n event_type: 'push'\n });\n array = Travis.ExpandableRecordArray.create({\n type: Travis.Build,\n content: Ember.A([]),\n store: this.get('store')\n });\n array.load(builds);\n return array;\n }).property(),\n pullRequests: (function() {\n var array, builds, id;\n id = this.get('id');\n builds = Travis.Build.byRepoId(id, {\n event_type: 'pull_request'\n });\n array = Travis.ExpandableRecordArray.create({\n type: Travis.Build,\n content: Ember.A([]),\n store: this.get('store')\n });\n array.load(builds);\n return array;\n }).property(),\n branches: (function() {\n return Travis.Branch.byRepoId(this.get('id'));\n }).property(),\n events: (function() {\n return Travis.Event.byRepoId(this.get('id'));\n }).property(),\n owner: (function() {\n return (this.get('slug') || '').split('/')[0];\n }).property('slug'),\n name: (function() {\n return (this.get('slug') || '').split('/')[1];\n }).property('slug'),\n lastBuildDuration: (function() {\n var duration;\n duration = this.get('data.last_build_duration');\n if (!duration) {\n duration = Travis.Helpers.durationFrom(this.get('lastBuildStartedAt'), this.get('lastBuildFinishedAt'));\n }\n return duration;\n }).property('data.last_build_duration', 'lastBuildStartedAt', 'lastBuildFinishedAt'),\n sortOrder: (function() {\n var lastBuildFinishedAt;\n if (lastBuildFinishedAt = this.get('lastBuildFinishedAt')) {\n return -new Date(lastBuildFinishedAt).getTime();\n } else {\n return -new Date('9999').getTime() - parseInt(this.get('lastBuildId'));\n }\n }).property('lastBuildFinishedAt', 'lastBuildId'),\n stats: (function() {\n var _this = this;\n return this.get('_stats') || $.get(\"https://api.github.com/repos/\" + (this.get('slug')), function(data) {\n _this.set('_stats', data);\n return _this.notifyPropertyChange('stats');\n }) && {};\n }).property(),\n updateTimes: function() {\n return this.notifyPropertyChange('lastBuildDuration');\n }\n });\n\n this.Travis.Repo.reopenClass({\n recent: function() {\n return this.find();\n },\n ownedBy: function(login) {\n return this.find({\n owner_name: login,\n orderBy: 'name'\n });\n },\n accessibleBy: function(login) {\n return this.find({\n member: login,\n orderBy: 'name'\n });\n },\n search: function(query) {\n return this.find({\n search: query,\n orderBy: 'name'\n });\n },\n bySlug: function(slug) {\n var repo;\n repo = $.select(this.find().toArray(), function(repo) {\n return repo.get('slug') === slug;\n });\n if (repo.length > 0) {\n return repo;\n } else {\n return this.find({\n slug: slug\n });\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/repo");minispade.register('models/sponsor', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Sponsor = Travis.Model.extend({\n type: DS.attr('string'),\n url: DS.attr('string'),\n link: DS.attr('string'),\n image: (function() {\n return \"/images/sponsors/\" + (this.get('data.image'));\n }).property('data.image')\n });\n\n Travis.Sponsor.reopenClass({\n decks: function() {\n return this.platinum().concat(this.gold());\n },\n platinum: function() {\n var platinum, sponsor, _i, _len, _results;\n platinum = this.byType('platinum').toArray();\n _results = [];\n for (_i = 0, _len = platinum.length; _i < _len; _i++) {\n sponsor = platinum[_i];\n _results.push([sponsor]);\n }\n return _results;\n },\n gold: function() {\n var gold, _results;\n gold = this.byType('gold').toArray();\n _results = [];\n while (gold.length > 0) {\n _results.push(gold.splice(0, 2));\n }\n return _results;\n },\n links: function() {\n return this.byType('silver');\n },\n byType: function() {\n var types;\n types = Array.prototype.slice.apply(arguments);\n return Travis.Sponsor.filter(function(sponsor) {\n return types.indexOf(sponsor.get('type')) !== -1;\n });\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/sponsor");minispade.register('models/user', "(function() {(function() {\nminispade.require('travis/ajax');\nminispade.require('travis/model');\n\n this.Travis.User = Travis.Model.extend({\n name: DS.attr('string'),\n email: DS.attr('string'),\n login: DS.attr('string'),\n token: DS.attr('string'),\n locale: DS.attr('string'),\n gravatarId: DS.attr('string'),\n isSyncing: DS.attr('boolean'),\n syncedAt: DS.attr('string'),\n repoCount: DS.attr('number'),\n init: function() {\n if (this.get('isSyncing')) {\n this.poll();\n }\n this._super();\n return Ember.run.next(this, function() {\n var transaction;\n transaction = this.get('store').transaction();\n return transaction.add(this);\n });\n },\n urlGithub: (function() {\n return \"https://github.com/\" + (this.get('login'));\n }).property(),\n permissions: (function() {\n var _this = this;\n if (!this.permissions) {\n this.permissions = Ember.ArrayProxy.create({\n content: []\n });\n Travis.ajax.get('/users/permissions', function(data) {\n return _this.permissions.set('content', data.permissions);\n });\n }\n return this.permissions;\n }).property(),\n updateLocale: function(locale) {\n var observer, self, transaction;\n this.setWithSession('locale', locale);\n transaction = this.get('transaction');\n transaction.commit();\n self = this;\n observer = function() {\n if (!self.get('isSaving')) {\n self.removeObserver('isSaving', observer);\n transaction = self.get('store').transaction();\n return transaction.add(self);\n }\n };\n return this.addObserver('isSaving', observer);\n },\n type: (function() {\n return 'user';\n }).property(),\n sync: function() {\n Travis.ajax.post('/users/sync');\n this.setWithSession('isSyncing', true);\n return this.poll();\n },\n poll: function() {\n var _this = this;\n return Travis.ajax.get('/users', function(data) {\n if (data.user.is_syncing) {\n return Ember.run.later(_this, _this.poll.bind(_this), 3000);\n } else {\n _this.set('isSyncing', false);\n return _this.setWithSession('syncedAt', data.user.synced_at);\n }\n });\n },\n setWithSession: function(name, value) {\n var user;\n this.set(name, value);\n user = JSON.parse(typeof sessionStorage !== \"undefined\" && sessionStorage !== null ? sessionStorage.getItem('travis.user') : void 0);\n user[$.underscore(name)] = this.get(name);\n return typeof sessionStorage !== \"undefined\" && sessionStorage !== null ? sessionStorage.setItem('travis.user', JSON.stringify(user)) : void 0;\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/user");minispade.register('models/worker', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Worker = Travis.Model.extend({\n state: DS.attr('string'),\n name: DS.attr('string'),\n host: DS.attr('string'),\n lastSeenAt: DS.attr('string'),\n payload: (function() {\n return this.get('data.payload');\n }).property('data.payload'),\n number: (function() {\n return this.get('name').match(/\\d+$/)[0];\n }).property('name'),\n isWorking: (function() {\n return this.get('state') === 'working';\n }).property('state'),\n repo: (function() {\n return Travis.Repo.find(this.get('payload.repository.id') || this.get('payload.repo.id'));\n }).property('payload.repository.id', 'payload.repo.id'),\n job_id: (function() {\n return this.get('payload.job.id');\n }).property('payload.job.id'),\n job: (function() {\n return Travis.Job.find(this.get('job_id'));\n }).property('job_id'),\n nameForSort: (function() {\n var id, match, name;\n if (name = this.get('name')) {\n match = name.match(/(.*?)-(\\d+)/);\n if (match) {\n name = match[1];\n id = match[2].toString();\n if (id.length < 2) {\n id = \"00\" + id;\n } else if (id.length < 3) {\n id = \"0\" + id;\n }\n return \"\" + name + \"-\" + id;\n }\n }\n }).property('name')\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/worker");minispade.register('pusher', "(function() {(function() {\n\n Travis.Pusher = function(key) {\n if (key) {\n this.init(key);\n }\n return this;\n };\n\n $.extend(Travis.Pusher, {\n CHANNELS: ['common'],\n CHANNEL_PREFIX: ''\n });\n\n $.extend(Travis.Pusher.prototype, {\n active_channels: [],\n init: function(key) {\n var channel, _i, _len, _ref, _results;\n Pusher.warn = this.warn.bind(this);\n this.pusher = new Pusher(key);\n _ref = Travis.Pusher.CHANNELS;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n channel = _ref[_i];\n _results.push(this.subscribe(channel));\n }\n return _results;\n },\n subscribe: function(channel) {\n var _this = this;\n if (this.pusher && this.active_channels.indexOf(channel) === -1) {\n this.active_channels.push(channel);\n return this.pusher.subscribe(this.prefix(channel)).bind_all(function(event, data) {\n return _this.receive(event, data);\n });\n }\n },\n unsubscribe: function(channel) {\n var ix;\n ix = this.active_channels.indexOf(channel);\n if (this.pusher && ix === -1) {\n this.active_channels.splice(ix, 1);\n return this.pusher.unsubscribe(this.prefix(channel));\n }\n },\n prefix: function(channel) {\n return \"\" + Travis.Pusher.CHANNEL_PREFIX + channel;\n },\n receive: function(event, data) {\n if (event.substr(0, 6) === 'pusher') {\n return;\n }\n if (data.id) {\n data = this.normalize(event, data);\n }\n return Ember.run.next(function() {\n return Travis.app.store.receive(event, data);\n });\n },\n normalize: function(event, data) {\n switch (event) {\n case 'build:started':\n case 'build:finished':\n return data;\n case 'job:created':\n case 'job:started':\n case 'job:finished':\n case 'job:log':\n if (data.queue) {\n data.queue = data.queue.replace('builds.', '');\n }\n return {\n job: data\n };\n case 'worker:added':\n case 'worker:updated':\n case 'worker:removed':\n return {\n worker: data\n };\n }\n },\n warn: function(type, warning) {\n if (!this.ignoreWarning(warning)) {\n return console.warn(warning);\n }\n },\n ignoreWarning: function(warning) {\n var message, _ref;\n if (message = (_ref = warning.data) != null ? _ref.message : void 0) {\n return message.indexOf('Existing subscription') === 0 || message.indexOf('No current subscription') === 0;\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=pusher");minispade.register('routes', "(function() {(function() {\n var defaultRoute, lineNumberRoute, nonHashRouteMatcher, resolvePath;\nminispade.require('travis/location');\n\n defaultRoute = Ember.Route.extend({\n route: '/',\n index: 1000\n });\n\n lineNumberRoute = Ember.Route.extend({\n route: '#L:number',\n index: 1,\n connectOutlets: function(router) {\n return router.saveLineNumberHash();\n },\n routeMatcher: Ember.computed(function() {\n var route;\n if (route = this.get('route')) {\n return Ember._RouteMatcher.create({\n route: route,\n init: function() {\n var count, escapeForRegex, escaped, identifiers, regex;\n escapeForRegex = function(text) {\n return text.replace(/[\\-\\[\\]{}()*+?.,\\\\\\^\\$|#\\s]/g, \"\\\\$&\");\n };\n route = this.route;\n identifiers = [];\n count = 1;\n if (route.charAt(0) === '/') {\n route = this.route = route.substr(1);\n }\n escaped = escapeForRegex(route);\n regex = escaped.replace(/:([a-z_]+)(?=$|\\/)/gi, function(match, id) {\n identifiers[count++] = id;\n return \"([0-9]+)\";\n });\n this.identifiers = identifiers;\n return this.regex = new RegExp(regex);\n }\n });\n }\n }).cacheable()\n });\n\n nonHashRouteMatcher = Ember.computed(function() {\n var route;\n if (route = this.get('route')) {\n return Ember._RouteMatcher.create({\n route: route,\n init: function() {\n var count, escapeForRegex, escaped, identifiers, regex;\n escapeForRegex = function(text) {\n return text.replace(/[\\-\\[\\]{}()*+?.,\\\\\\^\\$|#\\s]/g, \"\\\\$&\");\n };\n route = this.route;\n identifiers = [];\n count = 1;\n if (route.charAt(0) === '/') {\n route = this.route = route.substr(1);\n }\n escaped = escapeForRegex(route);\n regex = escaped.replace(/:([a-z_]+)(?=$|\\/)/gi, function(match, id) {\n identifiers[count++] = id;\n return \"([^/#]+)\";\n });\n this.identifiers = identifiers;\n return this.regex = new RegExp(\"^/?\" + regex);\n }\n });\n }\n }).cacheable();\n\n resolvePath = function(manager, path) {\n var childStates, match, resolvedState, state, states;\n if (this.get('isLeafRoute')) {\n return Ember.A();\n }\n childStates = this.get('childStates');\n childStates = Ember.A(childStates.filterProperty('isRoutable'));\n childStates = childStates.sort(function(a, b) {\n var aDynamicSegments, aIndex, aRoute, bDynamicSegments, bIndex, bRoute;\n aDynamicSegments = a.get('routeMatcher.identifiers.length');\n bDynamicSegments = b.get('routeMatcher.identifiers.length');\n aRoute = a.get('route');\n bRoute = b.get('route');\n aIndex = a.get('index');\n bIndex = b.get('index');\n if (aIndex && bIndex) {\n return aIndex - bIndex;\n }\n if (aRoute.indexOf(bRoute) === 0) {\n return -1;\n } else if (bRoute.indexOf(aRoute) === 0) {\n return 1;\n }\n if (aDynamicSegments !== bDynamicSegments) {\n return aDynamicSegments - bDynamicSegments;\n }\n return b.get('route.length') - a.get('route.length');\n });\n match = null;\n state = childStates.find(function(state) {\n var matcher;\n matcher = state.get('routeMatcher');\n if (match = matcher.match(path)) {\n return match;\n }\n });\n Ember.assert(\"Could not find state for path \" + path, !!state);\n resolvedState = Ember._ResolvedState.create({\n manager: manager,\n state: state,\n match: match\n });\n states = state.resolvePath(manager, match.remaining);\n return Ember.A([resolvedState]).pushObjects(states);\n };\n\n Travis.Router = Ember.Router.extend({\n location: 'travis',\n enableLogging: true,\n initialState: 'loading',\n showRoot: Ember.Route.transitionTo('root.home.show'),\n showStats: Ember.Route.transitionTo('root.stats'),\n showRepo: Ember.Route.transitionTo('root.home.repo.show'),\n showBuilds: Ember.Route.transitionTo('root.home.repo.builds.index'),\n showBuild: Ember.Route.transitionTo('root.home.repo.builds.show'),\n showPullRequests: Ember.Route.transitionTo('root.home.repo.pullRequests'),\n showBranches: Ember.Route.transitionTo('root.home.repo.branches'),\n showEvents: Ember.Route.transitionTo('root.home.repo.events'),\n showJob: Ember.Route.transitionTo('root.home.repo.job'),\n showProfile: Ember.Route.transitionTo('root.profile'),\n showAccount: Ember.Route.transitionTo('root.profile.account'),\n showUserProfile: Ember.Route.transitionTo('root.profile.account.profile'),\n saveLineNumberHash: function(path) {\n return Ember.run.next(this, function() {\n var match;\n path = path || this.get('location').getURL();\n if (match = path.match(/#L\\d+$/)) {\n return this.set('repoController.lineNumberHash', match[0]);\n }\n });\n },\n reload: function() {\n var url;\n url = this.get('location').getURL();\n this.transitionTo('loading');\n return this.route(url);\n },\n signedIn: function() {\n return !!Travis.app.get('auth.user');\n },\n needsAuth: function(path) {\n return path.indexOf('/profile') === 0;\n },\n afterSignIn: function() {\n var path;\n path = sessionStorage.getItem('travis.after_signin_path');\n sessionStorage.removeItem('travis.after_signin_path');\n this.transitionTo('root');\n return this.route(path || '/');\n },\n afterSignOut: function() {\n return this.authorize('/');\n },\n authorize: function(path) {\n if (!this.signedIn() && this.needsAuth(path)) {\n sessionStorage.setItem('travis.after_signin_path', path);\n this.transitionTo('root.auth');\n return Travis.app.autoSignIn();\n } else {\n this.transitionTo('root');\n return this.route(path);\n }\n },\n loading: Ember.Route.extend({\n routePath: function(router, path) {\n router.saveLineNumberHash(path);\n return router.authorize(path);\n }\n }),\n root: Ember.Route.extend({\n route: '/',\n loading: Ember.State.extend(),\n auth: Ember.Route.extend({\n route: '/auth',\n connectOutlets: function(router) {\n router.get('applicationController').connectOutlet('authLayout');\n $('body').attr('id', 'auth');\n router.get('authLayoutController').connectOutlet('top', 'top');\n return router.get('authLayoutController').connectOutlet('main', 'signin');\n }\n }),\n stats: Ember.Route.extend({\n route: '/stats',\n afterSignIn: (function() {}),\n connectOutlets: function(router) {\n router.get('applicationController').connectOutlet('statsLayout');\n $('body').attr('id', 'stats');\n router.get('statsLayoutController').connectOutlet('top', 'top');\n return router.get('statsLayoutController').connectOutlet('main', 'stats');\n }\n }),\n profile: Ember.Route.extend({\n initialState: 'index',\n afterSignIn: (function() {}),\n route: '/profile',\n connectOutlets: function(router) {\n router.get('applicationController').connectOutlet('profileLayout');\n $('body').attr('id', 'profile');\n router.get('accountsController').set('content', Travis.Account.find());\n router.get('profileLayoutController').connectOutlet('top', 'top');\n return router.get('profileLayoutController').connectOutlet('left', 'accounts');\n },\n index: Ember.Route.extend({\n route: '/',\n connectOutlets: function(router) {\n router.get('profileLayoutController').connectOutlet('main', 'profile');\n return router.get('profileController').activate('hooks');\n }\n }),\n account: Ember.Route.extend({\n initialState: 'index',\n route: '/:login',\n connectOutlets: function(router, account) {\n var params;\n if (account) {\n params = {\n login: account.get('login')\n };\n return router.get('profileController').setParams(params);\n } else {\n return router.send('showProfile');\n }\n },\n deserialize: function(router, params) {\n var account, controller, deferred, observer;\n controller = router.get('accountsController');\n if (!controller.get('content')) {\n controller.set('content', Travis.Account.find());\n }\n account = controller.findByLogin(params.login);\n if (account) {\n return account;\n } else {\n deferred = $.Deferred();\n observer = function() {\n if (account = controller.findByLogin(params.login)) {\n controller.removeObserver('content.length', observer);\n return deferred.resolve(account);\n }\n };\n controller.addObserver('content.length', observer);\n return deferred.promise();\n }\n },\n serialize: function(router, account) {\n if (account) {\n return {\n login: account.get('login')\n };\n } else {\n return {};\n }\n },\n index: Ember.Route.extend({\n route: '/',\n connectOutlets: function(router) {\n return router.get('profileController').activate('hooks');\n }\n }),\n profile: Ember.Route.extend({\n route: '/profile',\n connectOutlets: function(router) {\n return router.get('profileController').activate('user');\n }\n })\n })\n }),\n home: Ember.Route.extend({\n route: '/',\n afterSignIn: (function() {}),\n connectOutlets: function(router) {\n router.get('applicationController').connectOutlet('homeLayout');\n $('body').attr('id', 'home');\n router.get('homeLayoutController').connectOutlet('left', 'repos');\n router.get('homeLayoutController').connectOutlet('right', 'sidebar');\n router.get('homeLayoutController').connectOutlet('top', 'top');\n router.get('homeLayoutController').connectOutlet('main', 'repo');\n router.get('homeLayoutController').connectOutlet('flash', 'flash');\n return router.get('repoController').set('repos', router.get('reposController'));\n },\n show: Ember.Route.extend({\n route: '/',\n connectOutlets: function(router) {\n return router.get('repoController').activate('index');\n },\n initialState: 'default',\n \"default\": defaultRoute,\n lineNumber: lineNumberRoute,\n resolvePath: resolvePath\n }),\n showWithLineNumber: Ember.Route.extend({\n route: '/#/L:number',\n connectOutlets: function(router) {\n return router.get('repoController').activate('index');\n }\n }),\n repo: Ember.Route.extend({\n route: '/:owner/:name',\n routeMatcher: nonHashRouteMatcher,\n connectOutlets: function(router, repo) {\n return router.get('repoController').set('repo', repo);\n },\n deserialize: function(router, params) {\n var deferred, observer, repos, slug;\n slug = \"\" + params.owner + \"/\" + params.name;\n repos = Travis.Repo.bySlug(slug);\n deferred = $.Deferred();\n observer = function() {\n if (repos.get('isLoaded')) {\n repos.removeObserver('isLoaded', observer);\n return deferred.resolve(repos.objectAt(0));\n }\n };\n if (repos.length) {\n deferred.resolve(repos[0]);\n } else {\n repos.addObserver('isLoaded', observer);\n }\n return deferred.promise();\n },\n serialize: function(router, repo) {\n if (repo) {\n return {\n owner: repo.get('owner'),\n name: repo.get('name')\n };\n } else {\n return {};\n }\n },\n show: Ember.Route.extend({\n route: '/',\n connectOutlets: function(router) {\n return router.get('repoController').activate('current');\n },\n initialState: 'default',\n \"default\": defaultRoute,\n lineNumber: lineNumberRoute,\n resolvePath: resolvePath\n }),\n builds: Ember.Route.extend({\n route: '/builds',\n index: Ember.Route.extend({\n route: '/',\n connectOutlets: function(router, repo) {\n return router.get('repoController').activate('builds');\n }\n }),\n show: Ember.Route.extend({\n route: '/:build_id',\n connectOutlets: function(router, build) {\n if (!build.get) {\n build = Travis.Build.find(build);\n }\n router.get('repoController').set('build', build);\n return router.get('repoController').activate('build');\n },\n serialize: function(router, build) {\n if (build.get) {\n return {\n build_id: build.get('id')\n };\n } else {\n return {\n build_id: build\n };\n }\n },\n deserialize: function(router, params) {\n var build, deferred, observer;\n build = Travis.Build.find(params.build_id);\n if (build.get('id')) {\n return build;\n } else {\n deferred = $.Deferred();\n observer = function() {\n if (build.get('id')) {\n build.removeObserver('id', observer);\n return deferred.resolve(build);\n }\n };\n build.addObserver('id', observer);\n return deferred.promise();\n }\n },\n initialState: 'default',\n \"default\": defaultRoute,\n lineNumber: lineNumberRoute,\n routeMatcher: nonHashRouteMatcher,\n resolvePath: resolvePath\n })\n }),\n pullRequests: Ember.Route.extend({\n route: '/pull_requests',\n connectOutlets: function(router, repo) {\n return router.get('repoController').activate('pull_requests');\n }\n }),\n branches: Ember.Route.extend({\n route: '/branches',\n connectOutlets: function(router, repo) {\n return router.get('repoController').activate('branches');\n }\n }),\n events: Ember.Route.extend({\n route: '/events',\n connectOutlets: function(router, repo) {\n return router.get('repoController').activate('events');\n }\n }),\n job: Ember.Route.extend({\n route: '/jobs/:job_id',\n connectOutlets: function(router, job) {\n if (!job.get) {\n job = Travis.Job.find(job);\n }\n router.get('repoController').set('job', job);\n return router.get('repoController').activate('job');\n },\n serialize: function(router, job) {\n if (job.get) {\n return {\n job_id: job.get('id')\n };\n } else {\n return {\n job_id: job\n };\n }\n },\n deserialize: function(router, params) {\n var deferred, job, observer;\n job = Travis.Job.find(params.job_id);\n if (job.get('id')) {\n return job;\n } else {\n deferred = $.Deferred();\n observer = function() {\n if (job.get('id')) {\n job.removeObserver('id', observer);\n return deferred.resolve(job);\n }\n };\n job.addObserver('id', observer);\n return deferred.promise();\n }\n },\n initialState: 'default',\n \"default\": defaultRoute,\n lineNumber: lineNumberRoute,\n routeMatcher: nonHashRouteMatcher,\n resolvePath: resolvePath\n })\n })\n })\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=routes");minispade.register('slider', "(function() {(function() {\n\n this.Travis.Slider = function() {\n if ((typeof localStorage !== \"undefined\" && localStorage !== null ? localStorage.getItem('travis.maximized') : void 0) === 'true') {\n this.minimize();\n }\n return this;\n };\n\n $.extend(Travis.Slider.prototype, {\n persist: function() {\n return typeof localStorage !== \"undefined\" && localStorage !== null ? localStorage.setItem('travis.maximized', this.isMinimized()) : void 0;\n },\n isMinimized: function() {\n return $('body').hasClass('maximized');\n },\n minimize: function() {\n return $('body').addClass('maximized');\n },\n toggle: function() {\n var element;\n $('body').toggleClass('maximized');\n this.persist();\n element = $(' ');\n $('#top .profile').append(element);\n return Em.run.later((function() {\n return element.remove();\n }), 10);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=slider");minispade.register('store', "(function() {(function() {\n var DATA_PROXY,\n __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };\nminispade.require('store/rest_adapter');\n\n DATA_PROXY = {\n get: function(name) {\n return this.savedData[name];\n }\n };\n\n Travis.Store = DS.Store.extend({\n revision: 4,\n adapter: Travis.RestAdapter.create(),\n load: function(type, id, hash) {\n var record, result;\n result = this._super.apply(this, arguments);\n if (result && result.clientId) {\n record = this.findByClientId(type, result.clientId);\n record.set('incomplete', false);\n record.set('complete', true);\n }\n return result;\n },\n merge: function(type, id, hash) {\n var clientId, data, dataCache, primaryKey, record, recordCache, typeMap;\n if (hash === void 0) {\n hash = id;\n primaryKey = type.proto().primaryKey;\n Ember.assert(\"A data hash was loaded for a record of type \" + type.toString() + \" but no primary key '\" + primaryKey + \"' was provided.\", hash[primaryKey]);\n id = hash[primaryKey];\n }\n typeMap = this.typeMapFor(type);\n dataCache = typeMap.cidToHash;\n clientId = typeMap.idToCid[id];\n recordCache = this.get('recordCache');\n if (clientId !== void 0) {\n if (data = dataCache[clientId]) {\n $.extend(data, hash);\n } else {\n dataCache[clientId] = hash;\n }\n if (record = recordCache[clientId]) {\n record.send('didChangeData');\n }\n } else {\n clientId = this.pushHash(hash, id, type);\n }\n if (clientId) {\n DATA_PROXY.savedData = hash;\n this.updateRecordArrays(type, clientId, DATA_PROXY);\n return {\n id: id,\n clientId: clientId\n };\n }\n },\n receive: function(event, data) {\n var job, mappings, name, type, _ref;\n _ref = event.split(':'), name = _ref[0], type = _ref[1];\n mappings = this.adapter.get('mappings');\n type = mappings[name];\n if (event === 'job:log') {\n if (job = this.find(Travis.Job, data['job']['id'])) {\n return job.appendLog(data['job']['_log']);\n }\n } else if (data[type.singularName()]) {\n return this._loadOne(this, type, data);\n } else if (data[type.pluralName()]) {\n return this._loadMany(this, type, data);\n } else {\n if (!type) {\n throw \"can't load data for \" + name;\n }\n }\n },\n _loadOne: function(store, type, json) {\n var result, root;\n root = type.singularName();\n if (type === Travis.Build && json.repository) {\n result = this._loadIncomplete(Travis.Repo, 'repository', json.repository);\n }\n return this._loadIncomplete(type, root, json[root]);\n },\n _loadIncomplete: function(type, root, hash) {\n var record, result;\n result = this.merge(type, hash);\n if (result && result.clientId) {\n record = this.findByClientId(type, result.clientId);\n if (!record.get('complete')) {\n record.set('incomplete', true);\n }\n return this._updateAssociations(type, root, hash);\n }\n },\n _loadMany: function(store, type, json) {\n var root;\n root = type.pluralName();\n this.adapter.sideload(store, type, json, root);\n return this.loadMany(type, json[root]);\n },\n _updateAssociations: function(type, name, data) {\n var _this = this;\n return Em.get(type, 'associationsByName').forEach(function(key, meta) {\n var clientId, dataProxy, id, ids, parent, _ref;\n if (meta.kind === 'belongsTo') {\n id = data[\"\" + key + \"_id\"];\n if (clientId = _this.typeMapFor(meta.type).idToCid[id]) {\n if (parent = _this.findByClientId(meta.type, clientId, id)) {\n dataProxy = parent.get('data');\n if (ids = dataProxy.get(\"\" + name + \"_ids\")) {\n if (_ref = data.id, __indexOf.call(ids, _ref) < 0) {\n ids.pushObject(data.id);\n }\n return parent.send('didChangeData');\n }\n }\n }\n }\n });\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=store");minispade.register('store/fixture_adapter', "(function() {(function() {\n\n this.Travis.FixtureAdapter = DS.Adapter.extend({\n find: function(store, type, id) {\n var fixtures;\n fixtures = type.FIXTURES;\n Ember.assert(\"Unable to find fixtures for model type \" + type.toString(), !!fixtures);\n if (fixtures.hasLoaded) {\n return;\n }\n return setTimeout((function() {\n store.loadMany(type, fixtures);\n return fixtures.hasLoaded = true;\n }), 300);\n },\n findMany: function() {\n return this.find.apply(this, arguments);\n },\n findAll: function(store, type) {\n var fixtures, ids;\n fixtures = type.FIXTURES;\n Ember.assert(\"Unable to find fixtures for model type \" + type.toString(), !!fixtures);\n ids = fixtures.map(function(item, index, self) {\n return item.id;\n });\n return store.loadMany(type, ids, fixtures);\n },\n findQuery: function(store, type, params, array) {\n var fixture, fixtures, hashes, key, matches, value;\n fixtures = type.FIXTURES;\n Ember.assert(\"Unable to find fixtures for model type \" + type.toString(), !!fixtures);\n hashes = (function() {\n var _i, _len, _results;\n _results = [];\n for (_i = 0, _len = fixtures.length; _i < _len; _i++) {\n fixture = fixtures[_i];\n matches = (function() {\n var _results1;\n _results1 = [];\n for (key in params) {\n value = params[key];\n _results1.push(key === 'orderBy' || fixture[key] === value);\n }\n return _results1;\n })();\n if (matches.reduce(function(a, b) {\n return a && b;\n })) {\n _results.push(fixture);\n } else {\n _results.push(null);\n }\n }\n return _results;\n })();\n return array.load(hashes.compact());\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=store/fixture_adapter");minispade.register('store/rest_adapter', "(function() {(function() {\nminispade.require('travis/ajax');\nminispade.require('models');\n\n this.Travis.RestAdapter = DS.RESTAdapter.extend({\n mappings: {\n repositories: Travis.Repo,\n repository: Travis.Repo,\n repos: Travis.Repo,\n repo: Travis.Repo,\n builds: Travis.Build,\n build: Travis.Build,\n commits: Travis.Commit,\n commit: Travis.Commit,\n jobs: Travis.Job,\n job: Travis.Job,\n account: Travis.Account,\n accounts: Travis.Account,\n worker: Travis.Worker,\n workers: Travis.Worker\n },\n plurals: {\n repositories: 'repositories',\n repository: 'repositories',\n repo: 'repos',\n repos: 'repos',\n build: 'builds',\n branch: 'branches',\n job: 'jobs',\n worker: 'workers',\n profile: 'profile'\n },\n ajax: function() {\n return Travis.ajax.ajax.apply(this, arguments);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=store/rest_adapter");minispade.register('tailing', "(function() {(function() {\n\n this.Travis.Tailing = function() {\n this.position = $(window).scrollTop();\n $(window).scroll(this.onScroll.bind(this));\n return this;\n };\n\n $.extend(Travis.Tailing.prototype, {\n options: {\n timeout: 200\n },\n run: function() {\n this.autoScroll();\n this.positionButton();\n if (this.active()) {\n return Ember.run.later(this.run.bind(this), this.options.timeout);\n }\n },\n toggle: function(event) {\n if (this.active()) {\n return this.stop();\n } else {\n return this.start();\n }\n },\n active: function() {\n return $('#tail').hasClass('active');\n },\n start: function() {\n $('#tail').addClass('active');\n return this.run();\n },\n stop: function() {\n return $('#tail').removeClass('active');\n },\n autoScroll: function() {\n var log, logBottom, win, winBottom;\n if (!this.active()) {\n return;\n }\n win = $(window);\n log = $('#log');\n logBottom = log.offset().top + log.outerHeight() + 40;\n winBottom = win.scrollTop() + win.height();\n if (logBottom - winBottom > 0) {\n return win.scrollTop(logBottom - win.height());\n }\n },\n onScroll: function() {\n var position;\n this.positionButton();\n position = $(window).scrollTop();\n if (position < this.position) {\n this.stop();\n }\n return this.position = position;\n },\n positionButton: function() {\n var max, offset, tail;\n tail = $('#tail');\n if (tail.length === 0) {\n return;\n }\n offset = $(window).scrollTop() - $('#log').offset().top;\n max = $('#log').height() - $('#tail').height() + 5;\n if (offset > max) {\n offset = max;\n }\n if (offset > 0) {\n return tail.css({\n top: offset - 2\n });\n } else {\n return tail.css({\n top: 0\n });\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=tailing");minispade.register('views', "(function() {(function() {\nminispade.require('ext/ember/namespace');\n\n this.Travis.reopen({\n View: Em.View.extend({\n popup: function(event) {\n this.popupCloseAll();\n return $(\"#\" + event.target.name).toggleClass('display');\n },\n popupClose: function(event) {\n return $(event.target).closest('.popup').removeClass('display');\n },\n popupCloseAll: function() {\n return $('.popup').removeClass('display');\n }\n })\n });\n\n this.Travis.reopen({\n HomeLayoutView: Travis.View.extend({\n templateName: 'layouts/home'\n }),\n AuthLayoutView: Travis.View.extend({\n templateName: 'layouts/simple'\n }),\n ProfileLayoutView: Travis.View.extend({\n templateName: 'layouts/profile'\n }),\n StatsLayoutView: Travis.View.extend({\n templateName: 'layouts/simple'\n })\n });\nminispade.require('views/accounts');\nminispade.require('views/application');\nminispade.require('views/build');\nminispade.require('views/events');\nminispade.require('views/flash');\nminispade.require('views/job');\nminispade.require('views/repo');\nminispade.require('views/profile');\nminispade.require('views/sidebar');\nminispade.require('views/stats');\nminispade.require('views/signin');\nminispade.require('views/top');\n\n}).call(this);\n\n})();\n//@ sourceURL=views");minispade.register('views/accounts', "(function() {(function() {\n\n this.Travis.reopen({\n AccountsView: Travis.View.extend({\n tabBinding: 'controller.tab',\n templateName: 'profile/accounts',\n classAccounts: (function() {\n if (this.get('tab') === 'accounts') {\n return 'active';\n }\n }).property('tab')\n }),\n AccountsListView: Em.CollectionView.extend({\n elementId: 'accounts',\n accountBinding: 'content',\n tagName: 'ul',\n emptyView: Ember.View.extend({\n template: Ember.Handlebars.compile('Loading
')\n }),\n itemViewClass: Travis.View.extend({\n accountBinding: 'content',\n typeBinding: 'content.type',\n selectedBinding: 'account.selected',\n classNames: ['account'],\n classNameBindings: ['type', 'selected'],\n name: (function() {\n return this.get('content.name') || this.get('content.login');\n }).property('content.login', 'content.name'),\n urlAccount: (function() {\n return Travis.Urls.account(this.get('account.login'));\n }).property('account.login')\n })\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/accounts");minispade.register('views/application', "(function() {(function() {\n\n this.Travis.reopen({\n ApplicationView: Travis.View.extend({\n templateName: 'application',\n localeDidChange: (function() {\n var locale;\n if (locale = Travis.app.get('auth.user.locale')) {\n Travis.setLocale(locale);\n return Travis.app.get('router').reload();\n }\n }).observes('Travis.app.auth.user.locale'),\n click: function(event) {\n if (!$(event.target).parents().andSelf().hasClass('popup')) {\n this.popupCloseAll();\n }\n if (!$(event.target).parents().andSelf().hasClass('menu')) {\n return $('.menu').removeClass('display');\n }\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/application");minispade.register('views/build', "(function() {(function() {\n\n this.Travis.reopen({\n BuildsView: Travis.View.extend({\n templateName: 'builds/list',\n buildsBinding: 'controller.builds',\n showMore: function() {\n var id, number;\n id = this.get('controller.repo.id');\n number = this.get('builds.lastObject.number');\n return this.get('builds').load(Travis.Build.olderThanNumber(id, number));\n },\n ShowMoreButton: Em.View.extend({\n tagName: 'button',\n classNameBindings: ['isLoading'],\n attributeBindings: ['disabled'],\n isLoadingBinding: 'controller.builds.isLoading',\n template: Em.Handlebars.compile('{{view.label}}'),\n disabledBinding: 'isLoading',\n label: (function() {\n if (this.get('isLoading')) {\n return 'Loading';\n } else {\n return 'Show more';\n }\n }).property('isLoading'),\n click: function() {\n return this.get('parentView').showMore();\n }\n })\n }),\n BuildsItemView: Travis.View.extend({\n tagName: 'tr',\n classNameBindings: ['color'],\n repoBinding: 'controller.repo',\n buildBinding: 'context',\n commitBinding: 'build.commit',\n color: (function() {\n return Travis.Helpers.colorForResult(this.get('build.result'));\n }).property('build.result'),\n urlBuild: (function() {\n return Travis.Urls.build(this.get('repo.slug'), this.get('build.id'));\n }).property('repo.slug', 'build.id'),\n urlGithubCommit: (function() {\n return Travis.Urls.githubCommit(this.get('repo.slug'), this.get('commit.sha'));\n }).property('repo.slug', 'commit.sha')\n }),\n BuildView: Travis.View.extend({\n templateName: 'builds/show',\n elementId: 'build',\n classNameBindings: ['color', 'loading'],\n repoBinding: 'controller.repo',\n buildBinding: 'controller.build',\n commitBinding: 'build.commit',\n currentItemBinding: 'build',\n loading: (function() {\n return !this.get('build.isComplete');\n }).property('build.isComplete'),\n color: (function() {\n return Travis.Helpers.colorForResult(this.get('build.result'));\n }).property('build.result'),\n urlBuild: (function() {\n return Travis.Urls.build(this.get('repo.slug'), this.get('build.id'));\n }).property('repo.slug', 'build.id'),\n urlGithubCommit: (function() {\n return Travis.Urls.githubCommit(this.get('repo.slug'), this.get('commit.sha'));\n }).property('repo.slug', 'commit.sha'),\n urlAuthor: (function() {\n return Travis.Urls.email(this.get('commit.authorEmail'));\n }).property('commit.authorEmail'),\n urlCommitter: (function() {\n return Travis.Urls.email(this.get('commit.committerEmail'));\n }).property('commit.committerEmail')\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/build");minispade.register('views/events', "(function() {(function() {\n\n this.Travis.reopen({\n EventsView: Travis.View.extend({\n templateName: 'events/list',\n eventsBinding: 'controller.events'\n }),\n EventsItemView: Travis.View.extend({\n tagName: 'tr'\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/events");minispade.register('views/flash', "(function() {(function() {\n\n this.Travis.reopen({\n FlashView: Travis.View.extend({\n elementId: 'flash',\n tagName: 'ul',\n templateName: 'layouts/flash'\n }),\n FlashItemView: Travis.View.extend({\n tagName: 'li',\n classNameBindings: ['type'],\n type: (function() {\n return this.get('flash') && Ember.keys(this.get('flash'))[0];\n }).property('flash'),\n message: (function() {\n return this.get('flash') && this.get('flash')[this.get('type')];\n }).property('flash'),\n close: function(event) {\n return this.get('controller').removeObject(this.get('flash'));\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/flash");minispade.register('views/job', "(function() {(function() {\n\n this.Travis.reopen({\n JobsView: Travis.View.extend({\n templateName: 'jobs/list',\n buildBinding: 'controller.build'\n }),\n JobsItemView: Travis.View.extend({\n tagName: 'tr',\n classNameBindings: ['color'],\n repoBinding: 'context.repo',\n jobBinding: 'context',\n color: (function() {\n return Travis.Helpers.colorForResult(this.get('job.result'));\n }).property('job.result'),\n urlJob: (function() {\n return Travis.Urls.job(this.get('repo.slug'), this.get('job.id'));\n }).property('repo.slug', 'job.id')\n }),\n JobView: Travis.View.extend({\n templateName: 'jobs/show',\n repoBinding: 'controller.repo',\n jobBinding: 'controller.job',\n commitBinding: 'job.commit',\n currentItemBinding: 'job',\n color: (function() {\n return Travis.Helpers.colorForResult(this.get('job.result'));\n }).property('job.result'),\n urlJob: (function() {\n return Travis.Urls.job(this.get('repo.slug'), this.get('job.id'));\n }).property('repo.slug', 'job.id'),\n urlGithubCommit: (function() {\n return Travis.Urls.githubCommit(this.get('repo.slug'), this.get('commit.sha'));\n }).property('repo.slug', 'commit.sha'),\n urlAuthor: (function() {\n return Travis.Urls.email(this.get('commit.authorEmail'));\n }).property('commit.authorEmail'),\n urlCommitter: (function() {\n return Travis.Urls.email(this.get('commit.committerEmail'));\n }).property('commit.committerEmail')\n }),\n LogView: Travis.View.extend({\n templateName: 'jobs/log',\n logBinding: 'job.log',\n scrollTo: function(hash) {\n $('body').scrollTop($(hash).offset().top);\n return this.set('controller.lineNumberHash', null);\n },\n lineNumberHashDidChange: (function() {\n return this.tryScrollingToHashLineNumber();\n }).observes('controller.lineNumberHash'),\n tryScrollingToHashLineNumber: function() {\n var checker, hash, self;\n if (hash = this.get('controller.lineNumberHash')) {\n self = this;\n checker = function() {\n if (self.get('isDestroyed')) {\n return;\n }\n if ($(hash).length) {\n return self.scrollTo(hash);\n } else {\n return setTimeout(checker, 100);\n }\n };\n return checker();\n }\n },\n didInsertElement: function() {\n this._super.apply(this, arguments);\n return this.tryScrollingToHashLineNumber();\n },\n click: function(event) {\n var path, target;\n target = $(event.target);\n target.closest('.fold').toggleClass('open');\n if (target.is('.log-line-number')) {\n path = target.attr('href');\n Travis.app.get('router').route(path);\n event.stopPropagation();\n return false;\n }\n },\n toTop: function() {\n return $(window).scrollTop(0);\n },\n jobBinding: 'context',\n toggleTailing: function(event) {\n Travis.app.tailing.toggle();\n return event.preventDefault();\n },\n logSubscriber: (function() {\n var job, state;\n job = this.get('job');\n state = this.get('job.state');\n if (job && state !== 'finished') {\n job.subscribe();\n }\n return null;\n }).property('job', 'job.state')\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/job");minispade.register('views/left', "(function() {(function() {\n\n this.Travis.reopen({\n ReposView: Travis.View.extend({\n templateName: 'repos/list',\n tabBinding: 'controller.tab',\n classRecent: (function() {\n if (this.get('tab') === 'recent') {\n return 'active';\n }\n }).property('tab'),\n classOwned: (function() {\n var classes;\n classes = [];\n if (this.get('tab') === 'owned') {\n classes.push('active');\n }\n if (Travis.app.get('currentUser')) {\n classes.push('display');\n }\n return classes.join(' ');\n }).property('tab', 'Travis.currentUser'),\n classSearch: (function() {\n if (this.get('tab') === 'search') {\n return 'active';\n }\n }).property('tab')\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/left");minispade.register('views/profile', "(function() {(function() {\n\n this.Travis.reopen({\n ProfileView: Travis.View.extend({\n templateName: 'profile/show',\n accountBinding: 'controller.account',\n name: (function() {\n return this.get('account.name') || this.get('account.login');\n }).property('account.name', 'account.login')\n }),\n ProfileTabsView: Travis.View.extend({\n templateName: 'profile/tabs',\n tabBinding: 'controller.tab',\n activate: function(event) {\n return this.get('controller').activate(event.target.name);\n },\n classHooks: (function() {\n if (this.get('tab') === 'hooks') {\n return 'active';\n }\n }).property('tab'),\n classUser: (function() {\n if (this.get('tab') === 'user') {\n return 'active';\n }\n }).property('tab'),\n accountBinding: 'controller.account',\n displayUser: (function() {\n return this.get('controller.account.login') === this.get('controller.user.login');\n }).property('controller.account.login', 'controller.user.login')\n }),\n HooksView: Travis.View.extend({\n templateName: 'profile/tabs/hooks',\n userBinding: 'controller.user',\n urlGithubAdmin: (function() {\n return Travis.Urls.githubAdmin(this.get('hook.slug'));\n }).property('hook.slug')\n }),\n UserView: Travis.View.extend({\n templateName: 'profile/tabs/user',\n userBinding: 'controller.user',\n gravatarUrl: (function() {\n return \"\" + location.protocol + \"//www.gravatar.com/avatar/\" + (this.get('user.gravatarId')) + \"?s=48&d=mm\";\n }).property('user.gravatarId'),\n locales: (function() {\n return [\n {\n key: null,\n name: ''\n }, {\n key: 'en',\n name: 'English'\n }, {\n key: 'ca',\n name: 'Catalan'\n }, {\n key: 'cs',\n name: 'Čeština'\n }, {\n key: 'es',\n name: 'Español'\n }, {\n key: 'fr',\n name: 'Français'\n }, {\n key: 'ja',\n name: '日本語'\n }, {\n key: 'nl',\n name: 'Nederlands'\n }, {\n key: 'nb',\n name: 'Norsk Bokmål'\n }, {\n key: 'pl',\n name: 'Polski'\n }, {\n key: {\n 'pt-BR': {\n name: 'Português brasileiro'\n }\n }\n }, {\n key: 'ru',\n name: 'Русский'\n }\n ];\n }).property(),\n saveLocale: function(event) {\n return this.get('user').updateLocale($('#locale').val());\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/profile");minispade.register('views/repo', "(function() {(function() {\nminispade.require('views/repo/list');\nminispade.require('views/repo/show');\n\n}).call(this);\n\n})();\n//@ sourceURL=views/repo");minispade.register('views/repo/list', "(function() {(function() {\n\n this.Travis.reopen({\n ReposView: Travis.View.extend({\n templateName: 'repos/list',\n toggleInfo: function(event) {\n return $('#repos').toggleClass('open');\n }\n }),\n ReposListView: Em.CollectionView.extend({\n elementId: 'repos',\n tagName: 'ul',\n emptyView: Ember.View.extend({\n template: Ember.Handlebars.compile('Loading
')\n }),\n itemViewClass: Travis.View.extend({\n repoBinding: 'content',\n classNames: ['repo'],\n classNameBindings: ['color', 'selected'],\n selectedBinding: 'repo.selected',\n color: (function() {\n return Travis.Helpers.colorForResult(this.get('repo.lastBuildResult'));\n }).property('repo.lastBuildResult'),\n urlRepo: (function() {\n return Travis.Urls.repo(this.get('repo.slug'));\n }).property('repo.slug'),\n urlLastBuild: (function() {\n return Travis.Urls.build(this.get('repo.slug'), this.get('repo.lastBuildId'));\n }).property('repo.slug', 'repo.lastBuildId')\n })\n }),\n ReposListTabsView: Travis.View.extend({\n templateName: 'repos/list/tabs',\n tabBinding: 'controller.tab',\n activate: function(event) {\n return this.get('controller').activate(event.target.name);\n },\n classRecent: (function() {\n if (this.get('tab') === 'recent') {\n return 'active';\n }\n }).property('tab'),\n classOwned: (function() {\n var classes;\n classes = [];\n if (this.get('tab') === 'owned') {\n classes.push('active');\n }\n if (Travis.app.get('currentUser')) {\n classes.push('display-inline');\n }\n return classes.join(' ');\n }).property('tab', 'Travis.app.currentUser'),\n classSearch: (function() {\n if (this.get('tab') === 'search') {\n return 'active';\n }\n }).property('tab')\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/repo/list");minispade.register('views/repo/show', "(function() {(function() {\n\n this.Travis.reopen({\n RepoView: Travis.View.extend({\n templateName: 'repos/show',\n reposBinding: 'controller.repos',\n repoBinding: 'controller.repo',\n \"class\": (function() {\n if (!this.get('repo.isComplete') && !this.get('isEmpty')) {\n return 'loading';\n }\n }).property('repo.isComplete'),\n isEmpty: (function() {\n return this.get('repos.length') === 0;\n }).property('repos.length'),\n urlGithub: (function() {\n return Travis.Urls.githubRepo(this.get('repo.slug'));\n }).property('repo.slug'),\n urlGithubWatchers: (function() {\n return Travis.Urls.githubWatchers(this.get('repo.slug'));\n }).property('repo.slug'),\n urlGithubNetwork: (function() {\n return Travis.Urls.githubNetwork(this.get('repo.slug'));\n }).property('repo.slug')\n }),\n ReposEmptyView: Travis.View.extend({\n template: ''\n }),\n RepoShowTabsView: Travis.View.extend({\n templateName: 'repos/show/tabs',\n repoBinding: 'controller.repo',\n buildBinding: 'controller.build',\n jobBinding: 'controller.job',\n tabBinding: 'controller.tab',\n classCurrent: (function() {\n if (this.get('tab') === 'current') {\n return 'active';\n }\n }).property('tab'),\n classBuilds: (function() {\n if (this.get('tab') === 'builds') {\n return 'active';\n }\n }).property('tab'),\n classPullRequests: (function() {\n if (this.get('tab') === 'pull_requests') {\n return 'active';\n }\n }).property('tab'),\n classBranches: (function() {\n if (this.get('tab') === 'branches') {\n return 'active';\n }\n }).property('tab'),\n classEvents: (function() {\n if (this.get('tab') === 'events') {\n return 'active';\n }\n }).property('tab'),\n classBuild: (function() {\n var classes, tab;\n tab = this.get('tab');\n classes = [];\n if (tab === 'build') {\n classes.push('active');\n }\n if (tab === 'build' || tab === 'job') {\n classes.push('display-inline');\n }\n return classes.join(' ');\n }).property('tab'),\n classJob: (function() {\n if (this.get('tab') === 'job') {\n return 'active display-inline';\n }\n }).property('tab')\n }),\n RepoShowToolsView: Travis.View.extend({\n templateName: 'repos/show/tools',\n repoBinding: 'controller.repo',\n buildBinding: 'controller.build',\n jobBinding: 'controller.job',\n tabBinding: 'controller.tab',\n closeMenu: function() {\n return $('.menu').removeClass('display');\n },\n menu: function(event) {\n var element;\n this.popupCloseAll();\n element = $('#tools .menu').toggleClass('display');\n return event.stopPropagation();\n },\n requeue: function() {\n this.closeMenu();\n return this.get('build').requeue();\n },\n statusImages: function(event) {\n this.set('active', true);\n this.closeMenu();\n this.popup(event);\n return event.stopPropagation();\n },\n canPush: (function() {\n return this.get('isBuildTab') && this.get('build.isFinished') && this.get('hasPushPermissions');\n }).property('build.isFinished', 'hasPushPermissions', 'isBuildTab'),\n isBuildTab: (function() {\n return ['current', 'build', 'job'].indexOf(this.get('tab')) > -1;\n }).property('tab'),\n hasPushPermissions: (function() {\n var permissions;\n if (permissions = Travis.app.get('currentUser.permissions')) {\n return permissions.indexOf(this.get('repo.id')) > -1;\n }\n }).property('Travis.app.currentUser.permissions.length', 'repo.id'),\n branches: (function() {\n if (this.get('active')) {\n return this.get('repo.branches');\n }\n }).property('active', 'repo.branches'),\n urlRepo: (function() {\n return 'https://' + location.host + Travis.Urls.repo(this.get('repo.slug'));\n }).property('repo.slug'),\n urlStatusImage: (function() {\n return Travis.Urls.statusImage(this.get('repo.slug'), this.get('branch.commit.branch'));\n }).property('repo.slug', 'branch'),\n markdownStatusImage: (function() {\n return \"[) + \")](\" + (this.get('urlRepo')) + \")\";\n }).property('urlStatusImage'),\n textileStatusImage: (function() {\n return \"!\" + (this.get('urlStatusImage')) + \"!:\" + (this.get('urlRepo'));\n }).property('urlStatusImage'),\n rdocStatusImage: (function() {\n return \"{ }[\" + (this.get('urlRepo')) + \"]\";\n }).property('urlStatusImage')\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/repo/show");minispade.register('views/sidebar', "(function() {(function() {\n\n this.Travis.reopen({\n SidebarView: Travis.View.extend({\n templateName: 'layouts/sidebar',\n DecksView: Em.View.extend({\n templateName: \"sponsors/decks\",\n controller: Travis.SponsorsController.create({\n perPage: 1\n }),\n didInsertElement: function() {\n var controller;\n controller = this.get('controller');\n if (!controller.get('content')) {\n Travis.app.get('router.sidebarController').tickables.push(controller);\n controller.set('content', Travis.Sponsor.decks());\n }\n return this._super.apply(this, arguments);\n }\n }),\n LinksView: Em.View.extend({\n templateName: \"sponsors/links\",\n controller: Travis.SponsorsController.create({\n perPage: 6\n }),\n didInsertElement: function() {\n var controller;\n controller = this.get('controller');\n if (!controller.get('content')) {\n controller.set('content', Travis.Sponsor.links());\n Travis.app.get('router.sidebarController').tickables.push(controller);\n }\n return this._super.apply(this, arguments);\n }\n }),\n WorkersView: Em.View.extend({\n templateName: 'workers/list',\n controller: Travis.WorkersController.create(),\n didInsertElement: function() {\n this.set('controller.content', Travis.Worker.find());\n return this._super.apply(this, arguments);\n }\n }),\n QueuesView: Em.View.extend({\n templateName: 'queues/list',\n controller: Em.ArrayController.create(),\n didInsertElement: function() {\n var queue, queues;\n queues = (function() {\n var _i, _len, _ref, _results;\n _ref = Travis.QUEUES;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n queue = _ref[_i];\n _results.push(Em.ArrayController.create({\n content: Travis.Job.queued(queue.name),\n id: \"queue_\" + queue.name,\n name: queue.display\n }));\n }\n return _results;\n })();\n this.set('controller.content', queues);\n return this._super.apply(this, arguments);\n }\n })\n }),\n WorkersView: Travis.View.extend({\n toggleWorkers: function(event) {\n var handle;\n handle = $(event.target).toggleClass('open');\n if (handle.hasClass('open')) {\n return $('#workers li').addClass('open');\n } else {\n return $('#workers li').removeClass('open');\n }\n }\n }),\n WorkersListView: Travis.View.extend({\n toggle: function(event) {\n return $(event.target).closest('li').toggleClass('open');\n }\n }),\n WorkersItemView: Travis.View.extend({\n display: (function() {\n var name, number, payload, repo, state;\n name = (this.get('worker.name') || '').replace('travis-', '');\n state = this.get('worker.state');\n payload = this.get('worker.payload');\n if (state === 'working' && (payload != null ? payload.repository : void 0) && (payload != null ? payload.build : void 0)) {\n repo = payload.repository.slug;\n number = ' #' + payload.build.number;\n return (\"\" + name + \": \" + repo + \" \" + number).htmlSafe();\n } else {\n return \"\" + name + \": \" + state;\n }\n }).property('worker.state')\n }),\n QueueItemView: Travis.View.extend({\n tagName: 'li'\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/sidebar");minispade.register('views/signin', "(function() {(function() {\n\n this.Travis.reopen({\n SigninView: Travis.View.extend({\n templateName: 'auth/signin',\n signingIn: (function() {\n return Travis.app.get('authState') === 'signing-in';\n }).property('Travis.app.authState')\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/signin");minispade.register('views/stats', "(function() {(function() {\n\n this.Travis.reopen({\n StatsView: Travis.View.extend({\n templateName: 'stats/show',\n didInsertElement: function() {},\n renderChart: function(config) {\n var chart;\n chart = new Highcharts.Chart(config);\n return this.fetch(config.source, function(data) {\n var stats;\n stats = (function() {\n var _i, _len, _ref, _results;\n _ref = data.stats;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n stats = _ref[_i];\n _results.push(config.map(stats));\n }\n return _results;\n })();\n return chart.series[0].setData(stats);\n });\n },\n fetch: function(url, callback) {\n return $.ajax({\n type: 'GET',\n url: url,\n accepts: {\n json: 'application/vnd.travis-ci.2+json'\n },\n success: callback\n });\n },\n CHARTS: {\n repos: {\n source: '/api/stats/repos',\n total: 0,\n map: function(data) {\n return [Date.parse(data.date), this.total += parseInt(data.count)];\n },\n chart: {\n renderTo: \"repos_stats\"\n },\n title: {\n text: \"Total Projects/Repositories\"\n },\n xAxis: {\n type: \"datetime\",\n dateTimeLabelFormats: {\n month: \"%e. %b\",\n year: \"%b\"\n }\n },\n yAxis: {\n title: {\n text: \"Count\"\n },\n min: 0\n },\n tooltip: {\n formatter: function() {\n return Highcharts.dateFormat(\"%e. %b\", this.x) + \": \" + this.y + \" repos\";\n }\n },\n series: [\n {\n name: \"Repository Growth\",\n data: []\n }\n ]\n },\n builds: {\n source: '/api/stats/tests',\n map: function(data) {\n return [Date.parse(data.date), parseInt(data.count)];\n },\n chart: {\n renderTo: \"tests_stats\",\n type: \"column\"\n },\n title: {\n text: \"Build Count\"\n },\n subtitle: {\n text: \"last month\"\n },\n xAxis: {\n type: \"datetime\",\n dateTimeLabelFormats: {\n month: \"%e. %b\",\n year: \"%b\"\n }\n },\n yAxis: {\n title: {\n text: \"Count\"\n },\n min: 0\n },\n tooltip: {\n formatter: function() {\n return Highcharts.dateFormat(\"%e. %b\", this.x) + \": \" + this.y + \" builds\";\n }\n },\n series: [\n {\n name: \"Total Builds\",\n data: []\n }\n ]\n }\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/stats");minispade.register('views/top', "(function() {(function() {\n\n this.Travis.reopen({\n TopView: Travis.View.extend({\n templateName: 'layouts/top',\n tabBinding: 'controller.tab',\n userBinding: 'controller.user',\n gravatarUrl: (function() {\n return \"\" + location.protocol + \"//www.gravatar.com/avatar/\" + (this.get('user.gravatarId')) + \"?s=24&d=mm\";\n }).property('user.gravatarId'),\n classHome: (function() {\n if (this.get('tab') === 'home') {\n return 'active';\n }\n }).property('tab'),\n classStats: (function() {\n if (this.get('tab') === 'stats') {\n return 'active';\n }\n }).property('tab'),\n classProfile: (function() {\n var classes;\n classes = ['profile'];\n if (this.get('tab') === 'profile') {\n classes.push('active');\n }\n classes.push(Travis.app.get('authState'));\n return classes.join(' ');\n }).property('tab', 'Travis.app.authState'),\n showProfile: function() {\n return $('#top .profile ul').show();\n },\n hideProfile: function() {\n return $('#top .profile ul').hide();\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/top");minispade.register('config/emoij', "(function() {(function() {\n\n this.EmojiDictionary = ['-1', '0', '1', '109', '2', '3', '4', '5', '6', '7', '8', '8ball', '9', 'a', 'ab', 'airplane', 'alien', 'ambulance', 'angel', 'anger', 'angry', 'apple', 'aquarius', 'aries', 'arrow_backward', 'arrow_down', 'arrow_forward', 'arrow_left', 'arrow_lower_left', 'arrow_lower_right', 'arrow_right', 'arrow_up', 'arrow_upper_left', 'arrow_upper_right', 'art', 'astonished', 'atm', 'b', 'baby', 'baby_chick', 'baby_symbol', 'balloon', 'bamboo', 'bank', 'barber', 'baseball', 'basketball', 'bath', 'bear', 'beer', 'beers', 'beginner', 'bell', 'bento', 'bike', 'bikini', 'bird', 'birthday', 'black_square', 'blue_car', 'blue_heart', 'blush', 'boar', 'boat', 'bomb', 'book', 'boot', 'bouquet', 'bow', 'bowtie', 'boy', 'bread', 'briefcase', 'broken_heart', 'bug', 'bulb', 'bullettrain_front', 'bullettrain_side', 'bus', 'busstop', 'cactus', 'cake', 'calling', 'camel', 'camera', 'cancer', 'capricorn', 'car', 'cat', 'cd', 'chart', 'checkered_flag', 'cherry_blossom', 'chicken', 'christmas_tree', 'church', 'cinema', 'city_sunrise', 'city_sunset', 'clap', 'clapper', 'clock1', 'clock10', 'clock11', 'clock12', 'clock2', 'clock3', 'clock4', 'clock5', 'clock6', 'clock7', 'clock8', 'clock9', 'closed_umbrella', 'cloud', 'clubs', 'cn', 'cocktail', 'coffee', 'cold_sweat', 'computer', 'confounded', 'congratulations', 'construction', 'construction_worker', 'convenience_store', 'cool', 'cop', 'copyright', 'couple', 'couple_with_heart', 'couplekiss', 'cow', 'crossed_flags', 'crown', 'cry', 'cupid', 'currency_exchange', 'curry', 'cyclone', 'dancer', 'dancers', 'dango', 'dart', 'dash', 'de', 'department_store', 'diamonds', 'disappointed', 'dog', 'dolls', 'dolphin', 'dress', 'dvd', 'ear', 'ear_of_rice', 'egg', 'eggplant', 'egplant', 'eight_pointed_black_star', 'eight_spoked_asterisk', 'elephant', 'email', 'es', 'european_castle', 'exclamation', 'eyes', 'factory', 'fallen_leaf', 'fast_forward', 'fax', 'fearful', 'feelsgood', 'feet', 'ferris_wheel', 'finnadie', 'fire', 'fire_engine', 'fireworks', 'fish', 'fist', 'flags', 'flushed', 'football', 'fork_and_knife', 'fountain', 'four_leaf_clover', 'fr', 'fries', 'frog', 'fuelpump', 'gb', 'gem', 'gemini', 'ghost', 'gift', 'gift_heart', 'girl', 'goberserk', 'godmode', 'golf', 'green_heart', 'grey_exclamation', 'grey_question', 'grin', 'guardsman', 'guitar', 'gun', 'haircut', 'hamburger', 'hammer', 'hamster', 'hand', 'handbag', 'hankey', 'hash', 'headphones', 'heart', 'heart_decoration', 'heart_eyes', 'heartbeat', 'heartpulse', 'hearts', 'hibiscus', 'high_heel', 'horse', 'hospital', 'hotel', 'hotsprings', 'house', 'hurtrealbad', 'icecream', 'id', 'ideograph_advantage', 'imp', 'information_desk_person', 'iphone', 'it', 'jack_o_lantern', 'japanese_castle', 'joy', 'jp', 'key', 'kimono', 'kiss', 'kissing_face', 'kissing_heart', 'koala', 'koko', 'kr', 'leaves', 'leo', 'libra', 'lips', 'lipstick', 'lock', 'loop', 'loudspeaker', 'love_hotel', 'mag', 'mahjong', 'mailbox', 'man', 'man_with_gua_pi_mao', 'man_with_turban', 'maple_leaf', 'mask', 'massage', 'mega', 'memo', 'mens', 'metal', 'metro', 'microphone', 'minidisc', 'mobile_phone_off', 'moneybag', 'monkey', 'monkey_face', 'moon', 'mortar_board', 'mount_fuji', 'mouse', 'movie_camera', 'muscle', 'musical_note', 'nail_care', 'necktie', 'new', 'no_good', 'no_smoking', 'nose', 'notes', 'o', 'o2', 'ocean', 'octocat', 'octopus', 'oden', 'office', 'ok', 'ok_hand', 'ok_woman', 'older_man', 'older_woman', 'open_hands', 'ophiuchus', 'palm_tree', 'parking', 'part_alternation_mark', 'pencil', 'penguin', 'pensive', 'persevere', 'person_with_blond_hair', 'phone', 'pig', 'pill', 'pisces', 'plus1', 'point_down', 'point_left', 'point_right', 'point_up', 'point_up_2', 'police_car', 'poop', 'post_office', 'postbox', 'pray', 'princess', 'punch', 'purple_heart', 'question', 'rabbit', 'racehorse', 'radio', 'rage', 'rage1', 'rage2', 'rage3', 'rage4', 'rainbow', 'raised_hands', 'ramen', 'red_car', 'red_circle', 'registered', 'relaxed', 'relieved', 'restroom', 'rewind', 'ribbon', 'rice', 'rice_ball', 'rice_cracker', 'rice_scene', 'ring', 'rocket', 'roller_coaster', 'rose', 'ru', 'runner', 'sa', 'sagittarius', 'sailboat', 'sake', 'sandal', 'santa', 'satellite', 'satisfied', 'saxophone', 'school', 'school_satchel', 'scissors', 'scorpius', 'scream', 'seat', 'secret', 'shaved_ice', 'sheep', 'shell', 'ship', 'shipit', 'shirt', 'shit', 'shoe', 'signal_strength', 'six_pointed_star', 'ski', 'skull', 'sleepy', 'slot_machine', 'smile', 'smiley', 'smirk', 'smoking', 'snake', 'snowman', 'sob', 'soccer', 'space_invader', 'spades', 'spaghetti', 'sparkler', 'sparkles', 'speaker', 'speedboat', 'squirrel', 'star', 'star2', 'stars', 'station', 'statue_of_liberty', 'stew', 'strawberry', 'sunflower', 'sunny', 'sunrise', 'sunrise_over_mountains', 'surfer', 'sushi', 'suspect', 'sweat', 'sweat_drops', 'swimmer', 'syringe', 'tada', 'tangerine', 'taurus', 'taxi', 'tea', 'telephone', 'tennis', 'tent', 'thumbsdown', 'thumbsup', 'ticket', 'tiger', 'tm', 'toilet', 'tokyo_tower', 'tomato', 'tongue', 'top', 'tophat', 'traffic_light', 'train', 'trident', 'trophy', 'tropical_fish', 'truck', 'trumpet', 'tshirt', 'tulip', 'tv', 'u5272', 'u55b6', 'u6307', 'u6708', 'u6709', 'u6e80', 'u7121', 'u7533', 'u7a7a', 'umbrella', 'unamused', 'underage', 'unlock', 'up', 'us', 'v', 'vhs', 'vibration_mode', 'virgo', 'vs', 'walking', 'warning', 'watermelon', 'wave', 'wc', 'wedding', 'whale', 'wheelchair', 'white_square', 'wind_chime', 'wink', 'wink2', 'wolf', 'woman', 'womans_hat', 'womens', 'x', 'yellow_heart', 'zap', 'zzz'];\n\n}).call(this);\n\n})();\n//@ sourceURL=config/emoij");minispade.register('data/sponsors', "(function() {(function() {\n\n this.Travis.SPONSORS = [\n {\n type: 'platinum',\n url: \"http://www.wooga.com\",\n image: \"wooga-205x130.png\"\n }, {\n type: 'platinum',\n url: \"http://bendyworks.com\",\n image: \"bendyworks-205x130.png\"\n }, {\n type: 'platinum',\n url: \"http://cloudcontrol.com\",\n image: \"cloudcontrol-205x130.png\"\n }, {\n type: 'platinum',\n url: \"http://xing.de\",\n image: \"xing-205x130.png\"\n }, {\n type: 'gold',\n url: \"http://heroku.com\",\n image: \"heroku-205x60.png\"\n }, {\n type: 'gold',\n url: \"http://soundcloud.com\",\n image: \"soundcloud-205x60.png\"\n }, {\n type: 'gold',\n url: \"http://nedap.com\",\n image: \"nedap-205x60.png\"\n }, {\n type: 'gold',\n url: \"http://mongohq.com\",\n image: \"mongohq-205x60.png\"\n }, {\n type: 'gold',\n url: \"http://zweitag.de\",\n image: \"zweitag-205x60.png\"\n }, {\n type: 'gold',\n url: \"http://kanbanery.com\",\n image: \"kanbanery-205x60.png\"\n }, {\n type: 'gold',\n url: \"http://ticketevolution.com\",\n image: \"ticketevolution-205x60.jpg\"\n }, {\n type: 'gold',\n url: \"http://plan.io/travis\",\n image: \"planio-205x60.png\"\n }, {\n type: 'silver',\n link: \"Cobot : The one tool to run your coworking space \"\n }, {\n type: 'silver',\n link: \"JumpstartLab : We build developers \"\n }, {\n type: 'silver',\n link: \"Evil Martians : Agile Ruby on Rails development \"\n }, {\n type: 'silver',\n link: \"Zendesk : Love your helpdesk \"\n }, {\n type: 'silver',\n link: \"Stripe : Payments for developers \"\n }, {\n type: 'silver',\n link: \"Basho : We make Riak! \"\n }, {\n type: 'silver',\n link: \"Relevance : We deliver software solutions \"\n }, {\n type: 'silver',\n link: \"Mindmatters : Software für Menschen \"\n }, {\n type: 'silver',\n link: \"Amen : The best and worst of everything \"\n }, {\n type: 'silver',\n link: \"Site5 : Premium Web Hosting Solutions \"\n }, {\n type: 'silver',\n link: \"Crowd Interactive : Leading Rails consultancy in Mexico \"\n }, {\n type: 'silver',\n link: \"Atomic Object : Work with really smart people \"\n }, {\n type: 'silver',\n link: \"Codeminer : smart services for your startup \"\n }, {\n type: 'silver',\n link: \"Cloudant : grow into your data layer, not out of it \"\n }, {\n type: 'silver',\n link: \"Gidsy : Explore, organize & book unique things to do! \"\n }, {\n type: 'silver',\n link: \"5apps : Package & deploy HTML5 apps automatically \"\n }, {\n type: 'silver',\n link: \"Meltmedia : We are Interactive Superheroes \"\n }, {\n type: 'silver',\n link: \"Fingertips offers design and development services \"\n }, {\n type: 'silver',\n link: \"Engine Yard : Build epic apps, let us handle the rest \"\n }, {\n type: 'silver',\n link: \"Malwarebytes : Defeat Malware once and for all. \"\n }, {\n type: 'silver',\n link: \"Readmill : The best reading app on the iPad. \"\n }, {\n type: 'silver',\n link: \"Medidata : clinical tech improving quality of life \"\n }, {\n type: 'silver',\n link: \"ESM : Japan's best agile Ruby/Rails consultancy \"\n }, {\n type: 'silver',\n link: \"Twitter : instantly connects people everywhere \"\n }, {\n type: 'silver',\n link: \"AGiLE ANiMAL : we <3 Travis CI. \"\n }, {\n type: 'silver',\n link: \"Tupalo : Discover, review & share local businesses. \"\n }\n ];\n\n this.Travis.WORKERS = {\n \"jvm-otp1.worker.travis-ci.org\": {\n name: \"Travis Pro\",\n url: \"http://travis-ci.com\"\n },\n \"jvm-otp2.worker.travis-ci.org\": {\n name: \"Transloadit\",\n url: \"http://transloadit.com\"\n },\n \"ppp1.worker.travis-ci.org\": {\n name: \"Travis Pro\",\n url: \"http://beta.travis-ci.com\"\n },\n \"ppp2.worker.travis-ci.org\": {\n name: \"EnterpriseRails\",\n url: \"http://www.enterprise-rails.com\"\n },\n \"ppp3.worker.travis-ci.org\": {\n name: \"Alchemy CMS\",\n url: \"http://alchemy-cms.com/\"\n },\n \"rails1.worker.travis-ci.org\": {\n name: \"EnterpriseRails\",\n url: \"http://www.enterprise-rails.com\"\n },\n \"ruby1.worker.travis-ci.org\": {\n name: \"Engine Yard\",\n url: \"http://www.engineyard.com\"\n },\n \"ruby2.worker.travis-ci.org\": {\n name: \"EnterpriseRails\",\n url: \"http://www.enterprise-rails.com\"\n },\n \"ruby3.worker.travis-ci.org\": {\n name: \"Railslove\",\n url: \"http://railslove.de\"\n },\n \"ruby4.worker.travis-ci.org\": {\n name: \"Engine Yard\",\n url: \"http://www.engineyard.com\"\n },\n \"spree.worker.travis-ci.org\": {\n name: \"Spree\",\n url: \"http://spreecommerce.com\"\n },\n \"staging.worker.travis-ci.org\": {\n name: \"EnterpriseRails\",\n url: \"http://www.enterprise-rails.com\"\n }\n };\n\n}).call(this);\n\n})();\n//@ sourceURL=data/sponsors");minispade.register('ext/jquery', "(function() {(function() {\n\n $.fn.extend({\n outerHtml: function() {\n return $(this).wrap('
').parent().html();\n },\n outerElement: function() {\n return $($(this).outerHtml()).empty();\n },\n flash: function() {\n return Utils.flash(this);\n },\n unflash: function() {\n return Utils.unflash(this);\n },\n filterLog: function() {\n this.deansi();\n return this.foldLog();\n },\n deansi: function() {\n return this.html(Utils.deansi(this.html()));\n },\n foldLog: function() {\n return this.html(Utils.foldLog(this.html()));\n },\n unfoldLog: function() {\n return this.html(Utils.unfoldLog(this.html()));\n },\n updateTimes: function() {\n return Utils.updateTimes(this);\n },\n activateTab: function(tab) {\n return Utils.activateTab(this, tab);\n },\n timeInWords: function() {\n return $(this).each(function() {\n return $(this).text(Utils.timeInWords(parseInt($(this).attr('title'))));\n });\n },\n updateGithubStats: function(repo) {\n return Utils.updateGithubStats(repo, $(this));\n }\n });\n\n $.extend({\n isEmpty: function(obj) {\n if ($.isArray(obj)) {\n return !obj.length;\n } else if ($.isObject(obj)) {\n return !$.keys(obj).length;\n } else {\n return !obj;\n }\n },\n isObject: function(obj) {\n return Object.prototype.toString.call(obj) === '[object Object]';\n },\n keys: function(obj) {\n var keys;\n keys = [];\n $.each(obj, function(key) {\n return keys.push(key);\n });\n return keys;\n },\n values: function(obj) {\n var values;\n values = [];\n $.each(obj, function(key, value) {\n return values.push(value);\n });\n return values;\n },\n underscore: function(string) {\n return string[0].toLowerCase() + string.substring(1).replace(/([A-Z])?/g, function(match, chr) {\n if (chr) {\n return \"_\" + (chr.toUpperCase());\n } else {\n return '';\n }\n });\n },\n camelize: function(string, uppercase) {\n string = uppercase === false ? $.underscore(string) : $.capitalize(string);\n return string.replace(/_(.)?/g, function(match, chr) {\n if (chr) {\n return chr.toUpperCase();\n } else {\n return '';\n }\n });\n },\n capitalize: function(string) {\n return string[0].toUpperCase() + string.substring(1);\n },\n compact: function(object) {\n return $.grep(object, function(value) {\n return !!value;\n });\n },\n all: function(array, callback) {\n var args, i;\n args = Array.prototype.slice.apply(arguments);\n callback = args.pop();\n array = args.pop() || this;\n i = 0;\n while (i < array.length) {\n if (callback(array[i])) {\n return false;\n }\n i++;\n }\n return true;\n },\n detect: function(array, callback) {\n var args, i;\n args = Array.prototype.slice.apply(arguments);\n callback = args.pop();\n array = args.pop() || this;\n i = 0;\n while (i < array.length) {\n if (callback(array[i])) {\n return array[i];\n }\n i++;\n }\n },\n select: function(array, callback) {\n var args, i, result;\n args = Array.prototype.slice.apply(arguments);\n callback = args.pop();\n array = args.pop() || this;\n result = [];\n i = 0;\n while (i < array.length) {\n if (callback(array[i])) {\n result.push(array[i]);\n }\n i++;\n }\n return result;\n },\n slice: function(object, key) {\n var keys, result;\n keys = Array.prototype.slice.apply(arguments);\n object = (typeof keys[0] === 'object' ? keys.shift() : this);\n result = {};\n for (key in object) {\n if (keys.indexOf(key) > -1) {\n result[key] = object[key];\n }\n }\n return result;\n },\n only: function(object) {\n var key, keys, result;\n keys = Array.prototype.slice.apply(arguments);\n object = (typeof keys[0] === 'object' ? keys.shift() : this);\n result = {};\n for (key in object) {\n if (keys.indexOf(key) !== -1) {\n result[key] = object[key];\n }\n }\n return result;\n },\n except: function(object) {\n var key, keys, result;\n keys = Array.prototype.slice.apply(arguments);\n object = (typeof keys[0] === 'object' ? keys.shift() : this);\n result = {};\n for (key in object) {\n if (keys.indexOf(key) === -1) {\n result[key] = object[key];\n }\n }\n return result;\n },\n intersect: function(array, other) {\n return array.filter(function(element) {\n return other.indexOf(element) !== -1;\n });\n },\n map: function(elems, callback, arg) {\n var i, isArray, key, length, ret, value;\n value = void 0;\n key = void 0;\n ret = [];\n i = 0;\n length = elems.length;\n isArray = elems instanceof jQuery || length !== void 0 && typeof length === 'number' && (length > 0 && elems[0] && elems[length - 1]) || length === 0 || jQuery.isArray(elems);\n if (isArray) {\n while (i < length) {\n value = callback(elems[i], i, arg);\n if (value != null) {\n ret[ret.length] = value;\n }\n i++;\n }\n } else {\n for (key in elems) {\n value = callback(elems[key], key, arg);\n if (value != null) {\n ret[ret.length] = value;\n }\n }\n }\n return ret.concat.apply([], ret);\n },\n shuffle: function(array) {\n var current, tmp, top;\n array = array.slice();\n top = array.length;\n while (top && --top) {\n current = Math.floor(Math.random() * (top + 1));\n tmp = array[current];\n array[current] = array[top];\n array[top] = tmp;\n }\n return array;\n },\n truncate: function(string, length) {\n if (string.length > length) {\n return string.trim().substring(0, length) + '...';\n } else {\n return string;\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=ext/jquery");minispade.register('travis/ajax', "(function() {(function() {\n\n jQuery.support.cors = true;\n\n this.Travis.ajax = Em.Object.create({\n DEFAULT_OPTIONS: {\n accepts: {\n json: 'application/vnd.travis-ci.2+json'\n }\n },\n get: function(url, callback) {\n return this.ajax(url, 'get', {\n success: callback\n });\n },\n post: function(url, data, callback) {\n return this.ajax(url, 'post', {\n data: data,\n success: callback\n });\n },\n ajax: function(url, method, options) {\n var endpoint, success, token, _base,\n _this = this;\n endpoint = Travis.config.api_endpoint || '';\n options = options || {};\n if (token = sessionStorage.getItem('travis.token')) {\n options.headers || (options.headers = {});\n (_base = options.headers)['Authorization'] || (_base['Authorization'] = \"token \" + token);\n }\n options.url = \"\" + endpoint + url;\n options.type = method;\n options.dataType = 'json';\n options.contentType = 'application/json; charset=utf-8';\n options.context = this;\n if (options.data && method !== 'GET' && method !== 'get') {\n options.data = JSON.stringify(options.data);\n }\n success = options.success || (function() {});\n options.success = function(data) {\n var _ref;\n if (((_ref = Travis.app) != null ? _ref.router : void 0) && data.flash) {\n Travis.app.router.flashController.pushObjects(data.flash);\n }\n delete data.flash;\n return success.call(_this, data);\n };\n options.error = function(data) {\n if (data.flash) {\n return Travis.app.router.flashController.pushObject(data.flash);\n }\n };\n return $.ajax($.extend(options, Travis.ajax.DEFAULT_OPTIONS));\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/ajax");minispade.register('travis/expandable_record_array', "(function() {(function() {\n\n Travis.ExpandableRecordArray = DS.RecordArray.extend({\n isLoaded: false,\n isLoading: false,\n load: function(array) {\n var observer, self;\n this.set('isLoading', true);\n self = this;\n observer = function() {\n var content;\n if (this.get('isLoaded')) {\n content = self.get('content');\n array.removeObserver('isLoaded', observer);\n array.forEach(function(record) {\n return self.pushObject(record);\n });\n self.set('isLoading', false);\n return self.set('isLoaded', true);\n }\n };\n return array.addObserver('isLoaded', observer);\n },\n pushObject: function(record) {\n var clientId, id, ids;\n ids = this.get('content');\n id = record.get('id');\n clientId = record.get('clientId');\n if (ids.contains(clientId)) {\n return;\n }\n return ids.pushObject(clientId);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/expandable_record_array");minispade.register('travis/limited_array', "(function() {(function() {\n\n Travis.LimitedArray = Em.ArrayProxy.extend({\n limit: 10,\n init: function() {\n return this._super.apply(this, arguments);\n },\n arrangedContent: (function() {\n var content;\n if (content = this.get('content')) {\n return content.slice(0, this.get('limit'));\n }\n }).property('content'),\n contentArrayDidChange: function(array, index, removedCount, addedCount) {\n var addedObjects, arrangedContent, length, limit, object, _i, _len;\n this._super.apply(this, arguments);\n if (addedCount > 0) {\n addedObjects = array.slice(index, index + addedCount);\n arrangedContent = this.get('arrangedContent');\n for (_i = 0, _len = addedObjects.length; _i < _len; _i++) {\n object = addedObjects[_i];\n arrangedContent.unshiftObject(object);\n }\n limit = this.get('limit');\n length = arrangedContent.get('length');\n if (length > limit) {\n return arrangedContent.replace(limit, length - limit);\n }\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/limited_array");minispade.register('travis/location', "(function() {(function() {\n\n Travis.Location = Ember.HistoryLocation.extend({\n onUpdateURL: function(callback) {\n var guid;\n guid = Ember.guidFor(this);\n return Ember.$(window).bind('popstate.ember-location-' + guid, function(e) {\n return callback(location.pathname + location.hash);\n });\n },\n getURL: function() {\n var location;\n location = this.get('location');\n return location.pathname + location.hash;\n }\n });\n\n Ember.Location.implementations['travis'] = Travis.Location;\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/location");minispade.register('travis/log', "(function() {(function() {\n\n this.Travis.Log = {\n FOLDS: {\n schema: /(\\$ (?:bundle exec )?rake( db:create)? db:schema:load[\\s\\S]*?-- assume_migrated_upto_version[\\s\\S]*?<\\/p>\\n.*<\\/p>)/g,\n migrate: /(\\$ (?:bundle exec )?rake( db:create)? db:migrate[\\s\\S]*== +\\w+: migrated \\(.*\\) =+)/g,\n bundle: /(\\$ bundle install.*<\\/p>\\n((Updating|Using|Installing|Fetching|remote:|Receiving|Resolving).*?<\\/p>\\n|<\\/p>\\n)*)/g,\n exec: /([\\/\\w]*.rvm\\/rubies\\/[\\S]*?\\/(ruby|rbx|jruby) .*?<\\/p>)/g\n },\n filter: function(log, path) {\n log = this.escape(log);\n log = this.deansi(log);\n log = log.replace(/\\r/g, '');\n log = this.number(log, path);\n log = this.fold(log);\n log = log.replace(/\\n/g, '');\n return log;\n },\n stripPaths: function(log) {\n return log.replace(/\\/home\\/vagrant\\/builds(\\/[^\\/\\n]+){2}\\//g, '');\n },\n escape: function(log) {\n return Handlebars.Utils.escapeExpression(log);\n },\n escapeRuby: function(log) {\n return log.replace(/#<(\\w+.*?)>/, '#<$1>');\n },\n number: function(log, path) {\n var result;\n path = \"\" + path + \"/\";\n result = '';\n $.each(log.trim().split('\\n'), function(ix, line) {\n var number, pathWithNumber;\n number = ix + 1;\n pathWithNumber = \"\" + path + \"#L\" + number;\n return result += '%@ %@
\\n'.fmt(pathWithNumber, number, number, number, line);\n });\n return result.trim();\n },\n deansi: function(log) {\n var ansi, text;\n log = log.replace(/\\r\\r/g, '\\r').replace(/\\033\\[K\\r/g, '\\r').replace(/^.*\\r(?!$)/gm, '').replace(/\u001b\\[2K/g, '').replace(/\\033\\(B/g, \"\");\n ansi = ansiparse(log);\n text = '';\n ansi.forEach(function(part) {\n var classes;\n classes = [];\n part.foreground && classes.push(part.foreground);\n part.background && classes.push('bg-' + part.background);\n part.bold && classes.push('bold');\n part.italic && classes.push('italic');\n return text += (classes.length ? '' + part.text + ' ' : part.text);\n });\n return text.replace(/\\033/g, '');\n },\n fold: function(log) {\n log = this.unfold(log);\n $.each(Travis.Log.FOLDS, function(name, pattern) {\n return log = log.replace(pattern, function() {\n return '' + arguments[1].trim() + '
';\n });\n });\n return log;\n },\n unfold: function(log) {\n return log.replace(/([\\s\\S]*?)<\\/div>/g, '$1\\n');\n },\n location: function() {\n return window.location.hash;\n }\n };\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/log");minispade.register('travis/model', "(function() {(function() {\n\n this.Travis.Model = DS.Model.extend({\n primaryKey: 'id',\n id: DS.attr('number'),\n refresh: function() {\n var id, store;\n if (id = this.get('id')) {\n store = this.get('store');\n return store.adapter.find(store, this.constructor, id);\n }\n },\n update: function(attrs) {\n var _this = this;\n $.each(attrs, function(key, value) {\n if (key !== 'id') {\n return _this.set(key, value);\n }\n });\n return this;\n },\n isComplete: (function() {\n if (this.get('incomplete')) {\n this.loadTheRest();\n return false;\n } else {\n this.set('isCompleting', false);\n return this.get('isLoaded');\n }\n }).property('incomplete', 'isLoaded'),\n loadTheRest: function() {\n if (this.get('isCompleting')) {\n return;\n }\n this.set('isCompleting', true);\n return this.refresh();\n },\n select: function() {\n return this.constructor.select(this.get('id'));\n }\n });\n\n this.Travis.Model.reopenClass({\n find: function() {\n if (arguments.length === 0) {\n return Travis.app.store.findAll(this);\n } else {\n return this._super.apply(this, arguments);\n }\n },\n filter: function(callback) {\n return Travis.app.store.filter(this, callback);\n },\n load: function(attrs) {\n return Travis.app.store.load(this, attrs);\n },\n select: function(id) {\n return this.find().forEach(function(record) {\n return record.set('selected', record.get('id') === id);\n });\n },\n buildURL: function(suffix) {\n var base, url;\n base = this.url || this.pluralName();\n Ember.assert('Base URL (' + base + ') must not start with slash', !base || base.toString().charAt(0) !== '/');\n Ember.assert('URL suffix (' + suffix + ') must not start with slash', !suffix || suffix.toString().charAt(0) !== '/');\n url = [base];\n if (suffix !== void 0) {\n url.push(suffix);\n }\n return url.join('/');\n },\n singularName: function() {\n var name, parts;\n parts = this.toString().split('.');\n name = parts[parts.length - 1];\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().slice(1);\n },\n pluralName: function() {\n return Travis.app.store.adapter.pluralize(this.singularName());\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/model");minispade.register('travis/ticker', "(function() {(function() {\n\n this.Travis.Ticker = Ember.Object.extend({\n init: function() {\n if (this.get('interval') !== -1) {\n return this.schedule();\n }\n },\n tick: function() {\n var context, target, targets, _i, _len;\n context = this.get('context');\n targets = this.get('targets') || [this.get('target')];\n for (_i = 0, _len = targets.length; _i < _len; _i++) {\n target = targets[_i];\n if (context) {\n target = context.get(target);\n }\n if (target) {\n target.tick();\n }\n }\n return this.schedule();\n },\n schedule: function() {\n var _this = this;\n return Ember.run.later((function() {\n return _this.tick();\n }), this.get('interval') || Travis.app.TICK_INTERVAL);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/ticker");minispade.register('travis', "(function() {(function() {\nminispade.require('ext/jquery');\nminispade.require('ext/ember/namespace');\n\n this.Travis = Em.Namespace.create({\n config: {\n api_endpoint: $('meta[rel=\"travis.api_endpoint\"]').attr('href'),\n pusher_key: $('meta[name=\"travis.pusher_key\"]').attr('value')\n },\n CONFIG_KEYS: ['rvm', 'gemfile', 'env', 'jdk', 'otp_release', 'php', 'node_js', 'perl', 'python', 'scala'],\n ROUTES: {\n 'profile/:login/me': ['profile', 'user'],\n 'profile/:login': ['profile', 'hooks'],\n 'profile': ['profile', 'hooks'],\n 'stats': ['stats', 'show'],\n ':owner/:name/jobs/:id/:line': ['home', 'job'],\n ':owner/:name/jobs/:id': ['home', 'job'],\n ':owner/:name/builds/:id': ['home', 'build'],\n ':owner/:name/builds': ['home', 'builds'],\n ':owner/:name/pull_requests': ['home', 'pullRequests'],\n ':owner/:name/branches': ['home', 'branches'],\n ':owner/:name': ['home', 'current'],\n '': ['home', 'index'],\n '#': ['home', 'index']\n },\n QUEUES: [\n {\n name: 'common',\n display: 'Common'\n }, {\n name: 'php',\n display: 'PHP, Perl and Python'\n }, {\n name: 'node_js',\n display: 'Node.js'\n }, {\n name: 'jvmotp',\n display: 'JVM and Erlang'\n }, {\n name: 'rails',\n display: 'Rails'\n }, {\n name: 'spree',\n display: 'Spree'\n }\n ],\n INTERVALS: {\n sponsors: -1,\n times: -1,\n updateTimes: 1000\n },\n setLocale: function(locale) {\n if (!locale) {\n return;\n }\n I18n.locale = locale;\n return localStorage.setItem('travis.config.locale', locale);\n },\n run: function(attrs) {\n if (location.hash.slice(0, 2) === '#!') {\n location.href = location.href.replace('#!/', '');\n }\n this.setLocale(localStorage.getItem('travis.config.locale'));\n return Ember.run.next(this, function() {\n var app,\n _this = this;\n app = Travis.App.create(attrs || {});\n $.each(Travis, function(key, value) {\n if (value && value.isClass && key !== 'constructor') {\n return app[key] = value;\n }\n });\n this.app = app;\n this.store = app.store;\n return $(function() {\n return app.initialize();\n });\n });\n }\n });\nminispade.require('travis/ajax');\nminispade.require('app');\n\n}).call(this);\n\n})();\n//@ sourceURL=travis");minispade.register('templates', "(function() {\nEmber.TEMPLATES['application'] = Ember.Handlebars.compile(\"{{outlet}}\\n\");\n\nEmber.TEMPLATES['auth/signin'] = Ember.Handlebars.compile(\"{{#if view.signingIn}}\\n
Signing in ... \\n
\\n Trying to authenticate with GitHub.\\n
\\n{{else}}\\n
Sign in \\n
\\n Please sign in with GitHub. \\n
\\n{{/if}}\\n\\n\\n\");\n\nEmber.TEMPLATES['builds/list'] = Ember.Handlebars.compile(\"{{#if builds.isLoaded}}\\n
\\n \\n \\n {{t builds.name}} \\n {{t builds.commit}} \\n {{t builds.message}} \\n {{t builds.duration}} \\n {{t builds.finished_at}} \\n \\n \\n\\n \\n {{#each build in builds}}\\n {{#view Travis.BuildsItemView contextBinding=\\\"build\\\"}}\\n \\n \\n {{#if id}}\\n \\n {{number}}\\n \\n {{/if}}\\n \\n \\n \\n {{formatCommit commit}}\\n \\n \\n \\n {{{formatMessage commit.message short=\\\"true\\\"}}}\\n \\n \\n {{formatDuration duration}}\\n \\n \\n {{formatTime finishedAt}}\\n \\n {{/view}}\\n {{/each}}\\n \\n
\\n
\\n {{view view.ShowMoreButton}}\\n
\\n{{else}}\\n
Loading
\\n{{/if}}\\n\");\n\nEmber.TEMPLATES['builds/show'] = Ember.Handlebars.compile(\"{{#with view}}\\n {{#if loading}}\\n
Loading \\n {{else}}\\n
\\n \\n
{{t builds.name}} \\n
\\n \\n {{#if build.id}}\\n {{build.number}} \\n {{/if}}\\n \\n
{{t builds.finished_at}} \\n
{{formatTime build.finishedAt}} \\n
{{t builds.duration}} \\n
{{formatDuration build.duration}} \\n
\\n\\n \\n\\n {{t builds.message}} \\n {{{formatMessage build.commit.message}}} \\n\\n {{#unless isMatrix}}\\n {{t builds.config}} \\n {{formatConfig build.config}} \\n {{/unless}}\\n \\n\\n {{#if build.isMatrix}}\\n {{view Travis.JobsView jobsBinding=\\\"build.requiredJobs\\\" required=\\\"true\\\"}}\\n {{view Travis.JobsView jobsBinding=\\\"build.allowedFailureJobs\\\"}}\\n {{else}}\\n {{view Travis.LogView contextBinding=\\\"build.jobs.firstObject\\\"}}\\n {{/if}}\\n {{/if}}\\n{{/with}}\\n\");\n\nEmber.TEMPLATES['events/list'] = Ember.Handlebars.compile(\"{{#if view.events.isLoaded}}\\n
\\n \\n \\n Time \\n Message \\n \\n \\n\\n \\n {{#each event in view.events}}\\n {{#view Travis.EventsItemView contextBinding=\\\"event\\\"}}\\n \\n {{formatTime createdAt}}\\n \\n \\n {{event.message}}\\n \\n {{/view}}\\n {{/each}}\\n \\n
\\n{{else}}\\n
Loading
\\n{{/if}}\\n\\n\");\n\nEmber.TEMPLATES['jobs/list'] = Ember.Handlebars.compile(\"{{#if view.jobs.length}}\\n {{#if view.required}}\\n
\\n \\n {{t jobs.build_matrix}}\\n \\n {{else}}\\n \\n \\n {{t jobs.allowed_failures}}\\n \\n \\n {{/if}}\\n \\n \\n {{#each key in view.build.configKeys}}\\n {{key}} \\n {{/each}}\\n \\n \\n \\n {{#each job in view.jobs}}\\n {{#view Travis.JobsItemView contextBinding=\\\"job\\\"}}\\n \\n \\n {{#if job.id}}\\n {{number}} \\n {{/if}}\\n \\n \\n {{formatDuration duration}}\\n \\n \\n {{formatTime finishedAt}}\\n \\n {{#each value in configValues}}\\n {{value}} \\n {{/each}}\\n {{/view}}\\n {{/each}}\\n \\n
\\n\\n {{#unless view.required}}\\n \\n {{/unless}}\\n{{/if}}\\n\");\n\nEmber.TEMPLATES['jobs/log'] = Ember.Handlebars.compile(\"{{view.logSubscriber}}\\n\\n{{#if log.isLoaded}}\\n \\n \\n Follow logs \\n {{{formatLog log.body repo=\\\"repository\\\" item=\\\"parentView.currentItem\\\"}}} \\n\\n {{#if sponsor.name}}\\n \\n {{/if}}\\n\\n To top \\n{{else}}\\n \\n Loading \\n
\\n{{/if}}\\n\");\n\nEmber.TEMPLATES['jobs/show'] = Ember.Handlebars.compile(\"{{#with view}}\\n {{#if job.isComplete}}\\n \\n
\\n \\n
Job \\n
\\n \\n {{#if job.id}}\\n {{job.number}} \\n {{/if}}\\n \\n
{{t jobs.finished_at}} \\n
{{formatTime job.finishedAt}} \\n
{{t jobs.duration}} \\n
{{formatDuration job.duration}} \\n
\\n\\n \\n\\n {{t jobs.message}} \\n {{formatMessage commit.message}} \\n {{t jobs.config}} \\n {{formatConfig job.config}} \\n \\n\\n {{view Travis.LogView contextBinding=\\\"job\\\"}}}\\n
\\n {{else}}\\n \\n Loading \\n
\\n {{/if}}\\n{{/with}}\\n\");\n\nEmber.TEMPLATES['layouts/flash'] = Ember.Handlebars.compile(\"{{#each flash in controller}}\\n {{#view Travis.FlashItemView flashBinding=\\\"flash\\\"}}\\n {{view.message}}
\\n \\n {{/view}}\\n{{/each}}\\n\");\n\nEmber.TEMPLATES['layouts/home'] = Ember.Handlebars.compile(\"\\n {{outlet top}}\\n
\\n\\n\\n
\\n {{outlet left}}\\n
\\n\\n
\\n {{outlet flash}}\\n {{outlet main}}\\n
\\n\\n
\\n {{outlet right}}\\n
\\n
\\n\");\n\nEmber.TEMPLATES['layouts/profile'] = Ember.Handlebars.compile(\"\\n {{outlet top}}\\n
\\n\\n\\n
\\n {{outlet left}}\\n
\\n\\n
\\n {{outlet flash}}\\n {{outlet main}}\\n
\\n\\n
\\n
\\n\");\n\nEmber.TEMPLATES['layouts/sidebar'] = Ember.Handlebars.compile(\"\\n {{t layouts.application.fork_me}}\\n \\n\\n\\n\\n{{view view.DecksView}}\\n{{view view.WorkersView}}\\n{{view view.QueuesView}}\\n{{view view.LinksView}}\\n\\n\\n
{{t layouts.about.join}} \\n
\\n
\\n\");\n\nEmber.TEMPLATES['layouts/simple'] = Ember.Handlebars.compile(\"\\n {{outlet top}}\\n
\\n\\n\\n
\\n {{outlet flash}}\\n {{outlet main}}\\n
\\n
\\n\\n\");\n\nEmber.TEMPLATES['layouts/top'] = Ember.Handlebars.compile(\"\\n Travis \\n \\n\\n\\n\");\n\nEmber.TEMPLATES['profile/accounts'] = Ember.Handlebars.compile(\"\\n
\\n\\n\\n\\n\\n {{#collection Travis.AccountsListView contentBinding=\\\"controller\\\"}}\\n
{{view.name}} \\n
\\n Repositories: \\n {{view.account.reposCount}} \\n
\\n
\\n {{/collection}}\\n
\\n\");\n\nEmber.TEMPLATES['profile/show'] = Ember.Handlebars.compile(\"{{view.name}} \\n\\n{{view Travis.ProfileTabsView}}\\n\\n\\n {{outlet pane}}\\n
\\n\\n\");\n\nEmber.TEMPLATES['profile/tabs'] = Ember.Handlebars.compile(\"\\n \\n \\n \\n {{#if view.displayUser}}\\n \\n \\n \\n {{/if}}\\n \\n\");\n\nEmber.TEMPLATES['profile/tabs/hooks'] = Ember.Handlebars.compile(\"\\n {{{t profiles.show.message.your_repos}}}\\n
\\n\\n{{#if hooks.isLoaded}}\\n {{#if user.isSyncing}}\\n \\n Please wait while we sync from GitHub \\n
\\n {{else}}\\n \\n Last synchronized from GitHub: {{formatTime user.syncedAt}}\\n \\n Sync now\\n \\n
\\n\\n \\n {{#each hook in hooks}}\\n \\n {{hook.slug}} \\n {{hook.description}}
\\n\\n \\n \\n {{else}}\\n \\n You do not seem to have any repositories that we could sync.\\n \\n {{/each}}\\n \\n {{/if}}\\n{{else}}\\n \\n Loading \\n
\\n{{/if}}\\n\\n\\n\");\n\nEmber.TEMPLATES['profile/tabs/user'] = Ember.Handlebars.compile(\" \\n\\n\\n \\n {{t profiles.show.github}}:\\n \\n \\n {{user.login}} \\n \\n \\n {{t profiles.show.email}}:\\n \\n \\n {{user.email}}\\n \\n \\n {{t profiles.show.token}}:\\n \\n \\n {{user.token}}\\n \\n \\n\\n\\n\\n\\n\");\n\nEmber.TEMPLATES['queues/list'] = Ember.Handlebars.compile(\"\\n{{#each queue in controller}}\\n \\n {{t queue}}: {{queue.name}} \\n \\n \\n{{/each}}\\n \\n\");\n\nEmber.TEMPLATES['repos/list'] = Ember.Handlebars.compile(\"\\n {{view Ember.TextField valueBinding=\\\"controller.search\\\"}}\\n
\\n\\n{{view Travis.ReposListTabsView}}\\n\\n \\n\\n\\n {{#collection Travis.ReposListView contentBinding=\\\"controller\\\"}}\\n {{#with view.repo}}\\n
\\n
\\n {{#if slug}}\\n
{{slug}} \\n {{/if}}\\n
\\n {{#if lastBuildId}}\\n
{{lastBuildNumber}} \\n {{/if}}\\n\\n
\\n {{t repositories.duration}}: \\n {{formatDuration lastBuildDuration}} ,\\n {{t repositories.finished_at}}: \\n {{formatTime lastBuildFinishedAt}} \\n
\\n\\n
\\n\\n {{#if description}}\\n
\\n {{/if}}\\n {{/with}}\\n {{else}}\\n
\\n {{/collection}}\\n
\\n\");\n\nEmber.TEMPLATES['repos/list/tabs'] = Ember.Handlebars.compile(\"\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n\\n\");\n\nEmber.TEMPLATES['repos/show'] = Ember.Handlebars.compile(\"\\n {{#if view.isEmpty}}\\n {{view Travis.ReposEmptyView}}\\n {{else}}\\n {{#if view.repo.isComplete}}\\n {{#with view.repo}}\\n
\\n\\n
{{description}}
\\n\\n
\\n\\n {{view Travis.RepoShowTabsView}}\\n {{view Travis.RepoShowToolsView}}\\n {{/with}}\\n\\n {{else}}\\n
Loading \\n {{/if}}\\n\\n
\\n {{outlet pane}}\\n
\\n {{/if}}\\n
\\n\\n\");\n\nEmber.TEMPLATES['repos/show/tabs'] = Ember.Handlebars.compile(\"\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n {{#if view.repo.slug}}\\n \\n Events\\n \\n {{/if}}\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n\");\n\nEmber.TEMPLATES['repos/show/tools'] = Ember.Handlebars.compile(\"\\n\\n\\n\");\n\nEmber.TEMPLATES['sponsors/decks'] = Ember.Handlebars.compile(\"{{t layouts.application.sponsers}} \\n\\n\\n\\n\\n \\n {{{t layouts.application.sponsors_link}}}\\n \\n
\\n\");\n\nEmber.TEMPLATES['sponsors/links'] = Ember.Handlebars.compile(\"\\n\\n\");\n\nEmber.TEMPLATES['stats/show'] = Ember.Handlebars.compile(\"Sorry \\nStatistics are disabled for now.
\\n We're looking into a solution. If you want to help, please ping us!
\\n\");\n\nEmber.TEMPLATES['workers/list'] = Ember.Handlebars.compile(\"{{#view Travis.WorkersView}}\\n \\n {{t workers}}\\n \\n \\n \\n {{#each group in controller.groups}}\\n {{#view Travis.WorkersListView}}\\n \\n \\n {{group.firstObject.host}}\\n \\n \\n {{#each worker in group}}\\n {{#view Travis.WorkersItemView workerBinding=\\\"worker\\\"}}\\n \\n
\\n {{#if worker.isWorking}}\\n {{#if worker.job_id}}\\n \\n {{view.display}}\\n \\n {{/if}}\\n {{else}}\\n {{view.display}}\\n {{/if}}\\n \\n {{/view}}\\n {{/each}}\\n \\n \\n {{/view}}\\n {{else}}\\n No workers\\n {{/each}}\\n \\n{{/view}}\\n\");\n\n})();\n//@ sourceURL=templates");minispade.register('config/locales', "(function() {window.I18n = window.I18n || {}\nwindow.I18n.translations = {\"ca\":{\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"fr\":\"Français\",\"ja\":\"日本語\",\"nb\":\"Norsk Bokmål\",\"nl\":\"Nederlands\",\"pl\":\"Polski\",\"pt-BR\":\"português brasileiro\",\"ru\":\"Русский\"}},\"en\":{\"errors\":{\"messages\":{\"not_found\":\"not found\",\"already_confirmed\":\"was already confirmed\",\"not_locked\":\"was not locked\"}},\"devise\":{\"failure\":{\"unauthenticated\":\"You need to sign in or sign up before continuing.\",\"unconfirmed\":\"You have to confirm your account before continuing.\",\"locked\":\"Your account is locked.\",\"invalid\":\"Invalid email or password.\",\"invalid_token\":\"Invalid authentication token.\",\"timeout\":\"Your session expired, please sign in again to continue.\",\"inactive\":\"Your account was not activated yet.\"},\"sessions\":{\"signed_in\":\"Signed in successfully.\",\"signed_out\":\"Signed out successfully.\"},\"passwords\":{\"send_instructions\":\"You will receive an email with instructions about how to reset your password in a few minutes.\",\"updated\":\"Your password was changed successfully. You are now signed in.\"},\"confirmations\":{\"send_instructions\":\"You will receive an email with instructions about how to confirm your account in a few minutes.\",\"confirmed\":\"Your account was successfully confirmed. You are now signed in.\"},\"registrations\":{\"signed_up\":\"You have signed up successfully. If enabled, a confirmation was sent to your e-mail.\",\"updated\":\"You updated your account successfully.\",\"destroyed\":\"Bye! Your account was successfully cancelled. We hope to see you again soon.\"},\"unlocks\":{\"send_instructions\":\"You will receive an email with instructions about how to unlock your account in a few minutes.\",\"unlocked\":\"Your account was successfully unlocked. You are now signed in.\"},\"mailer\":{\"confirmation_instructions\":{\"subject\":\"Confirmation instructions\"},\"reset_password_instructions\":{\"subject\":\"Reset password instructions\"},\"unlock_instructions\":{\"subject\":\"Unlock Instructions\"}}},\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} hour\",\"other\":\"%{count} hours\"},\"minutes_exact\":{\"one\":\"%{count} minute\",\"other\":\"%{count} minutes\"},\"seconds_exact\":{\"one\":\"%{count} second\",\"other\":\"%{count} seconds\"}}},\"workers\":\"Workers\",\"queue\":\"Queue\",\"no_job\":\"There are no jobs\",\"repositories\":{\"branch\":\"Branch\",\"image_url\":\"Image URL\",\"markdown\":\"Markdown\",\"textile\":\"Textile\",\"rdoc\":\"RDOC\",\"commit\":\"Commit\",\"message\":\"Message\",\"started_at\":\"Started\",\"duration\":\"Duration\",\"finished_at\":\"Finished\",\"tabs\":{\"current\":\"Current\",\"build_history\":\"Build History\",\"branches\":\"Branch Summary\",\"pull_requests\":\"Pull Requests\",\"build\":\"Build\",\"job\":\"Job\"}},\"build\":{\"job\":\"Job\",\"duration\":\"Duration\",\"finished_at\":\"Finished\"},\"jobs\":{\"messages\":{\"sponsored_by\":\"This test suite was run on a worker box sponsored by\"},\"build_matrix\":\"Build Matrix\",\"allowed_failures\":\"Allowed Failures\",\"author\":\"Author\",\"config\":\"Config\",\"compare\":\"Compare\",\"committer\":\"Committer\",\"branch\":\"Branch\",\"commit\":\"Commit\",\"message\":\"Message\",\"started_at\":\"Started\",\"duration\":\"Duration\",\"finished_at\":\"Finished\"},\"builds\":{\"name\":\"Build\",\"messages\":{\"sponsored_by\":\"This test suite was run on a worker box sponsored by\"},\"build_matrix\":\"Build Matrix\",\"allowed_failures\":\"Allowed Failures\",\"author\":\"Author\",\"config\":\"Config\",\"compare\":\"Compare\",\"committer\":\"Committer\",\"branch\":\"Branch\",\"commit\":\"Commit\",\"message\":\"Message\",\"started_at\":\"Started\",\"duration\":\"Duration\",\"finished_at\":\"Finished\",\"show_more\":\"Show more\"},\"layouts\":{\"top\":{\"home\":\"Home\",\"blog\":\"Blog\",\"docs\":\"Docs\",\"stats\":\"Stats\",\"github_login\":\"Sign in with Github\",\"profile\":\"Profile\",\"sign_out\":\"Sign Out\",\"admin\":\"Admin\"},\"application\":{\"fork_me\":\"Fork me on Github\",\"recent\":\"Recent\",\"search\":\"Search\",\"sponsers\":\"Sponsors\",\"sponsors_link\":\"See all of our amazing sponsors →\",\"my_repositories\":\"My Repositories\"},\"about\":{\"alpha\":\"This stuff is alpha.\",\"messages\":{\"alpha\":\"Please do not consider this a stable service. We're still far from that! More info here. \"},\"join\":\"Join us and help!\",\"mailing_list\":\"Mailing List\",\"repository\":\"Repository\",\"twitter\":\"Twitter\"},\"mobile\":{\"author\":\"Author\",\"build\":\"Build\",\"build_matrix\":\"Build Matrix\",\"commit\":\"Commit\",\"committer\":\"Committer\",\"compare\":\"Compare\",\"config\":\"Config\",\"duration\":\"Duration\",\"finished_at\":\"Finished at\",\"job\":\"Job\",\"log\":\"Log\"}},\"profiles\":{\"show\":{\"email\":\"Email\",\"github\":\"Github\",\"message\":{\"your_repos\":\" Flick the switches below to turn on the Travis service hook for your projects, then push to GitHub.\",\"config\":\"how to configure custom build options\"},\"messages\":{\"notice\":\"To get started, please read our Getting Started guide .\\n It will only take a couple of minutes. \"},\"token\":\"Token\",\"your_repos\":\"Your Repositories\",\"update\":\"Update\",\"update_locale\":\"Update\",\"your_locale\":\"Your Locale\"}},\"statistics\":{\"index\":{\"count\":\"Count\",\"repo_growth\":\"Repository Growth\",\"total_projects\":\"Total Projects/Repositories\",\"build_count\":\"Build Count\",\"last_month\":\"last month\",\"total_builds\":\"Total Builds\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"fr\":\"Français\",\"ja\":\"日本語\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"ru\":\"Русский\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}},\"es\":{\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} hora\",\"other\":\"%{count} horas\"},\"minutes_exact\":{\"one\":\"%{count} minuto\",\"other\":\"%{count} minutos\"},\"seconds_exact\":{\"one\":\"%{count} segundo\",\"other\":\"%{count} segundos\"}}},\"workers\":\"Procesos\",\"queue\":\"Cola\",\"no_job\":\"No hay trabajos\",\"repositories\":{\"branch\":\"Rama\",\"image_url\":\"Imagen URL\",\"markdown\":\"Markdown\",\"textile\":\"Textile\",\"rdoc\":\"RDOC\",\"commit\":\"Commit\",\"message\":\"Mensaje\",\"started_at\":\"Iniciado\",\"duration\":\"Duración\",\"finished_at\":\"Finalizado\",\"tabs\":{\"current\":\"Actual\",\"build_history\":\"Histórico\",\"branches\":\"Ramas\",\"build\":\"Builds\",\"job\":\"Trabajo\"}},\"build\":{\"job\":\"Trabajo\",\"duration\":\"Duración\",\"finished_at\":\"Finalizado\"},\"jobs\":{\"messages\":{\"sponsored_by\":\"Esta serie de tests han sido ejecutados en una caja de Proceso patrocinada por\"},\"build_matrix\":\"Matriz de Builds\",\"allowed_failures\":\"Fallos Permitidos\",\"author\":\"Autor\",\"config\":\"Configuración\",\"compare\":\"Comparar\",\"committer\":\"Committer\",\"branch\":\"Rama\",\"commit\":\"Commit\",\"message\":\"Mensaje\",\"started_at\":\"Iniciado\",\"duration\":\"Duración\",\"finished_at\":\"Finalizado\",\"sponsored_by\":\"Patrocinado por\"},\"builds\":{\"name\":\"Build\",\"messages\":{\"sponsored_by\":\"Esta serie de tests han sido ejecutados en una caja de Proceso patrocinada por\"},\"build_matrix\":\"Matriz de Builds\",\"allowed_failures\":\"Fallos Permitidos\",\"author\":\"Autor\",\"config\":\"Configuración\",\"compare\":\"Comparar\",\"committer\":\"Committer\",\"branch\":\"Rama\",\"commit\":\"Commit\",\"message\":\"Mensaje\",\"started_at\":\"Iniciado\",\"duration\":\"Duración\",\"finished_at\":\"Finalizado\"},\"layouts\":{\"top\":{\"home\":\"Inicio\",\"blog\":\"Blog\",\"docs\":\"Documentación\",\"stats\":\"Estadísticas\",\"github_login\":\"Iniciar sesión con Github\",\"profile\":\"Perfil\",\"sign_out\":\"Desconectar\",\"admin\":\"Admin\"},\"application\":{\"fork_me\":\"Hazme un Fork en Github\",\"recent\":\"Reciente\",\"search\":\"Buscar\",\"sponsers\":\"Patrocinadores\",\"sponsors_link\":\"Ver todos nuestros patrocinadores →\",\"my_repositories\":\"Mis Repositorios\"},\"about\":{\"alpha\":\"Esto es alpha.\",\"messages\":{\"alpha\":\"Por favor no considereis esto un servicio estable. Estamos estamos aún lejos de ello! Más información aquí. \"},\"join\":\"Únetenos y ayudanos!\",\"mailing_list\":\"Lista de Correos\",\"repository\":\"Repositorio\",\"twitter\":\"Twitter\"}},\"profiles\":{\"show\":{\"email\":\"Correo electrónico\",\"github\":\"Github\",\"message\":{\"your_repos\":\" Activa los interruptores para inicial el Travis service hook para tus proyectos, y haz un Push en GitHub. \\n Para probar varias versiones de ruby, mira\",\"config\":\"como configurar tus propias opciones para el Build\"},\"messages\":{\"notice\":\"Para comenzar, por favor lee nuestra Guía de Inicio .\\n Solo tomará unos pocos minutos. \"},\"token\":\"Token\",\"your_repos\":\"Tus repositorios\",\"update\":\"Actualizar\",\"update_locale\":\"Actualizar\",\"your_locale\":\"Tu Idioma\"}},\"statistics\":{\"index\":{\"count\":\"Número\",\"repo_growth\":\"Crecimiento de Repositorios\",\"total_projects\":\"Total de Proyectos/Repositorios\",\"build_count\":\"Número de Builds\",\"last_month\":\"mes anterior\",\"total_builds\":\"Total de Builds\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"fr\":\"Français\",\"ja\":\"日本語\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"ru\":\"Русский\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}},\"fr\":{\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} heure\",\"other\":\"%{count} heures\"},\"minutes_exact\":{\"one\":\"%{count} minute\",\"other\":\"%{count} minutes\"},\"seconds_exact\":{\"one\":\"%{count} seconde\",\"other\":\"%{count} secondes\"}}},\"workers\":\"Processus\",\"queue\":\"File\",\"no_job\":\"Pas de tâches\",\"repositories\":{\"branch\":\"Branche\",\"image_url\":\"Image\",\"markdown\":\"Markdown\",\"textile\":\"Textile\",\"rdoc\":\"RDOC\",\"commit\":\"Commit\",\"message\":\"Message\",\"started_at\":\"Commencé\",\"duration\":\"Durée\",\"finished_at\":\"Terminé\",\"tabs\":{\"current\":\"Actuel\",\"build_history\":\"Historique des tâches\",\"branches\":\"Résumé des branches\",\"build\":\"Construction\",\"job\":\"Tâche\"}},\"build\":{\"job\":\"Tâche\",\"duration\":\"Durée\",\"finished_at\":\"Terminé\"},\"jobs\":{\"messages\":{\"sponsored_by\":\"Cette série de tests a été exécutée sur une machine sponsorisée par\"},\"build_matrix\":\"Matrice des versions\",\"allowed_failures\":\"Échecs autorisés\",\"author\":\"Auteur\",\"config\":\"Config\",\"compare\":\"Comparer\",\"committer\":\"Committeur\",\"branch\":\"Branche\",\"commit\":\"Commit\",\"message\":\"Message\",\"started_at\":\"Commencé\",\"duration\":\"Durée\",\"finished_at\":\"Terminé\",\"sponsored_by\":\"Cette série de tests a été exécutée sur une machine sponsorisée par\"},\"builds\":{\"name\":\"Version\",\"messages\":{\"sponsored_by\":\"Cette série de tests a été exécutée sur une machine sponsorisée par\"},\"build_matrix\":\"Matrice des versions\",\"allowed_failures\":\"Échecs autorisés\",\"author\":\"Auteur\",\"config\":\"Config\",\"compare\":\"Comparer\",\"committer\":\"Committeur\",\"branch\":\"Branche\",\"commit\":\"Commit\",\"message\":\"Message\",\"started_at\":\"Commencé\",\"duration\":\"Durée\",\"finished_at\":\"Terminé\"},\"layouts\":{\"top\":{\"home\":\"Accueil\",\"blog\":\"Blog\",\"docs\":\"Documentation\",\"stats\":\"Statistiques\",\"github_login\":\"Connection Github\",\"profile\":\"Profil\",\"sign_out\":\"Déconnection\",\"admin\":\"Admin\"},\"application\":{\"fork_me\":\"Faites un Fork sur Github\",\"recent\":\"Récent\",\"search\":\"Chercher\",\"sponsers\":\"Sponsors\",\"sponsors_link\":\"Voir tous nos extraordinaire sponsors →\",\"my_repositories\":\"Mes dépôts\"},\"about\":{\"alpha\":\"Ceci est en alpha.\",\"messages\":{\"alpha\":\"S'il vous plaît ne considérez pas ce service comme étant stable. Nous sommes loin de ça! Plus d'infos ici. \"},\"join\":\"Joignez-vous à nous et aidez-nous!\",\"mailing_list\":\"Liste de distribution\",\"repository\":\"Dépôt\",\"twitter\":\"Twitter\"},\"mobile\":{\"author\":\"Auteur\",\"build\":\"Version\",\"build_matrix\":\"Matrice des versions\",\"commit\":\"Commit\",\"committer\":\"Committeur\",\"compare\":\"Comparer\",\"config\":\"Config\",\"duration\":\"Durée\",\"finished_at\":\"Terminé à\",\"job\":\"Tâche\",\"log\":\"Journal\"}},\"profiles\":{\"show\":{\"github\":\"Github\",\"message\":{\"your_repos\":\"Utilisez les boutons ci-dessous pour activer Travis sur vos projets puis déployez sur GitHub. \\nPour tester sur plus de versions de ruby, voir\",\"config\":\"comment configurer des options de version personnalisées\"},\"messages\":{\"notice\":\"Pour commencer, veuillez lire notre guide de démarrage .\\n Cela ne vous prendra que quelques minutes. \"},\"token\":\"Jeton\",\"your_repos\":\"Vos dépôts\",\"email\":\"Courriel\",\"update\":\"Modifier\",\"update_locale\":\"Modifier\",\"your_locale\":\"Votre langue\"}},\"statistics\":{\"index\":{\"count\":\"Décompte\",\"repo_growth\":\"Croissance de dépôt\",\"total_projects\":\"Total des projets/dépôts\",\"build_count\":\"Décompte des versions\",\"last_month\":\"mois dernier\",\"total_builds\":\"Total des versions\"}},\"admin\":{\"actions\":{\"create\":\"créer\",\"created\":\"créé\",\"delete\":\"supprimer\",\"deleted\":\"supprimé\",\"update\":\"mise à jour\",\"updated\":\"mis à jour\"},\"credentials\":{\"log_out\":\"Déconnection\"},\"delete\":{\"confirmation\":\"Oui, je suis sure\",\"flash_confirmation\":\"%{name} a été détruit avec succès\"},\"flash\":{\"error\":\"%{name} n'a pas pu être %{action}\",\"noaction\":\"Aucune action n'a été entreprise\",\"successful\":\"%{name} a réussi à %{action}\"},\"history\":{\"name\":\"Historique\",\"no_activity\":\"Aucune activité\",\"page_name\":\"Historique pour %{name}\"},\"list\":{\"add_new\":\"Ajouter un nouveau\",\"delete_action\":\"Supprimer\",\"delete_selected\":\"Supprimer la sélection\",\"edit_action\":\"Modifier\",\"search\":\"Rechercher\",\"select\":\"Sélectionner le %{name} à modifier\",\"select_action\":\"Sélectionner\",\"show_all\":\"Montrer tout\"},\"new\":{\"basic_info\":\"Information de base\",\"cancel\":\"Annuler\",\"chosen\":\"%{name} choisi\",\"chose_all\":\"Choisir tout\",\"clear_all\":\"Déselectionner tout\",\"many_chars\":\"caractères ou moins\",\"one_char\":\"caractère.\",\"optional\":\"Optionnel\",\"required\":\"Requis\",\"save\":\"Sauvegarder\",\"save_and_add_another\":\"Sauvegarder et en ajouter un autre\",\"save_and_edit\":\"Sauvegarder et modifier\",\"select_choice\":\"Faites vos choix et cliquez\"},\"dashboard\":{\"add_new\":\"Ajouter un nouveau\",\"last_used\":\"Dernière utilisation\",\"model_name\":\"Nom du modèle\",\"modify\":\"Modification\",\"name\":\"Tableau de bord\",\"pagename\":\"Administration du site\",\"records\":\"Enregistrements\",\"show\":\"Voir\",\"ago\":\"plus tôt\"}},\"home\":{\"name\":\"accueil\"},\"repository\":{\"duration\":\"Durée\"},\"devise\":{\"confirmations\":{\"confirmed\":\"Votre compte a été crée avec succès. Vous être maintenant connecté.\",\"send_instructions\":\"Vous allez recevoir un courriel avec les instructions de confirmation de votre compte dans quelques minutes.\"},\"failure\":{\"inactive\":\"Votre compte n'a pas encore été activé.\",\"invalid\":\"Adresse courriel ou mot de passe invalide.\",\"invalid_token\":\"Jeton d'authentification invalide.\",\"locked\":\"Votre compte est bloqué.\",\"timeout\":\"Votre session est expirée, veuillez vous reconnecter pour continuer.\",\"unauthenticated\":\"Vous devez vous connecter ou vous enregistrer afin de continuer\",\"unconfirmed\":\"Vous devez confirmer votre compte avant de continuer.\"},\"mailer\":{\"confirmation_instructions\":{\"subject\":\"Instructions de confirmations\"},\"reset_password_instructions\":{\"subject\":\"Instruction de remise à zéro du mot de passe\"},\"unlock_instructions\":{\"subject\":\"Instruction de débloquage\"}},\"passwords\":{\"send_instructions\":\"Vous recevrez un courriel avec les instructions de remise à zéro du mot de passe dans quelques minutes.\",\"updated\":\"Votre mot de passe a été changé avec succès. Vous êtes maintenant connecté.\"},\"registrations\":{\"destroyed\":\"Au revoir! Votre compte a été annulé avec succès. Nous espérons vous revoir bientôt.\",\"signed_up\":\"Vous êtes enregistré avec succès. Si activé, une confirmation vous a été envoyé par courriel.\",\"updated\":\"Votre compte a été mis a jour avec succès\"},\"sessions\":{\"signed_in\":\"Connecté avec succès\",\"signed_out\":\"Déconnecté avec succès\"},\"unlocks\":{\"send_instructions\":\"Vous recevrez un courriel contenant les instructions pour débloquer votre compte dans quelques minutes.\",\"unlocked\":\"Votre compte a été débloqué avec succès.\"}},\"errors\":{\"messages\":{\"already_confirmed\":\"étais déja confirmé\",\"not_found\":\"n'a pas été trouvé\",\"not_locked\":\"n'étais pas bloqué\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"ja\":\"日本語\",\"ru\":\"Русский\",\"fr\":\"Français\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}},\"ja\":{\"workers\":\"ワーカー\",\"queue\":\"キュー\",\"no_job\":\"ジョブはありません\",\"repositories\":{\"branch\":\"ブランチ\",\"image_url\":\"画像URL\",\"markdown\":\".md\",\"textile\":\".textile\",\"rdoc\":\".rdoc\",\"commit\":\"コミット\",\"message\":\"メッセージ\",\"started_at\":\"開始時刻\",\"duration\":\"処理時間\",\"finished_at\":\"終了時刻\",\"tabs\":{\"current\":\"最新\",\"build_history\":\"ビルド履歴\",\"branches\":\"ブランチまとめ\",\"build\":\"ビルド\",\"job\":\"ジョブ\"}},\"build\":{\"job\":\"ジョブ\",\"duration\":\"処理時間\",\"finished_at\":\"終了時刻\"},\"jobs\":{\"messages\":{\"sponsored_by\":\"このテストは以下のスポンサーの協力で行いました。\"},\"build_matrix\":\"ビルドマトリクス\",\"allowed_failures\":\"失敗許容範囲内\",\"author\":\"制作者\",\"config\":\"設定\",\"compare\":\"比較\",\"committer\":\"コミット者\",\"branch\":\"ブランチ\",\"commit\":\"コミット\",\"message\":\"メッセージ\",\"started_at\":\"開始時刻\",\"duration\":\"処理時間\",\"finished_at\":\"終了時刻\"},\"builds\":{\"name\":\"ビルド\",\"messages\":{\"sponsored_by\":\"このテストは以下のスポンサーの協力で行いました。\"},\"build_matrix\":\"失敗許容範囲外\",\"allowed_failures\":\"失敗許容範囲内\",\"author\":\"制作者\",\"config\":\"設定\",\"compare\":\"比較\",\"committer\":\"コミット者\",\"branch\":\"ブランチ\",\"commit\":\"コミット\",\"message\":\"メッセージ\",\"started_at\":\"開始時刻\",\"duration\":\"処理時間\",\"finished_at\":\"終了時刻\"},\"layouts\":{\"about\":{\"alpha\":\"まだアルファですよ!\",\"join\":\"参加してみよう!\",\"mailing_list\":\"メールリスト\",\"messages\":{\"alpha\":\"Travis-ciは安定したサービスまで後一歩!詳しくはこちら \"},\"repository\":\"リポジトリ\",\"twitter\":\"ツイッター\"},\"application\":{\"fork_me\":\"Githubでフォークしよう\",\"my_repositories\":\"マイリポジトリ\",\"recent\":\"最近\",\"search\":\"検索\",\"sponsers\":\"スポンサー\",\"sponsors_link\":\"スポンサーをもっと見る →\"},\"top\":{\"blog\":\"ブログ\",\"docs\":\"Travisとは?\",\"github_login\":\"Githubでログイン\",\"home\":\"ホーム\",\"profile\":\"プロフィール\",\"sign_out\":\"ログアウト\",\"stats\":\"統計\",\"admin\":\"管理\"},\"mobile\":{\"author\":\"制作者\",\"build\":\"ビルド\",\"build_matrix\":\"ビルドマトリクス\",\"commit\":\"コミット\",\"committer\":\"コミット者\",\"compare\":\"比較\",\"config\":\"設定\",\"duration\":\"処理時間\",\"finished_at\":\"終了時刻\",\"job\":\"ジョブ\",\"log\":\"ログ\"}},\"profiles\":{\"show\":{\"github\":\"Github\",\"email\":\"メール\",\"message\":{\"config\":\"詳細設定\",\"your_repos\":\"以下のスイッチを設定し、Travis-ciを有効にします。Githubへプッシュしたらビルドは自動的に開始します。複数バーションや細かい設定はこちらへ:\"},\"messages\":{\"notice\":\"まずはTravisのはじめ方 を参照してください。\"},\"token\":\"トークン\",\"your_repos\":\"リポジトリ\",\"update\":\"更新\",\"update_locale\":\"更新\",\"your_locale\":\"言語設定\"}},\"statistics\":{\"index\":{\"build_count\":\"ビルド数\",\"count\":\"数\",\"last_month\":\"先月\",\"repo_growth\":\"リポジトリ\",\"total_builds\":\"合計ビルド数\",\"total_projects\":\"合計リポジトリ\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"fr\":\"Français\",\"ja\":\"日本語\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"ru\":\"Русский\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}},\"nb\":{\"admin\":{\"actions\":{\"create\":\"opprett\",\"created\":\"opprettet\",\"delete\":\"slett\",\"deleted\":\"slettet\",\"update\":\"oppdater\",\"updated\":\"oppdatert\"},\"credentials\":{\"log_out\":\"Logg ut\"},\"dashboard\":{\"add_new\":\"Legg til ny\",\"ago\":\"siden\",\"last_used\":\"Sist brukt\",\"model_name\":\"Modell\",\"modify\":\"Rediger\",\"name\":\"Dashbord\",\"pagename\":\"Nettstedsadministrasjon\",\"records\":\"Oppføringer\",\"show\":\"Vis\"},\"delete\":{\"confirmation\":\"Ja, jeg er sikker\",\"flash_confirmation\":\"%{name} ble slettet\"},\"flash\":{\"error\":\"%{name} kunne ikke bli %{action}\",\"noaction\":\"Ingen handlinger ble utført\",\"successful\":\"%{name} ble %{action}\"},\"history\":{\"name\":\"Logg\",\"no_activity\":\"Ingen aktivitet\",\"page_name\":\"Logg for %{name}\"},\"list\":{\"add_new\":\"Legg til ny\",\"delete_action\":\"Slett\",\"delete_selected\":\"Slett valgte\",\"edit_action\":\"Rediger\",\"search\":\"Søk\",\"select\":\"Velg %{name} for å redigere\",\"select_action\":\"Velg\",\"show_all\":\"Vis alle \"},\"new\":{\"basic_info\":\"Basisinformasjon\",\"cancel\":\"Avbryt\",\"chosen\":\"Valgt %{name}\",\"chose_all\":\"Velg alle\",\"clear_all\":\"Fjern alle\",\"many_chars\":\"eller færre tegn.\",\"one_char\":\"tegn.\",\"optional\":\"Valgfri\",\"required\":\"Påkrevd\",\"save\":\"Lagre\",\"save_and_add_another\":\"Lagre og legg til ny\",\"save_and_edit\":\"Lagre og rediger\",\"select_choice\":\"Kryss av for dine valg og klikk\"}},\"build\":{\"duration\":\"Varighet\",\"finished_at\":\"Fullført\",\"job\":\"Jobb\"},\"builds\":{\"allowed_failures\":\"Tillatte feil\",\"author\":\"Forfatter\",\"branch\":\"Gren\",\"build_matrix\":\"Jobbmatrise\",\"commit\":\"Innsending\",\"committer\":\"Innsender\",\"compare\":\"Sammenlign\",\"config\":\"Oppsett\",\"duration\":\"Varighet\",\"finished_at\":\"Fullført\",\"message\":\"Beskrivelse\",\"messages\":{\"sponsored_by\":\"Denne testen ble kjørt på en maskin sponset av\"},\"name\":\"Jobb\",\"started_at\":\"Startet\"},\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} time\",\"other\":\"%{count} timer\"},\"minutes_exact\":{\"one\":\"%{count} minutt\",\"other\":\"%{count} minutter\"},\"seconds_exact\":{\"one\":\"%{count} sekund\",\"other\":\"%{count} sekunder\"}}},\"devise\":{\"confirmations\":{\"confirmed\":\"Din konto er aktivert og du er nå innlogget.\",\"send_instructions\":\"Om noen få minutter så vil du få en e-post med informasjon om hvordan du bekrefter kontoen din.\"},\"failure\":{\"inactive\":\"Kontoen din har ikke blitt aktivert enda.\",\"invalid\":\"Ugyldig e-post eller passord.\",\"invalid_token\":\"Ugyldig autentiseringskode.\",\"locked\":\"Kontoen din er låst.\",\"timeout\":\"Du ble logget ut siden på grunn av mangel på aktivitet, vennligst logg inn på nytt.\",\"unauthenticated\":\"Du må logge inn eller registrere deg for å fortsette.\",\"unconfirmed\":\"Du må bekrefte kontoen din før du kan fortsette.\"},\"mailer\":{\"confirmation_instructions\":{\"subject\":\"Bekreftelsesinformasjon\"},\"reset_password_instructions\":{\"subject\":\"Instruksjoner for å få nytt passord\"},\"unlock_instructions\":{\"subject\":\"Opplåsningsinstruksjoner\"}},\"passwords\":{\"send_instructions\":\"Om noen få minutter så vil du få en epost med informasjon om hvordan du kan få et nytt passord.\",\"updated\":\"Passordet ditt ble endret, og du er logget inn.\"},\"registrations\":{\"destroyed\":\"Adjø! Kontoen din ble kansellert. Vi håper vi ser deg igjen snart.\",\"signed_up\":\"Du er nå registrert.\",\"updated\":\"Kontoen din ble oppdatert.\"},\"sessions\":{\"signed_in\":\"Du er nå logget inn.\",\"signed_out\":\"Du er nå logget ut.\"},\"unlocks\":{\"send_instructions\":\"Om noen få minutter så kommer du til å få en e-post med informasjon om hvordan du kan låse opp kontoen din.\",\"unlocked\":\"Kontoen din ble låst opp, og du er nå logget inn igjen.\"}},\"errors\":{\"messages\":{\"already_confirmed\":\"har allerede blitt bekreftet\",\"not_found\":\"ikke funnnet\",\"not_locked\":\"var ikke låst\"}},\"home\":{\"name\":\"hjem\"},\"jobs\":{\"allowed_failures\":\"Tillatte feil\",\"author\":\"Forfatter\",\"branch\":\"Gren\",\"build_matrix\":\"Jobbmatrise\",\"commit\":\"Innsending\",\"committer\":\"Innsender\",\"compare\":\"Sammenlign\",\"config\":\"Oppsett\",\"duration\":\"Varighet\",\"finished_at\":\"Fullført\",\"message\":\"Beskrivelse\",\"messages\":{\"sponsored_by\":\"Denne testserien ble kjørt på en maskin sponset av\"},\"started_at\":\"Startet\"},\"layouts\":{\"about\":{\"alpha\":\"Dette er alfa-greier.\",\"join\":\"Bli med og hjelp oss!\",\"mailing_list\":\"E-postliste\",\"messages\":{\"alpha\":\"Dette er ikke en stabil tjeneste. Vi har fremdeles et stykke igjen! Mer informasjon finner du her .\"},\"repository\":\"Kodelager\",\"twitter\":\"Twitter.\"},\"application\":{\"fork_me\":\"Se koden på Github\",\"my_repositories\":\"Mine kodelagre\",\"recent\":\"Nylig\",\"search\":\"Søk\",\"sponsers\":\"Sponsorer\",\"sponsors_link\":\"Se alle de flotte sponsorene våre →\"},\"mobile\":{\"author\":\"Forfatter\",\"build\":\"Jobb\",\"build_matrix\":\"Jobbmatrise\",\"commit\":\"Innsending\",\"committer\":\"Innsender\",\"compare\":\"Sammenlign\",\"config\":\"Oppsett\",\"duration\":\"Varighet\",\"finished_at\":\"Fullført\",\"job\":\"Jobb\",\"log\":\"Logg\"},\"top\":{\"admin\":\"Administrator\",\"blog\":\"Blogg\",\"docs\":\"Dokumentasjon\",\"github_login\":\"Logg inn med Github\",\"home\":\"Hjem\",\"profile\":\"Profil\",\"sign_out\":\"Logg ut\",\"stats\":\"Statistikk\"}},\"no_job\":\"Ingen jobber finnnes\",\"profiles\":{\"show\":{\"email\":\"E-post\",\"github\":\"Github\",\"message\":{\"config\":\"hvordan sette opp egne jobbinnstillinger\",\"your_repos\":\"Slå\\u0010 på Travis for prosjektene dine ved å dra i bryterne under, og send koden til Github. \\nFor å teste mot flere ruby-versjoner, se dokumentasjonen for\"},\"messages\":{\"notice\":\"For å komme i gang, vennligst les kom-i-gang-veivisereren vår. Det tar bare et par minutter. \"},\"token\":\"Kode\",\"update\":\"Oppdater\",\"update_locale\":\"Oppdater\",\"your_locale\":\"Ditt språk\",\"your_repos\":\"Dine kodelagre\"}},\"queue\":\"Kø\",\"repositories\":{\"branch\":\"Gren\",\"commit\":\"Innsender\",\"duration\":\"Varighet\",\"finished_at\":\"Fullført\",\"image_url\":\"Bilde-URL\",\"markdown\":\"Markdown\",\"message\":\"Beskrivelse\",\"rdoc\":\"RDOC\",\"started_at\":\"Startet\",\"tabs\":{\"branches\":\"Grensammendrag\",\"build\":\"Jobb\",\"build_history\":\"Jobblogg\",\"current\":\"Siste\",\"job\":\"Jobb\"},\"textile\":\"Textile\"},\"repository\":{\"duration\":\"Varighet\"},\"statistics\":{\"index\":{\"build_count\":\"Antall jobber\",\"count\":\"Antall\",\"last_month\":\"siste måned\",\"repo_growth\":\"Vekst i kodelager\",\"total_builds\":\"Totale jobber\",\"total_projects\":\"Antall prosjekter/kodelagre\"}},\"workers\":\"Arbeidere\",\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"ja\":\"日本語\",\"ru\":\"Русский\",\"fr\":\"Français\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}},\"nl\":{\"admin\":{\"actions\":{\"create\":\"aanmaken\",\"created\":\"aangemaakt\",\"delete\":\"verwijderen\",\"deleted\":\"verwijderd\",\"update\":\"bijwerken\",\"updated\":\"bijgewerkt\"},\"credentials\":{\"log_out\":\"Afmelden\"},\"dashboard\":{\"add_new\":\"Nieuwe toevoegen\",\"ago\":\"geleden\",\"last_used\":\"Laatst gebruikt\",\"model_name\":\"Model naam\",\"modify\":\"Wijzigen\",\"pagename\":\"Site administratie\",\"show\":\"Laten zien\",\"records\":\"Gegevens\"},\"delete\":{\"confirmation\":\"Ja, ik ben zeker\",\"flash_confirmation\":\"%{name} is vernietigd\"},\"flash\":{\"error\":\"%{name} kon niet worden %{action}\",\"noaction\":\"Er zijn geen acties genomen\",\"successful\":\"%{name} is %{action}\"},\"history\":{\"name\":\"Geschiedenis\",\"no_activity\":\"Geen activiteit\",\"page_name\":\"Geschiedenis van %{name}\"},\"list\":{\"add_new\":\"Nieuwe toevoegen\",\"delete_action\":\"Verwijderen\",\"delete_selected\":\"Verwijder geselecteerden\",\"edit_action\":\"Bewerken\",\"search\":\"Zoeken\",\"select\":\"Selecteer %{name} om te bewerken\",\"select_action\":\"Selecteer\",\"show_all\":\"Laat allen zien\"},\"new\":{\"basic_info\":\"Basisinfo\",\"cancel\":\"Annuleren\",\"chosen\":\"%{name} gekozen\",\"chose_all\":\"Kies allen\",\"clear_all\":\"Deselecteer allen\",\"many_chars\":\"tekens of minder.\",\"one_char\":\"teken.\",\"optional\":\"Optioneel\",\"required\":\"Vereist\",\"save\":\"Opslaan\",\"save_and_add_another\":\"Opslaan en een nieuwe toevoegen\",\"save_and_edit\":\"Opslaan en bewerken\",\"select_choice\":\"Selecteer uw keuzes en klik\"}},\"build\":{\"duration\":\"Duur\",\"finished_at\":\"Voltooid\",\"job\":\"Taak\"},\"builds\":{\"allowed_failures\":\"Toegestane mislukkingen\",\"author\":\"Auteur\",\"branch\":\"Tak\",\"build_matrix\":\"Bouw Matrix\",\"compare\":\"Vergelijk\",\"config\":\"Configuratie\",\"duration\":\"Duur\",\"finished_at\":\"Voltooid\",\"message\":\"Bericht\",\"messages\":{\"sponsored_by\":\"Deze tests zijn gedraaid op een machine gesponsord door\"},\"name\":\"Bouw\",\"started_at\":\"Gestart\",\"commit\":\"Commit\",\"committer\":\"Committer\"},\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} uur\",\"other\":\"%{count} uren\"},\"minutes_exact\":{\"one\":\"%{count} minuut\",\"other\":\"%{count} minuten\"},\"seconds_exact\":{\"one\":\"%{count} seconde\",\"other\":\"%{count} seconden\"}}},\"devise\":{\"confirmations\":{\"confirmed\":\"Uw account is bevestigd. U wordt nu ingelogd.\",\"send_instructions\":\"Binnen enkele minuten zal u een email ontvangen met instructies om uw account te bevestigen.\"},\"failure\":{\"inactive\":\"Uw account is nog niet geactiveerd.\",\"invalid\":\"Ongeldig email adres of wachtwoord.\",\"invalid_token\":\"Ongeldig authenticatie token.\",\"locked\":\"Uw account is vergrendeld.\",\"timeout\":\"Uw sessie is verlopen, gelieve opnieuw in te loggen om verder te gaan.\",\"unauthenticated\":\"U moet inloggen of u registeren voordat u verder gaat.\",\"unconfirmed\":\"U moet uw account bevestigen voordat u verder gaat.\"},\"mailer\":{\"confirmation_instructions\":{\"subject\":\"Bevestigings-instructies\"},\"reset_password_instructions\":{\"subject\":\"Wachtwoord herstel instructies\"},\"unlock_instructions\":{\"subject\":\"Ontgrendel-instructies\"}},\"passwords\":{\"send_instructions\":\"Binnen enkele minuten zal u een email krijgen met instructies om uw wachtwoord opnieuw in te stellen.\",\"updated\":\"Uw wachtwoord is veranderd. U wordt nu ingelogd.\"},\"registrations\":{\"destroyed\":\"Dag! Uw account is geannuleerd. We hopen u vlug terug te zien.\",\"signed_up\":\"Uw registratie is voltooid. Als het ingeschakeld is wordt een bevestiging naar uw email adres verzonden.\",\"updated\":\"Het bijwerken van uw account is gelukt.\"},\"sessions\":{\"signed_in\":\"Inloggen gelukt.\",\"signed_out\":\"Uitloggen gelukt.\"},\"unlocks\":{\"send_instructions\":\"Binnen enkele minuten zal u een email krijgen met instructies om uw account te ontgrendelen.\",\"unlocked\":\"Uw account is ontgrendeld. U wordt nu ingelogd.\"}},\"errors\":{\"messages\":{\"already_confirmed\":\"was al bevestigd\",\"not_found\":\"niet gevonden\",\"not_locked\":\"was niet vergrendeld\"}},\"jobs\":{\"allowed_failures\":\"Toegestane mislukkingen\",\"author\":\"Auteur\",\"branch\":\"Tak\",\"build_matrix\":\"Bouw matrix\",\"compare\":\"Vergelijk\",\"config\":\"Configuratie\",\"duration\":\"Duur\",\"finished_at\":\"Voltooid\",\"message\":\"Bericht\",\"messages\":{\"sponsored_by\":\"Deze testen zijn uitgevoerd op een machine gesponsord door\"},\"started_at\":\"Gestart\",\"commit\":\"Commit\",\"committer\":\"Committer\"},\"layouts\":{\"about\":{\"alpha\":\"Dit is in alfa-stadium.\",\"join\":\"Doe met ons mee en help!\",\"mailing_list\":\"Mailing lijst\",\"messages\":{\"alpha\":\"Gelieve deze service niet te beschouwen als stabiel. Daar zijn we nog lang niet! Meer info hier. \"},\"repository\":\"Repository\",\"twitter\":\"Twitter\"},\"application\":{\"fork_me\":\"Maak een fork op Github\",\"my_repositories\":\"Mijn repositories\",\"recent\":\"Recent\",\"search\":\"Zoeken\",\"sponsers\":\"Sponsors\",\"sponsors_link\":\"Bekijk al onze geweldige sponsors →\"},\"mobile\":{\"author\":\"Auteur\",\"build\":\"Bouw\",\"build_matrix\":\"Bouw matrix\",\"compare\":\"Vergelijk\",\"config\":\"Configuratie\",\"duration\":\"Duur\",\"finished_at\":\"Voltooid op\",\"job\":\"Taak\",\"commit\":\"Commit\",\"committer\":\"Committer\",\"log\":\"Logboek\"},\"top\":{\"admin\":\"Administratie\",\"blog\":\"Blog\",\"docs\":\"Documentatie\",\"github_login\":\"Inloggen met Github\",\"home\":\"Home\",\"profile\":\"Profiel\",\"sign_out\":\"Uitloggen\",\"stats\":\"Statistieken\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"fr\":\"Français\",\"ja\":\"日本語\",\"nb\":\"Norsk Bokmål\",\"nl\":\"Nederlands\",\"pl\":\"Polski\",\"ru\":\"Русский\",\"pt-BR\":\"português brasileiro\"},\"no_job\":\"Er zijn geen taken\",\"profiles\":{\"show\":{\"email\":\"Email adres\",\"github\":\"Github\",\"message\":{\"config\":\"hoe eigen bouw-opties in te stellen\",\"your_repos\":\"Zet de schakelaars hieronder aan om de Travis hook voor uw projecten te activeren en push daarna naar Github \\nOm te testen tegen meerdere rubies, zie\"},\"messages\":{\"notice\":\"Om te beginnen kunt u onze startersgids lezen.\\\\n Het zal maar enkele minuten van uw tijd vergen. \"},\"update\":\"Bijwerken\",\"update_locale\":\"Bijwerken\",\"your_locale\":\"Uw taal\",\"your_repos\":\"Uw repositories\",\"token\":\"Token\"}},\"queue\":\"Wachtrij\",\"repositories\":{\"branch\":\"Tak\",\"duration\":\"Duur\",\"finished_at\":\"Voltooid\",\"image_url\":\"Afbeeldings URL\",\"message\":\"Bericht\",\"started_at\":\"Gestart\",\"tabs\":{\"branches\":\"Tak samenvatting\",\"build\":\"Bouw\",\"build_history\":\"Bouw geschiedenis\",\"current\":\"Huidig\",\"job\":\"Taak\"},\"commit\":\"Commit\",\"markdown\":\"Markdown\",\"rdoc\":\"RDOC\",\"textile\":\"Textile\"},\"repository\":{\"duration\":\"Duur\"},\"statistics\":{\"index\":{\"build_count\":\"Bouw aantal\",\"count\":\"Aantal\",\"last_month\":\"voorbije maand\",\"repo_growth\":\"Repository groei\",\"total_builds\":\"Bouw totaal\",\"total_projects\":\"Projecten/Repository totaal\"}},\"workers\":\"Machines\",\"home\":{\"name\":\"Hoofdpagina\"}},\"pl\":{\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} godzina\",\"other\":\"%{count} godziny\"},\"minutes_exact\":{\"one\":\"%{count} minuta\",\"other\":\"%{count} minuty\"},\"seconds_exact\":{\"one\":\"%{count} sekunda\",\"other\":\"%{count} sekundy\"}}},\"workers\":\"Workers\",\"queue\":\"Kolejka\",\"no_job\":\"Brak zadań\",\"repositories\":{\"branch\":\"Gałąź\",\"image_url\":\"URL obrazka\",\"markdown\":\"Markdown\",\"textile\":\"Textile\",\"rdoc\":\"RDOC\",\"commit\":\"Commit\",\"message\":\"Opis\",\"started_at\":\"Rozpoczęto\",\"duration\":\"Czas trwania\",\"finished_at\":\"Zakończono\",\"tabs\":{\"current\":\"Aktualny\",\"build_history\":\"Historia Buildów\",\"branches\":\"Wszystkie Gałęzie\",\"build\":\"Build\",\"job\":\"Zadanie\"}},\"build\":{\"job\":\"Zadanie\",\"duration\":\"Czas trwania\",\"finished_at\":\"Zakończono\"},\"jobs\":{\"messages\":{\"sponsored_by\":\"Te testy zostały uruchomione na maszynie sponsorowanej przez\"},\"build_matrix\":\"Macierz Buildów\",\"allowed_failures\":\"Dopuszczalne Niepowodzenia\",\"author\":\"Autor\",\"config\":\"Konfiguracja\",\"compare\":\"Porównanie\",\"committer\":\"Committer\",\"branch\":\"Gałąź\",\"commit\":\"Commit\",\"message\":\"Opis\",\"started_at\":\"Rozpoczęto\",\"duration\":\"Czas trwania\",\"finished_at\":\"Zakończono\",\"sponsored_by\":\"Te testy zostały uruchomione na maszynie sponsorowanej przez\"},\"builds\":{\"name\":\"Build\",\"messages\":{\"sponsored_by\":\"Te testy zostały uruchomione na maszynie sponsorowanej przez\"},\"build_matrix\":\"Macierz Buildów\",\"allowed_failures\":\"Dopuszczalne Niepowodzenia\",\"author\":\"Autor\",\"config\":\"Konfiguracja\",\"compare\":\"Porównanie\",\"committer\":\"Komitujący\",\"branch\":\"Gałąź\",\"commit\":\"Commit\",\"message\":\"Opis\",\"started_at\":\"Rozpoczęto\",\"duration\":\"Czas trwania\",\"finished_at\":\"Zakończono\"},\"layouts\":{\"top\":{\"home\":\"Start\",\"blog\":\"Blog\",\"docs\":\"Dokumentacja\",\"stats\":\"Statystki\",\"github_login\":\"Zaloguj się przy pomocy Githuba\",\"profile\":\"Profil\",\"sign_out\":\"Wyloguj się\"},\"application\":{\"fork_me\":\"Fork me on Github\",\"recent\":\"Ostatnie\",\"search\":\"Wyniki\",\"sponsers\":\"Sponsorzy\",\"sponsors_link\":\"Zobacz naszych wszystkich wspaniałych sponsorów →\",\"my_repositories\":\"Moje repozytoria\"},\"about\":{\"alpha\":\"To wciąż jest wersja alpha.\",\"messages\":{\"alpha\":\"Proszę nie traktuj tego jako stabilnej usługi. Wciąż nam wiele do tego brakuje! Więcej informacji znajdziesz tutaj. \"},\"join\":\"Pomóż i dołącz do nas!\",\"mailing_list\":\"Lista mailingowa\",\"repository\":\"Repozytorium\",\"twitter\":\"Twitter\"},\"mobile\":{\"author\":\"Autor\",\"build\":\"Build\",\"build_matrix\":\"Macierz Buildów\",\"commit\":\"Commit\",\"committer\":\"Komitujący\",\"compare\":\"Porównianie\",\"config\":\"Konfiguracja\",\"duration\":\"Czas trwania\",\"finished_at\":\"Zakończono\",\"job\":\"Zadanie\",\"log\":\"Log\"}},\"profiles\":{\"show\":{\"email\":\"Email\",\"github\":\"Github\",\"message\":{\"your_repos\":\" Przesuń suwak poniżej, aby włączyć Travisa, dla twoich projektów, a następnie umieść swój kod na GitHubie. \\n Aby testować swój kod przy użyciu wielu wersji Rubiego, zobacz\",\"config\":\"jak skonfigurować niestandardowe opcje builda\"},\"messages\":{\"notice\":\"Aby zacząć, przeczytaj nasz Przewodnik .\\n Zajmie ci to tylko kilka minut. \"},\"token\":\"Token\",\"your_repos\":\"Twoje repozytoria\"}},\"statistics\":{\"index\":{\"count\":\"Ilość\",\"repo_growth\":\"Przyrost repozytoriów\",\"total_projects\":\"Łącznie projektów/repozytoriów\",\"build_count\":\"Liczba buildów\",\"last_month\":\"ostatni miesiąc\",\"total_builds\":\"Łącznie Buildów\"}},\"date\":{\"abbr_day_names\":[\"nie\",\"pon\",\"wto\",\"śro\",\"czw\",\"pią\",\"sob\"],\"abbr_month_names\":[\"sty\",\"lut\",\"mar\",\"kwi\",\"maj\",\"cze\",\"lip\",\"sie\",\"wrz\",\"paź\",\"lis\",\"gru\"],\"day_names\":[\"niedziela\",\"poniedziałek\",\"wtorek\",\"środa\",\"czwartek\",\"piątek\",\"sobota\"],\"formats\":{\"default\":\"%d-%m-%Y\",\"long\":\"%B %d, %Y\",\"short\":\"%d %b\"},\"month_names\":[\"styczeń\",\"luty\",\"marzec\",\"kwiecień\",\"maj\",\"czerwiec\",\"lipiec\",\"sierpień\",\"wrzesień\",\"październik\",\"listopad\",\"grudzień\"],\"order\":[\"day\",\"month\",\"year\"]},\"errors\":{\"format\":\"%{attribute} %{message}\",\"messages\":{\"accepted\":\"musi zostać zaakceptowane\",\"blank\":\"nie może być puste\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"ja\":\"日本語\",\"ru\":\"Русский\",\"fr\":\"Français\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}},\"pt-BR\":{\"admin\":{\"actions\":{\"create\":\"criar\",\"created\":\"criado\",\"delete\":\"deletar\",\"deleted\":\"deletado\",\"update\":\"atualizar\",\"updated\":\"atualizado\"},\"credentials\":{\"log_out\":\"Deslogar\"},\"dashboard\":{\"add_new\":\"Adicionar novo\",\"ago\":\"atrás\",\"last_used\":\"Última utilização\",\"model_name\":\"Nome do modelo\",\"modify\":\"Modificar\",\"name\":\"Dashboard\",\"pagename\":\"Administração do site\",\"records\":\"Registros\",\"show\":\"Mostrar\"},\"delete\":{\"confirmation\":\"Sim, tenho certeza\",\"flash_confirmation\":\"%{name} foi destruído com sucesso\"},\"flash\":{\"error\":\"%{name} falhou ao %{action}\",\"noaction\":\"Nenhuma ação foi tomada\",\"successful\":\"%{name} foi %{action} com sucesso\"},\"history\":{\"name\":\"Histórico\",\"no_activity\":\"Nenhuma Atividade\",\"page_name\":\"Histórico para %{name}\"},\"list\":{\"add_new\":\"Adicionar novo\",\"delete_action\":\"Deletar\",\"delete_selected\":\"Deletar selecionados\",\"edit_action\":\"Editar\",\"search\":\"Buscar\",\"select\":\"Selecionar %{name} para editar\",\"select_action\":\"Selecionar\",\"show_all\":\"Mostrar todos\"},\"new\":{\"basic_info\":\"Informações básicas\",\"cancel\":\"Cancelar\",\"chosen\":\"Escolhido %{name}\",\"chose_all\":\"Escolher todos\",\"clear_all\":\"Limpar todos\",\"many_chars\":\"caracteres ou menos.\",\"one_char\":\"caractere.\",\"optional\":\"Opcional\",\"required\":\"Requerido\",\"save\":\"Salvar\",\"save_and_add_another\":\"Salvar e adicionar outro\",\"save_and_edit\":\"Salvar e alterar\",\"select_choice\":\"Selecione e clique\"}},\"build\":{\"duration\":\"Duração\",\"finished_at\":\"Concluído em\",\"job\":\"Trabalho\"},\"builds\":{\"allowed_failures\":\"Falhas Permitidas\",\"author\":\"Autor\",\"branch\":\"Branch\",\"build_matrix\":\"Matriz de Build\",\"commit\":\"Commit\",\"committer\":\"Committer\",\"compare\":\"Comparar\",\"config\":\"Config\",\"duration\":\"Duração\",\"finished_at\":\"Concluído em\",\"message\":\"Mensagem\",\"messages\":{\"sponsored_by\":\"Esta série de testes foi executada em uma caixa de processos patrocinada por\"},\"name\":\"Build\",\"started_at\":\"Iniciou em\"},\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} hora\",\"other\":\"%{count} horas\"},\"minutes_exact\":{\"one\":\"%{count} minuto\",\"other\":\"%{count} minutos\"},\"seconds_exact\":{\"one\":\"%{count} segundo\",\"other\":\"%{count} segundos\"}}},\"devise\":{\"confirmations\":{\"confirmed\":\"Sua conta foi confirmada com sucesso. Você agora está logado.\",\"send_instructions\":\"Você receberá um email com instruções de como confirmar sua conta em alguns minutos.\"},\"failure\":{\"inactive\":\"Sua conta ainda não foi ativada.\",\"invalid\":\"Email ou senha inválidos.\",\"invalid_token\":\"Token de autenticação inválido.\",\"locked\":\"Sua conta está trancada.\",\"timeout\":\"Sua sessão expirou, por favor faça seu login novamente.\",\"unauthenticated\":\"Você precisa fazer o login ou cadastrar-se antes de continuar.\",\"unconfirmed\":\"Você precisa confirmar sua conta antes de continuar.\"},\"mailer\":{\"confirmation_instructions\":{\"subject\":\"Instruções de confirmação\"},\"reset_password_instructions\":{\"subject\":\"Instruções de atualização de senha\"},\"unlock_instructions\":{\"subject\":\"Instruções de destrancamento\"}},\"passwords\":{\"send_instructions\":\"Você receberá um email com instruções de como atualizar sua senha em alguns minutos.\",\"updated\":\"Sua senha foi alterada com sucesso. Você agora está logado.\"},\"registrations\":{\"destroyed\":\"Tchau! Sua conta foi cancelada com sucesso. Esperamos vê-lo novamente em breve!\",\"signed_up\":\"Você se cadastrou com sucesso. Se ativada, uma confirmação foi enviada para seu email.\",\"updated\":\"Você atualizou sua conta com sucesso.\"},\"sessions\":{\"signed_in\":\"Logado com sucesso.\",\"signed_out\":\"Deslogado com sucesso.\"},\"unlocks\":{\"send_instructions\":\"Você receberá um email com instruções de como destrancar sua conta em alguns minutos.\",\"unlocked\":\"Sua conta foi destrancada com sucesso. Você agora está logado.\"}},\"errors\":{\"messages\":{\"already_confirmed\":\"já foi confirmado\",\"not_found\":\"não encontrado\",\"not_locked\":\"não estava trancado\"}},\"home\":{\"name\":\"home\"},\"jobs\":{\"allowed_failures\":\"Falhas Permitidas\",\"author\":\"Autor\",\"branch\":\"Branch\",\"build_matrix\":\"Matriz de Build\",\"commit\":\"Commit\",\"committer\":\"Committer\",\"compare\":\"Comparar\",\"config\":\"Config\",\"duration\":\"Duração\",\"finished_at\":\"Concluído em\",\"message\":\"Mensagem\",\"messages\":{\"sponsored_by\":\"Esta série de testes foi executada em uma caixa de processos patrocinada por\"},\"started_at\":\"Iniciou em\"},\"layouts\":{\"about\":{\"alpha\":\"Isto é um alpha.\",\"join\":\"Junte-se à nós e ajude!\",\"mailing_list\":\"Lista de email\",\"messages\":{\"alpha\":\"Por favor, não considere isto um serviço estável. Estamos muito longe disso! Mais informações aqui. \"},\"repository\":\"Repositório\",\"twitter\":\"Twitter\"},\"application\":{\"fork_me\":\"Faça fork no Github\",\"my_repositories\":\"Meus Repositórios\",\"recent\":\"Recentes\",\"search\":\"Buscar\",\"sponsers\":\"Patrocinadores\",\"sponsors_link\":\"Conheça todos os nossos patrocinadores →\"},\"mobile\":{\"author\":\"Autor\",\"build\":\"Build\",\"build_matrix\":\"Matriz de Build\",\"commit\":\"Commit\",\"committer\":\"Committer\",\"compare\":\"Comparar\",\"config\":\"Config\",\"duration\":\"Duração\",\"finished_at\":\"Concluído em\",\"job\":\"Trabalho\",\"log\":\"Log\"},\"top\":{\"admin\":\"Admin\",\"blog\":\"Blog\",\"docs\":\"Documentação\",\"github_login\":\"Logue com o Github\",\"home\":\"Home\",\"profile\":\"Perfil\",\"sign_out\":\"Sair\",\"stats\":\"Estatísticas\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"fr\":\"Français\",\"ja\":\"日本語\",\"nb\":\"Norsk Bokmål\",\"nl\":\"Nederlands\",\"pl\":\"Polski\",\"ru\":\"Русский\",\"pt-BR\":\"português brasileiro\"},\"no_job\":\"Não há trabalhos\",\"profiles\":{\"show\":{\"email\":\"Email\",\"github\":\"Github\",\"message\":{\"config\":\"como configurar opções de build\",\"your_repos\":\"Use os botões abaixo para ligar ou desligar o hook de serviço do Travis para seus projetos, e então, faça um push para o Github. Para testar com múltiplas versões do Ruby, leia\"},\"messages\":{\"notice\":\"Para começar, leia nosso Guia de início . Só leva alguns minutinhos. \"},\"token\":\"Token\",\"update\":\"Atualizar\",\"update_locale\":\"Atualizar\",\"your_locale\":\"Sua língua\",\"your_repos\":\"Seus Repositórios\"}},\"queue\":\"Fila\",\"repositories\":{\"branch\":\"Branch\",\"commit\":\"Commit\",\"duration\":\"Duração\",\"finished_at\":\"Concluído em\",\"image_url\":\"URL da imagem\",\"markdown\":\"Markdown\",\"message\":\"Mensagem\",\"rdoc\":\"RDOC\",\"started_at\":\"Iniciou em\",\"tabs\":{\"branches\":\"Sumário do Branch\",\"build\":\"Build\",\"build_history\":\"Histórico de Build\",\"current\":\"Atual\",\"job\":\"Trabalho\"},\"textile\":\"Textile\"},\"repository\":{\"duration\":\"Duração\"},\"statistics\":{\"index\":{\"build_count\":\"Número de Builds\",\"count\":\"Número\",\"last_month\":\"último mês\",\"repo_growth\":\"Crescimento de Repositório\",\"total_builds\":\"Total de Builds\",\"total_projects\":\"Total de Projetos/Repositórios\"}},\"workers\":\"Processos\"},\"ru\":{\"admin\":{\"actions\":{\"create\":\"создать\",\"created\":\"создано\",\"delete\":\"удалить\",\"deleted\":\"удалено\",\"update\":\"обновить\",\"updated\":\"обновлено\"},\"credentials\":{\"log_out\":\"Выход\"},\"dashboard\":{\"add_new\":\"Добавить\",\"ago\":\"назад\",\"last_used\":\"Использовалось в последний раз\",\"model_name\":\"Имя модели\",\"modify\":\"Изменить\",\"name\":\"Панель управления\",\"pagename\":\"Управление сайтом\",\"records\":\"Записи\",\"show\":\"Показать\"},\"delete\":{\"confirmation\":\"Да, я уверен\",\"flash_confirmation\":\"%{name} успешно удалено\"},\"history\":{\"name\":\"История\",\"no_activity\":\"Нет активности\",\"page_name\":\"История %{name}\"},\"list\":{\"add_new\":\"Добавить\",\"delete_action\":\"Удалить\",\"delete_selected\":\"Удалить выбранные\",\"edit_action\":\"Редактировать\",\"search\":\"Поиск\",\"select\":\"Для редактирования выберите %{name}\",\"select_action\":\"Выбрать\",\"show_all\":\"Показать все\"},\"new\":{\"basic_info\":\"Основная информация\",\"cancel\":\"Отмена\",\"chosen\":\"Выбрано %{name}\",\"chose_all\":\"Выбрать все\",\"clear_all\":\"Очистить все\",\"one_char\":\"символ.\",\"optional\":\"Необязательно\",\"required\":\"Обязательно\",\"save\":\"Сохранить\",\"save_and_add_another\":\"Сохранить и добавить другое\",\"save_and_edit\":\"Сохранить и продолжить редактирование\",\"select_choice\":\"Выберите и кликните\",\"many_chars\":\"символов или меньше.\"},\"flash\":{\"error\":\"%{name} не удалось %{action}\",\"noaction\":\"Никаких действий не произведено\",\"successful\":\"%{name} было успешно %{action}\"}},\"build\":{\"duration\":\"Длительность\",\"finished_at\":\"Завершен\",\"job\":\"Задача\"},\"builds\":{\"allowed_failures\":\"Допустимые неудачи\",\"author\":\"Автор\",\"branch\":\"Ветка\",\"build_matrix\":\"Матрица\",\"commit\":\"Коммит\",\"committer\":\"Коммитер\",\"compare\":\"Дифф\",\"config\":\"Конфигурация\",\"duration\":\"Длительность\",\"finished_at\":\"Завершен\",\"message\":\"Комментарий\",\"messages\":{\"sponsored_by\":\"Эта серия тестов была запущена на машине, спонсируемой\"},\"name\":\"Билд\",\"started_at\":\"Начало\"},\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} час\",\"few\":\"%{count} часа\",\"many\":\"%{count} часов\",\"other\":\"%{count} часа\"},\"minutes_exact\":{\"one\":\"%{count} минута\",\"few\":\"%{count} минуты\",\"many\":\"%{count} минут\",\"other\":\"%{count} минуты\"},\"seconds_exact\":{\"one\":\"%{count} секунда\",\"few\":\"%{count} секунды\",\"many\":\"%{count} секунд\",\"other\":\"%{count} секунды\"}}},\"devise\":{\"confirmations\":{\"confirmed\":\"Ваш аккаунт успешно подтвержден. Приветствуем!\",\"send_instructions\":\"В течении нескольких минут вы получите электронное письмо с инструкциями для прохождения процедуры подтверждения аккаунта.\"},\"failure\":{\"inactive\":\"Ваш аккаунт еще не активирован.\",\"invalid\":\"Ошибка в адресе почты или пароле.\",\"invalid_token\":\"Неправильный токен аутентификации.\",\"locked\":\"Ваш аккаунт заблокирован.\",\"timeout\":\"Сессия окончена. Для продолжения работы войдите снова.\",\"unauthenticated\":\"Вам нужно войти или зарегистрироваться.\",\"unconfirmed\":\"Вы должны сначала подтвердить свой аккаунт.\"},\"mailer\":{\"confirmation_instructions\":{\"subject\":\"Инструкции для подтверждению аккаунта\"},\"reset_password_instructions\":{\"subject\":\"Инструкции для сброса пароля\"},\"unlock_instructions\":{\"subject\":\"Инструкции для разблокирования аккаунта\"}},\"passwords\":{\"send_instructions\":\"В течении нескольких минут вы получите электронное письмо с инструкциями для сброса пароля.\",\"updated\":\"Ваш пароль успешно изменен. Приветствуем!\"},\"registrations\":{\"destroyed\":\"Ваш аккаунт был успешно удален. Живите долго и процветайте!\",\"signed_up\":\"Вы успешно прошли регистрацию. Инструкции для подтверждения аккаунта отправлены на ваш электронный адрес.\",\"updated\":\"Аккаунт успешно обновлен.\"},\"sessions\":{\"signed_in\":\"Приветствуем!\",\"signed_out\":\"Удачи!\"},\"unlocks\":{\"send_instructions\":\"В течении нескольких минут вы получите электронное письмо с инструкциям для разблокировния аккаунта.\",\"unlocked\":\"Ваш аккаунт успешно разблокирован. Приветствуем!\"}},\"errors\":{\"messages\":{\"already_confirmed\":\"уже подтвержден\",\"not_found\":\"не найден\",\"not_locked\":\"не заблокирован\"}},\"home\":{\"name\":\"Главная\"},\"jobs\":{\"allowed_failures\":\"Допустимые неудачи\",\"author\":\"Автор\",\"branch\":\"Ветка\",\"build_matrix\":\"Матрица\",\"commit\":\"Коммит\",\"committer\":\"Коммитер\",\"compare\":\"Сравнение\",\"config\":\"Конфигурация\",\"duration\":\"Длительность\",\"finished_at\":\"Завершен\",\"message\":\"Комментарий\",\"messages\":{\"sponsored_by\":\"Эта серия тестов была запущена на машине спонсируемой\"},\"started_at\":\"Начало\"},\"layouts\":{\"about\":{\"alpha\":\"Это альфа-версия\",\"join\":\"Присоединяйтесь к нам и помогайте!\",\"mailing_list\":\"Лист рассылки\",\"messages\":{\"alpha\":\"Пожалуйста, не считайте данный сервис стабильным. Мы еще очень далеки от стабильности! Подробности \"},\"repository\":\"Репозиторий\",\"twitter\":\"Twitter\"},\"application\":{\"fork_me\":\"Fork me on Github\",\"my_repositories\":\"Мои репозитории\",\"recent\":\"Недавние\",\"search\":\"Поиск\",\"sponsers\":\"Спонсоры\",\"sponsors_link\":\"Список всех наших замечательных спонсоров →\"},\"mobile\":{\"author\":\"Автор\",\"build\":\"Сборка\",\"build_matrix\":\"Матрица сборок\",\"commit\":\"Коммит\",\"committer\":\"Коммитер\",\"compare\":\"Сравнение\",\"config\":\"Конфигурация\",\"duration\":\"Длительность\",\"finished_at\":\"Завершен\",\"job\":\"Задача\",\"log\":\"Журнал\"},\"top\":{\"admin\":\"Управление\",\"blog\":\"Блог\",\"docs\":\"Документация\",\"github_login\":\"Войти через Github\",\"home\":\"Главная\",\"profile\":\"Профиль\",\"sign_out\":\"Выход\",\"stats\":\"Статистика\"}},\"no_job\":\"Очередь пуста\",\"profiles\":{\"show\":{\"email\":\"Электронная почта\",\"github\":\"Github\",\"message\":{\"config\":\"как настроить специальные опции билда\",\"your_repos\":\"Используйте переключатели, чтобы включить Travis service hook для вашего проекта, а потом отправьте код на GitHub. \\nДля тестирования на нескольких версиях Ruby смотрите\"},\"messages\":{\"notice\":\"Перед началом, пожалуйста, прочтите Руководство для быстрого старта . Это займет всего несколько минут. \"},\"token\":\"Токен\",\"update\":\"Обновить\",\"update_locale\":\"Обновить\",\"your_locale\":\"Ваш язык\",\"your_repos\":\"Ваши репозитории\"}},\"queue\":\"Очередь\",\"repositories\":{\"branch\":\"Ветка\",\"commit\":\"Коммит\",\"duration\":\"Длительность\",\"finished_at\":\"Завершен\",\"image_url\":\"URL изображения\",\"markdown\":\"Markdown\",\"message\":\"Комментарий\",\"rdoc\":\"RDOC\",\"started_at\":\"Начало\",\"tabs\":{\"branches\":\"Статус веток\",\"build\":\"Билд\",\"build_history\":\"История\",\"current\":\"Текущий\",\"job\":\"Задача\"},\"textile\":\"Textile\"},\"repository\":{\"duration\":\"Длительность\"},\"statistics\":{\"index\":{\"build_count\":\"Количество билдов\",\"count\":\"Количество\",\"last_month\":\"прошлый месяц\",\"repo_growth\":\"Рост числа репозиториев\",\"total_builds\":\"Всего билдов\",\"total_projects\":\"Всего проектов/репозиториев\"}},\"workers\":\"Машины\",\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"ja\":\"日本語\",\"ru\":\"Русский\",\"fr\":\"Français\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}}};\n\n\n})();\n//@ sourceURL=config/locales");minispade.register('ext/ember/bound_helper', "(function() {// https://gist.github.com/2018185\n// For reference: https://github.com/wagenet/ember.js/blob/ac66dcb8a1cbe91d736074441f853e0da474ee6e/packages/ember-handlebars/lib/views/bound_property_view.js\nvar BoundHelperView = Ember.View.extend(Ember._Metamorph, {\n\n context: null,\n options: null,\n property: null,\n // paths of the property that are also observed\n propertyPaths: [],\n\n value: Ember.K,\n\n valueForRender: function() {\n var value = this.value(Ember.get(this.context, this.property), this.options);\n if (this.options.escaped) { value = Handlebars.Utils.escapeExpression(value); }\n return value;\n },\n\n render: function(buffer) {\n buffer.push(this.valueForRender());\n },\n\n valueDidChange: function() {\n if (this.morph.isRemoved()) { return; }\n this.morph.html(this.valueForRender());\n },\n\n didInsertElement: function() {\n this.valueDidChange();\n },\n\n init: function() {\n this._super();\n Ember.addObserver(this.context, this.property, this, 'valueDidChange');\n this.get('propertyPaths').forEach(function(propName) {\n Ember.addObserver(this.context, this.property + '.' + propName, this, 'valueDidChange');\n }, this);\n },\n\n destroy: function() {\n Ember.removeObserver(this.context, this.property, this, 'valueDidChange');\n this.get('propertyPaths').forEach(function(propName) {\n this.context.removeObserver(this.property + '.' + propName, this, 'valueDidChange');\n }, this);\n this._super();\n }\n\n});\n\nEmber.registerBoundHelper = function(name, func) {\n var propertyPaths = Array.prototype.slice.call(arguments, 2);\n Ember.Handlebars.registerHelper(name, function(property, options) {\n var data = options.data,\n view = data.view,\n ctx = this;\n\n var bindView = view.createChildView(BoundHelperView, {\n property: property,\n propertyPaths: propertyPaths,\n context: ctx,\n options: options.hash,\n value: func\n });\n\n view.appendChild(bindView);\n });\n};\n\n\n})();\n//@ sourceURL=ext/ember/bound_helper");minispade.register('ext/ember/namespace', "(function() {Em.Namespace.reopen = Em.Namespace.reopenClass\n\n\n\n})();\n//@ sourceURL=ext/ember/namespace");
\ No newline at end of file
+;minispade.register('app', "(function() {(function() {\nminispade.require('auth');\nminispade.require('controllers');\nminispade.require('helpers');\nminispade.require('models');\nminispade.require('pusher');\nminispade.require('routes');\nminispade.require('slider');\nminispade.require('store');\nminispade.require('tailing');\nminispade.require('templates');\nminispade.require('views');\nminispade.require('config/locales');\nminispade.require('data/sponsors');\n\n Travis.reopen({\n App: Em.Application.extend({\n autoinit: false,\n currentUserBinding: 'auth.user',\n authStateBinding: 'auth.state',\n init: function() {\n this._super.apply(this, arguments);\n this.store = Travis.Store.create();\n this.store.loadMany(Travis.Sponsor, Travis.SPONSORS);\n this.set('auth', Travis.Auth.create({\n app: this,\n endpoint: Travis.config.api_endpoint\n }));\n this.slider = new Travis.Slider();\n this.pusher = new Travis.Pusher(Travis.config.pusher_key);\n return this.tailing = new Travis.Tailing();\n },\n signIn: function() {\n return this.get('auth').signIn();\n },\n autoSignIn: function() {\n return this.get('auth').autoSignIn();\n },\n signOut: function() {\n this.get('auth').signOut();\n return this.get('router').send('afterSignOut');\n },\n receive: function() {\n return this.store.receive.apply(this.store, arguments);\n },\n toggleSidebar: function() {\n var element;\n $('body').toggleClass('maximized');\n element = $(' ');\n $('#top .profile').append(element);\n Em.run.later((function() {\n return element.remove();\n }), 10);\n element = $(' ');\n $('#repo').append(element);\n return Em.run.later((function() {\n return element.remove();\n }), 10);\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=app");minispade.register('auth', "(function() {(function() {\n\n this.Travis.Auth = Ember.Object.extend({\n iframe: $('').hide(),\n timeout: 5000,\n state: 'signed-out',\n receivingEnd: \"\" + location.protocol + \"//\" + location.host,\n init: function() {\n var _this = this;\n this.iframe.appendTo('body');\n window.addEventListener('message', function(e) {\n return _this.receiveMessage(e);\n });\n return this.loadUser();\n },\n accessToken: (function() {\n return sessionStorage.getItem('travis.token');\n }).property(),\n loadUser: function() {\n var user;\n if (user = sessionStorage.getItem('travis.user')) {\n return this.setData({\n user: JSON.parse(user)\n });\n } else {\n return this.autoSignIn();\n }\n },\n signIn: function() {\n this.set('state', 'signing-in');\n this.trySignIn();\n return Ember.run.later(this, this.checkSignIn.bind(this), this.timeout);\n },\n autoSignIn: function() {\n if (localStorage.getItem('travis.auto_signin')) {\n return this.signIn();\n }\n },\n signOut: function() {\n localStorage.clear();\n sessionStorage.clear();\n return this.setData();\n },\n trySignIn: function() {\n return this.iframe.attr('src', \"\" + this.endpoint + \"/auth/post_message?origin=\" + this.receivingEnd);\n },\n checkSignIn: function() {\n if (this.get('state') === 'signing-in') {\n return this.forceSignIn();\n }\n },\n forceSignIn: function() {\n localStorage.setItem('travis.auto_signin', 'true');\n return window.location = \"\" + this.endpoint + \"/auth/handshake?redirect_uri=\" + location;\n },\n setData: function(data) {\n var router, user, _ref;\n if (typeof data === 'string') {\n data = JSON.parse(data);\n }\n if (data != null ? data.token : void 0) {\n this.storeToken(data.token);\n }\n if (data != null ? data.user : void 0) {\n user = this.storeUser(data.user);\n }\n this.set('state', user ? 'signed-in' : 'signed-out');\n this.set('user', user ? user : void 0);\n if (router = (_ref = Travis.app) != null ? _ref.get('router') : void 0) {\n return router.send('afterSignIn');\n }\n },\n storeToken: function(token) {\n sessionStorage.setItem('travis.token', token);\n return this.notifyPropertyChange('accessToken');\n },\n storeUser: function(user) {\n localStorage.setItem('travis.auto_signin', 'true');\n sessionStorage.setItem('travis.user', JSON.stringify(user));\n this.app.store.load(Travis.User, user);\n user = this.app.store.find(Travis.User, user.id);\n user.get('permissions');\n return user;\n },\n receiveMessage: function(event) {\n if (event.origin === this.expectedOrigin()) {\n this.setData(event.data);\n return console.log(\"signed in as \" + event.data.user.login);\n } else {\n return console.log(\"unexpected message \" + event.origin + \": \" + event.data);\n }\n },\n expectedOrigin: function() {\n if (this.endpoint[0] === '/') {\n return this.receivingEnd;\n } else {\n return this.endpoint;\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=auth");minispade.register('controllers', "(function() {(function() {\nminispade.require('helpers');\nminispade.require('travis/ticker');\n\n Travis.reopen({\n Controller: Em.Controller.extend({\n connectOutlet: function() {\n var view, _connectedOutletViews;\n view = this._super.apply(this, arguments);\n if (view) {\n _connectedOutletViews = Travis.app.get('_connectedOutletViews');\n if (!_connectedOutletViews) {\n _connectedOutletViews = [];\n }\n _connectedOutletViews.pushObject(view);\n Travis.app.set('_connectedOutletViews', _connectedOutletViews);\n }\n return view;\n }\n }),\n TopController: Em.Controller.extend({\n userBinding: 'Travis.app.currentUser'\n }),\n ApplicationController: Em.Controller.extend(),\n MainController: Em.Controller.extend(),\n StatsLayoutController: Em.Controller.extend(),\n ProfileLayoutController: Em.Controller.extend(),\n AuthLayoutController: Em.Controller.extend()\n });\nminispade.require('controllers/accounts');\nminispade.require('controllers/builds');\nminispade.require('controllers/flash');\nminispade.require('controllers/home');\nminispade.require('controllers/profile');\nminispade.require('controllers/repos');\nminispade.require('controllers/repo');\nminispade.require('controllers/sidebar');\nminispade.require('controllers/stats');\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers");minispade.register('controllers/accounts', "(function() {(function() {\n\n Travis.AccountsController = Ember.ArrayController.extend({\n tab: 'accounts',\n init: function() {\n return this._super();\n },\n findByLogin: function(login) {\n return this.find(function(account) {\n return account.get('login') === login;\n });\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/accounts");minispade.register('controllers/builds', "(function() {(function() {\n\n Travis.BuildsController = Em.ArrayController.extend({\n repo: 'parent.repo',\n contentBinding: 'parent.builds'\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/builds");minispade.register('controllers/flash', "(function() {(function() {\n\n Travis.FlashController = Ember.ArrayController.extend({\n init: function() {\n this._super.apply(this, arguments);\n return this.set('content', Ember.A());\n },\n pushObjects: function(objects) {\n Ember.run.later(this, (function() {\n return this.removeObjects(objects);\n }), 10000);\n return this._super(objects);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/flash");minispade.register('controllers/home', "(function() {(function() {\n\n Travis.HomeLayoutController = Travis.Controller.extend();\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/home");minispade.register('controllers/profile', "(function() {(function() {\n\n Travis.ProfileController = Travis.Controller.extend({\n name: 'profile',\n userBinding: 'Travis.app.currentUser',\n accountsBinding: 'Travis.app.router.accountsController',\n account: (function() {\n var account, login;\n login = this.get('params.login') || Travis.app.get('currentUser.login');\n account = this.get('accounts').filter(function(account) {\n if (account.get('login') === login) {\n return account;\n }\n })[0];\n if (account) {\n account.select();\n }\n return account;\n }).property('accounts.length', 'params.login'),\n activate: function(action, params) {\n this.setParams(params || this.get('params'));\n return this[\"view\" + ($.camelize(action))]();\n },\n viewHooks: function() {\n this.connectTab('hooks');\n return this.set('hooks', Travis.Hook.find({\n owner_name: this.get('params.login') || Travis.app.get('currentUser.login')\n }));\n },\n viewUser: function() {\n return this.connectTab('user');\n },\n connectTab: function(tab) {\n var viewClass;\n viewClass = Travis[\"\" + ($.camelize(tab)) + \"View\"];\n this.set('tab', tab);\n return this.connectOutlet({\n outletName: 'pane',\n controller: this,\n viewClass: viewClass\n });\n },\n setParams: function(params) {\n var key, value, _results;\n this.set('params', {});\n _results = [];\n for (key in params) {\n value = params[key];\n _results.push(this.set(\"params.\" + key, params[key]));\n }\n return _results;\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/profile");minispade.register('controllers/repo', "(function() {(function() {\n\n Travis.RepoController = Travis.Controller.extend({\n bindings: [],\n init: function() {\n this._super.apply(this, arguments);\n return Ember.run.later(this.updateTimes.bind(this), Travis.INTERVALS.updateTimes);\n },\n updateTimes: function() {\n var build, builds, jobs;\n if (builds = this.get('builds')) {\n builds.forEach(function(b) {\n return b.updateTimes();\n });\n }\n if (build = this.get('build')) {\n build.updateTimes();\n }\n if (build && (jobs = build.get('jobs'))) {\n jobs.forEach(function(j) {\n return j.updateTimes();\n });\n }\n return Ember.run.later(this.updateTimes.bind(this), Travis.INTERVALS.updateTimes);\n },\n activate: function(action) {\n this._unbind();\n return this[\"view\" + ($.camelize(action))]();\n },\n viewIndex: function() {\n this._bind('repo', 'controllers.reposController.firstObject');\n this._bind('build', 'repo.lastBuild');\n return this.connectTab('current');\n },\n viewCurrent: function() {\n this.connectTab('current');\n return this._bind('build', 'repo.lastBuild');\n },\n viewBuilds: function() {\n this.connectTab('builds');\n return this._bind('builds', 'repo.builds');\n },\n viewPullRequests: function() {\n this.connectTab('pull_requests');\n return this._bind('builds', 'repo.pullRequests');\n },\n viewBranches: function() {\n this.connectTab('branches');\n return this._bind('builds', 'repo.branches');\n },\n viewEvents: function() {\n this.connectTab('events');\n return this._bind('events', 'repo.events');\n },\n viewBuild: function() {\n return this.connectTab('build');\n },\n viewJob: function() {\n this._bind('build', 'job.build');\n return this.connectTab('job');\n },\n repoObserver: (function() {\n var repo;\n repo = this.get('repo');\n if (repo) {\n return repo.select();\n }\n }).observes('repo.id'),\n connectTab: function(tab) {\n var name, viewClass;\n name = tab === 'current' ? 'build' : tab;\n viewClass = name === 'builds' || name === 'branches' || name === 'pull_requests' ? Travis.BuildsView : Travis[\"\" + ($.camelize(name)) + \"View\"];\n this.set('tab', tab);\n return this.connectOutlet({\n outletName: 'pane',\n controller: this,\n viewClass: viewClass\n });\n },\n _bind: function(to, from) {\n return this.bindings.push(Ember.oneWay(this, to, from));\n },\n _unbind: function() {\n var binding, _i, _len, _ref;\n _ref = this.bindings;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n binding = _ref[_i];\n binding.disconnect(this);\n }\n return this.bindings.length = 0;\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/repo");minispade.register('controllers/repos', "(function() {(function() {\nminispade.require('travis/limited_array');\n\n Travis.ReposController = Ember.ArrayController.extend({\n defaultTab: 'recent',\n sortProperties: ['sortOrder'],\n init: function() {\n this.activate(this.defaultTab);\n return Ember.run.later(this.updateTimes.bind(this), Travis.INTERVALS.updateTimes);\n },\n updateTimes: function() {\n var content;\n if (content = this.get('content')) {\n content.forEach(function(r) {\n return r.updateTimes();\n });\n }\n return Ember.run.later(this.updateTimes.bind(this), Travis.INTERVALS.updateTimes);\n },\n activate: function(tab, params) {\n this.set('tab', tab);\n return this[\"view\" + ($.camelize(tab))](params);\n },\n viewRecent: function() {\n var content;\n content = Travis.LimitedArray.create({\n content: Travis.Repo.find(),\n limit: 30\n });\n return this.set('content', content);\n },\n viewOwned: function() {\n return this.set('content', Travis.Repo.accessibleBy(Travis.app.get('currentUser.login')));\n },\n viewSearch: function(params) {\n return this.set('content', Travis.Repo.search(params.search));\n },\n searchObserver: (function() {\n var search;\n search = this.get('search');\n if (search) {\n return this.searchFor(search);\n } else {\n this.activate('recent');\n return 'recent';\n }\n }).observes('search'),\n searchFor: function(phrase) {\n if (this.searchLater) {\n Ember.run.cancel(this.searchLater);\n }\n return this.searchLater = Ember.run.later(this, (function() {\n return this.activate('search', {\n search: phrase\n });\n }), 500);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/repos");minispade.register('controllers/sidebar', "(function() {(function() {\n\n Travis.reopen({\n SidebarController: Em.ArrayController.extend({\n init: function() {\n this.tickables = [];\n return Travis.Ticker.create({\n target: this,\n interval: Travis.INTERVALS.sponsors\n });\n },\n tick: function() {\n var tickable, _i, _len, _ref, _results;\n _ref = this.tickables;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n tickable = _ref[_i];\n _results.push(tickable.tick());\n }\n return _results;\n }\n }),\n QueuesController: Em.ArrayController.extend(),\n WorkersController: Em.ArrayController.extend({\n groups: (function() {\n var content, groups, host, worker, _i, _len, _ref;\n if (content = this.get('arrangedContent')) {\n groups = {};\n _ref = content.toArray();\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n worker = _ref[_i];\n host = worker.get('host');\n if (!groups[host]) {\n groups[host] = Em.ArrayProxy.create(Em.SortableMixin, {\n content: [],\n sortProperties: ['nameForSort']\n });\n }\n groups[host].addObject(worker);\n }\n return $.values(groups);\n }\n }).property('length')\n }),\n SponsorsController: Em.ArrayController.extend({\n page: 0,\n arrangedContent: (function() {\n return this.get('shuffled').slice(this.start(), this.end());\n }).property('shuffled.length', 'page'),\n shuffled: (function() {\n var content;\n if (content = this.get('content')) {\n return $.shuffle(content);\n } else {\n return [];\n }\n }).property('content.length'),\n tick: function() {\n return this.set('page', this.isLast() ? 0 : this.get('page') + 1);\n },\n pages: (function() {\n var length;\n length = this.get('content.length');\n if (length) {\n return parseInt(length / this.get('perPage') + 1);\n } else {\n return 1;\n }\n }).property('length'),\n isLast: function() {\n return this.get('page') === this.get('pages') - 1;\n },\n start: function() {\n return this.get('page') * this.get('perPage');\n },\n end: function() {\n return this.start() + this.get('perPage');\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/sidebar");minispade.register('controllers/stats', "(function() {(function() {\n\n Travis.StatsController = Travis.Controller.extend({\n name: 'stats',\n init: function() {\n return this._super('top');\n },\n activate: function(action, params) {}\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=controllers/stats");minispade.register('helpers', "(function() {(function() {\nminispade.require('helpers/handlebars');\nminispade.require('helpers/helpers');\nminispade.require('helpers/urls');\n\n}).call(this);\n\n})();\n//@ sourceURL=helpers");minispade.register('helpers/handlebars', "(function() {(function() {\n var safe;\nminispade.require('ext/ember/bound_helper');\n\n safe = function(string) {\n return new Handlebars.SafeString(string);\n };\n\n Handlebars.registerHelper('tipsy', function(text, tip) {\n return safe('' + text + ' ');\n });\n\n Handlebars.registerHelper('t', function(key) {\n return safe(I18n.t(key));\n });\n\n Ember.registerBoundHelper('formatTime', function(value, options) {\n return safe(Travis.Helpers.timeAgoInWords(value) || '-');\n });\n\n Ember.registerBoundHelper('formatDuration', function(duration, options) {\n return safe(Travis.Helpers.timeInWords(duration));\n });\n\n Ember.registerBoundHelper('formatCommit', function(commit, options) {\n if (commit) {\n return safe(Travis.Helpers.formatCommit(commit.get('sha'), commit.get('branch')));\n }\n });\n\n Ember.registerBoundHelper('formatSha', function(sha, options) {\n return safe(Travis.Helpers.formatSha(sha));\n });\n\n Ember.registerBoundHelper('pathFrom', function(url, options) {\n return safe(Travis.Helpers.pathFrom(url));\n });\n\n Ember.registerBoundHelper('formatMessage', function(message, options) {\n return safe(Travis.Helpers.formatMessage(message, options));\n });\n\n Ember.registerBoundHelper('formatConfig', function(config, options) {\n return safe(Travis.Helpers.formatConfig(config));\n });\n\n Ember.registerBoundHelper('formatLog', function(log, options) {\n var item, parentView, repo;\n parentView = this.get('parentView');\n repo = parentView.get(options.repo);\n item = parentView.get(options.item);\n return Travis.Helpers.formatLog(log, repo, item) || '';\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=helpers/handlebars");minispade.register('helpers/helpers', "(function() {(function() {\nminispade.require('travis/log');\nminispade.require('config/emoij');\n\n this.Travis.Helpers = {\n compact: function(object) {\n var key, result, value, _ref;\n result = {};\n _ref = object || {};\n for (key in _ref) {\n value = _ref[key];\n if (!$.isEmpty(value)) {\n result[key] = value;\n }\n }\n return result;\n },\n safe: function(string) {\n return new Handlebars.SafeString(string);\n },\n colorForResult: function(result) {\n if (result === 0) {\n return 'green';\n } else {\n if (result === 1) {\n return 'red';\n } else {\n return null;\n }\n }\n },\n formatCommit: function(sha, branch) {\n return Travis.Helpers.formatSha(sha) + (branch ? \" (\" + branch + \")\" : '');\n },\n formatSha: function(sha) {\n return (sha || '').substr(0, 7);\n },\n formatConfig: function(config) {\n var values;\n config = $.only(config, 'rvm', 'gemfile', 'env', 'otp_release', 'php', 'node_js', 'scala', 'jdk', 'python', 'perl');\n values = $.map(config, function(value, key) {\n value = (value && value.join ? value.join(', ') : value) || '';\n return '%@: %@'.fmt($.camelize(key), value);\n });\n if (values.length === 0) {\n return '-';\n } else {\n return values.join(', ');\n }\n },\n formatMessage: function(message, options) {\n message = message || '';\n if (options.short) {\n message = message.split(/\\n/)[0];\n }\n return this._emojize(this._escape(message)).replace(/\\n/g, ' ');\n },\n formatLog: function(log, repo, item) {\n var event, url;\n event = item.constructor === Travis.Build ? 'showBuild' : 'showJob';\n url = Travis.app.get('router').urlForEvent(event, repo, item);\n return Travis.Log.filter(log, url);\n },\n pathFrom: function(url) {\n return (url || '').split('/').pop();\n },\n timeAgoInWords: function(date) {\n return $.timeago.distanceInWords(date);\n },\n durationFrom: function(started, finished) {\n started = started && this._toUtc(new Date(this._normalizeDateString(started)));\n finished = finished ? this._toUtc(new Date(this._normalizeDateString(finished))) : this._nowUtc();\n if (started && finished) {\n return Math.round((finished - started) / 1000);\n } else {\n return 0;\n }\n },\n timeInWords: function(duration) {\n var days, hours, minutes, result, seconds;\n days = Math.floor(duration / 86400);\n hours = Math.floor(duration % 86400 / 3600);\n minutes = Math.floor(duration % 3600 / 60);\n seconds = duration % 60;\n if (days > 0) {\n return 'more than 24 hrs';\n } else {\n result = [];\n if (hours === 1) {\n result.push(hours + ' hr');\n }\n if (hours > 1) {\n result.push(hours + ' hrs');\n }\n if (minutes > 0) {\n result.push(minutes + ' min');\n }\n if (seconds > 0) {\n result.push(seconds + ' sec');\n }\n if (result.length > 0) {\n return result.join(' ');\n } else {\n return '-';\n }\n }\n },\n _normalizeDateString: function(string) {\n if (window.JHW) {\n string = string.replace('T', ' ').replace(/-/g, '/');\n string = string.replace('Z', '').replace(/\\..*$/, '');\n }\n return string;\n },\n _nowUtc: function() {\n return this._toUtc(new Date());\n },\n _toUtc: function(date) {\n return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());\n },\n _emojize: function(text) {\n var emojis;\n emojis = text.match(/:\\S+?:/g);\n if (emojis !== null) {\n $.each(emojis.uniq(), function(ix, emoji) {\n var image, strippedEmoji;\n strippedEmoji = emoji.substring(1, emoji.length - 1);\n if (EmojiDictionary.indexOf(strippedEmoji) !== -1) {\n image = ' ';\n return text = text.replace(new RegExp(emoji, 'g'), image);\n }\n });\n }\n return text;\n },\n _escape: function(text) {\n return text.replace(/&/g, '&').replace(//g, '>');\n }\n };\n\n}).call(this);\n\n})();\n//@ sourceURL=helpers/helpers");minispade.register('helpers/urls', "(function() {(function() {\n\n this.Travis.Urls = {\n repo: function(slug) {\n return \"/\" + slug;\n },\n builds: function(slug) {\n return \"/\" + slug + \"/builds\";\n },\n pullRequests: function(slug) {\n return \"/\" + slug + \"/pull_requests\";\n },\n branches: function(slug) {\n return \"/\" + slug + \"/branches\";\n },\n build: function(slug, id) {\n return \"/\" + slug + \"/builds/\" + id;\n },\n job: function(slug, id) {\n return \"/\" + slug + \"/jobs/\" + id;\n },\n githubCommit: function(slug, sha) {\n return \"http://github.com/\" + slug + \"/commit/\" + sha;\n },\n githubRepo: function(slug) {\n return \"http://github.com/\" + slug;\n },\n githubWatchers: function(slug) {\n return \"http://github.com/\" + slug + \"/watchers\";\n },\n githubNetwork: function(slug) {\n return \"http://github.com/\" + slug + \"/network\";\n },\n githubAdmin: function(slug) {\n return \"http://github.com/\" + slug + \"/admin/hooks#travis_minibucket\";\n },\n statusImage: function(slug, branch) {\n return (\"https://secure.travis-ci.org/\" + slug + \".png\") + (branch ? \"?branch=\" + branch : '');\n },\n email: function(email) {\n return \"mailto:\" + email;\n },\n account: function(login) {\n return \"/profile/\" + login;\n },\n user: function(login) {\n return \"/profile/\" + login + \"/me\";\n }\n };\n\n}).call(this);\n\n})();\n//@ sourceURL=helpers/urls");minispade.register('models', "(function() {(function() {\nminispade.require('models/extensions');\nminispade.require('models/account');\nminispade.require('models/artifact');\nminispade.require('models/branch');\nminispade.require('models/build');\nminispade.require('models/commit');\nminispade.require('models/event');\nminispade.require('models/hook');\nminispade.require('models/job');\nminispade.require('models/repo');\nminispade.require('models/sponsor');\nminispade.require('models/user');\nminispade.require('models/worker');\n\n}).call(this);\n\n})();\n//@ sourceURL=models");minispade.register('models/account', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Account = Travis.Model.extend({\n primaryKey: 'login',\n login: DS.attr('string'),\n name: DS.attr('string'),\n type: DS.attr('string'),\n reposCount: DS.attr('number'),\n urlGithub: (function() {\n return \"http://github.com/\" + (this.get('login'));\n }).property()\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/account");minispade.register('models/artifact', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Artifact = Travis.Model.extend({\n body: DS.attr('string'),\n init: function() {\n this._super.apply(this, arguments);\n this.set('queue', Ember.A([]));\n this.addObserver('body', this.fetchWorker);\n return this.fetchWorker();\n },\n append: function(body) {\n if (this.get('isLoaded')) {\n return this.set('body', this.get('body') + body);\n } else {\n return this.get('queue').pushObject(body);\n }\n },\n recordDidLoad: (function() {\n var queue;\n if (this.get('isLoaded')) {\n queue = this.get('queue');\n if (queue.get('length') > 0) {\n return this.append(queue.toArray().join(''));\n }\n }\n }).observes('isLoaded'),\n fetchWorker: function() {\n var body, line, match, worker;\n if (body = this.get('body')) {\n line = body.split(\"\\n\")[0];\n if (line && (match = line.match(/Using worker: (.*)/))) {\n if (worker = match[1]) {\n worker = worker.trim().split(':')[0];\n this.set('workerName', worker);\n return this.removeObserver('body', this.fetchWorker);\n }\n }\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/artifact");minispade.register('models/branch', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Branch = Travis.Model.extend(Travis.Helpers, {\n repoId: DS.attr('number', {\n key: 'repository_id'\n }),\n commitId: DS.attr('number'),\n number: DS.attr('number'),\n branch: DS.attr('string'),\n message: DS.attr('string'),\n result: DS.attr('number'),\n duration: DS.attr('number'),\n startedAt: DS.attr('string'),\n finishedAt: DS.attr('string'),\n commit: DS.belongsTo('Travis.Commit'),\n repo: (function() {\n if (this.get('repoId')) {\n return Travis.Repo.find(this.get('repoId'));\n }\n }).property('repoId'),\n updateTimes: function() {\n this.notifyPropertyChange('started_at');\n return this.notifyPropertyChange('finished_at');\n }\n });\n\n this.Travis.Branch.reopenClass({\n byRepoId: function(id) {\n return this.find({\n repository_id: id\n });\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/branch");minispade.register('models/build', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Build = Travis.Model.extend(Travis.DurationCalculations, {\n eventType: DS.attr('string'),\n repoId: DS.attr('number', {\n key: 'repository_id'\n }),\n commitId: DS.attr('number'),\n state: DS.attr('string'),\n number: DS.attr('number'),\n branch: DS.attr('string'),\n message: DS.attr('string'),\n result: DS.attr('number'),\n _duration: DS.attr('number', {\n key: 'duration'\n }),\n startedAt: DS.attr('string', {\n key: 'started_at'\n }),\n finishedAt: DS.attr('string', {\n key: 'finished_at'\n }),\n repo: DS.belongsTo('Travis.Repo', {\n key: 'repository_id'\n }),\n commit: DS.belongsTo('Travis.Commit'),\n jobs: DS.hasMany('Travis.Job', {\n key: 'job_ids'\n }),\n config: (function() {\n return Travis.Helpers.compact(this.get('data.config'));\n }).property('data.config'),\n isMatrix: (function() {\n return this.get('data.job_ids.length') > 1;\n }).property('data.job_ids.length'),\n isFinished: (function() {\n return this.get('state') === 'finished';\n }).property('state'),\n requiredJobs: (function() {\n return this.get('jobs').filter(function(data) {\n return !data.get('allowFailure');\n });\n }).property('jobs.@each.allowFailure'),\n allowedFailureJobs: (function() {\n return this.get('jobs').filter(function(data) {\n return data.get('allowFailure');\n });\n }).property('jobs.@each.allowFailure'),\n configKeys: (function() {\n var config, headers, key, keys;\n if (!(config = this.get('config'))) {\n return [];\n }\n keys = $.intersect($.keys(config), Travis.CONFIG_KEYS);\n headers = (function() {\n var _i, _len, _ref, _results;\n _ref = ['build.job', 'build.duration', 'build.finished_at'];\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n key = _ref[_i];\n _results.push(I18n.t(key));\n }\n return _results;\n })();\n return $.map(headers.concat(keys), function(key) {\n return $.camelize(key);\n });\n }).property('config'),\n requeue: (function() {\n return Travis.ajax.post('/requests', {\n build_id: this.get('id')\n });\n })\n });\n\n this.Travis.Build.reopenClass({\n byRepoId: function(id, parameters) {\n return this.find($.extend(parameters || {}, {\n repository_id: id\n }));\n },\n olderThanNumber: function(id, build_number) {\n return this.find({\n url: \"/builds\",\n repository_id: id,\n after_number: build_number\n });\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/build");minispade.register('models/commit', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Commit = Travis.Model.extend({\n buildId: DS.attr('number'),\n sha: DS.attr('string'),\n branch: DS.attr('string'),\n message: DS.attr('string'),\n compareUrl: DS.attr('string'),\n authorName: DS.attr('string'),\n authorEmail: DS.attr('string'),\n committerName: DS.attr('string'),\n committerEmail: DS.attr('string'),\n build: DS.belongsTo('Travis.Build', {\n key: 'buildId'\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/commit");minispade.register('models/event', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Event = Travis.Model.extend({\n event: DS.attr('string'),\n repoId: DS.attr('number', {\n key: 'repository_id'\n }),\n createdAt: DS.attr('string', {\n key: 'created_at'\n }),\n message: (function() {\n var message;\n message = \"\" + (this.get('event')) + \": \" + (this.get('_data.result'));\n message = \"\" + message + \": \" + (this.get('_data.message'));\n return message;\n }).property('_data.result', '_data.message'),\n _data: (function() {\n return this.get('data.data');\n }).property('data.data')\n });\n\n this.Travis.Event.reopenClass({\n byRepoId: function(id) {\n return this.find({\n repository_id: id\n });\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/event");minispade.register('models/extensions', "(function() {(function() {\n\n Travis.DurationCalculations = Ember.Mixin.create({\n duration: (function() {\n var duration;\n if (duration = this.get('_duration')) {\n return duration;\n } else {\n return Travis.Helpers.durationFrom(this.get('startedAt'), this.get('finishedAt'));\n }\n }).property('_duration', 'finishedAt', 'startedAt'),\n updateTimes: function() {\n this.notifyPropertyChange('_duration');\n return this.notifyPropertyChange('finished_at');\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/extensions");minispade.register('models/hook', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Hook = Travis.Model.extend({\n name: DS.attr('string'),\n ownerName: DS.attr('string'),\n description: DS.attr('string'),\n active: DS.attr('boolean'),\n account: (function() {\n return this.get('slug').split('/')[0];\n }).property('slug'),\n slug: (function() {\n return \"\" + (this.get('ownerName')) + \"/\" + (this.get('name'));\n }).property('ownerName', 'name'),\n urlGithub: (function() {\n return \"http://github.com/\" + (this.get('slug'));\n }).property(),\n urlGithubAdmin: (function() {\n return \"http://github.com/\" + (this.get('slug')) + \"/admin/hooks#travis_minibucket\";\n }).property(),\n toggle: function() {\n var transaction;\n transaction = this.get('store').transaction();\n transaction.add(this);\n this.set('active', !this.get('active'));\n return transaction.commit();\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/hook");minispade.register('models/job', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Job = Travis.Model.extend(Travis.DurationCalculations, {\n repoId: DS.attr('number', {\n key: 'repository_id'\n }),\n buildId: DS.attr('number'),\n commitId: DS.attr('number'),\n logId: DS.attr('number'),\n queue: DS.attr('string'),\n state: DS.attr('string'),\n number: DS.attr('string'),\n result: DS.attr('number'),\n _duration: DS.attr('number', {\n key: 'duration'\n }),\n startedAt: DS.attr('string'),\n finishedAt: DS.attr('string'),\n allowFailure: DS.attr('boolean', {\n key: 'allow_failure'\n }),\n repo: DS.belongsTo('Travis.Repo', {\n key: 'repository_id'\n }),\n build: DS.belongsTo('Travis.Build', {\n key: 'build_id'\n }),\n commit: DS.belongsTo('Travis.Commit', {\n key: 'commit_id'\n }),\n log: DS.belongsTo('Travis.Artifact', {\n key: 'log_id'\n }),\n config: (function() {\n return Travis.Helpers.compact(this.get('data.config'));\n }).property('data.config'),\n sponsor: (function() {\n var worker;\n worker = this.get('log.workerName');\n if (worker && worker.length) {\n return Travis.WORKERS[worker] || {\n name: \"Travis Pro\",\n url: \"http://travis-ci.com\"\n };\n }\n }).property('log.workerName'),\n configValues: (function() {\n var config;\n if (config = this.get('config')) {\n return $.values($.only.apply(config, Travis.CONFIG_KEYS));\n } else {\n return [];\n }\n }).property('config'),\n appendLog: function(text) {\n var log;\n if (log = this.get('log')) {\n return log.append(text);\n }\n },\n subscribe: function() {\n var id;\n if (id = this.get('id')) {\n return Travis.app.pusher.subscribe(\"job-\" + id);\n }\n },\n onStateChange: (function() {\n if (this.get('state') === 'finished') {\n return Travis.app.pusher.unsubscribe(\"job-\" + (this.get('id')));\n }\n }).observes('state')\n });\n\n this.Travis.Job.reopenClass({\n queued: function(queue) {\n this.find();\n return Travis.app.store.filter(this, function(job) {\n var queued;\n queued = ['created', 'queued'].indexOf(job.get('state')) !== -1;\n return queued && (!queue || job.get('queue') === (\"builds.\" + queue));\n });\n },\n findMany: function(ids) {\n return Travis.app.store.findMany(this, ids);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/job");minispade.register('models/repo', "(function() {(function() {\nminispade.require('travis/expandable_record_array');\nminispade.require('travis/model');\n\n this.Travis.Repo = Travis.Model.extend({\n slug: DS.attr('string'),\n description: DS.attr('string'),\n lastBuildId: DS.attr('number'),\n lastBuildNumber: DS.attr('string'),\n lastBuildResult: DS.attr('number'),\n lastBuildStartedAt: DS.attr('string'),\n lastBuildFinishedAt: DS.attr('string'),\n lastBuild: DS.belongsTo('Travis.Build'),\n builds: (function() {\n var array, builds, id;\n id = this.get('id');\n builds = Travis.Build.byRepoId(id, {\n event_type: 'push'\n });\n array = Travis.ExpandableRecordArray.create({\n type: Travis.Build,\n content: Ember.A([]),\n store: this.get('store')\n });\n array.load(builds);\n return array;\n }).property(),\n pullRequests: (function() {\n var array, builds, id;\n id = this.get('id');\n builds = Travis.Build.byRepoId(id, {\n event_type: 'pull_request'\n });\n array = Travis.ExpandableRecordArray.create({\n type: Travis.Build,\n content: Ember.A([]),\n store: this.get('store')\n });\n array.load(builds);\n return array;\n }).property(),\n branches: (function() {\n return Travis.Branch.byRepoId(this.get('id'));\n }).property(),\n events: (function() {\n return Travis.Event.byRepoId(this.get('id'));\n }).property(),\n owner: (function() {\n return (this.get('slug') || '').split('/')[0];\n }).property('slug'),\n name: (function() {\n return (this.get('slug') || '').split('/')[1];\n }).property('slug'),\n lastBuildDuration: (function() {\n var duration;\n duration = this.get('data.last_build_duration');\n if (!duration) {\n duration = Travis.Helpers.durationFrom(this.get('lastBuildStartedAt'), this.get('lastBuildFinishedAt'));\n }\n return duration;\n }).property('data.last_build_duration', 'lastBuildStartedAt', 'lastBuildFinishedAt'),\n sortOrder: (function() {\n var lastBuildFinishedAt;\n if (lastBuildFinishedAt = this.get('lastBuildFinishedAt')) {\n return -new Date(lastBuildFinishedAt).getTime();\n } else {\n return -new Date('9999').getTime() - parseInt(this.get('lastBuildId'));\n }\n }).property('lastBuildFinishedAt', 'lastBuildId'),\n stats: (function() {\n var _this = this;\n return this.get('_stats') || $.get(\"https://api.github.com/repos/\" + (this.get('slug')), function(data) {\n _this.set('_stats', data);\n return _this.notifyPropertyChange('stats');\n }) && {};\n }).property(),\n updateTimes: function() {\n return this.notifyPropertyChange('lastBuildDuration');\n }\n });\n\n this.Travis.Repo.reopenClass({\n recent: function() {\n return this.find();\n },\n ownedBy: function(login) {\n return this.find({\n owner_name: login,\n orderBy: 'name'\n });\n },\n accessibleBy: function(login) {\n return this.find({\n member: login,\n orderBy: 'name'\n });\n },\n search: function(query) {\n return this.find({\n search: query,\n orderBy: 'name'\n });\n },\n bySlug: function(slug) {\n var repo;\n repo = $.select(this.find().toArray(), function(repo) {\n return repo.get('slug') === slug;\n });\n if (repo.length > 0) {\n return repo;\n } else {\n return this.find({\n slug: slug\n });\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/repo");minispade.register('models/sponsor', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Sponsor = Travis.Model.extend({\n type: DS.attr('string'),\n url: DS.attr('string'),\n link: DS.attr('string'),\n image: (function() {\n return \"/images/sponsors/\" + (this.get('data.image'));\n }).property('data.image')\n });\n\n Travis.Sponsor.reopenClass({\n decks: function() {\n return this.platinum().concat(this.gold());\n },\n platinum: function() {\n var platinum, sponsor, _i, _len, _results;\n platinum = this.byType('platinum').toArray();\n _results = [];\n for (_i = 0, _len = platinum.length; _i < _len; _i++) {\n sponsor = platinum[_i];\n _results.push([sponsor]);\n }\n return _results;\n },\n gold: function() {\n var gold, _results;\n gold = this.byType('gold').toArray();\n _results = [];\n while (gold.length > 0) {\n _results.push(gold.splice(0, 2));\n }\n return _results;\n },\n links: function() {\n return this.byType('silver');\n },\n byType: function() {\n var types;\n types = Array.prototype.slice.apply(arguments);\n return Travis.Sponsor.filter(function(sponsor) {\n return types.indexOf(sponsor.get('type')) !== -1;\n });\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/sponsor");minispade.register('models/user', "(function() {(function() {\nminispade.require('travis/ajax');\nminispade.require('travis/model');\n\n this.Travis.User = Travis.Model.extend({\n name: DS.attr('string'),\n email: DS.attr('string'),\n login: DS.attr('string'),\n token: DS.attr('string'),\n locale: DS.attr('string'),\n gravatarId: DS.attr('string'),\n isSyncing: DS.attr('boolean'),\n syncedAt: DS.attr('string'),\n repoCount: DS.attr('number'),\n init: function() {\n if (this.get('isSyncing')) {\n this.poll();\n }\n this._super();\n return Ember.run.next(this, function() {\n var transaction;\n transaction = this.get('store').transaction();\n return transaction.add(this);\n });\n },\n urlGithub: (function() {\n return \"https://github.com/\" + (this.get('login'));\n }).property(),\n permissions: (function() {\n var _this = this;\n if (!this.permissions) {\n this.permissions = Ember.ArrayProxy.create({\n content: []\n });\n Travis.ajax.get('/users/permissions', function(data) {\n return _this.permissions.set('content', data.permissions);\n });\n }\n return this.permissions;\n }).property(),\n updateLocale: function(locale) {\n var observer, self, transaction;\n this.setWithSession('locale', locale);\n transaction = this.get('transaction');\n transaction.commit();\n self = this;\n observer = function() {\n if (!self.get('isSaving')) {\n self.removeObserver('isSaving', observer);\n transaction = self.get('store').transaction();\n return transaction.add(self);\n }\n };\n return this.addObserver('isSaving', observer);\n },\n type: (function() {\n return 'user';\n }).property(),\n sync: function() {\n Travis.ajax.post('/users/sync');\n this.setWithSession('isSyncing', true);\n return this.poll();\n },\n poll: function() {\n var _this = this;\n return Travis.ajax.get('/users', function(data) {\n if (data.user.is_syncing) {\n return Ember.run.later(_this, _this.poll.bind(_this), 3000);\n } else {\n _this.set('isSyncing', false);\n return _this.setWithSession('syncedAt', data.user.synced_at);\n }\n });\n },\n setWithSession: function(name, value) {\n var user;\n this.set(name, value);\n user = JSON.parse(typeof sessionStorage !== \"undefined\" && sessionStorage !== null ? sessionStorage.getItem('travis.user') : void 0);\n user[$.underscore(name)] = this.get(name);\n return typeof sessionStorage !== \"undefined\" && sessionStorage !== null ? sessionStorage.setItem('travis.user', JSON.stringify(user)) : void 0;\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/user");minispade.register('models/worker', "(function() {(function() {\nminispade.require('travis/model');\n\n this.Travis.Worker = Travis.Model.extend({\n state: DS.attr('string'),\n name: DS.attr('string'),\n host: DS.attr('string'),\n lastSeenAt: DS.attr('string'),\n payload: (function() {\n return this.get('data.payload');\n }).property('data.payload'),\n number: (function() {\n return this.get('name').match(/\\d+$/)[0];\n }).property('name'),\n isWorking: (function() {\n return this.get('state') === 'working';\n }).property('state'),\n repo: (function() {\n return Travis.Repo.find(this.get('payload.repository.id') || this.get('payload.repo.id'));\n }).property('payload.repository.id', 'payload.repo.id'),\n job_id: (function() {\n return this.get('payload.job.id');\n }).property('payload.job.id'),\n job: (function() {\n return Travis.Job.find(this.get('job_id'));\n }).property('job_id'),\n nameForSort: (function() {\n var id, match, name;\n if (name = this.get('name')) {\n match = name.match(/(.*?)-(\\d+)/);\n if (match) {\n name = match[1];\n id = match[2].toString();\n if (id.length < 2) {\n id = \"00\" + id;\n } else if (id.length < 3) {\n id = \"0\" + id;\n }\n return \"\" + name + \"-\" + id;\n }\n }\n }).property('name')\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=models/worker");minispade.register('pusher', "(function() {(function() {\n\n Travis.Pusher = function(key) {\n if (key) {\n this.init(key);\n }\n return this;\n };\n\n $.extend(Travis.Pusher, {\n CHANNELS: ['common'],\n CHANNEL_PREFIX: ''\n });\n\n $.extend(Travis.Pusher.prototype, {\n active_channels: [],\n init: function(key) {\n var channel, _i, _len, _ref, _results;\n Pusher.warn = this.warn.bind(this);\n this.pusher = new Pusher(key);\n _ref = Travis.Pusher.CHANNELS;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n channel = _ref[_i];\n _results.push(this.subscribe(channel));\n }\n return _results;\n },\n subscribe: function(channel) {\n var _this = this;\n if (this.pusher && this.active_channels.indexOf(channel) === -1) {\n this.active_channels.push(channel);\n return this.pusher.subscribe(this.prefix(channel)).bind_all(function(event, data) {\n return _this.receive(event, data);\n });\n }\n },\n unsubscribe: function(channel) {\n var ix;\n ix = this.active_channels.indexOf(channel);\n if (this.pusher && ix === -1) {\n this.active_channels.splice(ix, 1);\n return this.pusher.unsubscribe(this.prefix(channel));\n }\n },\n prefix: function(channel) {\n return \"\" + Travis.Pusher.CHANNEL_PREFIX + channel;\n },\n receive: function(event, data) {\n if (event.substr(0, 6) === 'pusher') {\n return;\n }\n if (data.id) {\n data = this.normalize(event, data);\n }\n return Ember.run.next(function() {\n return Travis.app.store.receive(event, data);\n });\n },\n normalize: function(event, data) {\n switch (event) {\n case 'build:started':\n case 'build:finished':\n return data;\n case 'job:created':\n case 'job:started':\n case 'job:finished':\n case 'job:log':\n if (data.queue) {\n data.queue = data.queue.replace('builds.', '');\n }\n return {\n job: data\n };\n case 'worker:added':\n case 'worker:updated':\n case 'worker:removed':\n return {\n worker: data\n };\n }\n },\n warn: function(type, warning) {\n if (!this.ignoreWarning(warning)) {\n return console.warn(warning);\n }\n },\n ignoreWarning: function(warning) {\n var message, _ref;\n if (message = (_ref = warning.data) != null ? _ref.message : void 0) {\n return message.indexOf('Existing subscription') === 0 || message.indexOf('No current subscription') === 0;\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=pusher");minispade.register('routes', "(function() {(function() {\n var defaultRoute, lineNumberRoute, nonHashRouteMatcher, resolvePath;\nminispade.require('travis/location');\n\n defaultRoute = Ember.Route.extend({\n route: '/',\n index: 1000\n });\n\n lineNumberRoute = Ember.Route.extend({\n route: '#L:number',\n index: 1,\n connectOutlets: function(router) {\n return router.saveLineNumberHash();\n },\n routeMatcher: Ember.computed(function() {\n var route;\n if (route = this.get('route')) {\n return Ember._RouteMatcher.create({\n route: route,\n init: function() {\n var count, escapeForRegex, escaped, identifiers, regex;\n escapeForRegex = function(text) {\n return text.replace(/[\\-\\[\\]{}()*+?.,\\\\\\^\\$|#\\s]/g, \"\\\\$&\");\n };\n route = this.route;\n identifiers = [];\n count = 1;\n if (route.charAt(0) === '/') {\n route = this.route = route.substr(1);\n }\n escaped = escapeForRegex(route);\n regex = escaped.replace(/:([a-z_]+)(?=$|\\/)/gi, function(match, id) {\n identifiers[count++] = id;\n return \"([0-9]+)\";\n });\n this.identifiers = identifiers;\n return this.regex = new RegExp(regex);\n }\n });\n }\n }).cacheable()\n });\n\n nonHashRouteMatcher = Ember.computed(function() {\n var route;\n if (route = this.get('route')) {\n return Ember._RouteMatcher.create({\n route: route,\n init: function() {\n var count, escapeForRegex, escaped, identifiers, regex;\n escapeForRegex = function(text) {\n return text.replace(/[\\-\\[\\]{}()*+?.,\\\\\\^\\$|#\\s]/g, \"\\\\$&\");\n };\n route = this.route;\n identifiers = [];\n count = 1;\n if (route.charAt(0) === '/') {\n route = this.route = route.substr(1);\n }\n escaped = escapeForRegex(route);\n regex = escaped.replace(/:([a-z_]+)(?=$|\\/)/gi, function(match, id) {\n identifiers[count++] = id;\n return \"([^/#]+)\";\n });\n this.identifiers = identifiers;\n return this.regex = new RegExp(\"^/?\" + regex);\n }\n });\n }\n }).cacheable();\n\n resolvePath = function(manager, path) {\n var childStates, match, resolvedState, state, states;\n if (this.get('isLeafRoute')) {\n return Ember.A();\n }\n childStates = this.get('childStates');\n childStates = Ember.A(childStates.filterProperty('isRoutable'));\n childStates = childStates.sort(function(a, b) {\n var aDynamicSegments, aIndex, aRoute, bDynamicSegments, bIndex, bRoute;\n aDynamicSegments = a.get('routeMatcher.identifiers.length');\n bDynamicSegments = b.get('routeMatcher.identifiers.length');\n aRoute = a.get('route');\n bRoute = b.get('route');\n aIndex = a.get('index');\n bIndex = b.get('index');\n if (aIndex && bIndex) {\n return aIndex - bIndex;\n }\n if (aRoute.indexOf(bRoute) === 0) {\n return -1;\n } else if (bRoute.indexOf(aRoute) === 0) {\n return 1;\n }\n if (aDynamicSegments !== bDynamicSegments) {\n return aDynamicSegments - bDynamicSegments;\n }\n return b.get('route.length') - a.get('route.length');\n });\n match = null;\n state = childStates.find(function(state) {\n var matcher;\n matcher = state.get('routeMatcher');\n if (match = matcher.match(path)) {\n return match;\n }\n });\n Ember.assert(\"Could not find state for path \" + path, !!state);\n resolvedState = Ember._ResolvedState.create({\n manager: manager,\n state: state,\n match: match\n });\n states = state.resolvePath(manager, match.remaining);\n return Ember.A([resolvedState]).pushObjects(states);\n };\n\n Travis.Router = Ember.Router.extend({\n location: 'travis',\n enableLogging: true,\n initialState: 'loading',\n showRoot: Ember.Route.transitionTo('root.home.show'),\n showStats: Ember.Route.transitionTo('root.stats'),\n showRepo: Ember.Route.transitionTo('root.home.repo.show'),\n showBuilds: Ember.Route.transitionTo('root.home.repo.builds.index'),\n showBuild: Ember.Route.transitionTo('root.home.repo.builds.show'),\n showPullRequests: Ember.Route.transitionTo('root.home.repo.pullRequests'),\n showBranches: Ember.Route.transitionTo('root.home.repo.branches'),\n showEvents: Ember.Route.transitionTo('root.home.repo.events'),\n showJob: Ember.Route.transitionTo('root.home.repo.job'),\n showProfile: Ember.Route.transitionTo('root.profile'),\n showAccount: Ember.Route.transitionTo('root.profile.account'),\n showUserProfile: Ember.Route.transitionTo('root.profile.account.profile'),\n saveLineNumberHash: function(path) {\n return Ember.run.next(this, function() {\n var match;\n path = path || this.get('location').getURL();\n if (match = path.match(/#L\\d+$/)) {\n return this.set('repoController.lineNumberHash', match[0]);\n }\n });\n },\n reload: function() {\n var url;\n url = this.get('location').getURL();\n this.transitionTo('loading');\n return this.route(url);\n },\n signedIn: function() {\n return !!Travis.app.get('auth.user');\n },\n needsAuth: function(path) {\n return path.indexOf('/profile') === 0;\n },\n afterSignIn: function() {\n var path;\n path = sessionStorage.getItem('travis.after_signin_path');\n sessionStorage.removeItem('travis.after_signin_path');\n this.transitionTo('root');\n return this.route(path || '/');\n },\n afterSignOut: function() {\n return this.authorize('/');\n },\n authorize: function(path) {\n if (!this.signedIn() && this.needsAuth(path)) {\n sessionStorage.setItem('travis.after_signin_path', path);\n this.transitionTo('root.auth');\n return Travis.app.autoSignIn();\n } else {\n this.transitionTo('root');\n return this.route(path);\n }\n },\n loading: Ember.Route.extend({\n routePath: function(router, path) {\n router.saveLineNumberHash(path);\n return router.authorize(path);\n }\n }),\n root: Ember.Route.extend({\n route: '/',\n loading: Ember.State.extend(),\n auth: Ember.Route.extend({\n route: '/auth',\n connectOutlets: function(router) {\n router.get('applicationController').connectOutlet('authLayout');\n $('body').attr('id', 'auth');\n router.get('authLayoutController').connectOutlet('top', 'top');\n return router.get('authLayoutController').connectOutlet('main', 'signin');\n }\n }),\n stats: Ember.Route.extend({\n route: '/stats',\n afterSignIn: (function() {}),\n connectOutlets: function(router) {\n router.get('applicationController').connectOutlet('statsLayout');\n $('body').attr('id', 'stats');\n router.get('statsLayoutController').connectOutlet('top', 'top');\n return router.get('statsLayoutController').connectOutlet('main', 'stats');\n }\n }),\n profile: Ember.Route.extend({\n initialState: 'index',\n afterSignIn: (function() {}),\n route: '/profile',\n connectOutlets: function(router) {\n router.get('applicationController').connectOutlet('profileLayout');\n $('body').attr('id', 'profile');\n router.get('accountsController').set('content', Travis.Account.find());\n router.get('profileLayoutController').connectOutlet('top', 'top');\n return router.get('profileLayoutController').connectOutlet('left', 'accounts');\n },\n index: Ember.Route.extend({\n route: '/',\n connectOutlets: function(router) {\n router.get('profileLayoutController').connectOutlet('main', 'profile');\n return router.get('profileController').activate('hooks');\n }\n }),\n account: Ember.Route.extend({\n initialState: 'index',\n route: '/:login',\n connectOutlets: function(router, account) {\n var params;\n if (account) {\n params = {\n login: account.get('login')\n };\n return router.get('profileController').setParams(params);\n } else {\n return router.send('showProfile');\n }\n },\n deserialize: function(router, params) {\n var account, controller, deferred, observer;\n controller = router.get('accountsController');\n if (!controller.get('content')) {\n controller.set('content', Travis.Account.find());\n }\n account = controller.findByLogin(params.login);\n if (account) {\n return account;\n } else {\n deferred = $.Deferred();\n observer = function() {\n if (account = controller.findByLogin(params.login)) {\n controller.removeObserver('content.length', observer);\n return deferred.resolve(account);\n }\n };\n controller.addObserver('content.length', observer);\n return deferred.promise();\n }\n },\n serialize: function(router, account) {\n if (account) {\n return {\n login: account.get('login')\n };\n } else {\n return {};\n }\n },\n index: Ember.Route.extend({\n route: '/',\n connectOutlets: function(router) {\n return router.get('profileController').activate('hooks');\n }\n }),\n profile: Ember.Route.extend({\n route: '/profile',\n connectOutlets: function(router) {\n return router.get('profileController').activate('user');\n }\n })\n })\n }),\n home: Ember.Route.extend({\n route: '/',\n afterSignIn: (function() {}),\n connectOutlets: function(router) {\n router.get('applicationController').connectOutlet('homeLayout');\n $('body').attr('id', 'home');\n router.get('homeLayoutController').connectOutlet('left', 'repos');\n router.get('homeLayoutController').connectOutlet('right', 'sidebar');\n router.get('homeLayoutController').connectOutlet('top', 'top');\n router.get('homeLayoutController').connectOutlet('main', 'repo');\n router.get('homeLayoutController').connectOutlet('flash', 'flash');\n return router.get('repoController').set('repos', router.get('reposController'));\n },\n show: Ember.Route.extend({\n route: '/',\n connectOutlets: function(router) {\n return router.get('repoController').activate('index');\n },\n initialState: 'default',\n \"default\": defaultRoute,\n lineNumber: lineNumberRoute,\n resolvePath: resolvePath\n }),\n showWithLineNumber: Ember.Route.extend({\n route: '/#/L:number',\n connectOutlets: function(router) {\n return router.get('repoController').activate('index');\n }\n }),\n repo: Ember.Route.extend({\n route: '/:owner/:name',\n routeMatcher: nonHashRouteMatcher,\n connectOutlets: function(router, repo) {\n return router.get('repoController').set('repo', repo);\n },\n deserialize: function(router, params) {\n var deferred, observer, repos, slug;\n slug = \"\" + params.owner + \"/\" + params.name;\n repos = Travis.Repo.bySlug(slug);\n deferred = $.Deferred();\n observer = function() {\n if (repos.get('isLoaded')) {\n repos.removeObserver('isLoaded', observer);\n return deferred.resolve(repos.objectAt(0));\n }\n };\n if (repos.length) {\n deferred.resolve(repos[0]);\n } else {\n repos.addObserver('isLoaded', observer);\n }\n return deferred.promise();\n },\n serialize: function(router, repo) {\n if (repo) {\n return {\n owner: repo.get('owner'),\n name: repo.get('name')\n };\n } else {\n return {};\n }\n },\n show: Ember.Route.extend({\n route: '/',\n connectOutlets: function(router) {\n return router.get('repoController').activate('current');\n },\n initialState: 'default',\n \"default\": defaultRoute,\n lineNumber: lineNumberRoute,\n resolvePath: resolvePath\n }),\n builds: Ember.Route.extend({\n route: '/builds',\n index: Ember.Route.extend({\n route: '/',\n connectOutlets: function(router, repo) {\n return router.get('repoController').activate('builds');\n }\n }),\n show: Ember.Route.extend({\n route: '/:build_id',\n connectOutlets: function(router, build) {\n if (!build.get) {\n build = Travis.Build.find(build);\n }\n router.get('repoController').set('build', build);\n return router.get('repoController').activate('build');\n },\n serialize: function(router, build) {\n if (build.get) {\n return {\n build_id: build.get('id')\n };\n } else {\n return {\n build_id: build\n };\n }\n },\n deserialize: function(router, params) {\n var build, deferred, observer;\n build = Travis.Build.find(params.build_id);\n if (build.get('id')) {\n return build;\n } else {\n deferred = $.Deferred();\n observer = function() {\n if (build.get('id')) {\n build.removeObserver('id', observer);\n return deferred.resolve(build);\n }\n };\n build.addObserver('id', observer);\n return deferred.promise();\n }\n },\n initialState: 'default',\n \"default\": defaultRoute,\n lineNumber: lineNumberRoute,\n routeMatcher: nonHashRouteMatcher,\n resolvePath: resolvePath\n })\n }),\n pullRequests: Ember.Route.extend({\n route: '/pull_requests',\n connectOutlets: function(router, repo) {\n return router.get('repoController').activate('pull_requests');\n }\n }),\n branches: Ember.Route.extend({\n route: '/branches',\n connectOutlets: function(router, repo) {\n return router.get('repoController').activate('branches');\n }\n }),\n events: Ember.Route.extend({\n route: '/events',\n connectOutlets: function(router, repo) {\n return router.get('repoController').activate('events');\n }\n }),\n job: Ember.Route.extend({\n route: '/jobs/:job_id',\n connectOutlets: function(router, job) {\n if (!job.get) {\n job = Travis.Job.find(job);\n }\n router.get('repoController').set('job', job);\n return router.get('repoController').activate('job');\n },\n serialize: function(router, job) {\n if (job.get) {\n return {\n job_id: job.get('id')\n };\n } else {\n return {\n job_id: job\n };\n }\n },\n deserialize: function(router, params) {\n var deferred, job, observer;\n job = Travis.Job.find(params.job_id);\n if (job.get('id')) {\n return job;\n } else {\n deferred = $.Deferred();\n observer = function() {\n if (job.get('id')) {\n job.removeObserver('id', observer);\n return deferred.resolve(job);\n }\n };\n job.addObserver('id', observer);\n return deferred.promise();\n }\n },\n initialState: 'default',\n \"default\": defaultRoute,\n lineNumber: lineNumberRoute,\n routeMatcher: nonHashRouteMatcher,\n resolvePath: resolvePath\n })\n })\n })\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=routes");minispade.register('slider', "(function() {(function() {\n\n this.Travis.Slider = function() {\n if ((typeof localStorage !== \"undefined\" && localStorage !== null ? localStorage.getItem('travis.maximized') : void 0) === 'true') {\n this.minimize();\n }\n return this;\n };\n\n $.extend(Travis.Slider.prototype, {\n persist: function() {\n return typeof localStorage !== \"undefined\" && localStorage !== null ? localStorage.setItem('travis.maximized', this.isMinimized()) : void 0;\n },\n isMinimized: function() {\n return $('body').hasClass('maximized');\n },\n minimize: function() {\n return $('body').addClass('maximized');\n },\n toggle: function() {\n var element;\n $('body').toggleClass('maximized');\n this.persist();\n element = $(' ');\n $('#top .profile').append(element);\n return Em.run.later((function() {\n return element.remove();\n }), 10);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=slider");minispade.register('store', "(function() {(function() {\n var DATA_PROXY,\n __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };\nminispade.require('store/rest_adapter');\n\n DATA_PROXY = {\n get: function(name) {\n return this.savedData[name];\n }\n };\n\n Travis.Store = DS.Store.extend({\n revision: 4,\n adapter: Travis.RestAdapter.create(),\n load: function(type, id, hash) {\n var record, result;\n result = this._super.apply(this, arguments);\n if (result && result.clientId) {\n record = this.findByClientId(type, result.clientId);\n record.set('incomplete', false);\n record.set('complete', true);\n }\n return result;\n },\n merge: function(type, id, hash) {\n var clientId, data, dataCache, primaryKey, record, recordCache, typeMap;\n if (hash === void 0) {\n hash = id;\n primaryKey = type.proto().primaryKey;\n Ember.assert(\"A data hash was loaded for a record of type \" + type.toString() + \" but no primary key '\" + primaryKey + \"' was provided.\", hash[primaryKey]);\n id = hash[primaryKey];\n }\n typeMap = this.typeMapFor(type);\n dataCache = typeMap.cidToHash;\n clientId = typeMap.idToCid[id];\n recordCache = this.get('recordCache');\n if (clientId !== void 0) {\n if (data = dataCache[clientId]) {\n $.extend(data, hash);\n } else {\n dataCache[clientId] = hash;\n }\n if (record = recordCache[clientId]) {\n record.send('didChangeData');\n }\n } else {\n clientId = this.pushHash(hash, id, type);\n }\n if (clientId) {\n DATA_PROXY.savedData = hash;\n this.updateRecordArrays(type, clientId, DATA_PROXY);\n return {\n id: id,\n clientId: clientId\n };\n }\n },\n receive: function(event, data) {\n var job, mappings, name, type, _ref;\n _ref = event.split(':'), name = _ref[0], type = _ref[1];\n mappings = this.adapter.get('mappings');\n type = mappings[name];\n if (event === 'job:log') {\n if (job = this.find(Travis.Job, data['job']['id'])) {\n return job.appendLog(data['job']['_log']);\n }\n } else if (data[type.singularName()]) {\n return this._loadOne(this, type, data);\n } else if (data[type.pluralName()]) {\n return this._loadMany(this, type, data);\n } else {\n if (!type) {\n throw \"can't load data for \" + name;\n }\n }\n },\n _loadOne: function(store, type, json) {\n var result, root;\n root = type.singularName();\n if (type === Travis.Build && json.repository) {\n result = this._loadIncomplete(Travis.Repo, 'repository', json.repository);\n }\n return this._loadIncomplete(type, root, json[root]);\n },\n _loadIncomplete: function(type, root, hash) {\n var record, result;\n result = this.merge(type, hash);\n if (result && result.clientId) {\n record = this.findByClientId(type, result.clientId);\n if (!record.get('complete')) {\n record.set('incomplete', true);\n }\n return this._updateAssociations(type, root, hash);\n }\n },\n _loadMany: function(store, type, json) {\n var root;\n root = type.pluralName();\n this.adapter.sideload(store, type, json, root);\n return this.loadMany(type, json[root]);\n },\n _updateAssociations: function(type, name, data) {\n var _this = this;\n return Em.get(type, 'associationsByName').forEach(function(key, meta) {\n var clientId, dataProxy, id, ids, parent, _ref;\n if (meta.kind === 'belongsTo') {\n id = data[\"\" + key + \"_id\"];\n if (clientId = _this.typeMapFor(meta.type).idToCid[id]) {\n if (parent = _this.findByClientId(meta.type, clientId, id)) {\n dataProxy = parent.get('data');\n if (ids = dataProxy.get(\"\" + name + \"_ids\")) {\n if (_ref = data.id, __indexOf.call(ids, _ref) < 0) {\n ids.pushObject(data.id);\n }\n return parent.send('didChangeData');\n }\n }\n }\n }\n });\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=store");minispade.register('store/fixture_adapter', "(function() {(function() {\n\n this.Travis.FixtureAdapter = DS.Adapter.extend({\n find: function(store, type, id) {\n var fixtures;\n fixtures = type.FIXTURES;\n Ember.assert(\"Unable to find fixtures for model type \" + type.toString(), !!fixtures);\n if (fixtures.hasLoaded) {\n return;\n }\n return setTimeout((function() {\n store.loadMany(type, fixtures);\n return fixtures.hasLoaded = true;\n }), 300);\n },\n findMany: function() {\n return this.find.apply(this, arguments);\n },\n findAll: function(store, type) {\n var fixtures, ids;\n fixtures = type.FIXTURES;\n Ember.assert(\"Unable to find fixtures for model type \" + type.toString(), !!fixtures);\n ids = fixtures.map(function(item, index, self) {\n return item.id;\n });\n return store.loadMany(type, ids, fixtures);\n },\n findQuery: function(store, type, params, array) {\n var fixture, fixtures, hashes, key, matches, value;\n fixtures = type.FIXTURES;\n Ember.assert(\"Unable to find fixtures for model type \" + type.toString(), !!fixtures);\n hashes = (function() {\n var _i, _len, _results;\n _results = [];\n for (_i = 0, _len = fixtures.length; _i < _len; _i++) {\n fixture = fixtures[_i];\n matches = (function() {\n var _results1;\n _results1 = [];\n for (key in params) {\n value = params[key];\n _results1.push(key === 'orderBy' || fixture[key] === value);\n }\n return _results1;\n })();\n if (matches.reduce(function(a, b) {\n return a && b;\n })) {\n _results.push(fixture);\n } else {\n _results.push(null);\n }\n }\n return _results;\n })();\n return array.load(hashes.compact());\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=store/fixture_adapter");minispade.register('store/rest_adapter', "(function() {(function() {\nminispade.require('travis/ajax');\nminispade.require('models');\n\n this.Travis.RestAdapter = DS.RESTAdapter.extend({\n mappings: {\n repositories: Travis.Repo,\n repository: Travis.Repo,\n repos: Travis.Repo,\n repo: Travis.Repo,\n builds: Travis.Build,\n build: Travis.Build,\n commits: Travis.Commit,\n commit: Travis.Commit,\n jobs: Travis.Job,\n job: Travis.Job,\n account: Travis.Account,\n accounts: Travis.Account,\n worker: Travis.Worker,\n workers: Travis.Worker\n },\n plurals: {\n repositories: 'repositories',\n repository: 'repositories',\n repo: 'repos',\n repos: 'repos',\n build: 'builds',\n branch: 'branches',\n job: 'jobs',\n worker: 'workers',\n profile: 'profile'\n },\n ajax: function() {\n return Travis.ajax.ajax.apply(this, arguments);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=store/rest_adapter");minispade.register('tailing', "(function() {(function() {\n\n this.Travis.Tailing = function() {\n this.position = $(window).scrollTop();\n $(window).scroll(this.onScroll.bind(this));\n return this;\n };\n\n $.extend(Travis.Tailing.prototype, {\n options: {\n timeout: 200\n },\n run: function() {\n this.autoScroll();\n this.positionButton();\n if (this.active()) {\n return Ember.run.later(this.run.bind(this), this.options.timeout);\n }\n },\n toggle: function(event) {\n if (this.active()) {\n return this.stop();\n } else {\n return this.start();\n }\n },\n active: function() {\n return $('#tail').hasClass('active');\n },\n start: function() {\n $('#tail').addClass('active');\n return this.run();\n },\n stop: function() {\n return $('#tail').removeClass('active');\n },\n autoScroll: function() {\n var log, logBottom, win, winBottom;\n if (!this.active()) {\n return;\n }\n win = $(window);\n log = $('#log');\n logBottom = log.offset().top + log.outerHeight() + 40;\n winBottom = win.scrollTop() + win.height();\n if (logBottom - winBottom > 0) {\n return win.scrollTop(logBottom - win.height());\n }\n },\n onScroll: function() {\n var position;\n this.positionButton();\n position = $(window).scrollTop();\n if (position < this.position) {\n this.stop();\n }\n return this.position = position;\n },\n positionButton: function() {\n var max, offset, tail;\n tail = $('#tail');\n if (tail.length === 0) {\n return;\n }\n offset = $(window).scrollTop() - $('#log').offset().top;\n max = $('#log').height() - $('#tail').height() + 5;\n if (offset > max) {\n offset = max;\n }\n if (offset > 0) {\n return tail.css({\n top: offset - 2\n });\n } else {\n return tail.css({\n top: 0\n });\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=tailing");minispade.register('views', "(function() {(function() {\nminispade.require('ext/ember/namespace');\n\n this.Travis.reopen({\n View: Em.View.extend({\n popup: function(event) {\n this.popupCloseAll();\n return $(\"#\" + event.target.name).toggleClass('display');\n },\n popupClose: function(event) {\n return $(event.target).closest('.popup').removeClass('display');\n },\n popupCloseAll: function() {\n return $('.popup').removeClass('display');\n }\n })\n });\n\n this.Travis.reopen({\n HomeLayoutView: Travis.View.extend({\n templateName: 'layouts/home'\n }),\n AuthLayoutView: Travis.View.extend({\n templateName: 'layouts/simple'\n }),\n ProfileLayoutView: Travis.View.extend({\n templateName: 'layouts/profile'\n }),\n StatsLayoutView: Travis.View.extend({\n templateName: 'layouts/simple'\n })\n });\nminispade.require('views/accounts');\nminispade.require('views/application');\nminispade.require('views/build');\nminispade.require('views/events');\nminispade.require('views/flash');\nminispade.require('views/job');\nminispade.require('views/repo');\nminispade.require('views/profile');\nminispade.require('views/sidebar');\nminispade.require('views/stats');\nminispade.require('views/signin');\nminispade.require('views/top');\n\n}).call(this);\n\n})();\n//@ sourceURL=views");minispade.register('views/accounts', "(function() {(function() {\n\n this.Travis.reopen({\n AccountsView: Travis.View.extend({\n tabBinding: 'controller.tab',\n templateName: 'profile/accounts',\n classAccounts: (function() {\n if (this.get('tab') === 'accounts') {\n return 'active';\n }\n }).property('tab')\n }),\n AccountsListView: Em.CollectionView.extend({\n elementId: 'accounts',\n accountBinding: 'content',\n tagName: 'ul',\n emptyView: Ember.View.extend({\n template: Ember.Handlebars.compile('Loading
')\n }),\n itemViewClass: Travis.View.extend({\n accountBinding: 'content',\n typeBinding: 'content.type',\n selectedBinding: 'account.selected',\n classNames: ['account'],\n classNameBindings: ['type', 'selected'],\n name: (function() {\n return this.get('content.name') || this.get('content.login');\n }).property('content.login', 'content.name'),\n urlAccount: (function() {\n return Travis.Urls.account(this.get('account.login'));\n }).property('account.login')\n })\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/accounts");minispade.register('views/application', "(function() {(function() {\n\n this.Travis.reopen({\n ApplicationView: Travis.View.extend({\n templateName: 'application',\n classNames: ['application'],\n localeDidChange: (function() {\n var locale;\n if (locale = Travis.app.get('auth.user.locale')) {\n Travis.setLocale(locale);\n return Travis.app.get('router').reload();\n }\n }).observes('Travis.app.auth.user.locale'),\n click: function(event) {\n if (!$(event.target).parents().andSelf().hasClass('popup')) {\n this.popupCloseAll();\n }\n if (!$(event.target).parents().andSelf().hasClass('menu')) {\n return $('.menu').removeClass('display');\n }\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/application");minispade.register('views/build', "(function() {(function() {\n\n this.Travis.reopen({\n BuildsView: Travis.View.extend({\n templateName: 'builds/list',\n buildsBinding: 'controller.builds',\n showMore: function() {\n var id, number;\n id = this.get('controller.repo.id');\n number = this.get('builds.lastObject.number');\n return this.get('builds').load(Travis.Build.olderThanNumber(id, number));\n },\n ShowMoreButton: Em.View.extend({\n tagName: 'button',\n classNameBindings: ['isLoading'],\n attributeBindings: ['disabled'],\n isLoadingBinding: 'controller.builds.isLoading',\n template: Em.Handlebars.compile('{{view.label}}'),\n disabledBinding: 'isLoading',\n label: (function() {\n if (this.get('isLoading')) {\n return 'Loading';\n } else {\n return 'Show more';\n }\n }).property('isLoading'),\n click: function() {\n return this.get('parentView').showMore();\n }\n })\n }),\n BuildsItemView: Travis.View.extend({\n tagName: 'tr',\n classNameBindings: ['color'],\n repoBinding: 'controller.repo',\n buildBinding: 'context',\n commitBinding: 'build.commit',\n color: (function() {\n return Travis.Helpers.colorForResult(this.get('build.result'));\n }).property('build.result'),\n urlBuild: (function() {\n return Travis.Urls.build(this.get('repo.slug'), this.get('build.id'));\n }).property('repo.slug', 'build.id'),\n urlGithubCommit: (function() {\n return Travis.Urls.githubCommit(this.get('repo.slug'), this.get('commit.sha'));\n }).property('repo.slug', 'commit.sha')\n }),\n BuildView: Travis.View.extend({\n templateName: 'builds/show',\n elementId: 'build',\n classNameBindings: ['color', 'loading'],\n repoBinding: 'controller.repo',\n buildBinding: 'controller.build',\n commitBinding: 'build.commit',\n currentItemBinding: 'build',\n loading: (function() {\n return !this.get('build.isComplete');\n }).property('build.isComplete'),\n color: (function() {\n return Travis.Helpers.colorForResult(this.get('build.result'));\n }).property('build.result'),\n urlBuild: (function() {\n return Travis.Urls.build(this.get('repo.slug'), this.get('build.id'));\n }).property('repo.slug', 'build.id'),\n urlGithubCommit: (function() {\n return Travis.Urls.githubCommit(this.get('repo.slug'), this.get('commit.sha'));\n }).property('repo.slug', 'commit.sha'),\n urlAuthor: (function() {\n return Travis.Urls.email(this.get('commit.authorEmail'));\n }).property('commit.authorEmail'),\n urlCommitter: (function() {\n return Travis.Urls.email(this.get('commit.committerEmail'));\n }).property('commit.committerEmail')\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/build");minispade.register('views/events', "(function() {(function() {\n\n this.Travis.reopen({\n EventsView: Travis.View.extend({\n templateName: 'events/list',\n eventsBinding: 'controller.events'\n }),\n EventsItemView: Travis.View.extend({\n tagName: 'tr'\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/events");minispade.register('views/flash', "(function() {(function() {\n\n this.Travis.reopen({\n FlashView: Travis.View.extend({\n elementId: 'flash',\n tagName: 'ul',\n templateName: 'layouts/flash'\n }),\n FlashItemView: Travis.View.extend({\n tagName: 'li',\n classNameBindings: ['type'],\n type: (function() {\n return this.get('flash') && Ember.keys(this.get('flash'))[0];\n }).property('flash'),\n message: (function() {\n return this.get('flash') && this.get('flash')[this.get('type')];\n }).property('flash'),\n close: function(event) {\n return this.get('controller').removeObject(this.get('flash'));\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/flash");minispade.register('views/job', "(function() {(function() {\n\n this.Travis.reopen({\n JobsView: Travis.View.extend({\n templateName: 'jobs/list',\n buildBinding: 'controller.build'\n }),\n JobsItemView: Travis.View.extend({\n tagName: 'tr',\n classNameBindings: ['color'],\n repoBinding: 'context.repo',\n jobBinding: 'context',\n color: (function() {\n return Travis.Helpers.colorForResult(this.get('job.result'));\n }).property('job.result'),\n urlJob: (function() {\n return Travis.Urls.job(this.get('repo.slug'), this.get('job.id'));\n }).property('repo.slug', 'job.id')\n }),\n JobView: Travis.View.extend({\n templateName: 'jobs/show',\n repoBinding: 'controller.repo',\n jobBinding: 'controller.job',\n commitBinding: 'job.commit',\n currentItemBinding: 'job',\n color: (function() {\n return Travis.Helpers.colorForResult(this.get('job.result'));\n }).property('job.result'),\n urlJob: (function() {\n return Travis.Urls.job(this.get('repo.slug'), this.get('job.id'));\n }).property('repo.slug', 'job.id'),\n urlGithubCommit: (function() {\n return Travis.Urls.githubCommit(this.get('repo.slug'), this.get('commit.sha'));\n }).property('repo.slug', 'commit.sha'),\n urlAuthor: (function() {\n return Travis.Urls.email(this.get('commit.authorEmail'));\n }).property('commit.authorEmail'),\n urlCommitter: (function() {\n return Travis.Urls.email(this.get('commit.committerEmail'));\n }).property('commit.committerEmail')\n }),\n LogView: Travis.View.extend({\n templateName: 'jobs/log',\n logBinding: 'job.log',\n scrollTo: function(hash) {\n $('body').scrollTop($(hash).offset().top);\n return this.set('controller.lineNumberHash', null);\n },\n lineNumberHashDidChange: (function() {\n return this.tryScrollingToHashLineNumber();\n }).observes('controller.lineNumberHash'),\n tryScrollingToHashLineNumber: function() {\n var checker, hash, self;\n if (hash = this.get('controller.lineNumberHash')) {\n self = this;\n checker = function() {\n if (self.get('isDestroyed')) {\n return;\n }\n if ($(hash).length) {\n return self.scrollTo(hash);\n } else {\n return setTimeout(checker, 100);\n }\n };\n return checker();\n }\n },\n didInsertElement: function() {\n this._super.apply(this, arguments);\n return this.tryScrollingToHashLineNumber();\n },\n click: function(event) {\n var path, target;\n target = $(event.target);\n target.closest('.fold').toggleClass('open');\n if (target.is('.log-line-number')) {\n path = target.attr('href');\n Travis.app.get('router').route(path);\n event.stopPropagation();\n return false;\n }\n },\n toTop: function() {\n return $(window).scrollTop(0);\n },\n jobBinding: 'context',\n toggleTailing: function(event) {\n Travis.app.tailing.toggle();\n return event.preventDefault();\n },\n logSubscriber: (function() {\n var job, state;\n job = this.get('job');\n state = this.get('job.state');\n if (job && state !== 'finished') {\n job.subscribe();\n }\n return null;\n }).property('job', 'job.state')\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/job");minispade.register('views/left', "(function() {(function() {\n\n this.Travis.reopen({\n ReposView: Travis.View.extend({\n templateName: 'repos/list',\n tabBinding: 'controller.tab',\n classRecent: (function() {\n if (this.get('tab') === 'recent') {\n return 'active';\n }\n }).property('tab'),\n classOwned: (function() {\n var classes;\n classes = [];\n if (this.get('tab') === 'owned') {\n classes.push('active');\n }\n if (Travis.app.get('currentUser')) {\n classes.push('display');\n }\n return classes.join(' ');\n }).property('tab', 'Travis.currentUser'),\n classSearch: (function() {\n if (this.get('tab') === 'search') {\n return 'active';\n }\n }).property('tab')\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/left");minispade.register('views/profile', "(function() {(function() {\n\n this.Travis.reopen({\n ProfileView: Travis.View.extend({\n templateName: 'profile/show',\n accountBinding: 'controller.account',\n name: (function() {\n return this.get('account.name') || this.get('account.login');\n }).property('account.name', 'account.login')\n }),\n ProfileTabsView: Travis.View.extend({\n templateName: 'profile/tabs',\n tabBinding: 'controller.tab',\n activate: function(event) {\n return this.get('controller').activate(event.target.name);\n },\n classHooks: (function() {\n if (this.get('tab') === 'hooks') {\n return 'active';\n }\n }).property('tab'),\n classUser: (function() {\n if (this.get('tab') === 'user') {\n return 'active';\n }\n }).property('tab'),\n accountBinding: 'controller.account',\n displayUser: (function() {\n return this.get('controller.account.login') === this.get('controller.user.login');\n }).property('controller.account.login', 'controller.user.login')\n }),\n HooksView: Travis.View.extend({\n templateName: 'profile/tabs/hooks',\n userBinding: 'controller.user',\n urlGithubAdmin: (function() {\n return Travis.Urls.githubAdmin(this.get('hook.slug'));\n }).property('hook.slug')\n }),\n UserView: Travis.View.extend({\n templateName: 'profile/tabs/user',\n userBinding: 'controller.user',\n gravatarUrl: (function() {\n return \"\" + location.protocol + \"//www.gravatar.com/avatar/\" + (this.get('user.gravatarId')) + \"?s=48&d=mm\";\n }).property('user.gravatarId'),\n locales: (function() {\n return [\n {\n key: null,\n name: ''\n }, {\n key: 'en',\n name: 'English'\n }, {\n key: 'ca',\n name: 'Catalan'\n }, {\n key: 'cs',\n name: 'Čeština'\n }, {\n key: 'es',\n name: 'Español'\n }, {\n key: 'fr',\n name: 'Français'\n }, {\n key: 'ja',\n name: '日本語'\n }, {\n key: 'nl',\n name: 'Nederlands'\n }, {\n key: 'nb',\n name: 'Norsk Bokmål'\n }, {\n key: 'pl',\n name: 'Polski'\n }, {\n key: {\n 'pt-BR': {\n name: 'Português brasileiro'\n }\n }\n }, {\n key: 'ru',\n name: 'Русский'\n }\n ];\n }).property(),\n saveLocale: function(event) {\n return this.get('user').updateLocale($('#locale').val());\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/profile");minispade.register('views/repo', "(function() {(function() {\nminispade.require('views/repo/list');\nminispade.require('views/repo/show');\n\n}).call(this);\n\n})();\n//@ sourceURL=views/repo");minispade.register('views/repo/list', "(function() {(function() {\n\n this.Travis.reopen({\n ReposView: Travis.View.extend({\n templateName: 'repos/list',\n toggleInfo: function(event) {\n return $('#repos').toggleClass('open');\n }\n }),\n ReposListView: Em.CollectionView.extend({\n elementId: 'repos',\n tagName: 'ul',\n emptyView: Ember.View.extend({\n template: Ember.Handlebars.compile('Loading
')\n }),\n itemViewClass: Travis.View.extend({\n repoBinding: 'content',\n classNames: ['repo'],\n classNameBindings: ['color', 'selected'],\n selectedBinding: 'repo.selected',\n color: (function() {\n return Travis.Helpers.colorForResult(this.get('repo.lastBuildResult'));\n }).property('repo.lastBuildResult'),\n urlRepo: (function() {\n return Travis.Urls.repo(this.get('repo.slug'));\n }).property('repo.slug'),\n urlLastBuild: (function() {\n return Travis.Urls.build(this.get('repo.slug'), this.get('repo.lastBuildId'));\n }).property('repo.slug', 'repo.lastBuildId')\n })\n }),\n ReposListTabsView: Travis.View.extend({\n templateName: 'repos/list/tabs',\n tabBinding: 'controller.tab',\n activate: function(event) {\n return this.get('controller').activate(event.target.name);\n },\n classRecent: (function() {\n if (this.get('tab') === 'recent') {\n return 'active';\n }\n }).property('tab'),\n classOwned: (function() {\n var classes;\n classes = [];\n if (this.get('tab') === 'owned') {\n classes.push('active');\n }\n if (Travis.app.get('currentUser')) {\n classes.push('display-inline');\n }\n return classes.join(' ');\n }).property('tab', 'Travis.app.currentUser'),\n classSearch: (function() {\n if (this.get('tab') === 'search') {\n return 'active';\n }\n }).property('tab')\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/repo/list");minispade.register('views/repo/show', "(function() {(function() {\n\n this.Travis.reopen({\n RepoView: Travis.View.extend({\n templateName: 'repos/show',\n reposBinding: 'controller.repos',\n repoBinding: 'controller.repo',\n \"class\": (function() {\n if (!this.get('repo.isComplete') && !this.get('isEmpty')) {\n return 'loading';\n }\n }).property('repo.isComplete'),\n isEmpty: (function() {\n return this.get('repos.length') === 0;\n }).property('repos.length'),\n urlGithub: (function() {\n return Travis.Urls.githubRepo(this.get('repo.slug'));\n }).property('repo.slug'),\n urlGithubWatchers: (function() {\n return Travis.Urls.githubWatchers(this.get('repo.slug'));\n }).property('repo.slug'),\n urlGithubNetwork: (function() {\n return Travis.Urls.githubNetwork(this.get('repo.slug'));\n }).property('repo.slug')\n }),\n ReposEmptyView: Travis.View.extend({\n template: ''\n }),\n RepoShowTabsView: Travis.View.extend({\n templateName: 'repos/show/tabs',\n repoBinding: 'controller.repo',\n buildBinding: 'controller.build',\n jobBinding: 'controller.job',\n tabBinding: 'controller.tab',\n classCurrent: (function() {\n if (this.get('tab') === 'current') {\n return 'active';\n }\n }).property('tab'),\n classBuilds: (function() {\n if (this.get('tab') === 'builds') {\n return 'active';\n }\n }).property('tab'),\n classPullRequests: (function() {\n if (this.get('tab') === 'pull_requests') {\n return 'active';\n }\n }).property('tab'),\n classBranches: (function() {\n if (this.get('tab') === 'branches') {\n return 'active';\n }\n }).property('tab'),\n classEvents: (function() {\n if (this.get('tab') === 'events') {\n return 'active';\n }\n }).property('tab'),\n classBuild: (function() {\n var classes, tab;\n tab = this.get('tab');\n classes = [];\n if (tab === 'build') {\n classes.push('active');\n }\n if (tab === 'build' || tab === 'job') {\n classes.push('display-inline');\n }\n return classes.join(' ');\n }).property('tab'),\n classJob: (function() {\n if (this.get('tab') === 'job') {\n return 'active display-inline';\n }\n }).property('tab')\n }),\n RepoShowToolsView: Travis.View.extend({\n templateName: 'repos/show/tools',\n repoBinding: 'controller.repo',\n buildBinding: 'controller.build',\n jobBinding: 'controller.job',\n tabBinding: 'controller.tab',\n closeMenu: function() {\n return $('.menu').removeClass('display');\n },\n menu: function(event) {\n var element;\n this.popupCloseAll();\n element = $('#tools .menu').toggleClass('display');\n return event.stopPropagation();\n },\n requeue: function() {\n this.closeMenu();\n return this.get('build').requeue();\n },\n statusImages: function(event) {\n this.set('active', true);\n this.closeMenu();\n this.popup(event);\n return event.stopPropagation();\n },\n canPush: (function() {\n return this.get('isBuildTab') && this.get('build.isFinished') && this.get('hasPushPermissions');\n }).property('build.isFinished', 'hasPushPermissions', 'isBuildTab'),\n isBuildTab: (function() {\n return ['current', 'build', 'job'].indexOf(this.get('tab')) > -1;\n }).property('tab'),\n hasPushPermissions: (function() {\n var permissions;\n if (permissions = Travis.app.get('currentUser.permissions')) {\n return permissions.indexOf(this.get('repo.id')) > -1;\n }\n }).property('Travis.app.currentUser.permissions.length', 'repo.id'),\n branches: (function() {\n if (this.get('active')) {\n return this.get('repo.branches');\n }\n }).property('active', 'repo.branches'),\n urlRepo: (function() {\n return 'https://' + location.host + Travis.Urls.repo(this.get('repo.slug'));\n }).property('repo.slug'),\n urlStatusImage: (function() {\n return Travis.Urls.statusImage(this.get('repo.slug'), this.get('branch.commit.branch'));\n }).property('repo.slug', 'branch'),\n markdownStatusImage: (function() {\n return \"[) + \")](\" + (this.get('urlRepo')) + \")\";\n }).property('urlStatusImage'),\n textileStatusImage: (function() {\n return \"!\" + (this.get('urlStatusImage')) + \"!:\" + (this.get('urlRepo'));\n }).property('urlStatusImage'),\n rdocStatusImage: (function() {\n return \"{ }[\" + (this.get('urlRepo')) + \"]\";\n }).property('urlStatusImage')\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/repo/show");minispade.register('views/sidebar', "(function() {(function() {\n\n this.Travis.reopen({\n SidebarView: Travis.View.extend({\n templateName: 'layouts/sidebar',\n DecksView: Em.View.extend({\n templateName: \"sponsors/decks\",\n controller: Travis.SponsorsController.create({\n perPage: 1\n }),\n didInsertElement: function() {\n var controller;\n controller = this.get('controller');\n if (!controller.get('content')) {\n Travis.app.get('router.sidebarController').tickables.push(controller);\n controller.set('content', Travis.Sponsor.decks());\n }\n return this._super.apply(this, arguments);\n }\n }),\n LinksView: Em.View.extend({\n templateName: \"sponsors/links\",\n controller: Travis.SponsorsController.create({\n perPage: 6\n }),\n didInsertElement: function() {\n var controller;\n controller = this.get('controller');\n if (!controller.get('content')) {\n controller.set('content', Travis.Sponsor.links());\n Travis.app.get('router.sidebarController').tickables.push(controller);\n }\n return this._super.apply(this, arguments);\n }\n }),\n WorkersView: Em.View.extend({\n templateName: 'workers/list',\n controller: Travis.WorkersController.create(),\n didInsertElement: function() {\n this.set('controller.content', Travis.Worker.find());\n return this._super.apply(this, arguments);\n }\n }),\n QueuesView: Em.View.extend({\n templateName: 'queues/list',\n controller: Em.ArrayController.create(),\n didInsertElement: function() {\n var queue, queues;\n queues = (function() {\n var _i, _len, _ref, _results;\n _ref = Travis.QUEUES;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n queue = _ref[_i];\n _results.push(Em.ArrayController.create({\n content: Travis.Job.queued(queue.name),\n id: \"queue_\" + queue.name,\n name: queue.display\n }));\n }\n return _results;\n })();\n this.set('controller.content', queues);\n return this._super.apply(this, arguments);\n }\n })\n }),\n WorkersView: Travis.View.extend({\n toggleWorkers: function(event) {\n var handle;\n handle = $(event.target).toggleClass('open');\n if (handle.hasClass('open')) {\n return $('#workers li').addClass('open');\n } else {\n return $('#workers li').removeClass('open');\n }\n }\n }),\n WorkersListView: Travis.View.extend({\n toggle: function(event) {\n return $(event.target).closest('li').toggleClass('open');\n }\n }),\n WorkersItemView: Travis.View.extend({\n display: (function() {\n var name, number, payload, repo, state;\n name = (this.get('worker.name') || '').replace('travis-', '');\n state = this.get('worker.state');\n payload = this.get('worker.payload');\n if (state === 'working' && (payload != null ? payload.repository : void 0) && (payload != null ? payload.build : void 0)) {\n repo = payload.repository.slug;\n number = ' #' + payload.build.number;\n return (\"\" + name + \": \" + repo + \" \" + number).htmlSafe();\n } else {\n return \"\" + name + \": \" + state;\n }\n }).property('worker.state')\n }),\n QueueItemView: Travis.View.extend({\n tagName: 'li'\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/sidebar");minispade.register('views/signin', "(function() {(function() {\n\n this.Travis.reopen({\n SigninView: Travis.View.extend({\n templateName: 'auth/signin',\n signingIn: (function() {\n return Travis.app.get('authState') === 'signing-in';\n }).property('Travis.app.authState')\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/signin");minispade.register('views/stats', "(function() {(function() {\n\n this.Travis.reopen({\n StatsView: Travis.View.extend({\n templateName: 'stats/show',\n didInsertElement: function() {},\n renderChart: function(config) {\n var chart;\n chart = new Highcharts.Chart(config);\n return this.fetch(config.source, function(data) {\n var stats;\n stats = (function() {\n var _i, _len, _ref, _results;\n _ref = data.stats;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n stats = _ref[_i];\n _results.push(config.map(stats));\n }\n return _results;\n })();\n return chart.series[0].setData(stats);\n });\n },\n fetch: function(url, callback) {\n return $.ajax({\n type: 'GET',\n url: url,\n accepts: {\n json: 'application/vnd.travis-ci.2+json'\n },\n success: callback\n });\n },\n CHARTS: {\n repos: {\n source: '/api/stats/repos',\n total: 0,\n map: function(data) {\n return [Date.parse(data.date), this.total += parseInt(data.count)];\n },\n chart: {\n renderTo: \"repos_stats\"\n },\n title: {\n text: \"Total Projects/Repositories\"\n },\n xAxis: {\n type: \"datetime\",\n dateTimeLabelFormats: {\n month: \"%e. %b\",\n year: \"%b\"\n }\n },\n yAxis: {\n title: {\n text: \"Count\"\n },\n min: 0\n },\n tooltip: {\n formatter: function() {\n return Highcharts.dateFormat(\"%e. %b\", this.x) + \": \" + this.y + \" repos\";\n }\n },\n series: [\n {\n name: \"Repository Growth\",\n data: []\n }\n ]\n },\n builds: {\n source: '/api/stats/tests',\n map: function(data) {\n return [Date.parse(data.date), parseInt(data.count)];\n },\n chart: {\n renderTo: \"tests_stats\",\n type: \"column\"\n },\n title: {\n text: \"Build Count\"\n },\n subtitle: {\n text: \"last month\"\n },\n xAxis: {\n type: \"datetime\",\n dateTimeLabelFormats: {\n month: \"%e. %b\",\n year: \"%b\"\n }\n },\n yAxis: {\n title: {\n text: \"Count\"\n },\n min: 0\n },\n tooltip: {\n formatter: function() {\n return Highcharts.dateFormat(\"%e. %b\", this.x) + \": \" + this.y + \" builds\";\n }\n },\n series: [\n {\n name: \"Total Builds\",\n data: []\n }\n ]\n }\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/stats");minispade.register('views/top', "(function() {(function() {\n\n this.Travis.reopen({\n TopView: Travis.View.extend({\n templateName: 'layouts/top',\n tabBinding: 'controller.tab',\n userBinding: 'controller.user',\n gravatarUrl: (function() {\n return \"\" + location.protocol + \"//www.gravatar.com/avatar/\" + (this.get('user.gravatarId')) + \"?s=24&d=mm\";\n }).property('user.gravatarId'),\n classHome: (function() {\n if (this.get('tab') === 'home') {\n return 'active';\n }\n }).property('tab'),\n classStats: (function() {\n if (this.get('tab') === 'stats') {\n return 'active';\n }\n }).property('tab'),\n classProfile: (function() {\n var classes;\n classes = ['profile'];\n if (this.get('tab') === 'profile') {\n classes.push('active');\n }\n classes.push(Travis.app.get('authState'));\n return classes.join(' ');\n }).property('tab', 'Travis.app.authState'),\n showProfile: function() {\n return $('#top .profile ul').show();\n },\n hideProfile: function() {\n return $('#top .profile ul').hide();\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=views/top");minispade.register('config/emoij', "(function() {(function() {\n\n this.EmojiDictionary = ['-1', '0', '1', '109', '2', '3', '4', '5', '6', '7', '8', '8ball', '9', 'a', 'ab', 'airplane', 'alien', 'ambulance', 'angel', 'anger', 'angry', 'apple', 'aquarius', 'aries', 'arrow_backward', 'arrow_down', 'arrow_forward', 'arrow_left', 'arrow_lower_left', 'arrow_lower_right', 'arrow_right', 'arrow_up', 'arrow_upper_left', 'arrow_upper_right', 'art', 'astonished', 'atm', 'b', 'baby', 'baby_chick', 'baby_symbol', 'balloon', 'bamboo', 'bank', 'barber', 'baseball', 'basketball', 'bath', 'bear', 'beer', 'beers', 'beginner', 'bell', 'bento', 'bike', 'bikini', 'bird', 'birthday', 'black_square', 'blue_car', 'blue_heart', 'blush', 'boar', 'boat', 'bomb', 'book', 'boot', 'bouquet', 'bow', 'bowtie', 'boy', 'bread', 'briefcase', 'broken_heart', 'bug', 'bulb', 'bullettrain_front', 'bullettrain_side', 'bus', 'busstop', 'cactus', 'cake', 'calling', 'camel', 'camera', 'cancer', 'capricorn', 'car', 'cat', 'cd', 'chart', 'checkered_flag', 'cherry_blossom', 'chicken', 'christmas_tree', 'church', 'cinema', 'city_sunrise', 'city_sunset', 'clap', 'clapper', 'clock1', 'clock10', 'clock11', 'clock12', 'clock2', 'clock3', 'clock4', 'clock5', 'clock6', 'clock7', 'clock8', 'clock9', 'closed_umbrella', 'cloud', 'clubs', 'cn', 'cocktail', 'coffee', 'cold_sweat', 'computer', 'confounded', 'congratulations', 'construction', 'construction_worker', 'convenience_store', 'cool', 'cop', 'copyright', 'couple', 'couple_with_heart', 'couplekiss', 'cow', 'crossed_flags', 'crown', 'cry', 'cupid', 'currency_exchange', 'curry', 'cyclone', 'dancer', 'dancers', 'dango', 'dart', 'dash', 'de', 'department_store', 'diamonds', 'disappointed', 'dog', 'dolls', 'dolphin', 'dress', 'dvd', 'ear', 'ear_of_rice', 'egg', 'eggplant', 'egplant', 'eight_pointed_black_star', 'eight_spoked_asterisk', 'elephant', 'email', 'es', 'european_castle', 'exclamation', 'eyes', 'factory', 'fallen_leaf', 'fast_forward', 'fax', 'fearful', 'feelsgood', 'feet', 'ferris_wheel', 'finnadie', 'fire', 'fire_engine', 'fireworks', 'fish', 'fist', 'flags', 'flushed', 'football', 'fork_and_knife', 'fountain', 'four_leaf_clover', 'fr', 'fries', 'frog', 'fuelpump', 'gb', 'gem', 'gemini', 'ghost', 'gift', 'gift_heart', 'girl', 'goberserk', 'godmode', 'golf', 'green_heart', 'grey_exclamation', 'grey_question', 'grin', 'guardsman', 'guitar', 'gun', 'haircut', 'hamburger', 'hammer', 'hamster', 'hand', 'handbag', 'hankey', 'hash', 'headphones', 'heart', 'heart_decoration', 'heart_eyes', 'heartbeat', 'heartpulse', 'hearts', 'hibiscus', 'high_heel', 'horse', 'hospital', 'hotel', 'hotsprings', 'house', 'hurtrealbad', 'icecream', 'id', 'ideograph_advantage', 'imp', 'information_desk_person', 'iphone', 'it', 'jack_o_lantern', 'japanese_castle', 'joy', 'jp', 'key', 'kimono', 'kiss', 'kissing_face', 'kissing_heart', 'koala', 'koko', 'kr', 'leaves', 'leo', 'libra', 'lips', 'lipstick', 'lock', 'loop', 'loudspeaker', 'love_hotel', 'mag', 'mahjong', 'mailbox', 'man', 'man_with_gua_pi_mao', 'man_with_turban', 'maple_leaf', 'mask', 'massage', 'mega', 'memo', 'mens', 'metal', 'metro', 'microphone', 'minidisc', 'mobile_phone_off', 'moneybag', 'monkey', 'monkey_face', 'moon', 'mortar_board', 'mount_fuji', 'mouse', 'movie_camera', 'muscle', 'musical_note', 'nail_care', 'necktie', 'new', 'no_good', 'no_smoking', 'nose', 'notes', 'o', 'o2', 'ocean', 'octocat', 'octopus', 'oden', 'office', 'ok', 'ok_hand', 'ok_woman', 'older_man', 'older_woman', 'open_hands', 'ophiuchus', 'palm_tree', 'parking', 'part_alternation_mark', 'pencil', 'penguin', 'pensive', 'persevere', 'person_with_blond_hair', 'phone', 'pig', 'pill', 'pisces', 'plus1', 'point_down', 'point_left', 'point_right', 'point_up', 'point_up_2', 'police_car', 'poop', 'post_office', 'postbox', 'pray', 'princess', 'punch', 'purple_heart', 'question', 'rabbit', 'racehorse', 'radio', 'rage', 'rage1', 'rage2', 'rage3', 'rage4', 'rainbow', 'raised_hands', 'ramen', 'red_car', 'red_circle', 'registered', 'relaxed', 'relieved', 'restroom', 'rewind', 'ribbon', 'rice', 'rice_ball', 'rice_cracker', 'rice_scene', 'ring', 'rocket', 'roller_coaster', 'rose', 'ru', 'runner', 'sa', 'sagittarius', 'sailboat', 'sake', 'sandal', 'santa', 'satellite', 'satisfied', 'saxophone', 'school', 'school_satchel', 'scissors', 'scorpius', 'scream', 'seat', 'secret', 'shaved_ice', 'sheep', 'shell', 'ship', 'shipit', 'shirt', 'shit', 'shoe', 'signal_strength', 'six_pointed_star', 'ski', 'skull', 'sleepy', 'slot_machine', 'smile', 'smiley', 'smirk', 'smoking', 'snake', 'snowman', 'sob', 'soccer', 'space_invader', 'spades', 'spaghetti', 'sparkler', 'sparkles', 'speaker', 'speedboat', 'squirrel', 'star', 'star2', 'stars', 'station', 'statue_of_liberty', 'stew', 'strawberry', 'sunflower', 'sunny', 'sunrise', 'sunrise_over_mountains', 'surfer', 'sushi', 'suspect', 'sweat', 'sweat_drops', 'swimmer', 'syringe', 'tada', 'tangerine', 'taurus', 'taxi', 'tea', 'telephone', 'tennis', 'tent', 'thumbsdown', 'thumbsup', 'ticket', 'tiger', 'tm', 'toilet', 'tokyo_tower', 'tomato', 'tongue', 'top', 'tophat', 'traffic_light', 'train', 'trident', 'trophy', 'tropical_fish', 'truck', 'trumpet', 'tshirt', 'tulip', 'tv', 'u5272', 'u55b6', 'u6307', 'u6708', 'u6709', 'u6e80', 'u7121', 'u7533', 'u7a7a', 'umbrella', 'unamused', 'underage', 'unlock', 'up', 'us', 'v', 'vhs', 'vibration_mode', 'virgo', 'vs', 'walking', 'warning', 'watermelon', 'wave', 'wc', 'wedding', 'whale', 'wheelchair', 'white_square', 'wind_chime', 'wink', 'wink2', 'wolf', 'woman', 'womans_hat', 'womens', 'x', 'yellow_heart', 'zap', 'zzz'];\n\n}).call(this);\n\n})();\n//@ sourceURL=config/emoij");minispade.register('data/sponsors', "(function() {(function() {\n\n this.Travis.SPONSORS = [\n {\n type: 'platinum',\n url: \"http://www.wooga.com\",\n image: \"wooga-205x130.png\"\n }, {\n type: 'platinum',\n url: \"http://bendyworks.com\",\n image: \"bendyworks-205x130.png\"\n }, {\n type: 'platinum',\n url: \"http://cloudcontrol.com\",\n image: \"cloudcontrol-205x130.png\"\n }, {\n type: 'platinum',\n url: \"http://xing.de\",\n image: \"xing-205x130.png\"\n }, {\n type: 'gold',\n url: \"http://heroku.com\",\n image: \"heroku-205x60.png\"\n }, {\n type: 'gold',\n url: \"http://soundcloud.com\",\n image: \"soundcloud-205x60.png\"\n }, {\n type: 'gold',\n url: \"http://nedap.com\",\n image: \"nedap-205x60.png\"\n }, {\n type: 'gold',\n url: \"http://mongohq.com\",\n image: \"mongohq-205x60.png\"\n }, {\n type: 'gold',\n url: \"http://zweitag.de\",\n image: \"zweitag-205x60.png\"\n }, {\n type: 'gold',\n url: \"http://kanbanery.com\",\n image: \"kanbanery-205x60.png\"\n }, {\n type: 'gold',\n url: \"http://ticketevolution.com\",\n image: \"ticketevolution-205x60.jpg\"\n }, {\n type: 'gold',\n url: \"http://plan.io/travis\",\n image: \"planio-205x60.png\"\n }, {\n type: 'silver',\n link: \"Cobot : The one tool to run your coworking space \"\n }, {\n type: 'silver',\n link: \"JumpstartLab : We build developers \"\n }, {\n type: 'silver',\n link: \"Evil Martians : Agile Ruby on Rails development \"\n }, {\n type: 'silver',\n link: \"Zendesk : Love your helpdesk \"\n }, {\n type: 'silver',\n link: \"Stripe : Payments for developers \"\n }, {\n type: 'silver',\n link: \"Basho : We make Riak! \"\n }, {\n type: 'silver',\n link: \"Relevance : We deliver software solutions \"\n }, {\n type: 'silver',\n link: \"Mindmatters : Software für Menschen \"\n }, {\n type: 'silver',\n link: \"Amen : The best and worst of everything \"\n }, {\n type: 'silver',\n link: \"Site5 : Premium Web Hosting Solutions \"\n }, {\n type: 'silver',\n link: \"Crowd Interactive : Leading Rails consultancy in Mexico \"\n }, {\n type: 'silver',\n link: \"Atomic Object : Work with really smart people \"\n }, {\n type: 'silver',\n link: \"Codeminer : smart services for your startup \"\n }, {\n type: 'silver',\n link: \"Cloudant : grow into your data layer, not out of it \"\n }, {\n type: 'silver',\n link: \"Gidsy : Explore, organize & book unique things to do! \"\n }, {\n type: 'silver',\n link: \"5apps : Package & deploy HTML5 apps automatically \"\n }, {\n type: 'silver',\n link: \"Meltmedia : We are Interactive Superheroes \"\n }, {\n type: 'silver',\n link: \"Fingertips offers design and development services \"\n }, {\n type: 'silver',\n link: \"Engine Yard : Build epic apps, let us handle the rest \"\n }, {\n type: 'silver',\n link: \"Malwarebytes : Defeat Malware once and for all. \"\n }, {\n type: 'silver',\n link: \"Readmill : The best reading app on the iPad. \"\n }, {\n type: 'silver',\n link: \"Medidata : clinical tech improving quality of life \"\n }, {\n type: 'silver',\n link: \"ESM : Japan's best agile Ruby/Rails consultancy \"\n }, {\n type: 'silver',\n link: \"Twitter : instantly connects people everywhere \"\n }, {\n type: 'silver',\n link: \"AGiLE ANiMAL : we <3 Travis CI. \"\n }, {\n type: 'silver',\n link: \"Tupalo : Discover, review & share local businesses. \"\n }\n ];\n\n this.Travis.WORKERS = {\n \"jvm-otp1.worker.travis-ci.org\": {\n name: \"Travis Pro\",\n url: \"http://travis-ci.com\"\n },\n \"jvm-otp2.worker.travis-ci.org\": {\n name: \"Transloadit\",\n url: \"http://transloadit.com\"\n },\n \"ppp1.worker.travis-ci.org\": {\n name: \"Travis Pro\",\n url: \"http://beta.travis-ci.com\"\n },\n \"ppp2.worker.travis-ci.org\": {\n name: \"EnterpriseRails\",\n url: \"http://www.enterprise-rails.com\"\n },\n \"ppp3.worker.travis-ci.org\": {\n name: \"Alchemy CMS\",\n url: \"http://alchemy-cms.com/\"\n },\n \"rails1.worker.travis-ci.org\": {\n name: \"EnterpriseRails\",\n url: \"http://www.enterprise-rails.com\"\n },\n \"ruby1.worker.travis-ci.org\": {\n name: \"Engine Yard\",\n url: \"http://www.engineyard.com\"\n },\n \"ruby2.worker.travis-ci.org\": {\n name: \"EnterpriseRails\",\n url: \"http://www.enterprise-rails.com\"\n },\n \"ruby3.worker.travis-ci.org\": {\n name: \"Railslove\",\n url: \"http://railslove.de\"\n },\n \"ruby4.worker.travis-ci.org\": {\n name: \"Engine Yard\",\n url: \"http://www.engineyard.com\"\n },\n \"spree.worker.travis-ci.org\": {\n name: \"Spree\",\n url: \"http://spreecommerce.com\"\n },\n \"staging.worker.travis-ci.org\": {\n name: \"EnterpriseRails\",\n url: \"http://www.enterprise-rails.com\"\n }\n };\n\n}).call(this);\n\n})();\n//@ sourceURL=data/sponsors");minispade.register('ext/jquery', "(function() {(function() {\n\n $.fn.extend({\n outerHtml: function() {\n return $(this).wrap('
').parent().html();\n },\n outerElement: function() {\n return $($(this).outerHtml()).empty();\n },\n flash: function() {\n return Utils.flash(this);\n },\n unflash: function() {\n return Utils.unflash(this);\n },\n filterLog: function() {\n this.deansi();\n return this.foldLog();\n },\n deansi: function() {\n return this.html(Utils.deansi(this.html()));\n },\n foldLog: function() {\n return this.html(Utils.foldLog(this.html()));\n },\n unfoldLog: function() {\n return this.html(Utils.unfoldLog(this.html()));\n },\n updateTimes: function() {\n return Utils.updateTimes(this);\n },\n activateTab: function(tab) {\n return Utils.activateTab(this, tab);\n },\n timeInWords: function() {\n return $(this).each(function() {\n return $(this).text(Utils.timeInWords(parseInt($(this).attr('title'))));\n });\n },\n updateGithubStats: function(repo) {\n return Utils.updateGithubStats(repo, $(this));\n }\n });\n\n $.extend({\n isEmpty: function(obj) {\n if ($.isArray(obj)) {\n return !obj.length;\n } else if ($.isObject(obj)) {\n return !$.keys(obj).length;\n } else {\n return !obj;\n }\n },\n isObject: function(obj) {\n return Object.prototype.toString.call(obj) === '[object Object]';\n },\n keys: function(obj) {\n var keys;\n keys = [];\n $.each(obj, function(key) {\n return keys.push(key);\n });\n return keys;\n },\n values: function(obj) {\n var values;\n values = [];\n $.each(obj, function(key, value) {\n return values.push(value);\n });\n return values;\n },\n underscore: function(string) {\n return string[0].toLowerCase() + string.substring(1).replace(/([A-Z])?/g, function(match, chr) {\n if (chr) {\n return \"_\" + (chr.toUpperCase());\n } else {\n return '';\n }\n });\n },\n camelize: function(string, uppercase) {\n string = uppercase === false ? $.underscore(string) : $.capitalize(string);\n return string.replace(/_(.)?/g, function(match, chr) {\n if (chr) {\n return chr.toUpperCase();\n } else {\n return '';\n }\n });\n },\n capitalize: function(string) {\n return string[0].toUpperCase() + string.substring(1);\n },\n compact: function(object) {\n return $.grep(object, function(value) {\n return !!value;\n });\n },\n all: function(array, callback) {\n var args, i;\n args = Array.prototype.slice.apply(arguments);\n callback = args.pop();\n array = args.pop() || this;\n i = 0;\n while (i < array.length) {\n if (callback(array[i])) {\n return false;\n }\n i++;\n }\n return true;\n },\n detect: function(array, callback) {\n var args, i;\n args = Array.prototype.slice.apply(arguments);\n callback = args.pop();\n array = args.pop() || this;\n i = 0;\n while (i < array.length) {\n if (callback(array[i])) {\n return array[i];\n }\n i++;\n }\n },\n select: function(array, callback) {\n var args, i, result;\n args = Array.prototype.slice.apply(arguments);\n callback = args.pop();\n array = args.pop() || this;\n result = [];\n i = 0;\n while (i < array.length) {\n if (callback(array[i])) {\n result.push(array[i]);\n }\n i++;\n }\n return result;\n },\n slice: function(object, key) {\n var keys, result;\n keys = Array.prototype.slice.apply(arguments);\n object = (typeof keys[0] === 'object' ? keys.shift() : this);\n result = {};\n for (key in object) {\n if (keys.indexOf(key) > -1) {\n result[key] = object[key];\n }\n }\n return result;\n },\n only: function(object) {\n var key, keys, result;\n keys = Array.prototype.slice.apply(arguments);\n object = (typeof keys[0] === 'object' ? keys.shift() : this);\n result = {};\n for (key in object) {\n if (keys.indexOf(key) !== -1) {\n result[key] = object[key];\n }\n }\n return result;\n },\n except: function(object) {\n var key, keys, result;\n keys = Array.prototype.slice.apply(arguments);\n object = (typeof keys[0] === 'object' ? keys.shift() : this);\n result = {};\n for (key in object) {\n if (keys.indexOf(key) === -1) {\n result[key] = object[key];\n }\n }\n return result;\n },\n intersect: function(array, other) {\n return array.filter(function(element) {\n return other.indexOf(element) !== -1;\n });\n },\n map: function(elems, callback, arg) {\n var i, isArray, key, length, ret, value;\n value = void 0;\n key = void 0;\n ret = [];\n i = 0;\n length = elems.length;\n isArray = elems instanceof jQuery || length !== void 0 && typeof length === 'number' && (length > 0 && elems[0] && elems[length - 1]) || length === 0 || jQuery.isArray(elems);\n if (isArray) {\n while (i < length) {\n value = callback(elems[i], i, arg);\n if (value != null) {\n ret[ret.length] = value;\n }\n i++;\n }\n } else {\n for (key in elems) {\n value = callback(elems[key], key, arg);\n if (value != null) {\n ret[ret.length] = value;\n }\n }\n }\n return ret.concat.apply([], ret);\n },\n shuffle: function(array) {\n var current, tmp, top;\n array = array.slice();\n top = array.length;\n while (top && --top) {\n current = Math.floor(Math.random() * (top + 1));\n tmp = array[current];\n array[current] = array[top];\n array[top] = tmp;\n }\n return array;\n },\n truncate: function(string, length) {\n if (string.length > length) {\n return string.trim().substring(0, length) + '...';\n } else {\n return string;\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=ext/jquery");minispade.register('travis/ajax', "(function() {(function() {\n\n jQuery.support.cors = true;\n\n this.Travis.ajax = Em.Object.create({\n DEFAULT_OPTIONS: {\n accepts: {\n json: 'application/vnd.travis-ci.2+json'\n }\n },\n get: function(url, callback) {\n return this.ajax(url, 'get', {\n success: callback\n });\n },\n post: function(url, data, callback) {\n return this.ajax(url, 'post', {\n data: data,\n success: callback\n });\n },\n ajax: function(url, method, options) {\n var endpoint, success, token, _base,\n _this = this;\n endpoint = Travis.config.api_endpoint || '';\n options = options || {};\n if (token = sessionStorage.getItem('travis.token')) {\n options.headers || (options.headers = {});\n (_base = options.headers)['Authorization'] || (_base['Authorization'] = \"token \" + token);\n }\n options.url = \"\" + endpoint + url;\n options.type = method;\n options.dataType = 'json';\n options.contentType = 'application/json; charset=utf-8';\n options.context = this;\n if (options.data && method !== 'GET' && method !== 'get') {\n options.data = JSON.stringify(options.data);\n }\n success = options.success || (function() {});\n options.success = function(data) {\n var _ref;\n if (((_ref = Travis.app) != null ? _ref.router : void 0) && data.flash) {\n Travis.app.router.flashController.pushObjects(data.flash);\n }\n delete data.flash;\n return success.call(_this, data);\n };\n options.error = function(data) {\n if (data.flash) {\n return Travis.app.router.flashController.pushObject(data.flash);\n }\n };\n return $.ajax($.extend(options, Travis.ajax.DEFAULT_OPTIONS));\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/ajax");minispade.register('travis/expandable_record_array', "(function() {(function() {\n\n Travis.ExpandableRecordArray = DS.RecordArray.extend({\n isLoaded: false,\n isLoading: false,\n load: function(array) {\n var observer, self;\n this.set('isLoading', true);\n self = this;\n observer = function() {\n var content;\n if (this.get('isLoaded')) {\n content = self.get('content');\n array.removeObserver('isLoaded', observer);\n array.forEach(function(record) {\n return self.pushObject(record);\n });\n self.set('isLoading', false);\n return self.set('isLoaded', true);\n }\n };\n return array.addObserver('isLoaded', observer);\n },\n pushObject: function(record) {\n var clientId, id, ids;\n ids = this.get('content');\n id = record.get('id');\n clientId = record.get('clientId');\n if (ids.contains(clientId)) {\n return;\n }\n return ids.pushObject(clientId);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/expandable_record_array");minispade.register('travis/limited_array', "(function() {(function() {\n\n Travis.LimitedArray = Em.ArrayProxy.extend({\n limit: 10,\n init: function() {\n return this._super.apply(this, arguments);\n },\n arrangedContent: (function() {\n var content;\n if (content = this.get('content')) {\n return content.slice(0, this.get('limit'));\n }\n }).property('content'),\n contentArrayDidChange: function(array, index, removedCount, addedCount) {\n var addedObjects, arrangedContent, length, limit, object, _i, _len;\n this._super.apply(this, arguments);\n if (addedCount > 0) {\n addedObjects = array.slice(index, index + addedCount);\n arrangedContent = this.get('arrangedContent');\n for (_i = 0, _len = addedObjects.length; _i < _len; _i++) {\n object = addedObjects[_i];\n arrangedContent.unshiftObject(object);\n }\n limit = this.get('limit');\n length = arrangedContent.get('length');\n if (length > limit) {\n return arrangedContent.replace(limit, length - limit);\n }\n }\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/limited_array");minispade.register('travis/location', "(function() {(function() {\n\n Travis.Location = Ember.HistoryLocation.extend({\n onUpdateURL: function(callback) {\n var guid;\n guid = Ember.guidFor(this);\n return Ember.$(window).bind('popstate.ember-location-' + guid, function(e) {\n return callback(location.pathname + location.hash);\n });\n },\n getURL: function() {\n var location;\n location = this.get('location');\n return location.pathname + location.hash;\n }\n });\n\n Ember.Location.implementations['travis'] = Travis.Location;\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/location");minispade.register('travis/log', "(function() {(function() {\n\n this.Travis.Log = {\n FOLDS: {\n schema: /(\\$ (?:bundle exec )?rake( db:create)? db:schema:load[\\s\\S]*?-- assume_migrated_upto_version[\\s\\S]*?<\\/p>\\n.*<\\/p>)/g,\n migrate: /(\\$ (?:bundle exec )?rake( db:create)? db:migrate[\\s\\S]*== +\\w+: migrated \\(.*\\) =+)/g,\n bundle: /(\\$ bundle install.*<\\/p>\\n((Updating|Using|Installing|Fetching|remote:|Receiving|Resolving).*?<\\/p>\\n|<\\/p>\\n)*)/g,\n exec: /([\\/\\w]*.rvm\\/rubies\\/[\\S]*?\\/(ruby|rbx|jruby) .*?<\\/p>)/g\n },\n filter: function(log, path) {\n log = this.escape(log);\n log = this.deansi(log);\n log = log.replace(/\\r/g, '');\n log = this.number(log, path);\n log = this.fold(log);\n log = log.replace(/\\n/g, '');\n return log;\n },\n stripPaths: function(log) {\n return log.replace(/\\/home\\/vagrant\\/builds(\\/[^\\/\\n]+){2}\\//g, '');\n },\n escape: function(log) {\n return Handlebars.Utils.escapeExpression(log);\n },\n escapeRuby: function(log) {\n return log.replace(/#<(\\w+.*?)>/, '#<$1>');\n },\n number: function(log, path) {\n var result;\n path = \"\" + path + \"/\";\n result = '';\n $.each(log.trim().split('\\n'), function(ix, line) {\n var number, pathWithNumber;\n number = ix + 1;\n pathWithNumber = \"\" + path + \"#L\" + number;\n return result += '%@ %@
\\n'.fmt(pathWithNumber, number, number, number, line);\n });\n return result.trim();\n },\n deansi: function(log) {\n var ansi, text;\n log = log.replace(/\\r\\r/g, '\\r').replace(/\\033\\[K\\r/g, '\\r').replace(/^.*\\r(?!$)/gm, '').replace(/\u001b\\[2K/g, '').replace(/\\033\\(B/g, \"\");\n ansi = ansiparse(log);\n text = '';\n ansi.forEach(function(part) {\n var classes;\n classes = [];\n part.foreground && classes.push(part.foreground);\n part.background && classes.push('bg-' + part.background);\n part.bold && classes.push('bold');\n part.italic && classes.push('italic');\n return text += (classes.length ? '' + part.text + ' ' : part.text);\n });\n return text.replace(/\\033/g, '');\n },\n fold: function(log) {\n log = this.unfold(log);\n $.each(Travis.Log.FOLDS, function(name, pattern) {\n return log = log.replace(pattern, function() {\n return '' + arguments[1].trim() + '
';\n });\n });\n return log;\n },\n unfold: function(log) {\n return log.replace(/([\\s\\S]*?)<\\/div>/g, '$1\\n');\n },\n location: function() {\n return window.location.hash;\n }\n };\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/log");minispade.register('travis/model', "(function() {(function() {\n\n this.Travis.Model = DS.Model.extend({\n primaryKey: 'id',\n id: DS.attr('number'),\n refresh: function() {\n var id, store;\n if (id = this.get('id')) {\n store = this.get('store');\n return store.adapter.find(store, this.constructor, id);\n }\n },\n update: function(attrs) {\n var _this = this;\n $.each(attrs, function(key, value) {\n if (key !== 'id') {\n return _this.set(key, value);\n }\n });\n return this;\n },\n isComplete: (function() {\n if (this.get('incomplete')) {\n this.loadTheRest();\n return false;\n } else {\n this.set('isCompleting', false);\n return this.get('isLoaded');\n }\n }).property('incomplete', 'isLoaded'),\n loadTheRest: function() {\n if (this.get('isCompleting')) {\n return;\n }\n this.set('isCompleting', true);\n return this.refresh();\n },\n select: function() {\n return this.constructor.select(this.get('id'));\n }\n });\n\n this.Travis.Model.reopenClass({\n find: function() {\n if (arguments.length === 0) {\n return Travis.app.store.findAll(this);\n } else {\n return this._super.apply(this, arguments);\n }\n },\n filter: function(callback) {\n return Travis.app.store.filter(this, callback);\n },\n load: function(attrs) {\n return Travis.app.store.load(this, attrs);\n },\n select: function(id) {\n return this.find().forEach(function(record) {\n return record.set('selected', record.get('id') === id);\n });\n },\n buildURL: function(suffix) {\n var base, url;\n base = this.url || this.pluralName();\n Ember.assert('Base URL (' + base + ') must not start with slash', !base || base.toString().charAt(0) !== '/');\n Ember.assert('URL suffix (' + suffix + ') must not start with slash', !suffix || suffix.toString().charAt(0) !== '/');\n url = [base];\n if (suffix !== void 0) {\n url.push(suffix);\n }\n return url.join('/');\n },\n singularName: function() {\n var name, parts;\n parts = this.toString().split('.');\n name = parts[parts.length - 1];\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().slice(1);\n },\n pluralName: function() {\n return Travis.app.store.adapter.pluralize(this.singularName());\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/model");minispade.register('travis/ticker', "(function() {(function() {\n\n this.Travis.Ticker = Ember.Object.extend({\n init: function() {\n if (this.get('interval') !== -1) {\n return this.schedule();\n }\n },\n tick: function() {\n var context, target, targets, _i, _len;\n context = this.get('context');\n targets = this.get('targets') || [this.get('target')];\n for (_i = 0, _len = targets.length; _i < _len; _i++) {\n target = targets[_i];\n if (context) {\n target = context.get(target);\n }\n if (target) {\n target.tick();\n }\n }\n return this.schedule();\n },\n schedule: function() {\n var _this = this;\n return Ember.run.later((function() {\n return _this.tick();\n }), this.get('interval') || Travis.app.TICK_INTERVAL);\n }\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=travis/ticker");minispade.register('travis', "(function() {(function() {\nminispade.require('ext/jquery');\nminispade.require('ext/ember/namespace');\n\n this.Travis = Em.Namespace.create({\n config: {\n api_endpoint: $('meta[rel=\"travis.api_endpoint\"]').attr('href'),\n pusher_key: $('meta[name=\"travis.pusher_key\"]').attr('value')\n },\n CONFIG_KEYS: ['rvm', 'gemfile', 'env', 'jdk', 'otp_release', 'php', 'node_js', 'perl', 'python', 'scala'],\n ROUTES: {\n 'profile/:login/me': ['profile', 'user'],\n 'profile/:login': ['profile', 'hooks'],\n 'profile': ['profile', 'hooks'],\n 'stats': ['stats', 'show'],\n ':owner/:name/jobs/:id/:line': ['home', 'job'],\n ':owner/:name/jobs/:id': ['home', 'job'],\n ':owner/:name/builds/:id': ['home', 'build'],\n ':owner/:name/builds': ['home', 'builds'],\n ':owner/:name/pull_requests': ['home', 'pullRequests'],\n ':owner/:name/branches': ['home', 'branches'],\n ':owner/:name': ['home', 'current'],\n '': ['home', 'index'],\n '#': ['home', 'index']\n },\n QUEUES: [\n {\n name: 'common',\n display: 'Common'\n }, {\n name: 'php',\n display: 'PHP, Perl and Python'\n }, {\n name: 'node_js',\n display: 'Node.js'\n }, {\n name: 'jvmotp',\n display: 'JVM and Erlang'\n }, {\n name: 'rails',\n display: 'Rails'\n }, {\n name: 'spree',\n display: 'Spree'\n }\n ],\n INTERVALS: {\n sponsors: -1,\n times: -1,\n updateTimes: 1000\n },\n setLocale: function(locale) {\n if (!locale) {\n return;\n }\n I18n.locale = locale;\n return localStorage.setItem('travis.config.locale', locale);\n },\n run: function(attrs) {\n if (location.hash.slice(0, 2) === '#!') {\n location.href = location.href.replace('#!/', '');\n }\n this.setLocale(localStorage.getItem('travis.config.locale'));\n return Ember.run.next(this, function() {\n var app,\n _this = this;\n app = Travis.App.create(attrs || {});\n $.each(Travis, function(key, value) {\n if (value && value.isClass && key !== 'constructor') {\n return app[key] = value;\n }\n });\n this.app = app;\n this.store = app.store;\n return $(function() {\n return app.initialize();\n });\n });\n }\n });\nminispade.require('travis/ajax');\nminispade.require('app');\n\n}).call(this);\n\n})();\n//@ sourceURL=travis");minispade.register('templates', "(function() {\nEmber.TEMPLATES['application'] = Ember.Handlebars.compile(\"{{outlet}}\\n\");\n\nEmber.TEMPLATES['auth/signin'] = Ember.Handlebars.compile(\"{{#if view.signingIn}}\\n
Signing in ... \\n
\\n Trying to authenticate with GitHub.\\n
\\n{{else}}\\n
Sign in \\n
\\n Please sign in with GitHub. \\n
\\n{{/if}}\\n\\n\\n\");\n\nEmber.TEMPLATES['builds/list'] = Ember.Handlebars.compile(\"{{#if builds.isLoaded}}\\n
\\n \\n \\n {{t builds.name}} \\n {{t builds.commit}} \\n {{t builds.message}} \\n {{t builds.duration}} \\n {{t builds.finished_at}} \\n \\n \\n\\n \\n {{#each build in builds}}\\n {{#view Travis.BuildsItemView contextBinding=\\\"build\\\"}}\\n \\n \\n {{#if id}}\\n \\n {{number}}\\n \\n {{/if}}\\n \\n \\n \\n {{formatCommit commit}}\\n \\n \\n \\n {{{formatMessage commit.message short=\\\"true\\\"}}}\\n \\n \\n {{formatDuration duration}}\\n \\n \\n {{formatTime finishedAt}}\\n \\n {{/view}}\\n {{/each}}\\n \\n
\\n
\\n {{view view.ShowMoreButton}}\\n
\\n{{else}}\\n
Loading
\\n{{/if}}\\n\");\n\nEmber.TEMPLATES['builds/show'] = Ember.Handlebars.compile(\"{{#with view}}\\n {{#if loading}}\\n
Loading \\n {{else}}\\n
\\n \\n
{{t builds.name}} \\n
\\n \\n {{#if build.id}}\\n {{build.number}} \\n {{/if}}\\n \\n
{{t builds.finished_at}} \\n
{{formatTime build.finishedAt}} \\n
{{t builds.duration}} \\n
{{formatDuration build.duration}} \\n
\\n\\n \\n\\n {{t builds.message}} \\n {{{formatMessage build.commit.message}}} \\n\\n {{#unless isMatrix}}\\n {{t builds.config}} \\n {{formatConfig build.config}} \\n {{/unless}}\\n \\n\\n {{#if build.isMatrix}}\\n {{view Travis.JobsView jobsBinding=\\\"build.requiredJobs\\\" required=\\\"true\\\"}}\\n {{view Travis.JobsView jobsBinding=\\\"build.allowedFailureJobs\\\"}}\\n {{else}}\\n {{view Travis.LogView contextBinding=\\\"build.jobs.firstObject\\\"}}\\n {{/if}}\\n {{/if}}\\n{{/with}}\\n\");\n\nEmber.TEMPLATES['events/list'] = Ember.Handlebars.compile(\"{{#if view.events.isLoaded}}\\n
\\n \\n \\n Time \\n Message \\n \\n \\n\\n \\n {{#each event in view.events}}\\n {{#view Travis.EventsItemView contextBinding=\\\"event\\\"}}\\n \\n {{formatTime createdAt}}\\n \\n \\n {{event.message}}\\n \\n {{/view}}\\n {{/each}}\\n \\n
\\n{{else}}\\n
Loading
\\n{{/if}}\\n\\n\");\n\nEmber.TEMPLATES['jobs/list'] = Ember.Handlebars.compile(\"{{#if view.jobs.length}}\\n {{#if view.required}}\\n
\\n \\n {{t jobs.build_matrix}}\\n \\n {{else}}\\n \\n \\n {{t jobs.allowed_failures}}\\n \\n \\n {{/if}}\\n \\n \\n {{#each key in view.build.configKeys}}\\n {{key}} \\n {{/each}}\\n \\n \\n \\n {{#each job in view.jobs}}\\n {{#view Travis.JobsItemView contextBinding=\\\"job\\\"}}\\n \\n \\n {{#if job.id}}\\n {{number}} \\n {{/if}}\\n \\n \\n {{formatDuration duration}}\\n \\n \\n {{formatTime finishedAt}}\\n \\n {{#each value in configValues}}\\n {{value}} \\n {{/each}}\\n {{/view}}\\n {{/each}}\\n \\n
\\n\\n {{#unless view.required}}\\n \\n {{/unless}}\\n{{/if}}\\n\");\n\nEmber.TEMPLATES['jobs/log'] = Ember.Handlebars.compile(\"{{view.logSubscriber}}\\n\\n{{#if log.isLoaded}}\\n \\n \\n Follow logs \\n {{{formatLog log.body repo=\\\"repository\\\" item=\\\"parentView.currentItem\\\"}}} \\n\\n {{#if sponsor.name}}\\n \\n {{/if}}\\n\\n To top \\n{{else}}\\n \\n Loading \\n
\\n{{/if}}\\n\");\n\nEmber.TEMPLATES['jobs/show'] = Ember.Handlebars.compile(\"{{#with view}}\\n {{#if job.isComplete}}\\n \\n
\\n \\n
Job \\n
\\n \\n {{#if job.id}}\\n {{job.number}} \\n {{/if}}\\n \\n
{{t jobs.finished_at}} \\n
{{formatTime job.finishedAt}} \\n
{{t jobs.duration}} \\n
{{formatDuration job.duration}} \\n
\\n\\n \\n\\n {{t jobs.message}} \\n {{formatMessage commit.message}} \\n {{t jobs.config}} \\n {{formatConfig job.config}} \\n \\n\\n {{view Travis.LogView contextBinding=\\\"job\\\"}}}\\n
\\n {{else}}\\n \\n Loading \\n
\\n {{/if}}\\n{{/with}}\\n\");\n\nEmber.TEMPLATES['layouts/flash'] = Ember.Handlebars.compile(\"{{#each flash in controller}}\\n {{#view Travis.FlashItemView flashBinding=\\\"flash\\\"}}\\n {{view.message}}
\\n \\n {{/view}}\\n{{/each}}\\n\");\n\nEmber.TEMPLATES['layouts/home'] = Ember.Handlebars.compile(\"\\n {{outlet top}}\\n
\\n\\n\\n
\\n {{outlet left}}\\n
\\n\\n
\\n {{outlet flash}}\\n {{outlet main}}\\n
\\n\\n
\\n {{outlet right}}\\n
\\n
\\n\");\n\nEmber.TEMPLATES['layouts/profile'] = Ember.Handlebars.compile(\"\\n {{outlet top}}\\n
\\n\\n\\n
\\n {{outlet left}}\\n
\\n\\n
\\n {{outlet flash}}\\n {{outlet main}}\\n
\\n\\n
\\n
\\n\");\n\nEmber.TEMPLATES['layouts/sidebar'] = Ember.Handlebars.compile(\"\\n {{t layouts.application.fork_me}}\\n \\n\\n\\n\\n{{view view.DecksView}}\\n{{view view.WorkersView}}\\n{{view view.QueuesView}}\\n{{view view.LinksView}}\\n\\n\\n
{{t layouts.about.join}} \\n
\\n
\\n\");\n\nEmber.TEMPLATES['layouts/simple'] = Ember.Handlebars.compile(\"\\n {{outlet top}}\\n
\\n\\n\\n
\\n {{outlet flash}}\\n {{outlet main}}\\n
\\n
\\n\\n\");\n\nEmber.TEMPLATES['layouts/top'] = Ember.Handlebars.compile(\"\\n Travis \\n \\n\\n\\n\");\n\nEmber.TEMPLATES['profile/accounts'] = Ember.Handlebars.compile(\"\\n
\\n\\n\\n\\n\\n {{#collection Travis.AccountsListView contentBinding=\\\"controller\\\"}}\\n
{{view.name}} \\n
\\n Repositories: \\n {{view.account.reposCount}} \\n
\\n
\\n {{/collection}}\\n
\\n\");\n\nEmber.TEMPLATES['profile/show'] = Ember.Handlebars.compile(\"{{view.name}} \\n\\n{{view Travis.ProfileTabsView}}\\n\\n\\n {{outlet pane}}\\n
\\n\\n\");\n\nEmber.TEMPLATES['profile/tabs'] = Ember.Handlebars.compile(\"\\n \\n \\n \\n {{#if view.displayUser}}\\n \\n \\n \\n {{/if}}\\n \\n\");\n\nEmber.TEMPLATES['profile/tabs/hooks'] = Ember.Handlebars.compile(\"\\n {{{t profiles.show.message.your_repos}}}\\n
\\n\\n{{#if hooks.isLoaded}}\\n {{#if user.isSyncing}}\\n \\n Please wait while we sync from GitHub \\n
\\n {{else}}\\n \\n Last synchronized from GitHub: {{formatTime user.syncedAt}}\\n \\n Sync now\\n \\n
\\n\\n \\n {{#each hook in hooks}}\\n \\n {{hook.slug}} \\n {{hook.description}}
\\n\\n \\n \\n {{else}}\\n \\n You do not seem to have any repositories that we could sync.\\n \\n {{/each}}\\n \\n {{/if}}\\n{{else}}\\n \\n Loading \\n
\\n{{/if}}\\n\\n\\n\");\n\nEmber.TEMPLATES['profile/tabs/user'] = Ember.Handlebars.compile(\" \\n\\n\\n \\n {{t profiles.show.github}}:\\n \\n \\n {{user.login}} \\n \\n \\n {{t profiles.show.email}}:\\n \\n \\n {{user.email}}\\n \\n \\n {{t profiles.show.token}}:\\n \\n \\n {{user.token}}\\n \\n \\n\\n\\n\\n\\n\");\n\nEmber.TEMPLATES['queues/list'] = Ember.Handlebars.compile(\"\\n{{#each queue in controller}}\\n \\n {{t queue}}: {{queue.name}} \\n \\n \\n{{/each}}\\n \\n\");\n\nEmber.TEMPLATES['repos/list'] = Ember.Handlebars.compile(\"\\n {{view Ember.TextField valueBinding=\\\"controller.search\\\"}}\\n
\\n\\n{{view Travis.ReposListTabsView}}\\n\\n \\n\\n\\n {{#collection Travis.ReposListView contentBinding=\\\"controller\\\"}}\\n {{#with view.repo}}\\n
\\n
\\n {{#if slug}}\\n
{{slug}} \\n {{/if}}\\n
\\n {{#if lastBuildId}}\\n
{{lastBuildNumber}} \\n {{/if}}\\n\\n
\\n {{t repositories.duration}}: \\n {{formatDuration lastBuildDuration}} ,\\n {{t repositories.finished_at}}: \\n {{formatTime lastBuildFinishedAt}} \\n
\\n\\n
\\n\\n {{#if description}}\\n
\\n {{/if}}\\n {{/with}}\\n {{else}}\\n
\\n {{/collection}}\\n
\\n\");\n\nEmber.TEMPLATES['repos/list/tabs'] = Ember.Handlebars.compile(\"\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n\\n\");\n\nEmber.TEMPLATES['repos/show'] = Ember.Handlebars.compile(\"\\n {{#if view.isEmpty}}\\n {{view Travis.ReposEmptyView}}\\n {{else}}\\n {{#if view.repo.isComplete}}\\n {{#with view.repo}}\\n
\\n\\n
{{description}}
\\n\\n
\\n\\n {{view Travis.RepoShowTabsView}}\\n {{view Travis.RepoShowToolsView}}\\n {{/with}}\\n\\n {{else}}\\n
Loading \\n {{/if}}\\n\\n
\\n {{outlet pane}}\\n
\\n {{/if}}\\n
\\n\\n\");\n\nEmber.TEMPLATES['repos/show/tabs'] = Ember.Handlebars.compile(\"\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n {{#if view.repo.slug}}\\n \\n Events\\n \\n {{/if}}\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n\");\n\nEmber.TEMPLATES['repos/show/tools'] = Ember.Handlebars.compile(\"\\n\\n\\n\");\n\nEmber.TEMPLATES['sponsors/decks'] = Ember.Handlebars.compile(\"{{t layouts.application.sponsers}} \\n\\n\\n\\n\\n \\n {{{t layouts.application.sponsors_link}}}\\n \\n
\\n\");\n\nEmber.TEMPLATES['sponsors/links'] = Ember.Handlebars.compile(\"\\n\\n\");\n\nEmber.TEMPLATES['stats/show'] = Ember.Handlebars.compile(\"Sorry \\nStatistics are disabled for now.
\\n We're looking into a solution. If you want to help, please ping us!
\\n\");\n\nEmber.TEMPLATES['workers/list'] = Ember.Handlebars.compile(\"{{#view Travis.WorkersView}}\\n \\n {{t workers}}\\n \\n \\n \\n {{#each group in controller.groups}}\\n {{#view Travis.WorkersListView}}\\n \\n \\n {{group.firstObject.host}}\\n \\n \\n {{#each worker in group}}\\n {{#view Travis.WorkersItemView workerBinding=\\\"worker\\\"}}\\n \\n
\\n {{#if worker.isWorking}}\\n {{#if worker.job_id}}\\n \\n {{view.display}}\\n \\n {{/if}}\\n {{else}}\\n {{view.display}}\\n {{/if}}\\n \\n {{/view}}\\n {{/each}}\\n \\n \\n {{/view}}\\n {{else}}\\n No workers\\n {{/each}}\\n \\n{{/view}}\\n\");\n\n})();\n//@ sourceURL=templates");minispade.register('config/locales', "(function() {window.I18n = window.I18n || {}\nwindow.I18n.translations = {\"ca\":{\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"fr\":\"Français\",\"ja\":\"日本語\",\"nb\":\"Norsk Bokmål\",\"nl\":\"Nederlands\",\"pl\":\"Polski\",\"pt-BR\":\"português brasileiro\",\"ru\":\"Русский\"}},\"en\":{\"errors\":{\"messages\":{\"not_found\":\"not found\",\"already_confirmed\":\"was already confirmed\",\"not_locked\":\"was not locked\"}},\"devise\":{\"failure\":{\"unauthenticated\":\"You need to sign in or sign up before continuing.\",\"unconfirmed\":\"You have to confirm your account before continuing.\",\"locked\":\"Your account is locked.\",\"invalid\":\"Invalid email or password.\",\"invalid_token\":\"Invalid authentication token.\",\"timeout\":\"Your session expired, please sign in again to continue.\",\"inactive\":\"Your account was not activated yet.\"},\"sessions\":{\"signed_in\":\"Signed in successfully.\",\"signed_out\":\"Signed out successfully.\"},\"passwords\":{\"send_instructions\":\"You will receive an email with instructions about how to reset your password in a few minutes.\",\"updated\":\"Your password was changed successfully. You are now signed in.\"},\"confirmations\":{\"send_instructions\":\"You will receive an email with instructions about how to confirm your account in a few minutes.\",\"confirmed\":\"Your account was successfully confirmed. You are now signed in.\"},\"registrations\":{\"signed_up\":\"You have signed up successfully. If enabled, a confirmation was sent to your e-mail.\",\"updated\":\"You updated your account successfully.\",\"destroyed\":\"Bye! Your account was successfully cancelled. We hope to see you again soon.\"},\"unlocks\":{\"send_instructions\":\"You will receive an email with instructions about how to unlock your account in a few minutes.\",\"unlocked\":\"Your account was successfully unlocked. You are now signed in.\"},\"mailer\":{\"confirmation_instructions\":{\"subject\":\"Confirmation instructions\"},\"reset_password_instructions\":{\"subject\":\"Reset password instructions\"},\"unlock_instructions\":{\"subject\":\"Unlock Instructions\"}}},\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} hour\",\"other\":\"%{count} hours\"},\"minutes_exact\":{\"one\":\"%{count} minute\",\"other\":\"%{count} minutes\"},\"seconds_exact\":{\"one\":\"%{count} second\",\"other\":\"%{count} seconds\"}}},\"workers\":\"Workers\",\"queue\":\"Queue\",\"no_job\":\"There are no jobs\",\"repositories\":{\"branch\":\"Branch\",\"image_url\":\"Image URL\",\"markdown\":\"Markdown\",\"textile\":\"Textile\",\"rdoc\":\"RDOC\",\"commit\":\"Commit\",\"message\":\"Message\",\"started_at\":\"Started\",\"duration\":\"Duration\",\"finished_at\":\"Finished\",\"tabs\":{\"current\":\"Current\",\"build_history\":\"Build History\",\"branches\":\"Branch Summary\",\"pull_requests\":\"Pull Requests\",\"build\":\"Build\",\"job\":\"Job\"}},\"build\":{\"job\":\"Job\",\"duration\":\"Duration\",\"finished_at\":\"Finished\"},\"jobs\":{\"messages\":{\"sponsored_by\":\"This test suite was run on a worker box sponsored by\"},\"build_matrix\":\"Build Matrix\",\"allowed_failures\":\"Allowed Failures\",\"author\":\"Author\",\"config\":\"Config\",\"compare\":\"Compare\",\"committer\":\"Committer\",\"branch\":\"Branch\",\"commit\":\"Commit\",\"message\":\"Message\",\"started_at\":\"Started\",\"duration\":\"Duration\",\"finished_at\":\"Finished\"},\"builds\":{\"name\":\"Build\",\"messages\":{\"sponsored_by\":\"This test suite was run on a worker box sponsored by\"},\"build_matrix\":\"Build Matrix\",\"allowed_failures\":\"Allowed Failures\",\"author\":\"Author\",\"config\":\"Config\",\"compare\":\"Compare\",\"committer\":\"Committer\",\"branch\":\"Branch\",\"commit\":\"Commit\",\"message\":\"Message\",\"started_at\":\"Started\",\"duration\":\"Duration\",\"finished_at\":\"Finished\",\"show_more\":\"Show more\"},\"layouts\":{\"top\":{\"home\":\"Home\",\"blog\":\"Blog\",\"docs\":\"Docs\",\"stats\":\"Stats\",\"github_login\":\"Sign in with Github\",\"profile\":\"Profile\",\"sign_out\":\"Sign Out\",\"admin\":\"Admin\"},\"application\":{\"fork_me\":\"Fork me on Github\",\"recent\":\"Recent\",\"search\":\"Search\",\"sponsers\":\"Sponsors\",\"sponsors_link\":\"See all of our amazing sponsors →\",\"my_repositories\":\"My Repositories\"},\"about\":{\"alpha\":\"This stuff is alpha.\",\"messages\":{\"alpha\":\"Please do not consider this a stable service. We're still far from that! More info here. \"},\"join\":\"Join us and help!\",\"mailing_list\":\"Mailing List\",\"repository\":\"Repository\",\"twitter\":\"Twitter\"},\"mobile\":{\"author\":\"Author\",\"build\":\"Build\",\"build_matrix\":\"Build Matrix\",\"commit\":\"Commit\",\"committer\":\"Committer\",\"compare\":\"Compare\",\"config\":\"Config\",\"duration\":\"Duration\",\"finished_at\":\"Finished at\",\"job\":\"Job\",\"log\":\"Log\"}},\"profiles\":{\"show\":{\"email\":\"Email\",\"github\":\"Github\",\"message\":{\"your_repos\":\" Flick the switches below to turn on the Travis service hook for your projects, then push to GitHub.\",\"config\":\"how to configure custom build options\"},\"messages\":{\"notice\":\"To get started, please read our Getting Started guide .\\n It will only take a couple of minutes. \"},\"token\":\"Token\",\"your_repos\":\"Your Repositories\",\"update\":\"Update\",\"update_locale\":\"Update\",\"your_locale\":\"Your Locale\"}},\"statistics\":{\"index\":{\"count\":\"Count\",\"repo_growth\":\"Repository Growth\",\"total_projects\":\"Total Projects/Repositories\",\"build_count\":\"Build Count\",\"last_month\":\"last month\",\"total_builds\":\"Total Builds\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"fr\":\"Français\",\"ja\":\"日本語\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"ru\":\"Русский\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}},\"es\":{\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} hora\",\"other\":\"%{count} horas\"},\"minutes_exact\":{\"one\":\"%{count} minuto\",\"other\":\"%{count} minutos\"},\"seconds_exact\":{\"one\":\"%{count} segundo\",\"other\":\"%{count} segundos\"}}},\"workers\":\"Procesos\",\"queue\":\"Cola\",\"no_job\":\"No hay trabajos\",\"repositories\":{\"branch\":\"Rama\",\"image_url\":\"Imagen URL\",\"markdown\":\"Markdown\",\"textile\":\"Textile\",\"rdoc\":\"RDOC\",\"commit\":\"Commit\",\"message\":\"Mensaje\",\"started_at\":\"Iniciado\",\"duration\":\"Duración\",\"finished_at\":\"Finalizado\",\"tabs\":{\"current\":\"Actual\",\"build_history\":\"Histórico\",\"branches\":\"Ramas\",\"build\":\"Builds\",\"job\":\"Trabajo\"}},\"build\":{\"job\":\"Trabajo\",\"duration\":\"Duración\",\"finished_at\":\"Finalizado\"},\"jobs\":{\"messages\":{\"sponsored_by\":\"Esta serie de tests han sido ejecutados en una caja de Proceso patrocinada por\"},\"build_matrix\":\"Matriz de Builds\",\"allowed_failures\":\"Fallos Permitidos\",\"author\":\"Autor\",\"config\":\"Configuración\",\"compare\":\"Comparar\",\"committer\":\"Committer\",\"branch\":\"Rama\",\"commit\":\"Commit\",\"message\":\"Mensaje\",\"started_at\":\"Iniciado\",\"duration\":\"Duración\",\"finished_at\":\"Finalizado\",\"sponsored_by\":\"Patrocinado por\"},\"builds\":{\"name\":\"Build\",\"messages\":{\"sponsored_by\":\"Esta serie de tests han sido ejecutados en una caja de Proceso patrocinada por\"},\"build_matrix\":\"Matriz de Builds\",\"allowed_failures\":\"Fallos Permitidos\",\"author\":\"Autor\",\"config\":\"Configuración\",\"compare\":\"Comparar\",\"committer\":\"Committer\",\"branch\":\"Rama\",\"commit\":\"Commit\",\"message\":\"Mensaje\",\"started_at\":\"Iniciado\",\"duration\":\"Duración\",\"finished_at\":\"Finalizado\"},\"layouts\":{\"top\":{\"home\":\"Inicio\",\"blog\":\"Blog\",\"docs\":\"Documentación\",\"stats\":\"Estadísticas\",\"github_login\":\"Iniciar sesión con Github\",\"profile\":\"Perfil\",\"sign_out\":\"Desconectar\",\"admin\":\"Admin\"},\"application\":{\"fork_me\":\"Hazme un Fork en Github\",\"recent\":\"Reciente\",\"search\":\"Buscar\",\"sponsers\":\"Patrocinadores\",\"sponsors_link\":\"Ver todos nuestros patrocinadores →\",\"my_repositories\":\"Mis Repositorios\"},\"about\":{\"alpha\":\"Esto es alpha.\",\"messages\":{\"alpha\":\"Por favor no considereis esto un servicio estable. Estamos estamos aún lejos de ello! Más información aquí. \"},\"join\":\"Únetenos y ayudanos!\",\"mailing_list\":\"Lista de Correos\",\"repository\":\"Repositorio\",\"twitter\":\"Twitter\"}},\"profiles\":{\"show\":{\"email\":\"Correo electrónico\",\"github\":\"Github\",\"message\":{\"your_repos\":\" Activa los interruptores para inicial el Travis service hook para tus proyectos, y haz un Push en GitHub. \\n Para probar varias versiones de ruby, mira\",\"config\":\"como configurar tus propias opciones para el Build\"},\"messages\":{\"notice\":\"Para comenzar, por favor lee nuestra Guía de Inicio .\\n Solo tomará unos pocos minutos. \"},\"token\":\"Token\",\"your_repos\":\"Tus repositorios\",\"update\":\"Actualizar\",\"update_locale\":\"Actualizar\",\"your_locale\":\"Tu Idioma\"}},\"statistics\":{\"index\":{\"count\":\"Número\",\"repo_growth\":\"Crecimiento de Repositorios\",\"total_projects\":\"Total de Proyectos/Repositorios\",\"build_count\":\"Número de Builds\",\"last_month\":\"mes anterior\",\"total_builds\":\"Total de Builds\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"fr\":\"Français\",\"ja\":\"日本語\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"ru\":\"Русский\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}},\"fr\":{\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} heure\",\"other\":\"%{count} heures\"},\"minutes_exact\":{\"one\":\"%{count} minute\",\"other\":\"%{count} minutes\"},\"seconds_exact\":{\"one\":\"%{count} seconde\",\"other\":\"%{count} secondes\"}}},\"workers\":\"Processus\",\"queue\":\"File\",\"no_job\":\"Pas de tâches\",\"repositories\":{\"branch\":\"Branche\",\"image_url\":\"Image\",\"markdown\":\"Markdown\",\"textile\":\"Textile\",\"rdoc\":\"RDOC\",\"commit\":\"Commit\",\"message\":\"Message\",\"started_at\":\"Commencé\",\"duration\":\"Durée\",\"finished_at\":\"Terminé\",\"tabs\":{\"current\":\"Actuel\",\"build_history\":\"Historique des tâches\",\"branches\":\"Résumé des branches\",\"build\":\"Construction\",\"job\":\"Tâche\"}},\"build\":{\"job\":\"Tâche\",\"duration\":\"Durée\",\"finished_at\":\"Terminé\"},\"jobs\":{\"messages\":{\"sponsored_by\":\"Cette série de tests a été exécutée sur une machine sponsorisée par\"},\"build_matrix\":\"Matrice des versions\",\"allowed_failures\":\"Échecs autorisés\",\"author\":\"Auteur\",\"config\":\"Config\",\"compare\":\"Comparer\",\"committer\":\"Committeur\",\"branch\":\"Branche\",\"commit\":\"Commit\",\"message\":\"Message\",\"started_at\":\"Commencé\",\"duration\":\"Durée\",\"finished_at\":\"Terminé\",\"sponsored_by\":\"Cette série de tests a été exécutée sur une machine sponsorisée par\"},\"builds\":{\"name\":\"Version\",\"messages\":{\"sponsored_by\":\"Cette série de tests a été exécutée sur une machine sponsorisée par\"},\"build_matrix\":\"Matrice des versions\",\"allowed_failures\":\"Échecs autorisés\",\"author\":\"Auteur\",\"config\":\"Config\",\"compare\":\"Comparer\",\"committer\":\"Committeur\",\"branch\":\"Branche\",\"commit\":\"Commit\",\"message\":\"Message\",\"started_at\":\"Commencé\",\"duration\":\"Durée\",\"finished_at\":\"Terminé\"},\"layouts\":{\"top\":{\"home\":\"Accueil\",\"blog\":\"Blog\",\"docs\":\"Documentation\",\"stats\":\"Statistiques\",\"github_login\":\"Connection Github\",\"profile\":\"Profil\",\"sign_out\":\"Déconnection\",\"admin\":\"Admin\"},\"application\":{\"fork_me\":\"Faites un Fork sur Github\",\"recent\":\"Récent\",\"search\":\"Chercher\",\"sponsers\":\"Sponsors\",\"sponsors_link\":\"Voir tous nos extraordinaire sponsors →\",\"my_repositories\":\"Mes dépôts\"},\"about\":{\"alpha\":\"Ceci est en alpha.\",\"messages\":{\"alpha\":\"S'il vous plaît ne considérez pas ce service comme étant stable. Nous sommes loin de ça! Plus d'infos ici. \"},\"join\":\"Joignez-vous à nous et aidez-nous!\",\"mailing_list\":\"Liste de distribution\",\"repository\":\"Dépôt\",\"twitter\":\"Twitter\"},\"mobile\":{\"author\":\"Auteur\",\"build\":\"Version\",\"build_matrix\":\"Matrice des versions\",\"commit\":\"Commit\",\"committer\":\"Committeur\",\"compare\":\"Comparer\",\"config\":\"Config\",\"duration\":\"Durée\",\"finished_at\":\"Terminé à\",\"job\":\"Tâche\",\"log\":\"Journal\"}},\"profiles\":{\"show\":{\"github\":\"Github\",\"message\":{\"your_repos\":\"Utilisez les boutons ci-dessous pour activer Travis sur vos projets puis déployez sur GitHub. \\nPour tester sur plus de versions de ruby, voir\",\"config\":\"comment configurer des options de version personnalisées\"},\"messages\":{\"notice\":\"Pour commencer, veuillez lire notre guide de démarrage .\\n Cela ne vous prendra que quelques minutes. \"},\"token\":\"Jeton\",\"your_repos\":\"Vos dépôts\",\"email\":\"Courriel\",\"update\":\"Modifier\",\"update_locale\":\"Modifier\",\"your_locale\":\"Votre langue\"}},\"statistics\":{\"index\":{\"count\":\"Décompte\",\"repo_growth\":\"Croissance de dépôt\",\"total_projects\":\"Total des projets/dépôts\",\"build_count\":\"Décompte des versions\",\"last_month\":\"mois dernier\",\"total_builds\":\"Total des versions\"}},\"admin\":{\"actions\":{\"create\":\"créer\",\"created\":\"créé\",\"delete\":\"supprimer\",\"deleted\":\"supprimé\",\"update\":\"mise à jour\",\"updated\":\"mis à jour\"},\"credentials\":{\"log_out\":\"Déconnection\"},\"delete\":{\"confirmation\":\"Oui, je suis sure\",\"flash_confirmation\":\"%{name} a été détruit avec succès\"},\"flash\":{\"error\":\"%{name} n'a pas pu être %{action}\",\"noaction\":\"Aucune action n'a été entreprise\",\"successful\":\"%{name} a réussi à %{action}\"},\"history\":{\"name\":\"Historique\",\"no_activity\":\"Aucune activité\",\"page_name\":\"Historique pour %{name}\"},\"list\":{\"add_new\":\"Ajouter un nouveau\",\"delete_action\":\"Supprimer\",\"delete_selected\":\"Supprimer la sélection\",\"edit_action\":\"Modifier\",\"search\":\"Rechercher\",\"select\":\"Sélectionner le %{name} à modifier\",\"select_action\":\"Sélectionner\",\"show_all\":\"Montrer tout\"},\"new\":{\"basic_info\":\"Information de base\",\"cancel\":\"Annuler\",\"chosen\":\"%{name} choisi\",\"chose_all\":\"Choisir tout\",\"clear_all\":\"Déselectionner tout\",\"many_chars\":\"caractères ou moins\",\"one_char\":\"caractère.\",\"optional\":\"Optionnel\",\"required\":\"Requis\",\"save\":\"Sauvegarder\",\"save_and_add_another\":\"Sauvegarder et en ajouter un autre\",\"save_and_edit\":\"Sauvegarder et modifier\",\"select_choice\":\"Faites vos choix et cliquez\"},\"dashboard\":{\"add_new\":\"Ajouter un nouveau\",\"last_used\":\"Dernière utilisation\",\"model_name\":\"Nom du modèle\",\"modify\":\"Modification\",\"name\":\"Tableau de bord\",\"pagename\":\"Administration du site\",\"records\":\"Enregistrements\",\"show\":\"Voir\",\"ago\":\"plus tôt\"}},\"home\":{\"name\":\"accueil\"},\"repository\":{\"duration\":\"Durée\"},\"devise\":{\"confirmations\":{\"confirmed\":\"Votre compte a été crée avec succès. Vous être maintenant connecté.\",\"send_instructions\":\"Vous allez recevoir un courriel avec les instructions de confirmation de votre compte dans quelques minutes.\"},\"failure\":{\"inactive\":\"Votre compte n'a pas encore été activé.\",\"invalid\":\"Adresse courriel ou mot de passe invalide.\",\"invalid_token\":\"Jeton d'authentification invalide.\",\"locked\":\"Votre compte est bloqué.\",\"timeout\":\"Votre session est expirée, veuillez vous reconnecter pour continuer.\",\"unauthenticated\":\"Vous devez vous connecter ou vous enregistrer afin de continuer\",\"unconfirmed\":\"Vous devez confirmer votre compte avant de continuer.\"},\"mailer\":{\"confirmation_instructions\":{\"subject\":\"Instructions de confirmations\"},\"reset_password_instructions\":{\"subject\":\"Instruction de remise à zéro du mot de passe\"},\"unlock_instructions\":{\"subject\":\"Instruction de débloquage\"}},\"passwords\":{\"send_instructions\":\"Vous recevrez un courriel avec les instructions de remise à zéro du mot de passe dans quelques minutes.\",\"updated\":\"Votre mot de passe a été changé avec succès. Vous êtes maintenant connecté.\"},\"registrations\":{\"destroyed\":\"Au revoir! Votre compte a été annulé avec succès. Nous espérons vous revoir bientôt.\",\"signed_up\":\"Vous êtes enregistré avec succès. Si activé, une confirmation vous a été envoyé par courriel.\",\"updated\":\"Votre compte a été mis a jour avec succès\"},\"sessions\":{\"signed_in\":\"Connecté avec succès\",\"signed_out\":\"Déconnecté avec succès\"},\"unlocks\":{\"send_instructions\":\"Vous recevrez un courriel contenant les instructions pour débloquer votre compte dans quelques minutes.\",\"unlocked\":\"Votre compte a été débloqué avec succès.\"}},\"errors\":{\"messages\":{\"already_confirmed\":\"étais déja confirmé\",\"not_found\":\"n'a pas été trouvé\",\"not_locked\":\"n'étais pas bloqué\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"ja\":\"日本語\",\"ru\":\"Русский\",\"fr\":\"Français\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}},\"ja\":{\"workers\":\"ワーカー\",\"queue\":\"キュー\",\"no_job\":\"ジョブはありません\",\"repositories\":{\"branch\":\"ブランチ\",\"image_url\":\"画像URL\",\"markdown\":\".md\",\"textile\":\".textile\",\"rdoc\":\".rdoc\",\"commit\":\"コミット\",\"message\":\"メッセージ\",\"started_at\":\"開始時刻\",\"duration\":\"処理時間\",\"finished_at\":\"終了時刻\",\"tabs\":{\"current\":\"最新\",\"build_history\":\"ビルド履歴\",\"branches\":\"ブランチまとめ\",\"build\":\"ビルド\",\"job\":\"ジョブ\"}},\"build\":{\"job\":\"ジョブ\",\"duration\":\"処理時間\",\"finished_at\":\"終了時刻\"},\"jobs\":{\"messages\":{\"sponsored_by\":\"このテストは以下のスポンサーの協力で行いました。\"},\"build_matrix\":\"ビルドマトリクス\",\"allowed_failures\":\"失敗許容範囲内\",\"author\":\"制作者\",\"config\":\"設定\",\"compare\":\"比較\",\"committer\":\"コミット者\",\"branch\":\"ブランチ\",\"commit\":\"コミット\",\"message\":\"メッセージ\",\"started_at\":\"開始時刻\",\"duration\":\"処理時間\",\"finished_at\":\"終了時刻\"},\"builds\":{\"name\":\"ビルド\",\"messages\":{\"sponsored_by\":\"このテストは以下のスポンサーの協力で行いました。\"},\"build_matrix\":\"失敗許容範囲外\",\"allowed_failures\":\"失敗許容範囲内\",\"author\":\"制作者\",\"config\":\"設定\",\"compare\":\"比較\",\"committer\":\"コミット者\",\"branch\":\"ブランチ\",\"commit\":\"コミット\",\"message\":\"メッセージ\",\"started_at\":\"開始時刻\",\"duration\":\"処理時間\",\"finished_at\":\"終了時刻\"},\"layouts\":{\"about\":{\"alpha\":\"まだアルファですよ!\",\"join\":\"参加してみよう!\",\"mailing_list\":\"メールリスト\",\"messages\":{\"alpha\":\"Travis-ciは安定したサービスまで後一歩!詳しくはこちら \"},\"repository\":\"リポジトリ\",\"twitter\":\"ツイッター\"},\"application\":{\"fork_me\":\"Githubでフォークしよう\",\"my_repositories\":\"マイリポジトリ\",\"recent\":\"最近\",\"search\":\"検索\",\"sponsers\":\"スポンサー\",\"sponsors_link\":\"スポンサーをもっと見る →\"},\"top\":{\"blog\":\"ブログ\",\"docs\":\"Travisとは?\",\"github_login\":\"Githubでログイン\",\"home\":\"ホーム\",\"profile\":\"プロフィール\",\"sign_out\":\"ログアウト\",\"stats\":\"統計\",\"admin\":\"管理\"},\"mobile\":{\"author\":\"制作者\",\"build\":\"ビルド\",\"build_matrix\":\"ビルドマトリクス\",\"commit\":\"コミット\",\"committer\":\"コミット者\",\"compare\":\"比較\",\"config\":\"設定\",\"duration\":\"処理時間\",\"finished_at\":\"終了時刻\",\"job\":\"ジョブ\",\"log\":\"ログ\"}},\"profiles\":{\"show\":{\"github\":\"Github\",\"email\":\"メール\",\"message\":{\"config\":\"詳細設定\",\"your_repos\":\"以下のスイッチを設定し、Travis-ciを有効にします。Githubへプッシュしたらビルドは自動的に開始します。複数バーションや細かい設定はこちらへ:\"},\"messages\":{\"notice\":\"まずはTravisのはじめ方 を参照してください。\"},\"token\":\"トークン\",\"your_repos\":\"リポジトリ\",\"update\":\"更新\",\"update_locale\":\"更新\",\"your_locale\":\"言語設定\"}},\"statistics\":{\"index\":{\"build_count\":\"ビルド数\",\"count\":\"数\",\"last_month\":\"先月\",\"repo_growth\":\"リポジトリ\",\"total_builds\":\"合計ビルド数\",\"total_projects\":\"合計リポジトリ\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"fr\":\"Français\",\"ja\":\"日本語\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"ru\":\"Русский\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}},\"nb\":{\"admin\":{\"actions\":{\"create\":\"opprett\",\"created\":\"opprettet\",\"delete\":\"slett\",\"deleted\":\"slettet\",\"update\":\"oppdater\",\"updated\":\"oppdatert\"},\"credentials\":{\"log_out\":\"Logg ut\"},\"dashboard\":{\"add_new\":\"Legg til ny\",\"ago\":\"siden\",\"last_used\":\"Sist brukt\",\"model_name\":\"Modell\",\"modify\":\"Rediger\",\"name\":\"Dashbord\",\"pagename\":\"Nettstedsadministrasjon\",\"records\":\"Oppføringer\",\"show\":\"Vis\"},\"delete\":{\"confirmation\":\"Ja, jeg er sikker\",\"flash_confirmation\":\"%{name} ble slettet\"},\"flash\":{\"error\":\"%{name} kunne ikke bli %{action}\",\"noaction\":\"Ingen handlinger ble utført\",\"successful\":\"%{name} ble %{action}\"},\"history\":{\"name\":\"Logg\",\"no_activity\":\"Ingen aktivitet\",\"page_name\":\"Logg for %{name}\"},\"list\":{\"add_new\":\"Legg til ny\",\"delete_action\":\"Slett\",\"delete_selected\":\"Slett valgte\",\"edit_action\":\"Rediger\",\"search\":\"Søk\",\"select\":\"Velg %{name} for å redigere\",\"select_action\":\"Velg\",\"show_all\":\"Vis alle \"},\"new\":{\"basic_info\":\"Basisinformasjon\",\"cancel\":\"Avbryt\",\"chosen\":\"Valgt %{name}\",\"chose_all\":\"Velg alle\",\"clear_all\":\"Fjern alle\",\"many_chars\":\"eller færre tegn.\",\"one_char\":\"tegn.\",\"optional\":\"Valgfri\",\"required\":\"Påkrevd\",\"save\":\"Lagre\",\"save_and_add_another\":\"Lagre og legg til ny\",\"save_and_edit\":\"Lagre og rediger\",\"select_choice\":\"Kryss av for dine valg og klikk\"}},\"build\":{\"duration\":\"Varighet\",\"finished_at\":\"Fullført\",\"job\":\"Jobb\"},\"builds\":{\"allowed_failures\":\"Tillatte feil\",\"author\":\"Forfatter\",\"branch\":\"Gren\",\"build_matrix\":\"Jobbmatrise\",\"commit\":\"Innsending\",\"committer\":\"Innsender\",\"compare\":\"Sammenlign\",\"config\":\"Oppsett\",\"duration\":\"Varighet\",\"finished_at\":\"Fullført\",\"message\":\"Beskrivelse\",\"messages\":{\"sponsored_by\":\"Denne testen ble kjørt på en maskin sponset av\"},\"name\":\"Jobb\",\"started_at\":\"Startet\"},\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} time\",\"other\":\"%{count} timer\"},\"minutes_exact\":{\"one\":\"%{count} minutt\",\"other\":\"%{count} minutter\"},\"seconds_exact\":{\"one\":\"%{count} sekund\",\"other\":\"%{count} sekunder\"}}},\"devise\":{\"confirmations\":{\"confirmed\":\"Din konto er aktivert og du er nå innlogget.\",\"send_instructions\":\"Om noen få minutter så vil du få en e-post med informasjon om hvordan du bekrefter kontoen din.\"},\"failure\":{\"inactive\":\"Kontoen din har ikke blitt aktivert enda.\",\"invalid\":\"Ugyldig e-post eller passord.\",\"invalid_token\":\"Ugyldig autentiseringskode.\",\"locked\":\"Kontoen din er låst.\",\"timeout\":\"Du ble logget ut siden på grunn av mangel på aktivitet, vennligst logg inn på nytt.\",\"unauthenticated\":\"Du må logge inn eller registrere deg for å fortsette.\",\"unconfirmed\":\"Du må bekrefte kontoen din før du kan fortsette.\"},\"mailer\":{\"confirmation_instructions\":{\"subject\":\"Bekreftelsesinformasjon\"},\"reset_password_instructions\":{\"subject\":\"Instruksjoner for å få nytt passord\"},\"unlock_instructions\":{\"subject\":\"Opplåsningsinstruksjoner\"}},\"passwords\":{\"send_instructions\":\"Om noen få minutter så vil du få en epost med informasjon om hvordan du kan få et nytt passord.\",\"updated\":\"Passordet ditt ble endret, og du er logget inn.\"},\"registrations\":{\"destroyed\":\"Adjø! Kontoen din ble kansellert. Vi håper vi ser deg igjen snart.\",\"signed_up\":\"Du er nå registrert.\",\"updated\":\"Kontoen din ble oppdatert.\"},\"sessions\":{\"signed_in\":\"Du er nå logget inn.\",\"signed_out\":\"Du er nå logget ut.\"},\"unlocks\":{\"send_instructions\":\"Om noen få minutter så kommer du til å få en e-post med informasjon om hvordan du kan låse opp kontoen din.\",\"unlocked\":\"Kontoen din ble låst opp, og du er nå logget inn igjen.\"}},\"errors\":{\"messages\":{\"already_confirmed\":\"har allerede blitt bekreftet\",\"not_found\":\"ikke funnnet\",\"not_locked\":\"var ikke låst\"}},\"home\":{\"name\":\"hjem\"},\"jobs\":{\"allowed_failures\":\"Tillatte feil\",\"author\":\"Forfatter\",\"branch\":\"Gren\",\"build_matrix\":\"Jobbmatrise\",\"commit\":\"Innsending\",\"committer\":\"Innsender\",\"compare\":\"Sammenlign\",\"config\":\"Oppsett\",\"duration\":\"Varighet\",\"finished_at\":\"Fullført\",\"message\":\"Beskrivelse\",\"messages\":{\"sponsored_by\":\"Denne testserien ble kjørt på en maskin sponset av\"},\"started_at\":\"Startet\"},\"layouts\":{\"about\":{\"alpha\":\"Dette er alfa-greier.\",\"join\":\"Bli med og hjelp oss!\",\"mailing_list\":\"E-postliste\",\"messages\":{\"alpha\":\"Dette er ikke en stabil tjeneste. Vi har fremdeles et stykke igjen! Mer informasjon finner du her .\"},\"repository\":\"Kodelager\",\"twitter\":\"Twitter.\"},\"application\":{\"fork_me\":\"Se koden på Github\",\"my_repositories\":\"Mine kodelagre\",\"recent\":\"Nylig\",\"search\":\"Søk\",\"sponsers\":\"Sponsorer\",\"sponsors_link\":\"Se alle de flotte sponsorene våre →\"},\"mobile\":{\"author\":\"Forfatter\",\"build\":\"Jobb\",\"build_matrix\":\"Jobbmatrise\",\"commit\":\"Innsending\",\"committer\":\"Innsender\",\"compare\":\"Sammenlign\",\"config\":\"Oppsett\",\"duration\":\"Varighet\",\"finished_at\":\"Fullført\",\"job\":\"Jobb\",\"log\":\"Logg\"},\"top\":{\"admin\":\"Administrator\",\"blog\":\"Blogg\",\"docs\":\"Dokumentasjon\",\"github_login\":\"Logg inn med Github\",\"home\":\"Hjem\",\"profile\":\"Profil\",\"sign_out\":\"Logg ut\",\"stats\":\"Statistikk\"}},\"no_job\":\"Ingen jobber finnnes\",\"profiles\":{\"show\":{\"email\":\"E-post\",\"github\":\"Github\",\"message\":{\"config\":\"hvordan sette opp egne jobbinnstillinger\",\"your_repos\":\"Slå\\u0010 på Travis for prosjektene dine ved å dra i bryterne under, og send koden til Github. \\nFor å teste mot flere ruby-versjoner, se dokumentasjonen for\"},\"messages\":{\"notice\":\"For å komme i gang, vennligst les kom-i-gang-veivisereren vår. Det tar bare et par minutter. \"},\"token\":\"Kode\",\"update\":\"Oppdater\",\"update_locale\":\"Oppdater\",\"your_locale\":\"Ditt språk\",\"your_repos\":\"Dine kodelagre\"}},\"queue\":\"Kø\",\"repositories\":{\"branch\":\"Gren\",\"commit\":\"Innsender\",\"duration\":\"Varighet\",\"finished_at\":\"Fullført\",\"image_url\":\"Bilde-URL\",\"markdown\":\"Markdown\",\"message\":\"Beskrivelse\",\"rdoc\":\"RDOC\",\"started_at\":\"Startet\",\"tabs\":{\"branches\":\"Grensammendrag\",\"build\":\"Jobb\",\"build_history\":\"Jobblogg\",\"current\":\"Siste\",\"job\":\"Jobb\"},\"textile\":\"Textile\"},\"repository\":{\"duration\":\"Varighet\"},\"statistics\":{\"index\":{\"build_count\":\"Antall jobber\",\"count\":\"Antall\",\"last_month\":\"siste måned\",\"repo_growth\":\"Vekst i kodelager\",\"total_builds\":\"Totale jobber\",\"total_projects\":\"Antall prosjekter/kodelagre\"}},\"workers\":\"Arbeidere\",\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"ja\":\"日本語\",\"ru\":\"Русский\",\"fr\":\"Français\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}},\"nl\":{\"admin\":{\"actions\":{\"create\":\"aanmaken\",\"created\":\"aangemaakt\",\"delete\":\"verwijderen\",\"deleted\":\"verwijderd\",\"update\":\"bijwerken\",\"updated\":\"bijgewerkt\"},\"credentials\":{\"log_out\":\"Afmelden\"},\"dashboard\":{\"add_new\":\"Nieuwe toevoegen\",\"ago\":\"geleden\",\"last_used\":\"Laatst gebruikt\",\"model_name\":\"Model naam\",\"modify\":\"Wijzigen\",\"pagename\":\"Site administratie\",\"show\":\"Laten zien\",\"records\":\"Gegevens\"},\"delete\":{\"confirmation\":\"Ja, ik ben zeker\",\"flash_confirmation\":\"%{name} is vernietigd\"},\"flash\":{\"error\":\"%{name} kon niet worden %{action}\",\"noaction\":\"Er zijn geen acties genomen\",\"successful\":\"%{name} is %{action}\"},\"history\":{\"name\":\"Geschiedenis\",\"no_activity\":\"Geen activiteit\",\"page_name\":\"Geschiedenis van %{name}\"},\"list\":{\"add_new\":\"Nieuwe toevoegen\",\"delete_action\":\"Verwijderen\",\"delete_selected\":\"Verwijder geselecteerden\",\"edit_action\":\"Bewerken\",\"search\":\"Zoeken\",\"select\":\"Selecteer %{name} om te bewerken\",\"select_action\":\"Selecteer\",\"show_all\":\"Laat allen zien\"},\"new\":{\"basic_info\":\"Basisinfo\",\"cancel\":\"Annuleren\",\"chosen\":\"%{name} gekozen\",\"chose_all\":\"Kies allen\",\"clear_all\":\"Deselecteer allen\",\"many_chars\":\"tekens of minder.\",\"one_char\":\"teken.\",\"optional\":\"Optioneel\",\"required\":\"Vereist\",\"save\":\"Opslaan\",\"save_and_add_another\":\"Opslaan en een nieuwe toevoegen\",\"save_and_edit\":\"Opslaan en bewerken\",\"select_choice\":\"Selecteer uw keuzes en klik\"}},\"build\":{\"duration\":\"Duur\",\"finished_at\":\"Voltooid\",\"job\":\"Taak\"},\"builds\":{\"allowed_failures\":\"Toegestane mislukkingen\",\"author\":\"Auteur\",\"branch\":\"Tak\",\"build_matrix\":\"Bouw Matrix\",\"compare\":\"Vergelijk\",\"config\":\"Configuratie\",\"duration\":\"Duur\",\"finished_at\":\"Voltooid\",\"message\":\"Bericht\",\"messages\":{\"sponsored_by\":\"Deze tests zijn gedraaid op een machine gesponsord door\"},\"name\":\"Bouw\",\"started_at\":\"Gestart\",\"commit\":\"Commit\",\"committer\":\"Committer\"},\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} uur\",\"other\":\"%{count} uren\"},\"minutes_exact\":{\"one\":\"%{count} minuut\",\"other\":\"%{count} minuten\"},\"seconds_exact\":{\"one\":\"%{count} seconde\",\"other\":\"%{count} seconden\"}}},\"devise\":{\"confirmations\":{\"confirmed\":\"Uw account is bevestigd. U wordt nu ingelogd.\",\"send_instructions\":\"Binnen enkele minuten zal u een email ontvangen met instructies om uw account te bevestigen.\"},\"failure\":{\"inactive\":\"Uw account is nog niet geactiveerd.\",\"invalid\":\"Ongeldig email adres of wachtwoord.\",\"invalid_token\":\"Ongeldig authenticatie token.\",\"locked\":\"Uw account is vergrendeld.\",\"timeout\":\"Uw sessie is verlopen, gelieve opnieuw in te loggen om verder te gaan.\",\"unauthenticated\":\"U moet inloggen of u registeren voordat u verder gaat.\",\"unconfirmed\":\"U moet uw account bevestigen voordat u verder gaat.\"},\"mailer\":{\"confirmation_instructions\":{\"subject\":\"Bevestigings-instructies\"},\"reset_password_instructions\":{\"subject\":\"Wachtwoord herstel instructies\"},\"unlock_instructions\":{\"subject\":\"Ontgrendel-instructies\"}},\"passwords\":{\"send_instructions\":\"Binnen enkele minuten zal u een email krijgen met instructies om uw wachtwoord opnieuw in te stellen.\",\"updated\":\"Uw wachtwoord is veranderd. U wordt nu ingelogd.\"},\"registrations\":{\"destroyed\":\"Dag! Uw account is geannuleerd. We hopen u vlug terug te zien.\",\"signed_up\":\"Uw registratie is voltooid. Als het ingeschakeld is wordt een bevestiging naar uw email adres verzonden.\",\"updated\":\"Het bijwerken van uw account is gelukt.\"},\"sessions\":{\"signed_in\":\"Inloggen gelukt.\",\"signed_out\":\"Uitloggen gelukt.\"},\"unlocks\":{\"send_instructions\":\"Binnen enkele minuten zal u een email krijgen met instructies om uw account te ontgrendelen.\",\"unlocked\":\"Uw account is ontgrendeld. U wordt nu ingelogd.\"}},\"errors\":{\"messages\":{\"already_confirmed\":\"was al bevestigd\",\"not_found\":\"niet gevonden\",\"not_locked\":\"was niet vergrendeld\"}},\"jobs\":{\"allowed_failures\":\"Toegestane mislukkingen\",\"author\":\"Auteur\",\"branch\":\"Tak\",\"build_matrix\":\"Bouw matrix\",\"compare\":\"Vergelijk\",\"config\":\"Configuratie\",\"duration\":\"Duur\",\"finished_at\":\"Voltooid\",\"message\":\"Bericht\",\"messages\":{\"sponsored_by\":\"Deze testen zijn uitgevoerd op een machine gesponsord door\"},\"started_at\":\"Gestart\",\"commit\":\"Commit\",\"committer\":\"Committer\"},\"layouts\":{\"about\":{\"alpha\":\"Dit is in alfa-stadium.\",\"join\":\"Doe met ons mee en help!\",\"mailing_list\":\"Mailing lijst\",\"messages\":{\"alpha\":\"Gelieve deze service niet te beschouwen als stabiel. Daar zijn we nog lang niet! Meer info hier. \"},\"repository\":\"Repository\",\"twitter\":\"Twitter\"},\"application\":{\"fork_me\":\"Maak een fork op Github\",\"my_repositories\":\"Mijn repositories\",\"recent\":\"Recent\",\"search\":\"Zoeken\",\"sponsers\":\"Sponsors\",\"sponsors_link\":\"Bekijk al onze geweldige sponsors →\"},\"mobile\":{\"author\":\"Auteur\",\"build\":\"Bouw\",\"build_matrix\":\"Bouw matrix\",\"compare\":\"Vergelijk\",\"config\":\"Configuratie\",\"duration\":\"Duur\",\"finished_at\":\"Voltooid op\",\"job\":\"Taak\",\"commit\":\"Commit\",\"committer\":\"Committer\",\"log\":\"Logboek\"},\"top\":{\"admin\":\"Administratie\",\"blog\":\"Blog\",\"docs\":\"Documentatie\",\"github_login\":\"Inloggen met Github\",\"home\":\"Home\",\"profile\":\"Profiel\",\"sign_out\":\"Uitloggen\",\"stats\":\"Statistieken\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"fr\":\"Français\",\"ja\":\"日本語\",\"nb\":\"Norsk Bokmål\",\"nl\":\"Nederlands\",\"pl\":\"Polski\",\"ru\":\"Русский\",\"pt-BR\":\"português brasileiro\"},\"no_job\":\"Er zijn geen taken\",\"profiles\":{\"show\":{\"email\":\"Email adres\",\"github\":\"Github\",\"message\":{\"config\":\"hoe eigen bouw-opties in te stellen\",\"your_repos\":\"Zet de schakelaars hieronder aan om de Travis hook voor uw projecten te activeren en push daarna naar Github \\nOm te testen tegen meerdere rubies, zie\"},\"messages\":{\"notice\":\"Om te beginnen kunt u onze startersgids lezen.\\\\n Het zal maar enkele minuten van uw tijd vergen. \"},\"update\":\"Bijwerken\",\"update_locale\":\"Bijwerken\",\"your_locale\":\"Uw taal\",\"your_repos\":\"Uw repositories\",\"token\":\"Token\"}},\"queue\":\"Wachtrij\",\"repositories\":{\"branch\":\"Tak\",\"duration\":\"Duur\",\"finished_at\":\"Voltooid\",\"image_url\":\"Afbeeldings URL\",\"message\":\"Bericht\",\"started_at\":\"Gestart\",\"tabs\":{\"branches\":\"Tak samenvatting\",\"build\":\"Bouw\",\"build_history\":\"Bouw geschiedenis\",\"current\":\"Huidig\",\"job\":\"Taak\"},\"commit\":\"Commit\",\"markdown\":\"Markdown\",\"rdoc\":\"RDOC\",\"textile\":\"Textile\"},\"repository\":{\"duration\":\"Duur\"},\"statistics\":{\"index\":{\"build_count\":\"Bouw aantal\",\"count\":\"Aantal\",\"last_month\":\"voorbije maand\",\"repo_growth\":\"Repository groei\",\"total_builds\":\"Bouw totaal\",\"total_projects\":\"Projecten/Repository totaal\"}},\"workers\":\"Machines\",\"home\":{\"name\":\"Hoofdpagina\"}},\"pl\":{\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} godzina\",\"other\":\"%{count} godziny\"},\"minutes_exact\":{\"one\":\"%{count} minuta\",\"other\":\"%{count} minuty\"},\"seconds_exact\":{\"one\":\"%{count} sekunda\",\"other\":\"%{count} sekundy\"}}},\"workers\":\"Workers\",\"queue\":\"Kolejka\",\"no_job\":\"Brak zadań\",\"repositories\":{\"branch\":\"Gałąź\",\"image_url\":\"URL obrazka\",\"markdown\":\"Markdown\",\"textile\":\"Textile\",\"rdoc\":\"RDOC\",\"commit\":\"Commit\",\"message\":\"Opis\",\"started_at\":\"Rozpoczęto\",\"duration\":\"Czas trwania\",\"finished_at\":\"Zakończono\",\"tabs\":{\"current\":\"Aktualny\",\"build_history\":\"Historia Buildów\",\"branches\":\"Wszystkie Gałęzie\",\"build\":\"Build\",\"job\":\"Zadanie\"}},\"build\":{\"job\":\"Zadanie\",\"duration\":\"Czas trwania\",\"finished_at\":\"Zakończono\"},\"jobs\":{\"messages\":{\"sponsored_by\":\"Te testy zostały uruchomione na maszynie sponsorowanej przez\"},\"build_matrix\":\"Macierz Buildów\",\"allowed_failures\":\"Dopuszczalne Niepowodzenia\",\"author\":\"Autor\",\"config\":\"Konfiguracja\",\"compare\":\"Porównanie\",\"committer\":\"Committer\",\"branch\":\"Gałąź\",\"commit\":\"Commit\",\"message\":\"Opis\",\"started_at\":\"Rozpoczęto\",\"duration\":\"Czas trwania\",\"finished_at\":\"Zakończono\",\"sponsored_by\":\"Te testy zostały uruchomione na maszynie sponsorowanej przez\"},\"builds\":{\"name\":\"Build\",\"messages\":{\"sponsored_by\":\"Te testy zostały uruchomione na maszynie sponsorowanej przez\"},\"build_matrix\":\"Macierz Buildów\",\"allowed_failures\":\"Dopuszczalne Niepowodzenia\",\"author\":\"Autor\",\"config\":\"Konfiguracja\",\"compare\":\"Porównanie\",\"committer\":\"Komitujący\",\"branch\":\"Gałąź\",\"commit\":\"Commit\",\"message\":\"Opis\",\"started_at\":\"Rozpoczęto\",\"duration\":\"Czas trwania\",\"finished_at\":\"Zakończono\"},\"layouts\":{\"top\":{\"home\":\"Start\",\"blog\":\"Blog\",\"docs\":\"Dokumentacja\",\"stats\":\"Statystki\",\"github_login\":\"Zaloguj się przy pomocy Githuba\",\"profile\":\"Profil\",\"sign_out\":\"Wyloguj się\"},\"application\":{\"fork_me\":\"Fork me on Github\",\"recent\":\"Ostatnie\",\"search\":\"Wyniki\",\"sponsers\":\"Sponsorzy\",\"sponsors_link\":\"Zobacz naszych wszystkich wspaniałych sponsorów →\",\"my_repositories\":\"Moje repozytoria\"},\"about\":{\"alpha\":\"To wciąż jest wersja alpha.\",\"messages\":{\"alpha\":\"Proszę nie traktuj tego jako stabilnej usługi. Wciąż nam wiele do tego brakuje! Więcej informacji znajdziesz tutaj. \"},\"join\":\"Pomóż i dołącz do nas!\",\"mailing_list\":\"Lista mailingowa\",\"repository\":\"Repozytorium\",\"twitter\":\"Twitter\"},\"mobile\":{\"author\":\"Autor\",\"build\":\"Build\",\"build_matrix\":\"Macierz Buildów\",\"commit\":\"Commit\",\"committer\":\"Komitujący\",\"compare\":\"Porównianie\",\"config\":\"Konfiguracja\",\"duration\":\"Czas trwania\",\"finished_at\":\"Zakończono\",\"job\":\"Zadanie\",\"log\":\"Log\"}},\"profiles\":{\"show\":{\"email\":\"Email\",\"github\":\"Github\",\"message\":{\"your_repos\":\" Przesuń suwak poniżej, aby włączyć Travisa, dla twoich projektów, a następnie umieść swój kod na GitHubie. \\n Aby testować swój kod przy użyciu wielu wersji Rubiego, zobacz\",\"config\":\"jak skonfigurować niestandardowe opcje builda\"},\"messages\":{\"notice\":\"Aby zacząć, przeczytaj nasz Przewodnik .\\n Zajmie ci to tylko kilka minut. \"},\"token\":\"Token\",\"your_repos\":\"Twoje repozytoria\"}},\"statistics\":{\"index\":{\"count\":\"Ilość\",\"repo_growth\":\"Przyrost repozytoriów\",\"total_projects\":\"Łącznie projektów/repozytoriów\",\"build_count\":\"Liczba buildów\",\"last_month\":\"ostatni miesiąc\",\"total_builds\":\"Łącznie Buildów\"}},\"date\":{\"abbr_day_names\":[\"nie\",\"pon\",\"wto\",\"śro\",\"czw\",\"pią\",\"sob\"],\"abbr_month_names\":[\"sty\",\"lut\",\"mar\",\"kwi\",\"maj\",\"cze\",\"lip\",\"sie\",\"wrz\",\"paź\",\"lis\",\"gru\"],\"day_names\":[\"niedziela\",\"poniedziałek\",\"wtorek\",\"środa\",\"czwartek\",\"piątek\",\"sobota\"],\"formats\":{\"default\":\"%d-%m-%Y\",\"long\":\"%B %d, %Y\",\"short\":\"%d %b\"},\"month_names\":[\"styczeń\",\"luty\",\"marzec\",\"kwiecień\",\"maj\",\"czerwiec\",\"lipiec\",\"sierpień\",\"wrzesień\",\"październik\",\"listopad\",\"grudzień\"],\"order\":[\"day\",\"month\",\"year\"]},\"errors\":{\"format\":\"%{attribute} %{message}\",\"messages\":{\"accepted\":\"musi zostać zaakceptowane\",\"blank\":\"nie może być puste\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"ja\":\"日本語\",\"ru\":\"Русский\",\"fr\":\"Français\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}},\"pt-BR\":{\"admin\":{\"actions\":{\"create\":\"criar\",\"created\":\"criado\",\"delete\":\"deletar\",\"deleted\":\"deletado\",\"update\":\"atualizar\",\"updated\":\"atualizado\"},\"credentials\":{\"log_out\":\"Deslogar\"},\"dashboard\":{\"add_new\":\"Adicionar novo\",\"ago\":\"atrás\",\"last_used\":\"Última utilização\",\"model_name\":\"Nome do modelo\",\"modify\":\"Modificar\",\"name\":\"Dashboard\",\"pagename\":\"Administração do site\",\"records\":\"Registros\",\"show\":\"Mostrar\"},\"delete\":{\"confirmation\":\"Sim, tenho certeza\",\"flash_confirmation\":\"%{name} foi destruído com sucesso\"},\"flash\":{\"error\":\"%{name} falhou ao %{action}\",\"noaction\":\"Nenhuma ação foi tomada\",\"successful\":\"%{name} foi %{action} com sucesso\"},\"history\":{\"name\":\"Histórico\",\"no_activity\":\"Nenhuma Atividade\",\"page_name\":\"Histórico para %{name}\"},\"list\":{\"add_new\":\"Adicionar novo\",\"delete_action\":\"Deletar\",\"delete_selected\":\"Deletar selecionados\",\"edit_action\":\"Editar\",\"search\":\"Buscar\",\"select\":\"Selecionar %{name} para editar\",\"select_action\":\"Selecionar\",\"show_all\":\"Mostrar todos\"},\"new\":{\"basic_info\":\"Informações básicas\",\"cancel\":\"Cancelar\",\"chosen\":\"Escolhido %{name}\",\"chose_all\":\"Escolher todos\",\"clear_all\":\"Limpar todos\",\"many_chars\":\"caracteres ou menos.\",\"one_char\":\"caractere.\",\"optional\":\"Opcional\",\"required\":\"Requerido\",\"save\":\"Salvar\",\"save_and_add_another\":\"Salvar e adicionar outro\",\"save_and_edit\":\"Salvar e alterar\",\"select_choice\":\"Selecione e clique\"}},\"build\":{\"duration\":\"Duração\",\"finished_at\":\"Concluído em\",\"job\":\"Trabalho\"},\"builds\":{\"allowed_failures\":\"Falhas Permitidas\",\"author\":\"Autor\",\"branch\":\"Branch\",\"build_matrix\":\"Matriz de Build\",\"commit\":\"Commit\",\"committer\":\"Committer\",\"compare\":\"Comparar\",\"config\":\"Config\",\"duration\":\"Duração\",\"finished_at\":\"Concluído em\",\"message\":\"Mensagem\",\"messages\":{\"sponsored_by\":\"Esta série de testes foi executada em uma caixa de processos patrocinada por\"},\"name\":\"Build\",\"started_at\":\"Iniciou em\"},\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} hora\",\"other\":\"%{count} horas\"},\"minutes_exact\":{\"one\":\"%{count} minuto\",\"other\":\"%{count} minutos\"},\"seconds_exact\":{\"one\":\"%{count} segundo\",\"other\":\"%{count} segundos\"}}},\"devise\":{\"confirmations\":{\"confirmed\":\"Sua conta foi confirmada com sucesso. Você agora está logado.\",\"send_instructions\":\"Você receberá um email com instruções de como confirmar sua conta em alguns minutos.\"},\"failure\":{\"inactive\":\"Sua conta ainda não foi ativada.\",\"invalid\":\"Email ou senha inválidos.\",\"invalid_token\":\"Token de autenticação inválido.\",\"locked\":\"Sua conta está trancada.\",\"timeout\":\"Sua sessão expirou, por favor faça seu login novamente.\",\"unauthenticated\":\"Você precisa fazer o login ou cadastrar-se antes de continuar.\",\"unconfirmed\":\"Você precisa confirmar sua conta antes de continuar.\"},\"mailer\":{\"confirmation_instructions\":{\"subject\":\"Instruções de confirmação\"},\"reset_password_instructions\":{\"subject\":\"Instruções de atualização de senha\"},\"unlock_instructions\":{\"subject\":\"Instruções de destrancamento\"}},\"passwords\":{\"send_instructions\":\"Você receberá um email com instruções de como atualizar sua senha em alguns minutos.\",\"updated\":\"Sua senha foi alterada com sucesso. Você agora está logado.\"},\"registrations\":{\"destroyed\":\"Tchau! Sua conta foi cancelada com sucesso. Esperamos vê-lo novamente em breve!\",\"signed_up\":\"Você se cadastrou com sucesso. Se ativada, uma confirmação foi enviada para seu email.\",\"updated\":\"Você atualizou sua conta com sucesso.\"},\"sessions\":{\"signed_in\":\"Logado com sucesso.\",\"signed_out\":\"Deslogado com sucesso.\"},\"unlocks\":{\"send_instructions\":\"Você receberá um email com instruções de como destrancar sua conta em alguns minutos.\",\"unlocked\":\"Sua conta foi destrancada com sucesso. Você agora está logado.\"}},\"errors\":{\"messages\":{\"already_confirmed\":\"já foi confirmado\",\"not_found\":\"não encontrado\",\"not_locked\":\"não estava trancado\"}},\"home\":{\"name\":\"home\"},\"jobs\":{\"allowed_failures\":\"Falhas Permitidas\",\"author\":\"Autor\",\"branch\":\"Branch\",\"build_matrix\":\"Matriz de Build\",\"commit\":\"Commit\",\"committer\":\"Committer\",\"compare\":\"Comparar\",\"config\":\"Config\",\"duration\":\"Duração\",\"finished_at\":\"Concluído em\",\"message\":\"Mensagem\",\"messages\":{\"sponsored_by\":\"Esta série de testes foi executada em uma caixa de processos patrocinada por\"},\"started_at\":\"Iniciou em\"},\"layouts\":{\"about\":{\"alpha\":\"Isto é um alpha.\",\"join\":\"Junte-se à nós e ajude!\",\"mailing_list\":\"Lista de email\",\"messages\":{\"alpha\":\"Por favor, não considere isto um serviço estável. Estamos muito longe disso! Mais informações aqui. \"},\"repository\":\"Repositório\",\"twitter\":\"Twitter\"},\"application\":{\"fork_me\":\"Faça fork no Github\",\"my_repositories\":\"Meus Repositórios\",\"recent\":\"Recentes\",\"search\":\"Buscar\",\"sponsers\":\"Patrocinadores\",\"sponsors_link\":\"Conheça todos os nossos patrocinadores →\"},\"mobile\":{\"author\":\"Autor\",\"build\":\"Build\",\"build_matrix\":\"Matriz de Build\",\"commit\":\"Commit\",\"committer\":\"Committer\",\"compare\":\"Comparar\",\"config\":\"Config\",\"duration\":\"Duração\",\"finished_at\":\"Concluído em\",\"job\":\"Trabalho\",\"log\":\"Log\"},\"top\":{\"admin\":\"Admin\",\"blog\":\"Blog\",\"docs\":\"Documentação\",\"github_login\":\"Logue com o Github\",\"home\":\"Home\",\"profile\":\"Perfil\",\"sign_out\":\"Sair\",\"stats\":\"Estatísticas\"}},\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"fr\":\"Français\",\"ja\":\"日本語\",\"nb\":\"Norsk Bokmål\",\"nl\":\"Nederlands\",\"pl\":\"Polski\",\"ru\":\"Русский\",\"pt-BR\":\"português brasileiro\"},\"no_job\":\"Não há trabalhos\",\"profiles\":{\"show\":{\"email\":\"Email\",\"github\":\"Github\",\"message\":{\"config\":\"como configurar opções de build\",\"your_repos\":\"Use os botões abaixo para ligar ou desligar o hook de serviço do Travis para seus projetos, e então, faça um push para o Github. Para testar com múltiplas versões do Ruby, leia\"},\"messages\":{\"notice\":\"Para começar, leia nosso Guia de início . Só leva alguns minutinhos. \"},\"token\":\"Token\",\"update\":\"Atualizar\",\"update_locale\":\"Atualizar\",\"your_locale\":\"Sua língua\",\"your_repos\":\"Seus Repositórios\"}},\"queue\":\"Fila\",\"repositories\":{\"branch\":\"Branch\",\"commit\":\"Commit\",\"duration\":\"Duração\",\"finished_at\":\"Concluído em\",\"image_url\":\"URL da imagem\",\"markdown\":\"Markdown\",\"message\":\"Mensagem\",\"rdoc\":\"RDOC\",\"started_at\":\"Iniciou em\",\"tabs\":{\"branches\":\"Sumário do Branch\",\"build\":\"Build\",\"build_history\":\"Histórico de Build\",\"current\":\"Atual\",\"job\":\"Trabalho\"},\"textile\":\"Textile\"},\"repository\":{\"duration\":\"Duração\"},\"statistics\":{\"index\":{\"build_count\":\"Número de Builds\",\"count\":\"Número\",\"last_month\":\"último mês\",\"repo_growth\":\"Crescimento de Repositório\",\"total_builds\":\"Total de Builds\",\"total_projects\":\"Total de Projetos/Repositórios\"}},\"workers\":\"Processos\"},\"ru\":{\"admin\":{\"actions\":{\"create\":\"создать\",\"created\":\"создано\",\"delete\":\"удалить\",\"deleted\":\"удалено\",\"update\":\"обновить\",\"updated\":\"обновлено\"},\"credentials\":{\"log_out\":\"Выход\"},\"dashboard\":{\"add_new\":\"Добавить\",\"ago\":\"назад\",\"last_used\":\"Использовалось в последний раз\",\"model_name\":\"Имя модели\",\"modify\":\"Изменить\",\"name\":\"Панель управления\",\"pagename\":\"Управление сайтом\",\"records\":\"Записи\",\"show\":\"Показать\"},\"delete\":{\"confirmation\":\"Да, я уверен\",\"flash_confirmation\":\"%{name} успешно удалено\"},\"history\":{\"name\":\"История\",\"no_activity\":\"Нет активности\",\"page_name\":\"История %{name}\"},\"list\":{\"add_new\":\"Добавить\",\"delete_action\":\"Удалить\",\"delete_selected\":\"Удалить выбранные\",\"edit_action\":\"Редактировать\",\"search\":\"Поиск\",\"select\":\"Для редактирования выберите %{name}\",\"select_action\":\"Выбрать\",\"show_all\":\"Показать все\"},\"new\":{\"basic_info\":\"Основная информация\",\"cancel\":\"Отмена\",\"chosen\":\"Выбрано %{name}\",\"chose_all\":\"Выбрать все\",\"clear_all\":\"Очистить все\",\"one_char\":\"символ.\",\"optional\":\"Необязательно\",\"required\":\"Обязательно\",\"save\":\"Сохранить\",\"save_and_add_another\":\"Сохранить и добавить другое\",\"save_and_edit\":\"Сохранить и продолжить редактирование\",\"select_choice\":\"Выберите и кликните\",\"many_chars\":\"символов или меньше.\"},\"flash\":{\"error\":\"%{name} не удалось %{action}\",\"noaction\":\"Никаких действий не произведено\",\"successful\":\"%{name} было успешно %{action}\"}},\"build\":{\"duration\":\"Длительность\",\"finished_at\":\"Завершен\",\"job\":\"Задача\"},\"builds\":{\"allowed_failures\":\"Допустимые неудачи\",\"author\":\"Автор\",\"branch\":\"Ветка\",\"build_matrix\":\"Матрица\",\"commit\":\"Коммит\",\"committer\":\"Коммитер\",\"compare\":\"Дифф\",\"config\":\"Конфигурация\",\"duration\":\"Длительность\",\"finished_at\":\"Завершен\",\"message\":\"Комментарий\",\"messages\":{\"sponsored_by\":\"Эта серия тестов была запущена на машине, спонсируемой\"},\"name\":\"Билд\",\"started_at\":\"Начало\"},\"datetime\":{\"distance_in_words\":{\"hours_exact\":{\"one\":\"%{count} час\",\"few\":\"%{count} часа\",\"many\":\"%{count} часов\",\"other\":\"%{count} часа\"},\"minutes_exact\":{\"one\":\"%{count} минута\",\"few\":\"%{count} минуты\",\"many\":\"%{count} минут\",\"other\":\"%{count} минуты\"},\"seconds_exact\":{\"one\":\"%{count} секунда\",\"few\":\"%{count} секунды\",\"many\":\"%{count} секунд\",\"other\":\"%{count} секунды\"}}},\"devise\":{\"confirmations\":{\"confirmed\":\"Ваш аккаунт успешно подтвержден. Приветствуем!\",\"send_instructions\":\"В течении нескольких минут вы получите электронное письмо с инструкциями для прохождения процедуры подтверждения аккаунта.\"},\"failure\":{\"inactive\":\"Ваш аккаунт еще не активирован.\",\"invalid\":\"Ошибка в адресе почты или пароле.\",\"invalid_token\":\"Неправильный токен аутентификации.\",\"locked\":\"Ваш аккаунт заблокирован.\",\"timeout\":\"Сессия окончена. Для продолжения работы войдите снова.\",\"unauthenticated\":\"Вам нужно войти или зарегистрироваться.\",\"unconfirmed\":\"Вы должны сначала подтвердить свой аккаунт.\"},\"mailer\":{\"confirmation_instructions\":{\"subject\":\"Инструкции для подтверждению аккаунта\"},\"reset_password_instructions\":{\"subject\":\"Инструкции для сброса пароля\"},\"unlock_instructions\":{\"subject\":\"Инструкции для разблокирования аккаунта\"}},\"passwords\":{\"send_instructions\":\"В течении нескольких минут вы получите электронное письмо с инструкциями для сброса пароля.\",\"updated\":\"Ваш пароль успешно изменен. Приветствуем!\"},\"registrations\":{\"destroyed\":\"Ваш аккаунт был успешно удален. Живите долго и процветайте!\",\"signed_up\":\"Вы успешно прошли регистрацию. Инструкции для подтверждения аккаунта отправлены на ваш электронный адрес.\",\"updated\":\"Аккаунт успешно обновлен.\"},\"sessions\":{\"signed_in\":\"Приветствуем!\",\"signed_out\":\"Удачи!\"},\"unlocks\":{\"send_instructions\":\"В течении нескольких минут вы получите электронное письмо с инструкциям для разблокировния аккаунта.\",\"unlocked\":\"Ваш аккаунт успешно разблокирован. Приветствуем!\"}},\"errors\":{\"messages\":{\"already_confirmed\":\"уже подтвержден\",\"not_found\":\"не найден\",\"not_locked\":\"не заблокирован\"}},\"home\":{\"name\":\"Главная\"},\"jobs\":{\"allowed_failures\":\"Допустимые неудачи\",\"author\":\"Автор\",\"branch\":\"Ветка\",\"build_matrix\":\"Матрица\",\"commit\":\"Коммит\",\"committer\":\"Коммитер\",\"compare\":\"Сравнение\",\"config\":\"Конфигурация\",\"duration\":\"Длительность\",\"finished_at\":\"Завершен\",\"message\":\"Комментарий\",\"messages\":{\"sponsored_by\":\"Эта серия тестов была запущена на машине спонсируемой\"},\"started_at\":\"Начало\"},\"layouts\":{\"about\":{\"alpha\":\"Это альфа-версия\",\"join\":\"Присоединяйтесь к нам и помогайте!\",\"mailing_list\":\"Лист рассылки\",\"messages\":{\"alpha\":\"Пожалуйста, не считайте данный сервис стабильным. Мы еще очень далеки от стабильности! Подробности \"},\"repository\":\"Репозиторий\",\"twitter\":\"Twitter\"},\"application\":{\"fork_me\":\"Fork me on Github\",\"my_repositories\":\"Мои репозитории\",\"recent\":\"Недавние\",\"search\":\"Поиск\",\"sponsers\":\"Спонсоры\",\"sponsors_link\":\"Список всех наших замечательных спонсоров →\"},\"mobile\":{\"author\":\"Автор\",\"build\":\"Сборка\",\"build_matrix\":\"Матрица сборок\",\"commit\":\"Коммит\",\"committer\":\"Коммитер\",\"compare\":\"Сравнение\",\"config\":\"Конфигурация\",\"duration\":\"Длительность\",\"finished_at\":\"Завершен\",\"job\":\"Задача\",\"log\":\"Журнал\"},\"top\":{\"admin\":\"Управление\",\"blog\":\"Блог\",\"docs\":\"Документация\",\"github_login\":\"Войти через Github\",\"home\":\"Главная\",\"profile\":\"Профиль\",\"sign_out\":\"Выход\",\"stats\":\"Статистика\"}},\"no_job\":\"Очередь пуста\",\"profiles\":{\"show\":{\"email\":\"Электронная почта\",\"github\":\"Github\",\"message\":{\"config\":\"как настроить специальные опции билда\",\"your_repos\":\"Используйте переключатели, чтобы включить Travis service hook для вашего проекта, а потом отправьте код на GitHub. \\nДля тестирования на нескольких версиях Ruby смотрите\"},\"messages\":{\"notice\":\"Перед началом, пожалуйста, прочтите Руководство для быстрого старта . Это займет всего несколько минут. \"},\"token\":\"Токен\",\"update\":\"Обновить\",\"update_locale\":\"Обновить\",\"your_locale\":\"Ваш язык\",\"your_repos\":\"Ваши репозитории\"}},\"queue\":\"Очередь\",\"repositories\":{\"branch\":\"Ветка\",\"commit\":\"Коммит\",\"duration\":\"Длительность\",\"finished_at\":\"Завершен\",\"image_url\":\"URL изображения\",\"markdown\":\"Markdown\",\"message\":\"Комментарий\",\"rdoc\":\"RDOC\",\"started_at\":\"Начало\",\"tabs\":{\"branches\":\"Статус веток\",\"build\":\"Билд\",\"build_history\":\"История\",\"current\":\"Текущий\",\"job\":\"Задача\"},\"textile\":\"Textile\"},\"repository\":{\"duration\":\"Длительность\"},\"statistics\":{\"index\":{\"build_count\":\"Количество билдов\",\"count\":\"Количество\",\"last_month\":\"прошлый месяц\",\"repo_growth\":\"Рост числа репозиториев\",\"total_builds\":\"Всего билдов\",\"total_projects\":\"Всего проектов/репозиториев\"}},\"workers\":\"Машины\",\"locales\":{\"en\":\"English\",\"es\":\"Español\",\"ja\":\"日本語\",\"ru\":\"Русский\",\"fr\":\"Français\",\"nb\":\"Norsk Bokmål\",\"pl\":\"Polski\",\"nl\":\"Nederlands\",\"pt-BR\":\"português brasileiro\"}}};\n\n\n})();\n//@ sourceURL=config/locales");minispade.register('ext/ember/bound_helper', "(function() {// https://gist.github.com/2018185\n// For reference: https://github.com/wagenet/ember.js/blob/ac66dcb8a1cbe91d736074441f853e0da474ee6e/packages/ember-handlebars/lib/views/bound_property_view.js\nvar BoundHelperView = Ember.View.extend(Ember._Metamorph, {\n\n context: null,\n options: null,\n property: null,\n // paths of the property that are also observed\n propertyPaths: [],\n\n value: Ember.K,\n\n valueForRender: function() {\n var value = this.value(Ember.get(this.context, this.property), this.options);\n if (this.options.escaped) { value = Handlebars.Utils.escapeExpression(value); }\n return value;\n },\n\n render: function(buffer) {\n buffer.push(this.valueForRender());\n },\n\n valueDidChange: function() {\n if (this.morph.isRemoved()) { return; }\n this.morph.html(this.valueForRender());\n },\n\n didInsertElement: function() {\n this.valueDidChange();\n },\n\n init: function() {\n this._super();\n Ember.addObserver(this.context, this.property, this, 'valueDidChange');\n this.get('propertyPaths').forEach(function(propName) {\n Ember.addObserver(this.context, this.property + '.' + propName, this, 'valueDidChange');\n }, this);\n },\n\n destroy: function() {\n Ember.removeObserver(this.context, this.property, this, 'valueDidChange');\n this.get('propertyPaths').forEach(function(propName) {\n this.context.removeObserver(this.property + '.' + propName, this, 'valueDidChange');\n }, this);\n this._super();\n }\n\n});\n\nEmber.registerBoundHelper = function(name, func) {\n var propertyPaths = Array.prototype.slice.call(arguments, 2);\n Ember.Handlebars.registerHelper(name, function(property, options) {\n var data = options.data,\n view = data.view,\n ctx = this;\n\n var bindView = view.createChildView(BoundHelperView, {\n property: property,\n propertyPaths: propertyPaths,\n context: ctx,\n options: options.hash,\n value: func\n });\n\n view.appendChild(bindView);\n });\n};\n\n\n})();\n//@ sourceURL=ext/ember/bound_helper");minispade.register('ext/ember/namespace', "(function() {Em.Namespace.reopen = Em.Namespace.reopenClass\n\n\n\n})();\n//@ sourceURL=ext/ember/namespace");
\ No newline at end of file
diff --git a/public/scripts/specs.js b/public/scripts/specs.js
new file mode 100644
index 00000000..0f2cb783
--- /dev/null
+++ b/public/scripts/specs.js
@@ -0,0 +1,8867 @@
+var isCommonJS = typeof window == "undefined";
+
+/**
+ * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
+ *
+ * @namespace
+ */
+var jasmine = {};
+if (isCommonJS) exports.jasmine = jasmine;
+/**
+ * @private
+ */
+jasmine.unimplementedMethod_ = function() {
+ throw new Error("unimplemented method");
+};
+
+/**
+ * Use jasmine.undefined
instead of undefined
, since undefined
is just
+ * a plain old variable and may be redefined by somebody else.
+ *
+ * @private
+ */
+jasmine.undefined = jasmine.___undefined___;
+
+/**
+ * Show diagnostic messages in the console if set to true
+ *
+ */
+jasmine.VERBOSE = false;
+
+/**
+ * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
+ *
+ */
+jasmine.DEFAULT_UPDATE_INTERVAL = 250;
+
+/**
+ * Default timeout interval in milliseconds for waitsFor() blocks.
+ */
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
+
+jasmine.getGlobal = function() {
+ function getGlobal() {
+ return this;
+ }
+
+ return getGlobal();
+};
+
+/**
+ * Allows for bound functions to be compared. Internal use only.
+ *
+ * @ignore
+ * @private
+ * @param base {Object} bound 'this' for the function
+ * @param name {Function} function to find
+ */
+jasmine.bindOriginal_ = function(base, name) {
+ var original = base[name];
+ if (original.apply) {
+ return function() {
+ return original.apply(base, arguments);
+ };
+ } else {
+ // IE support
+ return jasmine.getGlobal()[name];
+ }
+};
+
+jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
+jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
+jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
+jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
+
+jasmine.MessageResult = function(values) {
+ this.type = 'log';
+ this.values = values;
+ this.trace = new Error(); // todo: test better
+};
+
+jasmine.MessageResult.prototype.toString = function() {
+ var text = "";
+ for (var i = 0; i < this.values.length; i++) {
+ if (i > 0) text += " ";
+ if (jasmine.isString_(this.values[i])) {
+ text += this.values[i];
+ } else {
+ text += jasmine.pp(this.values[i]);
+ }
+ }
+ return text;
+};
+
+jasmine.ExpectationResult = function(params) {
+ this.type = 'expect';
+ this.matcherName = params.matcherName;
+ this.passed_ = params.passed;
+ this.expected = params.expected;
+ this.actual = params.actual;
+ this.message = this.passed_ ? 'Passed.' : params.message;
+
+ var trace = (params.trace || new Error(this.message));
+ this.trace = this.passed_ ? '' : trace;
+};
+
+jasmine.ExpectationResult.prototype.toString = function () {
+ return this.message;
+};
+
+jasmine.ExpectationResult.prototype.passed = function () {
+ return this.passed_;
+};
+
+/**
+ * Getter for the Jasmine environment. Ensures one gets created
+ */
+jasmine.getEnv = function() {
+ var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
+ return env;
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isArray_ = function(value) {
+ return jasmine.isA_("Array", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isString_ = function(value) {
+ return jasmine.isA_("String", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isNumber_ = function(value) {
+ return jasmine.isA_("Number", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param {String} typeName
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isA_ = function(typeName, value) {
+ return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
+};
+
+/**
+ * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
+ *
+ * @param value {Object} an object to be outputted
+ * @returns {String}
+ */
+jasmine.pp = function(value) {
+ var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
+ stringPrettyPrinter.format(value);
+ return stringPrettyPrinter.string;
+};
+
+/**
+ * Returns true if the object is a DOM Node.
+ *
+ * @param {Object} obj object to check
+ * @returns {Boolean}
+ */
+jasmine.isDomNode = function(obj) {
+ return obj.nodeType > 0;
+};
+
+/**
+ * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
+ *
+ * @example
+ * // don't care about which function is passed in, as long as it's a function
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
+ *
+ * @param {Class} clazz
+ * @returns matchable object of the type clazz
+ */
+jasmine.any = function(clazz) {
+ return new jasmine.Matchers.Any(clazz);
+};
+
+/**
+ * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
+ * attributes on the object.
+ *
+ * @example
+ * // don't care about any other attributes than foo.
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
+ *
+ * @param sample {Object} sample
+ * @returns matchable object for the sample
+ */
+jasmine.objectContaining = function (sample) {
+ return new jasmine.Matchers.ObjectContaining(sample);
+};
+
+/**
+ * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
+ *
+ * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
+ * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
+ *
+ * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
+ *
+ * Spies are torn down at the end of every spec.
+ *
+ * Note: Do not call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
+ *
+ * @example
+ * // a stub
+ * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
+ *
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // actual foo.not will not be called, execution stops
+ * spyOn(foo, 'not');
+
+ // foo.not spied upon, execution will continue to implementation
+ * spyOn(foo, 'not').andCallThrough();
+ *
+ * // fake example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // foo.not(val) will return val
+ * spyOn(foo, 'not').andCallFake(function(value) {return value;});
+ *
+ * // mock example
+ * foo.not(7 == 7);
+ * expect(foo.not).toHaveBeenCalled();
+ * expect(foo.not).toHaveBeenCalledWith(true);
+ *
+ * @constructor
+ * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
+ * @param {String} name
+ */
+jasmine.Spy = function(name) {
+ /**
+ * The name of the spy, if provided.
+ */
+ this.identity = name || 'unknown';
+ /**
+ * Is this Object a spy?
+ */
+ this.isSpy = true;
+ /**
+ * The actual function this spy stubs.
+ */
+ this.plan = function() {
+ };
+ /**
+ * Tracking of the most recent call to the spy.
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy.mostRecentCall.args = [1, 2];
+ */
+ this.mostRecentCall = {};
+
+ /**
+ * Holds arguments for each call to the spy, indexed by call count
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy(7, 8);
+ * mySpy.mostRecentCall.args = [7, 8];
+ * mySpy.argsForCall[0] = [1, 2];
+ * mySpy.argsForCall[1] = [7, 8];
+ */
+ this.argsForCall = [];
+ this.calls = [];
+};
+
+/**
+ * Tells a spy to call through to the actual implemenatation.
+ *
+ * @example
+ * var foo = {
+ * bar: function() { // do some stuff }
+ * }
+ *
+ * // defining a spy on an existing property: foo.bar
+ * spyOn(foo, 'bar').andCallThrough();
+ */
+jasmine.Spy.prototype.andCallThrough = function() {
+ this.plan = this.originalValue;
+ return this;
+};
+
+/**
+ * For setting the return value of a spy.
+ *
+ * @example
+ * // defining a spy from scratch: foo() returns 'baz'
+ * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() returns 'baz'
+ * spyOn(foo, 'bar').andReturn('baz');
+ *
+ * @param {Object} value
+ */
+jasmine.Spy.prototype.andReturn = function(value) {
+ this.plan = function() {
+ return value;
+ };
+ return this;
+};
+
+/**
+ * For throwing an exception when a spy is called.
+ *
+ * @example
+ * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
+ * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
+ * spyOn(foo, 'bar').andThrow('baz');
+ *
+ * @param {String} exceptionMsg
+ */
+jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
+ this.plan = function() {
+ throw exceptionMsg;
+ };
+ return this;
+};
+
+/**
+ * Calls an alternate implementation when a spy is called.
+ *
+ * @example
+ * var baz = function() {
+ * // do some stuff, return something
+ * }
+ * // defining a spy from scratch: foo() calls the function baz
+ * var foo = jasmine.createSpy('spy on foo').andCall(baz);
+ *
+ * // defining a spy on an existing property: foo.bar() calls an anonymnous function
+ * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
+ *
+ * @param {Function} fakeFunc
+ */
+jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
+ this.plan = fakeFunc;
+ return this;
+};
+
+/**
+ * Resets all of a spy's the tracking variables so that it can be used again.
+ *
+ * @example
+ * spyOn(foo, 'bar');
+ *
+ * foo.bar();
+ *
+ * expect(foo.bar.callCount).toEqual(1);
+ *
+ * foo.bar.reset();
+ *
+ * expect(foo.bar.callCount).toEqual(0);
+ */
+jasmine.Spy.prototype.reset = function() {
+ this.wasCalled = false;
+ this.callCount = 0;
+ this.argsForCall = [];
+ this.calls = [];
+ this.mostRecentCall = {};
+};
+
+jasmine.createSpy = function(name) {
+
+ var spyObj = function() {
+ spyObj.wasCalled = true;
+ spyObj.callCount++;
+ var args = jasmine.util.argsToArray(arguments);
+ spyObj.mostRecentCall.object = this;
+ spyObj.mostRecentCall.args = args;
+ spyObj.argsForCall.push(args);
+ spyObj.calls.push({object: this, args: args});
+ return spyObj.plan.apply(this, arguments);
+ };
+
+ var spy = new jasmine.Spy(name);
+
+ for (var prop in spy) {
+ spyObj[prop] = spy[prop];
+ }
+
+ spyObj.reset();
+
+ return spyObj;
+};
+
+/**
+ * Determines whether an object is a spy.
+ *
+ * @param {jasmine.Spy|Object} putativeSpy
+ * @returns {Boolean}
+ */
+jasmine.isSpy = function(putativeSpy) {
+ return putativeSpy && putativeSpy.isSpy;
+};
+
+/**
+ * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
+ * large in one call.
+ *
+ * @param {String} baseName name of spy class
+ * @param {Array} methodNames array of names of methods to make spies
+ */
+jasmine.createSpyObj = function(baseName, methodNames) {
+ if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
+ throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
+ }
+ var obj = {};
+ for (var i = 0; i < methodNames.length; i++) {
+ obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
+ }
+ return obj;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
+ *
+ * Be careful not to leave calls to jasmine.log
in production code.
+ */
+jasmine.log = function() {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.log.apply(spec, arguments);
+};
+
+/**
+ * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
+ *
+ * @example
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
+ *
+ * @see jasmine.createSpy
+ * @param obj
+ * @param methodName
+ * @returns a Jasmine spy that can be chained with all spy methods
+ */
+var spyOn = function(obj, methodName) {
+ return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
+};
+if (isCommonJS) exports.spyOn = spyOn;
+
+/**
+ * Creates a Jasmine spec that will be added to the current suite.
+ *
+ * // TODO: pending tests
+ *
+ * @example
+ * it('should be true', function() {
+ * expect(true).toEqual(true);
+ * });
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var it = function(desc, func) {
+ return jasmine.getEnv().it(desc, func);
+};
+if (isCommonJS) exports.it = it;
+
+/**
+ * Creates a disabled Jasmine spec.
+ *
+ * A convenience method that allows existing specs to be disabled temporarily during development.
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var xit = function(desc, func) {
+ return jasmine.getEnv().xit(desc, func);
+};
+if (isCommonJS) exports.xit = xit;
+
+/**
+ * Starts a chain for a Jasmine expectation.
+ *
+ * It is passed an Object that is the actual value and should chain to one of the many
+ * jasmine.Matchers functions.
+ *
+ * @param {Object} actual Actual value to test against and expected value
+ */
+var expect = function(actual) {
+ return jasmine.getEnv().currentSpec.expect(actual);
+};
+if (isCommonJS) exports.expect = expect;
+
+/**
+ * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
+ *
+ * @param {Function} func Function that defines part of a jasmine spec.
+ */
+var runs = function(func) {
+ jasmine.getEnv().currentSpec.runs(func);
+};
+if (isCommonJS) exports.runs = runs;
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+var waits = function(timeout) {
+ jasmine.getEnv().currentSpec.waits(timeout);
+};
+if (isCommonJS) exports.waits = waits;
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
+};
+if (isCommonJS) exports.waitsFor = waitsFor;
+
+/**
+ * A function that is called before each spec in a suite.
+ *
+ * Used for spec setup, including validating assumptions.
+ *
+ * @param {Function} beforeEachFunction
+ */
+var beforeEach = function(beforeEachFunction) {
+ jasmine.getEnv().beforeEach(beforeEachFunction);
+};
+if (isCommonJS) exports.beforeEach = beforeEach;
+
+/**
+ * A function that is called after each spec in a suite.
+ *
+ * Used for restoring any state that is hijacked during spec execution.
+ *
+ * @param {Function} afterEachFunction
+ */
+var afterEach = function(afterEachFunction) {
+ jasmine.getEnv().afterEach(afterEachFunction);
+};
+if (isCommonJS) exports.afterEach = afterEach;
+
+/**
+ * Defines a suite of specifications.
+ *
+ * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
+ * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
+ * of setup in some tests.
+ *
+ * @example
+ * // TODO: a simple suite
+ *
+ * // TODO: a simple suite with a nested describe block
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var describe = function(description, specDefinitions) {
+ return jasmine.getEnv().describe(description, specDefinitions);
+};
+if (isCommonJS) exports.describe = describe;
+
+/**
+ * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var xdescribe = function(description, specDefinitions) {
+ return jasmine.getEnv().xdescribe(description, specDefinitions);
+};
+if (isCommonJS) exports.xdescribe = xdescribe;
+
+
+// Provide the XMLHttpRequest class for IE 5.x-6.x:
+jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
+ function tryIt(f) {
+ try {
+ return f();
+ } catch(e) {
+ }
+ return null;
+ }
+
+ var xhr = tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.6.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.3.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Microsoft.XMLHTTP");
+ });
+
+ if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
+
+ return xhr;
+} : XMLHttpRequest;
+/**
+ * @namespace
+ */
+jasmine.util = {};
+
+/**
+ * Declare that a child class inherit it's prototype from the parent class.
+ *
+ * @private
+ * @param {Function} childClass
+ * @param {Function} parentClass
+ */
+jasmine.util.inherit = function(childClass, parentClass) {
+ /**
+ * @private
+ */
+ var subclass = function() {
+ };
+ subclass.prototype = parentClass.prototype;
+ childClass.prototype = new subclass();
+};
+
+jasmine.util.formatException = function(e) {
+ var lineNumber;
+ if (e.line) {
+ lineNumber = e.line;
+ }
+ else if (e.lineNumber) {
+ lineNumber = e.lineNumber;
+ }
+
+ var file;
+
+ if (e.sourceURL) {
+ file = e.sourceURL;
+ }
+ else if (e.fileName) {
+ file = e.fileName;
+ }
+
+ var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
+
+ if (file && lineNumber) {
+ message += ' in ' + file + ' (line ' + lineNumber + ')';
+ }
+
+ return message;
+};
+
+jasmine.util.htmlEscape = function(str) {
+ if (!str) return str;
+ return str.replace(/&/g, '&')
+ .replace(//g, '>');
+};
+
+jasmine.util.argsToArray = function(args) {
+ var arrayOfArgs = [];
+ for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
+ return arrayOfArgs;
+};
+
+jasmine.util.extend = function(destination, source) {
+ for (var property in source) destination[property] = source[property];
+ return destination;
+};
+
+/**
+ * Environment for Jasmine
+ *
+ * @constructor
+ */
+jasmine.Env = function() {
+ this.currentSpec = null;
+ this.currentSuite = null;
+ this.currentRunner_ = new jasmine.Runner(this);
+
+ this.reporter = new jasmine.MultiReporter();
+
+ this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
+ this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
+ this.lastUpdate = 0;
+
+ function focusedSpecName() {
+ var specName;
+
+ (function memoizeFocusedSpec() {
+ if (specName) {
+ return;
+ }
+
+ var paramMap = [];
+ var params = window.cachedSearch.substring(1).split('&');
+
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ specName = paramMap.spec;
+ })();
+
+ if(specName)
+ specName = specName.replace(/%20/g, ' ');
+
+ return specName;
+ }
+
+ this.specFilter = function(spec) {
+ if(!focusedSpecName()) return true;
+
+ return spec.getFullName().indexOf(focusedSpecName()) === 0;
+ };
+
+ this.nextSpecId_ = 0;
+ this.nextSuiteId_ = 0;
+ this.equalityTesters_ = [];
+
+ // wrap matchers
+ this.matchersClass = function() {
+ jasmine.Matchers.apply(this, arguments);
+ };
+ jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
+
+ jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
+};
+
+
+jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
+jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
+jasmine.Env.prototype.setInterval = jasmine.setInterval;
+jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
+
+/**
+ * @returns an object containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.version = function () {
+ if (jasmine.version_) {
+ return jasmine.version_;
+ } else {
+ throw new Error('Version not set');
+ }
+};
+
+/**
+ * @returns string containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.versionString = function() {
+ if (!jasmine.version_) {
+ return "version unknown";
+ }
+
+ var version = this.version();
+ var versionString = version.major + "." + version.minor + "." + version.build;
+ if (version.release_candidate) {
+ versionString += ".rc" + version.release_candidate;
+ }
+ versionString += " revision " + version.revision;
+ return versionString;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSpecId = function () {
+ return this.nextSpecId_++;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSuiteId = function () {
+ return this.nextSuiteId_++;
+};
+
+/**
+ * Register a reporter to receive status updates from Jasmine.
+ * @param {jasmine.Reporter} reporter An object which will receive status updates.
+ */
+jasmine.Env.prototype.addReporter = function(reporter) {
+ this.reporter.addReporter(reporter);
+};
+
+jasmine.Env.prototype.execute = function() {
+ this.currentRunner_.execute();
+};
+
+jasmine.Env.prototype.describe = function(description, specDefinitions) {
+ var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
+
+ var parentSuite = this.currentSuite;
+ if (parentSuite) {
+ parentSuite.add(suite);
+ } else {
+ this.currentRunner_.add(suite);
+ }
+
+ this.currentSuite = suite;
+
+ var declarationError = null;
+ try {
+ specDefinitions.call(suite);
+ } catch(e) {
+ declarationError = e;
+ }
+
+ if (declarationError) {
+ this.it("encountered a declaration exception", function() {
+ throw declarationError;
+ });
+ }
+
+ this.currentSuite = parentSuite;
+
+ return suite;
+};
+
+jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.beforeEach(beforeEachFunction);
+ } else {
+ this.currentRunner_.beforeEach(beforeEachFunction);
+ }
+};
+
+jasmine.Env.prototype.currentRunner = function () {
+ return this.currentRunner_;
+};
+
+jasmine.Env.prototype.afterEach = function(afterEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.afterEach(afterEachFunction);
+ } else {
+ this.currentRunner_.afterEach(afterEachFunction);
+ }
+
+};
+
+jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
+ return {
+ execute: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.it = function(description, func) {
+ var spec = new jasmine.Spec(this, this.currentSuite, description);
+ this.currentSuite.add(spec);
+ this.currentSpec = spec;
+
+ if (func) {
+ spec.runs(func);
+ }
+
+ return spec;
+};
+
+jasmine.Env.prototype.xit = function(desc, func) {
+ return {
+ id: this.nextSpecId(),
+ runs: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
+ if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
+ return true;
+ }
+
+ a.__Jasmine_been_here_before__ = b;
+ b.__Jasmine_been_here_before__ = a;
+
+ var hasKey = function(obj, keyName) {
+ return obj !== null && obj[keyName] !== jasmine.undefined;
+ };
+
+ for (var property in b) {
+ if (!hasKey(a, property) && hasKey(b, property)) {
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+ }
+ }
+ for (property in a) {
+ if (!hasKey(b, property) && hasKey(a, property)) {
+ mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
+ }
+ }
+ for (property in b) {
+ if (property == '__Jasmine_been_here_before__') continue;
+ if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
+ mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
+ }
+ }
+
+ if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
+ mismatchValues.push("arrays were not the same length");
+ }
+
+ delete a.__Jasmine_been_here_before__;
+ delete b.__Jasmine_been_here_before__;
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
+ mismatchKeys = mismatchKeys || [];
+ mismatchValues = mismatchValues || [];
+
+ for (var i = 0; i < this.equalityTesters_.length; i++) {
+ var equalityTester = this.equalityTesters_[i];
+ var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
+ if (result !== jasmine.undefined) return result;
+ }
+
+ if (a === b) return true;
+
+ if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
+ return (a == jasmine.undefined && b == jasmine.undefined);
+ }
+
+ if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
+ return a === b;
+ }
+
+ if (a instanceof Date && b instanceof Date) {
+ return a.getTime() == b.getTime();
+ }
+
+ if (a.jasmineMatches) {
+ return a.jasmineMatches(b);
+ }
+
+ if (b.jasmineMatches) {
+ return b.jasmineMatches(a);
+ }
+
+ if (a instanceof jasmine.Matchers.ObjectContaining) {
+ return a.matches(b);
+ }
+
+ if (b instanceof jasmine.Matchers.ObjectContaining) {
+ return b.matches(a);
+ }
+
+ if (jasmine.isString_(a) && jasmine.isString_(b)) {
+ return (a == b);
+ }
+
+ if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
+ return (a == b);
+ }
+
+ if (typeof a === "object" && typeof b === "object") {
+ return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
+ }
+
+ //Straight check
+ return (a === b);
+};
+
+jasmine.Env.prototype.contains_ = function(haystack, needle) {
+ if (jasmine.isArray_(haystack)) {
+ for (var i = 0; i < haystack.length; i++) {
+ if (this.equals_(haystack[i], needle)) return true;
+ }
+ return false;
+ }
+ return haystack.indexOf(needle) >= 0;
+};
+
+jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
+ this.equalityTesters_.push(equalityTester);
+};
+/** No-op base class for Jasmine reporters.
+ *
+ * @constructor
+ */
+jasmine.Reporter = function() {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecResults = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.log = function(str) {
+};
+
+/**
+ * Blocks are functions with executable code that make up a spec.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {Function} func
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Block = function(env, func, spec) {
+ this.env = env;
+ this.func = func;
+ this.spec = spec;
+};
+
+jasmine.Block.prototype.execute = function(onComplete) {
+ try {
+ this.func.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ }
+ onComplete();
+};
+/** JavaScript API reporter.
+ *
+ * @constructor
+ */
+jasmine.JsApiReporter = function() {
+ this.started = false;
+ this.finished = false;
+ this.suites_ = [];
+ this.results_ = {};
+};
+
+jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
+ this.started = true;
+ var suites = runner.topLevelSuites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ this.suites_.push(this.summarize_(suite));
+ }
+};
+
+jasmine.JsApiReporter.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
+ var isSuite = suiteOrSpec instanceof jasmine.Suite;
+ var summary = {
+ id: suiteOrSpec.id,
+ name: suiteOrSpec.description,
+ type: isSuite ? 'suite' : 'spec',
+ children: []
+ };
+
+ if (isSuite) {
+ var children = suiteOrSpec.children();
+ for (var i = 0; i < children.length; i++) {
+ summary.children.push(this.summarize_(children[i]));
+ }
+ }
+ return summary;
+};
+
+jasmine.JsApiReporter.prototype.results = function() {
+ return this.results_;
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
+ return this.results_[specId];
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
+ this.finished = true;
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
+ this.results_[spec.id] = {
+ messages: spec.results().getItems(),
+ result: spec.results().failedCount > 0 ? "failed" : "passed"
+ };
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.log = function(str) {
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
+ var results = {};
+ for (var i = 0; i < specIds.length; i++) {
+ var specId = specIds[i];
+ results[specId] = this.summarizeResult_(this.results_[specId]);
+ }
+ return results;
+};
+
+jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
+ var summaryMessages = [];
+ var messagesLength = result.messages.length;
+ for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
+ var resultMessage = result.messages[messageIndex];
+ summaryMessages.push({
+ text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
+ passed: resultMessage.passed ? resultMessage.passed() : true,
+ type: resultMessage.type,
+ message: resultMessage.message,
+ trace: {
+ stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
+ }
+ });
+ }
+
+ return {
+ result : result.result,
+ messages : summaryMessages
+ };
+};
+
+/**
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param actual
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Matchers = function(env, actual, spec, opt_isNot) {
+ this.env = env;
+ this.actual = actual;
+ this.spec = spec;
+ this.isNot = opt_isNot || false;
+ this.reportWasCalled_ = false;
+};
+
+// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
+jasmine.Matchers.pp = function(str) {
+ throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
+};
+
+// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
+jasmine.Matchers.prototype.report = function(result, failing_message, details) {
+ throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
+};
+
+jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
+ for (var methodName in prototype) {
+ if (methodName == 'report') continue;
+ var orig = prototype[methodName];
+ matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
+ }
+};
+
+jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
+ return function() {
+ var matcherArgs = jasmine.util.argsToArray(arguments);
+ var result = matcherFunction.apply(this, arguments);
+
+ if (this.isNot) {
+ result = !result;
+ }
+
+ if (this.reportWasCalled_) return result;
+
+ var message;
+ if (!result) {
+ if (this.message) {
+ message = this.message.apply(this, arguments);
+ if (jasmine.isArray_(message)) {
+ message = message[this.isNot ? 1 : 0];
+ }
+ } else {
+ var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
+ message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
+ if (matcherArgs.length > 0) {
+ for (var i = 0; i < matcherArgs.length; i++) {
+ if (i > 0) message += ",";
+ message += " " + jasmine.pp(matcherArgs[i]);
+ }
+ }
+ message += ".";
+ }
+ }
+ var expectationResult = new jasmine.ExpectationResult({
+ matcherName: matcherName,
+ passed: result,
+ expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
+ actual: this.actual,
+ message: message
+ });
+ this.spec.addMatcherResult(expectationResult);
+ return jasmine.undefined;
+ };
+};
+
+
+
+
+/**
+ * toBe: compares the actual to the expected using ===
+ * @param expected
+ */
+jasmine.Matchers.prototype.toBe = function(expected) {
+ return this.actual === expected;
+};
+
+/**
+ * toNotBe: compares the actual to the expected using !==
+ * @param expected
+ * @deprecated as of 1.0. Use not.toBe() instead.
+ */
+jasmine.Matchers.prototype.toNotBe = function(expected) {
+ return this.actual !== expected;
+};
+
+/**
+ * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toEqual = function(expected) {
+ return this.env.equals_(this.actual, expected);
+};
+
+/**
+ * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
+ * @param expected
+ * @deprecated as of 1.0. Use not.toEqual() instead.
+ */
+jasmine.Matchers.prototype.toNotEqual = function(expected) {
+ return !this.env.equals_(this.actual, expected);
+};
+
+/**
+ * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
+ * a pattern or a String.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toMatch = function(expected) {
+ return new RegExp(expected).test(this.actual);
+};
+
+/**
+ * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
+ * @param expected
+ * @deprecated as of 1.0. Use not.toMatch() instead.
+ */
+jasmine.Matchers.prototype.toNotMatch = function(expected) {
+ return !(new RegExp(expected).test(this.actual));
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeDefined = function() {
+ return (this.actual !== jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeUndefined = function() {
+ return (this.actual === jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to null.
+ */
+jasmine.Matchers.prototype.toBeNull = function() {
+ return (this.actual === null);
+};
+
+/**
+ * Matcher that boolean not-nots the actual.
+ */
+jasmine.Matchers.prototype.toBeTruthy = function() {
+ return !!this.actual;
+};
+
+
+/**
+ * Matcher that boolean nots the actual.
+ */
+jasmine.Matchers.prototype.toBeFalsy = function() {
+ return !this.actual;
+};
+
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called.
+ */
+jasmine.Matchers.prototype.toHaveBeenCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to have been called.",
+ "Expected spy " + this.actual.identity + " not to have been called."
+ ];
+ };
+
+ return this.actual.wasCalled;
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
+jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was not called.
+ *
+ * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
+ */
+jasmine.Matchers.prototype.wasNotCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('wasNotCalled does not take arguments');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to not have been called.",
+ "Expected spy " + this.actual.identity + " to have been called."
+ ];
+ };
+
+ return !this.actual.wasCalled;
+};
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
+ *
+ * @example
+ *
+ */
+jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+ this.message = function() {
+ if (this.actual.callCount === 0) {
+ // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
+ return [
+ "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
+ "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
+ ];
+ } else {
+ return [
+ "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
+ "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
+ ];
+ }
+ };
+
+ return this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
+
+/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasNotCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
+ "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
+ ];
+ };
+
+ return !this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/**
+ * Matcher that checks that the expected item is an element in the actual Array.
+ *
+ * @param {Object} expected
+ */
+jasmine.Matchers.prototype.toContain = function(expected) {
+ return this.env.contains_(this.actual, expected);
+};
+
+/**
+ * Matcher that checks that the expected item is NOT an element in the actual Array.
+ *
+ * @param {Object} expected
+ * @deprecated as of 1.0. Use not.toContain() instead.
+ */
+jasmine.Matchers.prototype.toNotContain = function(expected) {
+ return !this.env.contains_(this.actual, expected);
+};
+
+jasmine.Matchers.prototype.toBeLessThan = function(expected) {
+ return this.actual < expected;
+};
+
+jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
+ return this.actual > expected;
+};
+
+/**
+ * Matcher that checks that the expected item is equal to the actual item
+ * up to a given level of decimal precision (default 2).
+ *
+ * @param {Number} expected
+ * @param {Number} precision
+ */
+jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
+ if (!(precision === 0)) {
+ precision = precision || 2;
+ }
+ var multiplier = Math.pow(10, precision);
+ var actual = Math.round(this.actual * multiplier);
+ expected = Math.round(expected * multiplier);
+ return expected == actual;
+};
+
+/**
+ * Matcher that checks that the expected exception was thrown by the actual.
+ *
+ * @param {String} expected
+ */
+jasmine.Matchers.prototype.toThrow = function(expected) {
+ var result = false;
+ var exception;
+ if (typeof this.actual != 'function') {
+ throw new Error('Actual is not a function');
+ }
+ try {
+ this.actual();
+ } catch (e) {
+ exception = e;
+ }
+ if (exception) {
+ result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
+ }
+
+ var not = this.isNot ? "not " : "";
+
+ this.message = function() {
+ if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
+ return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
+ } else {
+ return "Expected function to throw an exception.";
+ }
+ };
+
+ return result;
+};
+
+jasmine.Matchers.Any = function(expectedClass) {
+ this.expectedClass = expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
+ if (this.expectedClass == String) {
+ return typeof other == 'string' || other instanceof String;
+ }
+
+ if (this.expectedClass == Number) {
+ return typeof other == 'number' || other instanceof Number;
+ }
+
+ if (this.expectedClass == Function) {
+ return typeof other == 'function' || other instanceof Function;
+ }
+
+ if (this.expectedClass == Object) {
+ return typeof other == 'object';
+ }
+
+ return other instanceof this.expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineToString = function() {
+ return '';
+};
+
+jasmine.Matchers.ObjectContaining = function (sample) {
+ this.sample = sample;
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
+ mismatchKeys = mismatchKeys || [];
+ mismatchValues = mismatchValues || [];
+
+ var env = jasmine.getEnv();
+
+ var hasKey = function(obj, keyName) {
+ return obj != null && obj[keyName] !== jasmine.undefined;
+ };
+
+ for (var property in this.sample) {
+ if (!hasKey(other, property) && hasKey(this.sample, property)) {
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+ }
+ else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
+ mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
+ }
+ }
+
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
+ return "";
+};
+// Mock setTimeout, clearTimeout
+// Contributed by Pivotal Computer Systems, www.pivotalsf.com
+
+jasmine.FakeTimer = function() {
+ this.reset();
+
+ var self = this;
+ self.setTimeout = function(funcToCall, millis) {
+ self.timeoutsMade++;
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
+ return self.timeoutsMade;
+ };
+
+ self.setInterval = function(funcToCall, millis) {
+ self.timeoutsMade++;
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
+ return self.timeoutsMade;
+ };
+
+ self.clearTimeout = function(timeoutKey) {
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ };
+
+ self.clearInterval = function(timeoutKey) {
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ };
+
+};
+
+jasmine.FakeTimer.prototype.reset = function() {
+ this.timeoutsMade = 0;
+ this.scheduledFunctions = {};
+ this.nowMillis = 0;
+};
+
+jasmine.FakeTimer.prototype.tick = function(millis) {
+ var oldMillis = this.nowMillis;
+ var newMillis = oldMillis + millis;
+ this.runFunctionsWithinRange(oldMillis, newMillis);
+ this.nowMillis = newMillis;
+};
+
+jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
+ var scheduledFunc;
+ var funcsToRun = [];
+ for (var timeoutKey in this.scheduledFunctions) {
+ scheduledFunc = this.scheduledFunctions[timeoutKey];
+ if (scheduledFunc != jasmine.undefined &&
+ scheduledFunc.runAtMillis >= oldMillis &&
+ scheduledFunc.runAtMillis <= nowMillis) {
+ funcsToRun.push(scheduledFunc);
+ this.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ }
+ }
+
+ if (funcsToRun.length > 0) {
+ funcsToRun.sort(function(a, b) {
+ return a.runAtMillis - b.runAtMillis;
+ });
+ for (var i = 0; i < funcsToRun.length; ++i) {
+ try {
+ var funcToRun = funcsToRun[i];
+ this.nowMillis = funcToRun.runAtMillis;
+ funcToRun.funcToCall();
+ if (funcToRun.recurring) {
+ this.scheduleFunction(funcToRun.timeoutKey,
+ funcToRun.funcToCall,
+ funcToRun.millis,
+ true);
+ }
+ } catch(e) {
+ }
+ }
+ this.runFunctionsWithinRange(oldMillis, nowMillis);
+ }
+};
+
+jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
+ this.scheduledFunctions[timeoutKey] = {
+ runAtMillis: this.nowMillis + millis,
+ funcToCall: funcToCall,
+ recurring: recurring,
+ timeoutKey: timeoutKey,
+ millis: millis
+ };
+};
+
+/**
+ * @namespace
+ */
+jasmine.Clock = {
+ defaultFakeTimer: new jasmine.FakeTimer(),
+
+ reset: function() {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.defaultFakeTimer.reset();
+ },
+
+ tick: function(millis) {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.defaultFakeTimer.tick(millis);
+ },
+
+ runFunctionsWithinRange: function(oldMillis, nowMillis) {
+ jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
+ },
+
+ scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
+ jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
+ },
+
+ useMock: function() {
+ if (!jasmine.Clock.isInstalled()) {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.after(jasmine.Clock.uninstallMock);
+
+ jasmine.Clock.installMock();
+ }
+ },
+
+ installMock: function() {
+ jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
+ },
+
+ uninstallMock: function() {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.installed = jasmine.Clock.real;
+ },
+
+ real: {
+ setTimeout: jasmine.getGlobal().setTimeout,
+ clearTimeout: jasmine.getGlobal().clearTimeout,
+ setInterval: jasmine.getGlobal().setInterval,
+ clearInterval: jasmine.getGlobal().clearInterval
+ },
+
+ assertInstalled: function() {
+ if (!jasmine.Clock.isInstalled()) {
+ throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
+ }
+ },
+
+ isInstalled: function() {
+ return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
+ },
+
+ installed: null
+};
+jasmine.Clock.installed = jasmine.Clock.real;
+
+//else for IE support
+jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
+ if (jasmine.Clock.installed.setTimeout.apply) {
+ return jasmine.Clock.installed.setTimeout.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.setTimeout(funcToCall, millis);
+ }
+};
+
+jasmine.getGlobal().setInterval = function(funcToCall, millis) {
+ if (jasmine.Clock.installed.setInterval.apply) {
+ return jasmine.Clock.installed.setInterval.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.setInterval(funcToCall, millis);
+ }
+};
+
+jasmine.getGlobal().clearTimeout = function(timeoutKey) {
+ if (jasmine.Clock.installed.clearTimeout.apply) {
+ return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.clearTimeout(timeoutKey);
+ }
+};
+
+jasmine.getGlobal().clearInterval = function(timeoutKey) {
+ if (jasmine.Clock.installed.clearTimeout.apply) {
+ return jasmine.Clock.installed.clearInterval.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.clearInterval(timeoutKey);
+ }
+};
+
+/**
+ * @constructor
+ */
+jasmine.MultiReporter = function() {
+ this.subReporters_ = [];
+};
+jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
+
+jasmine.MultiReporter.prototype.addReporter = function(reporter) {
+ this.subReporters_.push(reporter);
+};
+
+(function() {
+ var functionNames = [
+ "reportRunnerStarting",
+ "reportRunnerResults",
+ "reportSuiteResults",
+ "reportSpecStarting",
+ "reportSpecResults",
+ "log"
+ ];
+ for (var i = 0; i < functionNames.length; i++) {
+ var functionName = functionNames[i];
+ jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
+ return function() {
+ for (var j = 0; j < this.subReporters_.length; j++) {
+ var subReporter = this.subReporters_[j];
+ if (subReporter[functionName]) {
+ subReporter[functionName].apply(subReporter, arguments);
+ }
+ }
+ };
+ })(functionName);
+ }
+})();
+/**
+ * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
+ *
+ * @constructor
+ */
+jasmine.NestedResults = function() {
+ /**
+ * The total count of results
+ */
+ this.totalCount = 0;
+ /**
+ * Number of passed results
+ */
+ this.passedCount = 0;
+ /**
+ * Number of failed results
+ */
+ this.failedCount = 0;
+ /**
+ * Was this suite/spec skipped?
+ */
+ this.skipped = false;
+ /**
+ * @ignore
+ */
+ this.items_ = [];
+};
+
+/**
+ * Roll up the result counts.
+ *
+ * @param result
+ */
+jasmine.NestedResults.prototype.rollupCounts = function(result) {
+ this.totalCount += result.totalCount;
+ this.passedCount += result.passedCount;
+ this.failedCount += result.failedCount;
+};
+
+/**
+ * Adds a log message.
+ * @param values Array of message parts which will be concatenated later.
+ */
+jasmine.NestedResults.prototype.log = function(values) {
+ this.items_.push(new jasmine.MessageResult(values));
+};
+
+/**
+ * Getter for the results: message & results.
+ */
+jasmine.NestedResults.prototype.getItems = function() {
+ return this.items_;
+};
+
+/**
+ * Adds a result, tracking counts (total, passed, & failed)
+ * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
+ */
+jasmine.NestedResults.prototype.addResult = function(result) {
+ if (result.type != 'log') {
+ if (result.items_) {
+ this.rollupCounts(result);
+ } else {
+ this.totalCount++;
+ if (result.passed()) {
+ this.passedCount++;
+ } else {
+ this.failedCount++;
+ }
+ }
+ }
+ this.items_.push(result);
+};
+
+/**
+ * @returns {Boolean} True if everything below passed
+ */
+jasmine.NestedResults.prototype.passed = function() {
+ return this.passedCount === this.totalCount;
+};
+/**
+ * Base class for pretty printing for expectation results.
+ */
+jasmine.PrettyPrinter = function() {
+ this.ppNestLevel_ = 0;
+};
+
+/**
+ * Formats a value in a nice, human-readable string.
+ *
+ * @param value
+ */
+jasmine.PrettyPrinter.prototype.format = function(value) {
+ if (this.ppNestLevel_ > 40) {
+ throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
+ }
+
+ this.ppNestLevel_++;
+ try {
+ if (value === jasmine.undefined) {
+ this.emitScalar('undefined');
+ } else if (value === null) {
+ this.emitScalar('null');
+ } else if (value === jasmine.getGlobal()) {
+ this.emitScalar('');
+ } else if (value.jasmineToString) {
+ this.emitScalar(value.jasmineToString());
+ } else if (typeof value === 'string') {
+ this.emitString(value);
+ } else if (jasmine.isSpy(value)) {
+ this.emitScalar("spy on " + value.identity);
+ } else if (value instanceof RegExp) {
+ this.emitScalar(value.toString());
+ } else if (typeof value === 'function') {
+ this.emitScalar('Function');
+ } else if (typeof value.nodeType === 'number') {
+ this.emitScalar('HTMLNode');
+ } else if (value instanceof Date) {
+ this.emitScalar('Date(' + value + ')');
+ } else if (value.__Jasmine_been_here_before__) {
+ this.emitScalar('');
+ } else if (jasmine.isArray_(value) || typeof value == 'object') {
+ value.__Jasmine_been_here_before__ = true;
+ if (jasmine.isArray_(value)) {
+ this.emitArray(value);
+ } else {
+ this.emitObject(value);
+ }
+ delete value.__Jasmine_been_here_before__;
+ } else {
+ this.emitScalar(value.toString());
+ }
+ } finally {
+ this.ppNestLevel_--;
+ }
+};
+
+jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
+ for (var property in obj) {
+ if (property == '__Jasmine_been_here_before__') continue;
+ fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
+ obj.__lookupGetter__(property) !== null) : false);
+ }
+};
+
+jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
+
+jasmine.StringPrettyPrinter = function() {
+ jasmine.PrettyPrinter.call(this);
+
+ this.string = '';
+};
+jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
+
+jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
+ this.append(value);
+};
+
+jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
+ this.append("'" + value + "'");
+};
+
+jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
+ this.append('[ ');
+ for (var i = 0; i < array.length; i++) {
+ if (i > 0) {
+ this.append(', ');
+ }
+ this.format(array[i]);
+ }
+ this.append(' ]');
+};
+
+jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
+ var self = this;
+ this.append('{ ');
+ var first = true;
+
+ this.iterateObject(obj, function(property, isGetter) {
+ if (first) {
+ first = false;
+ } else {
+ self.append(', ');
+ }
+
+ self.append(property);
+ self.append(' : ');
+ if (isGetter) {
+ self.append('');
+ } else {
+ self.format(obj[property]);
+ }
+ });
+
+ this.append(' }');
+};
+
+jasmine.StringPrettyPrinter.prototype.append = function(value) {
+ this.string += value;
+};
+jasmine.Queue = function(env) {
+ this.env = env;
+ this.blocks = [];
+ this.running = false;
+ this.index = 0;
+ this.offset = 0;
+ this.abort = false;
+};
+
+jasmine.Queue.prototype.addBefore = function(block) {
+ this.blocks.unshift(block);
+};
+
+jasmine.Queue.prototype.add = function(block) {
+ this.blocks.push(block);
+};
+
+jasmine.Queue.prototype.insertNext = function(block) {
+ this.blocks.splice((this.index + this.offset + 1), 0, block);
+ this.offset++;
+};
+
+jasmine.Queue.prototype.start = function(onComplete) {
+ this.running = true;
+ this.onComplete = onComplete;
+ this.next_();
+};
+
+jasmine.Queue.prototype.isRunning = function() {
+ return this.running;
+};
+
+jasmine.Queue.LOOP_DONT_RECURSE = true;
+
+jasmine.Queue.prototype.next_ = function() {
+ var self = this;
+ var goAgain = true;
+
+ while (goAgain) {
+ goAgain = false;
+
+ if (self.index < self.blocks.length && !this.abort) {
+ var calledSynchronously = true;
+ var completedSynchronously = false;
+
+ var onComplete = function () {
+ if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
+ completedSynchronously = true;
+ return;
+ }
+
+ if (self.blocks[self.index].abort) {
+ self.abort = true;
+ }
+
+ self.offset = 0;
+ self.index++;
+
+ var now = new Date().getTime();
+ if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
+ self.env.lastUpdate = now;
+ self.env.setTimeout(function() {
+ self.next_();
+ }, 0);
+ } else {
+ if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
+ goAgain = true;
+ } else {
+ self.next_();
+ }
+ }
+ };
+ self.blocks[self.index].execute(onComplete);
+
+ calledSynchronously = false;
+ if (completedSynchronously) {
+ onComplete();
+ }
+
+ } else {
+ self.running = false;
+ if (self.onComplete) {
+ self.onComplete();
+ }
+ }
+ }
+};
+
+jasmine.Queue.prototype.results = function() {
+ var results = new jasmine.NestedResults();
+ for (var i = 0; i < this.blocks.length; i++) {
+ if (this.blocks[i].results) {
+ results.addResult(this.blocks[i].results());
+ }
+ }
+ return results;
+};
+
+
+/**
+ * Runner
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ */
+jasmine.Runner = function(env) {
+ var self = this;
+ self.env = env;
+ self.queue = new jasmine.Queue(env);
+ self.before_ = [];
+ self.after_ = [];
+ self.suites_ = [];
+};
+
+jasmine.Runner.prototype.execute = function() {
+ var self = this;
+ if (self.env.reporter.reportRunnerStarting) {
+ self.env.reporter.reportRunnerStarting(this);
+ }
+ self.queue.start(function () {
+ self.finishCallback();
+ });
+};
+
+jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
+ beforeEachFunction.typeName = 'beforeEach';
+ this.before_.splice(0,0,beforeEachFunction);
+};
+
+jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
+ afterEachFunction.typeName = 'afterEach';
+ this.after_.splice(0,0,afterEachFunction);
+};
+
+
+jasmine.Runner.prototype.finishCallback = function() {
+ this.env.reporter.reportRunnerResults(this);
+};
+
+jasmine.Runner.prototype.addSuite = function(suite) {
+ this.suites_.push(suite);
+};
+
+jasmine.Runner.prototype.add = function(block) {
+ if (block instanceof jasmine.Suite) {
+ this.addSuite(block);
+ }
+ this.queue.add(block);
+};
+
+jasmine.Runner.prototype.specs = function () {
+ var suites = this.suites();
+ var specs = [];
+ for (var i = 0; i < suites.length; i++) {
+ specs = specs.concat(suites[i].specs());
+ }
+ return specs;
+};
+
+jasmine.Runner.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.Runner.prototype.topLevelSuites = function() {
+ var topLevelSuites = [];
+ for (var i = 0; i < this.suites_.length; i++) {
+ if (!this.suites_[i].parentSuite) {
+ topLevelSuites.push(this.suites_[i]);
+ }
+ }
+ return topLevelSuites;
+};
+
+jasmine.Runner.prototype.results = function() {
+ return this.queue.results();
+};
+/**
+ * Internal representation of a Jasmine specification, or test.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {jasmine.Suite} suite
+ * @param {String} description
+ */
+jasmine.Spec = function(env, suite, description) {
+ if (!env) {
+ throw new Error('jasmine.Env() required');
+ }
+ if (!suite) {
+ throw new Error('jasmine.Suite() required');
+ }
+ var spec = this;
+ spec.id = env.nextSpecId ? env.nextSpecId() : null;
+ spec.env = env;
+ spec.suite = suite;
+ spec.description = description;
+ spec.queue = new jasmine.Queue(env);
+
+ spec.afterCallbacks = [];
+ spec.spies_ = [];
+
+ spec.results_ = new jasmine.NestedResults();
+ spec.results_.description = description;
+ spec.matchersClass = null;
+};
+
+jasmine.Spec.prototype.getFullName = function() {
+ return this.suite.getFullName() + ' ' + this.description + '.';
+};
+
+
+jasmine.Spec.prototype.results = function() {
+ return this.results_;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the spec's output.
+ *
+ * Be careful not to leave calls to jasmine.log
in production code.
+ */
+jasmine.Spec.prototype.log = function() {
+ return this.results_.log(arguments);
+};
+
+jasmine.Spec.prototype.runs = function (func) {
+ var block = new jasmine.Block(this.env, func, this);
+ this.addToQueue(block);
+ return this;
+};
+
+jasmine.Spec.prototype.addToQueue = function (block) {
+ if (this.queue.isRunning()) {
+ this.queue.insertNext(block);
+ } else {
+ this.queue.add(block);
+ }
+};
+
+/**
+ * @param {jasmine.ExpectationResult} result
+ */
+jasmine.Spec.prototype.addMatcherResult = function(result) {
+ this.results_.addResult(result);
+};
+
+jasmine.Spec.prototype.expect = function(actual) {
+ var positive = new (this.getMatchersClass_())(this.env, actual, this);
+ positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
+ return positive;
+};
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+jasmine.Spec.prototype.waits = function(timeout) {
+ var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
+ this.addToQueue(waitsFunc);
+ return this;
+};
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ var latchFunction_ = null;
+ var optional_timeoutMessage_ = null;
+ var optional_timeout_ = null;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var arg = arguments[i];
+ switch (typeof arg) {
+ case 'function':
+ latchFunction_ = arg;
+ break;
+ case 'string':
+ optional_timeoutMessage_ = arg;
+ break;
+ case 'number':
+ optional_timeout_ = arg;
+ break;
+ }
+ }
+
+ var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
+ this.addToQueue(waitsForFunc);
+ return this;
+};
+
+jasmine.Spec.prototype.fail = function (e) {
+ var expectationResult = new jasmine.ExpectationResult({
+ passed: false,
+ message: e ? jasmine.util.formatException(e) : 'Exception',
+ trace: { stack: e.stack }
+ });
+ this.results_.addResult(expectationResult);
+};
+
+jasmine.Spec.prototype.getMatchersClass_ = function() {
+ return this.matchersClass || this.env.matchersClass;
+};
+
+jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
+ var parent = this.getMatchersClass_();
+ var newMatchersClass = function() {
+ parent.apply(this, arguments);
+ };
+ jasmine.util.inherit(newMatchersClass, parent);
+ jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
+ this.matchersClass = newMatchersClass;
+};
+
+jasmine.Spec.prototype.finishCallback = function() {
+ this.env.reporter.reportSpecResults(this);
+};
+
+jasmine.Spec.prototype.finish = function(onComplete) {
+ this.removeAllSpies();
+ this.finishCallback();
+ if (onComplete) {
+ onComplete();
+ }
+};
+
+jasmine.Spec.prototype.after = function(doAfter) {
+ if (this.queue.isRunning()) {
+ this.queue.add(new jasmine.Block(this.env, doAfter, this));
+ } else {
+ this.afterCallbacks.unshift(doAfter);
+ }
+};
+
+jasmine.Spec.prototype.execute = function(onComplete) {
+ var spec = this;
+ if (!spec.env.specFilter(spec)) {
+ spec.results_.skipped = true;
+ spec.finish(onComplete);
+ return;
+ }
+
+ this.env.reporter.reportSpecStarting(this);
+
+ spec.env.currentSpec = spec;
+
+ spec.addBeforesAndAftersToQueue();
+
+ spec.queue.start(function () {
+ spec.finish(onComplete);
+ });
+};
+
+jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
+ var runner = this.env.currentRunner();
+ var i;
+
+ for (var suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
+ }
+ }
+ for (i = 0; i < runner.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
+ }
+ for (i = 0; i < this.afterCallbacks.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
+ }
+ for (suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
+ }
+ }
+ for (i = 0; i < runner.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
+ }
+};
+
+jasmine.Spec.prototype.explodes = function() {
+ throw 'explodes function should not have been called';
+};
+
+jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
+ if (obj == jasmine.undefined) {
+ throw "spyOn could not find an object to spy upon for " + methodName + "()";
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
+ throw methodName + '() method does not exist';
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
+ throw new Error(methodName + ' has already been spied upon');
+ }
+
+ var spyObj = jasmine.createSpy(methodName);
+
+ this.spies_.push(spyObj);
+ spyObj.baseObj = obj;
+ spyObj.methodName = methodName;
+ spyObj.originalValue = obj[methodName];
+
+ obj[methodName] = spyObj;
+
+ return spyObj;
+};
+
+jasmine.Spec.prototype.removeAllSpies = function() {
+ for (var i = 0; i < this.spies_.length; i++) {
+ var spy = this.spies_[i];
+ spy.baseObj[spy.methodName] = spy.originalValue;
+ }
+ this.spies_ = [];
+};
+
+/**
+ * Internal representation of a Jasmine suite.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {String} description
+ * @param {Function} specDefinitions
+ * @param {jasmine.Suite} parentSuite
+ */
+jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
+ var self = this;
+ self.id = env.nextSuiteId ? env.nextSuiteId() : null;
+ self.description = description;
+ self.queue = new jasmine.Queue(env);
+ self.parentSuite = parentSuite;
+ self.env = env;
+ self.before_ = [];
+ self.after_ = [];
+ self.children_ = [];
+ self.suites_ = [];
+ self.specs_ = [];
+};
+
+jasmine.Suite.prototype.getFullName = function() {
+ var fullName = this.description;
+ for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
+ fullName = parentSuite.description + ' ' + fullName;
+ }
+ return fullName;
+};
+
+jasmine.Suite.prototype.finish = function(onComplete) {
+ this.env.reporter.reportSuiteResults(this);
+ this.finished = true;
+ if (typeof(onComplete) == 'function') {
+ onComplete();
+ }
+};
+
+jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
+ beforeEachFunction.typeName = 'beforeEach';
+ this.before_.unshift(beforeEachFunction);
+};
+
+jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
+ afterEachFunction.typeName = 'afterEach';
+ this.after_.unshift(afterEachFunction);
+};
+
+jasmine.Suite.prototype.results = function() {
+ return this.queue.results();
+};
+
+jasmine.Suite.prototype.add = function(suiteOrSpec) {
+ this.children_.push(suiteOrSpec);
+ if (suiteOrSpec instanceof jasmine.Suite) {
+ this.suites_.push(suiteOrSpec);
+ this.env.currentRunner().addSuite(suiteOrSpec);
+ } else {
+ this.specs_.push(suiteOrSpec);
+ }
+ this.queue.add(suiteOrSpec);
+};
+
+jasmine.Suite.prototype.specs = function() {
+ return this.specs_;
+};
+
+jasmine.Suite.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.Suite.prototype.children = function() {
+ return this.children_;
+};
+
+jasmine.Suite.prototype.execute = function(onComplete) {
+ var self = this;
+ this.queue.start(function () {
+ self.finish(onComplete);
+ });
+};
+jasmine.WaitsBlock = function(env, timeout, spec) {
+ this.timeout = timeout;
+ jasmine.Block.call(this, env, null, spec);
+};
+
+jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
+
+jasmine.WaitsBlock.prototype.execute = function (onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
+ }
+ this.env.setTimeout(function () {
+ onComplete();
+ }, this.timeout);
+};
+/**
+ * A block which waits for some condition to become true, with timeout.
+ *
+ * @constructor
+ * @extends jasmine.Block
+ * @param {jasmine.Env} env The Jasmine environment.
+ * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
+ * @param {Function} latchFunction A function which returns true when the desired condition has been met.
+ * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
+ * @param {jasmine.Spec} spec The Jasmine spec.
+ */
+jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
+ this.timeout = timeout || env.defaultTimeoutInterval;
+ this.latchFunction = latchFunction;
+ this.message = message;
+ this.totalTimeSpentWaitingForLatch = 0;
+ jasmine.Block.call(this, env, null, spec);
+};
+jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
+
+jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
+
+jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
+ }
+ var latchFunctionResult;
+ try {
+ latchFunctionResult = this.latchFunction.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ onComplete();
+ return;
+ }
+
+ if (latchFunctionResult) {
+ onComplete();
+ } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
+ var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
+ this.spec.fail({
+ name: 'timeout',
+ message: message
+ });
+
+ this.abort = true;
+ onComplete();
+ } else {
+ this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
+ var self = this;
+ this.env.setTimeout(function() {
+ self.execute(onComplete);
+ }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
+ }
+};
+
+jasmine.version_= {
+ "major": 1,
+ "minor": 2,
+ "build": 0,
+ "revision": 1337005947
+};
+jasmine.HtmlReporterHelpers = {};
+
+jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) {
+ el.appendChild(child);
+ }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
+ var results = child.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+
+ return status;
+};
+
+jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
+ var parentDiv = this.dom.summary;
+ var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
+ var parent = child[parentSuite];
+
+ if (parent) {
+ if (typeof this.views.suites[parent.id] == 'undefined') {
+ this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
+ }
+ parentDiv = this.views.suites[parent.id].element;
+ }
+
+ parentDiv.appendChild(childElement);
+};
+
+
+jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
+ for(var fn in jasmine.HtmlReporterHelpers) {
+ ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
+ }
+};
+
+jasmine.HtmlReporter = function(_doc) {
+ var self = this;
+ var doc = _doc || window.document;
+
+ var reporterView;
+
+ var dom = {};
+
+ // Jasmine Reporter Public Interface
+ self.logRunningSpecs = false;
+
+ self.reportRunnerStarting = function(runner) {
+ var specs = runner.specs() || [];
+
+ if (specs.length == 0) {
+ return;
+ }
+
+ createReporterDom(runner.env.versionString());
+ doc.body.appendChild(dom.reporter);
+
+ reporterView = new jasmine.HtmlReporter.ReporterView(dom);
+ reporterView.addSpecs(specs, self.specFilter);
+ };
+
+ self.reportRunnerResults = function(runner) {
+ reporterView && reporterView.complete();
+ };
+
+ self.reportSuiteResults = function(suite) {
+ reporterView.suiteComplete(suite);
+ };
+
+ self.reportSpecStarting = function(spec) {
+ if (self.logRunningSpecs) {
+ self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+ };
+
+ self.reportSpecResults = function(spec) {
+ reporterView.specComplete(spec);
+ };
+
+ self.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+ };
+
+ self.specFilter = function(spec) {
+ if (!focusedSpecName()) {
+ return true;
+ }
+
+ return spec.getFullName().indexOf(focusedSpecName()) === 0;
+ };
+
+ return self;
+
+ function focusedSpecName() {
+ var specName;
+
+ (function memoizeFocusedSpec() {
+ if (specName) {
+ return;
+ }
+
+ var paramMap = [];
+ var params = doc.location.search.substring(1).split('&');
+
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ specName = paramMap.spec;
+ })();
+
+ return specName;
+ }
+
+ function createReporterDom(version) {
+ dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
+ dom.banner = self.createDom('div', { className: 'banner' },
+ self.createDom('span', { className: 'title' }, "Jasmine "),
+ self.createDom('span', { className: 'version' }, version)),
+
+ dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
+ dom.alert = self.createDom('div', {className: 'alert'}),
+ dom.results = self.createDom('div', {className: 'results'},
+ dom.summary = self.createDom('div', { className: 'summary' }),
+ dom.details = self.createDom('div', { id: 'details' }))
+ );
+ }
+};
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) {
+ this.startedAt = new Date();
+ this.runningSpecCount = 0;
+ this.completeSpecCount = 0;
+ this.passedCount = 0;
+ this.failedCount = 0;
+ this.skippedCount = 0;
+
+ this.createResultsMenu = function() {
+ this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
+ this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
+ ' | ',
+ this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
+
+ this.summaryMenuItem.onclick = function() {
+ dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
+ };
+
+ this.detailsMenuItem.onclick = function() {
+ showDetails();
+ };
+ };
+
+ this.addSpecs = function(specs, specFilter) {
+ this.totalSpecCount = specs.length;
+
+ this.views = {
+ specs: {},
+ suites: {}
+ };
+
+ for (var i = 0; i < specs.length; i++) {
+ var spec = specs[i];
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
+ if (specFilter(spec)) {
+ this.runningSpecCount++;
+ }
+ }
+ };
+
+ this.specComplete = function(spec) {
+ this.completeSpecCount++;
+
+ if (isUndefined(this.views.specs[spec.id])) {
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
+ }
+
+ var specView = this.views.specs[spec.id];
+
+ switch (specView.status()) {
+ case 'passed':
+ this.passedCount++;
+ break;
+
+ case 'failed':
+ this.failedCount++;
+ break;
+
+ case 'skipped':
+ this.skippedCount++;
+ break;
+ }
+
+ specView.refresh();
+ this.refresh();
+ };
+
+ this.suiteComplete = function(suite) {
+ var suiteView = this.views.suites[suite.id];
+ if (isUndefined(suiteView)) {
+ return;
+ }
+ suiteView.refresh();
+ };
+
+ this.refresh = function() {
+
+ if (isUndefined(this.resultsMenu)) {
+ this.createResultsMenu();
+ }
+
+ // currently running UI
+ if (isUndefined(this.runningAlert)) {
+ this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
+ dom.alert.appendChild(this.runningAlert);
+ }
+ this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
+
+ // skipped specs UI
+ if (isUndefined(this.skippedAlert)) {
+ this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
+ }
+
+ this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.skippedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.skippedAlert);
+ }
+
+ // passing specs UI
+ if (isUndefined(this.passedAlert)) {
+ this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
+ }
+ this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
+
+ // failing specs UI
+ if (isUndefined(this.failedAlert)) {
+ this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
+ }
+ this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
+
+ if (this.failedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.failedAlert);
+ dom.alert.appendChild(this.resultsMenu);
+ }
+
+ // summary info
+ this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
+ this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
+ };
+
+ this.complete = function() {
+ dom.alert.removeChild(this.runningAlert);
+
+ this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.failedCount === 0) {
+ dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
+ } else {
+ showDetails();
+ }
+
+ dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
+ };
+
+ return this;
+
+ function showDetails() {
+ if (dom.reporter.className.search(/showDetails/) === -1) {
+ dom.reporter.className += " showDetails";
+ }
+ }
+
+ function isUndefined(obj) {
+ return typeof obj === 'undefined';
+ }
+
+ function isDefined(obj) {
+ return !isUndefined(obj);
+ }
+
+ function specPluralizedFor(count) {
+ var str = count + " spec";
+ if (count > 1) {
+ str += "s"
+ }
+ return str;
+ }
+
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
+
+
+jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
+ this.spec = spec;
+ this.dom = dom;
+ this.views = views;
+
+ this.symbol = this.createDom('li', { className: 'pending' });
+ this.dom.symbolSummary.appendChild(this.symbol);
+
+ this.summary = this.createDom('div', { className: 'specSummary' },
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+ title: this.spec.getFullName()
+ }, this.spec.description)
+ );
+
+ this.detail = this.createDom('div', { className: 'specDetail' },
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+ title: this.spec.getFullName()
+ }, this.spec.getFullName())
+ );
+};
+
+jasmine.HtmlReporter.SpecView.prototype.status = function() {
+ return this.getSpecStatus(this.spec);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
+ this.symbol.className = this.status();
+
+ switch (this.status()) {
+ case 'skipped':
+ break;
+
+ case 'passed':
+ this.appendSummaryToSuiteDiv();
+ break;
+
+ case 'failed':
+ this.appendSummaryToSuiteDiv();
+ this.appendFailureDetail();
+ break;
+ }
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
+ this.summary.className += ' ' + this.status();
+ this.appendToSummary(this.spec, this.summary);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
+ this.detail.className += ' ' + this.status();
+
+ var resultItems = this.spec.results().getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ this.detail.appendChild(messagesDiv);
+ this.dom.details.appendChild(this.detail);
+ }
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
+ this.suite = suite;
+ this.dom = dom;
+ this.views = views;
+
+ this.element = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
+ );
+
+ this.appendToSummary(this.suite, this.element);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.status = function() {
+ return this.getSpecStatus(this.suite);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
+ this.element.className += " " + this.status();
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
+
+/* @deprecated Use jasmine.HtmlReporter instead
+ */
+jasmine.TrivialReporter = function(doc) {
+ this.document = doc || document;
+ this.suiteDivs = {};
+ this.logRunningSpecs = false;
+};
+
+jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) { el.appendChild(child); }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
+ var showPassed, showSkipped;
+
+ this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
+ this.createDom('div', { className: 'banner' },
+ this.createDom('div', { className: 'logo' },
+ this.createDom('span', { className: 'title' }, "Jasmine"),
+ this.createDom('span', { className: 'version' }, runner.env.versionString())),
+ this.createDom('div', { className: 'options' },
+ "Show ",
+ showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
+ showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
+ )
+ ),
+
+ this.runnerDiv = this.createDom('div', { className: 'runner running' },
+ this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
+ this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
+ this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
+ );
+
+ this.document.body.appendChild(this.outerDiv);
+
+ var suites = runner.suites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ var suiteDiv = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
+ this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
+ this.suiteDivs[suite.id] = suiteDiv;
+ var parentDiv = this.outerDiv;
+ if (suite.parentSuite) {
+ parentDiv = this.suiteDivs[suite.parentSuite.id];
+ }
+ parentDiv.appendChild(suiteDiv);
+ }
+
+ this.startedAt = new Date();
+
+ var self = this;
+ showPassed.onclick = function(evt) {
+ if (showPassed.checked) {
+ self.outerDiv.className += ' show-passed';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
+ }
+ };
+
+ showSkipped.onclick = function(evt) {
+ if (showSkipped.checked) {
+ self.outerDiv.className += ' show-skipped';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
+ }
+ };
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
+ var results = runner.results();
+ var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
+ this.runnerDiv.setAttribute("class", className);
+ //do it twice for IE
+ this.runnerDiv.setAttribute("className", className);
+ var specs = runner.specs();
+ var specCount = 0;
+ for (var i = 0; i < specs.length; i++) {
+ if (this.specFilter(specs[i])) {
+ specCount++;
+ }
+ }
+ var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
+ message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
+ this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
+
+ this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
+};
+
+jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
+ var results = suite.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.totalCount === 0) { // todo: change this to check results.skipped
+ status = 'skipped';
+ }
+ this.suiteDivs[suite.id].className += " " + status;
+};
+
+jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
+ if (this.logRunningSpecs) {
+ this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+};
+
+jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
+ var results = spec.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+ var specDiv = this.createDom('div', { className: 'spec ' + status },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(spec.getFullName()),
+ title: spec.getFullName()
+ }, spec.description));
+
+
+ var resultItems = results.getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ specDiv.appendChild(messagesDiv);
+ }
+
+ this.suiteDivs[spec.suite.id].appendChild(specDiv);
+};
+
+jasmine.TrivialReporter.prototype.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+};
+
+jasmine.TrivialReporter.prototype.getLocation = function() {
+ return this.document.location;
+};
+
+jasmine.TrivialReporter.prototype.specFilter = function(spec) {
+ var paramMap = {};
+ var params = this.getLocation().search.substring(1).split('&');
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ if (!paramMap.spec) {
+ return true;
+ }
+ return spec.getFullName().indexOf(paramMap.spec) === 0;
+};
+/**
+ Jasmine Reporter that outputs test results to the browser console.
+ Useful for running in a headless environment such as PhantomJs, ZombieJs etc.
+
+ Usage:
+ // From your html file that loads jasmine:
+ jasmine.getEnv().addReporter(new jasmine.ConsoleReporter());
+ jasmine.getEnv().execute();
+*/
+
+(function(jasmine, console) {
+ if (!jasmine) {
+ throw "jasmine library isn't loaded!";
+ }
+
+ var ANSI = {}
+ ANSI.color_map = {
+ "green" : 32,
+ "red" : 31
+ }
+
+ ANSI.colorize_text = function(text, color) {
+ var color_code = this.color_map[color];
+ return "\033[" + color_code + "m" + text + "\033[0m";
+ }
+
+ var ConsoleReporter = function() {
+ if (!console || !console.log) { throw "console isn't present!"; }
+ this.status = this.statuses.stopped;
+ };
+
+ var proto = ConsoleReporter.prototype;
+ proto.statuses = {
+ stopped : "stopped",
+ running : "running",
+ fail : "fail",
+ success : "success"
+ };
+
+ proto.reportRunnerStarting = function(runner) {
+ this.status = this.statuses.running;
+ this.start_time = (new Date()).getTime();
+ this.executed_specs = 0;
+ this.passed_specs = 0;
+ this.log("Starting...");
+ };
+
+ proto.reportRunnerResults = function(runner) {
+ var failed = this.executed_specs - this.passed_specs;
+ var spec_str = this.executed_specs + (this.executed_specs === 1 ? " spec, " : " specs, ");
+ var fail_str = failed + (failed === 1 ? " failure in " : " failures in ");
+ var color = (failed > 0)? "red" : "green";
+ var dur = (new Date()).getTime() - this.start_time;
+
+ this.log("");
+ this.log("Finished");
+ this.log("-----------------");
+ this.log(spec_str + fail_str + (dur/1000) + "s.", color);
+
+ this.status = (failed > 0)? this.statuses.fail : this.statuses.success;
+
+ /* Print something that signals that testing is over so that headless browsers
+ like PhantomJs know when to terminate. */
+ this.log("");
+ this.log("ConsoleReporter finished");
+ };
+
+
+ proto.reportSpecStarting = function(spec) {
+ this.executed_specs++;
+ };
+
+ proto.reportSpecResults = function(spec) {
+ if (spec.results().passed()) {
+ this.passed_specs++;
+ return;
+ }
+
+ var resultText = spec.suite.description + " : " + spec.description;
+ this.log(resultText, "red");
+
+ var items = spec.results().getItems()
+ for (var i = 0; i < items.length; i++) {
+ var text = items[i].trace;
+ this.log(text, "red");
+ }
+ };
+
+ proto.reportSuiteResults = function(suite) {
+ if (!suite.parentSuite) { return; }
+ var results = suite.results();
+ var failed = results.totalCount - results.passedCount;
+ var color = (failed > 0)? "red" : "green";
+ this.log(suite.description + ": " + results.passedCount + " of " + results.totalCount + " passed.", color);
+ };
+
+ proto.log = function(str, color) {
+ var text = (color != undefined)? ANSI.colorize_text(str, color) : str;
+ console.log(text)
+ };
+
+ jasmine.ConsoleReporter = ConsoleReporter;
+})(jasmine, console);
+
+/**
+ * Sinon.JS 1.3.4, 2012/04/16
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ *
+ * (The BSD License)
+ *
+ * Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Christian Johansen nor the names of his contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+"use strict";
+var sinon = (function () {
+var buster = (function (buster, setTimeout) {
+ function extend(target) {
+ if (!target) {
+ return;
+ }
+
+ for (var i = 1, l = arguments.length, prop; i < l; ++i) {
+ for (prop in arguments[i]) {
+ target[prop] = arguments[i][prop];
+ }
+ }
+
+ return target;
+ }
+
+ var div = typeof document != "undefined" && document.createElement("div");
+
+ return extend(buster, {
+ bind: function (obj, methOrProp) {
+ var method = typeof methOrProp == "string" ? obj[methOrProp] : methOrProp;
+ var args = Array.prototype.slice.call(arguments, 2);
+
+ return function () {
+ var allArgs = args.concat(Array.prototype.slice.call(arguments));
+ return method.apply(obj, allArgs);
+ };
+ },
+
+ create: (function () {
+ function F() {}
+
+ return function create(object) {
+ F.prototype = object;
+ return new F();
+ }
+ }()),
+
+ extend: extend,
+
+ nextTick: function (callback) {
+ if (typeof process != "undefined" && process.nextTick) {
+ return process.nextTick(callback);
+ }
+
+ setTimeout(callback, 0);
+ },
+
+ functionName: function (func) {
+ if (!func) return "";
+ if (func.displayName) return func.displayName;
+ if (func.name) return func.name;
+
+ var matches = func.toString().match(/function\s+([^\(]+)/m);
+ return matches && matches[1] || "";
+ },
+
+ isNode: function (obj) {
+ if (!div) return false;
+
+ try {
+ obj.appendChild(div);
+ obj.removeChild(div);
+ } catch (e) {
+ return false;
+ }
+
+ return true;
+ },
+
+ isElement: function (obj) {
+ return obj && buster.isNode(obj) && obj.nodeType === 1;
+ }
+ });
+}(buster || {}, setTimeout));
+
+if (typeof module == "object" && typeof require == "function") {
+ module.exports = buster;
+ buster.eventEmitter = require("./buster-event-emitter");
+
+ Object.defineProperty(buster, "defineVersionGetter", {
+ get: function () {
+ return require("./define-version-getter");
+ }
+ });
+}
+if (typeof buster === "undefined") {
+ var buster = {};
+}
+
+if (typeof module === "object" && typeof require === "function") {
+ buster = require("buster-core");
+}
+
+buster.format = buster.format || {};
+buster.format.excludeConstructors = ["Object", /^.$/];
+buster.format.quoteStrings = true;
+
+buster.format.ascii = (function () {
+
+ function keys(object) {
+ var k = Object.keys && Object.keys(object) || [];
+
+ if (k.length == 0) {
+ for (var prop in object) {
+ if (object.hasOwnProperty(prop)) {
+ k.push(prop);
+ }
+ }
+ }
+
+ return k.sort();
+ }
+
+ function isCircular(object, objects) {
+ if (typeof object != "object") {
+ return false;
+ }
+
+ for (var i = 0, l = objects.length; i < l; ++i) {
+ if (objects[i] === object) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ function ascii(object, processed, indent) {
+ if (typeof object == "string") {
+ var quote = typeof this.quoteStrings != "boolean" || this.quoteStrings;
+ return processed || quote ? '"' + object + '"' : object;
+ }
+
+ if (typeof object == "function" && !(object instanceof RegExp)) {
+ return ascii.func(object);
+ }
+
+ processed = processed || [];
+
+ if (isCircular(object, processed)) {
+ return "[Circular]";
+ }
+
+ if (Object.prototype.toString.call(object) == "[object Array]") {
+ return ascii.array.call(this, object);
+ }
+
+ if (!object) {
+ return "" + object;
+ }
+
+ if (buster.isElement(object)) {
+ return ascii.element(object);
+ }
+
+ if (typeof object.toString == "function" &&
+ object.toString !== Object.prototype.toString) {
+ return object.toString();
+ }
+
+ return ascii.object.call(this, object, processed, indent);
+ }
+
+ ascii.func = function (func) {
+ return "function " + buster.functionName(func) + "() {}";
+ };
+
+ ascii.array = function (array, processed) {
+ processed = processed || [];
+ processed.push(array);
+ var pieces = [];
+
+ for (var i = 0, l = array.length; i < l; ++i) {
+ pieces.push(ascii.call(this, array[i], processed));
+ }
+
+ return "[" + pieces.join(", ") + "]";
+ };
+
+ ascii.object = function (object, processed, indent) {
+ processed = processed || [];
+ processed.push(object);
+ indent = indent || 0;
+ var pieces = [], properties = keys(object), prop, str, obj;
+ var is = "";
+ var length = 3;
+
+ for (var i = 0, l = indent; i < l; ++i) {
+ is += " ";
+ }
+
+ for (i = 0, l = properties.length; i < l; ++i) {
+ prop = properties[i];
+ obj = object[prop];
+
+ if (isCircular(obj, processed)) {
+ str = "[Circular]";
+ } else {
+ str = ascii.call(this, obj, processed, indent + 2);
+ }
+
+ str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
+ length += str.length;
+ pieces.push(str);
+ }
+
+ var cons = ascii.constructorName.call(this, object);
+ var prefix = cons ? "[" + cons + "] " : ""
+
+ return (length + indent) > 80 ?
+ prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" + is + "}" :
+ prefix + "{ " + pieces.join(", ") + " }";
+ };
+
+ ascii.element = function (element) {
+ var tagName = element.tagName.toLowerCase();
+ var attrs = element.attributes, attribute, pairs = [], attrName;
+
+ for (var i = 0, l = attrs.length; i < l; ++i) {
+ attribute = attrs.item(i);
+ attrName = attribute.nodeName.toLowerCase().replace("html:", "");
+
+ if (attrName == "contenteditable" && attribute.nodeValue == "inherit") {
+ continue;
+ }
+
+ if (!!attribute.nodeValue) {
+ pairs.push(attrName + "=\"" + attribute.nodeValue + "\"");
+ }
+ }
+
+ var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
+ var content = element.innerHTML;
+
+ if (content.length > 20) {
+ content = content.substr(0, 20) + "[...]";
+ }
+
+ var res = formatted + pairs.join(" ") + ">" + content + "" + tagName + ">";
+
+ return res.replace(/ contentEditable="inherit"/, "");
+ };
+
+ ascii.constructorName = function (object) {
+ var name = buster.functionName(object && object.constructor);
+ var excludes = this.excludeConstructors || buster.format.excludeConstructors || [];
+
+ for (var i = 0, l = excludes.length; i < l; ++i) {
+ if (typeof excludes[i] == "string" && excludes[i] == name) {
+ return "";
+ } else if (excludes[i].test && excludes[i].test(name)) {
+ return "";
+ }
+ }
+
+ return name;
+ };
+
+ return ascii;
+}());
+
+if (typeof module != "undefined") {
+ module.exports = buster.format;
+}
+/*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
+/*global module, require, __dirname, document*/
+/**
+ * Sinon core utilities. For internal use only.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+var sinon = (function (buster) {
+ var div = typeof document != "undefined" && document.createElement("div");
+ var hasOwn = Object.prototype.hasOwnProperty;
+
+ function isDOMNode(obj) {
+ var success = false;
+
+ try {
+ obj.appendChild(div);
+ success = div.parentNode == obj;
+ } catch (e) {
+ return false;
+ } finally {
+ try {
+ obj.removeChild(div);
+ } catch (e) {
+ // Remove failed, not much we can do about that
+ }
+ }
+
+ return success;
+ }
+
+ function isElement(obj) {
+ return div && obj && obj.nodeType === 1 && isDOMNode(obj);
+ }
+
+ function isFunction(obj) {
+ return !!(obj && obj.constructor && obj.call && obj.apply);
+ }
+
+ function mirrorProperties(target, source) {
+ for (var prop in source) {
+ if (!hasOwn.call(target, prop)) {
+ target[prop] = source[prop];
+ }
+ }
+ }
+
+ var sinon = {
+ wrapMethod: function wrapMethod(object, property, method) {
+ if (!object) {
+ throw new TypeError("Should wrap property of object");
+ }
+
+ if (typeof method != "function") {
+ throw new TypeError("Method wrapper should be function");
+ }
+
+ var wrappedMethod = object[property];
+
+ if (!isFunction(wrappedMethod)) {
+ throw new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
+ property + " as function");
+ }
+
+ if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
+ throw new TypeError("Attempted to wrap " + property + " which is already wrapped");
+ }
+
+ if (wrappedMethod.calledBefore) {
+ var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
+ throw new TypeError("Attempted to wrap " + property + " which is already " + verb);
+ }
+
+ // IE 8 does not support hasOwnProperty on the window object.
+ var owned = hasOwn.call(object, property);
+ object[property] = method;
+ method.displayName = property;
+
+ method.restore = function () {
+ if(owned) {
+ object[property] = wrappedMethod;
+ } else {
+ delete object[property];
+ }
+ };
+
+ method.restore.sinon = true;
+ mirrorProperties(method, wrappedMethod);
+
+ return method;
+ },
+
+ extend: function extend(target) {
+ for (var i = 1, l = arguments.length; i < l; i += 1) {
+ for (var prop in arguments[i]) {
+ if (arguments[i].hasOwnProperty(prop)) {
+ target[prop] = arguments[i][prop];
+ }
+
+ // DONT ENUM bug, only care about toString
+ if (arguments[i].hasOwnProperty("toString") &&
+ arguments[i].toString != target.toString) {
+ target.toString = arguments[i].toString;
+ }
+ }
+ }
+
+ return target;
+ },
+
+ create: function create(proto) {
+ var F = function () {};
+ F.prototype = proto;
+ return new F();
+ },
+
+ deepEqual: function deepEqual(a, b) {
+ if (typeof a != "object" || typeof b != "object") {
+ return a === b;
+ }
+
+ if (isElement(a) || isElement(b)) {
+ return a === b;
+ }
+
+ if (a === b) {
+ return true;
+ }
+
+ var aString = Object.prototype.toString.call(a);
+ if (aString != Object.prototype.toString.call(b)) {
+ return false;
+ }
+
+ if (aString == "[object Array]") {
+ if (a.length !== b.length) {
+ return false;
+ }
+
+ for (var i = 0, l = a.length; i < l; i += 1) {
+ if (!deepEqual(a[i], b[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ var prop, aLength = 0, bLength = 0;
+
+ for (prop in a) {
+ aLength += 1;
+
+ if (!deepEqual(a[prop], b[prop])) {
+ return false;
+ }
+ }
+
+ for (prop in b) {
+ bLength += 1;
+ }
+
+ if (aLength != bLength) {
+ return false;
+ }
+
+ return true;
+ },
+
+ functionName: function functionName(func) {
+ var name = func.displayName || func.name;
+
+ // Use function decomposition as a last resort to get function
+ // name. Does not rely on function decomposition to work - if it
+ // doesn't debugging will be slightly less informative
+ // (i.e. toString will say 'spy' rather than 'myFunc').
+ if (!name) {
+ var matches = func.toString().match(/function ([^\s\(]+)/);
+ name = matches && matches[1];
+ }
+
+ return name;
+ },
+
+ functionToString: function toString() {
+ if (this.getCall && this.callCount) {
+ var thisValue, prop, i = this.callCount;
+
+ while (i--) {
+ thisValue = this.getCall(i).thisValue;
+
+ for (prop in thisValue) {
+ if (thisValue[prop] === this) {
+ return prop;
+ }
+ }
+ }
+ }
+
+ return this.displayName || "sinon fake";
+ },
+
+ getConfig: function (custom) {
+ var config = {};
+ custom = custom || {};
+ var defaults = sinon.defaultConfig;
+
+ for (var prop in defaults) {
+ if (defaults.hasOwnProperty(prop)) {
+ config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
+ }
+ }
+
+ return config;
+ },
+
+ format: function (val) {
+ return "" + val;
+ },
+
+ defaultConfig: {
+ injectIntoThis: true,
+ injectInto: null,
+ properties: ["spy", "stub", "mock", "clock", "server", "requests"],
+ useFakeTimers: true,
+ useFakeServer: true
+ },
+
+ timesInWords: function timesInWords(count) {
+ return count == 1 && "once" ||
+ count == 2 && "twice" ||
+ count == 3 && "thrice" ||
+ (count || 0) + " times";
+ },
+
+ calledInOrder: function (spies) {
+ for (var i = 1, l = spies.length; i < l; i++) {
+ if (!spies[i - 1].calledBefore(spies[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ orderByFirstCall: function (spies) {
+ return spies.sort(function (a, b) {
+ // uuid, won't ever be equal
+ var aCall = a.getCall(0);
+ var bCall = b.getCall(0);
+ var aId = aCall && aCall.callId || -1;
+ var bId = bCall && bCall.callId || -1;
+
+ return aId < bId ? -1 : 1;
+ });
+ },
+
+ log: function () {},
+
+ logError: function (label, err) {
+ var msg = label + " threw exception: "
+ sinon.log(msg + "[" + err.name + "] " + err.message);
+ if (err.stack) { sinon.log(err.stack); }
+
+ setTimeout(function () {
+ err.message = msg + err.message;
+ throw err;
+ }, 0);
+ }
+ };
+
+ var isNode = typeof module == "object" && typeof require == "function";
+
+ if (isNode) {
+ try {
+ buster = { format: require("buster-format") };
+ } catch (e) {}
+ module.exports = sinon;
+ module.exports.spy = require("./sinon/spy");
+ module.exports.stub = require("./sinon/stub");
+ module.exports.mock = require("./sinon/mock");
+ module.exports.collection = require("./sinon/collection");
+ module.exports.assert = require("./sinon/assert");
+ module.exports.sandbox = require("./sinon/sandbox");
+ module.exports.test = require("./sinon/test");
+ module.exports.testCase = require("./sinon/test_case");
+ module.exports.assert = require("./sinon/assert");
+ }
+
+ if (buster) {
+ var formatter = sinon.create(buster.format);
+ formatter.quoteStrings = false;
+ sinon.format = function () {
+ return formatter.ascii.apply(formatter, arguments);
+ };
+ } else if (isNode) {
+ try {
+ var util = require("util");
+ sinon.format = function (value) {
+ return typeof value == "object" ? util.inspect(value) : value;
+ };
+ } catch (e) {
+ /* Node, but no util module - would be very old, but better safe than
+ sorry */
+ }
+ }
+
+ return sinon;
+}(typeof buster == "object" && buster));
+
+/* @depend ../sinon.js */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Spy functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+ var spyCall;
+ var callId = 0;
+ var push = [].push;
+ var slice = Array.prototype.slice;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function spy(object, property) {
+ if (!property && typeof object == "function") {
+ return spy.create(object);
+ }
+
+ if (!object || !property) {
+ return spy.create(function () {});
+ }
+
+ var method = object[property];
+ return sinon.wrapMethod(object, property, spy.create(method));
+ }
+
+ sinon.extend(spy, (function () {
+
+ function delegateToCalls(api, method, matchAny, actual, notCalled) {
+ api[method] = function () {
+ if (!this.called) {
+ if (notCalled) {
+ return notCalled.apply(this, arguments);
+ }
+ return false;
+ }
+
+ var currentCall;
+ var matches = 0;
+
+ for (var i = 0, l = this.callCount; i < l; i += 1) {
+ currentCall = this.getCall(i);
+
+ if (currentCall[actual || method].apply(currentCall, arguments)) {
+ matches += 1;
+
+ if (matchAny) {
+ return true;
+ }
+ }
+ }
+
+ return matches === this.callCount;
+ };
+ }
+
+ function matchingFake(fakes, args, strict) {
+ if (!fakes) {
+ return;
+ }
+
+ var alen = args.length;
+
+ for (var i = 0, l = fakes.length; i < l; i++) {
+ if (fakes[i].matches(args, strict)) {
+ return fakes[i];
+ }
+ }
+ }
+
+ function incrementCallCount() {
+ this.called = true;
+ this.callCount += 1;
+ this.calledOnce = this.callCount == 1;
+ this.calledTwice = this.callCount == 2;
+ this.calledThrice = this.callCount == 3;
+ }
+
+ function createCallProperties() {
+ this.firstCall = this.getCall(0);
+ this.secondCall = this.getCall(1);
+ this.thirdCall = this.getCall(2);
+ this.lastCall = this.getCall(this.callCount - 1);
+ }
+
+ var uuid = 0;
+
+ // Public API
+ var spyApi = {
+ reset: function () {
+ this.called = false;
+ this.calledOnce = false;
+ this.calledTwice = false;
+ this.calledThrice = false;
+ this.callCount = 0;
+ this.firstCall = null;
+ this.secondCall = null;
+ this.thirdCall = null;
+ this.lastCall = null;
+ this.args = [];
+ this.returnValues = [];
+ this.thisValues = [];
+ this.exceptions = [];
+ this.callIds = [];
+ },
+
+ create: function create(func) {
+ var name;
+
+ if (typeof func != "function") {
+ func = function () {};
+ } else {
+ name = sinon.functionName(func);
+ }
+
+ function proxy() {
+ return proxy.invoke(func, this, slice.call(arguments));
+ }
+
+ sinon.extend(proxy, spy);
+ delete proxy.create;
+ sinon.extend(proxy, func);
+
+ proxy.reset();
+ proxy.prototype = func.prototype;
+ proxy.displayName = name || "spy";
+ proxy.toString = sinon.functionToString;
+ proxy._create = sinon.spy.create;
+ proxy.id = "spy#" + uuid++;
+
+ return proxy;
+ },
+
+ invoke: function invoke(func, thisValue, args) {
+ var matching = matchingFake(this.fakes, args);
+ var exception, returnValue;
+
+ incrementCallCount.call(this);
+ push.call(this.thisValues, thisValue);
+ push.call(this.args, args);
+ push.call(this.callIds, callId++);
+
+ try {
+ if (matching) {
+ returnValue = matching.invoke(func, thisValue, args);
+ } else {
+ returnValue = (this.func || func).apply(thisValue, args);
+ }
+ } catch (e) {
+ push.call(this.returnValues, undefined);
+ exception = e;
+ throw e;
+ } finally {
+ push.call(this.exceptions, exception);
+ }
+
+ push.call(this.returnValues, returnValue);
+
+ createCallProperties.call(this);
+
+ return returnValue;
+ },
+
+ getCall: function getCall(i) {
+ if (i < 0 || i >= this.callCount) {
+ return null;
+ }
+
+ return spyCall.create(this, this.thisValues[i], this.args[i],
+ this.returnValues[i], this.exceptions[i],
+ this.callIds[i]);
+ },
+
+ calledBefore: function calledBefore(spyFn) {
+ if (!this.called) {
+ return false;
+ }
+
+ if (!spyFn.called) {
+ return true;
+ }
+
+ return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
+ },
+
+ calledAfter: function calledAfter(spyFn) {
+ if (!this.called || !spyFn.called) {
+ return false;
+ }
+
+ return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
+ },
+
+ withArgs: function () {
+ var args = slice.call(arguments);
+
+ if (this.fakes) {
+ var match = matchingFake(this.fakes, args, true);
+
+ if (match) {
+ return match;
+ }
+ } else {
+ this.fakes = [];
+ }
+
+ var original = this;
+ var fake = this._create();
+ fake.matchingAguments = args;
+ push.call(this.fakes, fake);
+
+ fake.withArgs = function () {
+ return original.withArgs.apply(original, arguments);
+ };
+
+ for (var i = 0; i < this.args.length; i++) {
+ if (fake.matches(this.args[i])) {
+ incrementCallCount.call(fake);
+ push.call(fake.thisValues, this.thisValues[i]);
+ push.call(fake.args, this.args[i]);
+ push.call(fake.returnValues, this.returnValues[i]);
+ push.call(fake.exceptions, this.exceptions[i]);
+ push.call(fake.callIds, this.callIds[i]);
+ }
+ }
+ createCallProperties.call(fake);
+
+ return fake;
+ },
+
+ matches: function (args, strict) {
+ var margs = this.matchingAguments;
+
+ if (margs.length <= args.length &&
+ sinon.deepEqual(margs, args.slice(0, margs.length))) {
+ return !strict || margs.length == args.length;
+ }
+ },
+
+ printf: function (format) {
+ var spy = this;
+ var args = slice.call(arguments, 1);
+ var formatter;
+
+ return (format || "").replace(/%(.)/g, function (match, specifyer) {
+ formatter = spyApi.formatters[specifyer];
+
+ if (typeof formatter == "function") {
+ return formatter.call(null, spy, args);
+ } else if (!isNaN(parseInt(specifyer), 10)) {
+ return sinon.format(args[specifyer - 1]);
+ }
+
+ return "%" + specifyer;
+ });
+ }
+ };
+
+ delegateToCalls(spyApi, "calledOn", true);
+ delegateToCalls(spyApi, "alwaysCalledOn", false, "calledOn");
+ delegateToCalls(spyApi, "calledWith", true);
+ delegateToCalls(spyApi, "alwaysCalledWith", false, "calledWith");
+ delegateToCalls(spyApi, "calledWithExactly", true);
+ delegateToCalls(spyApi, "alwaysCalledWithExactly", false, "calledWithExactly");
+ delegateToCalls(spyApi, "neverCalledWith", false, "notCalledWith",
+ function () { return true; });
+ delegateToCalls(spyApi, "threw", true);
+ delegateToCalls(spyApi, "alwaysThrew", false, "threw");
+ delegateToCalls(spyApi, "returned", true);
+ delegateToCalls(spyApi, "alwaysReturned", false, "returned");
+ delegateToCalls(spyApi, "calledWithNew", true);
+ delegateToCalls(spyApi, "alwaysCalledWithNew", false, "calledWithNew");
+ delegateToCalls(spyApi, "callArg", false, "callArgWith", function () {
+ throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
+ });
+ spyApi.callArgWith = spyApi.callArg;
+ delegateToCalls(spyApi, "yield", false, "yield", function () {
+ throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
+ });
+ // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
+ spyApi.invokeCallback = spyApi.yield;
+ delegateToCalls(spyApi, "yieldTo", false, "yieldTo", function (property) {
+ throw new Error(this.toString() + " cannot yield to '" + property +
+ "' since it was not yet invoked.");
+ });
+
+ spyApi.formatters = {
+ "c": function (spy) {
+ return sinon.timesInWords(spy.callCount);
+ },
+
+ "n": function (spy) {
+ return spy.toString();
+ },
+
+ "C": function (spy) {
+ var calls = [];
+
+ for (var i = 0, l = spy.callCount; i < l; ++i) {
+ push.call(calls, " " + spy.getCall(i).toString());
+ }
+
+ return calls.length > 0 ? "\n" + calls.join("\n") : "";
+ },
+
+ "t": function (spy) {
+ var objects = [];
+
+ for (var i = 0, l = spy.callCount; i < l; ++i) {
+ push.call(objects, sinon.format(spy.thisValues[i]));
+ }
+
+ return objects.join(", ");
+ },
+
+ "*": function (spy, args) {
+ return args.join(", ");
+ }
+ };
+
+ return spyApi;
+ }()));
+
+ spyCall = (function () {
+
+ function throwYieldError(proxy, text, args) {
+ var msg = sinon.functionName(proxy) + text;
+ if (args.length) {
+ msg += " Received [" + slice.call(args).join(", ") + "]";
+ }
+ throw new Error(msg);
+ }
+
+ return {
+ create: function create(spy, thisValue, args, returnValue, exception, id) {
+ var proxyCall = sinon.create(spyCall);
+ delete proxyCall.create;
+ proxyCall.proxy = spy;
+ proxyCall.thisValue = thisValue;
+ proxyCall.args = args;
+ proxyCall.returnValue = returnValue;
+ proxyCall.exception = exception;
+ proxyCall.callId = typeof id == "number" && id || callId++;
+
+ return proxyCall;
+ },
+
+ calledOn: function calledOn(thisValue) {
+ return this.thisValue === thisValue;
+ },
+
+ calledWith: function calledWith() {
+ for (var i = 0, l = arguments.length; i < l; i += 1) {
+ if (!sinon.deepEqual(arguments[i], this.args[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ calledWithExactly: function calledWithExactly() {
+ return arguments.length == this.args.length &&
+ this.calledWith.apply(this, arguments);
+ },
+
+ notCalledWith: function notCalledWith() {
+ for (var i = 0, l = arguments.length; i < l; i += 1) {
+ if (!sinon.deepEqual(arguments[i], this.args[i])) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ returned: function returned(value) {
+ return this.returnValue === value;
+ },
+
+ threw: function threw(error) {
+ if (typeof error == "undefined" || !this.exception) {
+ return !!this.exception;
+ }
+
+ if (typeof error == "string") {
+ return this.exception.name == error;
+ }
+
+ return this.exception === error;
+ },
+
+ calledWithNew: function calledWithNew(thisValue) {
+ return this.thisValue instanceof this.proxy;
+ },
+
+ calledBefore: function (other) {
+ return this.callId < other.callId;
+ },
+
+ calledAfter: function (other) {
+ return this.callId > other.callId;
+ },
+
+ callArg: function (pos) {
+ this.args[pos]();
+ },
+
+ callArgWith: function (pos) {
+ var args = slice.call(arguments, 1);
+ this.args[pos].apply(null, args);
+ },
+
+ "yield": function () {
+ var args = this.args;
+ for (var i = 0, l = args.length; i < l; ++i) {
+ if (typeof args[i] === "function") {
+ args[i].apply(null, slice.call(arguments));
+ return;
+ }
+ }
+ throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
+ },
+
+ yieldTo: function (prop) {
+ var args = this.args;
+ for (var i = 0, l = args.length; i < l; ++i) {
+ if (args[i] && typeof args[i][prop] === "function") {
+ args[i][prop].apply(null, slice.call(arguments, 1));
+ return;
+ }
+ }
+ throwYieldError(this.proxy, " cannot yield to '" + prop +
+ "' since no callback was passed.", args);
+ },
+
+ toString: function () {
+ var callStr = this.proxy.toString() + "(";
+ var args = [];
+
+ for (var i = 0, l = this.args.length; i < l; ++i) {
+ push.call(args, sinon.format(this.args[i]));
+ }
+
+ callStr = callStr + args.join(", ") + ")";
+
+ if (typeof this.returnValue != "undefined") {
+ callStr += " => " + sinon.format(this.returnValue);
+ }
+
+ if (this.exception) {
+ callStr += " !" + this.exception.name;
+
+ if (this.exception.message) {
+ callStr += "(" + this.exception.message + ")";
+ }
+ }
+
+ return callStr;
+ }
+ };
+ }());
+
+ spy.spyCall = spyCall;
+
+ // This steps outside the module sandbox and will be removed
+ sinon.spyCall = spyCall;
+
+ if (commonJSModule) {
+ module.exports = spy;
+ } else {
+ sinon.spy = spy;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend spy.js
+ */
+/*jslint eqeqeq: false, onevar: false*/
+/*global module, require, sinon*/
+/**
+ * Stub functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function stub(object, property, func) {
+ if (!!func && typeof func != "function") {
+ throw new TypeError("Custom stub should be function");
+ }
+
+ var wrapper;
+
+ if (func) {
+ wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
+ } else {
+ wrapper = stub.create();
+ }
+
+ if (!object && !property) {
+ return sinon.stub.create();
+ }
+
+ if (!property && !!object && typeof object == "object") {
+ for (var prop in object) {
+ if (typeof object[prop] === "function") {
+ stub(object, prop);
+ }
+ }
+
+ return object;
+ }
+
+ return sinon.wrapMethod(object, property, wrapper);
+ }
+
+ function getCallback(stub, args) {
+ if (stub.callArgAt < 0) {
+ for (var i = 0, l = args.length; i < l; ++i) {
+ if (!stub.callArgProp && typeof args[i] == "function") {
+ return args[i];
+ }
+
+ if (stub.callArgProp && args[i] &&
+ typeof args[i][stub.callArgProp] == "function") {
+ return args[i][stub.callArgProp];
+ }
+ }
+
+ return null;
+ }
+
+ return args[stub.callArgAt];
+ }
+
+ var join = Array.prototype.join;
+
+ function getCallbackError(stub, func, args) {
+ if (stub.callArgAt < 0) {
+ var msg;
+
+ if (stub.callArgProp) {
+ msg = sinon.functionName(stub) +
+ " expected to yield to '" + stub.callArgProp +
+ "', but no object with such a property was passed."
+ } else {
+ msg = sinon.functionName(stub) +
+ " expected to yield, but no callback was passed."
+ }
+
+ if (args.length > 0) {
+ msg += " Received [" + join.call(args, ", ") + "]";
+ }
+
+ return msg;
+ }
+
+ return "argument at index " + stub.callArgAt + " is not a function: " + func;
+ }
+
+ function callCallback(stub, args) {
+ if (typeof stub.callArgAt == "number") {
+ var func = getCallback(stub, args);
+
+ if (typeof func != "function") {
+ throw new TypeError(getCallbackError(stub, func, args));
+ }
+
+ func.apply(stub.callbackContext, stub.callbackArguments);
+ }
+ }
+
+ var uuid = 0;
+
+ sinon.extend(stub, (function () {
+ var slice = Array.prototype.slice;
+
+ function throwsException(error, message) {
+ if (typeof error == "string") {
+ this.exception = new Error(message || "");
+ this.exception.name = error;
+ } else if (!error) {
+ this.exception = new Error("Error");
+ } else {
+ this.exception = error;
+ }
+
+ return this;
+ }
+
+ return {
+ create: function create() {
+ var functionStub = function () {
+ if (functionStub.exception) {
+ throw functionStub.exception;
+ } else if (typeof functionStub.returnArgAt == 'number') {
+ return arguments[functionStub.returnArgAt];
+ }
+
+ callCallback(functionStub, arguments);
+
+ return functionStub.returnValue;
+ };
+
+ functionStub.id = "stub#" + uuid++;
+ var orig = functionStub;
+ functionStub = sinon.spy.create(functionStub);
+ functionStub.func = orig;
+
+ sinon.extend(functionStub, stub);
+ functionStub._create = sinon.stub.create;
+ functionStub.displayName = "stub";
+ functionStub.toString = sinon.functionToString;
+
+ return functionStub;
+ },
+
+ returns: function returns(value) {
+ this.returnValue = value;
+
+ return this;
+ },
+
+ returnsArg: function returnsArg(pos) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ this.returnArgAt = pos;
+
+ return this;
+ },
+
+ "throws": throwsException,
+ throwsException: throwsException,
+
+ callsArg: function callsArg(pos) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ this.callArgAt = pos;
+ this.callbackArguments = [];
+
+ return this;
+ },
+
+ callsArgOn: function callsArgOn(pos, context) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAt = pos;
+ this.callbackArguments = [];
+ this.callbackContext = context;
+
+ return this;
+ },
+
+ callsArgWith: function callsArgWith(pos) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ this.callArgAt = pos;
+ this.callbackArguments = slice.call(arguments, 1);
+
+ return this;
+ },
+
+ callsArgOnWith: function callsArgWith(pos, context) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAt = pos;
+ this.callbackArguments = slice.call(arguments, 2);
+ this.callbackContext = context;
+
+ return this;
+ },
+
+ yields: function () {
+ this.callArgAt = -1;
+ this.callbackArguments = slice.call(arguments, 0);
+
+ return this;
+ },
+
+ yieldsOn: function (context) {
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAt = -1;
+ this.callbackArguments = slice.call(arguments, 1);
+ this.callbackContext = context;
+
+ return this;
+ },
+
+ yieldsTo: function (prop) {
+ this.callArgAt = -1;
+ this.callArgProp = prop;
+ this.callbackArguments = slice.call(arguments, 1);
+
+ return this;
+ },
+
+ yieldsToOn: function (prop, context) {
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAt = -1;
+ this.callArgProp = prop;
+ this.callbackArguments = slice.call(arguments, 2);
+ this.callbackContext = context;
+
+ return this;
+ }
+ };
+ }()));
+
+ if (commonJSModule) {
+ module.exports = stub;
+ } else {
+ sinon.stub = stub;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ */
+/*jslint eqeqeq: false, onevar: false, nomen: false*/
+/*global module, require, sinon*/
+/**
+ * Mock functions.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+ var push = [].push;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function mock(object) {
+ if (!object) {
+ return sinon.expectation.create("Anonymous mock");
+ }
+
+ return mock.create(object);
+ }
+
+ sinon.mock = mock;
+
+ sinon.extend(mock, (function () {
+ function each(collection, callback) {
+ if (!collection) {
+ return;
+ }
+
+ for (var i = 0, l = collection.length; i < l; i += 1) {
+ callback(collection[i]);
+ }
+ }
+
+ return {
+ create: function create(object) {
+ if (!object) {
+ throw new TypeError("object is null");
+ }
+
+ var mockObject = sinon.extend({}, mock);
+ mockObject.object = object;
+ delete mockObject.create;
+
+ return mockObject;
+ },
+
+ expects: function expects(method) {
+ if (!method) {
+ throw new TypeError("method is falsy");
+ }
+
+ if (!this.expectations) {
+ this.expectations = {};
+ this.proxies = [];
+ }
+
+ if (!this.expectations[method]) {
+ this.expectations[method] = [];
+ var mockObject = this;
+
+ sinon.wrapMethod(this.object, method, function () {
+ return mockObject.invokeMethod(method, this, arguments);
+ });
+
+ push.call(this.proxies, method);
+ }
+
+ var expectation = sinon.expectation.create(method);
+ push.call(this.expectations[method], expectation);
+
+ return expectation;
+ },
+
+ restore: function restore() {
+ var object = this.object;
+
+ each(this.proxies, function (proxy) {
+ if (typeof object[proxy].restore == "function") {
+ object[proxy].restore();
+ }
+ });
+ },
+
+ verify: function verify() {
+ var expectations = this.expectations || {};
+ var messages = [], met = [];
+
+ each(this.proxies, function (proxy) {
+ each(expectations[proxy], function (expectation) {
+ if (!expectation.met()) {
+ push.call(messages, expectation.toString());
+ } else {
+ push.call(met, expectation.toString());
+ }
+ });
+ });
+
+ this.restore();
+
+ if (messages.length > 0) {
+ sinon.expectation.fail(messages.concat(met).join("\n"));
+ }
+
+ return true;
+ },
+
+ invokeMethod: function invokeMethod(method, thisValue, args) {
+ var expectations = this.expectations && this.expectations[method];
+ var length = expectations && expectations.length || 0;
+
+ for (var i = 0; i < length; i += 1) {
+ if (!expectations[i].met() &&
+ expectations[i].allowsCall(thisValue, args)) {
+ return expectations[i].apply(thisValue, args);
+ }
+ }
+
+ var messages = [];
+
+ for (i = 0; i < length; i += 1) {
+ push.call(messages, " " + expectations[i].toString());
+ }
+
+ messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
+ proxy: method,
+ args: args
+ }));
+
+ sinon.expectation.fail(messages.join("\n"));
+ }
+ };
+ }()));
+
+ var times = sinon.timesInWords;
+
+ sinon.expectation = (function () {
+ var slice = Array.prototype.slice;
+ var _invoke = sinon.spy.invoke;
+
+ function callCountInWords(callCount) {
+ if (callCount == 0) {
+ return "never called";
+ } else {
+ return "called " + times(callCount);
+ }
+ }
+
+ function expectedCallCountInWords(expectation) {
+ var min = expectation.minCalls;
+ var max = expectation.maxCalls;
+
+ if (typeof min == "number" && typeof max == "number") {
+ var str = times(min);
+
+ if (min != max) {
+ str = "at least " + str + " and at most " + times(max);
+ }
+
+ return str;
+ }
+
+ if (typeof min == "number") {
+ return "at least " + times(min);
+ }
+
+ return "at most " + times(max);
+ }
+
+ function receivedMinCalls(expectation) {
+ var hasMinLimit = typeof expectation.minCalls == "number";
+ return !hasMinLimit || expectation.callCount >= expectation.minCalls;
+ }
+
+ function receivedMaxCalls(expectation) {
+ if (typeof expectation.maxCalls != "number") {
+ return false;
+ }
+
+ return expectation.callCount == expectation.maxCalls;
+ }
+
+ return {
+ minCalls: 1,
+ maxCalls: 1,
+
+ create: function create(methodName) {
+ var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
+ delete expectation.create;
+ expectation.method = methodName;
+
+ return expectation;
+ },
+
+ invoke: function invoke(func, thisValue, args) {
+ this.verifyCallAllowed(thisValue, args);
+
+ return _invoke.apply(this, arguments);
+ },
+
+ atLeast: function atLeast(num) {
+ if (typeof num != "number") {
+ throw new TypeError("'" + num + "' is not number");
+ }
+
+ if (!this.limitsSet) {
+ this.maxCalls = null;
+ this.limitsSet = true;
+ }
+
+ this.minCalls = num;
+
+ return this;
+ },
+
+ atMost: function atMost(num) {
+ if (typeof num != "number") {
+ throw new TypeError("'" + num + "' is not number");
+ }
+
+ if (!this.limitsSet) {
+ this.minCalls = null;
+ this.limitsSet = true;
+ }
+
+ this.maxCalls = num;
+
+ return this;
+ },
+
+ never: function never() {
+ return this.exactly(0);
+ },
+
+ once: function once() {
+ return this.exactly(1);
+ },
+
+ twice: function twice() {
+ return this.exactly(2);
+ },
+
+ thrice: function thrice() {
+ return this.exactly(3);
+ },
+
+ exactly: function exactly(num) {
+ if (typeof num != "number") {
+ throw new TypeError("'" + num + "' is not a number");
+ }
+
+ this.atLeast(num);
+ return this.atMost(num);
+ },
+
+ met: function met() {
+ return !this.failed && receivedMinCalls(this);
+ },
+
+ verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
+ if (receivedMaxCalls(this)) {
+ this.failed = true;
+ sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
+ }
+
+ if ("expectedThis" in this && this.expectedThis !== thisValue) {
+ sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
+ this.expectedThis);
+ }
+
+ if (!("expectedArguments" in this)) {
+ return;
+ }
+
+ if (!args || args.length === 0) {
+ sinon.expectation.fail(this.method + " received no arguments, expected " +
+ this.expectedArguments.join());
+ }
+
+ if (args.length < this.expectedArguments.length) {
+ sinon.expectation.fail(this.method + " received too few arguments (" + args.join() +
+ "), expected " + this.expectedArguments.join());
+ }
+
+ if (this.expectsExactArgCount &&
+ args.length != this.expectedArguments.length) {
+ sinon.expectation.fail(this.method + " received too many arguments (" + args.join() +
+ "), expected " + this.expectedArguments.join());
+ }
+
+ for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
+ if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
+ sinon.expectation.fail(this.method + " received wrong arguments (" + args.join() +
+ "), expected " + this.expectedArguments.join());
+ }
+ }
+ },
+
+ allowsCall: function allowsCall(thisValue, args) {
+ if (this.met()) {
+ return false;
+ }
+
+ if ("expectedThis" in this && this.expectedThis !== thisValue) {
+ return false;
+ }
+
+ if (!("expectedArguments" in this)) {
+ return true;
+ }
+
+ args = args || [];
+
+ if (args.length < this.expectedArguments.length) {
+ return false;
+ }
+
+ if (this.expectsExactArgCount &&
+ args.length != this.expectedArguments.length) {
+ return false;
+ }
+
+ for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
+ if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ withArgs: function withArgs() {
+ this.expectedArguments = slice.call(arguments);
+ return this;
+ },
+
+ withExactArgs: function withExactArgs() {
+ this.withArgs.apply(this, arguments);
+ this.expectsExactArgCount = true;
+ return this;
+ },
+
+ on: function on(thisValue) {
+ this.expectedThis = thisValue;
+ return this;
+ },
+
+ toString: function () {
+ var args = (this.expectedArguments || []).slice();
+
+ if (!this.expectsExactArgCount) {
+ push.call(args, "[...]");
+ }
+
+ var callStr = sinon.spyCall.toString.call({
+ proxy: this.method, args: args
+ });
+
+ var message = callStr.replace(", [...", "[, ...") + " " +
+ expectedCallCountInWords(this);
+
+ if (this.met()) {
+ return "Expectation met: " + message;
+ }
+
+ return "Expected " + message + " (" +
+ callCountInWords(this.callCount) + ")";
+ },
+
+ verify: function verify() {
+ if (!this.met()) {
+ sinon.expectation.fail(this.toString());
+ }
+
+ return true;
+ },
+
+ fail: function (message) {
+ var exception = new Error(message);
+ exception.name = "ExpectationError";
+
+ throw exception;
+ }
+ };
+ }());
+
+ if (commonJSModule) {
+ module.exports = mock;
+ } else {
+ sinon.mock = mock;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ * @depend mock.js
+ */
+/*jslint eqeqeq: false, onevar: false, forin: true*/
+/*global module, require, sinon*/
+/**
+ * Collections of stubs, spies and mocks.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+ var push = [].push;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function getFakes(fakeCollection) {
+ if (!fakeCollection.fakes) {
+ fakeCollection.fakes = [];
+ }
+
+ return fakeCollection.fakes;
+ }
+
+ function each(fakeCollection, method) {
+ var fakes = getFakes(fakeCollection);
+
+ for (var i = 0, l = fakes.length; i < l; i += 1) {
+ if (typeof fakes[i][method] == "function") {
+ fakes[i][method]();
+ }
+ }
+ }
+
+ function compact(fakeCollection) {
+ var fakes = getFakes(fakeCollection);
+ var i = 0;
+ while (i < fakes.length) {
+ fakes.splice(i, 1);
+ }
+ }
+
+ var collection = {
+ verify: function resolve() {
+ each(this, "verify");
+ },
+
+ restore: function restore() {
+ each(this, "restore");
+ compact(this);
+ },
+
+ verifyAndRestore: function verifyAndRestore() {
+ var exception;
+
+ try {
+ this.verify();
+ } catch (e) {
+ exception = e;
+ }
+
+ this.restore();
+
+ if (exception) {
+ throw exception;
+ }
+ },
+
+ add: function add(fake) {
+ push.call(getFakes(this), fake);
+ return fake;
+ },
+
+ spy: function spy() {
+ return this.add(sinon.spy.apply(sinon, arguments));
+ },
+
+ stub: function stub(object, property, value) {
+ if (property) {
+ var original = object[property];
+
+ if (typeof original != "function") {
+ if (!object.hasOwnProperty(property)) {
+ throw new TypeError("Cannot stub non-existent own property " + property);
+ }
+
+ object[property] = value;
+
+ return this.add({
+ restore: function () {
+ object[property] = original;
+ }
+ });
+ }
+ }
+
+ return this.add(sinon.stub.apply(sinon, arguments));
+ },
+
+ mock: function mock() {
+ return this.add(sinon.mock.apply(sinon, arguments));
+ },
+
+ inject: function inject(obj) {
+ var col = this;
+
+ obj.spy = function () {
+ return col.spy.apply(col, arguments);
+ };
+
+ obj.stub = function () {
+ return col.stub.apply(col, arguments);
+ };
+
+ obj.mock = function () {
+ return col.mock.apply(col, arguments);
+ };
+
+ return obj;
+ }
+ };
+
+ if (commonJSModule) {
+ module.exports = collection;
+ } else {
+ sinon.collection = collection;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
+/*global module, require, window*/
+/**
+ * Fake timer API
+ * setTimeout
+ * setInterval
+ * clearTimeout
+ * clearInterval
+ * tick
+ * reset
+ * Date
+ *
+ * Inspired by jsUnitMockTimeOut from JsUnit
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ var sinon = {};
+}
+
+(function (global) {
+ var id = 1;
+
+ function addTimer(args, recurring) {
+ if (args.length === 0) {
+ throw new Error("Function requires at least 1 parameter");
+ }
+
+ var toId = id++;
+ var delay = args[1] || 0;
+
+ if (!this.timeouts) {
+ this.timeouts = {};
+ }
+
+ this.timeouts[toId] = {
+ id: toId,
+ func: args[0],
+ callAt: this.now + delay
+ };
+
+ if (recurring === true) {
+ this.timeouts[toId].interval = delay;
+ }
+
+ return toId;
+ }
+
+ function parseTime(str) {
+ if (!str) {
+ return 0;
+ }
+
+ var strings = str.split(":");
+ var l = strings.length, i = l;
+ var ms = 0, parsed;
+
+ if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
+ throw new Error("tick only understands numbers and 'h:m:s'");
+ }
+
+ while (i--) {
+ parsed = parseInt(strings[i], 10);
+
+ if (parsed >= 60) {
+ throw new Error("Invalid time " + str);
+ }
+
+ ms += parsed * Math.pow(60, (l - i - 1));
+ }
+
+ return ms * 1000;
+ }
+
+ function createObject(object) {
+ var newObject;
+
+ if (Object.create) {
+ newObject = Object.create(object);
+ } else {
+ var F = function () {};
+ F.prototype = object;
+ newObject = new F();
+ }
+
+ newObject.Date.clock = newObject;
+ return newObject;
+ }
+
+ sinon.clock = {
+ now: 0,
+
+ create: function create(now) {
+ var clock = createObject(this);
+
+ if (typeof now == "number") {
+ clock.now = now;
+ }
+
+ if (!!now && typeof now == "object") {
+ throw new TypeError("now should be milliseconds since UNIX epoch");
+ }
+
+ return clock;
+ },
+
+ setTimeout: function setTimeout(callback, timeout) {
+ return addTimer.call(this, arguments, false);
+ },
+
+ clearTimeout: function clearTimeout(timerId) {
+ if (!this.timeouts) {
+ this.timeouts = [];
+ }
+
+ if (timerId in this.timeouts) {
+ delete this.timeouts[timerId];
+ }
+ },
+
+ setInterval: function setInterval(callback, timeout) {
+ return addTimer.call(this, arguments, true);
+ },
+
+ clearInterval: function clearInterval(timerId) {
+ this.clearTimeout(timerId);
+ },
+
+ tick: function tick(ms) {
+ ms = typeof ms == "number" ? ms : parseTime(ms);
+ var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
+ var timer = this.firstTimerInRange(tickFrom, tickTo);
+
+ var firstException;
+ while (timer && tickFrom <= tickTo) {
+ if (this.timeouts[timer.id]) {
+ tickFrom = this.now = timer.callAt;
+ try {
+ this.callTimer(timer);
+ } catch (e) {
+ firstException = firstException || e;
+ }
+ }
+
+ timer = this.firstTimerInRange(previous, tickTo);
+ previous = tickFrom;
+ }
+
+ this.now = tickTo;
+
+ if (firstException) {
+ throw firstException;
+ }
+ },
+
+ firstTimerInRange: function (from, to) {
+ var timer, smallest, originalTimer;
+
+ for (var id in this.timeouts) {
+ if (this.timeouts.hasOwnProperty(id)) {
+ if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
+ continue;
+ }
+
+ if (!smallest || this.timeouts[id].callAt < smallest) {
+ originalTimer = this.timeouts[id];
+ smallest = this.timeouts[id].callAt;
+
+ timer = {
+ func: this.timeouts[id].func,
+ callAt: this.timeouts[id].callAt,
+ interval: this.timeouts[id].interval,
+ id: this.timeouts[id].id
+ };
+ }
+ }
+ }
+
+ return timer || null;
+ },
+
+ callTimer: function (timer) {
+ try {
+ if (typeof timer.func == "function") {
+ timer.func.call(null);
+ } else {
+ eval(timer.func);
+ }
+ } catch (e) {
+ var exception = e;
+ }
+
+ if (!this.timeouts[timer.id]) {
+ if (exception) {
+ throw exception;
+ }
+ return;
+ }
+
+ if (typeof timer.interval == "number") {
+ this.timeouts[timer.id].callAt += timer.interval;
+ } else {
+ delete this.timeouts[timer.id];
+ }
+
+ if (exception) {
+ throw exception;
+ }
+ },
+
+ reset: function reset() {
+ this.timeouts = {};
+ },
+
+ Date: (function () {
+ var NativeDate = Date;
+
+ function ClockDate(year, month, date, hour, minute, second, ms) {
+ // Defensive and verbose to avoid potential harm in passing
+ // explicit undefined when user does not pass argument
+ switch (arguments.length) {
+ case 0:
+ return new NativeDate(ClockDate.clock.now);
+ case 1:
+ return new NativeDate(year);
+ case 2:
+ return new NativeDate(year, month);
+ case 3:
+ return new NativeDate(year, month, date);
+ case 4:
+ return new NativeDate(year, month, date, hour);
+ case 5:
+ return new NativeDate(year, month, date, hour, minute);
+ case 6:
+ return new NativeDate(year, month, date, hour, minute, second);
+ default:
+ return new NativeDate(year, month, date, hour, minute, second, ms);
+ }
+ }
+
+ return mirrorDateProperties(ClockDate, NativeDate);
+ }())
+ };
+
+ function mirrorDateProperties(target, source) {
+ if (source.now) {
+ target.now = function now() {
+ return target.clock.now;
+ };
+ } else {
+ delete target.now;
+ }
+
+ if (source.toSource) {
+ target.toSource = function toSource() {
+ return source.toSource();
+ };
+ } else {
+ delete target.toSource;
+ }
+
+ target.toString = function toString() {
+ return source.toString();
+ };
+
+ target.prototype = source.prototype;
+ target.parse = source.parse;
+ target.UTC = source.UTC;
+ target.prototype.toUTCString = source.prototype.toUTCString;
+ return target;
+ }
+
+ var methods = ["Date", "setTimeout", "setInterval",
+ "clearTimeout", "clearInterval"];
+
+ function restore() {
+ var method;
+
+ for (var i = 0, l = this.methods.length; i < l; i++) {
+ method = this.methods[i];
+ global[method] = this["_" + method];
+ }
+ }
+
+ function stubGlobal(method, clock) {
+ clock["_" + method] = global[method];
+
+ if (method == "Date") {
+ var date = mirrorDateProperties(clock[method], global[method]);
+ global[method] = date;
+ } else {
+ global[method] = function () {
+ return clock[method].apply(clock, arguments);
+ };
+
+ for (var prop in clock[method]) {
+ if (clock[method].hasOwnProperty(prop)) {
+ global[method][prop] = clock[method][prop];
+ }
+ }
+ }
+
+ global[method].clock = clock;
+ }
+
+ sinon.useFakeTimers = function useFakeTimers(now) {
+ var clock = sinon.clock.create(now);
+ clock.restore = restore;
+ clock.methods = Array.prototype.slice.call(arguments,
+ typeof now == "number" ? 1 : 0);
+
+ if (clock.methods.length === 0) {
+ clock.methods = methods;
+ }
+
+ for (var i = 0, l = clock.methods.length; i < l; i++) {
+ stubGlobal(clock.methods[i], clock);
+ }
+
+ return clock;
+ };
+}(typeof global != "undefined" && typeof global !== "function" ? global : this));
+
+sinon.timers = {
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ setInterval: setInterval,
+ clearInterval: clearInterval,
+ Date: Date
+};
+
+if (typeof module == "object" && typeof require == "function") {
+ module.exports = sinon;
+}
+
+/*jslint eqeqeq: false, onevar: false*/
+/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
+/**
+ * Minimal Event interface implementation
+ *
+ * Original implementation by Sven Fuchs: https://gist.github.com/995028
+ * Modifications and tests by Christian Johansen.
+ *
+ * @author Sven Fuchs (svenfuchs@artweb-design.de)
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2011 Sven Fuchs, Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ this.sinon = {};
+}
+
+(function () {
+ var push = [].push;
+
+ sinon.Event = function Event(type, bubbles, cancelable) {
+ this.initEvent(type, bubbles, cancelable);
+ };
+
+ sinon.Event.prototype = {
+ initEvent: function(type, bubbles, cancelable) {
+ this.type = type;
+ this.bubbles = bubbles;
+ this.cancelable = cancelable;
+ },
+
+ stopPropagation: function () {},
+
+ preventDefault: function () {
+ this.defaultPrevented = true;
+ }
+ };
+
+ sinon.EventTarget = {
+ addEventListener: function addEventListener(event, listener, useCapture) {
+ this.eventListeners = this.eventListeners || {};
+ this.eventListeners[event] = this.eventListeners[event] || [];
+ push.call(this.eventListeners[event], listener);
+ },
+
+ removeEventListener: function removeEventListener(event, listener, useCapture) {
+ var listeners = this.eventListeners && this.eventListeners[event] || [];
+
+ for (var i = 0, l = listeners.length; i < l; ++i) {
+ if (listeners[i] == listener) {
+ return listeners.splice(i, 1);
+ }
+ }
+ },
+
+ dispatchEvent: function dispatchEvent(event) {
+ var type = event.type;
+ var listeners = this.eventListeners && this.eventListeners[type] || [];
+
+ for (var i = 0; i < listeners.length; i++) {
+ if (typeof listeners[i] == "function") {
+ listeners[i].call(this, event);
+ } else {
+ listeners[i].handleEvent(event);
+ }
+ }
+
+ return !!event.defaultPrevented;
+ }
+ };
+}());
+
+/**
+ * @depend event.js
+ */
+/*jslint eqeqeq: false, onevar: false*/
+/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
+/**
+ * Fake XMLHttpRequest object
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ this.sinon = {};
+}
+sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
+
+// wrapper for global
+(function(global) {
+ var xhr = sinon.xhr;
+ xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
+ xhr.GlobalActiveXObject = global.ActiveXObject;
+ xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined";
+ xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
+ xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
+ ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
+
+ /*jsl:ignore*/
+ var unsafeHeaders = {
+ "Accept-Charset": true,
+ "Accept-Encoding": true,
+ "Connection": true,
+ "Content-Length": true,
+ "Cookie": true,
+ "Cookie2": true,
+ "Content-Transfer-Encoding": true,
+ "Date": true,
+ "Expect": true,
+ "Host": true,
+ "Keep-Alive": true,
+ "Referer": true,
+ "TE": true,
+ "Trailer": true,
+ "Transfer-Encoding": true,
+ "Upgrade": true,
+ "User-Agent": true,
+ "Via": true
+ };
+ /*jsl:end*/
+
+ function FakeXMLHttpRequest() {
+ this.readyState = FakeXMLHttpRequest.UNSENT;
+ this.requestHeaders = {};
+ this.requestBody = null;
+ this.status = 0;
+ this.statusText = "";
+
+ if (typeof FakeXMLHttpRequest.onCreate == "function") {
+ FakeXMLHttpRequest.onCreate(this);
+ }
+ }
+
+ function verifyState(xhr) {
+ if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
+ throw new Error("INVALID_STATE_ERR");
+ }
+
+ if (xhr.sendFlag) {
+ throw new Error("INVALID_STATE_ERR");
+ }
+ }
+
+ // filtering to enable a white-list version of Sinon FakeXhr,
+ // where whitelisted requests are passed through to real XHR
+ function each(collection, callback) {
+ if (!collection) return;
+ for (var i = 0, l = collection.length; i < l; i += 1) {
+ callback(collection[i]);
+ }
+ }
+ function some(collection, callback) {
+ for (var index = 0; index < collection.length; index++) {
+ if(callback(collection[index]) === true) return true;
+ };
+ return false;
+ }
+ // largest arity in XHR is 5 - XHR#open
+ var apply = function(obj,method,args) {
+ switch(args.length) {
+ case 0: return obj[method]();
+ case 1: return obj[method](args[0]);
+ case 2: return obj[method](args[0],args[1]);
+ case 3: return obj[method](args[0],args[1],args[2]);
+ case 4: return obj[method](args[0],args[1],args[2],args[3]);
+ case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
+ };
+ };
+
+ FakeXMLHttpRequest.filters = [];
+ FakeXMLHttpRequest.addFilter = function(fn) {
+ this.filters.push(fn)
+ };
+ var IE6Re = /MSIE 6/;
+ FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {
+ var xhr = new sinon.xhr.workingXHR();
+ each(["open","setRequestHeader","send","abort","getResponseHeader",
+ "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"],
+ function(method) {
+ fakeXhr[method] = function() {
+ return apply(xhr,method,arguments);
+ };
+ });
+
+ var copyAttrs = function(args) {
+ each(args, function(attr) {
+ try {
+ fakeXhr[attr] = xhr[attr]
+ } catch(e) {
+ if(!IE6Re.test(navigator.userAgent)) throw e;
+ }
+ });
+ };
+
+ var stateChange = function() {
+ fakeXhr.readyState = xhr.readyState;
+ if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ copyAttrs(["status","statusText"]);
+ }
+ if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {
+ copyAttrs(["responseText"]);
+ }
+ if(xhr.readyState === FakeXMLHttpRequest.DONE) {
+ copyAttrs(["responseXML"]);
+ }
+ if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr);
+ };
+ if(xhr.addEventListener) {
+ for(var event in fakeXhr.eventListeners) {
+ if(fakeXhr.eventListeners.hasOwnProperty(event)) {
+ each(fakeXhr.eventListeners[event],function(handler) {
+ xhr.addEventListener(event, handler);
+ });
+ }
+ }
+ xhr.addEventListener("readystatechange",stateChange);
+ } else {
+ xhr.onreadystatechange = stateChange;
+ }
+ apply(xhr,"open",xhrArgs);
+ };
+ FakeXMLHttpRequest.useFilters = false;
+
+ function verifyRequestSent(xhr) {
+ if (xhr.readyState == FakeXMLHttpRequest.DONE) {
+ throw new Error("Request done");
+ }
+ }
+
+ function verifyHeadersReceived(xhr) {
+ if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ throw new Error("No headers received");
+ }
+ }
+
+ function verifyResponseBodyType(body) {
+ if (typeof body != "string") {
+ var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
+ body + ", which is not a string.");
+ error.name = "InvalidBodyException";
+ throw error;
+ }
+ }
+
+ sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
+ async: true,
+
+ open: function open(method, url, async, username, password) {
+ this.method = method;
+ this.url = url;
+ this.async = typeof async == "boolean" ? async : true;
+ this.username = username;
+ this.password = password;
+ this.responseText = null;
+ this.responseXML = null;
+ this.requestHeaders = {};
+ this.sendFlag = false;
+ if(sinon.FakeXMLHttpRequest.useFilters === true) {
+ var xhrArgs = arguments;
+ var defake = some(FakeXMLHttpRequest.filters,function(filter) {
+ return filter.apply(this,xhrArgs)
+ });
+ if (defake) {
+ return sinon.FakeXMLHttpRequest.defake(this,arguments);
+ }
+ }
+ this.readyStateChange(FakeXMLHttpRequest.OPENED);
+ },
+
+ readyStateChange: function readyStateChange(state) {
+ this.readyState = state;
+
+ if (typeof this.onreadystatechange == "function") {
+ try {
+ this.onreadystatechange();
+ } catch (e) {
+ sinon.logError("Fake XHR onreadystatechange handler", e);
+ }
+ }
+
+ this.dispatchEvent(new sinon.Event("readystatechange"));
+ },
+
+ setRequestHeader: function setRequestHeader(header, value) {
+ verifyState(this);
+
+ if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
+ throw new Error("Refused to set unsafe header \"" + header + "\"");
+ }
+
+ if (this.requestHeaders[header]) {
+ this.requestHeaders[header] += "," + value;
+ } else {
+ this.requestHeaders[header] = value;
+ }
+ },
+
+ // Helps testing
+ setResponseHeaders: function setResponseHeaders(headers) {
+ this.responseHeaders = {};
+
+ for (var header in headers) {
+ if (headers.hasOwnProperty(header)) {
+ this.responseHeaders[header] = headers[header];
+ }
+ }
+
+ if (this.async) {
+ this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
+ }
+ },
+
+ // Currently treats ALL data as a DOMString (i.e. no Document)
+ send: function send(data) {
+ verifyState(this);
+
+ if (!/^(get|head)$/i.test(this.method)) {
+ if (this.requestHeaders["Content-Type"]) {
+ var value = this.requestHeaders["Content-Type"].split(";");
+ this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
+ } else {
+ this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
+ }
+
+ this.requestBody = data;
+ }
+
+ this.errorFlag = false;
+ this.sendFlag = this.async;
+ this.readyStateChange(FakeXMLHttpRequest.OPENED);
+
+ if (typeof this.onSend == "function") {
+ this.onSend(this);
+ }
+ },
+
+ abort: function abort() {
+ this.aborted = true;
+ this.responseText = null;
+ this.errorFlag = true;
+ this.requestHeaders = {};
+
+ if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
+ this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
+ this.sendFlag = false;
+ }
+
+ this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
+ },
+
+ getResponseHeader: function getResponseHeader(header) {
+ if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ return null;
+ }
+
+ if (/^Set-Cookie2?$/i.test(header)) {
+ return null;
+ }
+
+ header = header.toLowerCase();
+
+ for (var h in this.responseHeaders) {
+ if (h.toLowerCase() == header) {
+ return this.responseHeaders[h];
+ }
+ }
+
+ return null;
+ },
+
+ getAllResponseHeaders: function getAllResponseHeaders() {
+ if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ return "";
+ }
+
+ var headers = "";
+
+ for (var header in this.responseHeaders) {
+ if (this.responseHeaders.hasOwnProperty(header) &&
+ !/^Set-Cookie2?$/i.test(header)) {
+ headers += header + ": " + this.responseHeaders[header] + "\r\n";
+ }
+ }
+
+ return headers;
+ },
+
+ setResponseBody: function setResponseBody(body) {
+ verifyRequestSent(this);
+ verifyHeadersReceived(this);
+ verifyResponseBodyType(body);
+
+ var chunkSize = this.chunkSize || 10;
+ var index = 0;
+ this.responseText = "";
+
+ do {
+ if (this.async) {
+ this.readyStateChange(FakeXMLHttpRequest.LOADING);
+ }
+
+ this.responseText += body.substring(index, index + chunkSize);
+ index += chunkSize;
+ } while (index < body.length);
+
+ var type = this.getResponseHeader("Content-Type");
+
+ if (this.responseText &&
+ (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
+ try {
+ this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
+ } catch (e) {
+ // Unable to parse XML - no biggie
+ }
+ }
+
+ if (this.async) {
+ this.readyStateChange(FakeXMLHttpRequest.DONE);
+ } else {
+ this.readyState = FakeXMLHttpRequest.DONE;
+ }
+ },
+
+ respond: function respond(status, headers, body) {
+ this.setResponseHeaders(headers || {});
+ this.status = typeof status == "number" ? status : 200;
+ this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
+ this.setResponseBody(body || "");
+ }
+ });
+
+ sinon.extend(FakeXMLHttpRequest, {
+ UNSENT: 0,
+ OPENED: 1,
+ HEADERS_RECEIVED: 2,
+ LOADING: 3,
+ DONE: 4
+ });
+
+ // Borrowed from JSpec
+ FakeXMLHttpRequest.parseXML = function parseXML(text) {
+ var xmlDoc;
+
+ if (typeof DOMParser != "undefined") {
+ var parser = new DOMParser();
+ xmlDoc = parser.parseFromString(text, "text/xml");
+ } else {
+ xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+ xmlDoc.async = "false";
+ xmlDoc.loadXML(text);
+ }
+
+ return xmlDoc;
+ };
+
+ FakeXMLHttpRequest.statusCodes = {
+ 100: "Continue",
+ 101: "Switching Protocols",
+ 200: "OK",
+ 201: "Created",
+ 202: "Accepted",
+ 203: "Non-Authoritative Information",
+ 204: "No Content",
+ 205: "Reset Content",
+ 206: "Partial Content",
+ 300: "Multiple Choice",
+ 301: "Moved Permanently",
+ 302: "Found",
+ 303: "See Other",
+ 304: "Not Modified",
+ 305: "Use Proxy",
+ 307: "Temporary Redirect",
+ 400: "Bad Request",
+ 401: "Unauthorized",
+ 402: "Payment Required",
+ 403: "Forbidden",
+ 404: "Not Found",
+ 405: "Method Not Allowed",
+ 406: "Not Acceptable",
+ 407: "Proxy Authentication Required",
+ 408: "Request Timeout",
+ 409: "Conflict",
+ 410: "Gone",
+ 411: "Length Required",
+ 412: "Precondition Failed",
+ 413: "Request Entity Too Large",
+ 414: "Request-URI Too Long",
+ 415: "Unsupported Media Type",
+ 416: "Requested Range Not Satisfiable",
+ 417: "Expectation Failed",
+ 422: "Unprocessable Entity",
+ 500: "Internal Server Error",
+ 501: "Not Implemented",
+ 502: "Bad Gateway",
+ 503: "Service Unavailable",
+ 504: "Gateway Timeout",
+ 505: "HTTP Version Not Supported"
+ };
+
+ sinon.useFakeXMLHttpRequest = function () {
+ sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
+ if (xhr.supportsXHR) {
+ global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;
+ }
+
+ if (xhr.supportsActiveX) {
+ global.ActiveXObject = xhr.GlobalActiveXObject;
+ }
+
+ delete sinon.FakeXMLHttpRequest.restore;
+
+ if (keepOnCreate !== true) {
+ delete sinon.FakeXMLHttpRequest.onCreate;
+ }
+ };
+ if (xhr.supportsXHR) {
+ global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
+ }
+
+ if (xhr.supportsActiveX) {
+ global.ActiveXObject = function ActiveXObject(objId) {
+ if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
+
+ return new sinon.FakeXMLHttpRequest();
+ }
+
+ return new xhr.GlobalActiveXObject(objId);
+ };
+ }
+
+ return sinon.FakeXMLHttpRequest;
+ };
+
+ sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
+})(this);
+
+if (typeof module == "object" && typeof require == "function") {
+ module.exports = sinon;
+}
+
+/**
+ * @depend fake_xml_http_request.js
+ */
+/*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
+/*global module, require, window*/
+/**
+ * The Sinon "server" mimics a web server that receives requests from
+ * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
+ * both synchronously and asynchronously. To respond synchronuously, canned
+ * answers have to be provided upfront.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ var sinon = {};
+}
+
+sinon.fakeServer = (function () {
+ var push = [].push;
+ function F() {}
+
+ function create(proto) {
+ F.prototype = proto;
+ return new F();
+ }
+
+ function responseArray(handler) {
+ var response = handler;
+
+ if (Object.prototype.toString.call(handler) != "[object Array]") {
+ response = [200, {}, handler];
+ }
+
+ if (typeof response[2] != "string") {
+ throw new TypeError("Fake server response body should be string, but was " +
+ typeof response[2]);
+ }
+
+ return response;
+ }
+
+ var wloc = window.location;
+ var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
+
+ function matchOne(response, reqMethod, reqUrl) {
+ var rmeth = response.method;
+ var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
+ var url = response.url;
+ var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
+
+ return matchMethod && matchUrl;
+ }
+
+ function match(response, request) {
+ var requestMethod = this.getHTTPMethod(request);
+ var requestUrl = request.url;
+
+ if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
+ requestUrl = requestUrl.replace(rCurrLoc, "");
+ }
+
+ if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
+ if (typeof response.response == "function") {
+ var ru = response.url;
+ var args = [request].concat(!ru ? [] : requestUrl.match(ru).slice(1));
+ return response.response.apply(response, args);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ return {
+ create: function () {
+ var server = create(this);
+ this.xhr = sinon.useFakeXMLHttpRequest();
+ server.requests = [];
+
+ this.xhr.onCreate = function (xhrObj) {
+ server.addRequest(xhrObj);
+ };
+
+ return server;
+ },
+
+ addRequest: function addRequest(xhrObj) {
+ var server = this;
+ push.call(this.requests, xhrObj);
+
+ xhrObj.onSend = function () {
+ server.handleRequest(this);
+ };
+
+ if (this.autoRespond && !this.responding) {
+ setTimeout(function () {
+ server.responding = false;
+ server.respond();
+ }, this.autoRespondAfter || 10);
+
+ this.responding = true;
+ }
+ },
+
+ getHTTPMethod: function getHTTPMethod(request) {
+ if (this.fakeHTTPMethods && /post/i.test(request.method)) {
+ var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
+ return !!matches ? matches[1] : request.method;
+ }
+
+ return request.method;
+ },
+
+ handleRequest: function handleRequest(xhr) {
+ if (xhr.async) {
+ if (!this.queue) {
+ this.queue = [];
+ }
+
+ push.call(this.queue, xhr);
+ } else {
+ this.processRequest(xhr);
+ }
+ },
+
+ respondWith: function respondWith(method, url, body) {
+ if (arguments.length == 1 && typeof method != "function") {
+ this.response = responseArray(method);
+ return;
+ }
+
+ if (!this.responses) { this.responses = []; }
+
+ if (arguments.length == 1) {
+ body = method;
+ url = method = null;
+ }
+
+ if (arguments.length == 2) {
+ body = url;
+ url = method;
+ method = null;
+ }
+
+ push.call(this.responses, {
+ method: method,
+ url: url,
+ response: typeof body == "function" ? body : responseArray(body)
+ });
+ },
+
+ respond: function respond() {
+ if (arguments.length > 0) this.respondWith.apply(this, arguments);
+ var queue = this.queue || [];
+ var request;
+
+ while(request = queue.shift()) {
+ this.processRequest(request);
+ }
+ },
+
+ processRequest: function processRequest(request) {
+ try {
+ if (request.aborted) {
+ return;
+ }
+
+ var response = this.response || [404, {}, ""];
+
+ if (this.responses) {
+ for (var i = 0, l = this.responses.length; i < l; i++) {
+ if (match.call(this, this.responses[i], request)) {
+ response = this.responses[i].response;
+ break;
+ }
+ }
+ }
+
+ if (request.readyState != 4) {
+ request.respond(response[0], response[1], response[2]);
+ }
+ } catch (e) {
+ sinon.logError("Fake server request processing", e);
+ }
+ },
+
+ restore: function restore() {
+ return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
+ }
+ };
+}());
+
+if (typeof module == "object" && typeof require == "function") {
+ module.exports = sinon;
+}
+
+/**
+ * @depend fake_server.js
+ * @depend fake_timers.js
+ */
+/*jslint browser: true, eqeqeq: false, onevar: false*/
+/*global sinon*/
+/**
+ * Add-on for sinon.fakeServer that automatically handles a fake timer along with
+ * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
+ * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
+ * it polls the object for completion with setInterval. Dispite the direct
+ * motivation, there is nothing jQuery-specific in this file, so it can be used
+ * in any environment where the ajax implementation depends on setInterval or
+ * setTimeout.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function () {
+ function Server() {}
+ Server.prototype = sinon.fakeServer;
+
+ sinon.fakeServerWithClock = new Server();
+
+ sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
+ if (xhr.async) {
+ if (typeof setTimeout.clock == "object") {
+ this.clock = setTimeout.clock;
+ } else {
+ this.clock = sinon.useFakeTimers();
+ this.resetClock = true;
+ }
+
+ if (!this.longestTimeout) {
+ var clockSetTimeout = this.clock.setTimeout;
+ var clockSetInterval = this.clock.setInterval;
+ var server = this;
+
+ this.clock.setTimeout = function (fn, timeout) {
+ server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+ return clockSetTimeout.apply(this, arguments);
+ };
+
+ this.clock.setInterval = function (fn, timeout) {
+ server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+ return clockSetInterval.apply(this, arguments);
+ };
+ }
+ }
+
+ return sinon.fakeServer.addRequest.call(this, xhr);
+ };
+
+ sinon.fakeServerWithClock.respond = function respond() {
+ var returnVal = sinon.fakeServer.respond.apply(this, arguments);
+
+ if (this.clock) {
+ this.clock.tick(this.longestTimeout || 0);
+ this.longestTimeout = 0;
+
+ if (this.resetClock) {
+ this.clock.restore();
+ this.resetClock = false;
+ }
+ }
+
+ return returnVal;
+ };
+
+ sinon.fakeServerWithClock.restore = function restore() {
+ if (this.clock) {
+ this.clock.restore();
+ }
+
+ return sinon.fakeServer.restore.apply(this, arguments);
+ };
+}());
+
+/**
+ * @depend ../sinon.js
+ * @depend collection.js
+ * @depend util/fake_timers.js
+ * @depend util/fake_server_with_clock.js
+ */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global require, module*/
+/**
+ * Manages fake collections as well as fake utilities such as Sinon's
+ * timers and fake XHR implementation in one convenient object.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+if (typeof module == "object" && typeof require == "function") {
+ var sinon = require("../sinon");
+ sinon.extend(sinon, require("./util/fake_timers"));
+}
+
+(function () {
+ var push = [].push;
+
+ function exposeValue(sandbox, config, key, value) {
+ if (!value) {
+ return;
+ }
+
+ if (config.injectInto) {
+ config.injectInto[key] = value;
+ } else {
+ push.call(sandbox.args, value);
+ }
+ }
+
+ function prepareSandboxFromConfig(config) {
+ var sandbox = sinon.create(sinon.sandbox);
+
+ if (config.useFakeServer) {
+ if (typeof config.useFakeServer == "object") {
+ sandbox.serverPrototype = config.useFakeServer;
+ }
+
+ sandbox.useFakeServer();
+ }
+
+ if (config.useFakeTimers) {
+ if (typeof config.useFakeTimers == "object") {
+ sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
+ } else {
+ sandbox.useFakeTimers();
+ }
+ }
+
+ return sandbox;
+ }
+
+ sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
+ useFakeTimers: function useFakeTimers() {
+ this.clock = sinon.useFakeTimers.apply(sinon, arguments);
+
+ return this.add(this.clock);
+ },
+
+ serverPrototype: sinon.fakeServer,
+
+ useFakeServer: function useFakeServer() {
+ var proto = this.serverPrototype || sinon.fakeServer;
+
+ if (!proto || !proto.create) {
+ return null;
+ }
+
+ this.server = proto.create();
+ return this.add(this.server);
+ },
+
+ inject: function (obj) {
+ sinon.collection.inject.call(this, obj);
+
+ if (this.clock) {
+ obj.clock = this.clock;
+ }
+
+ if (this.server) {
+ obj.server = this.server;
+ obj.requests = this.server.requests;
+ }
+
+ return obj;
+ },
+
+ create: function (config) {
+ if (!config) {
+ return sinon.create(sinon.sandbox);
+ }
+
+ var sandbox = prepareSandboxFromConfig(config);
+ sandbox.args = sandbox.args || [];
+ var prop, value, exposed = sandbox.inject({});
+
+ if (config.properties) {
+ for (var i = 0, l = config.properties.length; i < l; i++) {
+ prop = config.properties[i];
+ value = exposed[prop] || prop == "sandbox" && sandbox;
+ exposeValue(sandbox, config, prop, value);
+ }
+ } else {
+ exposeValue(sandbox, config, "sandbox", value);
+ }
+
+ return sandbox;
+ }
+ });
+
+ sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
+
+ if (typeof module == "object" && typeof require == "function") {
+ module.exports = sinon.sandbox;
+ }
+}());
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ * @depend mock.js
+ * @depend sandbox.js
+ */
+/*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Test function, sandboxes fakes
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function test(callback) {
+ var type = typeof callback;
+
+ if (type != "function") {
+ throw new TypeError("sinon.test needs to wrap a test function, got " + type);
+ }
+
+ return function () {
+ var config = sinon.getConfig(sinon.config);
+ config.injectInto = config.injectIntoThis && this || config.injectInto;
+ var sandbox = sinon.sandbox.create(config);
+ var exception, result;
+ var args = Array.prototype.slice.call(arguments).concat(sandbox.args);
+
+ try {
+ result = callback.apply(this, args);
+ } finally {
+ sandbox.verifyAndRestore();
+ }
+
+ return result;
+ };
+ }
+
+ test.config = {
+ injectIntoThis: true,
+ injectInto: null,
+ properties: ["spy", "stub", "mock", "clock", "server", "requests"],
+ useFakeTimers: true,
+ useFakeServer: true
+ };
+
+ if (commonJSModule) {
+ module.exports = test;
+ } else {
+ sinon.test = test;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend test.js
+ */
+/*jslint eqeqeq: false, onevar: false, eqeqeq: false*/
+/*global module, require, sinon*/
+/**
+ * Test case, sandboxes all test functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon || !Object.prototype.hasOwnProperty) {
+ return;
+ }
+
+ function createTest(property, setUp, tearDown) {
+ return function () {
+ if (setUp) {
+ setUp.apply(this, arguments);
+ }
+
+ var exception, result;
+
+ try {
+ result = property.apply(this, arguments);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (tearDown) {
+ tearDown.apply(this, arguments);
+ }
+
+ if (exception) {
+ throw exception;
+ }
+
+ return result;
+ };
+ }
+
+ function testCase(tests, prefix) {
+ /*jsl:ignore*/
+ if (!tests || typeof tests != "object") {
+ throw new TypeError("sinon.testCase needs an object with test functions");
+ }
+ /*jsl:end*/
+
+ prefix = prefix || "test";
+ var rPrefix = new RegExp("^" + prefix);
+ var methods = {}, testName, property, method;
+ var setUp = tests.setUp;
+ var tearDown = tests.tearDown;
+
+ for (testName in tests) {
+ if (tests.hasOwnProperty(testName)) {
+ property = tests[testName];
+
+ if (/^(setUp|tearDown)$/.test(testName)) {
+ continue;
+ }
+
+ if (typeof property == "function" && rPrefix.test(testName)) {
+ method = property;
+
+ if (setUp || tearDown) {
+ method = createTest(property, setUp, tearDown);
+ }
+
+ methods[testName] = sinon.test(method);
+ } else {
+ methods[testName] = tests[testName];
+ }
+ }
+ }
+
+ return methods;
+ }
+
+ if (commonJSModule) {
+ module.exports = testCase;
+ } else {
+ sinon.testCase = testCase;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ */
+/*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Assertions matching the test spy retrieval interface.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon, global) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+ var slice = Array.prototype.slice;
+ var assert;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function verifyIsStub() {
+ var method;
+
+ for (var i = 0, l = arguments.length; i < l; ++i) {
+ method = arguments[i];
+
+ if (!method) {
+ assert.fail("fake is not a spy");
+ }
+
+ if (typeof method != "function") {
+ assert.fail(method + " is not a function");
+ }
+
+ if (typeof method.getCall != "function") {
+ assert.fail(method + " is not stubbed");
+ }
+ }
+ }
+
+ function failAssertion(object, msg) {
+ object = object || global;
+ var failMethod = object.fail || assert.fail;
+ failMethod.call(object, msg);
+ }
+
+ function mirrorPropAsAssertion(name, method, message) {
+ if (arguments.length == 2) {
+ message = method;
+ method = name;
+ }
+
+ assert[name] = function (fake) {
+ verifyIsStub(fake);
+
+ var args = slice.call(arguments, 1);
+ var failed = false;
+
+ if (typeof method == "function") {
+ failed = !method(fake);
+ } else {
+ failed = typeof fake[method] == "function" ?
+ !fake[method].apply(fake, args) : !fake[method];
+ }
+
+ if (failed) {
+ failAssertion(this, fake.printf.apply(fake, [message].concat(args)));
+ } else {
+ assert.pass(name);
+ }
+ };
+ }
+
+ function exposedName(prefix, prop) {
+ return !prefix || /^fail/.test(prop) ? prop :
+ prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
+ };
+
+ assert = {
+ failException: "AssertError",
+
+ fail: function fail(message) {
+ var error = new Error(message);
+ error.name = this.failException || assert.failException;
+
+ throw error;
+ },
+
+ pass: function pass(assertion) {},
+
+ callOrder: function assertCallOrder() {
+ verifyIsStub.apply(null, arguments);
+ var expected = "", actual = "";
+
+ if (!sinon.calledInOrder(arguments)) {
+ try {
+ expected = [].join.call(arguments, ", ");
+ actual = sinon.orderByFirstCall(slice.call(arguments)).join(", ");
+ } catch (e) {
+ // If this fails, we'll just fall back to the blank string
+ }
+
+ failAssertion(this, "expected " + expected + " to be " +
+ "called in order but were called as " + actual);
+ } else {
+ assert.pass("callOrder");
+ }
+ },
+
+ callCount: function assertCallCount(method, count) {
+ verifyIsStub(method);
+
+ if (method.callCount != count) {
+ var msg = "expected %n to be called " + sinon.timesInWords(count) +
+ " but was called %c%C";
+ failAssertion(this, method.printf(msg));
+ } else {
+ assert.pass("callCount");
+ }
+ },
+
+ expose: function expose(target, options) {
+ if (!target) {
+ throw new TypeError("target is null or undefined");
+ }
+
+ var o = options || {};
+ var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
+ var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
+
+ for (var method in this) {
+ if (method != "export" && (includeFail || !/^(fail)/.test(method))) {
+ target[exposedName(prefix, method)] = this[method];
+ }
+ }
+
+ return target;
+ }
+ };
+
+ mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
+ mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
+ "expected %n to not have been called but was called %c%C");
+ mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
+ mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
+ mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
+ mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
+ mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
+ mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
+ mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
+ mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
+ mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
+ mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
+ mirrorPropAsAssertion("threw", "%n did not throw exception%C");
+ mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
+
+ if (commonJSModule) {
+ module.exports = assert;
+ } else {
+ sinon.assert = assert;
+ }
+}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : global));
+
+return sinon;}.call(typeof window != 'undefined' && window || {}));
+/*!
+ * MockJax - jQuery Plugin to Mock Ajax requests
+ *
+ * Version: 1.5.1
+ * Released:
+ * Home: http://github.com/appendto/jquery-mockjax
+ * Author: Jonathan Sharp (http://jdsharp.com)
+ * License: MIT,GPL
+ *
+ * Copyright (c) 2011 appendTo LLC.
+ * Dual licensed under the MIT or GPL licenses.
+ * http://appendto.com/open-source-licenses
+ */
+(function($) {
+ var _ajax = $.ajax,
+ mockHandlers = [],
+ CALLBACK_REGEX = /=\?(&|$)/,
+ jsc = (new Date()).getTime();
+
+
+ // Parse the given XML string.
+ function parseXML(xml) {
+ if ( window['DOMParser'] == undefined && window.ActiveXObject ) {
+ DOMParser = function() { };
+ DOMParser.prototype.parseFromString = function( xmlString ) {
+ var doc = new ActiveXObject('Microsoft.XMLDOM');
+ doc.async = 'false';
+ doc.loadXML( xmlString );
+ return doc;
+ };
+ }
+
+ try {
+ var xmlDoc = ( new DOMParser() ).parseFromString( xml, 'text/xml' );
+ if ( $.isXMLDoc( xmlDoc ) ) {
+ var err = $('parsererror', xmlDoc);
+ if ( err.length == 1 ) {
+ throw('Error: ' + $(xmlDoc).text() );
+ }
+ } else {
+ throw('Unable to parse XML');
+ }
+ } catch( e ) {
+ var msg = ( e.name == undefined ? e : e.name + ': ' + e.message );
+ $(document).trigger('xmlParseError', [ msg ]);
+ return undefined;
+ }
+ return xmlDoc;
+ }
+
+ // Trigger a jQuery event
+ function trigger(s, type, args) {
+ (s.context ? $(s.context) : $.event).trigger(type, args);
+ }
+
+ // Check if the data field on the mock handler and the request match. This
+ // can be used to restrict a mock handler to being used only when a certain
+ // set of data is passed to it.
+ function isMockDataEqual( mock, live ) {
+ var identical = false;
+ // Test for situations where the data is a querystring (not an object)
+ if (typeof live === 'string') {
+ // Querystring may be a regex
+ return $.isFunction( mock.test ) ? mock.test(live) : mock == live;
+ }
+ $.each(mock, function(k, v) {
+ if ( live[k] === undefined ) {
+ identical = false;
+ return identical;
+ } else {
+ identical = true;
+ if ( typeof live[k] == 'object' ) {
+ return isMockDataEqual(mock[k], live[k]);
+ } else {
+ if ( $.isFunction( mock[k].test ) ) {
+ identical = mock[k].test(live[k]);
+ } else {
+ identical = ( mock[k] == live[k] );
+ }
+ return identical;
+ }
+ }
+ });
+
+ return identical;
+ }
+
+ // Check the given handler should mock the given request
+ function getMockForRequest( handler, requestSettings ) {
+ // If the mock was registered with a function, let the function decide if we
+ // want to mock this request
+ if ( $.isFunction(handler) ) {
+ return handler( requestSettings );
+ }
+
+ // Inspect the URL of the request and check if the mock handler's url
+ // matches the url for this ajax request
+ if ( $.isFunction(handler.url.test) ) {
+ // The user provided a regex for the url, test it
+ if ( !handler.url.test( requestSettings.url ) ) {
+ return null;
+ }
+ } else {
+ // Look for a simple wildcard '*' or a direct URL match
+ var star = handler.url.indexOf('*');
+ if (handler.url !== requestSettings.url && star === -1 ||
+ !new RegExp(handler.url.replace(/[-[\]{}()+?.,\\^$|#\s]/g, "\\$&").replace('*', '.+')).test(requestSettings.url)) {
+ return null;
+ }
+ }
+
+ // Inspect the data submitted in the request (either POST body or GET query string)
+ if ( handler.data && requestSettings.data ) {
+ if ( !isMockDataEqual(handler.data, requestSettings.data) ) {
+ // They're not identical, do not mock this request
+ return null;
+ }
+ }
+ // Inspect the request type
+ if ( handler && handler.type &&
+ handler.type.toLowerCase() != requestSettings.type.toLowerCase() ) {
+ // The request type doesn't match (GET vs. POST)
+ return null;
+ }
+
+ return handler;
+ }
+
+ // If logging is enabled, log the mock to the console
+ function logMock( mockHandler, requestSettings ) {
+ var c = $.extend({}, $.mockjaxSettings, mockHandler);
+ if ( c.log && $.isFunction(c.log) ) {
+ c.log('MOCK ' + requestSettings.type.toUpperCase() + ': ' + requestSettings.url, $.extend({}, requestSettings));
+ }
+ }
+
+ // Process the xhr objects send operation
+ function _xhrSend(mockHandler, requestSettings, origSettings) {
+
+ // This is a substitute for < 1.4 which lacks $.proxy
+ var process = (function(that) {
+ return function() {
+ return (function() {
+ // The request has returned
+ this.status = mockHandler.status;
+ this.statusText = mockHandler.statusText;
+ this.readyState = 4;
+
+ // We have an executable function, call it to give
+ // the mock handler a chance to update it's data
+ if ( $.isFunction(mockHandler.response) ) {
+ mockHandler.response(origSettings);
+ }
+ // Copy over our mock to our xhr object before passing control back to
+ // jQuery's onreadystatechange callback
+ if ( requestSettings.dataType == 'json' && ( typeof mockHandler.responseText == 'object' ) ) {
+ this.responseText = JSON.stringify(mockHandler.responseText);
+ } else if ( requestSettings.dataType == 'xml' ) {
+ if ( typeof mockHandler.responseXML == 'string' ) {
+ this.responseXML = parseXML(mockHandler.responseXML);
+ } else {
+ this.responseXML = mockHandler.responseXML;
+ }
+ } else {
+ this.responseText = mockHandler.responseText;
+ }
+ if( typeof mockHandler.status == 'number' || typeof mockHandler.status == 'string' ) {
+ this.status = mockHandler.status;
+ }
+ if( typeof mockHandler.statusText === "string") {
+ this.statusText = mockHandler.statusText;
+ }
+ // jQuery < 1.4 doesn't have onreadystate change for xhr
+ if ( $.isFunction(this.onreadystatechange) ) {
+ if( mockHandler.isTimeout) {
+ this.status = -1;
+ }
+ this.onreadystatechange( mockHandler.isTimeout ? 'timeout' : undefined );
+ } else if ( mockHandler.isTimeout ) {
+ // Fix for 1.3.2 timeout to keep success from firing.
+ this.status = -1;
+ }
+ }).apply(that);
+ };
+ })(this);
+
+ if ( mockHandler.proxy ) {
+ // We're proxying this request and loading in an external file instead
+ _ajax({
+ global: false,
+ url: mockHandler.proxy,
+ type: mockHandler.proxyType,
+ data: mockHandler.data,
+ dataType: requestSettings.dataType === "script" ? "text/plain" : requestSettings.dataType,
+ complete: function(xhr, txt) {
+ mockHandler.responseXML = xhr.responseXML;
+ mockHandler.responseText = xhr.responseText;
+ mockHandler.status = xhr.status;
+ mockHandler.statusText = xhr.statusText;
+ this.responseTimer = setTimeout(process, mockHandler.responseTime || 0);
+ }
+ });
+ } else {
+ // type == 'POST' || 'GET' || 'DELETE'
+ if ( requestSettings.async === false ) {
+ // TODO: Blocking delay
+ process();
+ } else {
+ this.responseTimer = setTimeout(process, mockHandler.responseTime || 50);
+ }
+ }
+ }
+
+ // Construct a mocked XHR Object
+ function xhr(mockHandler, requestSettings, origSettings, origHandler) {
+ // Extend with our default mockjax settings
+ mockHandler = $.extend({}, $.mockjaxSettings, mockHandler);
+
+ if (typeof mockHandler.headers === 'undefined') {
+ mockHandler.headers = {};
+ }
+ if ( mockHandler.contentType ) {
+ mockHandler.headers['content-type'] = mockHandler.contentType;
+ }
+
+ return {
+ status: mockHandler.status,
+ statusText: mockHandler.statusText,
+ readyState: 1,
+ open: function() { },
+ send: function() {
+ origHandler.fired = true;
+ _xhrSend.call(this, mockHandler, requestSettings, origSettings);
+ },
+ abort: function() {
+ clearTimeout(this.responseTimer);
+ },
+ setRequestHeader: function(header, value) {
+ mockHandler.headers[header] = value;
+ },
+ getResponseHeader: function(header) {
+ // 'Last-modified', 'Etag', 'content-type' are all checked by jQuery
+ if ( mockHandler.headers && mockHandler.headers[header] ) {
+ // Return arbitrary headers
+ return mockHandler.headers[header];
+ } else if ( header.toLowerCase() == 'last-modified' ) {
+ return mockHandler.lastModified || (new Date()).toString();
+ } else if ( header.toLowerCase() == 'etag' ) {
+ return mockHandler.etag || '';
+ } else if ( header.toLowerCase() == 'content-type' ) {
+ return mockHandler.contentType || 'text/plain';
+ }
+ },
+ getAllResponseHeaders: function() {
+ var headers = '';
+ $.each(mockHandler.headers, function(k, v) {
+ headers += k + ': ' + v + "\n";
+ });
+ return headers;
+ }
+ };
+ }
+
+ // Process a JSONP mock request.
+ function processJsonpMock( requestSettings, mockHandler, origSettings ) {
+ // Handle JSONP Parameter Callbacks, we need to replicate some of the jQuery core here
+ // because there isn't an easy hook for the cross domain script tag of jsonp
+
+ processJsonpUrl( requestSettings );
+
+ requestSettings.dataType = "json";
+ if(requestSettings.data && CALLBACK_REGEX.test(requestSettings.data) || CALLBACK_REGEX.test(requestSettings.url)) {
+ createJsonpCallback(requestSettings, mockHandler);
+
+ // We need to make sure
+ // that a JSONP style response is executed properly
+
+ var rurl = /^(\w+:)?\/\/([^\/?#]+)/,
+ parts = rurl.exec( requestSettings.url ),
+ remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
+
+ requestSettings.dataType = "script";
+ if(requestSettings.type.toUpperCase() === "GET" && remote ) {
+ var newMockReturn = processJsonpRequest( requestSettings, mockHandler, origSettings );
+
+ // Check if we are supposed to return a Deferred back to the mock call, or just
+ // signal success
+ if(newMockReturn) {
+ return newMockReturn;
+ } else {
+ return true;
+ }
+ }
+ }
+ return null;
+ }
+
+ // Append the required callback parameter to the end of the request URL, for a JSONP request
+ function processJsonpUrl( requestSettings ) {
+ if ( requestSettings.type.toUpperCase() === "GET" ) {
+ if ( !CALLBACK_REGEX.test( requestSettings.url ) ) {
+ requestSettings.url += (/\?/.test( requestSettings.url ) ? "&" : "?") +
+ (requestSettings.jsonp || "callback") + "=?";
+ }
+ } else if ( !requestSettings.data || !CALLBACK_REGEX.test(requestSettings.data) ) {
+ requestSettings.data = (requestSettings.data ? requestSettings.data + "&" : "") + (requestSettings.jsonp || "callback") + "=?";
+ }
+ }
+
+ // Process a JSONP request by evaluating the mocked response text
+ function processJsonpRequest( requestSettings, mockHandler, origSettings ) {
+ // Synthesize the mock request for adding a script tag
+ var callbackContext = origSettings && origSettings.context || requestSettings,
+ newMock = null;
+
+
+ // If the response handler on the moock is a function, call it
+ if ( mockHandler.response && $.isFunction(mockHandler.response) ) {
+ mockHandler.response(origSettings);
+ } else {
+
+ // Evaluate the responseText javascript in a global context
+ if( typeof mockHandler.responseText === 'object' ) {
+ $.globalEval( '(' + JSON.stringify( mockHandler.responseText ) + ')');
+ } else {
+ $.globalEval( '(' + mockHandler.responseText + ')');
+ }
+ }
+
+ // Successful response
+ jsonpSuccess( requestSettings, mockHandler );
+ jsonpComplete( requestSettings, mockHandler );
+
+ // If we are running under jQuery 1.5+, return a deferred object
+ if($.Deferred){
+ newMock = new $.Deferred();
+ if(typeof mockHandler.responseText == "object"){
+ newMock.resolveWith( callbackContext, [mockHandler.responseText] );
+ }
+ else{
+ newMock.resolveWith( callbackContext, [$.parseJSON( mockHandler.responseText )] );
+ }
+ }
+ return newMock;
+ }
+
+
+ // Create the required JSONP callback function for the request
+ function createJsonpCallback( requestSettings, mockHandler ) {
+ jsonp = requestSettings.jsonpCallback || ("jsonp" + jsc++);
+
+ // Replace the =? sequence both in the query string and the data
+ if ( requestSettings.data ) {
+ requestSettings.data = (requestSettings.data + "").replace(CALLBACK_REGEX, "=" + jsonp + "$1");
+ }
+
+ requestSettings.url = requestSettings.url.replace(CALLBACK_REGEX, "=" + jsonp + "$1");
+
+
+ // Handle JSONP-style loading
+ window[ jsonp ] = window[ jsonp ] || function( tmp ) {
+ data = tmp;
+ jsonpSuccess( requestSettings, mockHandler );
+ jsonpComplete( requestSettings, mockHandler );
+ // Garbage collect
+ window[ jsonp ] = undefined;
+
+ try {
+ delete window[ jsonp ];
+ } catch(e) {}
+
+ if ( head ) {
+ head.removeChild( script );
+ }
+ };
+ }
+
+ // The JSONP request was successful
+ function jsonpSuccess(requestSettings, mockHandler) {
+ // If a local callback was specified, fire it and pass it the data
+ if ( requestSettings.success ) {
+ requestSettings.success.call( callbackContext, ( mockHandler.response ? mockHandler.response.toString() : mockHandler.responseText || ''), status, {} );
+ }
+
+ // Fire the global callback
+ if ( requestSettings.global ) {
+ trigger(requestSettings, "ajaxSuccess", [{}, requestSettings] );
+ }
+ }
+
+ // The JSONP request was completed
+ function jsonpComplete(requestSettings, mockHandler) {
+ // Process result
+ if ( requestSettings.complete ) {
+ requestSettings.complete.call( callbackContext, {} , status );
+ }
+
+ // The request was completed
+ if ( requestSettings.global ) {
+ trigger( "ajaxComplete", [{}, requestSettings] );
+ }
+
+ // Handle the global AJAX counter
+ if ( requestSettings.global && ! --$.active ) {
+ $.event.trigger( "ajaxStop" );
+ }
+ }
+
+
+ // The core $.ajax replacement.
+ function handleAjax( url, origSettings ) {
+ var mockRequest, requestSettings, mockHandler;
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ origSettings = url;
+ url = undefined;
+ } else {
+ // work around to support 1.5 signature
+ origSettings.url = url;
+ }
+
+ // Extend the original settings for the request
+ requestSettings = $.extend(true, {}, $.ajaxSettings, origSettings);
+
+ // Iterate over our mock handlers (in registration order) until we find
+ // one that is willing to intercept the request
+ for(var k = 0; k < mockHandlers.length; k++) {
+ if ( !mockHandlers[k] ) {
+ continue;
+ }
+
+ mockHandler = getMockForRequest( mockHandlers[k], requestSettings );
+ if(!mockHandler) {
+ // No valid mock found for this request
+ continue;
+ }
+
+ // Handle console logging
+ logMock( mockHandler, requestSettings );
+
+
+ if ( requestSettings.dataType === "jsonp" ) {
+ if ((mockRequest = processJsonpMock( requestSettings, mockHandler, origSettings ))) {
+ // This mock will handle the JSONP request
+ return mockRequest;
+ }
+ }
+
+
+ // Removed to fix #54 - keep the mocking data object intact
+ //mockHandler.data = requestSettings.data;
+
+ mockHandler.cache = requestSettings.cache;
+ mockHandler.timeout = requestSettings.timeout;
+ mockHandler.global = requestSettings.global;
+
+ (function(mockHandler, requestSettings, origSettings, origHandler) {
+ mockRequest = _ajax.call($, $.extend(true, {}, origSettings, {
+ // Mock the XHR object
+ xhr: function() { return xhr( mockHandler, requestSettings, origSettings, origHandler ) }
+ }));
+ })(mockHandler, requestSettings, origSettings, mockHandlers[k]);
+
+ return mockRequest;
+ }
+
+ // We don't have a mock request, trigger a normal request
+ return _ajax.apply($, [origSettings]);
+ }
+
+
+ // Public
+
+ $.extend({
+ ajax: handleAjax
+ });
+
+ $.mockjaxSettings = {
+ //url: null,
+ //type: 'GET',
+ log: function( msg ) {
+ if ( window[ 'console' ] && window.console.log ) {
+ window.console.log.apply( console, arguments );
+ }
+ },
+ status: 200,
+ statusText: "OK",
+ responseTime: 500,
+ isTimeout: false,
+ contentType: 'text/plain',
+ response: '',
+ responseText: '',
+ responseXML: '',
+ proxy: '',
+ proxyType: 'GET',
+
+ lastModified: null,
+ etag: '',
+ headers: {
+ etag: 'IJF@H#@923uf8023hFO@I#H#',
+ 'content-type' : 'text/plain'
+ }
+ };
+
+ $.mockjax = function(settings) {
+ var i = mockHandlers.length;
+ mockHandlers[i] = settings;
+ return i;
+ };
+ $.mockjaxClear = function(i) {
+ if ( arguments.length == 1 ) {
+ mockHandlers[i] = null;
+ } else {
+ mockHandlers = [];
+ }
+ };
+ $.mockjax.handler = function(i) {
+ if ( arguments.length == 1 ) {
+ return mockHandlers[i];
+ }
+ };
+})(jQuery);(function() {
+
+ this.notEmpty = function(selector) {
+ return function() {
+ return $(selector).text().trim() !== '';
+ };
+ };
+
+ this.hasText = function(selector, text) {
+ return function() {
+ return $(selector).text().trim() === text;
+ };
+ };
+
+ this.reposRendered = notEmpty('#repos li.selected');
+
+ this.buildRendered = notEmpty('#summary .number');
+
+ this.buildsRendered = notEmpty('#builds .number');
+
+ this.jobRendered = notEmpty('#summary .number');
+
+ this.jobsRendered = notEmpty('#jobs .number');
+
+ this.queuesRendered = notEmpty('#queue_common li');
+
+ this.workersRendered = notEmpty('.worker');
+
+}).call(this);
+(function() {
+
+ this.displaysRepository = function(repo) {
+ return expect($('#repo h3 a').attr('href')).toEqual(repo.href);
+ };
+
+ this.displaysTabs = function(tabs) {
+ var name, tab, _results;
+ _results = [];
+ for (name in tabs) {
+ tab = tabs[name];
+ if (!tab.hidden) {
+ expect($("#tab_" + name + " a").attr('href')).toEqual(tab.href);
+ }
+ expect($("#tab_" + name).hasClass('active')).toEqual(!!tab.active);
+ if (name === 'build' || name === 'job') {
+ _results.push(expect($("#tab_" + name).hasClass('display-inline')).toEqual(!tab.hidden));
+ } else {
+ _results.push(void 0);
+ }
+ }
+ return _results;
+ };
+
+ this.displaysSummary = function(data) {
+ var element;
+ element = $('#summary .left:first-child dt:first-child');
+ expect(element.text()).toEqual($.camelize(data.type));
+ element = $('#summary .number a');
+ expect(element.attr('href')).toEqual("/" + data.repo + "/" + data.type + "s/" + data.id);
+ element = $('#summary .finished_at');
+ expect(element.text()).toEqual(data.finishedAt);
+ element = $('#summary .duration');
+ expect(element.text()).toEqual(data.duration);
+ element = $('#summary .commit a');
+ expect(element.attr('href')).toEqual("http://github.com/" + data.repo + "/commit/" + data.commit);
+ element = $('#summary .commit a');
+ expect(element.text()).toEqual("" + data.commit + " (" + data.branch + ")");
+ element = $('#summary .compare a');
+ expect(element.attr('href')).toEqual("http://github.com/compare/" + data.compare);
+ element = $('#summary .compare a');
+ expect(element.text()).toEqual(data.compare);
+ element = $('#summary .message');
+ return expect(element.text()).toEqual(data.message);
+ };
+
+ this.displaysLog = function(lines) {
+ var ix, log;
+ ix = 0;
+ log = $.map(lines, function(line) {
+ ix += 1;
+ return "" + ix + line;
+ }).join("\n");
+ return expect($('#log p').text().trim()).toEqual(log);
+ };
+
+ this.listsRepos = function(items) {
+ return listsItems('repo', items);
+ };
+
+ this.listsRepo = function(data) {
+ var repo, row;
+ row = $('#repos li')[data.row - 1];
+ repo = data.item;
+ expect($('a.slug', row).attr('href')).toEqual("/" + repo.slug);
+ expect($('a.last_build', row).attr('href')).toEqual(repo.build.url);
+ expect($('.duration', row).text()).toEqual(repo.build.duration);
+ return expect($('.finished_at', row).text()).toEqual(repo.build.finishedAt);
+ };
+
+ this.listsBuilds = function(builds) {
+ return listsItems('build', builds);
+ };
+
+ this.listsBuild = function(data) {
+ var build, row;
+ row = $('#builds tbody tr')[data.row - 1];
+ build = data.item;
+ expect($('.number a', row).attr('href')).toEqual("/" + build.slug + "/builds/" + build.id);
+ expect($('.number a', row).text().trim()).toEqual(build.number);
+ expect($('.message', row).text().trim()).toEqual(build.message);
+ expect($('.duration', row).text().trim()).toEqual(build.duration);
+ expect($('.finished_at', row).text().trim()).toEqual(build.finishedAt);
+ return expect($(row).attr('class')).toMatch(build.color);
+ };
+
+ this.listsJobs = function(data) {
+ var element, headers, table;
+ table = $(data.table);
+ headers = (function() {
+ var _i, _len, _ref, _results;
+ _ref = $("thead th", table);
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ element = _ref[_i];
+ _results.push($(element).text());
+ }
+ return _results;
+ })();
+ expect(headers).toEqual(data.headers);
+ return $.each(data.jobs, function(row, job) {
+ return listsJob({
+ table: data.table,
+ row: row + 1,
+ item: job
+ });
+ });
+ };
+
+ this.listsJob = function(data) {
+ var element, job, row;
+ row = $('tbody tr', data.table)[data.row - 1];
+ job = data.item;
+ element = $(row);
+ expect(element.attr('class')).toMatch(job.color);
+ element = $("td.number", row);
+ expect(element.text().trim()).toEqual(job.number);
+ element = $("td.number a", row);
+ expect(element.attr('href')).toEqual("/" + job.repo + "/jobs/" + job.id);
+ element = $("td.duration", row);
+ expect(element.text().trim()).toEqual(job.duration);
+ element = $("td.finished_at", row);
+ expect(element.text().trim()).toEqual(job.finishedAt);
+ element = $("td:nth-child(6)", row);
+ return expect(element.text().trim()).toEqual(job.rvm);
+ };
+
+ this.listsQueuedJobs = function(jobs) {
+ return listsItems('queuedJob', jobs);
+ };
+
+ this.listsQueuedJob = function(data) {
+ var job, text;
+ job = data.item;
+ text = $($("#queue_" + data.name + " li")[data.row - 1]).text();
+ expect(text).toContain(job.repo);
+ return expect(text).toContain("#" + job.number);
+ };
+
+ this.listsQueue = function(data) {
+ var job, name, text;
+ name = data.item.name;
+ job = data.item.item;
+ text = $($("#queue_" + name + " li")[data.row - 1]).text();
+ expect(text).toContain(job.repo);
+ return expect(text).toContain("#" + job.number);
+ };
+
+ this.listsItems = function(type, items) {
+ var _this = this;
+ return $.each(items, function(row, item) {
+ return _this["lists" + ($.camelize(type))]({
+ item: item,
+ row: row + 1
+ });
+ });
+ };
+
+ this.listsQueues = function(queues) {
+ return listsItems('queue', queues);
+ };
+
+ this.listsWorker = function(data) {
+ var element, group, worker;
+ group = $("#workers li:contains('" + data.group + "')");
+ element = $($('ul li', group)[data.row - 1]);
+ worker = data.item;
+ expect(element.text()).toContain(worker.name);
+ return expect(element.text()).toContain(worker.state);
+ };
+
+}).call(this);
+(function() {
+
+ this.after = function(time, func) {
+ waits(time);
+ return jasmine.getEnv().currentSpec.runs(func);
+ };
+
+ this.once = function(condition, func) {
+ waitsFor(condition);
+ return jasmine.getEnv().currentSpec.runs(func);
+ };
+
+ this.waitFor = waitsFor;
+
+}).call(this);
+(function() {
+ var artifact, artifacts, branches, build, builds, commits, data, hooks, id, job, jobs, repos, repository, responseTime, workers, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m;
+
+ responseTime = 0;
+
+ repos = [
+ {
+ id: 1,
+ owner: 'travis-ci',
+ name: 'travis-core',
+ slug: 'travis-ci/travis-core',
+ build_ids: [1, 2],
+ last_build_id: 1,
+ last_build_number: 1,
+ last_build_result: 0,
+ last_build_duration: 30,
+ last_build_started_at: '2012-07-02T00:00:00Z',
+ last_build_finished_at: '2012-07-02T00:00:30Z',
+ description: 'Description of travis-core'
+ }, {
+ id: 2,
+ owner: 'travis-ci',
+ name: 'travis-assets',
+ slug: 'travis-ci/travis-assets',
+ build_ids: [3],
+ last_build_id: 3,
+ last_build_number: 3,
+ last_build_result: 1,
+ last_build_duration: 30,
+ last_build_started_at: '2012-07-02T00:01:00Z',
+ last_build_finished_at: '2012-07-01T00:01:30Z',
+ description: 'Description of travis-assets'
+ }, {
+ id: 3,
+ owner: 'travis-ci',
+ name: 'travis-hub',
+ slug: 'travis-ci/travis-hub',
+ build_ids: [4],
+ last_build_id: 4,
+ last_build_number: 4,
+ last_build_result: void 0,
+ last_build_duration: void 0,
+ last_build_started_at: '2012-07-02T00:02:00Z',
+ last_build_finished_at: void 0,
+ description: 'Description of travis-hub'
+ }
+ ];
+
+ builds = [
+ {
+ id: 1,
+ repository_id: '1',
+ commit_id: 1,
+ job_ids: [1, 2, 3],
+ number: 1,
+ pull_request: false,
+ config: {
+ rvm: ['rbx', '1.9.3', 'jruby']
+ },
+ duration: 30,
+ started_at: '2012-07-02T00:00:00Z',
+ finished_at: '2012-07-02T00:00:30Z',
+ result: 0
+ }, {
+ id: 2,
+ repository_id: '1',
+ commit_id: 2,
+ job_ids: [4],
+ number: 2,
+ pull_request: false,
+ config: {
+ rvm: ['rbx']
+ }
+ }, {
+ id: 3,
+ repository_id: '2',
+ commit_id: 3,
+ job_ids: [5],
+ number: 3,
+ pull_request: false,
+ config: {
+ rvm: ['rbx']
+ },
+ duration: 30,
+ started_at: '2012-07-02T00:01:00Z',
+ finished_at: '2012-07-01T00:01:30Z',
+ result: 1
+ }, {
+ id: 4,
+ repository_id: '3',
+ commit_id: 4,
+ job_ids: [6],
+ number: 4,
+ pull_request: false,
+ config: {
+ rvm: ['rbx']
+ },
+ started_at: '2012-07-02T00:02:00Z'
+ }
+ ];
+
+ commits = [
+ {
+ id: 1,
+ sha: '1234567',
+ branch: 'master',
+ message: 'commit message 1',
+ author_name: 'author name',
+ author_email: 'author@email.com',
+ committer_name: 'committer name',
+ committer_email: 'committer@email.com',
+ compare_url: 'http://github.com/compare/0123456..1234567'
+ }, {
+ id: 2,
+ sha: '2345678',
+ branch: 'feature',
+ message: 'commit message 2',
+ author_name: 'author name',
+ author_email: 'author@email.com',
+ committer_name: 'committer name',
+ committer_email: 'committer@email.com',
+ compare_url: 'http://github.com/compare/0123456..2345678'
+ }, {
+ id: 3,
+ sha: '3456789',
+ branch: 'master',
+ message: 'commit message 3',
+ author_name: 'author name',
+ author_email: 'author@email.com',
+ committer_name: 'committer name',
+ committer_email: 'committer@email.com',
+ compare_url: 'http://github.com/compare/0123456..3456789'
+ }, {
+ id: 4,
+ sha: '4567890',
+ branch: 'master',
+ message: 'commit message 4',
+ author_name: 'author name',
+ author_email: 'author@email.com',
+ committer_name: 'committer name',
+ committer_email: 'committer@email.com',
+ compare_url: 'http://github.com/compare/0123456..4567890'
+ }
+ ];
+
+ jobs = [
+ {
+ id: 1,
+ repository_id: 1,
+ build_id: 1,
+ commit_id: 1,
+ log_id: 1,
+ number: '1.1',
+ config: {
+ rvm: 'rbx'
+ },
+ duration: 30,
+ started_at: '2012-07-02T00:00:00Z',
+ finished_at: '2012-07-02T00:00:30Z',
+ result: 0
+ }, {
+ id: 2,
+ repository_id: 1,
+ build_id: 1,
+ commit_id: 1,
+ log_id: 2,
+ number: '1.2',
+ config: {
+ rvm: '1.9.3'
+ },
+ duration: 40,
+ started_at: '2012-07-02T00:00:00Z',
+ finished_at: '2012-07-02T00:00:40Z',
+ result: 1
+ }, {
+ id: 3,
+ repository_id: 1,
+ build_id: 1,
+ commit_id: 1,
+ log_id: 3,
+ number: '1.3',
+ config: {
+ rvm: 'jruby'
+ },
+ allow_failure: true
+ }, {
+ id: 4,
+ repository_id: 1,
+ build_id: 2,
+ commit_id: 2,
+ log_id: 4,
+ number: '2.1',
+ config: {
+ rvm: 'rbx'
+ }
+ }, {
+ id: 5,
+ repository_id: 2,
+ build_id: 3,
+ commit_id: 3,
+ log_id: 5,
+ number: '3.1',
+ config: {
+ rvm: 'rbx'
+ },
+ duration: 30,
+ started_at: '2012-07-02T00:01:00Z',
+ finished_at: '2012-07-02T00:01:30Z',
+ result: 1
+ }, {
+ id: 6,
+ repository_id: 3,
+ build_id: 4,
+ commit_id: 4,
+ log_id: 6,
+ number: '4.1',
+ config: {
+ rvm: 'rbx'
+ },
+ started_at: '2012-07-02T00:02:00Z'
+ }, {
+ id: 7,
+ repository_id: 1,
+ build_id: 5,
+ commit_id: 5,
+ log_id: 7,
+ number: '5.1',
+ config: {
+ rvm: 'rbx'
+ },
+ state: 'created',
+ queue: 'builds.common'
+ }, {
+ id: 8,
+ repository_id: 1,
+ build_id: 5,
+ commit_id: 5,
+ log_id: 8,
+ number: '5.2',
+ config: {
+ rvm: 'rbx'
+ },
+ state: 'created',
+ queue: 'builds.common'
+ }
+ ];
+
+ artifacts = [
+ {
+ id: 1,
+ body: 'log 1'
+ }, {
+ id: 2,
+ body: 'log 2'
+ }, {
+ id: 3,
+ body: 'log 3'
+ }, {
+ id: 4,
+ body: 'log 4'
+ }, {
+ id: 5,
+ body: 'log 5'
+ }, {
+ id: 6,
+ body: 'log 6'
+ }, {
+ id: 7,
+ body: 'log 7'
+ }, {
+ id: 8,
+ body: 'log 8'
+ }
+ ];
+
+ branches = [
+ {
+ branches: [builds[0], builds[1]],
+ commits: [commits[0], commits[1]]
+ }, {
+ branches: [builds[2]],
+ commits: [commits[2]]
+ }, {
+ branches: [builds[3]],
+ commits: [commits[3]]
+ }
+ ];
+
+ workers = [
+ {
+ id: 1,
+ name: 'ruby-1',
+ host: 'worker.travis-ci.org',
+ state: 'ready'
+ }, {
+ id: 2,
+ name: 'ruby-2',
+ host: 'worker.travis-ci.org',
+ state: 'ready'
+ }
+ ];
+
+ hooks = [
+ {
+ slug: 'travis-ci/travis-core',
+ description: 'description of travis-core',
+ active: true,
+ "private": false
+ }, {
+ slug: 'travis-ci/travis-assets',
+ description: 'description of travis-assets',
+ active: false,
+ "private": false
+ }, {
+ slug: 'svenfuchs/minimal',
+ description: 'description of minimal',
+ active: true,
+ "private": false
+ }
+ ];
+
+ $.mockjax({
+ url: '/repos',
+ responseTime: responseTime,
+ response: function(settings) {
+ var search, slug;
+ if (!settings.data) {
+ return this.responseText = {
+ repos: repos
+ };
+ } else if (slug = settings.data.slug) {
+ return this.responseText = {
+ repos: [
+ $.detect(repos, function(repository) {
+ return repository.slug === slug;
+ })
+ ]
+ };
+ } else if (search = settings.data.search) {
+ return this.responseText = {
+ repos: $.select(repos, function(repository) {
+ return repository.slug.indexOf(search) > -1;
+ }).toArray()
+ };
+ } else {
+ return raise("don't know this ditty");
+ }
+ }
+ });
+
+ for (_i = 0, _len = repos.length; _i < _len; _i++) {
+ repository = repos[_i];
+ $.mockjax({
+ url: '/' + repository.slug,
+ responseTime: responseTime,
+ responseText: {
+ repository: repository
+ }
+ });
+ $.mockjax({
+ url: '/repos',
+ data: {
+ slug: repository.slug
+ },
+ responseTime: responseTime,
+ responseText: {
+ repos: [repository]
+ }
+ });
+ $.mockjax({
+ url: '/builds',
+ data: {
+ ids: repository.build_ids
+ },
+ responseTime: responseTime,
+ responseText: {
+ builds: $.select(builds, function(build) {
+ return repository.build_ids.indexOf(build.id) !== -1;
+ })
+ }
+ });
+ $.mockjax({
+ url: '/builds',
+ data: {
+ repository_id: repository.id,
+ event_type: 'push'
+ },
+ responseTime: responseTime,
+ responseText: {
+ builds: (function() {
+ var _j, _len1, _ref, _results;
+ _ref = repository.build_ids;
+ _results = [];
+ for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
+ id = _ref[_j];
+ _results.push(builds[id - 1]);
+ }
+ return _results;
+ })(),
+ commits: (function() {
+ var _j, _len1, _ref, _results;
+ _ref = repository.build_ids;
+ _results = [];
+ for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
+ id = _ref[_j];
+ _results.push(commits[builds[id - 1].commit_id - 1]);
+ }
+ return _results;
+ })()
+ }
+ });
+ }
+
+ for (_j = 0, _len1 = builds.length; _j < _len1; _j++) {
+ build = builds[_j];
+ $.mockjax({
+ url: '/builds/' + build.id,
+ responseTime: responseTime,
+ responseText: {
+ build: build,
+ commit: commits[build.commit_id - 1],
+ jobs: (function() {
+ var _k, _len2, _ref, _results;
+ _ref = build.job_ids;
+ _results = [];
+ for (_k = 0, _len2 = _ref.length; _k < _len2; _k++) {
+ id = _ref[_k];
+ _results.push(jobs[id - 1]);
+ }
+ return _results;
+ })()
+ }
+ });
+ }
+
+ for (_k = 0, _len2 = jobs.length; _k < _len2; _k++) {
+ job = jobs[_k];
+ $.mockjax({
+ url: '/jobs/' + job.id,
+ responseTime: responseTime,
+ responseText: {
+ job: job,
+ commit: commits[job.commit_id - 1]
+ }
+ });
+ }
+
+ $.mockjax({
+ url: '/jobs',
+ responseTime: responseTime,
+ responseText: {
+ jobs: $.select(jobs, function(job) {
+ return job.state === 'created';
+ })
+ }
+ });
+
+ for (_l = 0, _len3 = branches.length; _l < _len3; _l++) {
+ data = branches[_l];
+ $.mockjax({
+ url: '/branches',
+ data: {
+ repository_id: data.branches[0].repository_id
+ },
+ responseTime: responseTime,
+ responseText: data
+ });
+ }
+
+ for (_m = 0, _len4 = artifacts.length; _m < _len4; _m++) {
+ artifact = artifacts[_m];
+ $.mockjax({
+ url: '/artifacts/' + artifact.id,
+ responseTime: responseTime,
+ responseText: {
+ artifact: artifact
+ }
+ });
+ }
+
+ $.mockjax({
+ url: '/workers',
+ responseTime: responseTime,
+ responseText: {
+ workers: workers
+ }
+ });
+
+ $.mockjax({
+ url: '/profile/hooks',
+ responseTime: responseTime,
+ responseText: {
+ hooks: hooks
+ }
+ });
+
+}).call(this);
+(function() {
+
+ describe('on the "build" state', function() {
+ beforeEach(function() {
+ app('travis-ci/travis-core/builds/1');
+ waitFor(reposRendered);
+ return runs(function() {
+ return waitFor(buildRendered);
+ });
+ });
+ afterEach(function() {
+ return window.history.pushState({}, null, '/spec.html');
+ });
+ return it('displays the expected stuff', function() {
+ listsRepos([
+ {
+ slug: 'travis-ci/travis-hub',
+ build: {
+ number: 4,
+ url: '/travis-ci/travis-hub/builds/4',
+ duration: '1 min',
+ finishedAt: '-'
+ }
+ }, {
+ slug: 'travis-ci/travis-core',
+ build: {
+ number: 1,
+ url: '/travis-ci/travis-core/builds/1',
+ duration: '30 sec',
+ finishedAt: '3 minutes ago'
+ }
+ }, {
+ slug: 'travis-ci/travis-assets',
+ build: {
+ number: 3,
+ url: '/travis-ci/travis-assets/builds/3',
+ duration: '30 sec',
+ finishedAt: 'a day ago'
+ }
+ }
+ ]);
+ displaysRepository({
+ href: 'http://github.com/travis-ci/travis-core'
+ });
+ displaysSummary({
+ type: 'build',
+ id: 1,
+ repo: 'travis-ci/travis-core',
+ commit: '1234567',
+ branch: 'master',
+ compare: '0123456..1234567',
+ finishedAt: '3 minutes ago',
+ duration: '30 sec',
+ message: 'commit message 1'
+ });
+ displaysTabs({
+ current: {
+ href: '/travis-ci/travis-core'
+ },
+ builds: {
+ href: '/travis-ci/travis-core/builds'
+ },
+ build: {
+ href: '/travis-ci/travis-core/builds/1',
+ active: true
+ },
+ job: {
+ hidden: true
+ }
+ });
+ listsJobs({
+ table: '#jobs',
+ headers: ['Job', 'Duration', 'Finished', 'Rvm'],
+ jobs: [
+ {
+ color: 'green',
+ id: 1,
+ number: '1.1',
+ repo: 'travis-ci/travis-core',
+ finishedAt: '3 minutes ago',
+ duration: '30 sec',
+ rvm: 'rbx'
+ }, {
+ color: 'red',
+ id: 2,
+ number: '1.2',
+ repo: 'travis-ci/travis-core',
+ finishedAt: '2 minutes ago',
+ duration: '40 sec',
+ rvm: '1.9.3'
+ }
+ ]
+ });
+ return listsJobs({
+ table: '#allowed_failure_jobs',
+ headers: ['Job', 'Duration', 'Finished', 'Rvm'],
+ jobs: [
+ {
+ color: '',
+ id: 3,
+ number: '1.3',
+ repo: 'travis-ci/travis-core',
+ finishedAt: '-',
+ duration: '-',
+ rvm: 'jruby'
+ }
+ ]
+ });
+ });
+ });
+
+}).call(this);
+(function() {
+
+ describe('on the "builds" state', function() {
+ beforeEach(function() {
+ app('travis-ci/travis-core/builds');
+ return waitFor(buildsRendered);
+ });
+ afterEach(function() {
+ return window.history.pushState({}, null, '/spec.html');
+ });
+ return it('displays the expected stuff', function() {
+ listsRepos([
+ {
+ slug: 'travis-ci/travis-hub',
+ build: {
+ number: 4,
+ url: '/travis-ci/travis-hub/builds/4',
+ duration: '1 min',
+ finishedAt: '-'
+ }
+ }, {
+ slug: 'travis-ci/travis-core',
+ build: {
+ number: 1,
+ url: '/travis-ci/travis-core/builds/1',
+ duration: '30 sec',
+ finishedAt: '3 minutes ago'
+ }
+ }, {
+ slug: 'travis-ci/travis-assets',
+ build: {
+ number: 3,
+ url: '/travis-ci/travis-assets/builds/3',
+ duration: '30 sec',
+ finishedAt: 'a day ago'
+ }
+ }
+ ]);
+ displaysRepository({
+ href: 'http://github.com/travis-ci/travis-core'
+ });
+ displaysTabs({
+ current: {
+ href: '/travis-ci/travis-core'
+ },
+ builds: {
+ href: '/travis-ci/travis-core/builds',
+ active: true
+ },
+ build: {
+ hidden: true
+ },
+ job: {
+ hidden: true
+ }
+ });
+ return listsBuilds([
+ {
+ id: 1,
+ slug: 'travis-ci/travis-core',
+ number: '1',
+ sha: '1234567',
+ branch: 'master',
+ message: 'commit message 1',
+ duration: '30 sec',
+ finishedAt: '3 minutes ago',
+ color: 'green'
+ }, {
+ id: 2,
+ slug: 'travis-ci/travis-core',
+ number: '2',
+ sha: '2345678',
+ branch: 'feature',
+ message: 'commit message 2',
+ duration: '-',
+ finishedAt: '-',
+ color: ''
+ }
+ ]);
+ });
+ });
+
+}).call(this);
+(function() {
+
+ describe('on the "current" state', function() {
+ beforeEach(function() {
+ app('travis-ci/travis-core');
+ return waitFor(buildRendered);
+ });
+ afterEach(function() {
+ return window.history.pushState({}, null, '/spec.html');
+ });
+ return it('displays the expected stuff', function() {
+ listsRepos([
+ {
+ slug: 'travis-ci/travis-hub',
+ build: {
+ number: 4,
+ url: '/travis-ci/travis-hub/builds/4',
+ duration: '1 min',
+ finishedAt: '-'
+ }
+ }, {
+ slug: 'travis-ci/travis-core',
+ build: {
+ number: 1,
+ url: '/travis-ci/travis-core/builds/1',
+ duration: '30 sec',
+ finishedAt: '3 minutes ago'
+ }
+ }, {
+ slug: 'travis-ci/travis-assets',
+ build: {
+ number: 3,
+ url: '/travis-ci/travis-assets/builds/3',
+ duration: '30 sec',
+ finishedAt: 'a day ago'
+ }
+ }
+ ]);
+ displaysRepository({
+ href: 'http://github.com/travis-ci/travis-core'
+ });
+ displaysSummary({
+ type: 'build',
+ id: 1,
+ repo: 'travis-ci/travis-core',
+ commit: '1234567',
+ branch: 'master',
+ compare: '0123456..1234567',
+ finishedAt: '3 minutes ago',
+ duration: '30 sec',
+ message: 'commit message 1'
+ });
+ displaysTabs({
+ current: {
+ href: '/travis-ci/travis-core',
+ active: true
+ },
+ builds: {
+ href: '/travis-ci/travis-core/builds'
+ },
+ build: {
+ hidden: true
+ },
+ job: {
+ hidden: true
+ }
+ });
+ listsJobs({
+ table: '#jobs',
+ headers: ['Job', 'Duration', 'Finished', 'Rvm'],
+ jobs: [
+ {
+ id: 1,
+ color: 'green',
+ number: '1.1',
+ repo: 'travis-ci/travis-core',
+ finishedAt: '3 minutes ago',
+ duration: '30 sec',
+ rvm: 'rbx'
+ }, {
+ id: 2,
+ color: 'red',
+ number: '1.2',
+ repo: 'travis-ci/travis-core',
+ finishedAt: '2 minutes ago',
+ duration: '40 sec',
+ rvm: '1.9.3'
+ }
+ ]
+ });
+ return listsJobs({
+ table: '#allowed_failure_jobs',
+ headers: ['Job', 'Duration', 'Finished', 'Rvm'],
+ jobs: [
+ {
+ id: 3,
+ color: '',
+ number: '1.3',
+ repo: 'travis-ci/travis-core',
+ finishedAt: '-',
+ duration: '-',
+ rvm: 'jruby'
+ }
+ ]
+ });
+ });
+ });
+
+}).call(this);
+(function() {
+
+ describe('events', function() {
+ afterEach(function() {
+ return window.history.pushState({}, null, '/spec.html');
+ });
+ describe('an event adding a repository', function() {
+ beforeEach(function() {
+ app('travis-ci/travis-core');
+ return waitFor(jobsRendered);
+ });
+ return it('adds a repository to the list', function() {
+ waitFor(reposRendered);
+ return runs(function() {
+ var payload;
+ payload = {
+ repository: {
+ id: 10
+ },
+ build: {
+ id: 10,
+ repository_id: 10
+ }
+ };
+ $.mockjax({
+ url: '/builds/10',
+ responseTime: 0,
+ responseText: payload
+ });
+ Em.run(function() {
+ return Travis.app.receive('build:started', {
+ build: {
+ id: 10
+ },
+ repository: {
+ id: 10,
+ slug: 'travis-ci/travis-support',
+ last_build_id: 10,
+ last_build_number: 10,
+ last_build_started_at: '2012-07-02T00:01:00Z',
+ last_build_finished_at: '2012-07-02T00:02:30Z'
+ }
+ });
+ });
+ waits(100);
+ return runs(function() {
+ return listsRepo({
+ row: 2,
+ item: {
+ slug: 'travis-ci/travis-support',
+ build: {
+ number: 4,
+ url: '/travis-ci/travis-support/builds/10',
+ duration: '1 min 30 sec',
+ finishedAt: 'less than a minute ago'
+ }
+ }
+ });
+ });
+ });
+ });
+ });
+ describe('an event adding a job', function() {
+ beforeEach(function() {
+ app('travis-ci/travis-core');
+ waitFor(jobsRendered);
+ return runs(function() {
+ return waitFor(queuesRendered);
+ });
+ });
+ it('adds a job to the jobs matrix', function() {
+ var payload;
+ payload = {
+ job: {
+ id: 15
+ }
+ };
+ $.mockjax({
+ url: '/jobs/15',
+ responseTime: 0,
+ responseText: payload
+ });
+ Em.run(function() {
+ return Travis.app.receive('job:started', {
+ job: {
+ id: 15,
+ repository_id: 1,
+ build_id: 1,
+ commit_id: 1,
+ log_id: 1,
+ number: '1.4',
+ duration: 55,
+ started_at: '2012-07-02T00:02:00Z',
+ finished_at: '2012-07-02T00:02:55Z',
+ config: {
+ rvm: 'jruby'
+ }
+ }
+ });
+ });
+ waits(100);
+ return runs(function() {
+ return listsJob({
+ table: $('#jobs'),
+ row: 3,
+ item: {
+ id: 15,
+ number: '1.4',
+ repo: 'travis-ci/travis-core',
+ finishedAt: 'less than a minute ago',
+ duration: '55 sec',
+ rvm: 'jruby'
+ }
+ });
+ });
+ });
+ it('adds a job to the jobs queue', function() {
+ var payload;
+ payload = {
+ job: {
+ id: 12,
+ repository_id: 1,
+ number: '1.4',
+ queue: 'builds.common'
+ }
+ };
+ $.mockjax({
+ url: '/jobs/12',
+ responseTime: 0,
+ responseText: payload
+ });
+ Em.run(function() {
+ return Travis.app.receive('job:started', {
+ job: {
+ id: 12,
+ repository_id: 1,
+ number: '1.4',
+ queue: 'builds.common',
+ state: 'created'
+ }
+ });
+ });
+ waits(100);
+ return runs(function() {
+ return listsQueuedJob({
+ name: 'common',
+ row: 3,
+ item: {
+ number: '1.4',
+ repo: 'travis-ci/travis-core'
+ }
+ });
+ });
+ });
+ return it('updates only keys that are available', function() {
+ Em.run(function() {
+ return Travis.app.receive('job:started', {
+ job: {
+ id: 1,
+ build_id: 1
+ }
+ });
+ });
+ waits(100);
+ return runs(function() {
+ return listsJob({
+ table: $('#jobs'),
+ row: 1,
+ item: {
+ id: 1,
+ number: '1.1',
+ repo: 'travis-ci/travis-core',
+ finishedAt: '3 minutes ago',
+ duration: '30 sec',
+ rvm: 'rbx'
+ }
+ });
+ });
+ });
+ });
+ return describe('an event adding a worker', function() {
+ beforeEach(function() {
+ app('');
+ return waitFor(workersRendered);
+ });
+ return it('adds a worker to the workers list', function() {
+ var payload;
+ payload = {
+ worker: {
+ id: 10,
+ host: 'worker.travis-ci.org',
+ name: 'ruby-3',
+ state: 'ready'
+ }
+ };
+ $.mockjax({
+ url: '/workers/10',
+ responseTime: 0,
+ responseText: payload
+ });
+ Em.run(function() {
+ return Travis.app.receive('worker:created', {
+ worker: {
+ id: 10,
+ name: 'ruby-3',
+ host: 'worker.travis-ci.org',
+ state: 'ready'
+ }
+ });
+ });
+ waits(100);
+ return runs(function() {
+ return listsWorker({
+ group: 'worker.travis-ci.org',
+ row: 3,
+ item: {
+ name: 'ruby-3',
+ state: 'ready'
+ }
+ });
+ });
+ });
+ });
+ });
+
+}).call(this);
+(function() {
+
+ describe('on the "index" state', function() {
+ beforeEach(function() {
+ app('travis-ci/travis-core');
+ return waitFor(buildRendered);
+ });
+ afterEach(function() {
+ return window.history.pushState({}, null, '/spec.html');
+ });
+ return it('displays the expected stuff', function() {
+ listsRepos([
+ {
+ slug: 'travis-ci/travis-hub',
+ build: {
+ number: 4,
+ url: '/travis-ci/travis-hub/builds/4',
+ duration: '1 min',
+ finishedAt: '-'
+ }
+ }, {
+ slug: 'travis-ci/travis-core',
+ build: {
+ number: 1,
+ url: '/travis-ci/travis-core/builds/1',
+ duration: '30 sec',
+ finishedAt: '3 minutes ago'
+ }
+ }, {
+ slug: 'travis-ci/travis-assets',
+ build: {
+ number: 3,
+ url: '/travis-ci/travis-assets/builds/3',
+ duration: '30 sec',
+ finishedAt: 'a day ago'
+ }
+ }
+ ]);
+ displaysRepository({
+ href: 'http://github.com/travis-ci/travis-core'
+ });
+ displaysSummary({
+ type: 'build',
+ id: 1,
+ repo: 'travis-ci/travis-core',
+ commit: '1234567',
+ branch: 'master',
+ compare: '0123456..1234567',
+ finishedAt: '3 minutes ago',
+ duration: '30 sec',
+ message: 'commit message 1'
+ });
+ displaysTabs({
+ current: {
+ href: '/travis-ci/travis-core',
+ active: true
+ },
+ builds: {
+ href: '/travis-ci/travis-core/builds'
+ },
+ build: {
+ hidden: true
+ },
+ job: {
+ hidden: true
+ }
+ });
+ listsJobs({
+ table: '#jobs',
+ headers: ['Job', 'Duration', 'Finished', 'Rvm'],
+ jobs: [
+ {
+ color: 'green',
+ id: 1,
+ number: '1.1',
+ repo: 'travis-ci/travis-core',
+ finishedAt: '3 minutes ago',
+ duration: '30 sec',
+ rvm: 'rbx'
+ }, {
+ color: 'red',
+ id: 2,
+ number: '1.2',
+ repo: 'travis-ci/travis-core',
+ finishedAt: '2 minutes ago',
+ duration: '40 sec',
+ rvm: '1.9.3'
+ }
+ ]
+ });
+ return listsJobs({
+ table: '#allowed_failure_jobs',
+ headers: ['Job', 'Duration', 'Finished', 'Rvm'],
+ jobs: [
+ {
+ color: '',
+ id: 3,
+ number: '1.3',
+ repo: 'travis-ci/travis-core',
+ finishedAt: '-',
+ duration: '-',
+ rvm: 'jruby'
+ }
+ ]
+ });
+ });
+ });
+
+}).call(this);
+(function() {
+
+ describe('on the "job" state', function() {
+ beforeEach(function() {
+ app('travis-ci/travis-core/jobs/1');
+ waitFor(jobRendered);
+ return runs(function() {
+ return waitFor(hasText('#tab_build', 'Build #1'));
+ });
+ });
+ afterEach(function() {
+ return window.history.pushState({}, null, '/spec.html');
+ });
+ return it('displays the expected stuff', function() {
+ listsRepos([
+ {
+ slug: 'travis-ci/travis-hub',
+ build: {
+ number: 4,
+ url: '/travis-ci/travis-hub/builds/4',
+ duration: '1 min',
+ finishedAt: '-'
+ }
+ }, {
+ slug: 'travis-ci/travis-core',
+ build: {
+ number: 1,
+ url: '/travis-ci/travis-core/builds/1',
+ duration: '30 sec',
+ finishedAt: '3 minutes ago'
+ }
+ }, {
+ slug: 'travis-ci/travis-assets',
+ build: {
+ number: 3,
+ url: '/travis-ci/travis-assets/builds/3',
+ duration: '30 sec',
+ finishedAt: 'a day ago'
+ }
+ }
+ ]);
+ displaysRepository({
+ href: 'http://github.com/travis-ci/travis-core'
+ });
+ displaysSummary({
+ id: 1,
+ type: 'job',
+ repo: 'travis-ci/travis-core',
+ commit: '1234567',
+ branch: 'master',
+ compare: '0123456..1234567',
+ finishedAt: '3 minutes ago',
+ duration: '30 sec',
+ message: 'commit message 1'
+ });
+ displaysTabs({
+ current: {
+ href: '/travis-ci/travis-core'
+ },
+ builds: {
+ href: '/travis-ci/travis-core/builds'
+ },
+ build: {
+ href: '/travis-ci/travis-core/builds/1'
+ },
+ job: {
+ href: '/travis-ci/travis-core/jobs/1',
+ active: true
+ }
+ });
+ return displaysLog(['log 1']);
+ });
+ });
+
+}).call(this);
+(function() {
+
+ describe('the sidebar', function() {
+ beforeEach(function() {
+ app('travis-ci/travis-core/jobs/1');
+ waitFor(jobRendered);
+ return runs(function() {
+ return waitFor(hasText('#tab_build', 'Build #1'));
+ });
+ });
+ afterEach(function() {
+ return window.history.pushState({}, null, '/spec.html');
+ });
+ return it('displays the expected stuff', function() {
+ return listsQueues([
+ {
+ name: 'common',
+ item: {
+ number: '5.1',
+ repo: 'travis-ci/travis-core'
+ }
+ }, {
+ name: 'common',
+ item: {
+ number: '5.2',
+ repo: 'travis-ci/travis-core'
+ }
+ }
+ ]);
+ });
+ });
+
+}).call(this);
+(function() {
+ var _Date;
+
+ minispade.require('app');
+
+ this.reset = function() {
+ Em.run(function() {
+ if (Travis.app) {
+ if (Travis.app.store) {
+ Travis.app.store.destroy();
+ }
+ Travis.app.destroy();
+ delete Travis.app;
+ return delete Travis.store;
+ }
+ });
+ waits(500);
+ $('#application').remove();
+ return $('body').append($('
'));
+ };
+
+ this.app = function(url) {
+ reset();
+ return Em.run(function() {
+ Travis.run({
+ rootElement: $('#application')
+ });
+ waitFor(function() {
+ return Travis.app;
+ });
+ return runs(function() {
+ if (url && !url.match(/^\//)) {
+ url = "/" + url;
+ }
+ Travis.app.router.route(url);
+ waits(100);
+ return runs(function() {
+ var foo;
+ return foo = 'bar';
+ });
+ });
+ });
+ };
+
+ _Date = Date;
+
+ this.Date = function(date) {
+ return new _Date(date || '2012-07-02T00:03:00Z');
+ };
+
+ this.Date.UTC = _Date.UTC;
+
+}).call(this);
diff --git a/public/spec.html b/public/spec.html
new file mode 100644
index 00000000..e94d83ab
--- /dev/null
+++ b/public/spec.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+ Travis CI - Distributed Continuous Integration Platform for the Open Source Community
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/styles/app.css b/public/styles/app.css
index 37f47708..1df0e3b2 100644
--- a/public/styles/app.css
+++ b/public/styles/app.css
@@ -2526,13 +2526,13 @@ html, body {
}
/* line 8, /Users/sven/Development/projects/travis/travis-web/assets/styles/layout.sass */
-body > div {
+.application {
width: 100%;
overflow: hidden;
}
/* line 13, /Users/sven/Development/projects/travis/travis-web/assets/styles/layout.sass */
-body > div, body > div > div {
+.application, .application > div {
width: 100%;
min-height: 100%;
display: -webkit-box;
diff --git a/public/styles/jasmine-ext.css b/public/styles/jasmine-ext.css
new file mode 100644
index 00000000..94fef03a
--- /dev/null
+++ b/public/styles/jasmine-ext.css
@@ -0,0 +1,11 @@
+#HTMLReporter {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ width: 50%;
+ height: 150px;
+ z-index: 1000;
+ background-color: white;
+ overflow: auto;
+ border: 1px solid #A80000;
+}
diff --git a/public/styles/jasmine.css b/public/styles/jasmine.css
new file mode 100644
index 00000000..705dd7d6
--- /dev/null
+++ b/public/styles/jasmine.css
@@ -0,0 +1,79 @@
+#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
+#HTMLReporter a { text-decoration: none; }
+#HTMLReporter a:hover { text-decoration: underline; }
+#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
+#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
+#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
+#HTMLReporter .version { color: #aaaaaa; }
+#HTMLReporter .banner { margin-top: 14px; }
+#HTMLReporter .duration { color: #aaaaaa; float: right; }
+#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
+#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
+#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
+#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
+#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
+#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
+#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
+#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
+#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
+#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
+#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
+#HTMLReporter .runningAlert { background-color: #666666; }
+#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
+#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
+#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
+#HTMLReporter .passingAlert { background-color: #a6b779; }
+#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
+#HTMLReporter .failingAlert { background-color: #cf867e; }
+#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
+#HTMLReporter .results { margin-top: 14px; }
+#HTMLReporter #details { display: none; }
+#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
+#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
+#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
+#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter.showDetails .summary { display: none; }
+#HTMLReporter.showDetails #details { display: block; }
+#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter .summary { margin-top: 14px; }
+#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
+#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
+#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
+#HTMLReporter .description + .suite { margin-top: 0; }
+#HTMLReporter .suite { margin-top: 14px; }
+#HTMLReporter .suite a { color: #333333; }
+#HTMLReporter #details .specDetail { margin-bottom: 28px; }
+#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
+#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
+#HTMLReporter .resultMessage span.result { display: block; }
+#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
+
+#TrivialReporter { padding: 8px 13px; clear: both; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
+#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
+#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
+#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
+#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
+#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
+#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
+#TrivialReporter .runner.running { background-color: yellow; }
+#TrivialReporter .options { text-align: right; font-size: .8em; }
+#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
+#TrivialReporter .suite .suite { margin: 5px; }
+#TrivialReporter .suite.passed { background-color: #dfd; }
+#TrivialReporter .suite.failed { background-color: #fdd; }
+#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
+#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
+#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
+#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
+#TrivialReporter .spec.skipped { background-color: #bbb; }
+#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
+#TrivialReporter .passed { background-color: #cfc; display: none; }
+#TrivialReporter .failed { background-color: #fbb; }
+#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
+#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
+#TrivialReporter .resultMessage .mismatch { color: black; }
+#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
+#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
+#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
+#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
+#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
diff --git a/public/version b/public/version
index 66ccad93..993d66b9 100644
--- a/public/version
+++ b/public/version
@@ -1 +1 @@
-6250e20b
\ No newline at end of file
+4b27d9a7
\ No newline at end of file
diff --git a/spec/assets/spec_helper.coffee b/spec/assets/spec_helper.coffee
deleted file mode 100644
index f7e958ae..00000000
--- a/spec/assets/spec_helper.coffee
+++ /dev/null
@@ -1,25 +0,0 @@
-minispade.require 'app'
-
-@reset = ->
- Em.run ->
- if Travis.app
- if Travis.app.store
- Travis.app.store.destroy()
- if views = Travis.app.get('_connectedOutletViews')
- views.forEach (v) -> v.destroy()
- Travis.app.destroy()
-
- waits(500) # TODO not sure what we need to wait for here
- $('#content').remove()
- $('body').append('
')
-
-@app = (url) ->
- reset()
- Em.run ->
- Travis.run(rootElement: $('#content'))
- Em.routes.set('location', url)
-
-_Date = Date
-@Date = (date) ->
- new _Date(date || '2012-07-02T00:03:00Z')
-@Date.UTC = _Date.UTC