├── .gitignore
├── .jshintrc
├── Gruntfile.js
├── app
├── .jshintrc
├── application.js
├── modules
│ ├── base.js
│ ├── search.js
│ ├── startup.js
│ └── utils.js
├── pages
│ └── index.html
└── templates
│ ├── metadata-search.html
│ ├── metadata-valuation.html
│ ├── panel-startup-full.html
│ ├── panel-startup-list-item.html
│ ├── panel-startup-list.html
│ ├── search-container.html
│ ├── single-search-container.html
│ ├── single-search-item.html
│ ├── single-tag-count.html
│ └── tag-count-list.html
├── assets
├── css
│ ├── colorbox.css
│ ├── images
│ │ ├── border1.png
│ │ ├── border2.png
│ │ ├── loading.gif
│ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png
│ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png
│ │ ├── ui-bg_flat_10_000000_40x100.png
│ │ ├── ui-bg_glass_100_f6f6f6_1x400.png
│ │ ├── ui-bg_glass_100_fdf5ce_1x400.png
│ │ ├── ui-bg_glass_65_ffffff_1x400.png
│ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png
│ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png
│ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png
│ │ ├── ui-icons_222222_256x240.png
│ │ ├── ui-icons_228ef1_256x240.png
│ │ ├── ui-icons_ef8c08_256x240.png
│ │ ├── ui-icons_ffd27a_256x240.png
│ │ └── ui-icons_ffffff_256x240.png
│ ├── jquery-ui-1.8.16.custom.css
│ ├── jquery-ui-1.8.16.custom_default.css
│ ├── satisfy.woff
│ └── style.css
├── img
│ ├── .gitignore
│ ├── ajax-loader.gif
│ ├── follow_twitter_gray.png
│ ├── loader.grey.gif
│ ├── logo_38pt.gif
│ ├── ui-bg_diagonals-thick_18_b81900_40x40.png
│ ├── ui-bg_diagonals-thick_20_666666_40x40.png
│ ├── ui-bg_flat_10_000000_40x100.png
│ ├── ui-bg_glass_100_f6f6f6_1x400.png
│ ├── ui-bg_glass_100_fdf5ce_1x400.png
│ ├── ui-bg_glass_65_ffffff_1x400.png
│ ├── ui-bg_gloss-wave_35_f6a828_500x100.png
│ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png
│ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png
│ ├── ui-icons_222222_256x240.png
│ ├── ui-icons_228ef1_256x240.png
│ ├── ui-icons_ef8c08_256x240.png
│ ├── ui-icons_ffd27a_256x240.png
│ └── ui-icons_ffffff_256x240.png
├── js
│ ├── jquery-sparklines.js
│ ├── jquery-ui-1.8.16.custom.min.js
│ ├── jquery.colorbox-min.js
│ └── libs
│ │ ├── backbone.js
│ │ ├── jquery.js
│ │ └── underscore.js
├── mockups.bmml
├── mockups.png
├── mockups_2.png
├── search_header.jpg
└── sparkline.png
├── favicon.ico
├── package.json
├── readme.md
├── tasks
├── contrib-clean.js
├── contrib-concat.js
├── contrib-connect.js
├── contrib-copy.js
├── contrib-jshint.js
├── contrib-jst.js
├── contrib-uglify.js
├── contrib-watch.js
└── s3.js
└── test
├── index.html
├── unit
├── .jshintrc
└── core.js
└── vendor
├── jslitmus.js
├── qunit.css
└── qunit.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | prod/
4 | credentials.json
5 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "curly": true,
3 | "eqeqeq": true,
4 | "immed": true,
5 | "latedef": "nofunc",
6 | "newcap": true,
7 | "noarg": true,
8 | "sub": true,
9 | "undef": true,
10 | "unused": "vars",
11 | "boss": true,
12 | "eqnull": true,
13 | "node": true
14 | }
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = function(grunt) {
3 |
4 | // Project configuration.
5 | grunt.initConfig({
6 | pkg: grunt.file.readJSON('package.json'),
7 | aws: grunt.file.readJSON('credentials.json')
8 | });
9 |
10 | // Load Grunt plugins.
11 | grunt.loadTasks('tasks');
12 |
13 | grunt.registerTask('build',
14 | 'Builds prod version',
15 | ['jshint', 'clean:prod', 'jst', 'copy', 'uglify', 'concat', 'clean:postbuild']);
16 |
17 | grunt.registerTask('dev',
18 | 'Compile and start a dev webserver.',
19 | ['build', 'watch']);
20 |
21 | grunt.registerTask('default', ['dev']);
22 |
23 | };
--------------------------------------------------------------------------------
/app/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "curly": true,
3 | "eqeqeq": true,
4 | "immed": true,
5 | "latedef": "nofunc",
6 | "newcap": true,
7 | "noarg": true,
8 | "sub": true,
9 | "undef": true,
10 | "unused": "vars",
11 | "boss": true,
12 | "eqnull": true,
13 | "browser": true,
14 | "loopfunc": true,
15 | "globals": {
16 | "_": true,
17 | "$": true,
18 | "Backbone": true,
19 | "jQuery": true,
20 | "ALT": true,
21 | "console": true
22 | }
23 | }
--------------------------------------------------------------------------------
/app/application.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Startup Data Trends
3 | * Author Irene Ros (Bocoup)
4 | */
5 | // Namespace: ALT - AngelListTrends.
6 |
7 |
8 | ALT.module = (function() {
9 | var modules = {};
10 |
11 | return function(name) {
12 | if (modules[name]) {
13 | return modules[name];
14 | }
15 |
16 | return (modules[name] = { Views: {} });
17 | };
18 | })();
19 |
20 | ALT.app = _.extend(ALT.app, Backbone.Events);
21 |
22 | jQuery(function($) {
23 | var app = ALT.app,
24 | Router,
25 | // U = ALT.module("utils"),
26 | // S = ALT.module("search"),
27 | B = ALT.module("base"),
28 | ST = ALT.module("startup");
29 |
30 | // Only need this for pushState enabled browsers
31 | if (Backbone.history && Backbone.history._hasPushState) {
32 | // All navigation that is relative should be passed through the navigate
33 | // method, to be processed by the router. If the link has a data-bypass
34 | // attribute, bypass the delegation completely.
35 | $(document).on("click", "a:not([data-bypass])", function(evt) {
36 | // Get the anchor href and protcol
37 | var href = $(this).attr("href"),
38 | protocol = this.protocol + "//";
39 |
40 | // Ensure the protocol is not part of URL, meaning its relative.
41 | if (href && href.slice(0, protocol.length) !== protocol) {
42 | // Stop the default event to ensure the link will not cause a page
43 | // refresh.
44 | evt.preventDefault();
45 |
46 | // This uses the default router defined above, and not any routers
47 | // that may be placed in modules. To have this work globally (at the
48 | // cost of losing all route events) you can change the following line
49 | // to: Backbone.history.navigate(href, true);
50 | app.router.navigate(href, true);
51 | }
52 | });
53 | }
54 |
55 | Router = Backbone.Router.extend({
56 | routes: {
57 | "": "index",
58 | "?tags=:tags": "search"
59 | },
60 |
61 | _init: function() {
62 |
63 | // create a holder for startups
64 | ALT.app.startupCollection = new ST.Collections.Startups([], {
65 | page_max: 5,
66 | pages_attribute: "last_page"
67 | });
68 |
69 | // initialize list of current tags
70 | ALT.app.currentTags = new Backbone.Collection();
71 |
72 | // Pretty much all functionality is routed through this callback.
73 | // When a tag is added or removed from the searchable list, all
74 | // UIs update, all calls are made etc.
75 | ALT.app.currentTags.bind("add", function(model) {
76 |
77 | // reset collection
78 |
79 | ALT.app.startupCollection.clear();
80 |
81 | // update search view
82 | ALT.app.mainView.leftView.searchView.addTag(model);
83 |
84 | // Only perform a search on a tag that is market as such. This is
85 | // key because if a user comes in via a url with a tag list,
86 | // we only want to perform the search on all tags together, not
87 | // individually.
88 | // A regular tag search through form will mark each tag
89 | // as search-triggering.
90 | if (model.get("triggerSearch")) {
91 |
92 | // redo the search
93 | ALT.app.mainView.rightView.cleanup();
94 | ALT.app.mainView.rightView.render();
95 |
96 | // update url
97 | this.navigate("?tags=" + ALT.app.currentTags.pluck("id").join(","), false);
98 | }
99 |
100 | }, this);
101 |
102 | ALT.app.currentTags.bind("remove", function(model) {
103 |
104 | // if this was the last tag, reset url to root.
105 | if (ALT.app.currentTags.length === 0) {
106 | window.location = "/";
107 | }
108 |
109 | // reset collection
110 | ALT.app.startupCollection.clear();
111 |
112 | // redo the search
113 | ALT.app.mainView.rightView.cleanup();
114 | ALT.app.mainView.rightView.render();
115 |
116 | // update url
117 | this.navigate("?tags=" + ALT.app.currentTags.pluck("id").join(","), false);
118 | }, this);
119 |
120 | // Render the main view of the application.
121 | ALT.app.mainView = new B.Views.AppView();
122 | ALT.app.mainView.render();
123 | },
124 |
125 | index: function() {
126 | this._init();
127 | },
128 |
129 | search: function(tags) {
130 | this._init();
131 |
132 | var S = ALT.module("search"),
133 | // parse tags
134 | tagIds = tags.split(","),
135 | tagFetches = [],
136 | tagModels = [];
137 |
138 | // Initiate the fecth on each tag's metadata. This is
139 | // required to then do a startup search itself and display
140 | // what tags we're searching in the UI.
141 | _.each(tagIds, function(tagId) {
142 | var tag = new S.Models.Tag({ id: tagId });
143 | tagModels.push(tag);
144 |
145 | // Save the fetch calls so that we can attach a callback to
146 | // their successful completion.
147 | tagFetches.push(tag.fetch({
148 | silent: true
149 | }));
150 | });
151 |
152 | // When each tag is fetched, add it to the current tag list
153 | // but only peform the startup search at the end when all tags
154 | // have been fetched.
155 | $.when.apply(null, tagFetches).then(function(tag) {
156 | _.each(tagModels, function(tag, i) {
157 |
158 | // only search when all tags are present.
159 | if (tagModels.length-1 === i) {
160 | tag.triggerSearch();
161 | }
162 |
163 | // when available, add each tag to our list of
164 | // current tags.
165 | ALT.app.currentTags.add(tag);
166 | });
167 | });
168 | }
169 |
170 | });
171 |
172 | app.router = new Router();
173 | Backbone.history.start({ pushState: true });
174 | });
175 |
--------------------------------------------------------------------------------
/app/modules/base.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Startup Data Trends
3 | * Author Irene Ros (Bocoup)
4 | */
5 | (function(B) {
6 |
7 | // required modules - startup, search.
8 | var ST = ALT.module("startup"),
9 | S = ALT.module("search"),
10 | U = ALT.module("utils"),
11 |
12 | // Progress viewers are tied to a count. Only when
13 | // all operations are done will the progress indicator
14 | // actually be removed.
15 | loadingViews = 0;
16 | //$loader = $(".about .loader");
17 |
18 | B.Views.Progressify = function() {
19 | loadingViews += 1;
20 | S.trigger("searchStart");
21 | };
22 |
23 | B.Views.Done = function() {
24 | if (loadingViews === 1) {
25 | S.trigger("searchStop");
26 | }
27 | loadingViews -= 1;
28 | };
29 |
30 | /**
31 | * The overarching application view manager.
32 | */
33 | B.Views.AppView = Backbone.View.extend({
34 | id: "#main",
35 |
36 | initialize: function(attributes) {
37 | this.el = $(this.id);
38 | },
39 |
40 | render: function() {
41 |
42 | this.leftView = new B.Views.LeftView();
43 | this.leftView.render();
44 |
45 | this.rightView = new B.Views.RightView();
46 |
47 | // right view rendering left for search!
48 | return this;
49 | },
50 |
51 | cleanup: function() {
52 | this.leftView.cleanup();
53 | this.rightView.cleanup();
54 | }
55 | });
56 |
57 | B.Views.LeftView = Backbone.View.extend({
58 | id: "#left-container",
59 |
60 | initialize: function(attributes) {
61 | this.el = $(this.id);
62 |
63 | // when the collection of startups is done loading,
64 | // render the tag cloud
65 | ALT.app.startupCollection.bind("done", this.addTags, this);
66 | },
67 |
68 | render: function() {
69 |
70 | // render search view
71 | this.searchView = new S.Views.SearchView();
72 | this.searchView.render();
73 | },
74 |
75 | addTags: function() {
76 |
77 | var tagContainer = $("#tag-container"),
78 | // render a list of tags when were ready.
79 | tags = ALT.app.startupCollection.markets();
80 |
81 | this.tagListView = new U.TagList({}, { tags: tags });
82 | tagContainer.html(this.tagListView.render().el);
83 | },
84 |
85 | cleanup: function() {
86 |
87 | // unbind
88 | ALT.app.startupCollection.unbind("done", this.addTags);
89 |
90 | // remove the list of tags
91 | this.tagListView.cleanup();
92 |
93 | // note, no cleanup required on search. we ammend that.
94 | }
95 | });
96 |
97 | B.Views.RightView = Backbone.View.extend({
98 | id: "#right-container",
99 |
100 | initialize: function(attributes) {
101 | this.el = $(this.id);
102 | },
103 |
104 | render: function() {
105 |
106 | // Create a new startup collection
107 | var tags = ALT.app.currentTags.pluck("id").join(",");
108 | ALT.app.currentTags.tags = tags;
109 |
110 | // Create a new metadata view.
111 | this.metadataView = new B.Views.Panels.Metadata({
112 | collection: ALT.app.startupCollection
113 | });
114 |
115 | // remove the about info if it's there
116 | $("#startup-data-container .about").remove();
117 | $("#startup-list-container").show();
118 | $("#startup-info-container").css({
119 | top: $("#metadata-container").height() + 150
120 | });
121 |
122 | // Create a new startup list collection view
123 | // which will also create the startupInfoView
124 | this.startupListView = new ST.Views.List({
125 | collection: ALT.app.startupCollection,
126 | tags: tags
127 | });
128 | },
129 |
130 | cleanup: function() {
131 | if (this.metadataView) {
132 | this.metadataView.cleanup();
133 | }
134 | if (this.startupListView) {
135 | this.startupListView.cleanup();
136 | }
137 | }
138 | });
139 |
140 | // Just a container for all our panel views
141 |
142 | B.Views.Panels = {};
143 | /**
144 | * A container for metadata about the currently searched tags.
145 | * contains:
146 | * metadata about search
147 | * metadata about valuation
148 | */
149 | B.Views.Panels.Metadata = Backbone.View.extend({
150 | id: "#metadata-container",
151 | template: "#metadata-search",
152 |
153 | initialize: function() {
154 |
155 | // init housing element & template
156 | this.el = $(this.id);
157 |
158 | // add the border. We remove it while things are loading.
159 | this.$(".inner").addClass("border");
160 |
161 | // Create new metadata valuation view
162 | // it takes care of it's own rendering.
163 | this.metadataValuationView = new B.Views.Panels.MetadataValuation();
164 |
165 | // Create a new metadata search view
166 | this.metadataSearchView = new B.Views.Panels.MetadataSearch({
167 | collection: this.collection
168 | });
169 | },
170 |
171 | cleanup: function() {
172 | this.metadataValuationView.cleanup();
173 | this.metadataSearchView.cleanup();
174 | }
175 | });
176 |
177 | /**
178 | * View for range slider and select dropdown
179 | */
180 | B.Views.Panels.MetadataSearch = Backbone.View.extend({
181 | template: "metadata-search",
182 | id: "#metadata-startup-container",
183 |
184 | initialize: function(attributes, options) {
185 |
186 | // this.collection is set to startup list!
187 |
188 | // find element
189 | this.el = $(this.id);
190 |
191 | // Get compile templated from cache
192 | this.template = ALT.app.templates[this.template];
193 |
194 | // render container shell
195 | this.render();
196 |
197 | // When the first page of the collection is fetched,
198 | // show the control interface (although keep things disabled, like)
199 | // the select control.
200 | this.collection.bind("start", this.bindStart, this);
201 |
202 | // When a collection fetches a new page, update some counts
203 | this.collection.bind("page", this.bindPage, this);
204 |
205 | // When the last page of the collection is loaded, finish
206 | // whatever rendering we have left.
207 | this.collection.bind("done", this.finish, this);
208 | },
209 |
210 | bindStart: function() {
211 | this.$(".details").show();
212 | this.$(".sort").show();
213 | this.$("span#startup-total-count").html(this.collection.total_startups);
214 |
215 | },
216 |
217 | bindPage: function() {
218 | this.$("span#startup-list-counts").html(this.collection.length);
219 | },
220 |
221 | cleanup: function() {
222 |
223 | this.delegateEvents({});
224 |
225 | this.el.html(
226 | this.template()
227 | );
228 |
229 | this.$("#range").hide();
230 |
231 | this.collection.unbind("start", this.bindStart);
232 | this.collection.unbind("page", this.bindPage);
233 | this.collection.unbind("done", this.finish);
234 |
235 | // disable the sorting until we're done loading everything
236 | this.$("select").attr("disabled", "disabled");
237 |
238 | this.el.html("
Loading... ");
239 | },
240 |
241 | render: function() {
242 |
243 | this.el.html(
244 | this.template()
245 | );
246 |
247 | this.delegateEvents({
248 | "click #load-more-startups": "onLoadMore",
249 | "change select": "onSelect"
250 | });
251 |
252 | // disable the sorting until we're done loading everything
253 | this.$("select").attr("disabled", "disabled");
254 |
255 | return this;
256 | },
257 |
258 | finish: function() {
259 | if (this.collection.length) {
260 | // Enable sorting select
261 | this.$("select").removeAttr("disabled");
262 |
263 | this.makeRangeSlider();
264 | this.makeSparkline();
265 | }
266 | },
267 |
268 | onSelect: function(event) {
269 |
270 | var value = event.target.value,
271 | // Cache Selection match references
272 | $range = $("#range"),
273 | $decay = $("#about-decay-over-time");
274 |
275 | // When a new sort is selected, tell the list to
276 | // handle it
277 | this.collection.trigger("alt.resort", value);
278 |
279 | // hide the appropriate counts in the startup list
280 | ALT.app.mainView.rightView.startupListView.hideCounts(value);
281 |
282 | // hide the range selectors if it's not followers
283 | if (value !== "follower_count") {
284 | $range.slideUp();
285 | } else {
286 | $range.slideDown("slow");
287 | }
288 |
289 | // show the about follower trends message
290 | if (value === "followers_over_time") {
291 | $decay.slideDown();
292 | } else {
293 | $decay.slideUp();
294 | }
295 | },
296 |
297 | onLoadMore: function(event) {
298 |
299 | // Add a few pages to the collection max pages.
300 | var oldPages = ALT.app.startupCollection.pages;
301 | this.collection.pages = Math.min(
302 | oldPages + 10,
303 | this.collection.total_pages
304 | );
305 |
306 | // If we actually increased the page size
307 | if (oldPages < this.collection.pages) {
308 |
309 | this.collection.fetch({
310 |
311 | // on the first page, render a side panel
312 | success: _.bind(function(collection) {
313 |
314 | // trigger that another page was fetched of the collection
315 | collection.trigger("page");
316 |
317 | }, this)
318 | });
319 | }
320 | },
321 |
322 | makeRangeSlider: function(collection) {
323 | // make a range slider
324 | this.$("#range").show();
325 | var vals = this.collection.pluck("follower_count"),
326 | min = _.min(vals),
327 | max = _.max(vals);
328 |
329 | this.$("#slider-range").slider({
330 | range: true,
331 | min: min,
332 | max: max,
333 | values: [min, max],
334 | step: 10,
335 | slide: function(event, ui) {
336 | $("#slider-range-left").html(ui.values[0]);
337 | $("#slider-range-right").html(ui.values[1]);
338 | },
339 | stop: _.bind(
340 | function(event, ui) {
341 | // find all startups who's follower counts are between ranges.
342 | var subset = this.collection.select(function(startup) {
343 | return (startup.get("follower_count") >= ui.values[0] &&
344 | startup.get("follower_count") <= ui.values[1]);
345 | });
346 |
347 | // update the layout with subset
348 | ALT.app.mainView.rightView.startupListView.update(subset);
349 | }, this)
350 | });
351 | $("#slider-range-left").html(min);
352 | $("#slider-range-right").html(max);
353 | },
354 |
355 | makeSparkline: function(collection) {
356 |
357 | // make a sparkline of follower counts
358 | this.$(".slider-sparkline").sparkline(
359 | this.collection.histogram(30),
360 | {
361 | type: "bar",
362 | width: "100%",
363 | barColor: "orange",
364 | lineColor: "none",
365 | zeroColor: "#ddd"
366 | });
367 | this.$(".slider-sparkline canvas").css({ width: "100%" });
368 | }
369 | });
370 |
371 | B.Views.Panels.MetadataValuation = Backbone.View.extend({
372 | template: "metadata-valuation",
373 | id: "#metadata-valuation-container",
374 |
375 | initialize: function() {
376 |
377 | // find element
378 | this.el = $(this.id);
379 |
380 | // Get compile templated from cache
381 | this.template = ALT.app.templates[this.template];
382 |
383 | // --- get metadata from server
384 | // get current tags
385 | var tags = ALT.app.currentTags.pluck("id").join(",");
386 |
387 | // Fetch stats about the tags if they exist
388 | if (tags.length) {
389 |
390 | // Stats model (valuation data)
391 | this.model = new S.Models.SearchStats({}, {
392 | tags: tags
393 | });
394 |
395 | // When data is fetched, render this view.
396 | this.model.fetch({
397 | success: _.bind(function(model) {
398 | this.render();
399 | }, this)
400 | });
401 | }
402 | },
403 |
404 | render: function() {
405 |
406 | // Render valuation data into its container.
407 | this.el.html(
408 | this.template({
409 | stats: this.model.toJSON()
410 | })
411 | );
412 |
413 | return this;
414 | },
415 |
416 | cleanup: function() {
417 | this.el.html("");
418 | }
419 | });
420 |
421 |
422 | /**
423 | * A container for the metadata about a startup.
424 | */
425 | B.Views.Panels.StartupInfo = Backbone.View.extend({
426 | id: "#startup-info-container",
427 | initialize: function(attributes, options) {
428 | this.el = $(this.id);
429 |
430 | if (this.model) {
431 | this.model.fetch({
432 | success: _.bind(function(model) {
433 | this.model = model;
434 | this.render();
435 | }, this),
436 | error: this.renderEmpty
437 | });
438 | } else {
439 | this.renderEmpty();
440 | }
441 | },
442 |
443 | render: function() {
444 |
445 | var fullPanel = new ST.Views.Full({
446 | model: this.model
447 | });
448 | this.el.html(fullPanel.render().el);
449 |
450 | return this;
451 | },
452 |
453 | renderEmpty: function(message) {
454 | message = message || " No Startups Found ";
455 | this.el.html("");
456 | return this;
457 | }
458 | });
459 |
460 | })(ALT.module("base"));
461 |
--------------------------------------------------------------------------------
/app/modules/search.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Startup Data Trends
3 | * Author Irene Ros (Bocoup)
4 | */
5 | (function(S, U) {
6 |
7 | S.Models = (S.Models || {});
8 | S.Collections = (S.Collections || {});
9 |
10 | _.extend(S, Backbone.Events);
11 |
12 | // Responsible for holding a single search.
13 | S.Models.Search = Backbone.Model.extend({});
14 |
15 | // Responsible for holding a single tag - particularly useful
16 | // when loading from a url with tags in it.
17 | S.Models.Tag = Backbone.Model.extend({
18 | url: function() {
19 | return "http://api.angel.co/1/tags/" + this.id + "?callback=?";
20 | },
21 | triggerSearch: function() {
22 | this.set({ "triggerSearch": true });
23 | }
24 | });
25 |
26 | // Responsible for search metadata
27 | S.Models.SearchStats = Backbone.Model.extend({
28 | initialize: function(attributes, options) {
29 | this.tags = options.tags;
30 | },
31 | url: function() {
32 | return "http://api.angel.co/1/tags/stats?tag_ids=" + this.tags +
33 | "&callback=?";
34 | },
35 | parse: function(data) {
36 | if (data.raising.amount) {
37 | data.raising.amount = U.formatDollarAmount(data.raising.amount);
38 | } else {
39 | data.raising.amount = "Not Enough Data";
40 | }
41 |
42 | if (data.pre_money.amount) {
43 | data.pre_money.amount = U.formatDollarAmount(data.pre_money.amount);
44 | } else {
45 | data.pre_money.amount = "Not Enough Data";
46 | }
47 |
48 | return data;
49 | }
50 | });
51 |
52 | // A single search result entry
53 | S.Models.SearchItem = Backbone.Model.extend({});
54 |
55 | // A container of search results
56 | S.Collections.SearchItems = Backbone.Collection.extend({
57 | model: S.Collections.SearchItem,
58 | initialize: function(collections, options) {
59 | this.search = options.search;
60 | },
61 | url: function() {
62 | // TODO: want to have a way to restrict the type of search!
63 | return "http://api.angel.co/1/search?query=" + this.search.get("query") + "&type=" + this.search.get("type") + "&callback=?";
64 | },
65 | autocompleteItems: function() {
66 | return this.map(function(model) {
67 | return {
68 | id: model.id,
69 | label: model.get("name"),
70 | value: model.get("value")
71 | };
72 | });
73 | }
74 | });
75 |
76 | /**
77 | * Contains all the search boxes.
78 | */
79 | S.Views.SearchView = Backbone.View.extend({
80 | id: "#search-container",
81 | template: "search-container",
82 |
83 | initialize: function(attributes) {
84 | this.el = $(this.id);
85 |
86 | // Get compile templated from cache
87 | this.template = ALT.app.templates[this.template];
88 |
89 | this._searchComponents = {
90 | location: null,
91 | market: null,
92 | person: null
93 | };
94 | this.blocker = this.$(".search-blocker");
95 | S.bind("searchStart", function() {
96 | this.blocker.fadeTo(500, 0.8);
97 | },this)
98 | .bind("searchStop", function() {
99 | this.blocker.fadeOut(500);
100 | },this);
101 | },
102 |
103 | addTag: function(tag) {
104 |
105 | // hide about
106 | $(".about .info").slideUp(500);
107 | S.trigger("searchStart");
108 |
109 | var tagView = new S.Views.SearchSelectedComponentItem({
110 | model: tag
111 | });
112 | this.$(".search-tags")
113 | .append(tagView.render().el);
114 | },
115 |
116 | render: function() {
117 |
118 | // Render template
119 | this.el.append(this.template());
120 |
121 | // TODO: Append 3 search components
122 | this._searchComponents.location = new S.Views.SearchComponentView({
123 | collection: new S.Collections.SearchItems({}, { search: new S.Models.Search({
124 | type: "LocationTag",
125 | name: "Location"
126 | })})
127 | });
128 |
129 | this._searchComponents.market = new S.Views.SearchComponentView({
130 | collection: new S.Collections.SearchItems({}, { search: new S.Models.Search({
131 | type: "MarketTag",
132 | name: "Market"
133 | })})
134 | });
135 |
136 | this.el.prepend(this._searchComponents.market.render().el);
137 | this.el.prepend(this._searchComponents.location.render().el);
138 |
139 | return this;
140 | }
141 |
142 | });
143 |
144 | /**
145 | * A single selected item that gets appended at the end of a
146 | * autocomplete dropdown
147 | */
148 | S.Views.SearchSelectedComponentItem = Backbone.View.extend({
149 | template: "single-search-item",
150 | events: {
151 | "click .close": "onClose"
152 | },
153 | initialize: function(attributes, options) {
154 | this.template = ALT.app.templates[this.template];
155 | },
156 |
157 | render: function() {
158 | $(this.el).html(this.template({
159 | id: this.model.id,
160 | label: this.model.get("label") || this.model.get("display_name")
161 | }));
162 | return this;
163 | },
164 |
165 | onClose: function(event) {
166 | event.preventDefault();
167 |
168 | var value = this.$("a").attr("data-id"),
169 | model = ALT.app.currentTags.get(value);
170 |
171 | // delete current tag model
172 | ALT.app.currentTags.remove(model);
173 |
174 | // delete this thing
175 | this.remove();
176 | }
177 | });
178 |
179 | // Declare handler for: clear, blur
180 | // function clearFocus(event) {
181 | // $(event.target).val(" ").focus();
182 | // }
183 |
184 | /**
185 | * An individual search component.
186 | */
187 | S.Views.SearchComponentView = Backbone.View.extend({
188 | className: "c25 single-search-container",
189 | template: "single-search-container",
190 |
191 | initialize: function(attributes, options) {
192 |
193 | // save Search information attributes
194 | this.search = this.collection.search;
195 |
196 | this.template = ALT.app.templates[this.template];
197 |
198 | $(this.el).attr({ "id": "search-" + this.search.get("type") });
199 | },
200 | render: function() {
201 |
202 | // Render search component.
203 | $(this.el).html(this.template({
204 | id: this.search.get("type"),
205 | type: this.search.get("name")
206 | }));
207 |
208 | // enable jquery autocomplete dropdown
209 | var input = this.$("input");
210 | input.autocomplete({
211 | source : _.bind(function(request, response) {
212 | this.collection.search.set(
213 | { "query": request.term },
214 | { silent: true }
215 | );
216 | this.$(".search-loader").addClass("searching");
217 | this.collection.fetch({
218 | success: _.bind(function(collection) {
219 | this.$(".search-loader").removeClass("searching");
220 | response(collection.autocompleteItems());
221 | },this)
222 | });
223 | }, this),
224 | minLength: 2,
225 | select : _.bind(function(event, ui) {
226 | // TODO: append item to list
227 | // TODO: clear search
228 | // Add a tag to the current list of tags
229 |
230 | var tagModel = new S.Models.Tag(ui.item);
231 | tagModel.set({
232 | "tag_type" : this.search.get("type")
233 | }, { silent:true });
234 |
235 | // rendering happens on tag add, not here. This is
236 | // to support url based searches.
237 | tagModel.triggerSearch();
238 | ALT.app.currentTags.add(tagModel);
239 | event.preventDefault();
240 | input.val("").focus();
241 | }, this)
242 | });
243 | return this;
244 | }
245 | });
246 | })(ALT.module("search"), ALT.module("utils"));
--------------------------------------------------------------------------------
/app/modules/startup.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Startup Data Trends
3 | * Author Irene Ros (Bocoup)
4 | */
5 | (function(ST, U, B) {
6 |
7 | ST.Models = (ST.Models || {});
8 | ST.Collections = (ST.Collections || {});
9 |
10 | // Stealing from Backbone... because sync needs it and I'm overwriting it.
11 | var methodMap = {
12 | "create": "POST",
13 | "update": "PUT",
14 | "delete": "DELETE",
15 | "read": "GET"
16 | };
17 |
18 | /**
19 | * A single representation of a startup.
20 | */
21 | ST.Models.Startup = Backbone.Model.extend({
22 | url: function() {
23 | return "https://api.angel.co/1/startups/" + this.get("id") +"?callback=?";
24 | }
25 | });
26 |
27 | /**
28 | * A useful little pagination collection extension. Handles two
29 | * types of collections:
30 | * 1. Those where the number of pages is discoered on first page
31 | * 2. Those whose number of pages is known in advance.
32 | * Used by startup Collection and Trends collection.
33 | */
34 | ST.Collections.PaginatedCollection = Backbone.Collection.extend({
35 |
36 | initialize: function(attributes, options) {
37 | options = (options || {});
38 |
39 | options.page = options.page || 1;
40 | options.pages = options.pages || 1;
41 | options.total_pages = options.pages;
42 |
43 | // If fetching total page number from data, what's the attribute
44 | // name
45 | options.pages_attribute = options.pages_attribute || null;
46 |
47 | // max number of pages we'll fetch. Null will fetch all.
48 | options.page_max = options.page_max || null;
49 |
50 | // by default append to collection
51 | options.append = options.append || true;
52 |
53 | _.extend(this, options);
54 | },
55 |
56 | clear: function() {
57 |
58 | // remove all models
59 | this.reset([], { silent: true });
60 |
61 | // reset page counts
62 | this.page = 1;
63 | this.pages = 1;
64 | },
65 |
66 | sync: function(method, model, options) {
67 | var type = methodMap[method],
68 | params, extended, fetch, success, i;
69 |
70 | if (this.append) {
71 | options.add = true;
72 | }
73 |
74 | // Default JSON-request options.
75 | params = _.extend({
76 | type: type,
77 | dataType: "json"
78 | }, options);
79 |
80 | // Ensure that we have a URL.
81 | if (!params.url) {
82 | params.url = model.url();
83 | }
84 |
85 | // Ensure that we have the appropriate request data.
86 | if (!params.data && model && (method === "create" || method === "update")) {
87 | params.contentType = "application/json";
88 | params.data = JSON.stringify(model.toJSON());
89 | }
90 |
91 | // For older servers, emulate JSON by encoding the request into an HTML-form.
92 | if (Backbone.emulateJSON) {
93 | params.contentType = "application/x-www-form-urlencoded";
94 | params.data = params.data ? {model: params.data}: {};
95 | }
96 |
97 | // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
98 | // And an `X-HTTP-Method-Override` header.
99 | if (Backbone.emulateHTTP) {
100 | if (type === "PUT" || type === "DELETE") {
101 | if (Backbone.emulateJSON) {
102 | params.data._method = type;
103 | }
104 | params.type = "POST";
105 | params.beforeSend = function(xhr) {
106 | xhr.setRequestHeader("X-HTTP-Method-Override", type);
107 | };
108 | }
109 | }
110 |
111 | // Don't process data on a non-GET request.
112 | if (params.type !== "GET" && !Backbone.emulateJSON) {
113 | params.processData = false;
114 | }
115 |
116 | // make first request, then on success, make all subsequent requests
117 | extended = _.clone(params);
118 | fetch = function(start, end) {
119 | for (i = start; i <= end; i++) {
120 | extended.url = model.url(i);
121 | extended.success = function(data) {
122 | model.page += 1;
123 | if (options.success) {
124 | options.success(data);
125 | }
126 |
127 | // if this is the last page, call the done callback if we have one
128 | if ((model.page - 1) === model.pages && options.done) {
129 | options.done(model);
130 | }
131 | };
132 |
133 | $.ajax(extended);
134 | }
135 | };
136 |
137 | // do we know how many pages we are already fetching? If so
138 | // just make N simultanious requests.
139 | if (model.pages_attribute === null) {
140 | fetch(model.page, model.pages);
141 | } else {
142 | // we are getting total number of pages from the first call
143 | // and then going to fetch everything
144 |
145 | success = (function(fetch) {
146 | return function(data) {
147 |
148 | if (model.page === 1) {
149 | model.pages = Math.min(model.page_max, data[model.pages_attribute]);
150 | model.total_pages = data[model.pages_attribute];
151 | }
152 |
153 | // process first page
154 | options.success(data);
155 | model.page += 1;
156 |
157 | // if this is the last page, call the done callback if we have one
158 | if ((model.page - 1) === model.pages && options.done) {
159 | options.done(model);
160 | }
161 |
162 | fetch(model.page, model.pages);
163 | };
164 | }(fetch));
165 |
166 | params.success = success;
167 | $.ajax(params);
168 | }
169 | }
170 |
171 |
172 | });
173 |
174 | /**
175 | * A collection of startup objects
176 | */
177 | ST.Collections.Startups = ST.Collections.PaginatedCollection.extend({
178 | model: ST.Models.Startup,
179 | url: function(page) {
180 | var tags = ALT.app.currentTags.pluck("id").join(",");
181 | return "http://api.angel.co/1/startups?tag_ids=" + tags +
182 | "&order=popularity" +
183 | "&page=" + (page || this.page) +
184 | "&callback=?";
185 | },
186 |
187 | parse: function(data) {
188 |
189 | // save total number of startups.
190 | if (this.page === 1) {
191 | this.total_startups = data.total;
192 | }
193 |
194 | // Only show visible startups. Hidden ones have no actual
195 | // data.
196 | var visible_data = _.select(data.startups, function(startup) {
197 | return startup.hidden === false;
198 | });
199 |
200 | // cache screenshot count
201 | _.each(visible_data, function(startup) {
202 | startup.screenshot_count = startup.screenshots.length;
203 | });
204 |
205 | return visible_data;
206 | },
207 |
208 | histogram: function(buckets, attribute) {
209 | attribute = (attribute || "follower_count");
210 |
211 | // get all numeric values
212 | var vals = this.pluck(attribute),
213 | // min = _.min(vals),
214 | max = _.max(vals),
215 | // compute step
216 | step = Math.ceil(max / buckets),
217 | // bins
218 | bins = [],
219 | bin = 0,i;
220 | // range = [min, min + step],
221 | // val,
222 |
223 | for (i = 0; i < vals.length; i++) {
224 | bin = Math.floor(vals[i]/step);
225 | bins[bin] = (bins[bin] || 0);
226 | bins[bin]++;
227 | }
228 |
229 | // swap undefined with 0s
230 | for (i = 0; i < bins.length; i++) {
231 | if (bins[i] == null) {
232 | bins[i] = 0;
233 | }
234 | }
235 |
236 | return bins;
237 | },
238 |
239 | markets: function() {
240 | var tags = ALT.app.currentTags.pluck("id");
241 |
242 | return U.frequencyCount(
243 | _.flatten(
244 | _.select(this.pluck("markets"), function(tag) {
245 | return tags.indexOf(tag.id) === -1;
246 | })
247 | ),
248 | "display_name", "id");
249 | }
250 | });
251 |
252 | ST.Trend = Backbone.Model.extend({
253 |
254 | decayScore: function() {
255 | var sum = 0,
256 | arr = this.get("timeseries"),
257 | mean = U.Stats(arr).mean,
258 | i = 0;
259 |
260 | for (; i < arr.length; i++) {
261 | sum += (arr[i] - (U.Stats(arr.slice(0,i)).mean || 0)) * Math.pow(1, -i/mean);
262 | }
263 | return sum || 0;
264 | }
265 | });
266 |
267 | ST.Trends = ST.Collections.PaginatedCollection.extend({
268 | model: ST.Trend,
269 |
270 | url: function(page) {
271 | // based on the page, get a subset of ids to request.
272 | var id_subset = this.ids.slice((page - 1) * this.per_page, page * this.per_page);
273 | return "http://api.angel.co/1/follows/trends?startup_ids=" + id_subset.join(",") + "&callback=?";
274 | },
275 | parse: function(data) {
276 | this.dates = data.dates;
277 | var trends = [];
278 | _.each(data.trends, function(value, key) {
279 | trends.push({
280 | id: key,
281 | timeseries: value
282 | });
283 | });
284 | return trends;
285 | }
286 | });
287 |
288 | /**
289 | * A startup info panel, showing full data.
290 | */
291 | ST.Views.Full = Backbone.View.extend({
292 | template: "panel-startup-full",
293 |
294 | initialize: function(attributes, options) {
295 | // Get compile template from cache
296 | this.template = ALT.app.templates[this.template];
297 | this.el = $(this.el);
298 |
299 | this.model.bind("change", this.render, this);
300 | },
301 |
302 | render: function() {
303 | this.el.html(this.template({ startup: this.model.toJSON() }));
304 |
305 | // make tabs
306 | this.$("#tabs").tabs();
307 |
308 | // render screenshots
309 | this.$("a.screenshot").colorbox({
310 | "rel": "screenshots",
311 | "maxWidth": "960px",
312 | "maxHeight": "800px"
313 | });
314 | return this;
315 | }
316 | });
317 |
318 | /**
319 | * A single startup in the list of startups
320 | */
321 | ST.Views.Mini = Backbone.View.extend({
322 | template: "panel-startup-list-item",
323 | className: "startup-list-item",
324 | tagName: "li",
325 | events: {
326 | "click": "onClick"
327 | },
328 |
329 | initialize: function(attributes, options) {
330 | // Get compile template from cache
331 | this.template = ALT.app.templates[this.template];
332 | },
333 |
334 | render: function() {
335 | $(this.el).append(this.template({ startup: this.model.toJSON()}));
336 | return this;
337 | },
338 |
339 | assignHeight: function(height) {
340 |
341 | // this is a separate method because this needs to happen AFTER
342 | // the item has been appended to a parent.
343 | this.height = height || $(this.el).height();
344 | $(this.el).css({
345 | "height": this.height,
346 | "display": "block",
347 | "position": "relative"
348 | });
349 |
350 | this.top = $(this.el).position().top;
351 | },
352 |
353 | onClick: function(e) {
354 | // On click, we need to rerender the main panel. This will
355 | // happen because when the currentStartup model changes,
356 | // that render method will be called.
357 | if (!ALT.app.currentStartup) {
358 | ALT.app.currentStartup = new ST.Models.Startup();
359 | }
360 | ALT.app.currentStartup.clear({ silent: true });
361 | ALT.app.currentStartup.set(this.model.toJSON(), { silent: true });
362 | ALT.app.currentStartup.fetch({
363 | success: function(model) {
364 | model.change();
365 | }
366 | });
367 | }
368 | });
369 |
370 | /**
371 | * A view of the startup list.
372 | */
373 | ST.Views.List = Backbone.View.extend({
374 |
375 | id: "#startup-list-container",
376 | template: "panel-startup-list",
377 |
378 | initialize: function(attributes) {
379 |
380 | this.el = $(this.id);
381 |
382 | // Get compile template from cache
383 | this.template = ALT.app.templates[this.template];
384 |
385 | // save incoming tags.
386 | this.tags = attributes.tags;
387 |
388 | // Create cache for startup list items
389 | this._startupListItems = {};
390 |
391 | // base render, just container
392 | this.render();
393 |
394 | // if there are any tags, start the list fetching!
395 | if (this.tags.length) {
396 |
397 | // TODO REPLACE THIS WITH A UTIL THING
398 | B.Views.Progressify();
399 |
400 | this.collection.fetch({
401 | success : _.bind(function(collection) {
402 |
403 | // If there are no startups, exit gracefully
404 | if (!collection.length) {
405 | collection.trigger("done");
406 | return B.Views.Done();
407 | }
408 |
409 | if (collection.page === 1) {
410 | // We are cloning the model instead of just referencing it
411 | // because the full startup panel is tied to this one
412 | // model and we are going to reset it with the proper
413 | // model on click (so we don't want to overwrite the first
414 | // model in the actual startup list collection.)
415 | collection.trigger("start");
416 | }
417 |
418 | // trigger that another page was fetched of the collection
419 | collection.trigger("page");
420 |
421 | // When all things are rendered, trigger that we are
422 | // done fetching all pages.
423 | if (collection.page === collection.pages+1 ||
424 | collection.pages === 1) {
425 |
426 | collection.trigger("done");
427 | B.Views.Done();
428 | }
429 |
430 | }, this)
431 | });
432 | }
433 |
434 |
435 | // ---- BIND EVENTS -----
436 |
437 | // When a new item is added to the collection, append another
438 | // list item to it.
439 | this.collection.bind("add", this.bindAdd, this);
440 |
441 | // bind on a resorting of the list operation (from select on metadata panel)
442 | this.collection.bind("alt.resort", this.bindResort, this);
443 |
444 | // when the collection resorts, animate the transition.
445 | this.collection.bind("reset", this.update, this);
446 |
447 | // When the collection is done loading the last page, finish
448 | // whatever rendering we needed to.
449 | this.collection.bind("done", this.finish, this);
450 |
451 | },
452 |
453 | bindAdd: function(model) {
454 |
455 | // create a new startup item and append it.
456 | var startupListItem = new ST.Views.Mini({ model: model });
457 | this._startupListItems[model.id] = startupListItem;
458 | this.$("ul.startup-list").append(startupListItem.render().el);
459 | },
460 |
461 | bindResort: function(by) {
462 |
463 | // redefine collection comparator.
464 | this.collection.comparator = _.bind(function(model) {
465 | if (by === "follower_count" || by === "screenshot_count") {
466 | return -model.get(by);
467 | } else if (by === "followers_over_time") {
468 | return -this.trends.get(model.id).decayScore();
469 | } else {
470 | return model.get(by).toLowerCase();
471 | }
472 | }, this);
473 |
474 | // Resort the collection.
475 | this.collection.sort();
476 |
477 | },
478 |
479 | /**
480 | * Startup list item click selection
481 | */
482 | onClickStartup: function(event) {
483 | if (this.clickedStartup) {
484 | this.clickedStartup.removeClass("selected");
485 | }
486 | this.clickedStartup = $(event.currentTarget);
487 | this.clickedStartup.addClass("selected");
488 | },
489 |
490 | /**
491 | * Cleans up the view and unbinds all events to the collection
492 | */
493 | cleanup: function() {
494 |
495 | // reset to clean slate
496 | this.render();
497 |
498 | // unbind all events!
499 | this.collection.unbind("reset", this.update);
500 | this.collection.unbind("add", this.bindAdd);
501 | this.collection.unbind("done", this.finish);
502 | this.collection.unbind("alt.resort", this.bindResort);
503 | },
504 |
505 | /**
506 | * Reanimates the list sort order
507 | */
508 | update: function(subset) {
509 |
510 | var models = subset || this.collection.models,
511 | pos = 0;
512 |
513 | this.collection.each(function(startup, i, collection) {
514 |
515 | var listItem = this._startupListItems[startup.id],
516 | $listItem = $(listItem.el),
517 | from, to;
518 |
519 | if (models.indexOf(startup) === -1) {
520 |
521 | // if startup is not in the subset, hide its element.
522 | $listItem.hide();
523 |
524 | } else {
525 | // show the element since we might have hidden it in a previous
526 | // situation (like slider movement)
527 | $listItem.show();
528 |
529 | // reposition it.
530 | from = listItem.top;
531 | to = listItem.height * pos;
532 |
533 | if (collection.length < 100) {
534 | $listItem.css({
535 | position: "absolute",
536 | top: from
537 | }).animate({
538 | top: to
539 | }, 500, function() {
540 | // save the top so that we can animate from it in the future
541 | // if it's hidden.
542 | listItem.top = to;
543 | });
544 | } else {
545 | $listItem.css({
546 | position: "absolute",
547 | top: to
548 | });
549 | }
550 | pos++;
551 | }
552 | }, this);
553 | },
554 |
555 | render: function() {
556 |
557 | // Render initial list, empty.
558 | this.el.html(this.template());
559 | },
560 |
561 | getTrends: function() {
562 | var ids = this.collection.pluck("id");
563 |
564 | this.trends = new ST.Trends([], {
565 | ids: ids,
566 | per_page: 50,
567 | pages: Math.ceil(ids.length / 50)
568 | });
569 |
570 | this.trends.fetch({
571 | done: _.bind(function(collection) {
572 | collection.each(function(trend) {
573 |
574 | // find the list view item for it
575 | var startupListViewItem = this._startupListItems[trend.id],
576 | $trend = startupListViewItem.$(".follower_count_trend");
577 |
578 | $trend.sparkline(
579 | trend.get("timeseries"),
580 | {
581 | lineColor: "#222",
582 | fillColor: false
583 | }
584 | );
585 |
586 | $trend.attr({
587 | title: "Decay Score: " + trend.decayScore().toPrecision(2)
588 | });
589 |
590 | }, this);
591 | }, this)
592 | });
593 | },
594 |
595 | finish: function() {
596 |
597 | // added loaded classname
598 | this.$(".startup-list-container").addClass("loaded");
599 |
600 | // Render startup info panel
601 | // it takes care of its own rendering and startup
602 | // extended info fetching.
603 | if (this.collection.length) {
604 | ALT.app.currentStartup = this.collection.at(0).clone();
605 | ALT.app.startupPanel = new B.Views.Panels.StartupInfo({
606 | model: ALT.app.currentStartup
607 | });
608 | } else {
609 | if (ALT.app.startupPanel) {
610 | ALT.app.startupPanel.renderEmpty();
611 | }
612 | }
613 |
614 | this.assignHeights();
615 |
616 | // get time series data
617 | this.getTrends();
618 |
619 | // remove the more button if we're all out of pages
620 | if (this.collection.pages === this.collection.total_pages) {
621 | this.$("#load-more-startups").hide();
622 | }
623 |
624 | // Bind select change.
625 | // we have to wait until all items are loaded.
626 | // TODO look into binding to the ul instead!
627 | this.delegateEvents({
628 | "click li.startup-list-item": "onClickStartup"
629 | });
630 |
631 | },
632 |
633 | assignHeights: function() {
634 |
635 | // find the maxHeight of list element
636 | var maxHeight = Math.max.apply(null,
637 | $(".startup-list-item").map(function (){
638 | return $(this).height();
639 | }).get());
640 |
641 | // Set the height of all list elements to the max. This
642 | // is required for happy sorting.
643 | _.each(this._startupListItems, function(view) {
644 | view.assignHeight(maxHeight);
645 | });
646 | },
647 |
648 | hideCounts: function(type) {
649 | this.$(".counts").hide();
650 |
651 | if (type === "followers_over_time") {
652 | type = "follower_count";
653 | }
654 |
655 | this.$(".counts." + type).show();
656 | }
657 |
658 | });
659 |
660 | })(ALT.module("startup"), ALT.module("utils"), ALT.module("base"));
--------------------------------------------------------------------------------
/app/modules/utils.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Startup Data Trends
3 | * Author Irene Ros (Bocoup)
4 | */
5 | (function(U) {
6 |
7 | /**
8 | * Formats a number into an actual dollar amount.
9 | * @param val The value to convert.
10 | */
11 | U.formatDollarAmount = function(val) {
12 | val = "" + val;
13 | var delimiter = ",",
14 | // remove decimals
15 | amountStr = val.split(".", 2),
16 | // save decimal point
17 | // decimals = amountStr[1] || 0,
18 | // parse amount to int
19 | amount = parseInt(amountStr[0], 10),
20 | // Initialize, no assign
21 | clone, parts, sub;
22 |
23 | if (isNaN(amount)) {
24 |
25 | return "$0";
26 |
27 | } else {
28 | clone = "" + amount;
29 | parts = [];
30 |
31 | // break string into threes.
32 | while (clone.length > 3) {
33 | sub = clone.substr(clone.length-3);
34 | parts.unshift(sub);
35 | clone = clone.substr(0, clone.length-3);
36 | }
37 | // grab any remaining pieces.
38 | if (clone.length > 0) {
39 | parts.unshift(clone);
40 | }
41 |
42 | return "$" + parts.join(delimiter);
43 | }
44 | };
45 |
46 | /**
47 | * Returns the frequency count of an array of objects.
48 | * @param { Array } arr Array of objects
49 | * @param { String } prop The property inside the array objects to count
50 | * @returns { Array } [[key, count], [key, count]].
51 | */
52 | U.frequencyCount = function(arr, prop, id) {
53 | var freq = {},
54 | key;
55 |
56 | _.each(arr, function(obj) {
57 | key = obj[prop];
58 |
59 | freq[key] = (freq[key] || [key, 0]);
60 | freq[key][freq[key].length-1]++;
61 |
62 | if (id != null && freq[key].length < 3) {
63 | freq[key].unshift(obj[id]);
64 | }
65 | });
66 |
67 | return _.sortBy(_.values(freq), function(pair) {
68 | return -pair[pair.length-1];
69 | });
70 | };
71 |
72 | U.remap = function(value, min, max, start, end) {
73 | return ((value / (max - min)) * (end - start)) + start;
74 | };
75 |
76 | U.Stats = function(a) {
77 | var r = {
78 | mean: 0,
79 | variance: 0,
80 | deviation: 0
81 | },
82 | t = a.length,
83 | len = t,
84 | sum = 0,
85 | m;
86 |
87 | // sum up items.
88 | for (; len--;){
89 | sum += a[len];
90 | }
91 |
92 | m = r.mean = sum / t;
93 | for (len = t, sum = 0; len--;){
94 | sum += Math.pow(a[len] - m, 2);
95 | }
96 |
97 | r.deviation = Math.sqrt(r.variance = sum / t);
98 | return r;
99 | };
100 |
101 | U.TagList = Backbone.View.extend({
102 | template: "tag-count-list",
103 |
104 | initialize: function(attributes, options) {
105 | // Get compiled template from cache
106 | this.template = ALT.app.templates[this.template];
107 |
108 | this.tags = options.tags;
109 | if (this.tags.length) {
110 | this.metrics = {
111 | maxFontSize: 19,
112 | minFontSize: 10,
113 | maxCount: this.tags[0][2],
114 | minCount: this.tags[this.tags.length-1][2]
115 | };
116 | this.tag_template = ALT.app.templates["single-tag-count"];
117 | }
118 | },
119 |
120 | render: function() {
121 |
122 | this.el = $(this.template({
123 | message : this.tags.length ?
124 | "Matching startups also tagged with..." :
125 | "No startups found"
126 | }));
127 |
128 | var count = Math.min(this.tags.length, 15),
129 | otherTagList = ALT.app.currentTags.pluck("id"),
130 | i = 0,
131 | tag, tagEl, fontSize;
132 |
133 | for ( ; i < count; i++) {
134 | tag = this.tags[i];
135 |
136 | // don't bother painting the selected tag.
137 | if (otherTagList.indexOf(tag[0]) === -1) {
138 | fontSize = U.remap(
139 | tag[2],
140 | this.metrics.minCount,
141 | this.metrics.maxCount,
142 | this.metrics.minFontSize,
143 | this.metrics.maxFontSize
144 | );
145 |
146 | tagEl = $(
147 | this.tag_template({
148 | tag: {
149 | id: tag[0],
150 | name: tag[1],
151 | count: tag[2],
152 | url: _.union(otherTagList, tag[0]).join(",")
153 | }
154 | })
155 | ).css({
156 | fontSize: fontSize
157 | });
158 |
159 | $(this.$("ul.taglist")).append(tagEl);
160 | }
161 | }
162 | return this;
163 | },
164 |
165 | cleanup: function() {
166 | this.el = $(this.template());
167 | }
168 | });
169 |
170 | })(ALT.module("utils"));
--------------------------------------------------------------------------------
/app/pages/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Startup Data Trends
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | ↓ Start by searching for a location, market, or both!
54 |
55 |
56 |
57 |
Loading...
58 |
59 |
60 |
61 |
62 |
Searching startups...
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
83 |
84 |
85 |
86 |
What is Startup Data Trends
87 |
88 | Startup Data Trends is a way to browse the publicly visible startups on
89 | AngelList . Here, you can search for startups
90 | in a specific location and/or market.
91 |
92 |
93 |
94 | Filtering
95 | The returned startups can be filtered by their follower counts, screenshot counts, alphabetic order and a
96 | ranking function based on followers over time.
97 |
98 |
99 |
100 | Metadata
101 | Alongside the startups, you can see some key metadata about the
102 | search itself, such as the average amount being raised by startups that match it, and
103 | the average public valuation.
104 |
105 |
106 |
107 | Try it out!
108 | Start searching by typing your desired location and/or market above or try one of
109 | the following searches:
110 |
111 |
112 | All Startups in Cambridge, MA
113 | All Startups in the Analytics Market.
114 |
115 |
116 | Code?
117 | Yes please! We've open sourced this application, so fork
118 | StartupDataTrends on Github !
119 | Pull requests and tickets are welcome.
120 |
121 |
Bugs? Questions? Suggestions? Complaints?
122 |
123 | Please join the conversation on github →
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
145 |
146 |
147 |
148 |
149 |
150 |
162 |
163 |
--------------------------------------------------------------------------------
/app/templates/metadata-search.html:
--------------------------------------------------------------------------------
1 |
2 |
35 |
--------------------------------------------------------------------------------
/app/templates/metadata-valuation.html:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 | Average Amount Raised:
19 |
20 |
21 | Average Valuation:
22 |
23 |
24 |
25 |
26 |
27 |
<%= stats.raising.amount %>
28 |
29 |
30 | Based on <%= stats.raising.data_points || 0 %> data points.
31 |
32 |
33 |
34 |
35 |
<%= stats.pre_money.amount %>
36 |
37 |
38 | Based on <%= stats.pre_money.data_points || 0 %> data points.
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/templates/panel-startup-full.html:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
<%= startup.name %>
12 |
<%= startup.high_concept %>
13 |
14 |
15 | <% if (startup.twitter_url) { %>
16 |
17 | <% } %>
18 |
Website
19 |
Profile
20 |
21 |
22 |
23 |
24 | <% _.each(_.union(startup.locations, startup.markets), function(tag) { %>
25 |
26 | <% }); %>
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | <%= startup.product_desc %>
40 |
41 |
42 |
43 | <% if (startup.screenshots.length) { %>
44 |
Showing <%= startup.screenshots.length %> screenshots:
45 |
46 |
Click an image to see a larger version
47 |
48 |
49 | <% _.each(startup.screenshots, function(screenshot) { %>
50 |
51 |
52 |
53 |
54 | <% }); %>
55 |
56 | <% } else { %>
57 |
This startup has posted no screenshots
58 | <% } %>
59 |
60 |
--------------------------------------------------------------------------------
/app/templates/panel-startup-list-item.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
<%= startup.name %>
6 |
7 |
8 |
9 | <%= startup.follower_count %>
10 |
11 |
12 |
13 |
14 | Followers
15 |
16 |
17 |
18 |
19 |
<%= startup.screenshot_count %>
20 |
21 | Screenshots
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/templates/panel-startup-list.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/templates/search-container.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/templates/single-search-container.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/templates/single-search-item.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/app/templates/single-tag-count.html:
--------------------------------------------------------------------------------
1 |
2 | <%= tag.count %>
3 |
4 |
--------------------------------------------------------------------------------
/app/templates/tag-count-list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= message %>
4 |
5 |
7 |
--------------------------------------------------------------------------------
/assets/css/colorbox.css:
--------------------------------------------------------------------------------
1 | /*
2 | ColorBox Core Style:
3 | The following CSS is consistent between example themes and should not be altered.
4 | */
5 | #colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;}
6 | #cboxOverlay{position:fixed; width:100%; height:100%;}
7 | #cboxMiddleLeft, #cboxBottomLeft{clear:left;}
8 | #cboxContent{position:relative;}
9 | #cboxLoadedContent{overflow:auto;}
10 | #cboxTitle{margin:0;}
11 | #cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;}
12 | #cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
13 | .cboxPhoto{float:left; margin:auto; border:0; display:block;}
14 | .cboxIframe{width:100%; height:100%; display:block; border:0;}
15 |
16 | /*
17 | User Style:
18 | Change the following styles to modify the appearance of ColorBox. They are
19 | ordered & tabbed in a way that represents the nesting of the generated HTML.
20 | */
21 | #cboxOverlay{background:#fff;}
22 | #colorbox{}
23 | #cboxTopLeft{width:25px; height:25px; background:url(images/border1.png) no-repeat 0 0;}
24 | #cboxTopCenter{height:25px; background:url(images/border1.png) repeat-x 0 -50px;}
25 | #cboxTopRight{width:25px; height:25px; background:url(images/border1.png) no-repeat -25px 0;}
26 | #cboxBottomLeft{width:25px; height:25px; background:url(images/border1.png) no-repeat 0 -25px;}
27 | #cboxBottomCenter{height:25px; background:url(images/border1.png) repeat-x 0 -75px;}
28 | #cboxBottomRight{width:25px; height:25px; background:url(images/border1.png) no-repeat -25px -25px;}
29 | #cboxMiddleLeft{width:25px; background:url(images/border2.png) repeat-y 0 0;}
30 | #cboxMiddleRight{width:25px; background:url(images/border2.png) repeat-y -25px 0;}
31 | #cboxContent{background:#fff; overflow:hidden;}
32 | .cboxIframe{background:#fff;}
33 | #cboxError{padding:50px; border:1px solid #ccc;}
34 | #cboxLoadedContent{margin-bottom:20px;}
35 | #cboxTitle{position:absolute; bottom:0px; left:0; text-align:center; width:100%; color:#999;}
36 | #cboxCurrent{position:absolute; bottom:0px; left:100px; color:#999;}
37 | #cboxSlideshow{position:absolute; bottom:0px; right:42px; color:#444;}
38 | #cboxPrevious{position:absolute; bottom:0px; left:0; color:#444;}
39 | #cboxNext{position:absolute; bottom:0px; left:63px; color:#444;}
40 | #cboxLoadingOverlay{background:#fff url(images/loading.gif) no-repeat 5px 5px;}
41 | #cboxClose{position:absolute; bottom:0; right:0; display:block; color:#444;}
42 |
43 | /*
44 | The following fixes a problem where IE7 and IE8 replace a PNG's alpha transparency with a black fill
45 | when an alpha filter (opacity change) is set on the element or ancestor element. This style is not applied to or needed in IE9.
46 | See: http://jacklmoore.com/notes/ie-transparency-problems/
47 | */
48 | .cboxIE #cboxTopLeft,
49 | .cboxIE #cboxTopCenter,
50 | .cboxIE #cboxTopRight,
51 | .cboxIE #cboxBottomLeft,
52 | .cboxIE #cboxBottomCenter,
53 | .cboxIE #cboxBottomRight,
54 | .cboxIE #cboxMiddleLeft,
55 | .cboxIE #cboxMiddleRight {
56 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF);
57 | }
58 |
59 | /*
60 | The following provides PNG transparency support for IE6
61 | Feel free to remove this and the /ie6/ directory if you have dropped IE6 support.
62 | */
63 | .cboxIE6 #cboxTopLeft{background:url(images/ie6/borderTopLeft.png);}
64 | .cboxIE6 #cboxTopCenter{background:url(images/ie6/borderTopCenter.png);}
65 | .cboxIE6 #cboxTopRight{background:url(images/ie6/borderTopRight.png);}
66 | .cboxIE6 #cboxBottomLeft{background:url(images/ie6/borderBottomLeft.png);}
67 | .cboxIE6 #cboxBottomCenter{background:url(images/ie6/borderBottomCenter.png);}
68 | .cboxIE6 #cboxBottomRight{background:url(images/ie6/borderBottomRight.png);}
69 | .cboxIE6 #cboxMiddleLeft{background:url(images/ie6/borderMiddleLeft.png);}
70 | .cboxIE6 #cboxMiddleRight{background:url(images/ie6/borderMiddleRight.png);}
71 |
72 | .cboxIE6 #cboxTopLeft,
73 | .cboxIE6 #cboxTopCenter,
74 | .cboxIE6 #cboxTopRight,
75 | .cboxIE6 #cboxBottomLeft,
76 | .cboxIE6 #cboxBottomCenter,
77 | .cboxIE6 #cboxBottomRight,
78 | .cboxIE6 #cboxMiddleLeft,
79 | .cboxIE6 #cboxMiddleRight {
80 | _behavior: expression(this.src = this.src ? this.src : this.currentStyle.backgroundImage.split('"')[1], this.style.background = "none", this.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + this.src + ", sizingMethod='scale')");
81 | }
82 |
--------------------------------------------------------------------------------
/assets/css/images/border1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/border1.png
--------------------------------------------------------------------------------
/assets/css/images/border2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/border2.png
--------------------------------------------------------------------------------
/assets/css/images/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/loading.gif
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_diagonals-thick_20_666666_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-bg_diagonals-thick_20_666666_40x40.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_flat_10_000000_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-bg_flat_10_000000_40x100.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_glass_100_f6f6f6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-bg_glass_100_f6f6f6_1x400.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_glass_100_fdf5ce_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-bg_glass_100_fdf5ce_1x400.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
--------------------------------------------------------------------------------
/assets/css/images/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/assets/css/images/ui-icons_228ef1_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-icons_228ef1_256x240.png
--------------------------------------------------------------------------------
/assets/css/images/ui-icons_ef8c08_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-icons_ef8c08_256x240.png
--------------------------------------------------------------------------------
/assets/css/images/ui-icons_ffd27a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-icons_ffd27a_256x240.png
--------------------------------------------------------------------------------
/assets/css/images/ui-icons_ffffff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/images/ui-icons_ffffff_256x240.png
--------------------------------------------------------------------------------
/assets/css/jquery-ui-1.8.16.custom.css:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery UI CSS Framework 1.8.16
3 | *
4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | * http://jquery.org/license
7 | *
8 | * http://docs.jquery.com/UI/Theming/API
9 | */
10 |
11 | /* Layout helpers
12 | ----------------------------------*/
13 | .ui-helper-hidden { display: none; }
14 | .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
15 | .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
16 | .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
17 | .ui-helper-clearfix { display: inline-block; }
18 | /* required comment for clearfix to work in Opera \*/
19 | * html .ui-helper-clearfix { height:1%; }
20 | .ui-helper-clearfix { display:block; }
21 | /* end clearfix */
22 | .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
23 |
24 |
25 | /* Interaction Cues
26 | ----------------------------------*/
27 | .ui-state-disabled { cursor: default !important; }
28 |
29 |
30 | /* Icons
31 | ----------------------------------*/
32 |
33 | /* states and images */
34 | .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
35 |
36 |
37 | /* Misc visuals
38 | ----------------------------------*/
39 |
40 | /* Overlays */
41 | .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
42 |
43 |
44 | /*
45 | * jQuery UI CSS Framework 1.8.16
46 | *
47 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
48 | * Dual licensed under the MIT or GPL Version 2 licenses.
49 | * http://jquery.org/license
50 | *
51 | * http://docs.jquery.com/UI/Theming/API
52 | *
53 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Helvetica,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=2px&bgColorHeader=dddddd&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=50&borderColorHeader=dddddd&fcHeader=444444&iconColorHeader=0073ea&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=dddddd&fcContent=444444&iconColorContent=ff0084&bgColorDefault=f6f6f6&bgTextureDefault=03_highlight_soft.png&bgImgOpacityDefault=100&borderColorDefault=dddddd&fcDefault=0073ea&iconColorDefault=666666&bgColorHover=0073ea&bgTextureHover=03_highlight_soft.png&bgImgOpacityHover=25&borderColorHover=0073ea&fcHover=ffffff&iconColorHover=ffffff&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=dddddd&fcActive=ff0084&iconColorActive=454545&bgColorHighlight=ffffff&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=cccccc&fcHighlight=444444&iconColorHighlight=0073ea&bgColorError=ffffff&bgTextureError=01_flat.png&bgImgOpacityError=55&borderColorError=ff0084&fcError=222222&iconColorError=ff0084&bgColorOverlay=eeeeee&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=80&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=60&thicknessShadow=4px&offsetTopShadow=-4px&offsetLeftShadow=-4px&cornerRadiusShadow=0px
54 | */
55 |
56 |
57 | /* Component containers
58 | ----------------------------------*/
59 | .ui-widget { font-family: Helvetica, Arial, sans-serif; font-size: 1.1em; }
60 | .ui-widget .ui-widget { font-size: 1em; }
61 | .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Helvetica, Arial, sans-serif; font-size: 1em; }
62 | .ui-widget-content { border: 1px solid #dddddd; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #444444; }
63 | .ui-widget-content a { color: #444444; }
64 | .ui-widget-header { border: 1px solid #dddddd; background: #dddddd url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #444444; font-weight: bold; }
65 | .ui-widget-header a { color: #444444; }
66 |
67 | /* Interaction states
68 | ----------------------------------*/
69 | .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #dddddd; background: #f6f6f6 url(images/ui-bg_highlight-soft_100_f6f6f6_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #0073ea; }
70 | .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #0073ea; text-decoration: none; }
71 | .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #0073ea; background: #0073ea url(images/ui-bg_highlight-soft_25_0073ea_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #ffffff; }
72 | .ui-state-hover a, .ui-state-hover a:hover { color: #ffffff; text-decoration: none; }
73 | .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #dddddd; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #ff0084; }
74 | .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #ff0084; text-decoration: none; }
75 | .ui-widget :active { outline: none; }
76 |
77 | /* Interaction Cues
78 | ----------------------------------*/
79 | .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #cccccc; background: #ffffff url(images/ui-bg_flat_55_ffffff_40x100.png) 50% 50% repeat-x; color: #444444; }
80 | .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #444444; }
81 | .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #ff0084; background: #ffffff url(images/ui-bg_flat_55_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
82 | .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #222222; }
83 | .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #222222; }
84 | .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
85 | .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
86 | .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
87 |
88 | /* Icons
89 | ----------------------------------*/
90 |
91 | /* states and images */
92 | .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
93 | .ui-widget-content .ui-icon {background-image: url(images/ui-icons_ff0084_256x240.png); }
94 | .ui-widget-header .ui-icon {background-image: url(images/ui-icons_0073ea_256x240.png); }
95 | .ui-state-default .ui-icon { background-image: url(images/ui-icons_666666_256x240.png); }
96 | .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
97 | .ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
98 | .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_0073ea_256x240.png); }
99 | .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ff0084_256x240.png); }
100 |
101 | /* positioning */
102 | .ui-icon-carat-1-n { background-position: 0 0; }
103 | .ui-icon-carat-1-ne { background-position: -16px 0; }
104 | .ui-icon-carat-1-e { background-position: -32px 0; }
105 | .ui-icon-carat-1-se { background-position: -48px 0; }
106 | .ui-icon-carat-1-s { background-position: -64px 0; }
107 | .ui-icon-carat-1-sw { background-position: -80px 0; }
108 | .ui-icon-carat-1-w { background-position: -96px 0; }
109 | .ui-icon-carat-1-nw { background-position: -112px 0; }
110 | .ui-icon-carat-2-n-s { background-position: -128px 0; }
111 | .ui-icon-carat-2-e-w { background-position: -144px 0; }
112 | .ui-icon-triangle-1-n { background-position: 0 -16px; }
113 | .ui-icon-triangle-1-ne { background-position: -16px -16px; }
114 | .ui-icon-triangle-1-e { background-position: -32px -16px; }
115 | .ui-icon-triangle-1-se { background-position: -48px -16px; }
116 | .ui-icon-triangle-1-s { background-position: -64px -16px; }
117 | .ui-icon-triangle-1-sw { background-position: -80px -16px; }
118 | .ui-icon-triangle-1-w { background-position: -96px -16px; }
119 | .ui-icon-triangle-1-nw { background-position: -112px -16px; }
120 | .ui-icon-triangle-2-n-s { background-position: -128px -16px; }
121 | .ui-icon-triangle-2-e-w { background-position: -144px -16px; }
122 | .ui-icon-arrow-1-n { background-position: 0 -32px; }
123 | .ui-icon-arrow-1-ne { background-position: -16px -32px; }
124 | .ui-icon-arrow-1-e { background-position: -32px -32px; }
125 | .ui-icon-arrow-1-se { background-position: -48px -32px; }
126 | .ui-icon-arrow-1-s { background-position: -64px -32px; }
127 | .ui-icon-arrow-1-sw { background-position: -80px -32px; }
128 | .ui-icon-arrow-1-w { background-position: -96px -32px; }
129 | .ui-icon-arrow-1-nw { background-position: -112px -32px; }
130 | .ui-icon-arrow-2-n-s { background-position: -128px -32px; }
131 | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
132 | .ui-icon-arrow-2-e-w { background-position: -160px -32px; }
133 | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
134 | .ui-icon-arrowstop-1-n { background-position: -192px -32px; }
135 | .ui-icon-arrowstop-1-e { background-position: -208px -32px; }
136 | .ui-icon-arrowstop-1-s { background-position: -224px -32px; }
137 | .ui-icon-arrowstop-1-w { background-position: -240px -32px; }
138 | .ui-icon-arrowthick-1-n { background-position: 0 -48px; }
139 | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
140 | .ui-icon-arrowthick-1-e { background-position: -32px -48px; }
141 | .ui-icon-arrowthick-1-se { background-position: -48px -48px; }
142 | .ui-icon-arrowthick-1-s { background-position: -64px -48px; }
143 | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
144 | .ui-icon-arrowthick-1-w { background-position: -96px -48px; }
145 | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
146 | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
147 | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
148 | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
149 | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
150 | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
151 | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
152 | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
153 | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
154 | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
155 | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
156 | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
157 | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
158 | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
159 | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
160 | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
161 | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
162 | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
163 | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
164 | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
165 | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
166 | .ui-icon-arrow-4 { background-position: 0 -80px; }
167 | .ui-icon-arrow-4-diag { background-position: -16px -80px; }
168 | .ui-icon-extlink { background-position: -32px -80px; }
169 | .ui-icon-newwin { background-position: -48px -80px; }
170 | .ui-icon-refresh { background-position: -64px -80px; }
171 | .ui-icon-shuffle { background-position: -80px -80px; }
172 | .ui-icon-transfer-e-w { background-position: -96px -80px; }
173 | .ui-icon-transferthick-e-w { background-position: -112px -80px; }
174 | .ui-icon-folder-collapsed { background-position: 0 -96px; }
175 | .ui-icon-folder-open { background-position: -16px -96px; }
176 | .ui-icon-document { background-position: -32px -96px; }
177 | .ui-icon-document-b { background-position: -48px -96px; }
178 | .ui-icon-note { background-position: -64px -96px; }
179 | .ui-icon-mail-closed { background-position: -80px -96px; }
180 | .ui-icon-mail-open { background-position: -96px -96px; }
181 | .ui-icon-suitcase { background-position: -112px -96px; }
182 | .ui-icon-comment { background-position: -128px -96px; }
183 | .ui-icon-person { background-position: -144px -96px; }
184 | .ui-icon-print { background-position: -160px -96px; }
185 | .ui-icon-trash { background-position: -176px -96px; }
186 | .ui-icon-locked { background-position: -192px -96px; }
187 | .ui-icon-unlocked { background-position: -208px -96px; }
188 | .ui-icon-bookmark { background-position: -224px -96px; }
189 | .ui-icon-tag { background-position: -240px -96px; }
190 | .ui-icon-home { background-position: 0 -112px; }
191 | .ui-icon-flag { background-position: -16px -112px; }
192 | .ui-icon-calendar { background-position: -32px -112px; }
193 | .ui-icon-cart { background-position: -48px -112px; }
194 | .ui-icon-pencil { background-position: -64px -112px; }
195 | .ui-icon-clock { background-position: -80px -112px; }
196 | .ui-icon-disk { background-position: -96px -112px; }
197 | .ui-icon-calculator { background-position: -112px -112px; }
198 | .ui-icon-zoomin { background-position: -128px -112px; }
199 | .ui-icon-zoomout { background-position: -144px -112px; }
200 | .ui-icon-search { background-position: -160px -112px; }
201 | .ui-icon-wrench { background-position: -176px -112px; }
202 | .ui-icon-gear { background-position: -192px -112px; }
203 | .ui-icon-heart { background-position: -208px -112px; }
204 | .ui-icon-star { background-position: -224px -112px; }
205 | .ui-icon-link { background-position: -240px -112px; }
206 | .ui-icon-cancel { background-position: 0 -128px; }
207 | .ui-icon-plus { background-position: -16px -128px; }
208 | .ui-icon-plusthick { background-position: -32px -128px; }
209 | .ui-icon-minus { background-position: -48px -128px; }
210 | .ui-icon-minusthick { background-position: -64px -128px; }
211 | .ui-icon-close { background-position: -80px -128px; }
212 | .ui-icon-closethick { background-position: -96px -128px; }
213 | .ui-icon-key { background-position: -112px -128px; }
214 | .ui-icon-lightbulb { background-position: -128px -128px; }
215 | .ui-icon-scissors { background-position: -144px -128px; }
216 | .ui-icon-clipboard { background-position: -160px -128px; }
217 | .ui-icon-copy { background-position: -176px -128px; }
218 | .ui-icon-contact { background-position: -192px -128px; }
219 | .ui-icon-image { background-position: -208px -128px; }
220 | .ui-icon-video { background-position: -224px -128px; }
221 | .ui-icon-script { background-position: -240px -128px; }
222 | .ui-icon-alert { background-position: 0 -144px; }
223 | .ui-icon-info { background-position: -16px -144px; }
224 | .ui-icon-notice { background-position: -32px -144px; }
225 | .ui-icon-help { background-position: -48px -144px; }
226 | .ui-icon-check { background-position: -64px -144px; }
227 | .ui-icon-bullet { background-position: -80px -144px; }
228 | .ui-icon-radio-off { background-position: -96px -144px; }
229 | .ui-icon-radio-on { background-position: -112px -144px; }
230 | .ui-icon-pin-w { background-position: -128px -144px; }
231 | .ui-icon-pin-s { background-position: -144px -144px; }
232 | .ui-icon-play { background-position: 0 -160px; }
233 | .ui-icon-pause { background-position: -16px -160px; }
234 | .ui-icon-seek-next { background-position: -32px -160px; }
235 | .ui-icon-seek-prev { background-position: -48px -160px; }
236 | .ui-icon-seek-end { background-position: -64px -160px; }
237 | .ui-icon-seek-start { background-position: -80px -160px; }
238 | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
239 | .ui-icon-seek-first { background-position: -80px -160px; }
240 | .ui-icon-stop { background-position: -96px -160px; }
241 | .ui-icon-eject { background-position: -112px -160px; }
242 | .ui-icon-volume-off { background-position: -128px -160px; }
243 | .ui-icon-volume-on { background-position: -144px -160px; }
244 | .ui-icon-power { background-position: 0 -176px; }
245 | .ui-icon-signal-diag { background-position: -16px -176px; }
246 | .ui-icon-signal { background-position: -32px -176px; }
247 | .ui-icon-battery-0 { background-position: -48px -176px; }
248 | .ui-icon-battery-1 { background-position: -64px -176px; }
249 | .ui-icon-battery-2 { background-position: -80px -176px; }
250 | .ui-icon-battery-3 { background-position: -96px -176px; }
251 | .ui-icon-circle-plus { background-position: 0 -192px; }
252 | .ui-icon-circle-minus { background-position: -16px -192px; }
253 | .ui-icon-circle-close { background-position: -32px -192px; }
254 | .ui-icon-circle-triangle-e { background-position: -48px -192px; }
255 | .ui-icon-circle-triangle-s { background-position: -64px -192px; }
256 | .ui-icon-circle-triangle-w { background-position: -80px -192px; }
257 | .ui-icon-circle-triangle-n { background-position: -96px -192px; }
258 | .ui-icon-circle-arrow-e { background-position: -112px -192px; }
259 | .ui-icon-circle-arrow-s { background-position: -128px -192px; }
260 | .ui-icon-circle-arrow-w { background-position: -144px -192px; }
261 | .ui-icon-circle-arrow-n { background-position: -160px -192px; }
262 | .ui-icon-circle-zoomin { background-position: -176px -192px; }
263 | .ui-icon-circle-zoomout { background-position: -192px -192px; }
264 | .ui-icon-circle-check { background-position: -208px -192px; }
265 | .ui-icon-circlesmall-plus { background-position: 0 -208px; }
266 | .ui-icon-circlesmall-minus { background-position: -16px -208px; }
267 | .ui-icon-circlesmall-close { background-position: -32px -208px; }
268 | .ui-icon-squaresmall-plus { background-position: -48px -208px; }
269 | .ui-icon-squaresmall-minus { background-position: -64px -208px; }
270 | .ui-icon-squaresmall-close { background-position: -80px -208px; }
271 | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
272 | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
273 | .ui-icon-grip-solid-vertical { background-position: -32px -224px; }
274 | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
275 | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
276 | .ui-icon-grip-diagonal-se { background-position: -80px -224px; }
277 |
278 |
279 | /* Misc visuals
280 | ----------------------------------*/
281 |
282 | /* Corner radius */
283 | .ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 2px; -webkit-border-top-left-radius: 2px; -khtml-border-top-left-radius: 2px; border-top-left-radius: 2px; }
284 | .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 2px; -webkit-border-top-right-radius: 2px; -khtml-border-top-right-radius: 2px; border-top-right-radius: 2px; }
285 | .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 2px; -webkit-border-bottom-left-radius: 2px; -khtml-border-bottom-left-radius: 2px; border-bottom-left-radius: 2px; }
286 | .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 2px; -webkit-border-bottom-right-radius: 2px; -khtml-border-bottom-right-radius: 2px; border-bottom-right-radius: 2px; }
287 |
288 | /* Overlays */
289 | .ui-widget-overlay { background: #eeeeee url(images/ui-bg_flat_0_eeeeee_40x100.png) 50% 50% repeat-x; opacity: .80;filter:Alpha(Opacity=80); }
290 | .ui-widget-shadow { margin: -4px 0 0 -4px; padding: 4px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .60;filter:Alpha(Opacity=60); -moz-border-radius: 0px; -khtml-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; }/*
291 | * jQuery UI Autocomplete 1.8.16
292 | *
293 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
294 | * Dual licensed under the MIT or GPL Version 2 licenses.
295 | * http://jquery.org/license
296 | *
297 | * http://docs.jquery.com/UI/Autocomplete#theming
298 | */
299 | .ui-autocomplete { position: absolute; cursor: default; }
300 |
301 | /* workarounds */
302 | * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
303 |
304 | /*
305 | * jQuery UI Menu 1.8.16
306 | *
307 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
308 | * Dual licensed under the MIT or GPL Version 2 licenses.
309 | * http://jquery.org/license
310 | *
311 | * http://docs.jquery.com/UI/Menu#theming
312 | */
313 | .ui-menu {
314 | list-style:none;
315 | padding: 2px;
316 | margin: 0;
317 | display:block;
318 | float: left;
319 | }
320 | .ui-menu .ui-menu {
321 | margin-top: -3px;
322 | }
323 | .ui-menu .ui-menu-item {
324 | margin:0;
325 | padding: 0;
326 | zoom: 1;
327 | float: left;
328 | clear: left;
329 | width: 100%;
330 | }
331 | .ui-menu .ui-menu-item a {
332 | text-decoration:none;
333 | display:block;
334 | padding:.2em .4em;
335 | line-height:1.5;
336 | zoom:1;
337 | }
338 | .ui-menu .ui-menu-item a.ui-state-hover,
339 | .ui-menu .ui-menu-item a.ui-state-active {
340 | font-weight: normal;
341 | margin: -1px;
342 | }
343 | /*
344 | * jQuery UI Tabs 1.8.16
345 | *
346 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
347 | * Dual licensed under the MIT or GPL Version 2 licenses.
348 | * http://jquery.org/license
349 | *
350 | * http://docs.jquery.com/UI/Tabs#theming
351 | */
352 | .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
353 | .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
354 | .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
355 | .ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
356 | .ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
357 | .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
358 | .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
359 | .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
360 | .ui-tabs .ui-tabs-hide { display: none !important; }
361 | /*
362 | * jQuery UI Progressbar 1.8.16
363 | *
364 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
365 | * Dual licensed under the MIT or GPL Version 2 licenses.
366 | * http://jquery.org/license
367 | *
368 | * http://docs.jquery.com/UI/Progressbar#theming
369 | */
370 | .ui-progressbar { height:2em; text-align: left; }
371 | .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
372 | /*
373 | * jQuery UI Slider 1.8.16
374 | *
375 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
376 | * Dual licensed under the MIT or GPL Version 2 licenses.
377 | * http://jquery.org/license
378 | *
379 | * http://docs.jquery.com/UI/Slider#theming
380 | */
381 | .ui-slider { position: relative; text-align: left; }
382 | .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
383 | .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
384 |
385 | .ui-slider-horizontal { height: .8em; }
386 | .ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
387 | .ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
388 | .ui-slider-horizontal .ui-slider-range-min { left: 0; }
389 | .ui-slider-horizontal .ui-slider-range-max { right: 0; }
390 |
391 | .ui-slider-vertical { width: .8em; height: 100px; }
392 | .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
393 | .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
394 | .ui-slider-vertical .ui-slider-range-min { bottom: 0; }
395 | .ui-slider-vertical .ui-slider-range-max { top: 0; }
--------------------------------------------------------------------------------
/assets/css/jquery-ui-1.8.16.custom_default.css:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery UI CSS Framework 1.8.16
3 | *
4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | * http://jquery.org/license
7 | *
8 | * http://docs.jquery.com/UI/Theming/API
9 | */
10 |
11 | /* Layout helpers
12 | ----------------------------------*/
13 | .ui-helper-hidden { display: none; }
14 | .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
15 | .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
16 | .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
17 | .ui-helper-clearfix { display: inline-block; }
18 | /* required comment for clearfix to work in Opera \*/
19 | * html .ui-helper-clearfix { height:1%; }
20 | .ui-helper-clearfix { display:block; }
21 | /* end clearfix */
22 | .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
23 |
24 |
25 | /* Interaction Cues
26 | ----------------------------------*/
27 | .ui-state-disabled { cursor: default !important; }
28 |
29 |
30 | /* Icons
31 | ----------------------------------*/
32 |
33 | /* states and images */
34 | .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
35 |
36 |
37 | /* Misc visuals
38 | ----------------------------------*/
39 |
40 | /* Overlays */
41 | .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
42 |
43 |
44 | /*
45 | * jQuery UI CSS Framework 1.8.16
46 | *
47 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
48 | * Dual licensed under the MIT or GPL Version 2 licenses.
49 | * http://jquery.org/license
50 | *
51 | * http://docs.jquery.com/UI/Theming/API
52 | *
53 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
54 | */
55 |
56 |
57 | /* Component containers
58 | ----------------------------------*/
59 | .ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; }
60 | .ui-widget .ui-widget { font-size: 1em; }
61 | .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; }
62 | .ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; }
63 | .ui-widget-content a { color: #333333; }
64 | .ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
65 | .ui-widget-header a { color: #ffffff; }
66 |
67 | /* Interaction states
68 | ----------------------------------*/
69 | .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; }
70 | .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; }
71 | .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; }
72 | .ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; }
73 | .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; }
74 | .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; }
75 | .ui-widget :active { outline: none; }
76 |
77 | /* Interaction Cues
78 | ----------------------------------*/
79 | .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; }
80 | .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
81 | .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; }
82 | .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
83 | .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
84 | .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
85 | .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
86 | .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
87 |
88 | /* Icons
89 | ----------------------------------*/
90 |
91 | /* states and images */
92 | .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
93 | .ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
94 | .ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
95 | .ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); }
96 | .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
97 | .ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
98 | .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); }
99 | .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); }
100 |
101 | /* positioning */
102 | .ui-icon-carat-1-n { background-position: 0 0; }
103 | .ui-icon-carat-1-ne { background-position: -16px 0; }
104 | .ui-icon-carat-1-e { background-position: -32px 0; }
105 | .ui-icon-carat-1-se { background-position: -48px 0; }
106 | .ui-icon-carat-1-s { background-position: -64px 0; }
107 | .ui-icon-carat-1-sw { background-position: -80px 0; }
108 | .ui-icon-carat-1-w { background-position: -96px 0; }
109 | .ui-icon-carat-1-nw { background-position: -112px 0; }
110 | .ui-icon-carat-2-n-s { background-position: -128px 0; }
111 | .ui-icon-carat-2-e-w { background-position: -144px 0; }
112 | .ui-icon-triangle-1-n { background-position: 0 -16px; }
113 | .ui-icon-triangle-1-ne { background-position: -16px -16px; }
114 | .ui-icon-triangle-1-e { background-position: -32px -16px; }
115 | .ui-icon-triangle-1-se { background-position: -48px -16px; }
116 | .ui-icon-triangle-1-s { background-position: -64px -16px; }
117 | .ui-icon-triangle-1-sw { background-position: -80px -16px; }
118 | .ui-icon-triangle-1-w { background-position: -96px -16px; }
119 | .ui-icon-triangle-1-nw { background-position: -112px -16px; }
120 | .ui-icon-triangle-2-n-s { background-position: -128px -16px; }
121 | .ui-icon-triangle-2-e-w { background-position: -144px -16px; }
122 | .ui-icon-arrow-1-n { background-position: 0 -32px; }
123 | .ui-icon-arrow-1-ne { background-position: -16px -32px; }
124 | .ui-icon-arrow-1-e { background-position: -32px -32px; }
125 | .ui-icon-arrow-1-se { background-position: -48px -32px; }
126 | .ui-icon-arrow-1-s { background-position: -64px -32px; }
127 | .ui-icon-arrow-1-sw { background-position: -80px -32px; }
128 | .ui-icon-arrow-1-w { background-position: -96px -32px; }
129 | .ui-icon-arrow-1-nw { background-position: -112px -32px; }
130 | .ui-icon-arrow-2-n-s { background-position: -128px -32px; }
131 | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
132 | .ui-icon-arrow-2-e-w { background-position: -160px -32px; }
133 | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
134 | .ui-icon-arrowstop-1-n { background-position: -192px -32px; }
135 | .ui-icon-arrowstop-1-e { background-position: -208px -32px; }
136 | .ui-icon-arrowstop-1-s { background-position: -224px -32px; }
137 | .ui-icon-arrowstop-1-w { background-position: -240px -32px; }
138 | .ui-icon-arrowthick-1-n { background-position: 0 -48px; }
139 | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
140 | .ui-icon-arrowthick-1-e { background-position: -32px -48px; }
141 | .ui-icon-arrowthick-1-se { background-position: -48px -48px; }
142 | .ui-icon-arrowthick-1-s { background-position: -64px -48px; }
143 | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
144 | .ui-icon-arrowthick-1-w { background-position: -96px -48px; }
145 | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
146 | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
147 | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
148 | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
149 | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
150 | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
151 | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
152 | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
153 | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
154 | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
155 | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
156 | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
157 | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
158 | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
159 | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
160 | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
161 | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
162 | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
163 | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
164 | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
165 | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
166 | .ui-icon-arrow-4 { background-position: 0 -80px; }
167 | .ui-icon-arrow-4-diag { background-position: -16px -80px; }
168 | .ui-icon-extlink { background-position: -32px -80px; }
169 | .ui-icon-newwin { background-position: -48px -80px; }
170 | .ui-icon-refresh { background-position: -64px -80px; }
171 | .ui-icon-shuffle { background-position: -80px -80px; }
172 | .ui-icon-transfer-e-w { background-position: -96px -80px; }
173 | .ui-icon-transferthick-e-w { background-position: -112px -80px; }
174 | .ui-icon-folder-collapsed { background-position: 0 -96px; }
175 | .ui-icon-folder-open { background-position: -16px -96px; }
176 | .ui-icon-document { background-position: -32px -96px; }
177 | .ui-icon-document-b { background-position: -48px -96px; }
178 | .ui-icon-note { background-position: -64px -96px; }
179 | .ui-icon-mail-closed { background-position: -80px -96px; }
180 | .ui-icon-mail-open { background-position: -96px -96px; }
181 | .ui-icon-suitcase { background-position: -112px -96px; }
182 | .ui-icon-comment { background-position: -128px -96px; }
183 | .ui-icon-person { background-position: -144px -96px; }
184 | .ui-icon-print { background-position: -160px -96px; }
185 | .ui-icon-trash { background-position: -176px -96px; }
186 | .ui-icon-locked { background-position: -192px -96px; }
187 | .ui-icon-unlocked { background-position: -208px -96px; }
188 | .ui-icon-bookmark { background-position: -224px -96px; }
189 | .ui-icon-tag { background-position: -240px -96px; }
190 | .ui-icon-home { background-position: 0 -112px; }
191 | .ui-icon-flag { background-position: -16px -112px; }
192 | .ui-icon-calendar { background-position: -32px -112px; }
193 | .ui-icon-cart { background-position: -48px -112px; }
194 | .ui-icon-pencil { background-position: -64px -112px; }
195 | .ui-icon-clock { background-position: -80px -112px; }
196 | .ui-icon-disk { background-position: -96px -112px; }
197 | .ui-icon-calculator { background-position: -112px -112px; }
198 | .ui-icon-zoomin { background-position: -128px -112px; }
199 | .ui-icon-zoomout { background-position: -144px -112px; }
200 | .ui-icon-search { background-position: -160px -112px; }
201 | .ui-icon-wrench { background-position: -176px -112px; }
202 | .ui-icon-gear { background-position: -192px -112px; }
203 | .ui-icon-heart { background-position: -208px -112px; }
204 | .ui-icon-star { background-position: -224px -112px; }
205 | .ui-icon-link { background-position: -240px -112px; }
206 | .ui-icon-cancel { background-position: 0 -128px; }
207 | .ui-icon-plus { background-position: -16px -128px; }
208 | .ui-icon-plusthick { background-position: -32px -128px; }
209 | .ui-icon-minus { background-position: -48px -128px; }
210 | .ui-icon-minusthick { background-position: -64px -128px; }
211 | .ui-icon-close { background-position: -80px -128px; }
212 | .ui-icon-closethick { background-position: -96px -128px; }
213 | .ui-icon-key { background-position: -112px -128px; }
214 | .ui-icon-lightbulb { background-position: -128px -128px; }
215 | .ui-icon-scissors { background-position: -144px -128px; }
216 | .ui-icon-clipboard { background-position: -160px -128px; }
217 | .ui-icon-copy { background-position: -176px -128px; }
218 | .ui-icon-contact { background-position: -192px -128px; }
219 | .ui-icon-image { background-position: -208px -128px; }
220 | .ui-icon-video { background-position: -224px -128px; }
221 | .ui-icon-script { background-position: -240px -128px; }
222 | .ui-icon-alert { background-position: 0 -144px; }
223 | .ui-icon-info { background-position: -16px -144px; }
224 | .ui-icon-notice { background-position: -32px -144px; }
225 | .ui-icon-help { background-position: -48px -144px; }
226 | .ui-icon-check { background-position: -64px -144px; }
227 | .ui-icon-bullet { background-position: -80px -144px; }
228 | .ui-icon-radio-off { background-position: -96px -144px; }
229 | .ui-icon-radio-on { background-position: -112px -144px; }
230 | .ui-icon-pin-w { background-position: -128px -144px; }
231 | .ui-icon-pin-s { background-position: -144px -144px; }
232 | .ui-icon-play { background-position: 0 -160px; }
233 | .ui-icon-pause { background-position: -16px -160px; }
234 | .ui-icon-seek-next { background-position: -32px -160px; }
235 | .ui-icon-seek-prev { background-position: -48px -160px; }
236 | .ui-icon-seek-end { background-position: -64px -160px; }
237 | .ui-icon-seek-start { background-position: -80px -160px; }
238 | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
239 | .ui-icon-seek-first { background-position: -80px -160px; }
240 | .ui-icon-stop { background-position: -96px -160px; }
241 | .ui-icon-eject { background-position: -112px -160px; }
242 | .ui-icon-volume-off { background-position: -128px -160px; }
243 | .ui-icon-volume-on { background-position: -144px -160px; }
244 | .ui-icon-power { background-position: 0 -176px; }
245 | .ui-icon-signal-diag { background-position: -16px -176px; }
246 | .ui-icon-signal { background-position: -32px -176px; }
247 | .ui-icon-battery-0 { background-position: -48px -176px; }
248 | .ui-icon-battery-1 { background-position: -64px -176px; }
249 | .ui-icon-battery-2 { background-position: -80px -176px; }
250 | .ui-icon-battery-3 { background-position: -96px -176px; }
251 | .ui-icon-circle-plus { background-position: 0 -192px; }
252 | .ui-icon-circle-minus { background-position: -16px -192px; }
253 | .ui-icon-circle-close { background-position: -32px -192px; }
254 | .ui-icon-circle-triangle-e { background-position: -48px -192px; }
255 | .ui-icon-circle-triangle-s { background-position: -64px -192px; }
256 | .ui-icon-circle-triangle-w { background-position: -80px -192px; }
257 | .ui-icon-circle-triangle-n { background-position: -96px -192px; }
258 | .ui-icon-circle-arrow-e { background-position: -112px -192px; }
259 | .ui-icon-circle-arrow-s { background-position: -128px -192px; }
260 | .ui-icon-circle-arrow-w { background-position: -144px -192px; }
261 | .ui-icon-circle-arrow-n { background-position: -160px -192px; }
262 | .ui-icon-circle-zoomin { background-position: -176px -192px; }
263 | .ui-icon-circle-zoomout { background-position: -192px -192px; }
264 | .ui-icon-circle-check { background-position: -208px -192px; }
265 | .ui-icon-circlesmall-plus { background-position: 0 -208px; }
266 | .ui-icon-circlesmall-minus { background-position: -16px -208px; }
267 | .ui-icon-circlesmall-close { background-position: -32px -208px; }
268 | .ui-icon-squaresmall-plus { background-position: -48px -208px; }
269 | .ui-icon-squaresmall-minus { background-position: -64px -208px; }
270 | .ui-icon-squaresmall-close { background-position: -80px -208px; }
271 | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
272 | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
273 | .ui-icon-grip-solid-vertical { background-position: -32px -224px; }
274 | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
275 | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
276 | .ui-icon-grip-diagonal-se { background-position: -80px -224px; }
277 |
278 |
279 | /* Misc visuals
280 | ----------------------------------*/
281 |
282 | /* Corner radius */
283 | .ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
284 | .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
285 | .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
286 | .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
287 |
288 | /* Overlays */
289 | .ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); }
290 | .ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/*
291 | * jQuery UI Autocomplete 1.8.16
292 | *
293 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
294 | * Dual licensed under the MIT or GPL Version 2 licenses.
295 | * http://jquery.org/license
296 | *
297 | * http://docs.jquery.com/UI/Autocomplete#theming
298 | */
299 | .ui-autocomplete { position: absolute; cursor: default; }
300 |
301 | /* workarounds */
302 | * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
303 |
304 | /*
305 | * jQuery UI Menu 1.8.16
306 | *
307 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
308 | * Dual licensed under the MIT or GPL Version 2 licenses.
309 | * http://jquery.org/license
310 | *
311 | * http://docs.jquery.com/UI/Menu#theming
312 | */
313 | .ui-menu {
314 | list-style:none;
315 | padding: 2px;
316 | margin: 0;
317 | display:block;
318 | float: left;
319 | }
320 | .ui-menu .ui-menu {
321 | margin-top: -3px;
322 | }
323 | .ui-menu .ui-menu-item {
324 | margin:0;
325 | padding: 0;
326 | zoom: 1;
327 | float: left;
328 | clear: left;
329 | width: 100%;
330 | }
331 | .ui-menu .ui-menu-item a {
332 | text-decoration:none;
333 | display:block;
334 | padding:.2em .4em;
335 | line-height:1.5;
336 | zoom:1;
337 | }
338 | .ui-menu .ui-menu-item a.ui-state-hover,
339 | .ui-menu .ui-menu-item a.ui-state-active {
340 | font-weight: normal;
341 | margin: -1px;
342 | }
343 | /*
344 | * jQuery UI Tabs 1.8.16
345 | *
346 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
347 | * Dual licensed under the MIT or GPL Version 2 licenses.
348 | * http://jquery.org/license
349 | *
350 | * http://docs.jquery.com/UI/Tabs#theming
351 | */
352 | .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
353 | .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
354 | .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
355 | .ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
356 | .ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
357 | .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
358 | .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
359 | .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
360 | .ui-tabs .ui-tabs-hide { display: none !important; }
361 | /*
362 | * jQuery UI Progressbar 1.8.16
363 | *
364 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
365 | * Dual licensed under the MIT or GPL Version 2 licenses.
366 | * http://jquery.org/license
367 | *
368 | * http://docs.jquery.com/UI/Progressbar#theming
369 | */
370 | .ui-progressbar { height:2em; text-align: left; }
371 | .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
--------------------------------------------------------------------------------
/assets/css/satisfy.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/css/satisfy.woff
--------------------------------------------------------------------------------
/assets/img/.gitignore:
--------------------------------------------------------------------------------
1 | !.gitignore
2 |
3 |
--------------------------------------------------------------------------------
/assets/img/ajax-loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ajax-loader.gif
--------------------------------------------------------------------------------
/assets/img/follow_twitter_gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/follow_twitter_gray.png
--------------------------------------------------------------------------------
/assets/img/loader.grey.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/loader.grey.gif
--------------------------------------------------------------------------------
/assets/img/logo_38pt.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/logo_38pt.gif
--------------------------------------------------------------------------------
/assets/img/ui-bg_diagonals-thick_18_b81900_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-bg_diagonals-thick_18_b81900_40x40.png
--------------------------------------------------------------------------------
/assets/img/ui-bg_diagonals-thick_20_666666_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-bg_diagonals-thick_20_666666_40x40.png
--------------------------------------------------------------------------------
/assets/img/ui-bg_flat_10_000000_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-bg_flat_10_000000_40x100.png
--------------------------------------------------------------------------------
/assets/img/ui-bg_glass_100_f6f6f6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-bg_glass_100_f6f6f6_1x400.png
--------------------------------------------------------------------------------
/assets/img/ui-bg_glass_100_fdf5ce_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-bg_glass_100_fdf5ce_1x400.png
--------------------------------------------------------------------------------
/assets/img/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/assets/img/ui-bg_gloss-wave_35_f6a828_500x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-bg_gloss-wave_35_f6a828_500x100.png
--------------------------------------------------------------------------------
/assets/img/ui-bg_highlight-soft_100_eeeeee_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-bg_highlight-soft_100_eeeeee_1x100.png
--------------------------------------------------------------------------------
/assets/img/ui-bg_highlight-soft_75_ffe45c_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-bg_highlight-soft_75_ffe45c_1x100.png
--------------------------------------------------------------------------------
/assets/img/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/assets/img/ui-icons_228ef1_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-icons_228ef1_256x240.png
--------------------------------------------------------------------------------
/assets/img/ui-icons_ef8c08_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-icons_ef8c08_256x240.png
--------------------------------------------------------------------------------
/assets/img/ui-icons_ffd27a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-icons_ffd27a_256x240.png
--------------------------------------------------------------------------------
/assets/img/ui-icons_ffffff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/img/ui-icons_ffffff_256x240.png
--------------------------------------------------------------------------------
/assets/js/jquery-sparklines.js:
--------------------------------------------------------------------------------
1 | /* jquery.sparkline 1.6 - http://omnipotent.net/jquery.sparkline/
2 | ** Licensed under the New BSD License - see above site for details */
3 |
4 | (function($){var defaults={common:{type:'line',lineColor:'#00f',fillColor:'#cdf',defaultPixelsPerValue:3,width:'auto',height:'auto',composite:false,tagValuesAttribute:'values',tagOptionsPrefix:'spark',enableTagOptions:false},line:{spotColor:'#f80',spotRadius:1.5,minSpotColor:'#f80',maxSpotColor:'#f80',lineWidth:1,normalRangeMin:undefined,normalRangeMax:undefined,normalRangeColor:'#ccc',drawNormalOnTop:false,chartRangeMin:undefined,chartRangeMax:undefined,chartRangeMinX:undefined,chartRangeMaxX:undefined},bar:{barColor:'#00f',negBarColor:'#f44',zeroColor:undefined,nullColor:undefined,zeroAxis:undefined,barWidth:4,barSpacing:1,chartRangeMax:undefined,chartRangeMin:undefined,chartRangeClip:false,colorMap:undefined},tristate:{barWidth:4,barSpacing:1,posBarColor:'#6f6',negBarColor:'#f44',zeroBarColor:'#999',colorMap:{}},discrete:{lineHeight:'auto',thresholdColor:undefined,thresholdValue:0,chartRangeMax:undefined,chartRangeMin:undefined,chartRangeClip:false},bullet:{targetColor:'red',targetWidth:3,performanceColor:'blue',rangeColors:['#D3DAFE','#A8B6FF','#7F94FF'],base:undefined},pie:{sliceColors:['#f00','#0f0','#00f']},box:{raw:false,boxLineColor:'black',boxFillColor:'#cdf',whiskerColor:'black',outlierLineColor:'#333',outlierFillColor:'white',medianColor:'red',showOutliers:true,outlierIQR:1.5,spotRadius:1.5,target:undefined,targetColor:'#4a2',chartRangeMax:undefined,chartRangeMin:undefined}};var VCanvas_base,VCanvas_canvas,VCanvas_vml;$.fn.simpledraw=function(width,height,use_existing){if(use_existing&&this[0].VCanvas){return this[0].VCanvas;}
5 | if(width===undefined){width=$(this).innerWidth();}
6 | if(height===undefined){height=$(this).innerHeight();}
7 | if($.browser.hasCanvas){return new VCanvas_canvas(width,height,this);}else if($.browser.msie){return new VCanvas_vml(width,height,this);}else{return false;}};var pending=[];$.fn.sparkline=function(uservalues,userOptions){return this.each(function(){var options=new $.fn.sparkline.options(this,userOptions);var render=function(){var values,width,height;if(uservalues==='html'||uservalues===undefined){var vals=this.getAttribute(options.get('tagValuesAttribute'));if(vals===undefined||vals===null){vals=$(this).html();}
8 | values=vals.replace(/(^\s*\s*$)|\s+/g,'').split(',');}else{values=uservalues;}
9 | width=options.get('width')=='auto'?values.length*options.get('defaultPixelsPerValue'):options.get('width');if(options.get('height')=='auto'){if(!options.get('composite')||!this.VCanvas){var tmp=document.createElement('span');tmp.innerHTML='a';$(this).html(tmp);height=$(tmp).innerHeight();$(tmp).remove();}}else{height=options.get('height');}
10 | $.fn.sparkline[options.get('type')].call(this,values,options,width,height);};if(($(this).html()&&$(this).is(':hidden'))||($.fn.jquery<"1.3.0"&&$(this).parents().is(':hidden'))||!$(this).parents('body').length){pending.push([this,render]);}else{render.call(this);}});};$.fn.sparkline.defaults=defaults;$.sparkline_display_visible=function(){for(var i=pending.length-1;i>=0;i--){var el=pending[i][0];if($(el).is(':visible')&&!$(el).parents().is(':hidden')){pending[i][1].call(el);pending.splice(i,1);}}};var UNSET_OPTION={};var normalizeValue=function(val){switch(val){case'undefined':val=undefined;break;case'null':val=null;break;case'true':val=true;break;case'false':val=false;break;default:var nf=parseFloat(val);if(val==nf){val=nf;}}
11 | return val;};$.fn.sparkline.options=function(tag,userOptions){var extendedOptions;this.userOptions=userOptions=userOptions||{};this.tag=tag;this.tagValCache={};var defaults=$.fn.sparkline.defaults;var base=defaults.common;this.tagOptionsPrefix=userOptions.enableTagOptions&&(userOptions.tagOptionsPrefix||base.tagOptionsPrefix);var tagOptionType=this.getTagSetting('type');if(tagOptionType===UNSET_OPTION){extendedOptions=defaults[userOptions.type||base.type];}else{extendedOptions=defaults[tagOptionType];}
12 | this.mergedOptions=$.extend({},base,extendedOptions,userOptions);};$.fn.sparkline.options.prototype.getTagSetting=function(key){var val,i,prefix=this.tagOptionsPrefix;if(prefix===false||prefix===undefined){return UNSET_OPTION;}
13 | if(this.tagValCache.hasOwnProperty(key)){val=this.tagValCache.key;}else{val=this.tag.getAttribute(prefix+key);if(val===undefined||val===null){val=UNSET_OPTION;}else if(val.substr(0,1)=='['){val=val.substr(1,val.length-2).split(',');for(i=val.length;i--;){val[i]=normalizeValue(val[i].replace(/(^\s*)|(\s*$)/g,''));}}else if(val.substr(0,1)=='{'){var pairs=val.substr(1,val.length-2).split(',');val={};for(i=pairs.length;i--;){var keyval=pairs[i].split(':',2);val[keyval[0].replace(/(^\s*)|(\s*$)/g,'')]=normalizeValue(keyval[1].replace(/(^\s*)|(\s*$)/g,''));}}else{val=normalizeValue(val);}
14 | this.tagValCache.key=val;}
15 | return val;};$.fn.sparkline.options.prototype.get=function(key){var tagOption=this.getTagSetting(key);if(tagOption!==UNSET_OPTION){return tagOption;}
16 | return this.mergedOptions[key];};$.fn.sparkline.line=function(values,options,width,height){var xvalues=[],yvalues=[],yminmax=[];for(var i=0;imaxy){maxy=normalRangeMax;}}
20 | if(options.get('chartRangeMin')!==undefined&&(options.get('chartRangeClip')||options.get('chartRangeMin')maxy)){maxy=options.get('chartRangeMax');}
22 | if(options.get('chartRangeMinX')!==undefined&&(options.get('chartRangeClipX')||options.get('chartRangeMinX')maxx)){maxx=options.get('chartRangeMaxX');}
24 | var rangex=maxx-minx===0?1:maxx-minx;var rangey=maxy-miny===0?1:maxy-miny;var vl=yvalues.length-1;if(vl<1){this.innerHTML='';return;}
25 | var target=$(this).simpledraw(width,height,options.get('composite'));if(target){var canvas_width=target.pixel_width;var canvas_height=target.pixel_height;var canvas_top=0;var canvas_left=0;var spotRadius=options.get('spotRadius');if(spotRadius&&(canvas_width<(spotRadius*4)||canvas_height<(spotRadius*4))){spotRadius=0;}
26 | if(spotRadius){if(options.get('minSpotColor')||(options.get('spotColor')&&yvalues[vl]==miny)){canvas_height-=Math.ceil(spotRadius);}
27 | if(options.get('maxSpotColor')||(options.get('spotColor')&&yvalues[vl]==maxy)){canvas_height-=Math.ceil(spotRadius);canvas_top+=Math.ceil(spotRadius);}
28 | if(options.get('minSpotColor')||options.get('maxSpotColor')&&(yvalues[0]==miny||yvalues[0]==maxy)){canvas_left+=Math.ceil(spotRadius);canvas_width-=Math.ceil(spotRadius);}
29 | if(options.get('spotColor')||(options.get('minSpotColor')||options.get('maxSpotColor')&&(yvalues[vl]==miny||yvalues[vl]==maxy))){canvas_width-=Math.ceil(spotRadius);}}
30 | canvas_height--;var drawNormalRange=function(){if(normalRangeMin!==undefined){var ytop=canvas_top+Math.round(canvas_height-(canvas_height*((normalRangeMax-miny)/rangey)));var height=Math.round((canvas_height*(normalRangeMax-normalRangeMin))/rangey);target.drawRect(canvas_left,ytop,canvas_width,height,undefined,options.get('normalRangeColor'));}};if(!options.get('drawNormalOnTop')){drawNormalRange();}
31 | var path=[];var paths=[path];var x,y,vlen=yvalues.length;for(i=0;imaxy){y=maxy;}
33 | if(!path.length){path.push([canvas_left+Math.round((x-minx)*(canvas_width/rangex)),canvas_top+canvas_height]);}
34 | path.push([canvas_left+Math.round((x-minx)*(canvas_width/rangex)),canvas_top+Math.round(canvas_height-(canvas_height*((y-miny)/rangey)))]);}}
35 | var lineshapes=[];var fillshapes=[];var plen=paths.length;for(i=0;i2){path[0]=[path[0][0],path[1][1]];}
38 | lineshapes.push(path);}
39 | plen=fillshapes.length;for(i=0;imax)){max=options.get('chartRangeMax');}
47 | var zeroAxis=options.get('zeroAxis');if(zeroAxis===undefined){zeroAxis=min<0;}
48 | var range=max-min===0?1:max-min;var colorMapByIndex,colorMapByValue;if($.isArray(options.get('colorMap'))){colorMapByIndex=options.get('colorMap');colorMapByValue=null;}else{colorMapByIndex=null;colorMapByValue=options.get('colorMap');}
49 | var target=$(this).simpledraw(width,height,options.get('composite'));if(target){var color,canvas_height=target.pixel_height,yzero=min<0&&zeroAxis?canvas_height-Math.round(canvas_height*(Math.abs(min)/range))-1:canvas_height-1;for(i=values.length;i--;){var x=i*(options.get('barWidth')+options.get('barSpacing')),y,val=values[i];if(val===null){if(options.get('nullColor')){color=options.get('nullColor');val=(zeroAxis&&min<0)?0:min;height=1;y=(zeroAxis&&min<0)?yzero:canvas_height-height;}else{continue;}}else{if(valmax){val=max;}
51 | color=(val<0)?options.get('negBarColor'):options.get('barColor');if(zeroAxis&&min<0){height=Math.round(canvas_height*((Math.abs(val)/range)))+1;y=(val<0)?yzero:yzero-height;}else{height=Math.round(canvas_height*((val-min)/range))+1;y=canvas_height-height;}
52 | if(val===0&&options.get('zeroColor')!==undefined){color=options.get('zeroColor');}
53 | if(colorMapByValue&&colorMapByValue[val]){color=colorMapByValue[val];}else if(colorMapByIndex&&colorMapByIndex.length>i){color=colorMapByIndex[i];}
54 | if(color===null){continue;}}
55 | target.drawRect(x,y,options.get('barWidth')-1,height-1,color,color);}}else{this.innerHTML='';}};$.fn.sparkline.tristate=function(values,options,width,height){values=$.map(values,Number);width=(values.length*options.get('barWidth'))+((values.length-1)*options.get('barSpacing'));var colorMapByIndex,colorMapByValue;if($.isArray(options.get('colorMap'))){colorMapByIndex=options.get('colorMap');colorMapByValue=null;}else{colorMapByIndex=null;colorMapByValue=options.get('colorMap');}
56 | var target=$(this).simpledraw(width,height,options.get('composite'));if(target){var canvas_height=target.pixel_height,half_height=Math.round(canvas_height/2);for(var i=values.length;i--;){var x=i*(options.get('barWidth')+options.get('barSpacing')),y,color;if(values[i]<0){y=half_height;height=half_height-1;color=options.get('negBarColor');}else if(values[i]>0){y=0;height=half_height-1;color=options.get('posBarColor');}else{y=half_height-1;height=2;color=options.get('zeroBarColor');}
57 | if(colorMapByValue&&colorMapByValue[values[i]]){color=colorMapByValue[values[i]];}else if(colorMapByIndex&&colorMapByIndex.length>i){color=colorMapByIndex[i];}
58 | if(color===null){continue;}
59 | target.drawRect(x,y,options.get('barWidth')-1,height-1,color,color);}}else{this.innerHTML='';}};$.fn.sparkline.discrete=function(values,options,width,height){values=$.map(values,Number);width=options.get('width')=='auto'?values.length*2:width;var interval=Math.floor(width/values.length);var target=$(this).simpledraw(width,height,options.get('composite'));if(target){var canvas_height=target.pixel_height,line_height=options.get('lineHeight')=='auto'?Math.round(canvas_height*0.3):options.get('lineHeight'),pheight=canvas_height-line_height,min=Math.min.apply(Math,values),max=Math.max.apply(Math,values);if(options.get('chartRangeMin')!==undefined&&(options.get('chartRangeClip')||options.get('chartRangeMin')max)){max=options.get('chartRangeMax');}
61 | var range=max-min;for(var i=values.length;i--;){var val=values[i];if(valmax){val=max;}
63 | var x=(i*interval),ytop=Math.round(pheight-pheight*((val-min)/range));target.drawLine(x,ytop,x,ytop+line_height,(options.get('thresholdColor')&&val1){var canvas_width=target.pixel_width-Math.ceil(options.get('targetWidth')/2),canvas_height=target.pixel_height,min=Math.min.apply(Math,values),max=Math.max.apply(Math,values);if(options.get('base')===undefined){min=min<0?min:0;}else{min=options.get('base');}
64 | var range=max-min;for(var i=2,vlen=values.length;i1){var canvas_width=target.pixel_width,canvas_height=target.pixel_height,radius=Math.floor(Math.min(canvas_width,canvas_height)/2),total=0,next=0,circle=2*Math.PI;for(var i=values.length;i--;){total+=values[i];}
66 | if(options.get('offset')){next+=(2*Math.PI)*(options.get('offset')/360);}
67 | var vlen=values.length;for(i=0;i0){end=next+(circle*(values[i]/total));}
68 | target.drawPieSlice(radius,radius,radius,start,end,undefined,options.get('sliceColors')[i%options.get('sliceColors').length]);next=end;}}};var quartile=function(values,q){if(q==2){var vl2=Math.floor(values.length/2);return values.length%2?values[vl2]:(values[vl2]+values[vl2+1])/2;}else{var vl4=Math.floor(values.length/4);return values.length%2?(values[vl4*q]+values[vl4*q+1])/2:values[vl4*q];}};$.fn.sparkline.box=function(values,options,width,height){values=$.map(values,Number);width=options.get('width')=='auto'?'4.0em':width;var minvalue=options.get('chartRangeMin')===undefined?Math.min.apply(Math,values):options.get('chartRangeMin'),maxvalue=options.get('chartRangeMax')===undefined?Math.max.apply(Math,values):options.get('chartRangeMax'),target=$(this).simpledraw(width,height,options.get('composite')),vlen=values.length,lwhisker,loutlier,q1,q2,q3,rwhisker,routlier;if(target&&values.length>1){var canvas_width=target.pixel_width,canvas_height=target.pixel_height;if(options.get('raw')){if(options.get('showOutliers')&&values.length>5){loutlier=values[0];lwhisker=values[1];q1=values[2];q2=values[3];q3=values[4];rwhisker=values[5];routlier=values[6];}else{lwhisker=values[0];q1=values[1];q2=values[2];q3=values[3];rwhisker=values[4];}}else{values.sort(function(a,b){return a-b;});q1=quartile(values,1);q2=quartile(values,2);q3=quartile(values,3);var iqr=q3-q1;if(options.get('showOutliers')){lwhisker=undefined;rwhisker=undefined;for(var i=0;iq1-(iqr*options.get('outlierIQR'))){lwhisker=values[i];}
69 | if(values[i]rwhisker){target.drawCircle((routlier-minvalue)*unitsize+canvas_left,canvas_height/2,options.get('spotRadius'),options.get('outlierLineColor'),options.get('outlierFillColor'));}}
73 | target.drawRect(Math.round((q1-minvalue)*unitsize+canvas_left),Math.round(canvas_height*0.1),Math.round((q3-q1)*unitsize),Math.round(canvas_height*0.8),options.get('boxLineColor'),options.get('boxFillColor'));target.drawLine(Math.round((lwhisker-minvalue)*unitsize+canvas_left),Math.round(canvas_height/2),Math.round((q1-minvalue)*unitsize+canvas_left),Math.round(canvas_height/2),options.get('lineColor'));target.drawLine(Math.round((lwhisker-minvalue)*unitsize+canvas_left),Math.round(canvas_height/4),Math.round((lwhisker-minvalue)*unitsize+canvas_left),Math.round(canvas_height-canvas_height/4),options.get('whiskerColor'));target.drawLine(Math.round((rwhisker-minvalue)*unitsize+canvas_left),Math.round(canvas_height/2),Math.round((q3-minvalue)*unitsize+canvas_left),Math.round(canvas_height/2),options.get('lineColor'));target.drawLine(Math.round((rwhisker-minvalue)*unitsize+canvas_left),Math.round(canvas_height/4),Math.round((rwhisker-minvalue)*unitsize+canvas_left),Math.round(canvas_height-canvas_height/4),options.get('whiskerColor'));target.drawLine(Math.round((q2-minvalue)*unitsize+canvas_left),Math.round(canvas_height*0.1),Math.round((q2-minvalue)*unitsize+canvas_left),Math.round(canvas_height*0.9),options.get('medianColor'));if(options.get('target')){var size=Math.ceil(options.get('spotRadius'));target.drawLine(Math.round((options.get('target')-minvalue)*unitsize+canvas_left),Math.round((canvas_height/2)-size),Math.round((options.get('target')-minvalue)*unitsize+canvas_left),Math.round((canvas_height/2)+size),options.get('targetColor'));target.drawLine(Math.round((options.get('target')-minvalue)*unitsize+canvas_left-size),Math.round(canvas_height/2),Math.round((options.get('target')-minvalue)*unitsize+canvas_left+size),Math.round(canvas_height/2),options.get('targetColor'));}}else{this.innerHTML='';}};if($.browser.msie&&!document.namespaces.v){document.namespaces.add('v','urn:schemas-microsoft-com:vml','#default#VML');}
74 | if($.browser.hasCanvas===undefined){var t=document.createElement('canvas');$.browser.hasCanvas=t.getContext!==undefined;}
75 | VCanvas_base=function(width,height,target){};VCanvas_base.prototype={init:function(width,height,target){this.width=width;this.height=height;this.target=target;if(target[0]){target=target[0];}
76 | target.VCanvas=this;},drawShape:function(path,lineColor,fillColor,lineWidth){alert('drawShape not implemented');},drawLine:function(x1,y1,x2,y2,lineColor,lineWidth){return this.drawShape([[x1,y1],[x2,y2]],lineColor,lineWidth);},drawCircle:function(x,y,radius,lineColor,fillColor){alert('drawCircle not implemented');},drawPieSlice:function(x,y,radius,startAngle,endAngle,lineColor,fillColor){alert('drawPieSlice not implemented');},drawRect:function(x,y,width,height,lineColor,fillColor){alert('drawRect not implemented');},getElement:function(){return this.canvas;},_insert:function(el,target){$(target).html(el);}};VCanvas_canvas=function(width,height,target){return this.init(width,height,target);};VCanvas_canvas.prototype=$.extend(new VCanvas_base(),{_super:VCanvas_base.prototype,init:function(width,height,target){this._super.init(width,height,target);this.canvas=document.createElement('canvas');if(target[0]){target=target[0];}
77 | target.VCanvas=this;$(this.canvas).css({display:'inline-block',width:width,height:height,verticalAlign:'top'});this._insert(this.canvas,target);this.pixel_height=$(this.canvas).height();this.pixel_width=$(this.canvas).width();this.canvas.width=this.pixel_width;this.canvas.height=this.pixel_height;$(this.canvas).css({width:this.pixel_width,height:this.pixel_height});},_getContext:function(lineColor,fillColor,lineWidth){var context=this.canvas.getContext('2d');if(lineColor!==undefined){context.strokeStyle=lineColor;}
78 | context.lineWidth=lineWidth===undefined?1:lineWidth;if(fillColor!==undefined){context.fillStyle=fillColor;}
79 | return context;},drawShape:function(path,lineColor,fillColor,lineWidth){var context=this._getContext(lineColor,fillColor,lineWidth);context.beginPath();context.moveTo(path[0][0]+0.5,path[0][1]+0.5);for(var i=1,plen=path.length;i';this.canvas.insertAdjacentHTML('beforeEnd',groupel);this.group=$(this.canvas).children()[0];},drawShape:function(path,lineColor,fillColor,lineWidth){var vpath=[];for(var i=0,plen=path.length;i'+' ';this.group.insertAdjacentHTML('beforeEnd',vel);},drawCircle:function(x,y,radius,lineColor,fillColor){x-=radius+1;y-=radius+1;var stroke=lineColor===undefined?' stroked="false" ':' strokeWeight="1" strokeColor="'+lineColor+'" ';var fill=fillColor===undefined?' filled="false"':' fillColor="'+fillColor+'" filled="true" ';var vel=' ';this.group.insertAdjacentHTML('beforeEnd',vel);},drawPieSlice:function(x,y,radius,startAngle,endAngle,lineColor,fillColor){if(startAngle==endAngle){return;}
90 | if((endAngle-startAngle)==(2*Math.PI)){startAngle=0.0;endAngle=(2*Math.PI);}
91 | var startx=x+Math.round(Math.cos(startAngle)*radius);var starty=y+Math.round(Math.sin(startAngle)*radius);var endx=x+Math.round(Math.cos(endAngle)*radius);var endy=y+Math.round(Math.sin(endAngle)*radius);if(startx==endx&&starty==endy&&(endAngle-startAngle)'+' ';this.group.insertAdjacentHTML('beforeEnd',vel);},drawRect:function(x,y,width,height,lineColor,fillColor){return this.drawShape([[x,y],[x,y+height],[x+width,y+height],[x+width,y],[x,y]],lineColor,fillColor);}});})(jQuery);
--------------------------------------------------------------------------------
/assets/js/jquery.colorbox-min.js:
--------------------------------------------------------------------------------
1 | // ColorBox v1.3.18 - a full featured, light-weight, customizable lightbox based on jQuery 1.3+
2 | // Copyright (c) 2011 Jack Moore - jack@colorpowered.com
3 | // Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
4 | (function(a,b,c){function Y(c,d,e){var g=b.createElement(c);return d&&(g.id=f+d),e&&(g.style.cssText=e),a(g)}function Z(a){var b=y.length,c=(Q+a)%b;return c<0?b+c:c}function $(a,b){return Math.round((/%/.test(a)?(b==="x"?z.width():z.height())/100:1)*parseInt(a,10))}function _(a){return K.photo||/\.(gif|png|jpe?g|bmp|ico)((#|\?).*)?$/i.test(a)}function ba(){var b;K=a.extend({},a.data(P,e));for(b in K)a.isFunction(K[b])&&b.slice(0,2)!=="on"&&(K[b]=K[b].call(P));K.rel=K.rel||P.rel||"nofollow",K.href=K.href||a(P).attr("href"),K.title=K.title||P.title,typeof K.href=="string"&&(K.href=a.trim(K.href))}function bb(b,c){a.event.trigger(b),c&&c.call(P)}function bc(){var a,b=f+"Slideshow_",c="click."+f,d,e,g;K.slideshow&&y[1]?(d=function(){F.text(K.slideshowStop).unbind(c).bind(j,function(){if(Q "),b.open=!0}return c&&(b.onComplete=c),f.each(function(){a.data(this,e,a.extend({},a.data(this,e)||d,b)),a(this).addClass(g)}),(a.isFunction(b.open)&&b.open.call(f)||b.open)&&bd(f[0]),f},W.init=function(){if(!r){if(!a("body")[0]){a(W.init);return}z=a(c),r=Y(X).attr({id:e,"class":n?f+(o?"IE6":"IE"):""}),q=Y(X,"Overlay",o?"position:absolute":"").hide(),s=Y(X,"Wrapper"),t=Y(X,"Content").append(A=Y(X,"LoadedContent","width:0; height:0; overflow:hidden"),C=Y(X,"LoadingOverlay").add(Y(X,"LoadingGraphic")),D=Y(X,"Title"),E=Y(X,"Current"),G=Y(X,"Next"),H=Y(X,"Previous"),F=Y(X,"Slideshow").bind(h,bc),I=Y(X,"Close")),s.append(Y(X).append(Y(X,"TopLeft"),u=Y(X,"TopCenter"),Y(X,"TopRight")),Y(X,!1,"clear:left").append(v=Y(X,"MiddleLeft"),t,w=Y(X,"MiddleRight")),Y(X,!1,"clear:left").append(Y(X,"BottomLeft"),x=Y(X,"BottomCenter"),Y(X,"BottomRight"))).find("div div").css({"float":"left"}),B=Y(X,!1,"position:absolute; width:9999px; visibility:hidden; display:none"),a("body").prepend(q,r.append(s,B)),L=u.height()+x.height()+t.outerHeight(!0)-t.height(),M=v.width()+w.width()+t.outerWidth(!0)-t.width(),N=A.outerHeight(!0),O=A.outerWidth(!0),r.css({"padding-bottom":L,"padding-right":M}).hide(),G.click(function(){W.next()}),H.click(function(){W.prev()}),I.click(function(){W.close()}),J=G.add(H).add(E).add(F),q.click(function(){K.overlayClose&&W.close()}),a(b).bind("keydown."+f,function(a){var b=a.keyCode;S&&K.escKey&&b===27&&(a.preventDefault(),W.close()),S&&K.arrowKey&&y[1]&&(b===37?(a.preventDefault(),H.click()):b===39&&(a.preventDefault(),G.click()))})}},W.remove=function(){r.add(q).remove(),r=null,a("."+g).removeData(e).removeClass(g)},W.position=function(a,b){function g(a){u[0].style.width=x[0].style.width=t[0].style.width=a.style.width,C[0].style.height=C[1].style.height=t[0].style.height=v[0].style.height=w[0].style.height=a.style.height}var c=0,d=0,e=r.offset();z.unbind("resize."+f),r.css({top:-99999,left:-99999}),K.fixed&&!o?r.css({position:"fixed"}):(c=z.scrollTop(),d=z.scrollLeft(),r.css({position:"absolute"})),K.right!==!1?d+=Math.max(z.width()-K.w-O-M-$(K.right,"x"),0):K.left!==!1?d+=$(K.left,"x"):d+=Math.round(Math.max(z.width()-K.w-O-M,0)/2),K.bottom!==!1?c+=Math.max(z.height()-K.h-N-L-$(K.bottom,"y"),0):K.top!==!1?c+=$(K.top,"y"):c+=Math.round(Math.max(z.height()-K.h-N-L,0)/2),r.css({top:e.top,left:e.left}),a=r.width()===K.w+O&&r.height()===K.h+N?0:a||0,s[0].style.width=s[0].style.height="9999px",r.dequeue().animate({width:K.w+O,height:K.h+N,top:c,left:d},{duration:a,complete:function(){g(this),T=!1,s[0].style.width=K.w+O+M+"px",s[0].style.height=K.h+N+L+"px",b&&b(),setTimeout(function(){z.bind("resize."+f,W.position)},1)},step:function(){g(this)}})},W.resize=function(a){S&&(a=a||{},a.width&&(K.w=$(a.width,"x")-O-M),a.innerWidth&&(K.w=$(a.innerWidth,"x")),A.css({width:K.w}),a.height&&(K.h=$(a.height,"y")-N-L),a.innerHeight&&(K.h=$(a.innerHeight,"y")),!a.innerHeight&&!a.height&&(A.css({height:"auto"}),K.h=A.height()),A.css({height:K.h}),W.position(K.transition==="none"?0:K.speed))},W.prep=function(b){function g(){return K.w=K.w||A.width(),K.w=K.mw&&K.mw1){typeof K.current=="string"&&E.html(K.current.replace("{current}",Q+1).replace("{total}",g)).show(),G[K.loop||QK.mw&&(a=(R.width-K.mw)/R.width,d()),K.mh&&R.height>K.mh&&(a=(R.height-K.mh)/R.height,d())),K.h&&(R.style.marginTop=Math.max(K.h-R.height,0)/2+"px"),y[1]&&(Q1||a.shiftKey||a.altKey||a.metaKey||(a.preventDefault(),bd(this))}),W.init()})(jQuery,document,this);
--------------------------------------------------------------------------------
/assets/mockups.bmml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AngelList%20Trends
6 |
7 |
8 |
9 |
10 | About%3A
11 |
12 |
13 |
14 |
15 | Startups%3A
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | 0
37 | Product%2C%20About
38 |
39 |
40 |
41 |
42 | AngelList%20Trends
43 |
44 |
45 |
46 |
47 | Pick%20your%20Location%3A
48 |
49 |
50 |
51 |
52 | Cambridge%2C%20MA
53 |
54 |
55 |
56 |
57 | 13
58 | Average%20Amount%20Being%20Raised
59 |
60 |
61 |
62 |
63 | 28
64 | %24120%2C000
65 |
66 |
67 |
68 |
69 | Relative%20to%20location%20siblings.%20Becomes%20more%20complex%20if%20we%20allow%20multiple%20LocationTags%20-%20which%20I%20think%20we%20shouldn%27t%20if%20we%20want%20to%20keep%20this%20metric.
70 |
71 |
72 |
73 |
74 |
75 |
76 | 28
77 | WebHere
78 |
79 |
80 |
81 |
82 | 13
83 | World%27s%20greatest%20web%20hosting%20company
84 |
85 |
86 |
87 |
88 | true
89 | ./assets/sparkline.png
90 |
91 |
92 |
93 |
94 |
95 | 13576743
96 | DownArrowIcon%7Csmall
97 | right
98 | down%2012%25
99 |
100 |
101 |
102 |
103 |
104 |
105 | Number%20of%20Followers
106 |
107 |
108 |
109 |
110 | Sort%20By%3A
111 |
112 |
113 |
114 |
115 |
116 | 13
117 | Average%20Valuation
118 |
119 |
120 |
121 |
122 | 28
123 | %24150%2C000
124 |
125 |
126 |
127 |
128 | 28
129 | 30
130 |
131 |
132 |
133 |
134 | 13
135 | Startups
136 |
137 |
138 |
139 |
140 | 28
141 | 100
142 |
143 |
144 |
145 |
146 | 13
147 | Followers
148 |
149 |
150 |
151 |
152 | 28
153 | 12
154 |
155 |
156 |
157 |
158 | 13
159 | Investors
160 |
161 |
162 |
163 |
164 | 10470904
165 | 16
166 | %285%25%29
167 |
168 |
169 |
170 |
171 | 10470904
172 | 16
173 | 40%25
174 |
175 |
176 |
177 |
178 | 10470904
179 | 16
180 | %285%25%29
181 |
182 |
183 |
184 |
185 | 28
186 | 120
187 |
188 |
189 |
190 |
191 | 13
192 | Users
193 |
194 |
195 |
196 |
197 | 10470904
198 | 16
199 | %285%25%29
200 |
201 |
202 |
203 |
204 |
205 | 10470904
206 | 16
207 | %28140%25%29
208 |
209 |
210 |
211 |
212 | Relative%20to%20either%3A%0AAll%20other%20startups%20in%20this%20MarketTag%20in%20other%20LocationTags%20OR%0AAll%20other%20startups%20in%20this%20LocationTag%20with%20other%20MarketTags.
213 |
214 |
215 |
216 |
217 | 10470904
218 | 16
219 | %2810%25%29
220 |
221 |
222 |
223 |
224 | 16750848
225 | DotIcon%7Csmall
226 |
227 |
228 |
229 |
230 | 16750848
231 | DotIcon%7Csmall
232 |
233 |
234 |
235 |
236 | 16750848
237 | DotIcon%7Csmall
238 |
239 |
240 |
241 |
242 | 40463
243 | DotIcon%7Csmall
244 |
245 |
246 |
247 |
248 | 40463
249 | DotIcon%7Csmall
250 |
251 |
252 |
253 |
254 | 40463
255 | DotIcon%7Csmall
256 |
257 |
258 |
259 |
260 | 40463
261 | DotIcon%7Csmall
262 |
263 |
264 |
265 |
266 | 40463
267 | DotIcon%7Csmall
268 |
269 |
270 |
271 |
272 |
273 |
274 | 28
275 | WebHere
276 |
277 |
278 |
279 |
280 | 13
281 | World%27s%20greatest%20web%20hosting%20company
282 |
283 |
284 |
285 |
286 | true
287 | ./assets/sparkline.png
288 |
289 |
290 |
291 |
292 |
293 | 13576743
294 | DownArrowIcon%7Csmall
295 | right
296 | down%2012%25
297 |
298 |
299 |
300 |
301 |
302 |
303 | If%20no%20screenshots%20exist%2C%20we%20show%20about%20tab.
304 |
305 |
306 |
307 |
308 | 2848996
309 | DotIcon%7Csmall
310 |
311 |
312 |
313 |
314 | 2848996
315 | DotIcon%7Csmall
316 |
317 |
318 |
319 |
320 | 2848996
321 | DotIcon%7Csmall
322 |
323 |
324 |
325 |
326 | 2848996
327 | DotIcon%7Csmall
328 |
329 |
330 |
331 |
332 | 28
333 | Marketing
334 |
335 |
336 |
337 |
338 |
339 | 14
340 | Hosting
341 |
342 |
343 |
344 |
345 | 20
346 | Information
347 |
348 |
349 |
350 |
351 | 20
352 | Analytics
353 |
354 |
355 |
356 |
357 | 13
358 | Commonly%20used%20other%20tags%3A
359 |
360 |
361 |
362 |
363 | Pick%20your%20Market%3A
364 |
365 |
366 |
367 |
368 | Web%20Hosting
369 |
370 |
371 |
372 |
373 | Note%2C%20not%20adding%20person%20selection%20things%20here....%20We%20could%20if%20the%20search%20allows%20us%20to%20find%20all%20startups%20where%20that%20person%20has%20a%20role%2C%20but%20I%20think%20that%20becomes%20more%20complicated%20when%20a%20person%20is%20a%20follower%20in%20one%20and%20an%20investor%20in%20another%20etc.
374 |
375 |
376 |
377 |
378 | 13576743
379 | DotIcon%7Csmall
380 |
381 |
382 |
383 |
384 | 13576743
385 | DotIcon%7Csmall
386 |
387 |
388 |
389 |
--------------------------------------------------------------------------------
/assets/mockups.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/mockups.png
--------------------------------------------------------------------------------
/assets/mockups_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/mockups_2.png
--------------------------------------------------------------------------------
/assets/search_header.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/search_header.jpg
--------------------------------------------------------------------------------
/assets/sparkline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/assets/sparkline.png
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bocoup/StartupDataTrends/c4640b1cc037d5e093a167295ffd9375b829f0cb/favicon.ico
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "Irene Ros (http://bocoup.com)",
3 | "name": "StartupDataTrends",
4 | "description": "Startup Data Trends Visualization",
5 | "version": "0.0.0",
6 | "homepage": "https://github.com/bocoup/angellist-viz",
7 | "repository": {
8 | "type": "git",
9 | "url": "git://github.com/bocoup/angellist-viz.git"
10 | },
11 | "main": "application.js",
12 | "engines": {
13 | "node": "~0.6"
14 | },
15 | "dependencies": {
16 | "backbone": "0.5.3",
17 | "express": "2.5.1",
18 | "request": "2.9.100"
19 | },
20 | "devDependencies": {
21 | "jake": "*",
22 | "underscore": "*",
23 | "jshint": "*",
24 | "uglify-js": "*",
25 | "express": "*",
26 | "vows": "*",
27 | "colors": "*",
28 | "zlib": "*",
29 | "dateformat": "*",
30 | "stats": "*",
31 | "grunt": "~0.4.5",
32 | "grunt-contrib-jshint": "~0.10.0",
33 | "grunt-contrib-clean": "~0.6.0",
34 | "grunt-contrib-copy": "~0.5.0",
35 | "grunt-contrib-jst": "~0.6.0",
36 | "grunt-contrib-uglify": "~0.5.1",
37 | "grunt-contrib-concat": "~0.5.0",
38 | "grunt-contrib-watch": "~0.6.1",
39 | "grunt-contrib-connect": "~0.8.0",
40 | "grunt-aws": "~0.2.5"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | ## This project has been archived as of August 2023.
2 |
3 | # Startup Data Trends
4 |
5 | This repo contains the code that was written to build http://startupdatatrends.com, a visual browser of startup data from AngelList (http://angel.com.)
6 |
7 | The repo was built on top of Backbone-boilerplate by @tbranyen (https://github.com/tbranyen/backbone-boilerplate)
8 |
9 | See the Bocoup blog for more information about the application (http://weblog.bocoup.com)
10 |
11 | If you have any questions or comments, contact @iros here or: irene at bocoup dot com.
12 |
13 | Setting up dev environment
14 | --------------------------
15 |
16 | Run `npm install` from your application root.
17 |
18 | Build
19 | -----
20 |
21 | The application is built using grunt. Run `grunt build` to build the source, and `grunt dev` during development to watch
22 | files and recompile on changes.
23 |
24 | Server
25 | ------
26 |
27 | Run with `grunt connect`. It will run on port `8082`
28 |
--------------------------------------------------------------------------------
/tasks/contrib-clean.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.config.set('clean', {
4 | prod: {
5 | src: ['prod']
6 | },
7 | postbuild: {
8 | src: ['prod/alt.deps.min.js', 'prod/alt.src.min.js', 'prod/js']
9 | }
10 | });
11 |
12 | grunt.loadNpmTasks('grunt-contrib-clean');
13 |
14 | };
--------------------------------------------------------------------------------
/tasks/contrib-concat.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.config.set("concat", {
4 | js: {
5 | options: {
6 | separator: ";"
7 | },
8 | src : [
9 | "prod/alt.deps.min.js",
10 | "assets/js/jquery-ui-1.8.16.custom.min.js",
11 | "assets/js/jquery-sparklines.js",
12 | "assets/js/jquery.colorbox-min.js",
13 | "prod/alt.src.min.js"
14 | ],
15 |
16 | dest: "prod/alt.min.js"
17 | }
18 | });
19 |
20 | grunt.loadNpmTasks("grunt-contrib-concat");
21 |
22 | };
--------------------------------------------------------------------------------
/tasks/contrib-connect.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 |
4 | grunt.config.set('connect', {
5 | options: {
6 | port: 8082,
7 | hostname: '*',
8 | },
9 | server: {
10 | options: {
11 | base: ['prod', '.'],
12 | keepalive: true
13 | }
14 | }
15 | });
16 |
17 | grunt.loadNpmTasks('grunt-contrib-connect');
18 |
19 | };
--------------------------------------------------------------------------------
/tasks/contrib-copy.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.config.set('copy', {
4 | prod: {
5 | expand: true,
6 | cwd: 'assets/',
7 | src: '**/*',
8 | dest: 'prod/',
9 | },
10 |
11 | index: {
12 | expand: true,
13 | cwd: 'app/pages/',
14 | src: 'index.html',
15 | dest: 'prod/'
16 | }
17 | });
18 |
19 | grunt.loadNpmTasks('grunt-contrib-copy');
20 |
21 | };
--------------------------------------------------------------------------------
/tasks/contrib-jshint.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.config.set('jshint', {
4 | build: {
5 | options: {
6 | jshintrc: '.jshintrc',
7 | },
8 | src: ['Gruntfile.js', 'build/**/*.js'],
9 | },
10 |
11 | app: {
12 | options: {
13 | jshintrc: 'app/.jshintrc',
14 | },
15 | src: ['app/**/*.js'],
16 | },
17 |
18 | 'test-unit': {
19 | options: {
20 | jshintrc: 'test/unit/.jshintrc'
21 | },
22 | src: ['test/unit/*.js']
23 | }
24 | });
25 |
26 | grunt.loadNpmTasks('grunt-contrib-jshint');
27 |
28 | };
--------------------------------------------------------------------------------
/tasks/contrib-jst.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.config.set('jst', {
4 | compile : {
5 | options : {
6 | namespace: 'ALT.app.templates',
7 | processName: function(filepath) {
8 | var l = filepath.length;
9 | return filepath.slice("app/templates/".length, l - 5);
10 |
11 | }
12 | },
13 |
14 | files : {
15 | 'prod/templates.js' : ['app/templates/*.html']
16 | }
17 | }
18 | });
19 |
20 | grunt.loadNpmTasks('grunt-contrib-jst');
21 |
22 | };
--------------------------------------------------------------------------------
/tasks/contrib-uglify.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.config.set('uglify', {
4 | options: {
5 | compress: false,
6 | beautify: true
7 | },
8 |
9 | deps: {
10 | files: {
11 | 'prod/alt.deps.min.js': [
12 | "assets/js/libs/jquery.js",
13 | "assets/js/libs/underscore.js",
14 | "assets/js/libs/backbone.js"
15 | ]
16 | }
17 | },
18 |
19 | src: {
20 | files: {
21 | 'prod/alt.src.min.js': [
22 | "prod/templates.js",
23 | "app/application.js",
24 | "app/modules/utils.js",
25 | "app/modules/search.js",
26 | "app/modules/startup.js",
27 | "app/modules/base.js"
28 | ]
29 | }
30 | }
31 |
32 | });
33 |
34 | grunt.loadNpmTasks('grunt-contrib-uglify');
35 |
36 | };
--------------------------------------------------------------------------------
/tasks/contrib-watch.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.config.set('watch', {
4 |
5 | jshintrc: {
6 | files: ['**/.jshintrc'],
7 | tasks: ['jshint'],
8 | },
9 |
10 | build: {
11 | files: ['<%= jshint.build.src %>'],
12 | tasks: ['jshint:build'],
13 | },
14 |
15 | scripts: {
16 | files: ['<%= jshint.app.src %>'],
17 | tasks: ['jshint:app', 'uglify', 'concat'],
18 | },
19 |
20 | tests: {
21 | files: ['test/unit/**/*'],
22 | tasks: ['jshint:test-unit'],
23 | },
24 |
25 | page: {
26 | files: 'app/pages/*.html',
27 | tasks: ['copy:index'],
28 | },
29 |
30 | templates: {
31 | files: 'app/templates/*.html',
32 | tasks: ['jst']
33 | },
34 |
35 | assets: {
36 | files: 'assets/**/*',
37 | tasks: ['copy:prod', 'uglify', 'concat'],
38 | }
39 |
40 | });
41 |
42 | grunt.loadNpmTasks('grunt-contrib-watch');
43 |
44 | };
--------------------------------------------------------------------------------
/tasks/s3.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.config.set('s3', {
4 |
5 | options: {
6 | accessKeyId: "<%= aws.accessKeyId %>",
7 | secretAccessKey: "<%= aws.secretAccessKey %>",
8 | bucket: "www.startupdatatrends.com"
9 | },
10 | prod: {
11 | cwd: "prod/",
12 | src: "**"
13 | }
14 |
15 | });
16 |
17 | grunt.loadNpmTasks('grunt-aws');
18 |
19 | };
20 |
21 |
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Your Application Test Suite
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/test/unit/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "curly": true,
3 | "eqeqeq": true,
4 | "immed": true,
5 | "latedef": "nofunc",
6 | "newcap": true,
7 | "noarg": true,
8 | "sub": true,
9 | "undef": true,
10 | "unused": "vars",
11 | "boss": true,
12 | "eqnull": true,
13 | "browser": true,
14 | "globals": {
15 | "module": true,
16 | "ALT": true,
17 | "ok": true,
18 | "_": true,
19 | "console": true,
20 | "test": true
21 | }
22 | }
--------------------------------------------------------------------------------
/test/unit/core.js:
--------------------------------------------------------------------------------
1 | module("Utils");
2 |
3 | var U = ALT.module("utils");
4 | test("Utils Signature Test", function() {
5 | ok(typeof U.formatDollarAmount !== "undefined", "formatDollarAmount exists");
6 | ok(typeof U.frequencyCount !== "undefined", "frequencyCount exists");
7 | });
8 |
9 | test("Frequency Count Basic", function() {
10 | var obj = [
11 | { "name" : "a" },
12 | { "name" : "a" },
13 | { "name" : "a" },
14 | { "name" : "a" },
15 | { "name" : "b" },
16 | { "name" : "b" },
17 | { "name" : "c" },
18 | ];
19 |
20 | var result = [
21 | ["a", 4],
22 | ["b", 2],
23 | ["c", 1]
24 | ];
25 | ok(_.isEqual(U.frequencyCount(obj, "name"), result),
26 | "frequency counts are correct");
27 | });
28 |
29 |
30 | test("Frequency Count Basic with id", function() {
31 | var obj = [
32 | { "name" : "a", "id" : 1 },
33 | { "name" : "a", "id" : 1 },
34 | { "name" : "a", "id" : 1 },
35 | { "name" : "a", "id" : 1 },
36 | { "name" : "b", "id" : 2 },
37 | { "name" : "b", "id" : 2 },
38 | { "name" : "c", "id" : 3 }
39 | ];
40 |
41 | var result = [
42 | [1, "a", 4],
43 | [2, "b", 2],
44 | [3, "c", 1]
45 | ];
46 | console.log(U.frequencyCount(obj, "name", "id"));
47 | ok(_.isEqual(U.frequencyCount(obj, "name", "id"), result),
48 | "frequency counts are correct");
49 | });
50 |
51 | test("Frequency Count Out of Order", function() {
52 | var obj = [
53 | { "name" : "b" },
54 | { "name" : "c" },
55 | { "name" : "a" },
56 | { "name" : "b" },
57 | { "name" : "a" },
58 | { "name" : "a" },
59 | { "name" : "a" }
60 | ];
61 |
62 | var result = [
63 | ["a", 4],
64 | ["b", 2],
65 | ["c", 1]
66 | ];
67 |
68 | ok(_.isEqual(U.frequencyCount(obj, "name"), result),
69 | "frequency counts are correct");
70 | });
71 |
72 | test("Format Dollar Amount", function() {
73 | var samples = {
74 | 0 : "$0",
75 | 10 : "$10",
76 | 100 : "$100",
77 | 1000 : "$1,000",
78 | 1000000 : "$1,000,000"
79 | };
80 |
81 | _.each(samples, function(value, key) {
82 | ok(U.formatDollarAmount(key) === value, "dollar amount " + key + " is formatted correctly as " + value);
83 | });
84 | });
85 |
86 | test("Remap values", function() {
87 | ok(U.remap(1, 0, 10, 0, 100) === 10, "U.remap(1, 0, 10, 0, 100) === 10");
88 | ok(U.remap(10, 0, 10, 0, 100) === 100, "U.remap(10, 0, 10, 0, 100) === 100");
89 | ok(U.remap(5, 0, 10, 0, 100) === 50, "U.remap(5, 0, 10, 0, 100) === 50");
90 | });
--------------------------------------------------------------------------------
/test/vendor/jslitmus.js:
--------------------------------------------------------------------------------
1 | // JSLitmus.js
2 | //
3 | // Copyright (c) 2010, Robert Kieffer, http://broofa.com
4 | // Available under MIT license (http://en.wikipedia.org/wiki/MIT_License)
5 |
6 | (function() {
7 | // Private methods and state
8 |
9 | // Get platform info but don't go crazy trying to recognize everything
10 | // that's out there. This is just for the major platforms and OSes.
11 | var platform = 'unknown platform', ua = navigator.userAgent;
12 |
13 | // Detect OS
14 | var oses = ['Windows','iPhone OS','(Intel |PPC )?Mac OS X','Linux'].join('|');
15 | var pOS = new RegExp('((' + oses + ') [^ \);]*)').test(ua) ? RegExp.$1 : null;
16 | if (!pOS) pOS = new RegExp('((' + oses + ')[^ \);]*)').test(ua) ? RegExp.$1 : null;
17 |
18 | // Detect browser
19 | var pName = /(Chrome|MSIE|Safari|Opera|Firefox)/.test(ua) ? RegExp.$1 : null;
20 |
21 | // Detect version
22 | var vre = new RegExp('(Version|' + pName + ')[ \/]([^ ;]*)');
23 | var pVersion = (pName && vre.test(ua)) ? RegExp.$2 : null;
24 | var platform = (pOS && pName && pVersion) ? pName + ' ' + pVersion + ' on ' + pOS : 'unknown platform';
25 |
26 | /**
27 | * A smattering of methods that are needed to implement the JSLitmus testbed.
28 | */
29 | var jsl = {
30 | /**
31 | * Enhanced version of escape()
32 | */
33 | escape: function(s) {
34 | s = s.replace(/,/g, '\\,');
35 | s = escape(s);
36 | s = s.replace(/\+/g, '%2b');
37 | s = s.replace(/ /g, '+');
38 | return s;
39 | },
40 |
41 | /**
42 | * Get an element by ID.
43 | */
44 | $: function(id) {
45 | return document.getElementById(id);
46 | },
47 |
48 | /**
49 | * Null function
50 | */
51 | F: function() {},
52 |
53 | /**
54 | * Set the status shown in the UI
55 | */
56 | status: function(msg) {
57 | var el = jsl.$('jsl_status');
58 | if (el) el.innerHTML = msg || '';
59 | },
60 |
61 | /**
62 | * Convert a number to an abbreviated string like, "15K" or "10M"
63 | */
64 | toLabel: function(n) {
65 | if (n == Infinity) {
66 | return 'Infinity';
67 | } else if (n > 1e9) {
68 | n = Math.round(n/1e8);
69 | return n/10 + 'B';
70 | } else if (n > 1e6) {
71 | n = Math.round(n/1e5);
72 | return n/10 + 'M';
73 | } else if (n > 1e3) {
74 | n = Math.round(n/1e2);
75 | return n/10 + 'K';
76 | }
77 | return n;
78 | },
79 |
80 | /**
81 | * Copy properties from src to dst
82 | */
83 | extend: function(dst, src) {
84 | for (var k in src) dst[k] = src[k]; return dst;
85 | },
86 |
87 | /**
88 | * Like Array.join(), but for the key-value pairs in an object
89 | */
90 | join: function(o, delimit1, delimit2) {
91 | if (o.join) return o.join(delimit1); // If it's an array
92 | var pairs = [];
93 | for (var k in o) pairs.push(k + delimit1 + o[k]);
94 | return pairs.join(delimit2);
95 | },
96 |
97 | /**
98 | * Array#indexOf isn't supported in IE, so we use this as a cross-browser solution
99 | */
100 | indexOf: function(arr, o) {
101 | if (arr.indexOf) return arr.indexOf(o);
102 | for (var i = 0; i < this.length; i++) if (arr[i] === o) return i;
103 | return -1;
104 | }
105 | };
106 |
107 | /**
108 | * Test manages a single test (created with
109 | * JSLitmus.test())
110 | *
111 | * @private
112 | */
113 | var Test = function (name, f) {
114 | if (!f) throw new Error('Undefined test function');
115 | if (!/function[^\(]*\(([^,\)]*)/.test(f.toString())) {
116 | throw new Error('"' + name + '" test: Test is not a valid Function object');
117 | }
118 | this.loopArg = RegExp.$1;
119 | this.name = name;
120 | this.f = f;
121 | };
122 |
123 | jsl.extend(Test, /** @lends Test */ {
124 | /** Calibration tests for establishing iteration loop overhead */
125 | CALIBRATIONS: [
126 | new Test('calibrating loop', function(count) {while (count--);}),
127 | new Test('calibrating function', jsl.F)
128 | ],
129 |
130 | /**
131 | * Run calibration tests. Returns true if calibrations are not yet
132 | * complete (in which case calling code should run the tests yet again).
133 | * onCalibrated - Callback to invoke when calibrations have finished
134 | */
135 | calibrate: function(onCalibrated) {
136 | for (var i = 0; i < Test.CALIBRATIONS.length; i++) {
137 | var cal = Test.CALIBRATIONS[i];
138 | if (cal.running) return true;
139 | if (!cal.count) {
140 | cal.isCalibration = true;
141 | cal.onStop = onCalibrated;
142 | //cal.MIN_TIME = .1; // Do calibrations quickly
143 | cal.run(2e4);
144 | return true;
145 | }
146 | }
147 | return false;
148 | }
149 | });
150 |
151 | jsl.extend(Test.prototype, {/** @lends Test.prototype */
152 | /** Initial number of iterations */
153 | INIT_COUNT: 10,
154 | /** Max iterations allowed (i.e. used to detect bad looping functions) */
155 | MAX_COUNT: 1e9,
156 | /** Minimum time a test should take to get valid results (secs) */
157 | MIN_TIME: .5,
158 |
159 | /** Callback invoked when test state changes */
160 | onChange: jsl.F,
161 |
162 | /** Callback invoked when test is finished */
163 | onStop: jsl.F,
164 |
165 | /**
166 | * Reset test state
167 | */
168 | reset: function() {
169 | delete this.count;
170 | delete this.time;
171 | delete this.running;
172 | delete this.error;
173 | },
174 |
175 | /**
176 | * Run the test (in a timeout). We use a timeout to make sure the browser
177 | * has a chance to finish rendering any UI changes we've made, like
178 | * updating the status message.
179 | */
180 | run: function(count) {
181 | count = count || this.INIT_COUNT;
182 | jsl.status(this.name + ' x ' + count);
183 | this.running = true;
184 | var me = this;
185 | setTimeout(function() {me._run(count);}, 200);
186 | },
187 |
188 | /**
189 | * The nuts and bolts code that actually runs a test
190 | */
191 | _run: function(count) {
192 | var me = this;
193 |
194 | // Make sure calibration tests have run
195 | if (!me.isCalibration && Test.calibrate(function() {me.run(count);})) return;
196 | this.error = null;
197 |
198 | try {
199 | var start, f = this.f, now, i = count;
200 |
201 | // Start the timer
202 | start = new Date();
203 |
204 | // Now for the money shot. If this is a looping function ...
205 | if (this.loopArg) {
206 | // ... let it do the iteration itself
207 | f(count);
208 | } else {
209 | // ... otherwise do the iteration for it
210 | while (i--) f();
211 | }
212 |
213 | // Get time test took (in secs)
214 | this.time = Math.max(1,new Date() - start)/1000;
215 |
216 | // Store iteration count and per-operation time taken
217 | this.count = count;
218 | this.period = this.time/count;
219 |
220 | // Do we need to do another run?
221 | this.running = this.time <= this.MIN_TIME;
222 |
223 | // ... if so, compute how many times we should iterate
224 | if (this.running) {
225 | // Bump the count to the nearest power of 2
226 | var x = this.MIN_TIME/this.time;
227 | var pow = Math.pow(2, Math.max(1, Math.ceil(Math.log(x)/Math.log(2))));
228 | count *= pow;
229 | if (count > this.MAX_COUNT) {
230 | throw new Error('Max count exceeded. If this test uses a looping function, make sure the iteration loop is working properly.');
231 | }
232 | }
233 | } catch (e) {
234 | // Exceptions are caught and displayed in the test UI
235 | this.reset();
236 | this.error = e;
237 | }
238 |
239 | // Figure out what to do next
240 | if (this.running) {
241 | me.run(count);
242 | } else {
243 | jsl.status('');
244 | me.onStop(me);
245 | }
246 |
247 | // Finish up
248 | this.onChange(this);
249 | },
250 |
251 | /**
252 | * Get the number of operations per second for this test.
253 | *
254 | * @param normalize if true, iteration loop overhead taken into account
255 | */
256 | getHz: function(/**Boolean*/ normalize) {
257 | var p = this.period;
258 |
259 | // Adjust period based on the calibration test time
260 | if (normalize && !this.isCalibration) {
261 | var cal = Test.CALIBRATIONS[this.loopArg ? 0 : 1];
262 |
263 | // If the period is within 20% of the calibration time, then zero the
264 | // it out
265 | p = p < cal.period*1.2 ? 0 : p - cal.period;
266 | }
267 |
268 | return Math.round(1/p);
269 | },
270 |
271 | /**
272 | * Get a friendly string describing the test
273 | */
274 | toString: function() {
275 | return this.name + ' - ' + this.time/this.count + ' secs';
276 | }
277 | });
278 |
279 | // CSS we need for the UI
280 | var STYLESHEET = '';
360 |
361 | // HTML markup for the UI
362 | var MARKUP = ' \
363 |
Run Tests \
364 |
Stop Tests \
365 |
\
366 |
\
367 |
Normalize results \
368 |
\
369 | \
370 | \
371 | \
372 | \
373 | ' + platform + ' \
374 | Test Ops/sec \
375 | \
376 | \
377 | Ready \
378 | \
379 |
\
380 |
\
381 |
\
382 |
\
383 | TinyURL (for chart): \
384 |
\
385 |
\
386 |
Powered by JSLitmus \
387 |
';
388 |
389 | /**
390 | * The public API for creating and running tests
391 | */
392 | window.JSLitmus = {
393 | /** The list of all tests that have been registered with JSLitmus.test */
394 | _tests: [],
395 | /** The queue of tests that need to be run */
396 | _queue: [],
397 |
398 | /**
399 | * The parsed query parameters the current page URL. This is provided as a
400 | * convenience for test functions - it's not used by JSLitmus proper
401 | */
402 | params: {},
403 |
404 | /**
405 | * Initialize
406 | */
407 | _init: function() {
408 | // Parse query params into JSLitmus.params[] hash
409 | var match = (location + '').match(/([^?#]*)(#.*)?$/);
410 | if (match) {
411 | var pairs = match[1].split('&');
412 | for (var i = 0; i < pairs.length; i++) {
413 | var pair = pairs[i].split('=');
414 | if (pair.length > 1) {
415 | var key = pair.shift();
416 | var value = pair.length > 1 ? pair.join('=') : pair[0];
417 | this.params[key] = value;
418 | }
419 | }
420 | }
421 |
422 | // Write out the stylesheet. We have to do this here because IE
423 | // doesn't honor sheets written after the document has loaded.
424 | document.write(STYLESHEET);
425 |
426 | // Setup the rest of the UI once the document is loaded
427 | if (window.addEventListener) {
428 | window.addEventListener('load', this._setup, false);
429 | } else if (document.addEventListener) {
430 | document.addEventListener('load', this._setup, false);
431 | } else if (window.attachEvent) {
432 | window.attachEvent('onload', this._setup);
433 | }
434 |
435 | return this;
436 | },
437 |
438 | /**
439 | * Set up the UI
440 | */
441 | _setup: function() {
442 | var el = jsl.$('jslitmus_container');
443 | if (!el) document.body.appendChild(el = document.createElement('div'));
444 |
445 | el.innerHTML = MARKUP;
446 |
447 | // Render the UI for all our tests
448 | for (var i=0; i < JSLitmus._tests.length; i++)
449 | JSLitmus.renderTest(JSLitmus._tests[i]);
450 | },
451 |
452 | /**
453 | * (Re)render all the test results
454 | */
455 | renderAll: function() {
456 | for (var i = 0; i < JSLitmus._tests.length; i++)
457 | JSLitmus.renderTest(JSLitmus._tests[i]);
458 | JSLitmus.renderChart();
459 | },
460 |
461 | /**
462 | * (Re)render the chart graphics
463 | */
464 | renderChart: function() {
465 | var url = JSLitmus.chartUrl();
466 | jsl.$('chart_link').href = url;
467 | jsl.$('chart_image').src = url;
468 | jsl.$('chart').style.display = '';
469 |
470 | // Update the tiny URL
471 | jsl.$('tiny_url').src = 'http://tinyurl.com/api-create.php?url='+escape(url);
472 | },
473 |
474 | /**
475 | * (Re)render the results for a specific test
476 | */
477 | renderTest: function(test) {
478 | // Make a new row if needed
479 | if (!test._row) {
480 | var trow = jsl.$('test_row_template');
481 | if (!trow) return;
482 |
483 | test._row = trow.cloneNode(true);
484 | test._row.style.display = '';
485 | test._row.id = '';
486 | test._row.onclick = function() {JSLitmus._queueTest(test);};
487 | test._row.title = 'Run ' + test.name + ' test';
488 | trow.parentNode.appendChild(test._row);
489 | test._row.cells[0].innerHTML = test.name;
490 | }
491 |
492 | var cell = test._row.cells[1];
493 | var cns = [test.loopArg ? 'test_looping' : 'test_nonlooping'];
494 |
495 | if (test.error) {
496 | cns.push('test_error');
497 | cell.innerHTML =
498 | '' + test.error + '
' +
499 | '' +
500 | jsl.join(test.error, ': ', ' ') +
501 | ' ';
502 | } else {
503 | if (test.running) {
504 | cns.push('test_running');
505 | cell.innerHTML = 'running';
506 | } else if (jsl.indexOf(JSLitmus._queue, test) >= 0) {
507 | cns.push('test_pending');
508 | cell.innerHTML = 'pending';
509 | } else if (test.count) {
510 | cns.push('test_done');
511 | var hz = test.getHz(jsl.$('test_normalize').checked);
512 | cell.innerHTML = hz != Infinity ? hz : '∞';
513 | cell.title = 'Looped ' + test.count + ' times in ' + test.time + ' seconds';
514 | } else {
515 | cell.innerHTML = 'ready';
516 | }
517 | }
518 | cell.className = cns.join(' ');
519 | },
520 |
521 | /**
522 | * Create a new test
523 | */
524 | test: function(name, f) {
525 | // Create the Test object
526 | var test = new Test(name, f);
527 | JSLitmus._tests.push(test);
528 |
529 | // Re-render if the test state changes
530 | test.onChange = JSLitmus.renderTest;
531 |
532 | // Run the next test if this one finished
533 | test.onStop = function(test) {
534 | if (JSLitmus.onTestFinish) JSLitmus.onTestFinish(test);
535 | JSLitmus.currentTest = null;
536 | JSLitmus._nextTest();
537 | };
538 |
539 | // Render the new test
540 | this.renderTest(test);
541 | },
542 |
543 | /**
544 | * Add all tests to the run queue
545 | */
546 | runAll: function(e) {
547 | e = e || window.event;
548 | var reverse = e && e.shiftKey, len = JSLitmus._tests.length;
549 | for (var i = 0; i < len; i++) {
550 | JSLitmus._queueTest(JSLitmus._tests[!reverse ? i : (len - i - 1)]);
551 | }
552 | },
553 |
554 | /**
555 | * Remove all tests from the run queue. The current test has to finish on
556 | * it's own though
557 | */
558 | stop: function() {
559 | while (JSLitmus._queue.length) {
560 | var test = JSLitmus._queue.shift();
561 | JSLitmus.renderTest(test);
562 | }
563 | },
564 |
565 | /**
566 | * Run the next test in the run queue
567 | */
568 | _nextTest: function() {
569 | if (!JSLitmus.currentTest) {
570 | var test = JSLitmus._queue.shift();
571 | if (test) {
572 | jsl.$('stop_button').disabled = false;
573 | JSLitmus.currentTest = test;
574 | test.run();
575 | JSLitmus.renderTest(test);
576 | if (JSLitmus.onTestStart) JSLitmus.onTestStart(test);
577 | } else {
578 | jsl.$('stop_button').disabled = true;
579 | JSLitmus.renderChart();
580 | }
581 | }
582 | },
583 |
584 | /**
585 | * Add a test to the run queue
586 | */
587 | _queueTest: function(test) {
588 | if (jsl.indexOf(JSLitmus._queue, test) >= 0) return;
589 | JSLitmus._queue.push(test);
590 | JSLitmus.renderTest(test);
591 | JSLitmus._nextTest();
592 | },
593 |
594 | /**
595 | * Generate a Google Chart URL that shows the data for all tests
596 | */
597 | chartUrl: function() {
598 | var n = JSLitmus._tests.length, markers = [], data = [];
599 | var d, min = 0, max = -1e10;
600 | var normalize = jsl.$('test_normalize').checked;
601 |
602 | // Gather test data
603 | for (var i=0; i < JSLitmus._tests.length; i++) {
604 | var test = JSLitmus._tests[i];
605 | if (test.count) {
606 | var hz = test.getHz(normalize);
607 | var v = hz != Infinity ? hz : 0;
608 | data.push(v);
609 | markers.push('t' + jsl.escape(test.name + '(' + jsl.toLabel(hz)+ ')') + ',000000,0,' +
610 | markers.length + ',10');
611 | max = Math.max(v, max);
612 | }
613 | }
614 | if (markers.length <= 0) return null;
615 |
616 | // Build chart title
617 | var title = document.getElementsByTagName('title');
618 | title = (title && title.length) ? title[0].innerHTML : null;
619 | var chart_title = [];
620 | if (title) chart_title.push(title);
621 | chart_title.push('Ops/sec (' + platform + ')');
622 |
623 | // Build labels
624 | var labels = [jsl.toLabel(min), jsl.toLabel(max)];
625 |
626 | var w = 250, bw = 15;
627 | var bs = 5;
628 | var h = markers.length*(bw + bs) + 30 + chart_title.length*20;
629 |
630 | var params = {
631 | chtt: escape(chart_title.join('|')),
632 | chts: '000000,10',
633 | cht: 'bhg', // chart type
634 | chd: 't:' + data.join(','), // data set
635 | chds: min + ',' + max, // max/min of data
636 | chxt: 'x', // label axes
637 | chxl: '0:|' + labels.join('|'), // labels
638 | chsp: '0,1',
639 | chm: markers.join('|'), // test names
640 | chbh: [bw, 0, bs].join(','), // bar widths
641 | // chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient
642 | chs: w + 'x' + h
643 | };
644 | return 'http://chart.apis.google.com/chart?' + jsl.join(params, '=', '&');
645 | }
646 | };
647 |
648 | JSLitmus._init();
649 | })();
650 |
--------------------------------------------------------------------------------
/test/vendor/qunit.css:
--------------------------------------------------------------------------------
1 | /**
2 | * QUnit 1.2.0pre - A JavaScript Unit Testing Framework
3 | *
4 | * http://docs.jquery.com/QUnit
5 | *
6 | * Copyright (c) 2011 John Resig, Jörn Zaefferer
7 | * Dual licensed under the MIT (MIT-LICENSE.txt)
8 | * or GPL (GPL-LICENSE.txt) licenses.
9 | * Pulled Live from Git Mon Oct 31 14:00:02 UTC 2011
10 | * Last Commit: ee156923cdb01820e35e6bb579d5cf6bf55736d4
11 | */
12 |
13 | /** Font Family and Sizes */
14 |
15 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
16 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
17 | }
18 |
19 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
20 | #qunit-tests { font-size: smaller; }
21 |
22 |
23 | /** Resets */
24 |
25 | #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
26 | margin: 0;
27 | padding: 0;
28 | }
29 |
30 |
31 | /** Header */
32 |
33 | #qunit-header {
34 | padding: 0.5em 0 0.5em 1em;
35 |
36 | color: #8699a4;
37 | background-color: #0d3349;
38 |
39 | font-size: 1.5em;
40 | line-height: 1em;
41 | font-weight: normal;
42 |
43 | border-radius: 15px 15px 0 0;
44 | -moz-border-radius: 15px 15px 0 0;
45 | -webkit-border-top-right-radius: 15px;
46 | -webkit-border-top-left-radius: 15px;
47 | }
48 |
49 | #qunit-header a {
50 | text-decoration: none;
51 | color: #c2ccd1;
52 | }
53 |
54 | #qunit-header a:hover,
55 | #qunit-header a:focus {
56 | color: #fff;
57 | }
58 |
59 | #qunit-banner {
60 | height: 5px;
61 | }
62 |
63 | #qunit-testrunner-toolbar {
64 | padding: 0.5em 0 0.5em 2em;
65 | color: #5E740B;
66 | background-color: #eee;
67 | }
68 |
69 | #qunit-userAgent {
70 | padding: 0.5em 0 0.5em 2.5em;
71 | background-color: #2b81af;
72 | color: #fff;
73 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
74 | }
75 |
76 |
77 | /** Tests: Pass/Fail */
78 |
79 | #qunit-tests {
80 | list-style-position: inside;
81 | }
82 |
83 | #qunit-tests li {
84 | padding: 0.4em 0.5em 0.4em 2.5em;
85 | border-bottom: 1px solid #fff;
86 | list-style-position: inside;
87 | }
88 |
89 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
90 | display: none;
91 | }
92 |
93 | #qunit-tests li strong {
94 | cursor: pointer;
95 | }
96 |
97 | #qunit-tests li a {
98 | padding: 0.5em;
99 | color: #c2ccd1;
100 | text-decoration: none;
101 | }
102 | #qunit-tests li a:hover,
103 | #qunit-tests li a:focus {
104 | color: #000;
105 | }
106 |
107 | #qunit-tests ol {
108 | margin-top: 0.5em;
109 | padding: 0.5em;
110 |
111 | background-color: #fff;
112 |
113 | border-radius: 15px;
114 | -moz-border-radius: 15px;
115 | -webkit-border-radius: 15px;
116 |
117 | box-shadow: inset 0px 2px 13px #999;
118 | -moz-box-shadow: inset 0px 2px 13px #999;
119 | -webkit-box-shadow: inset 0px 2px 13px #999;
120 | }
121 |
122 | #qunit-tests table {
123 | border-collapse: collapse;
124 | margin-top: .2em;
125 | }
126 |
127 | #qunit-tests th {
128 | text-align: right;
129 | vertical-align: top;
130 | padding: 0 .5em 0 0;
131 | }
132 |
133 | #qunit-tests td {
134 | vertical-align: top;
135 | }
136 |
137 | #qunit-tests pre {
138 | margin: 0;
139 | white-space: pre-wrap;
140 | word-wrap: break-word;
141 | }
142 |
143 | #qunit-tests del {
144 | background-color: #e0f2be;
145 | color: #374e0c;
146 | text-decoration: none;
147 | }
148 |
149 | #qunit-tests ins {
150 | background-color: #ffcaca;
151 | color: #500;
152 | text-decoration: none;
153 | }
154 |
155 | /*** Test Counts */
156 |
157 | #qunit-tests b.counts { color: black; }
158 | #qunit-tests b.passed { color: #5E740B; }
159 | #qunit-tests b.failed { color: #710909; }
160 |
161 | #qunit-tests li li {
162 | margin: 0.5em;
163 | padding: 0.4em 0.5em 0.4em 0.5em;
164 | background-color: #fff;
165 | border-bottom: none;
166 | list-style-position: inside;
167 | }
168 |
169 | /*** Passing Styles */
170 |
171 | #qunit-tests li li.pass {
172 | color: #5E740B;
173 | background-color: #fff;
174 | border-left: 26px solid #C6E746;
175 | }
176 |
177 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
178 | #qunit-tests .pass .test-name { color: #366097; }
179 |
180 | #qunit-tests .pass .test-actual,
181 | #qunit-tests .pass .test-expected { color: #999999; }
182 |
183 | #qunit-banner.qunit-pass { background-color: #C6E746; }
184 |
185 | /*** Failing Styles */
186 |
187 | #qunit-tests li li.fail {
188 | color: #710909;
189 | background-color: #fff;
190 | border-left: 26px solid #EE5757;
191 | white-space: pre;
192 | }
193 |
194 | #qunit-tests > li:last-child {
195 | border-radius: 0 0 15px 15px;
196 | -moz-border-radius: 0 0 15px 15px;
197 | -webkit-border-bottom-right-radius: 15px;
198 | -webkit-border-bottom-left-radius: 15px;
199 | }
200 |
201 | #qunit-tests .fail { color: #000000; background-color: #EE5757; }
202 | #qunit-tests .fail .test-name,
203 | #qunit-tests .fail .module-name { color: #000000; }
204 |
205 | #qunit-tests .fail .test-actual { color: #EE5757; }
206 | #qunit-tests .fail .test-expected { color: green; }
207 |
208 | #qunit-banner.qunit-fail { background-color: #EE5757; }
209 |
210 |
211 | /** Result */
212 |
213 | #qunit-testresult {
214 | padding: 0.5em 0.5em 0.5em 2.5em;
215 |
216 | color: #2b81af;
217 | background-color: #D2E0E6;
218 |
219 | border-bottom: 1px solid white;
220 | }
221 |
222 | /** Fixture */
223 |
224 | #qunit-fixture {
225 | position: absolute;
226 | top: -10000px;
227 | left: -10000px;
228 | }
229 |
--------------------------------------------------------------------------------