├── .gitignore ├── Dockerfile ├── README.md ├── admin-notes.md ├── app.js ├── bin └── www ├── docker-compose.yml ├── lib ├── cache.js ├── clean_deps.js ├── clean_package.js ├── get_gh_username.js ├── get_maint.js ├── get_package.js ├── get_packages.js ├── get_packages_by.js ├── get_photo_url.js ├── get_revdeps.js ├── linkify.js ├── num_active.js ├── num_downloads.js ├── num_maint.js ├── num_updates.js ├── pkg_link.js ├── recent.js ├── top_downloaded.js ├── top_revdeps.js ├── trending.js ├── tv_linkify.js └── urls.js ├── package-lock.json ├── package.json ├── public ├── android-chrome-144x144.png ├── android-chrome-192x192.png ├── android-chrome-36x36.png ├── android-chrome-48x48.png ├── android-chrome-72x72.png ├── android-chrome-96x96.png ├── apple-touch-icon-114x114.png ├── apple-touch-icon-120x120.png ├── apple-touch-icon-144x144.png ├── apple-touch-icon-152x152.png ├── apple-touch-icon-180x180.png ├── apple-touch-icon-57x57.png ├── apple-touch-icon-60x60.png ├── apple-touch-icon-72x72.png ├── apple-touch-icon-76x76.png ├── apple-touch-icon-precomposed.png ├── apple-touch-icon.png ├── browserconfig.xml ├── css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap.css │ ├── bootstrap.css.map │ ├── bootstrap.min.css │ └── main.css ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon-96x96.png ├── favicon.ico ├── favicon.svg ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── img │ ├── Bayesian-small.jpg │ ├── ChemPhys-small.jpg │ ├── ClinicalTrials-small.jpg │ ├── Cluster-small.jpg │ ├── DifferentialEquations-small.jpg │ ├── Distributions-small.jpg │ ├── Econometrics-small.jpg │ ├── Environmetrics-small.jpg │ ├── ExperimentalDesign-small.jpg │ ├── Finance-small.jpg │ ├── Genetics-small.jpg │ ├── Graphics-small.jpg │ ├── HighPerformanceComputing-small.jpg │ ├── MachineLearning-small.jpg │ ├── MedicalImaging-small.jpg │ ├── MetaAnalysis-small.jpg │ ├── Multivariate-small.jpg │ ├── NaturalLanguageProcessing-small.jpg │ ├── NumericalMathematics-small.jpg │ ├── OfficialStatistics-small.jpg │ ├── Optimization-small.jpg │ ├── Pharmacokinetics-small.jpg │ ├── Phylogenetics-small.jpg │ ├── Psychometrics-small.jpg │ ├── ReproducibleResearch-small.jpg │ ├── Robust-small.jpg │ ├── SocialSciences-small.jpg │ ├── Spatial-small.jpg │ ├── SpatioTemporal-small.jpg │ ├── Survival-small.jpg │ ├── TimeSeries-small.jpg │ ├── WebTechnologies-small.jpg │ ├── gR-small.jpg │ ├── metacran-logo.svg │ └── orcid.svg ├── js │ ├── main.js │ └── vendor │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ ├── jquery-1.11.2.min.js │ │ ├── modernizr-2.8.3-respond-1.4.2.min.js │ │ └── npm.js ├── manifest.json ├── mstile-144x144.png ├── mstile-150x150.png ├── mstile-310x150.png ├── mstile-310x310.png ├── mstile-70x70.png ├── robots.txt ├── stylesheets │ └── style.css ├── tile-wide.png └── tile.png ├── routes ├── badges.js ├── check.js ├── depended.js ├── downloadlist.js ├── index.js ├── maint.js ├── mostrecent.js ├── pkg.js ├── pkglist.js ├── search.js └── trendinglist.js └── views ├── about.ejs ├── depended.ejs ├── downloaded.ejs ├── error.ejs ├── featured.ejs ├── footer.ejs ├── header.ejs ├── index.ejs ├── links.ejs ├── maint.ejs ├── maint1.ejs ├── nav.ejs ├── new.ejs ├── numbers.ejs ├── package.ejs ├── person.ejs ├── pkglist.ejs ├── pkglist_result.ejs ├── recent.ejs ├── search.ejs ├── search_hit_pkg.ejs ├── searchbox.ejs ├── searchhits.ejs ├── services.ejs ├── slogan.ejs ├── starred.ejs ├── trending.ejs └── underconstruction.ejs /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /tags 3 | /dump.rdb 4 | 5 | \.vscode/ 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:8-alpine AS build 2 | 3 | RUN apk add --no-cache git python make gcc musl-dev g++ 4 | 5 | WORKDIR /src 6 | COPY package*.json / 7 | 8 | RUN npm install -g nodemon && npm install 9 | COPY . . 10 | RUN npm install 11 | 12 | FROM node:8-alpine as final 13 | 14 | COPY --from=build /src /src 15 | WORKDIR /src 16 | EXPOSE 80 17 | ENV PORT=80 18 | 19 | CMD ["npm", "start"] 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # METACRAN 3 | 4 | > This is the Express application for the main METACRAN 5 | > website at http://www.r-pkg.org 6 | 7 | ## Contributions 8 | 9 | Yes, please! METACRAN is developed completely in the open. 10 | All code and files are on GitHub at https://github.com/metacran. 11 | 12 | Bug reports, code, design, ideas, any and all feedback 13 | are welcome. 14 | 15 | ## Run it locally 16 | 17 | Install docker and run: 18 | ``` 19 | docker compose build 20 | docker compose up 21 | ``` 22 | then go to `http://localhost:3000` in your browser. 23 | 24 | ## Bits and pieces 25 | 26 | Technology used in the app itself: 27 | 28 | - [express.js](http://expressjs.com/) 29 | - [ejs](https://github.com/mde/ejs) templates 30 | - [request](https://github.com/request/request) for running queries 31 | - [elasticsearch](https://github.com/elastic/elasticsearch-js) 32 | client to connect to the package search service 33 | 34 | Plus several smaller packages, see [package.json](/package.json). 35 | 36 | We connect to various database backends, via HTTP(S): 37 | - [crandb](https://github.com/metacran/crandb) A CouchDB database of 38 | CRAN package metadata. 39 | - [cranlogs](https://github.com/metacran/cranlogs.app) CRAN download 40 | data from the RStudio mirror. A PostgreSQL database with a HTTP API. 41 | 42 | ## License 43 | 44 | MIT © 2015-2024 Gabor Csardi and contributors 45 | -------------------------------------------------------------------------------- /admin-notes.md: -------------------------------------------------------------------------------- 1 | # 2024-04 2 | 3 | ## Move to api.r-pkg.org 4 | 5 | Very similar, but it has a redis cache, so need to create that first. 6 | Currently it has: 7 | ``` 8 | root@www:~# dokku redis:list 9 | NAME VERSION STATUS EXPOSED PORTS LINKS 10 | www redis:3.2.3 running - - 11 | wwwredis redis:3.2.3 running - www 12 | ``` 13 | so we'll name the new one wwwredis as well, although it probably does not 14 | matter. We don't need to copy the contents of the cache, but we can. 15 | 16 | ``` 17 | dokku plugin:install https://github.com/dokku/dokku-redis.git redis 18 | dokku apps:create www 19 | dokku redis:create wwwredis 20 | dokku redis:link wwwredis www 21 | dokku config:set www REDIS_HOST=dokku-redis-wwwredis REDIS_PORT=6379 22 | dokku config:set www REDIS_URL=redis://dokku-redis-wwwredis:6379 23 | dokku config:set www REDIS_HOST=dokku-redis-wwwredis REDIS_PORT=6379 24 | dokku config:set www GH_TOKEN= 25 | ``` 26 | 27 | Turn off passwords, add redis config to www app: 28 | ``` 29 | dokku redis:connect wwwredis 30 | 127.0.0.1:6379> CONFIG SET REQUIREPASS "" 31 | ``` 32 | 33 | Copy stuff: 34 | ``` 35 | dokku redis:export wwwredis > www.db 36 | ``` 37 | and then on the new server: 38 | ``` 39 | dokku redis:import wwwredis < www.db 40 | ``` 41 | 42 | Add Dockerfile to project, update node version, etc. and then deploy: 43 | ``` 44 | git remote add dokku dokku@api.r-pkg.org:www 45 | git push dokku 46 | ``` 47 | 48 | Do the same dance for copying the certs from the old server. 49 | 50 | ``` 51 | dokku domains:add www www.r-pkg.org 52 | dokku domains:add www r-pkg.org 53 | tar cf cert.tar server.{key,crt} 54 | cat cert.tar | dokku certs:add www 55 | ``` 56 | 57 | Edit `/etc/hosts` locally to test. 58 | 59 | Update DNS. www is proxied by Cloudflare, so turn off the 60 | proxy temporarily, to make sure everything works correctly. 61 | Turn the proxy back on at the end. 62 | 63 | ``` 64 | dokku letsencrypt:set www email csardi.gabor@gmail.com 65 | dokku letsencrypt:enable www 66 | ``` 67 | 68 | Enable proxy again. 69 | 70 | Stop old app a couple of hours later. 71 | 72 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var favicon = require('serve-favicon'); 4 | var logger = require('morgan'); 5 | var cookieParser = require('cookie-parser'); 6 | var bodyParser = require('body-parser'); 7 | var debug = require('debug')('web'); 8 | 9 | // Routes 10 | 11 | var routes = require('./routes/index'); 12 | var badges = require('./routes/badges'); 13 | var search = require('./routes/search'); 14 | var pkg = require('./routes/pkg'); 15 | var pkglist = require('./routes/pkglist'); 16 | var trendinglist = require('./routes/trendinglist'); 17 | var downloadlist = require('./routes/downloadlist'); 18 | var mostrecent = require('./routes/mostrecent'); 19 | var depended = require('./routes/depended'); 20 | var maint = require('./routes/maint'); 21 | var dokkucheck = require('./routes/check'); 22 | 23 | var app = express(); 24 | 25 | // view engine setup 26 | app.set('views', path.join(__dirname, 'views')); 27 | app.set('view engine', 'ejs'); 28 | 29 | app.get('/robots.txt', function (req, res) { 30 | res.type('text/plain'); 31 | res.send("User-agent: *\nCrawl-delay: 10\n"); 32 | }); 33 | 34 | // uncomment after placing your favicon in /public 35 | //app.use(favicon(__dirname + '/public/favicon.ico')); 36 | app.use(logger('dev')); 37 | app.use(bodyParser.json()); 38 | app.use(bodyParser.urlencoded({ extended: false })); 39 | app.use(cookieParser()); 40 | app.use(express.static(path.join(__dirname, 'public'))); 41 | 42 | app.use('/recent', mostrecent); 43 | app.use('/trending', trendinglist); 44 | app.use('/downloaded', downloadlist); 45 | app.use('/depended', depended); 46 | app.use('/badges', badges); 47 | app.use('/pkglist', pkglist); 48 | app.use('/pkg', pkg); 49 | app.use('/maint', maint); 50 | app.use('/', search); 51 | app.use('/', routes); 52 | app.use('/check', dokkucheck); 53 | 54 | // catch 404 and forward to error handler 55 | app.use(function(req, res, next) { 56 | var err = new Error('Not Found'); 57 | err.status = 404; 58 | next(err); 59 | }); 60 | 61 | // error handlers 62 | 63 | // development error handler 64 | // will print stacktrace 65 | if (app.get('env') === 'development') { 66 | debug('Development error handler activated, will print stacktraces in error messages.') 67 | app.use(function(err, req, res, next) { 68 | res.set('Cache-Control', 'no-cache, no-store, must-revalidate'); 69 | console.log(err) 70 | res.status(err.status || 500); 71 | res.render('error', { 72 | message: err.message, 73 | error: err 74 | }); 75 | }); 76 | } 77 | 78 | // production error handler 79 | // no stacktraces leaked to user 80 | app.use(function(err, req, res, next) { 81 | res.set('Cache-Control', 'no-cache, no-store, must-revalidate'); 82 | res.status(err.status || 500); 83 | res.render('error', { 84 | message: err.message, 85 | error: {} 86 | }); 87 | }); 88 | 89 | 90 | module.exports = app; 91 | -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var debug = require('debug')('web'); 3 | var app = require('../app'); 4 | 5 | app.set('port', process.env.PORT || 3000); 6 | 7 | var server = app.listen(app.get('port'), function() { 8 | debug('Express server listening on port ' + server.address().port); 9 | }); 10 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | redis: 3 | image: "redis:4.0.11-alpine" 4 | www: 5 | build: 6 | context: . 7 | ports: 8 | - "3000:80" 9 | environment: 10 | - REDIS_HOST=redis 11 | - REDIS_PORT=6379 12 | - REDIS_URL=redis://redis:6379 13 | -------------------------------------------------------------------------------- /lib/cache.js: -------------------------------------------------------------------------------- 1 | var redis = require('redis'); 2 | var urls = require('../lib/urls'); 3 | var client = redis.createClient(urls.redis_port, urls.redis_host); 4 | 5 | // When do things expire? 6 | var expires = { 7 | 'ghstars:': 60 * 60, // GitHub stars, 1 hour 8 | 'news:': 60 * 60 * 5, // NEWS, 5 hours 9 | 'package:': 60 * 60, // Package info, 1 hour 10 | 'pkgtv:': 60 * 60 * 24, // Task views for a package, 1 day 11 | 'readme:': 60 * 60 * 5, // Package README, 5 hours 12 | 'revdeps:': 60 * 60, // Package reverse dependencies, 1 hour 13 | 14 | 'index:num-active': 60 * 60, // # active pkgs, 1 hour 15 | 'index:num-downloads': 60 * 60 * 24, // # downloads, 1 day 16 | 'index:num-maint': 60 * 60, // # maintainers, 1 hour 17 | 'index:num-updates': 60 * 60 * 24, // # updates last week 18 | 'index:recent': 60 * 10, // # recent packages, 10 minutes 19 | 'index:top-downloaded': 60 * 60 * 24, // top downloaded, 1 day 20 | 'index:top-starred': 60 * 60 * 5, // top starred, 5 hours 21 | 'index:trending': 60 * 60 * 24, // trending packages, 1 day 22 | 'index:top-revdeps': 60 * 60, // most depended upon, 1 hour 23 | 24 | 'list:top-depended': 60 * 60 * 24 // most depended upon 25 | }; 26 | 27 | function get_expiry(key) { 28 | var exps = Object.keys(expires); 29 | for (var e in exps) { 30 | var ee = exps[e]; 31 | if (key.match(ee)) { return expires[ee]; } 32 | } 33 | 34 | return 5 * 60; // Default is five minutes 35 | } 36 | 37 | // Try to get a key from the cache 38 | // 1. If the key is there, return it 39 | // 2. If the key is not there, get the key from the remote 40 | // service, return it via the callback, and then put it 41 | // in the cache, after we returned the response. 42 | 43 | function cache(key, callback, cleanup, refresh) { 44 | client.get(key, function(err, value) { 45 | if (err || value === null) { 46 | try { 47 | // error, or not there, get it from remote 48 | refresh(key, function(err, result) { 49 | if (err) { return callback(err); } 50 | try { 51 | var clean_result = result; 52 | if (cleanup) { clean_result = cleanup(result); } 53 | callback(null, clean_result); 54 | add_to_cache(key, result); 55 | } catch(err) { 56 | return callback(err); 57 | } 58 | }) 59 | } catch(err) { 60 | return callback(err); 61 | } 62 | 63 | } else { 64 | try { 65 | // there, we are all done 66 | var clean_value = value; 67 | if (cleanup) { clean_value = cleanup(value); } 68 | callback(null, clean_value) 69 | } catch(err) { 70 | return callback(err); 71 | } 72 | } 73 | }) 74 | } 75 | 76 | function add_to_cache(key, value) { 77 | var exp = get_expiry(key); 78 | client.set(key, value, 'EX', exp); 79 | } 80 | 81 | module.exports = cache; 82 | -------------------------------------------------------------------------------- /lib/clean_deps.js: -------------------------------------------------------------------------------- 1 | 2 | function clean_deps(pkg) { 3 | 4 | function clean(field) { 5 | if (!field) return field; 6 | var deps = Object.keys(field); 7 | var index = deps.indexOf('R'); 8 | if (index > -1) { deps.splice(index, 1); } 9 | deps = deps.map(function(x) { 10 | return '' + x + ''; 11 | }) 12 | return deps.join(", "); 13 | } 14 | 15 | pkg.Imports = clean(pkg.Imports); 16 | pkg.Depends = clean(pkg.Depends); 17 | pkg.Suggests = clean(pkg.Suggests); 18 | pkg.LinkingTo = clean(pkg.LinkingTo); 19 | pkg.Enhances = clean(pkg.Enhances); 20 | 21 | return pkg; 22 | } 23 | 24 | module.exports = clean_deps; 25 | -------------------------------------------------------------------------------- /lib/clean_package.js: -------------------------------------------------------------------------------- 1 | var moment = require('moment'); 2 | var linkify = require('../lib/linkify'); 3 | 4 | function clean_package(pkg) { 5 | 6 | // Linkify URLs 7 | if (pkg.URL) { pkg.URL = linkify(pkg.URL); } 8 | if (pkg.BugReports) { pkg.BugReports = linkify(pkg.BugReports); } 9 | 10 | // Remove newlines from title 11 | if (pkg.Title) { pkg.Title = pkg.Title.replace(//g, ' '); } 12 | 13 | // Remove newlines from description, also linkify 14 | if (pkg.Description) { 15 | pkg.Description = 16 | linkify(pkg.Description.replace(//g, ' ')); 17 | } 18 | 19 | // Remove newlines from Author, SystemRequirements 20 | if (pkg.Author) { 21 | pkg.Author = pkg.Author.replace(//g, ' '); 22 | } 23 | 24 | if (pkg.SystemRequirements) { 25 | pkg.SystemRequirements = 26 | pkg.SystemRequirements.replace(//g, ' '); 27 | } 28 | 29 | // Use 'time ago' instead of date 30 | if (pkg.date) { pkg.timeago = moment(pkg.date).fromNow(); } 31 | 32 | // Take email addess from maintainer 33 | if (pkg.Maintainer) { 34 | pkg.maintainer_email = 35 | pkg.Maintainer.replace(/^.*\s*<([^>]*)>\s*$/, '$1'); 36 | } 37 | 38 | // Remove email address from maintainer 39 | if (pkg.Maintainer) { 40 | pkg.Maintainer = pkg.Maintainer.replace(/\s*<[^>]*>\s*$/, ''). 41 | trim() 42 | .replace(/^"/, '') 43 | .replace(/"$/, ''); 44 | } 45 | 46 | return pkg; 47 | } 48 | 49 | module.exports = clean_package; 50 | -------------------------------------------------------------------------------- /lib/get_gh_username.js: -------------------------------------------------------------------------------- 1 | var github_username = require('github-username'); 2 | var gh_user = require('gh-user'); 3 | 4 | var gh_token = process.env.GH_TOKEN || null; 5 | 6 | function get_gh_username(email, callback) { 7 | 8 | if (!gh_token) { return callback(null, { }); } 9 | 10 | github_username(email, gh_token, function(err, user) { 11 | 12 | // Never return an error 13 | if (err) { return callback(null, { }); } 14 | 15 | gh_user(user, gh_token, function(err, record) { 16 | 17 | // Never return an error 18 | if (err) { return callback(null, { 'login': user }); } 19 | 20 | callback(null, record); 21 | }) 22 | }) 23 | } 24 | 25 | module.exports = get_gh_username; 26 | -------------------------------------------------------------------------------- /lib/get_maint.js: -------------------------------------------------------------------------------- 1 | 2 | function get_maint(maint, callback) { 3 | callback(null, { }); 4 | } 5 | 6 | module.exports = get_maint; 7 | -------------------------------------------------------------------------------- /lib/get_package.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var cache = require('../lib/cache'); 3 | var urls = require('../lib/urls'); 4 | var clean_package = require('../lib/clean_package'); 5 | var clean_deps = require('../lib/clean_deps'); 6 | 7 | function cleanup(pkg) { 8 | return clean_deps(clean_package(JSON.parse(pkg))); 9 | } 10 | 11 | function get_package(package, callback) { 12 | 13 | try { 14 | cache('package:' + package, callback, cleanup, function(key, cb) { 15 | var url = urls.crandb + '/' + package; 16 | request(url, function(error, response, body) { 17 | cb(error || response.statusCode != 200, body || '{}'); 18 | }); 19 | }); 20 | } catch(err) { 21 | return callback(err); 22 | } 23 | } 24 | 25 | module.exports = get_package; 26 | -------------------------------------------------------------------------------- /lib/get_packages.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var urls = require('../lib/urls'); 3 | var clean_package = require('../lib/clean_package'); 4 | 5 | function get_packages(pkgnames, callback) { 6 | 7 | try { 8 | var pkgnames = pkgnames.map(function(x) { return '"' + x + '"'; }); 9 | var url2 = urls.crandb + '/-/versions?keys=[' + pkgnames.join(',') + ']'; 10 | request(url2, function(error, response, body) { 11 | if (error || response.statusCode != 200) { return callback(error); } 12 | try { 13 | var pkgs = JSON.parse(body); 14 | var keys = Object.keys(pkgs); 15 | var pkg_array = []; 16 | for (k in keys) { pkg_array.push(pkgs[keys[k]]); } 17 | callback(null, pkg_array.map(clean_package)) 18 | } catch(err) { 19 | return callback(err); 20 | } 21 | }) 22 | } catch(err) { 23 | return callback(err); 24 | } 25 | 26 | } 27 | 28 | module.exports = get_packages; 29 | -------------------------------------------------------------------------------- /lib/get_packages_by.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var get_packages = require('../lib/get_packages'); 3 | var urls = require('../lib/urls'); 4 | 5 | 6 | function get_packages_by(maint, callback) { 7 | 8 | try { 9 | var url = urls.crandb + '/-/maintainer?key=' + 10 | encodeURIComponent(JSON.stringify(maint)) 11 | 12 | request(url, function(error, response, body) { 13 | if (error || response.statusCode != 200) { return callback(error); } 14 | try { 15 | var pkgnames = JSON.parse(body).map(function(x) { return x[1]; }); 16 | 17 | get_packages(pkgnames, function(error, pkgs) { 18 | try { 19 | if (error || !pkgs[0]) { return callback(error || !pkgs[0]); } 20 | return callback(null, pkgs); 21 | } catch(err) { 22 | return callback(err); 23 | } 24 | }) 25 | } catch(err) { 26 | return callback(err); 27 | } 28 | }) 29 | 30 | } catch(err) { 31 | return callback(err); 32 | } 33 | } 34 | 35 | module.exports = get_packages_by; 36 | -------------------------------------------------------------------------------- /lib/get_photo_url.js: -------------------------------------------------------------------------------- 1 | var gravatar = require('gravatar'); 2 | 3 | function get_photo_url(maint, callback) { 4 | var url = gravatar.url(maint, { 's': '380', 'd': 'mm' }, false); 5 | callback(null, url); 6 | } 7 | 8 | module.exports = get_photo_url; 9 | -------------------------------------------------------------------------------- /lib/get_revdeps.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var cache = require('../lib/cache'); 3 | var urls = require('../lib/urls'); 4 | 5 | function get_revdeps(package, callback) { 6 | 7 | try { 8 | cache('revdeps:' + package, callback, JSON.parse, function(key, cb) { 9 | var url = urls.crandb + '/-/revdeps/' + package; 10 | request(url, function(error, response, body) { 11 | cb(error || response.statusCode != 200, body || '{}'); 12 | }); 13 | }); 14 | } catch(err) { 15 | return callback(err); 16 | } 17 | } 18 | 19 | module.exports = get_revdeps; 20 | -------------------------------------------------------------------------------- /lib/linkify.js: -------------------------------------------------------------------------------- 1 | 2 | function linkify(text) { 3 | var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; 4 | return text.replace(exp," $1"); 5 | } 6 | 7 | module.exports = linkify; 8 | -------------------------------------------------------------------------------- /lib/num_active.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var cache = require('../lib/cache'); 3 | var urls = require('../lib/urls'); 4 | var comma = require('comma-numbers')(); 5 | 6 | function cleanup(x) { return comma(JSON.parse(x)); } 7 | 8 | function num_active(callback) { 9 | 10 | try { 11 | cache('index:num-active', callback, cleanup, function(key, cb) { 12 | var url = urls.crandb + '/-/numactive'; 13 | request(url, function(error, response, body) { 14 | if (error) { return cb(error); } 15 | cb(error, body); 16 | }); 17 | }); 18 | } catch(err) { 19 | return callback(err); 20 | } 21 | } 22 | 23 | module.exports = num_active; 24 | -------------------------------------------------------------------------------- /lib/num_downloads.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var cache = require('../lib/cache'); 3 | var urls = require('../lib/urls'); 4 | var comma = require('comma-numbers')(); 5 | 6 | function cleanup(x) { return comma(JSON.parse(x)[0].downloads); } 7 | 8 | function num_downloads(callback) { 9 | 10 | try { 11 | cache('index:num-downloads', callback, cleanup, function(key, cb) { 12 | var url = urls.cranlogs + '/downloads/total/last-week'; 13 | request(url, function(error, response, body) { 14 | if (error) { return cb(error); } 15 | cb(null, body); 16 | }); 17 | }); 18 | } catch(err) { 19 | return callback(err); 20 | } 21 | } 22 | 23 | module.exports = num_downloads; 24 | -------------------------------------------------------------------------------- /lib/num_maint.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var cache = require('../lib/cache'); 3 | var urls = require('../lib/urls'); 4 | var comma = require('comma-numbers')(); 5 | 6 | function cleanup(x) { return comma(JSON.parse(x).count); } 7 | 8 | function num_maint(callback) { 9 | 10 | try { 11 | cache('index:num-maint', callback, cleanup, function(key, cb) { 12 | var url = urls.crandb + '/-/nummaint'; 13 | request(url, function(error, response, body) { 14 | if (error) { return cb(error); } 15 | cb(error, body); 16 | }); 17 | }); 18 | } catch(err) { 19 | return callback(err); 20 | } 21 | } 22 | 23 | module.exports = num_maint; 24 | -------------------------------------------------------------------------------- /lib/num_updates.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var cache = require('../lib/cache'); 3 | var urls = require('../lib/urls'); 4 | var comma = require('comma-numbers')(); 5 | 6 | function cleanup(x) { return comma(JSON.parse(x)); } 7 | 8 | function num_updates(callback) { 9 | 10 | try { 11 | cache('index:num-updates', callback, cleanup, function(key, cb) { 12 | try { 13 | var tmpd = new Date(); 14 | tmpd.setDate(tmpd.getDate() - 7); 15 | var weekago = tmpd.toISOString(); 16 | var url = urls.crandb + '/-/numpkgreleases?start_key="' + weekago + '"'; 17 | request(url, function(error, response, body) { 18 | if (error) { return cb(error); } 19 | cb(null, body); 20 | }); 21 | } catch(err) { 22 | return cb(err); 23 | } 24 | }); 25 | } catch(err) { 26 | return callback(err); 27 | } 28 | } 29 | 30 | module.exports = num_updates; 31 | -------------------------------------------------------------------------------- /lib/pkg_link.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = function(x) { 3 | return '' + x + ''; 4 | }; 5 | -------------------------------------------------------------------------------- /lib/recent.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var cache = require('../lib/cache'); 3 | var urls = require('../lib/urls'); 4 | var clean_package = require('../lib/clean_package'); 5 | 6 | function recent(callback) { 7 | 8 | try { 9 | cache('index:recent', callback, JSON.parse, function(key, cb) { 10 | var url = urls.crandb + '/-/pkgreleases?limit=9&descending=true' 11 | request(url, function(error, response, body) { 12 | if (error) { cb(error); } 13 | try { 14 | var pkgs = JSON.parse(body) 15 | .map(function(x) { return clean_package(x.package) }); 16 | cb(null, JSON.stringify(pkgs)); 17 | } catch(err) { 18 | return cb(err); 19 | } 20 | }); 21 | }); 22 | } catch(err) { 23 | return callback(err); 24 | } 25 | } 26 | 27 | module.exports = recent; 28 | -------------------------------------------------------------------------------- /lib/top_downloaded.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var cache = require('../lib/cache'); 3 | var urls = require('../lib/urls'); 4 | var clean_package = require('../lib/clean_package'); 5 | 6 | function top_downloaded(callback) { 7 | 8 | try { 9 | cache('index:top-downloaded', callback, JSON.parse, function(key, cb) { 10 | var url = urls.cranlogs + '/top/last-week/9'; 11 | request(url, function(error, response, body) { 12 | if (error) { return cb(error); } 13 | try { 14 | var pbody = JSON.parse(body).downloads; 15 | var pkgs = pbody.map(function(x) { return '"' + x.package + '"'; }); 16 | 17 | var url = urls.crandb + '/-/versions?keys=[' + pkgs.join(',') + ']'; 18 | request(url, function(error, response, body) { 19 | if (error) { return cb(error); } 20 | try { 21 | var pkgs = JSON.parse(body); 22 | var keys = Object.keys(pkgs); 23 | var pkg_array = []; 24 | for (k in keys) { pkg_array.push(pkgs[keys[k]]); } 25 | cb(null, JSON.stringify(pkg_array.map(clean_package))); 26 | } catch(err) { 27 | return cb(err); 28 | } 29 | }) 30 | } catch(err) { 31 | return cb(err); 32 | } 33 | }) 34 | }) 35 | } catch(err) { 36 | return callback(err); 37 | } 38 | } 39 | 40 | module.exports = top_downloaded; 41 | -------------------------------------------------------------------------------- /lib/top_revdeps.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var cache = require('../lib/cache'); 3 | var urls = require('../lib/urls'); 4 | var clean_package = require('../lib/clean_package'); 5 | 6 | function top_revdeps(callback) { 7 | 8 | try { 9 | cache('index:top-revdeps', callback, JSON.parse, function(key, cb) { 10 | var url = urls.crandb + '/-/topdeps/devel'; 11 | request(url, function(error, response, body) { 12 | if (error || response.statusCode != 200) { cb(error); } 13 | try { 14 | var pkgs = JSON.parse(body) 15 | .map(function(x) { return '"' + Object.keys(x)[0] + '"' }) 16 | .slice(0, 9); 17 | var url = urls.crandb + '/-/versions?keys=[' + pkgs.join(',') + ']'; 18 | request(url, function(error, response, body) { 19 | if (error) { return cb(error); } 20 | try { 21 | var pkgs = JSON.parse(body); 22 | var keys = Object.keys(pkgs); 23 | var pkg_array = []; 24 | for (k in keys) { pkg_array.push(pkgs[keys[k]]); } 25 | cb(null, JSON.stringify(pkg_array.map(clean_package))); 26 | } catch(err) { 27 | return cb(err); 28 | } 29 | }) 30 | } catch(err) { 31 | return cb(err); 32 | } 33 | }); 34 | }); 35 | } catch(err) { 36 | return callback(err); 37 | } 38 | } 39 | 40 | module.exports = top_revdeps; 41 | -------------------------------------------------------------------------------- /lib/trending.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var cache = require('../lib/cache'); 3 | var urls = require('../lib/urls'); 4 | var clean_package = require('../lib/clean_package'); 5 | 6 | function trending(callback) { 7 | 8 | try { 9 | cache('index:trending', callback, JSON.parse, function(key, cb) { 10 | var url = urls.cranlogs + '/trending'; 11 | request(url, function(error, response, body) { 12 | if (error) { return cb(error); } 13 | try { 14 | var pbody = JSON.parse(body).slice(0, 10); 15 | var pkgs = pbody.map(function(x) { return '"' + x.package + '"'; }); 16 | 17 | var url = urls.crandb + '/-/versions?keys=[' + pkgs.join(',') + ']'; 18 | request(url, function(error, response, body) { 19 | if (error) { return cb(error); } 20 | try { 21 | var pkgs = JSON.parse(body); 22 | var keys = Object.keys(pkgs); 23 | var pkg_array = []; 24 | for (k in keys) { pkg_array.push(pkgs[keys[k]]); } 25 | cb(null, JSON.stringify(pkg_array.map(clean_package))); 26 | } catch(err) { 27 | return cb(err); 28 | } 29 | }); 30 | } catch(err) { 31 | return cb(err); 32 | } 33 | }); 34 | }); 35 | } catch(err) { 36 | return callback(err); 37 | } 38 | } 39 | 40 | module.exports = trending; 41 | -------------------------------------------------------------------------------- /lib/tv_linkify.js: -------------------------------------------------------------------------------- 1 | 2 | // TODO: should we do this during preprocessing? 3 | function tv_linkify(tv) { 4 | 5 | if (tv.info) { tv.info = do_replace(tv.info); } 6 | if (tv.links) { tv.links = tv.links.map(do_replace2); } 7 | 8 | return tv; 9 | } 10 | 11 | function do_replace(entry) { 12 | return entry.replace(/(.*?)<\/pkg>/g, '$1') 13 | .replace(/(.*?)<\/view>/g, '$1') 14 | .replace(/(.*?)<\/bioc>/g, 15 | '$1') 16 | .replace(/(.*?)<\/ohat>/g, 17 | '$1') 18 | .replace(/(.*?)<\/rforge>/g, 19 | '$1') 20 | .replace(/(.*?)<\/gcode>/g, 21 | '$1'); 22 | } 23 | 24 | function do_replace2(entry) { 25 | return entry 26 | .replace(/(.*?)<\/view>/g, 'Task view: $1') 27 | .replace(/(.*?)<\/bioc>/g, 28 | 'Bioconductor package: $1') 29 | .replace(/(.*?)<\/ohat>/g, 30 | 'Omegahat package: $1') 31 | .replace(/(.*?)<\/rforge>/g, 32 | 'R-Forget project: $1') 33 | .replace(/(.*?)<\/gcode>/g, 34 | 'Google Code project: $1'); 35 | } 36 | 37 | module.exports = tv_linkify; 38 | -------------------------------------------------------------------------------- /lib/urls.js: -------------------------------------------------------------------------------- 1 | 2 | var urls = { 3 | 'crandb': 'https://crandb.r-pkg.org', 4 | 'seer': 'https://search.r-pkg.org', 5 | 'cranlogs': 'https://cranlogs.r-pkg.org', 6 | 'redis_host': process.env.REDIS_HOST || '127.0.0.1', 7 | 'redis_port': process.env.REDIS_PORT || 6379 8 | } 9 | 10 | module.exports = urls; 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "metacranweb", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "engines": { 9 | "node": "8.12.x" 10 | }, 11 | "dependencies": { 12 | "async": "~0.9.0", 13 | "body-parser": "~1.8.1", 14 | "comma-numbers": "~0.0.2", 15 | "cookie-parser": "~1.3.3", 16 | "debug": "^4.1.1", 17 | "ejs": "~2.3.1", 18 | "express": "^4.17.1", 19 | "gh-user": "~1.0.0", 20 | "github-username": "~2.0.0", 21 | "gravatar": "~1.1.1", 22 | "hiredis": "^0.4.0", 23 | "identifiers-orcid": "^0.1.1", 24 | "metacran-node": "https://github.com/metacran/metacran-node.git", 25 | "moment": "^2.24.0", 26 | "morgan": "^1.9.1", 27 | "multiline": "~1.0.2", 28 | "redis": "^0.12.1", 29 | "request": "^2.88.0", 30 | "serve-favicon": "^2.5.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /public/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/android-chrome-144x144.png -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/android-chrome-36x36.png -------------------------------------------------------------------------------- /public/android-chrome-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/android-chrome-48x48.png -------------------------------------------------------------------------------- /public/android-chrome-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/android-chrome-72x72.png -------------------------------------------------------------------------------- /public/android-chrome-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/android-chrome-96x96.png -------------------------------------------------------------------------------- /public/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /public/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /public/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /public/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /public/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /public/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /public/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /public/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /public/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | #ffc40d 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.1 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | .btn-default, 8 | .btn-primary, 9 | .btn-success, 10 | .btn-info, 11 | .btn-warning, 12 | .btn-danger { 13 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); 14 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 15 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 16 | } 17 | .btn-default:active, 18 | .btn-primary:active, 19 | .btn-success:active, 20 | .btn-info:active, 21 | .btn-warning:active, 22 | .btn-danger:active, 23 | .btn-default.active, 24 | .btn-primary.active, 25 | .btn-success.active, 26 | .btn-info.active, 27 | .btn-warning.active, 28 | .btn-danger.active { 29 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 30 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 31 | } 32 | .btn-default .badge, 33 | .btn-primary .badge, 34 | .btn-success .badge, 35 | .btn-info .badge, 36 | .btn-warning .badge, 37 | .btn-danger .badge { 38 | text-shadow: none; 39 | } 40 | .btn:active, 41 | .btn.active { 42 | background-image: none; 43 | } 44 | .btn-default { 45 | text-shadow: 0 1px 0 #fff; 46 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); 47 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); 48 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); 49 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); 50 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 51 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 52 | background-repeat: repeat-x; 53 | border-color: #dbdbdb; 54 | border-color: #ccc; 55 | } 56 | .btn-default:hover, 57 | .btn-default:focus { 58 | background-color: #e0e0e0; 59 | background-position: 0 -15px; 60 | } 61 | .btn-default:active, 62 | .btn-default.active { 63 | background-color: #e0e0e0; 64 | border-color: #dbdbdb; 65 | } 66 | .btn-default:disabled, 67 | .btn-default[disabled] { 68 | background-color: #e0e0e0; 69 | background-image: none; 70 | } 71 | .btn-primary { 72 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%); 73 | background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%); 74 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88)); 75 | background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%); 76 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0); 77 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 78 | background-repeat: repeat-x; 79 | border-color: #245580; 80 | } 81 | .btn-primary:hover, 82 | .btn-primary:focus { 83 | background-color: #265a88; 84 | background-position: 0 -15px; 85 | } 86 | .btn-primary:active, 87 | .btn-primary.active { 88 | background-color: #265a88; 89 | border-color: #245580; 90 | } 91 | .btn-primary:disabled, 92 | .btn-primary[disabled] { 93 | background-color: #265a88; 94 | background-image: none; 95 | } 96 | .btn-success { 97 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 98 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); 99 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); 100 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 101 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 102 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 103 | background-repeat: repeat-x; 104 | border-color: #3e8f3e; 105 | } 106 | .btn-success:hover, 107 | .btn-success:focus { 108 | background-color: #419641; 109 | background-position: 0 -15px; 110 | } 111 | .btn-success:active, 112 | .btn-success.active { 113 | background-color: #419641; 114 | border-color: #3e8f3e; 115 | } 116 | .btn-success:disabled, 117 | .btn-success[disabled] { 118 | background-color: #419641; 119 | background-image: none; 120 | } 121 | .btn-info { 122 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 123 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 124 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 125 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 126 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 127 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 128 | background-repeat: repeat-x; 129 | border-color: #28a4c9; 130 | } 131 | .btn-info:hover, 132 | .btn-info:focus { 133 | background-color: #2aabd2; 134 | background-position: 0 -15px; 135 | } 136 | .btn-info:active, 137 | .btn-info.active { 138 | background-color: #2aabd2; 139 | border-color: #28a4c9; 140 | } 141 | .btn-info:disabled, 142 | .btn-info[disabled] { 143 | background-color: #2aabd2; 144 | background-image: none; 145 | } 146 | .btn-warning { 147 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 148 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 149 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); 150 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 151 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 152 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 153 | background-repeat: repeat-x; 154 | border-color: #e38d13; 155 | } 156 | .btn-warning:hover, 157 | .btn-warning:focus { 158 | background-color: #eb9316; 159 | background-position: 0 -15px; 160 | } 161 | .btn-warning:active, 162 | .btn-warning.active { 163 | background-color: #eb9316; 164 | border-color: #e38d13; 165 | } 166 | .btn-warning:disabled, 167 | .btn-warning[disabled] { 168 | background-color: #eb9316; 169 | background-image: none; 170 | } 171 | .btn-danger { 172 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 173 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 174 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); 175 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 176 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 177 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 178 | background-repeat: repeat-x; 179 | border-color: #b92c28; 180 | } 181 | .btn-danger:hover, 182 | .btn-danger:focus { 183 | background-color: #c12e2a; 184 | background-position: 0 -15px; 185 | } 186 | .btn-danger:active, 187 | .btn-danger.active { 188 | background-color: #c12e2a; 189 | border-color: #b92c28; 190 | } 191 | .btn-danger:disabled, 192 | .btn-danger[disabled] { 193 | background-color: #c12e2a; 194 | background-image: none; 195 | } 196 | .thumbnail, 197 | .img-thumbnail { 198 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 199 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 200 | } 201 | .dropdown-menu > li > a:hover, 202 | .dropdown-menu > li > a:focus { 203 | background-color: #e8e8e8; 204 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 205 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 206 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 207 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 208 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 209 | background-repeat: repeat-x; 210 | } 211 | .dropdown-menu > .active > a, 212 | .dropdown-menu > .active > a:hover, 213 | .dropdown-menu > .active > a:focus { 214 | background-color: #2e6da4; 215 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 216 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 217 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 218 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 219 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 220 | background-repeat: repeat-x; 221 | } 222 | .navbar-default { 223 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); 224 | background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); 225 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); 226 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); 227 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 228 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 229 | background-repeat: repeat-x; 230 | border-radius: 4px; 231 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 232 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 233 | } 234 | .navbar-default .navbar-nav > .open > a, 235 | .navbar-default .navbar-nav > .active > a { 236 | background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 237 | background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 238 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); 239 | background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); 240 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); 241 | background-repeat: repeat-x; 242 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 243 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 244 | } 245 | .navbar-brand, 246 | .navbar-nav > li > a { 247 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 248 | } 249 | .navbar-inverse { 250 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); 251 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); 252 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); 253 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); 254 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 255 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 256 | background-repeat: repeat-x; 257 | } 258 | .navbar-inverse .navbar-nav > .open > a, 259 | .navbar-inverse .navbar-nav > .active > a { 260 | background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); 261 | background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); 262 | background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); 263 | background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); 264 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); 265 | background-repeat: repeat-x; 266 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 267 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 268 | } 269 | .navbar-inverse .navbar-brand, 270 | .navbar-inverse .navbar-nav > li > a { 271 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 272 | } 273 | .navbar-static-top, 274 | .navbar-fixed-top, 275 | .navbar-fixed-bottom { 276 | border-radius: 0; 277 | } 278 | @media (max-width: 767px) { 279 | .navbar .navbar-nav .open .dropdown-menu > .active > a, 280 | .navbar .navbar-nav .open .dropdown-menu > .active > a:hover, 281 | .navbar .navbar-nav .open .dropdown-menu > .active > a:focus { 282 | color: #fff; 283 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 284 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 285 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 286 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 287 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 288 | background-repeat: repeat-x; 289 | } 290 | } 291 | .alert { 292 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 293 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 294 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 295 | } 296 | .alert-success { 297 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 298 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 299 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); 300 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 301 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 302 | background-repeat: repeat-x; 303 | border-color: #b2dba1; 304 | } 305 | .alert-info { 306 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 307 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 308 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); 309 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 310 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 311 | background-repeat: repeat-x; 312 | border-color: #9acfea; 313 | } 314 | .alert-warning { 315 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 316 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 317 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); 318 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 319 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 320 | background-repeat: repeat-x; 321 | border-color: #f5e79e; 322 | } 323 | .alert-danger { 324 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 325 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 326 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); 327 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 328 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 329 | background-repeat: repeat-x; 330 | border-color: #dca7a7; 331 | } 332 | .progress { 333 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 334 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 335 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); 336 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 337 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 338 | background-repeat: repeat-x; 339 | } 340 | .progress-bar { 341 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%); 342 | background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%); 343 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090)); 344 | background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%); 345 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0); 346 | background-repeat: repeat-x; 347 | } 348 | .progress-bar-success { 349 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 350 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); 351 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); 352 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 353 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 354 | background-repeat: repeat-x; 355 | } 356 | .progress-bar-info { 357 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 358 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 359 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 360 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 361 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 362 | background-repeat: repeat-x; 363 | } 364 | .progress-bar-warning { 365 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 366 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 367 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); 368 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 369 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 370 | background-repeat: repeat-x; 371 | } 372 | .progress-bar-danger { 373 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 374 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); 375 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); 376 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 377 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 378 | background-repeat: repeat-x; 379 | } 380 | .progress-bar-striped { 381 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 382 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 383 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 384 | } 385 | .list-group { 386 | border-radius: 4px; 387 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 388 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 389 | } 390 | .list-group-item.active, 391 | .list-group-item.active:hover, 392 | .list-group-item.active:focus { 393 | text-shadow: 0 -1px 0 #286090; 394 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%); 395 | background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%); 396 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a)); 397 | background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%); 398 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0); 399 | background-repeat: repeat-x; 400 | border-color: #2b669a; 401 | } 402 | .list-group-item.active .badge, 403 | .list-group-item.active:hover .badge, 404 | .list-group-item.active:focus .badge { 405 | text-shadow: none; 406 | } 407 | .panel { 408 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 409 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 410 | } 411 | .panel-default > .panel-heading { 412 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 413 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 414 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 415 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 416 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 417 | background-repeat: repeat-x; 418 | } 419 | .panel-primary > .panel-heading { 420 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 421 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 422 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 423 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 424 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 425 | background-repeat: repeat-x; 426 | } 427 | .panel-success > .panel-heading { 428 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 429 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 430 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); 431 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 432 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 433 | background-repeat: repeat-x; 434 | } 435 | .panel-info > .panel-heading { 436 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 437 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 438 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); 439 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 440 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 441 | background-repeat: repeat-x; 442 | } 443 | .panel-warning > .panel-heading { 444 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 445 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 446 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); 447 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 448 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 449 | background-repeat: repeat-x; 450 | } 451 | .panel-danger > .panel-heading { 452 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 453 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 454 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); 455 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 456 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 457 | background-repeat: repeat-x; 458 | } 459 | .well { 460 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 461 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 462 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); 463 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 464 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 465 | background-repeat: repeat-x; 466 | border-color: #dcdcdc; 467 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 468 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 469 | } 470 | /*# sourceMappingURL=bootstrap-theme.css.map */ 471 | -------------------------------------------------------------------------------- /public/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.1 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-default .badge,.btn-primary .badge,.btn-success .badge,.btn-info .badge,.btn-warning .badge,.btn-danger .badge{text-shadow:none}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:hover,.btn-primary:focus{background-color:#265a88;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#265a88;border-color:#245580}.btn-primary:disabled,.btn-primary[disabled]{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:hover .badge,.list-group-item.active:focus .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -------------------------------------------------------------------------------- /public/css/main.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* ========================================================================== 4 | Author's custom styles 5 | ========================================================================== */ 6 | 7 | .page-header { 8 | color: #cb3837; 9 | } 10 | 11 | .page-header a { 12 | color: #cb3837; 13 | } 14 | 15 | .page-header a:visited { 16 | color: #cb3837; 17 | } 18 | 19 | .index-numbers a, .index-numbers a:visited { 20 | color: #000; 21 | } 22 | 23 | .logo, .logo-small { 24 | margin-left: 20px; 25 | margin-right: 10px; 26 | margin-top: 10px; 27 | } 28 | 29 | .jumbotron { 30 | padding-top: 0px; 31 | padding-bottom: 0px; 32 | } 33 | 34 | @media (min-width: 1200px) { 35 | .logo { 36 | width: 200px; 37 | height: auto; 38 | } 39 | .logo-small { 40 | width: 100px; 41 | height: auto; 42 | } 43 | } 44 | 45 | @media (max-width: 1199px) { 46 | .logo { 47 | width: 140px; 48 | height: auto; 49 | } 50 | .logo-small { 51 | width: 70px; 52 | height: auto; 53 | } 54 | } 55 | 56 | @media (min-width: 1200px) { 57 | .container { 58 | width: 80%; 59 | } 60 | } 61 | 62 | .alphatitle { 63 | color: #222; 64 | font-size: 90%; 65 | line-height: 100%; 66 | } 67 | 68 | p.alphatitle { 69 | margin-bottom: 5px; 70 | } 71 | 72 | .description { 73 | color: #555; 74 | font-size: 80%; 75 | margin-bottom: 5px; 76 | } 77 | 78 | .package { 79 | margin-bottom: 40px; 80 | font-size: 140%; 81 | } 82 | 83 | .packagetitle { 84 | font-size: 140%; 85 | color: "#00f"; 86 | } 87 | 88 | .packageauthor { 89 | color: #888; 90 | font-style: italic; 91 | font-size: 90%; 92 | padding-left: 10px; 93 | padding-top: 10px; 94 | } 95 | 96 | .packageurl { 97 | font-size: 75%; 98 | } 99 | 100 | .install-package { 101 | margin-top: 53px; 102 | font-family: monospace; 103 | } 104 | 105 | .package-page { 106 | font-size: 130%; 107 | } 108 | 109 | .package-sidebar { 110 | padding-left: 30px; 111 | } 112 | 113 | .bottom-links { 114 | margin-top: 100px; 115 | } 116 | 117 | #readme pre { 118 | border: 0px; 119 | } 120 | 121 | #tabpanel { 122 | margin-top: 70px; 123 | } 124 | 125 | #tabpanel .tab-content { 126 | padding-left: 10px; 127 | } 128 | 129 | .package-main .page-header { 130 | font-size: 300%; 131 | } 132 | 133 | .tab-pane { 134 | margin-top: 10px; 135 | } 136 | 137 | .index-number { 138 | font-size: 140%; 139 | } 140 | 141 | .slogan { 142 | margin-top: 10px; 143 | margin-bottom: 20px; 144 | } 145 | 146 | .index-number .glyphicon { 147 | font-size: 1.6em; 148 | float: left; 149 | padding-right: 5px; 150 | padding-top: 5px; 151 | } 152 | 153 | .index-number { 154 | display: block; 155 | white-space: nowrap; 156 | } 157 | 158 | .about-page { 159 | font-size: 1.2em; 160 | } 161 | 162 | .about-page p { 163 | padding-left: 20px; 164 | margin-bottom: 20px; 165 | } 166 | 167 | #Manual { 168 | height: 1000px; 169 | border: 0px; 170 | } 171 | 172 | .maint-list h3 a { 173 | color: #000; 174 | } 175 | 176 | .maint-list h3 a:visited { 177 | color: #777; 178 | } 179 | 180 | .packagelist h3 a { 181 | color: #000; 182 | } 183 | 184 | .packagelist h3 a:visited { 185 | color: #777; 186 | } 187 | 188 | .no-search-hits, .yes-search-hits { 189 | font-size: 1.5em; 190 | } 191 | 192 | .maint-box { 193 | margin-top: 90px; 194 | } 195 | 196 | .maint-data { 197 | margin-top: 20px; 198 | font-size: 1.2em; 199 | } 200 | 201 | .page-header .pkg-icons { 202 | margin-top: 10px; 203 | } 204 | 205 | .page-header .pkg-icons a { 206 | color: #555; 207 | } 208 | 209 | p.note { 210 | color: #888; 211 | } 212 | 213 | .task-view-left { 214 | padding-right: 30px; 215 | border-right: 1px solid; 216 | border-color: #eee; 217 | } 218 | 219 | .bottom-note { 220 | margin-top: 30px; 221 | } 222 | 223 | .task-view-list a { 224 | color: #000; 225 | } 226 | 227 | .task-view-list a:visited { 228 | color: #777; 229 | } 230 | 231 | .task-view-well { 232 | padding-bottom: 30px; 233 | } 234 | 235 | .task-view-topic { 236 | font-size: 130%; 237 | } 238 | 239 | .task-view-author { 240 | color: #000; 241 | } 242 | 243 | .task-view-date { 244 | color: #555; 245 | } 246 | 247 | .task-view-list p { 248 | padding-left: 27px; 249 | } 250 | 251 | .package-icon { 252 | color: #999; 253 | font-size: 80%; 254 | } 255 | 256 | .package-list-item p { 257 | padding-left: 27px; 258 | } 259 | 260 | .package-list-item { 261 | margin-bottom: 20px; 262 | } 263 | 264 | .wide-container { 265 | margin-right: 0px; 266 | margin-left: 0px; 267 | width: auto; 268 | } 269 | 270 | @media (min-width: 800px) { 271 | .wide-container { 272 | margin-right: 50px; 273 | margin-left: 50px; 274 | width: auto; 275 | } 276 | } 277 | 278 | @media (min-width: 1200px) { 279 | .wide-container { 280 | margin-right: 150px; 281 | margin-left: 150px; 282 | width: auto; 283 | } 284 | } 285 | 286 | .package-list-dateline { 287 | color: #999; 288 | font-size: 80%; 289 | } 290 | 291 | .packagelist p { 292 | margin-bottom: 2px; 293 | } 294 | 295 | .maintlist-icon { 296 | color: #999; 297 | font-size: 80%; 298 | } 299 | 300 | .maintlist-box { 301 | padding-left: 0px; 302 | } 303 | 304 | .maintlist-box p { 305 | padding-left: 27px; 306 | max-width: 450px; 307 | } 308 | 309 | .next-button { 310 | padding-left: 40px; 311 | } 312 | 313 | .maint-span { 314 | white-space: nowrap; 315 | } 316 | 317 | .readme-badge { 318 | display: none; 319 | } 320 | 321 | .package-name-title { 322 | font-size: 100%; 323 | } 324 | 325 | #readme img { 326 | max-width: 100%; 327 | } 328 | -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/favicon-96x96.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 46 | 55 | 56 | 58 | 59 | 61 | image/svg+xml 62 | 64 | 65 | 66 | 67 | 68 | 73 | 76 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/img/Bayesian-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Bayesian-small.jpg -------------------------------------------------------------------------------- /public/img/ChemPhys-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/ChemPhys-small.jpg -------------------------------------------------------------------------------- /public/img/ClinicalTrials-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/ClinicalTrials-small.jpg -------------------------------------------------------------------------------- /public/img/Cluster-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Cluster-small.jpg -------------------------------------------------------------------------------- /public/img/DifferentialEquations-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/DifferentialEquations-small.jpg -------------------------------------------------------------------------------- /public/img/Distributions-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Distributions-small.jpg -------------------------------------------------------------------------------- /public/img/Econometrics-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Econometrics-small.jpg -------------------------------------------------------------------------------- /public/img/Environmetrics-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Environmetrics-small.jpg -------------------------------------------------------------------------------- /public/img/ExperimentalDesign-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/ExperimentalDesign-small.jpg -------------------------------------------------------------------------------- /public/img/Finance-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Finance-small.jpg -------------------------------------------------------------------------------- /public/img/Genetics-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Genetics-small.jpg -------------------------------------------------------------------------------- /public/img/Graphics-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Graphics-small.jpg -------------------------------------------------------------------------------- /public/img/HighPerformanceComputing-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/HighPerformanceComputing-small.jpg -------------------------------------------------------------------------------- /public/img/MachineLearning-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/MachineLearning-small.jpg -------------------------------------------------------------------------------- /public/img/MedicalImaging-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/MedicalImaging-small.jpg -------------------------------------------------------------------------------- /public/img/MetaAnalysis-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/MetaAnalysis-small.jpg -------------------------------------------------------------------------------- /public/img/Multivariate-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Multivariate-small.jpg -------------------------------------------------------------------------------- /public/img/NaturalLanguageProcessing-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/NaturalLanguageProcessing-small.jpg -------------------------------------------------------------------------------- /public/img/NumericalMathematics-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/NumericalMathematics-small.jpg -------------------------------------------------------------------------------- /public/img/OfficialStatistics-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/OfficialStatistics-small.jpg -------------------------------------------------------------------------------- /public/img/Optimization-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Optimization-small.jpg -------------------------------------------------------------------------------- /public/img/Pharmacokinetics-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Pharmacokinetics-small.jpg -------------------------------------------------------------------------------- /public/img/Phylogenetics-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Phylogenetics-small.jpg -------------------------------------------------------------------------------- /public/img/Psychometrics-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Psychometrics-small.jpg -------------------------------------------------------------------------------- /public/img/ReproducibleResearch-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/ReproducibleResearch-small.jpg -------------------------------------------------------------------------------- /public/img/Robust-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Robust-small.jpg -------------------------------------------------------------------------------- /public/img/SocialSciences-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/SocialSciences-small.jpg -------------------------------------------------------------------------------- /public/img/Spatial-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Spatial-small.jpg -------------------------------------------------------------------------------- /public/img/SpatioTemporal-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/SpatioTemporal-small.jpg -------------------------------------------------------------------------------- /public/img/Survival-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/Survival-small.jpg -------------------------------------------------------------------------------- /public/img/TimeSeries-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/TimeSeries-small.jpg -------------------------------------------------------------------------------- /public/img/WebTechnologies-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/WebTechnologies-small.jpg -------------------------------------------------------------------------------- /public/img/gR-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metacran/metacranweb/364ab23ab0abbfb2b791ca52f12f3022740acc6b/public/img/gR-small.jpg -------------------------------------------------------------------------------- /public/img/metacran-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 46 | 55 | 56 | 58 | 59 | 61 | image/svg+xml 62 | 64 | 65 | 66 | 67 | 68 | 73 | 76 | 81 | 86 | 91 | 96 | 102 | 108 | 113 | 118 | 119 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /public/img/orcid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /public/js/main.js: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/js/vendor/modernizr-2.8.3-respond-1.4.2.min.js: -------------------------------------------------------------------------------- 1 | /* Modernizr 2.8.3 (Custom Build) | MIT & BSD 2 | * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load 3 | */ 4 | ;window.Modernizr=function(a,b,c){function D(a){j.cssText=a}function E(a,b){return D(n.join(a+";")+(b||""))}function F(a,b){return typeof a===b}function G(a,b){return!!~(""+a).indexOf(b)}function H(a,b){for(var d in a){var e=a[d];if(!G(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function I(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:F(f,"function")?f.bind(d||b):f}return!1}function J(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+p.join(d+" ")+d).split(" ");return F(b,"string")||F(b,"undefined")?H(e,b):(e=(a+" "+q.join(d+" ")+d).split(" "),I(e,b,c))}function K(){e.input=function(c){for(var d=0,e=c.length;d',a,""].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b)&&c(b).matches||!1;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=F(e[d],"function"),F(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),B={}.hasOwnProperty,C;!F(B,"undefined")&&!F(B.call,"undefined")?C=function(a,b){return B.call(a,b)}:C=function(a,b){return b in a&&F(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e}),s.flexbox=function(){return J("flexWrap")},s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.canvastext=function(){return!!e.canvas&&!!F(b.createElement("canvas").getContext("2d").fillText,"function")},s.webgl=function(){return!!a.WebGLRenderingContext},s.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:y(["@media (",n.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},s.geolocation=function(){return"geolocation"in navigator},s.postmessage=function(){return!!a.postMessage},s.websqldatabase=function(){return!!a.openDatabase},s.indexedDB=function(){return!!J("indexedDB",a)},s.hashchange=function(){return A("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},s.history=function(){return!!a.history&&!!history.pushState},s.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},s.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},s.rgba=function(){return D("background-color:rgba(150,255,150,.5)"),G(j.backgroundColor,"rgba")},s.hsla=function(){return D("background-color:hsla(120,40%,100%,.5)"),G(j.backgroundColor,"rgba")||G(j.backgroundColor,"hsla")},s.multiplebgs=function(){return D("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(j.background)},s.backgroundsize=function(){return J("backgroundSize")},s.borderimage=function(){return J("borderImage")},s.borderradius=function(){return J("borderRadius")},s.boxshadow=function(){return J("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return E("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return J("animationName")},s.csscolumns=function(){return J("columnCount")},s.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return D((a+"-webkit- ".split(" ").join(b+a)+n.join(c+a)).slice(0,-a.length)),G(j.backgroundImage,"gradient")},s.cssreflections=function(){return J("boxReflect")},s.csstransforms=function(){return!!J("transform")},s.csstransforms3d=function(){var a=!!J("perspective");return a&&"webkitPerspective"in g.style&&y("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},s.csstransitions=function(){return J("transition")},s.fontface=function(){var a;return y('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},s.generatedcontent=function(){var a;return y(["#",h,"{font:0/0 a}#",h,':after{content:"',l,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a},s.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},s.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},s.localstorage=function(){try{return localStorage.setItem(h,h),localStorage.removeItem(h),!0}catch(a){return!1}},s.sessionstorage=function(){try{return sessionStorage.setItem(h,h),sessionStorage.removeItem(h),!0}catch(a){return!1}},s.webworkers=function(){return!!a.Worker},s.applicationcache=function(){return!!a.applicationCache},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect},s.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="",(a.firstChild&&a.firstChild.namespaceURI)==r.svg},s.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(m.call(b.createElementNS(r.svg,"animate")))},s.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(m.call(b.createElementNS(r.svg,"clipPath")))};for(var L in s)C(s,L)&&(x=L.toLowerCase(),e[x]=s[L](),v.push((e[x]?"":"no-")+x));return e.input||K(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)C(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},D(""),i=k=null,function(a,b){function l(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function m(){var a=s.elements;return typeof a=="string"?a.split(" "):a}function n(a){var b=j[a[h]];return b||(b={},i++,a[h]=i,j[i]=b),b}function o(a,c,d){c||(c=b);if(k)return c.createElement(a);d||(d=n(c));var g;return d.cache[a]?g=d.cache[a].cloneNode():f.test(a)?g=(d.cache[a]=d.createElem(a)).cloneNode():g=d.createElem(a),g.canHaveChildren&&!e.test(a)&&!g.tagUrn?d.frag.appendChild(g):g}function p(a,c){a||(a=b);if(k)return a.createDocumentFragment();c=c||n(a);var d=c.frag.cloneNode(),e=0,f=m(),g=f.length;for(;e",g="hidden"in a,k=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){g=!0,k=!0}})();var s={elements:d.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:c,shivCSS:d.shivCSS!==!1,supportsUnknownElements:k,shivMethods:d.shivMethods!==!1,type:"default",shivDocument:r,createElement:o,createDocumentFragment:p};a.html5=s,r(b)}(this,b),e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.hasEvent=A,e.testProp=function(a){return H([a])},e.testAllProps=J,e.testStyles=y,e.prefixed=function(a,b,c){return b?J(a,b,c):J(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f #mq-test-1 { width: 42px; }',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){v(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q=30,r=k.getElementsByTagName("head")[0]||l,s=k.getElementsByTagName("base")[0],t=r.getElementsByTagName("link"),u=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},v=function(b){var c="clientWidth",d=l[c],e="CSS1Compat"===k.compatMode&&d||k.body[c]||d,f={},g=t[t.length-1],p=(new Date).getTime();if(b&&h&&q>p-h)return a.clearTimeout(i),i=a.setTimeout(v,q),void 0;h=p;for(var s in m)if(m.hasOwnProperty(s)){var w=m[s],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?j||u():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?j||u():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(n[w.rules]))}for(var C in o)o.hasOwnProperty(C)&&o[C]&&o[C].parentNode===r&&r.removeChild(o[C]);o.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=k.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,r.insertBefore(E,g.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(k.createTextNode(F)),o.push(E)}},w=function(a,b,d){var e=a.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},i=!f&&d;b.length&&(b+="/"),i&&(f=1);for(var j=0;f>j;j++){var k,l,o,p;i?(k=d,n.push(h(a))):(k=e[j].match(c.regex.findStyles)&&RegExp.$1,n.push(RegExp.$2&&h(RegExp.$2))),o=k.split(","),p=o.length;for(var q=0;p>q;q++)l=o[q],g(l)||m.push({media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}v()},x=function(){if(d.length){var b=d.shift();f(b.href,function(c){w(c,b.href,b.media),p[b.href]=!0,a.setTimeout(function(){x()},0)})}},y=function(){for(var b=0;b 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | :text: 37 | 38 | 39 | :text: 40 | 41 | 42 | :message: 43 | 44 | 45 | :message: 46 | 47 | 48 | 49 | */}); 50 | 51 | router.get("/", function(req, res) { 52 | res.render('underconstruction'); 53 | }) 54 | 55 | var re_pre = '^/(version|last-release|ago|version-ago|version-last-release)/'; 56 | var re_pkg = '([\\w\\.]+)'; 57 | var re_suf = '$'; 58 | var re_full = new RegExp(re_pre + re_pkg + re_suf, 'i'); 59 | 60 | router.get(re_full, function(req, res, next) { 61 | var type = req.params[0]; 62 | var package = req.params[1]; 63 | 64 | var now = new Date(); 65 | var fivemin = new Date(now.getTime() + 5 * 60000).toUTCString(); 66 | res.set('Content-Type', 'image/svg+xml'); 67 | res.set('Expires', fivemin); 68 | res.set('Cache-Control', 'max-age=300, public'); 69 | 70 | if (type == 'version') { 71 | return do_version_badge(res, next, package, req.query); 72 | } else { 73 | return do_lastrelease_badge(res, next, package, req.query, type); 74 | } 75 | 76 | }); 77 | 78 | function do_version_badge(res, next, package, query) { 79 | 80 | var url = urls.crandb + '/-/desc?keys=["' + package + '"]'; 81 | request(url, function(error, response, body) { 82 | if (error || response.statusCode != 200) { 83 | return next(error || response.statusCode); 84 | } 85 | try { 86 | var pbody = JSON.parse(body); 87 | var message = "not published"; 88 | if (pbody[package]) { 89 | message = pbody[package]["version"] || "not published"; 90 | } 91 | var svg = make_badge(res, "CRAN", message, query); 92 | 93 | res.set(200); 94 | res.send(svg); 95 | } catch(err) { 96 | return next(err); 97 | } 98 | }); 99 | } 100 | 101 | function do_lastrelease_badge(res, next, package, query, type) { 102 | 103 | var url = urls.crandb + '/' + package; 104 | request(url, function(error, response, body) { 105 | if (error) { 106 | return next(error || response.statusCode); 107 | } 108 | 109 | try { 110 | if (response.statusCode == 404) { 111 | svg = make_badge(res, 'CRAN', 'not published', query); 112 | 113 | } else { 114 | var json = JSON.parse(body); 115 | var svg; 116 | var d = new Date(json.date); 117 | var now = new Date(); 118 | if (d > now) { d = now; } 119 | var ver = json.Version; 120 | var str = d.toISOString().slice(0, 10); 121 | var ago = moment(d).fromNow(); 122 | 123 | if (type == 'last-release') { 124 | svg = make_badge(res, 'CRAN', str, query); 125 | } else if (type == 'ago') { 126 | svg = make_badge(res, 'CRAN', ago, query); 127 | } else if (type == 'version-ago') { 128 | svg = make_badge(res, 'CRAN', ver + ' – ' + ago, query); 129 | } else if (type == 'version-last-release') { 130 | svg = make_badge(res, 'CRAN', ver + ' – ' + str, query); 131 | } 132 | } 133 | 134 | res.set(200); 135 | res.send(svg); 136 | } catch(err) { 137 | return next(err); 138 | } 139 | }); 140 | } 141 | 142 | function make_badge(res, text, message, query) { 143 | 144 | var def_color = "brightgreen"; 145 | if (message == "not published") { def_color = "red" } 146 | var color = query['color'] || def_color; 147 | color = svg_colors[color] || color; 148 | 149 | var len = message.length; 150 | var no_dots = (message.match(/\./g) || []).length 151 | if (message == "not published") { 152 | var width = 53 + 6 * len; 153 | var textwidth = 47 + 3 * len; 154 | var path_d = 36 + 6 * len; 155 | } else { 156 | var width = 61 + 6 * len - 3 * no_dots; 157 | var textwidth = 51 + 3 * len - 1.5 * no_dots; 158 | var path_d = 36 + 6 * len - 1.5 * no_dots; 159 | } 160 | 161 | svg = badge_svg 162 | .replace(/:text:/g, text) 163 | .replace(/:color:/g, '#' + color.replace(/[^\w]/g, '')) 164 | .replace(/:width:/g, width) 165 | .replace(/:textwidth:/g, textwidth) 166 | .replace(/:path_d:/g, path_d) 167 | .replace(/:message:/g, message) 168 | 169 | return svg; 170 | } 171 | 172 | module.exports = router; 173 | -------------------------------------------------------------------------------- /routes/check.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | router.get('/', function(req, res) { 5 | res.set('Content-Type', 'text/plain') 6 | .send('I am alive') 7 | }) 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /routes/depended.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var request = require('request'); 4 | var cache = require('../lib/cache'); 5 | var urls = require('../lib/urls'); 6 | var clean_package = require('../lib/clean_package'); 7 | 8 | router.get('/', function(req, res, next) { 9 | 10 | cache( 11 | 'list:top-depended', 12 | // callback 13 | function(err, result) { 14 | if (err) return next(err); 15 | try { 16 | res.render( 17 | 'pkglist', 18 | { 'pkgs': result, 19 | 'title': 'Most depended upon', 20 | 'paging': false, 21 | 'pagetitle': 'Most depended upon' 22 | }); 23 | } catch(err) { 24 | return next(err); 25 | } 26 | }, 27 | JSON.parse, 28 | // refresh 29 | function(key, cb) { 30 | try { 31 | var url = urls.crandb + '/-/deps/devel'; 32 | request(url, function(error, response, body) { 33 | if (error || response.statusCode != 200) { cb(error); } 34 | try { 35 | var obj = JSON.parse(body); 36 | var pkgs = Object.keys(obj); 37 | var pkgnames = pkgs.map(function(p) { return [ p, obj[p] ]; }) 38 | .sort(function(a,b) { 39 | if (a[1] > b[1]) { return -1; } else { return 1; } }) 40 | .splice(0, 99) 41 | .map(function(x) { return '"' + x[0] + '"'; }); 42 | var url2 = urls.crandb + '/-/versions?keys=[' + 43 | pkgnames.join(',') + ']'; 44 | console.log(url2); 45 | request(url2, function(error, response, body) { 46 | if (error || response.statusCode != 200) { cb(error); } 47 | try { 48 | var pkgs = JSON.parse(body); 49 | var keys = Object.keys(pkgs); 50 | var pkg_array = []; 51 | for (k in keys) { pkg_array.push(pkgs[keys[k]]); } 52 | pkg_array = pkg_array.map(clean_package); 53 | console.log(pkg_array); 54 | cb(null, JSON.stringify(pkg_array)); 55 | } catch(err) { 56 | return cb(err); 57 | } 58 | }) 59 | } catch(err) { 60 | return cb(err); 61 | } 62 | }) 63 | } catch(err) { 64 | return next(err); 65 | } 66 | } 67 | ); 68 | }) 69 | 70 | module.exports = router; 71 | -------------------------------------------------------------------------------- /routes/downloadlist.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var request = require('request'); 4 | var urls = require('../lib/urls'); 5 | var clean_package = require('../lib/clean_package'); 6 | 7 | router.get('/', function(req, res, next) { 8 | 9 | var url = urls.cranlogs + '/top/last-week/100'; 10 | request(url, function(error, response, body) { 11 | if (error || response.statusCode != 200) { 12 | return next(error || response.statusCode); 13 | } 14 | try { 15 | var pkgnames = JSON.parse(body) 16 | .downloads 17 | .map(function(x) { return '"' + x.package + '"'; }); 18 | var url2 = urls.crandb + '/-/versions?keys=[' + pkgnames.join(',') + ']'; 19 | request(url2, function(error, response, body) { 20 | if (error || response.statusCode != 200) { 21 | return next(error || response.statusCode); 22 | } 23 | try { 24 | var pkgs = JSON.parse(body); 25 | var keys = Object.keys(pkgs); 26 | var pkg_array = []; 27 | for (k in keys) { pkg_array.push(pkgs[keys[k]]); } 28 | res.render( 29 | 'pkglist', 30 | { 'pkgs': pkg_array.map(clean_package), 31 | 'title': 'Top downloaded packages', 32 | 'paging': false, 33 | 'number': false, 34 | 'pagetitle': 'Top downloaded METACRAN' 35 | }); 36 | } catch(err) { 37 | return next(err); 38 | } 39 | }) 40 | } catch(err) { 41 | return next(err); 42 | } 43 | }) 44 | }) 45 | 46 | module.exports = router; 47 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var top_downloaded = require('../lib/top_downloaded'); 4 | var top_revdeps = require('../lib/top_revdeps'); 5 | var trending = require('../lib/trending'); 6 | var recent = require('../lib/recent'); 7 | var num_active = require('../lib/num_active'); 8 | var num_maint = require('../lib/num_maint'); 9 | var num_downloads = require('../lib/num_downloads'); 10 | var num_updates = require('../lib/num_updates'); 11 | var async = require('async'); 12 | 13 | router.get('/', function(req, res, next) { 14 | 15 | async.parallel( 16 | { 'numactive': function(cb) { 17 | num_active(function(e, r) { cb(e, r) }) }, 18 | 'nummaint': function(cb) { 19 | num_maint(function(e, r) { cb(e, r) }) }, 20 | 'numupdates': function(cb) { 21 | num_updates(function(e, r) { cb(e, r) }) }, 22 | 'numdownloads': function(cb) { 23 | num_downloads(function(e, r) { cb(e, r) }) }, 24 | 'downloads': function(cb) { 25 | top_downloaded(function(e, r) { cb(e, r) }) }, 26 | 'trending': function(cb) { 27 | trending(function(e, r) { cb(e, r) }) }, 28 | 'recent': function(cb) { 29 | recent(function(e, r) { cb(e, r) }) }, 30 | 'toprevdeps': function(cb) { 31 | top_revdeps(function(e, r) { cb(e, r) }) } 32 | }, 33 | function(err, results) { 34 | if (err) { return next(err); } 35 | try { 36 | res.render('index', results); 37 | } catch(err) { 38 | return next(err); 39 | } 40 | } 41 | ) 42 | }); 43 | 44 | router.get('/about', function(req, res) { 45 | res.render('about', { 'pagetitle': 'About METACRAN' }); 46 | }) 47 | 48 | router.get('/services', function(req, res) { 49 | res.render('services', { 'pagetitle': 'METACRAN services' }); 50 | }) 51 | 52 | module.exports = router; 53 | -------------------------------------------------------------------------------- /routes/maint.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var request = require('request'); 4 | var async = require('async'); 5 | var get_maint = require('../lib/get_maint'); 6 | var urls = require('../lib/urls'); 7 | var pkg_link = require('../lib/pkg_link'); 8 | var get_packages_by = require('../lib/get_packages_by'); 9 | var get_photo_url = require('../lib/get_photo_url'); 10 | var get_gh_username = require('../lib/get_gh_username'); 11 | 12 | router.get('/', function(req, res, next) { 13 | var startkey = req.query.startkey || ''; 14 | var url = urls.crandb + 15 | '/-/maintainernames?group_level=2&limit=100&startkey=["' + 16 | encodeURI(startkey) + '"]'; 17 | request(url, function(error, response, body) { 18 | if (error || response.statusCode != 200) { 19 | return next(error || response.statusCode); 20 | } 21 | try { 22 | var pp = JSON.parse(body) 23 | .map(function(x) { return { 'name': x[0][0], 24 | 'email': x[0][1], 25 | 'num_pkgs': x[1] }; }); 26 | var keys = pp.map(function(x) { 27 | return '"' + encodeURIComponent(x.email) + '"'; }).join(','); 28 | var url2 = urls.crandb + '/-/maintainer?keys=[' + keys + ']'; 29 | 30 | request(url2, function(error, response, body) { 31 | if (error || response.statusCode != 200) { 32 | return next(error || response.statusCode); 33 | } 34 | try { 35 | var packages = {}; 36 | JSON.parse(body).map(function(x) { 37 | var email = x[0]; 38 | var package = x[1]; 39 | if (!packages[email]) { packages[email] = []; } 40 | if (packages[email].indexOf(package) < 0) { 41 | packages[email].push(package); 42 | } 43 | }) 44 | res.render('maint', { 'people': pp, 45 | 'packages': packages, 46 | 'pkg_link': pkg_link, 47 | 'pagetitle': 'METACRAN maintainers' }); 48 | } catch(err) { 49 | return next(err); 50 | } 51 | }) 52 | } catch(err) { 53 | return next(err); 54 | } 55 | }); 56 | }) 57 | 58 | re_full = new RegExp("^/(.+)$"); 59 | router.get(re_full, function(req, res, next) { 60 | 61 | var maint = req.params[0]; 62 | 63 | async.parallel( 64 | { 65 | 'pkgs': function(cb) { 66 | get_packages_by(maint, function(e, r) { cb(e, r)}) }, 67 | 'photo': function(cb) { 68 | get_photo_url(maint, function(e, r) { cb(e, r)}) }, 69 | 'ghuser': function(cb) { 70 | get_gh_username(maint, function(e, r) { cb(e, r)}) } 71 | }, 72 | function(err, results) { 73 | 74 | if (err || results.pkgs === undefined) { 75 | var err = new Error('Not Found'); 76 | err.status = 404; 77 | return next(err); 78 | } 79 | try { 80 | results.email = maint; 81 | results.title = 'Packages by ' + 82 | results.pkgs[0].Maintainer.replace(/^'(.*)'$/, '$1'); 83 | results.paging = false; 84 | results.number = false; 85 | results.pagetitle = 'METACRAN maintainers'; 86 | results.npr = 3; 87 | results.cw = "col-md-4"; 88 | 89 | res.render('maint1', results); 90 | } catch(err) { 91 | return next(err); 92 | } 93 | } 94 | ) 95 | }) 96 | 97 | module.exports = router; 98 | -------------------------------------------------------------------------------- /routes/mostrecent.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var request = require('request'); 4 | var urls = require('../lib/urls'); 5 | var clean_package = require('../lib/clean_package'); 6 | 7 | router.get('/', function(req, res, next) { 8 | 9 | var url = urls.crandb + '/-/pkgreleases?limit=100&descending=true'; 10 | request(url, function(error, response, body) { 11 | if (error || response.statusCode != 200) { 12 | return next(error || response.statusCode); 13 | } 14 | try { 15 | var pkg_array = JSON.parse(body) 16 | .map(function(x) { return x.package; }); 17 | res.render( 18 | 'pkglist', 19 | { 'pkgs': pkg_array.map(clean_package), 20 | 'title': 'Most recently updated packages', 21 | 'paging': false, 22 | 'number': false, 23 | 'pagetitle': 'Most recent @ METACRAN' 24 | }); 25 | } catch(err) { 26 | return next(err); 27 | } 28 | }) 29 | }) 30 | 31 | module.exports = router; 32 | -------------------------------------------------------------------------------- /routes/pkg.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var get_package = require('../lib/get_package'); 4 | var get_revdeps = require('../lib/get_revdeps'); 5 | var async = require('async'); 6 | var pkg_link = require('../lib/pkg_link'); 7 | var meta = require('metacran-node'); 8 | var orcid = require('identifiers-orcid'); 9 | 10 | re_full = new RegExp("^/([\\w\\.]+)$", 'i'); 11 | 12 | router.get(re_full, function(req, res, next) { 13 | var package = req.params[0]; 14 | do_query(res, next, package); 15 | }) 16 | 17 | function do_query(res, next, package) { 18 | 19 | async.parallel( 20 | { 21 | 'pkg': function(cb) { 22 | get_package(package, function(e, r) { cb(e, r)}) }, 23 | 'revdeps': function(cb) { 24 | get_revdeps(package, function(e, r) { cb(e, r)}) } 25 | }, 26 | function(err, results) { 27 | if (err) { return next(err) } 28 | try { 29 | results.pkg_link = pkg_link; 30 | results.github_repo = meta.get_gh_repo(results.pkg); 31 | results.pdf_url = 'https://cran.rstudio.com/web/packages/'; 32 | results.pagetitle = results.pkg.Package + ' @ METACRAN'; 33 | 34 | if (results.pkg.Author) { 35 | // split authors on commas not inside [] 36 | authors_parsed = results.pkg.Author.split(/(?!\B\[[^\]]*),(?![^\[]*\]\B)/g); 37 | // extract ORCID iDs 38 | authors_parsed = authors_parsed.map((a) => { 39 | author = {}; 40 | author.name_role = a.trim(); 41 | id = orcid.extract(author.name_role); 42 | if (id.length > 0) { 43 | author.orcid = id; 44 | author.name_role = author.name_role.replace(/(\(|\<).*?(\)|\>)\)?\s*/g, ''); 45 | } 46 | return(author); 47 | }); 48 | results.pkg.authors_parsed = authors_parsed; 49 | } 50 | res.render('package', results); 51 | } catch(err) { 52 | return next(err); 53 | } 54 | } 55 | ) 56 | } 57 | 58 | module.exports = router; 59 | -------------------------------------------------------------------------------- /routes/pkglist.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var request = require('request'); 4 | var urls = require('../lib/urls'); 5 | var clean_package = require('../lib/clean_package'); 6 | 7 | var re_full = new RegExp('^/([\\w\\.]+)?$') 8 | 9 | router.get(re_full, function(req, res, next) { 10 | var from = req.params[0]; 11 | do_query(res, next, from, req.query); 12 | }) 13 | 14 | function do_query(res, next, from, query) { 15 | var startkey = query.startkey || from || ''; 16 | var url = urls.crandb + '/-/latest?limit=100&startkey="' + 17 | startkey + '"'; 18 | request(url, function(error, response, body) { 19 | if (error || response.statusCode != 200) { 20 | return next(error || response.statusCode); 21 | } 22 | try { 23 | var pkgs = JSON.parse(body); 24 | for (p in pkgs) { pkgs[p] = clean_package(pkgs[p]); } 25 | res.render('pkglist', { 'pkgs': pkgs, 26 | 'title': 'All packages', 27 | 'paging': true, 28 | 'number': false 29 | }); 30 | } catch(err) { 31 | return next(err); 32 | } 33 | }) 34 | } 35 | 36 | module.exports = router; 37 | -------------------------------------------------------------------------------- /routes/search.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var request = require('request'); 3 | var router = express.Router(); 4 | var urls = require('../lib/urls'); 5 | var clean_package = require('../lib/clean_package'); 6 | 7 | router.get("/search.html", function (req, res, next) { 8 | req.query.page = + req.query.page || 1; 9 | if (!!req.query['q']) { 10 | do_query(req, res, next); 11 | } else { 12 | show_empty(res, next); 13 | } 14 | }) 15 | 16 | function do_query(req, res, next) { 17 | 18 | const url = urls["seer"] + '/package/_search'; 19 | 20 | var fields = ["Package^10", "Title^5", "Description^2", 21 | "Author^3", "Maintainer^4", "_all"]; 22 | 23 | const body = { 24 | "from": (req.query.page - 1) * 10, 25 | "size": 10, 26 | "query": { 27 | "function_score": { 28 | "functions": [ 29 | { 30 | "field_value_factor": { 31 | "field": "revdeps", 32 | "modifier": "sqrt", 33 | "factor": 1 34 | } 35 | } 36 | ], 37 | "query": { 38 | "bool": { 39 | "must": [ 40 | { 41 | "multi_match": { 42 | "query": req.query['q'], 43 | "type": "most_fields" 44 | } 45 | } 46 | ], 47 | "should": [ 48 | { 49 | "multi_match": { 50 | "query": req.query['q'], 51 | "fields": ["Title^10", "Description^2", "_all"], 52 | "type": "phrase", 53 | "analyzer": "english_and_synonyms", 54 | "boost": 10 55 | } 56 | }, 57 | { 58 | "multi_match": { 59 | "query": req.query['q'], 60 | "fields": ["Package^20", "Title^10", "Description^2", "Author^5", "Maintainer^6", "_all"], 61 | "operator": "and", 62 | "analyzer": "english_and_synonyms", 63 | "boost": 5 64 | } 65 | } 66 | ] 67 | } 68 | } 69 | } 70 | } 71 | }; 72 | 73 | request.post( 74 | { url: url, method: 'POST', json: true, body: body }, 75 | function (error, response, body) { 76 | if (error) { 77 | next(error); 78 | } else { 79 | show_results(response.body, req, res); 80 | } 81 | }) 82 | } 83 | 84 | // Errors here will be caught by the promise, and forwarded to next() 85 | 86 | function show_results(resp, req, res) { 87 | var hits; 88 | var no_hits; 89 | if (resp.hits) { 90 | hits = resp.hits.hits.map(function (x) { 91 | x._source = clean_package(x._source); 92 | return x; 93 | }); 94 | no_hits = resp.hits.total; 95 | } else { 96 | hits = []; 97 | no_hits = 0; 98 | } 99 | var took = resp.took; 100 | var no_pages = Math.min(Math.ceil(no_hits / 10), 10); 101 | 102 | res.render('search', { 103 | 'q': req.query.q, 104 | 'page': req.query.page, 105 | 'no_hits': no_hits, 106 | 'took': took, 107 | 'hits': hits, 108 | 'no_pages': no_pages, 109 | 'pagetitle': 'METACRAN search results' 110 | }); 111 | } 112 | 113 | function show_empty(res, next) { 114 | res.redirect('/'); 115 | } 116 | 117 | module.exports = router; 118 | -------------------------------------------------------------------------------- /routes/trendinglist.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var request = require('request'); 4 | var urls = require('../lib/urls'); 5 | var clean_package = require('../lib/clean_package'); 6 | 7 | router.get('/', function(req, res, next) { 8 | 9 | var url = urls.cranlogs + '/trending'; 10 | request(url, function(error, response, body) { 11 | if (error || response.statusCode != 200) { 12 | return next(error || response.statusCode); 13 | } 14 | try { 15 | var pkgnames = JSON.parse(body) 16 | .map(function(x) { return '"' + x.package + '"'; }); 17 | var url2 = urls.crandb + '/-/versions?keys=[' + pkgnames.join(',') + ']'; 18 | request(url2, function(error, response, body) { 19 | if (error || response.statusCode != 200) { 20 | return next(error || response.statusCode); 21 | } 22 | try { 23 | var pkgs = JSON.parse(body); 24 | var keys = Object.keys(pkgs); 25 | var pkg_array = []; 26 | for (k in keys) { pkg_array.push(pkgs[keys[k]]); } 27 | res.render( 28 | 'pkglist', 29 | { 'pkgs': pkg_array.map(clean_package), 30 | 'title': 'Trending packages', 31 | 'paging': false, 32 | 'number': false, 33 | 'pagetitle': 'Trending @ METACRAN' 34 | }); 35 | } catch(err) { 36 | return next(err); 37 | } 38 | }) 39 | } catch(err) { 40 | return next(err); 41 | } 42 | }) 43 | }) 44 | 45 | module.exports = router; 46 | -------------------------------------------------------------------------------- /views/about.ejs: -------------------------------------------------------------------------------- 1 | <% include header %> 2 | <% include nav %> 3 | 4 |
5 |
6 | 9 |
10 | 11 |

What is METACRAN?

12 |

METACRAN is a (somewhat integrated) collection of small services 13 | around the CRAN repository 14 | of R packages. It contains this website, 15 | a mirror at GitHub, 16 | a database with API, 17 | package search, 18 | database of 19 | package downloads (from the RStudio mirror), 20 | tools to check R 21 | packages on GitHub, etc. 22 |

23 |

24 | See the menu on top for the complete list. 25 |

26 |

27 | METACRAN is not a CRAN project. No METACRAN 28 | services use any of the CRAN mirrors or other CRAN 29 | infrastructure, other than downloading new and updated 30 | packages and other files. 31 |

32 |

33 | METACRAN is not a separate R package repository. It contains 34 | exactly the same packages as CRAN itself. 35 |

36 | 37 |

Contribute

38 |

39 | Yes, please! METACRAN is developed completely 40 | in the open. All code and files are on Github at 41 | https://github.com/metacran 42 | . 43 |

44 |

Report bugs

45 |

46 | Found an error on this web site? Really sorry about it. 47 | Please report it in the 48 | issue 49 | tracker. Pull requests are also more than welcome. 50 |

51 |

52 | Found a METACRAN bug? METACRAN projects have issue trackers, 53 | see the list of projects on 54 | GitHub. If you can't choose a project, use 55 | this one. 56 |

57 |

Code, design, ideas, etc,

58 |

59 | Are all welcome! Send pull requests or just open issues please. 60 |

61 | 62 |
63 |
64 |
65 | 66 | <% include links %> 67 | <% include footer %> 68 | -------------------------------------------------------------------------------- /views/depended.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

5 | 7 | Most depended upon 8 | 9 |

10 | <%- include('featured', { pkgs: toprevdeps }); %> 11 |
12 | -------------------------------------------------------------------------------- /views/downloaded.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

5 | 7 | Most downloaded 8 | 9 |

10 | <%- include('featured', { pkgs: downloads }); %> 11 |
12 | -------------------------------------------------------------------------------- /views/error.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found 6 | 7 | 54 | 55 | 56 |

Page Not Found

57 |

Sorry, but the page you were trying to view does not exist.

58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /views/featured.ejs: -------------------------------------------------------------------------------- 1 | <% var ptr = 0; %> 2 | <% for (var i = 0; i < 3; i++) { %> 3 |
4 | <% for (var j = 0; j < 3; j++) { %> 5 | <% var mypkg = pkgs[ptr]; ptr++; if (mypkg === undefined) { continue; } %> 6 |
7 |

<%= mypkg.Package %>

8 |

<%= mypkg.Title %>

9 |

<%= mypkg.Version %>, published 10 | <%= mypkg.timeago %>, by 11 | <%= mypkg.Maintainer %> 12 | 13 |

14 |
15 | <% } %> 16 |
17 | <% } %> 18 | -------------------------------------------------------------------------------- /views/footer.ejs: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /views/header.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | <% if (typeof pagetitle !== 'undefined' && pagetitle) { %> 11 | <%= pagetitle %> 12 | <% } else { %> 13 | METACRAN 14 | <% } %> 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 55 | -------------------------------------------------------------------------------- /views/index.ejs: -------------------------------------------------------------------------------- 1 | <% include header %> 2 | <% include nav %> 3 | <% include slogan %> 4 | <% include numbers %> 5 | <% include downloaded %>
6 | <% include trending %>
7 | <% include depended %>
8 | <% include recent %>
9 | <% include links %> 10 | <% include footer %> 11 | -------------------------------------------------------------------------------- /views/links.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 35 | -------------------------------------------------------------------------------- /views/maint.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <% include header %> 4 | <% include nav %> 5 | 6 |
7 |

Package maintainers

8 | 9 |
10 |
11 | · 12 | <% for (var i = 65; i <= 90; i++) { %> 13 | <% var c = String.fromCharCode(i); %> 14 | <%= c %> · 15 | <% } %> 16 |
17 |
18 | 19 | 20 |
21 | <% var j=1; for (ptr in people) { %> 22 |
23 |

24 | 25 | 26 | 27 | 28 | <%= people[ptr].name %> 29 | 30 | 31 |

32 |

<%- packages[people[ptr].email].map(pkg_link).join(', '); %>

33 |
34 | <% if (! (+j % 2)) { %>
<% } %> 35 | <% j++; } %> 36 |
37 |
38 | 39 |
41 |
42 | Next page 45 |
46 |
47 | 48 | 49 | 50 | <% include links %> 51 | <% include footer %> 52 | -------------------------------------------------------------------------------- /views/maint1.ejs: -------------------------------------------------------------------------------- 1 | <% include header %> 2 | <% include nav %> 3 | 4 |
5 |
6 |
7 | <% include person %> 8 |
9 |
10 | <% include pkglist_result %> 11 |
12 |
13 |
14 | 15 | <% include links %> 16 | <% include footer %> 17 | -------------------------------------------------------------------------------- /views/nav.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 65 | -------------------------------------------------------------------------------- /views/new.ejs: -------------------------------------------------------------------------------- 1 |
2 |

Newly added

3 | <%- include('featured', { pkgs: newlyadded }); %> 4 |
5 | -------------------------------------------------------------------------------- /views/numbers.ejs: -------------------------------------------------------------------------------- 1 | 33 | -------------------------------------------------------------------------------- /views/package.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <% include header %> 4 | <% include nav %> 5 | 6 |
7 |
8 | 9 |
10 | 27 | 28 |
29 |
30 |

Reference manual

31 | 35 |

It appears you don't have a PDF plugin for this browser. You can 36 | 37 | click here to download the reference manual.

38 |
39 |
40 | 41 |
42 |
43 | 44 | 45 | 46 |
47 |
48 | 50 | install.packages("<%= pkg.Package %>") 51 |
52 |
53 |

54 | <%= pkg.Version %> 55 | by 56 | <%= pkg.Maintainer %>, <%= pkg.timeago %>

57 |
58 | 59 | <% if (pkg.URL) { %>

<%- pkg.URL %>


<% } %> 60 | 61 | <% if (pkg.BugReports) { %> 62 |

Report a bug at <%- pkg.BugReports %>


63 | <% } %> 64 | 65 |

Browse source code at 66 | 67 | https://github.com/cran/<%= pkg.Package %> 68 | 69 |

70 |
71 | 72 |

Authors: 73 | <% if (pkg.authors_parsed) { %> 74 | <% for (a in pkg.authors_parsed) { %> 75 | <%= pkg.authors_parsed[a].name_role %> 76 | <% if (pkg.authors_parsed[a].orcid) { %> 77 | 78 | 79 | <% } %> 80 | <% if (a != pkg.authors_parsed.length - 1) { %>,<% } %> 81 | <% } %> 82 | <% } else { %> 83 | <%= pkg.Author %> 84 | <% } %> 85 | 86 |

87 |
88 | 89 |

90 | Documentation: 91 | 92 |   PDF Manual 93 |   94 |
95 |

96 |
97 | 98 | <% if (pkg.License) { %>

<%= pkg.License %> 99 | license


<% } %> 100 | <% if (pkg.Imports) { %> 101 |

Imports <%- pkg.Imports %>

102 | <% } %> 103 | <% if (pkg.Depends) { %> 104 |

Depends on <%- pkg.Depends %>

105 | <% } %> 106 | <% if (pkg.Suggests) { %> 107 |

Suggests <%- pkg.Suggests %>

108 | <% } %> 109 | <% if (pkg.Enhances) { %> 110 |

Enhances <%- pkg.Enhances %>

111 | <% } %> 112 | <% if (pkg.LinkingTo) { %> 113 |

Linking to <%- pkg.LinkingTo %>

114 | <% } %> 115 | 116 | <% if (pkg.SystemRequirements) { %> 117 |

System requirements: <%= pkg.SystemRequirements %>

118 | <% } %> 119 | 120 | <% if (pkg.Package in revdeps) { %> 121 |
122 | <% var rd = revdeps[pkg.Package]; %> 123 | <% if ('Imports' in rd) { %> 124 |

Imported by 125 | <%- rd.Imports.map(pkg_link).join(', ') %>.

126 | <% } %> 127 | <% if ('Depends' in rd) { %> 128 |

Depended on by 129 | <%- rd.Depends.map(pkg_link).join(', ') %>.

130 | <% } %> 131 | <% if ('Suggests' in rd) { %> 132 |

Suggested by 133 | <%- rd.Suggests.map(pkg_link).join(', ') %>.

134 | <% } %> 135 | <% if ('Enhances' in rd) { %> 136 |

Enhanced by 137 | <%- rd.Enhances.map(pkg_link).join(', ') %>.

138 | <% } %> 139 | <% if ('LinkingTo' in rd) { %> 140 |

Linked to by 141 | <%- rd.LinkingTo.map(pkg_link).join(', ') %>.

142 | <% } %> 143 | 144 | <% } %> 145 | 146 |
147 |

148 | See at CRAN

149 | 150 |
151 | 152 |
153 |
154 | 155 | 156 | <% if (github_repo[0]) { %> 157 | 158 | <% } %> 159 | 160 | <% include links %> 161 | <% include footer %> 162 | -------------------------------------------------------------------------------- /views/person.ejs: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |
6 |
7 |
8 |

<%= email %>

9 |
10 | 11 | <% if (ghuser.login) { %> 12 |

13 | 14 | @<%= ghuser.login %> 15 | 16 | at GitHub 17 |

18 |
19 | <% } %> 20 | 21 | <% if (ghuser.company) { %>

<%= ghuser.company %>

<% } %> 22 | <% if (ghuser.location) { %>

<%= ghuser.location %>

<% } %> 23 | <% if (ghuser.company || ghuser.location) { %>
<% } %> 24 | 25 | <% if (ghuser.blog) { %> 26 |

<%= ghuser.blog %>


27 | <% } %> 28 | 29 | 30 | 31 | 32 |
33 |
34 | -------------------------------------------------------------------------------- /views/pkglist.ejs: -------------------------------------------------------------------------------- 1 | <% include header %> 2 | <% include nav %> 3 |
4 | <% include pkglist_result %> 5 |
6 | <% include links %> 7 | <% include footer %> 8 | -------------------------------------------------------------------------------- /views/pkglist_result.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <% if (typeof npr === "undefined") { npr = 4; } %> 4 | <% if (typeof cw === "undefined") { cw = "col-lg-3 col-md-6"; } %> 5 | <% if (typeof paging === "undefined") { paging = false; } %> 6 | <% if (typeof number === "undefined") { number = false; } %> 7 | <% if (typeof title === "undefined") { title = false; } %> 8 | 9 | <% if (title) { %> 10 |

<%= title %>

11 | <% } %> 12 | 13 | <% if (paging) { %> 14 |
15 |
16 | · 17 | <% for (var i = 65; i <= 90; i++) { %> 18 | <% var c = String.fromCharCode(i); %> 19 | <%= c %> · 20 | <% } %> 21 |
22 |
23 | <% } %> 24 | 25 |
26 | <% var no=0; for (var pkg in pkgs) { %> 27 |
28 |

29 | 30 | 31 | <% if (number) { %><%= no + 1 %><% } %> 32 | <%= pkgs[pkg].Package %> 33 | 34 | 35 | — <%= pkgs[pkg].Version %> 36 |

37 |

43 | <%= pkgs[pkg].Title %> 44 |

45 |
46 | <% no++; %> 47 | <% if ( ! (+no % npr)) { %>
<% } %> 48 | <% if ( ! (+no % (npr/2))) { %>
<% } %> 49 | <% } %>
50 | 51 | 52 | <% if (paging) { %> 53 |
54 |
55 | Next page 58 |
59 |
60 | <% } %> 61 | -------------------------------------------------------------------------------- /views/recent.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

5 | 7 | Recently updated 8 | 9 |

10 | <%- include('featured', { pkgs: recent }); %> 11 |
12 | -------------------------------------------------------------------------------- /views/search.ejs: -------------------------------------------------------------------------------- 1 | <% include header %> 2 | <% include nav %> 3 | <% include searchbox %> 4 | <% include searchhits %> 5 | <% include links %> 6 | <% include footer %> 7 | -------------------------------------------------------------------------------- /views/search_hit_pkg.ejs: -------------------------------------------------------------------------------- 1 |
2 |

3 | 4 | <%= pkg.Package %> 5 | 6 | 7 | — by <%= pkg.Maintainer %>, 8 | <%= pkg.timeago %> 9 | 10 |

11 |
12 |

<%= pkg.Title %>

13 |

<%- pkg.Description %>

14 |
15 |
<%- pkg.URL %>
16 |
17 | -------------------------------------------------------------------------------- /views/searchbox.ejs: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | 6 |

7 |

8 |
9 |
10 | 13 | value="<%= q %>" 14 | <% } %> 15 | placeholder="Search for a package name, keywords, people" 16 | name="q"> 17 | 18 | 21 | 22 |
23 |
24 |
25 |

26 |

27 | Examples: 28 | visualization, 29 | C++, 30 | networks, 31 | data cleaning, 32 | html widgets, 33 | ropensci. 34 |

35 |
36 |
37 |
38 | -------------------------------------------------------------------------------- /views/searchhits.ejs: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | <% if (no_hits == 0) { %> 6 |

7 | Your search – <%= q %> – did not match 8 | any packages. 9 |

10 | <% } else if (no_hits == 1) { %> 11 |

12 | Found 1 package in <%= (took/1000).toFixed(2) %> seconds 13 |

14 | <% } else { %> 15 |

16 | Found <%= no_hits %> packages in <%= (took/1000).toFixed(2) %> seconds 17 |

18 | <% } %> 19 |
20 |
21 |
22 | 23 |
24 |
25 |
26 |

27 | <% hits.forEach(function(hit) { %> 28 | <%- include('search_hit_pkg', { pkg: hit._source }); %> 29 | <% }); %> 30 |

31 |
32 |
33 |
34 | 35 | <% if (no_hits > 10) { %> 36 |
37 |
38 |
39 | 56 |
57 |
58 |
59 | <% } %> 60 | 61 | -------------------------------------------------------------------------------- /views/services.ejs: -------------------------------------------------------------------------------- 1 | <% include header %> 2 | <% include nav %> 3 | 4 |
5 |
6 | 7 | 10 |
11 |

12 | METACRAN mirrors CRAN packages at GitHub. Each CRAN package lives 13 | in its own github repository, .g. package Rcpp is 14 | at 15 | https://github.com/cran/Rcpp. All versions of all packages are 16 | included, and each version is a separate git commit, tagged with the 17 | version number. We tried to keep the original dates and 18 | authors/maintainers as well. 19 |

20 |

21 | The main goal of CRAN @ GitHub is the easy access to the 22 | source code or CRAN packages. In particular, you can 23 |

31 |

32 |
33 | 34 | 37 |
38 | 39 |

CRAN versions

40 |

41 | https://www.r-pkg.org/badges/version/{package} 42 |

43 |

44 | 45 | 46 |

47 |

48 | Shows the version number of the package on CRAN, 49 | or “not published” if the package is not 50 | published on CRAN. 51 |

52 | 53 |

CRAN release dates

54 |

55 | https://www.r-pkg.org/badges/version-ago/{package}
56 | https://www.r-pkg.org/badges/version-last-release/{package}
57 | https://www.r-pkg.org/badges/ago/{package}
58 | https://www.r-pkg.org/badges/last-release/{package} 59 |

60 |

61 | 62 | 63 | 64 | 65 |

66 |

67 | Variations on CRAN versions and release dates. 68 |

69 | 70 |

CRAN downloads

71 |

72 | https://cranlogs.r-pkg.org/badges/{summary}/{package} 73 |

74 |

75 | 76 | 77 | 78 | 79 |

80 |

81 | Shows number of downloads for a given package, see 82 | 83 | https://github.com/metacran/cranlogs.app for details. 84 |

85 | 86 |
87 | 88 | 91 |
92 | 93 |

Overview

94 |

95 | Several METACRAN services offer a public API. The API is over 96 | HTTP, and data is sent and received as JSON. 97 |

98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 |

Package database

107 |

108 | Database of all CRAN R packages. It is a CouchDB database, 109 | hosted at 110 | https://crandb.r-pkg.org/. Its API is discussed at the project 111 | page: 112 | https://github.com/metacran/crandb. 113 |

114 | 115 | 116 |

117 | Search service that indexes package metadata. It is provided 118 | by an Elasticsearch server, that exposes its search API. 119 | It is hosted at 120 | http://seer.r-pkg.org:9200/_search, and its API is the 121 | standard Elasticsearch API. 122 |

123 | 124 |

Package downloads

125 |

126 | Download summaries from the RStudio CRAN mirror, 127 | taken from 128 | http://cran-logs.rstudio.com/. 129 | It is hosted 130 | http://cranlogs.r-pkg.org and its API is discussed 131 | at the project page: 132 | 133 | https://github.com/metacran/cranlogs.app. 134 |

135 | 136 |

R versions

137 |

138 | Small API that reports current and old R versions. It is 139 | hosted at 140 | https://rversions.r-pkg.org and it API is documented 141 | at the project page: 142 | 143 | https://github.com/metacran/rversions.app. 144 |

145 | 146 |
147 | 148 | 151 |
152 |

153 | R-builder is a script that eases building R packages 154 | from GitHub with various CI services. See its project page 155 | for details: 156 | https://github.com/metacran/r-builder. 157 |

158 |
159 | 160 |
161 |
162 | 163 | <% include links %> 164 | <% include footer %> 165 | -------------------------------------------------------------------------------- /views/slogan.ejs: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |

6 | METACRAN: 7 | Search and browse all CRAN/R packages 8 |

9 |
10 |
11 |
12 | -------------------------------------------------------------------------------- /views/starred.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

5 | 7 | Featured packages 8 | 9 |

10 | <%- include('featured', { pkgs: stars }); %> 11 |
12 | -------------------------------------------------------------------------------- /views/trending.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

5 | 7 | Trending this week 8 | 9 |

10 | <%- include('featured', { pkgs: trending }); %> 11 |
12 | -------------------------------------------------------------------------------- /views/underconstruction.ejs: -------------------------------------------------------------------------------- 1 | <% include header %> 2 | <% include nav %> 3 | 4 |
5 |
6 | 10 |
11 |
12 | 13 | <% include links %> 14 | <% include footer %> 15 | --------------------------------------------------------------------------------