├── .circleci └── config.yml ├── .dockerignore ├── .ebextensions └── 10docker.config ├── .editorconfig ├── .env.sample ├── .eslintrc ├── .gitignore ├── .sailsrc ├── Dockerfile ├── Dockerrun.aws.json.in ├── Gruntfile.js ├── LICENSE.md ├── Procfile ├── README.md ├── api ├── _apidoc.js ├── controllers │ ├── .gitkeep │ ├── AuthController.js │ ├── BadgeController.js │ ├── CampusController.js │ ├── CollaboratorController.js │ ├── ExampleController.js │ ├── HomeController.js │ ├── PackageController.js │ ├── PackageVersionController.js │ ├── ReviewController.js │ ├── RstudioController.js │ ├── SearchController.js │ ├── TaskViewController.js │ ├── TopicController.js │ ├── TrendsController.js │ ├── UserController.js │ └── WorkerController.js ├── hooks │ ├── aws │ │ └── index.js │ ├── elasticsearch │ │ └── index.js │ ├── redis │ │ └── index.js │ └── worker │ │ └── index.js ├── models │ ├── .gitkeep │ ├── Alias.js │ ├── ApiToken.js │ ├── Argument.js │ ├── BiocDownloadStatistics.js │ ├── Collaborator.js │ ├── Dependency.js │ ├── DownloadStatistic.js │ ├── Example.js │ ├── Package.js │ ├── PackageVersion.js │ ├── ParsingJob.js │ ├── Percentile.js │ ├── Repository.js │ ├── Review.js │ ├── Section.js │ ├── Star.js │ ├── Tag.js │ ├── TaskView.js │ ├── Topic.js │ └── User.js ├── policies │ ├── api_auth.js │ ├── flash.js │ └── sessionAuth.js ├── responses │ ├── badRequest.js │ ├── created.js │ ├── forbidden.js │ ├── notFound.js │ ├── ok.js │ ├── rstudio_redirect.js │ └── serverError.js └── services │ ├── .gitkeep │ ├── AuthorService.js │ ├── CronService.js │ ├── DownloadStatsService.js │ ├── ElasticSearchService.js │ ├── FlashService.js │ ├── PackageService.js │ ├── PackageVersionService.js │ ├── RStudioService.js │ ├── RecoverService.js │ ├── RedisService.js │ ├── TopicService.js │ ├── Utils.js │ ├── passport.js │ └── s3Service.js ├── apidoc.json ├── app.js ├── assets ├── css │ ├── bootstrap-glyphicons.css │ ├── bootstrap-treeview.css │ └── nv.d3.min.css ├── favicon.ico ├── images │ ├── .gitkeep │ ├── GitHub-Mark-32px.png │ ├── logo-dark.png │ ├── logo.png │ └── placeholder.png ├── js │ ├── dependencies │ │ ├── async_loader.js │ │ ├── highlight.pack.js │ │ ├── highlightjs-line-numbers.js │ │ └── rstudio_navigator.js │ ├── helpers │ │ ├── boot.js │ │ ├── downloadStats.js │ │ ├── list-table-filtering.js │ │ ├── toggle.js │ │ └── utils.js │ ├── libs │ │ ├── bootstrap-treeview.js │ │ ├── countUp.min.js │ │ ├── experiment.js │ │ ├── jquery.cookie-1.4.1.min.js │ │ ├── marked.min.js │ │ └── tooltip.js │ ├── pages │ │ ├── collaborator.js │ │ ├── examples.js │ │ ├── package.js │ │ ├── search.js │ │ ├── source.js │ │ ├── task_views.js │ │ ├── trending.js │ │ └── user.js │ └── search.js ├── robots.txt ├── sitemap │ ├── sitemap-1.xml.gz │ ├── sitemap-2.xml.gz │ ├── sitemap-3.xml.gz │ ├── sitemap-4.xml.gz │ ├── sitemap-5.xml.gz │ └── sitemapindex.xml.gz ├── styles │ ├── application.scss │ ├── jquery-ui │ │ ├── core.scss │ │ └── tabs.scss │ ├── pages │ │ ├── _authentication.scss │ │ ├── _collaborator.scss │ │ ├── _error-page.scss │ │ ├── _examples.scss │ │ ├── _home.scss │ │ ├── _package-details.scss │ │ ├── _package-header.scss │ │ ├── _package-readme.scss │ │ ├── _package-source.scss │ │ ├── _package-vignettes.scss │ │ ├── _package.scss │ │ ├── _search.scss │ │ ├── _shared.scss │ │ ├── _task-view-sidebar.scss │ │ ├── _task-views.scss │ │ ├── _topic-header.scss │ │ ├── _topic.scss │ │ ├── _trends.scss │ │ └── _user.scss │ ├── styleguide │ │ ├── _base.scss │ │ ├── _globals.scss │ │ ├── _normalize.scss │ │ └── partials │ │ │ ├── _buttons.scss │ │ │ ├── _flash.scss │ │ │ ├── _footer.scss │ │ │ ├── _forms.scss │ │ │ ├── _grid.scss │ │ │ ├── _labels.scss │ │ │ ├── _lists.scss │ │ │ ├── _navbar.scss │ │ │ ├── _rstudio.scss │ │ │ ├── _tables.scss │ │ │ ├── _tooltip.scss │ │ │ └── _typography.scss │ └── widgets │ │ ├── _big-number.scss │ │ ├── _github-markdown.scss │ │ ├── _loader.scss │ │ ├── _modal.scss │ │ ├── _search.scss │ │ └── mono-blue.css └── templates │ └── .gitkeep ├── build.sh ├── catalog-info.yaml ├── config ├── blueprints.js ├── bootstrap.js ├── connections.js ├── cors.js ├── csrf.js ├── elasticsearch.js ├── env │ ├── development.js │ ├── docker.js │ ├── production.js │ ├── staging.js │ └── worker.js ├── globals.js ├── http.js ├── i18n.js ├── locales │ ├── _README.md │ ├── de.json │ ├── en.json │ ├── es.json │ └── fr.json ├── log.js ├── models.js ├── policies.js ├── redis.js ├── routes.js ├── session.js ├── sockets.js └── views.js ├── cron.yaml ├── database.json ├── deploy_worker.sh ├── docker-compose.yml ├── ecs.json ├── ecs.worker.json ├── jake ├── Jakefile.js └── sails-lifter.js ├── migrations ├── 20160603105133-initial.js ├── 20160607121610-indexAliases.js ├── 20160609193515-title-allow-null.js ├── 20160610094821-argument-description.js ├── 20160612100705-users.js ├── 20160612150901-package-type.js ├── 20160612161712-package-type-allow-null.js ├── 20160612162625-topic-add-sourceJSON.js ├── 20160613085210-comments.js ├── 20160614083536-review-model.js ├── 20160621104843-task-views.js ├── 20160624081405-download-statistics.js ├── 20160626120528-token-table.js ├── 20160626154713-unique-review.js ├── 20160708081226-readme-in-versions.js ├── 20160711142622-splitted-downloads.js ├── 20160714072116-downloads-per-day.js ├── 20160714100838-stringToText.js ├── 20160714102013-add-dependency-enum.js ├── 20160714113658-cascading-delete-of-sections.js ├── 20160812141926-BiocDownloads.js ├── 20160821202039-stars.js ├── 20160822080118-examples.js ├── 20160830084534-percentiles.js ├── 20170809033252-parser-version.js ├── 20170809222533-parsing-jobs.js └── sqls │ ├── 20160603105133-migration-name-down.sql │ ├── 20160603105133-migration-name-up.sql │ ├── 20160609193515-title-allow-null-down.sql │ ├── 20160609193515-title-allow-null-up.sql │ ├── 20160610094821-argument-description-down.sql │ ├── 20160610094821-argument-description-up.sql │ ├── 20160612150901-package-type-down.sql │ ├── 20160612150901-package-type-up.sql │ ├── 20160612161712-package-type-allow-null-down.sql │ ├── 20160612161712-package-type-allow-null-up.sql │ ├── 20160612162625-topic-add-sourceJSON-down.sql │ ├── 20160612162625-topic-add-sourceJSON-up.sql │ ├── 20160613085210-comments-down.sql │ ├── 20160613085210-comments-up.sql │ ├── 20160614083536-review-model-down.sql │ ├── 20160614083536-review-model-up.sql │ ├── 20160621104843-task-views-down.sql │ ├── 20160621104843-task-views-up.sql │ ├── 20160624081405-download-statistics-down.sql │ ├── 20160624081405-download-statistics-up.sql │ ├── 20160626120528-token-table-down.sql │ ├── 20160626120528-token-table-up.sql │ ├── 20160708081226-readme-in-versions-down.sql │ ├── 20160708081226-readme-in-versions-up.sql │ ├── 20160711142622-splitted-downloads-down.sql │ ├── 20160711142622-splitted-downloads-up.sql │ ├── 20160714072116-downloads-per-day-down.sql │ ├── 20160714072116-downloads-per-day-up.sql │ ├── 20160714100838-stringToText-down.sql │ ├── 20160714100838-stringToText-up.sql │ ├── 20160714102013-add-dependency-enum-down.sql │ ├── 20160714102013-add-dependency-enum-up.sql │ ├── 20160714113658-cascading-delete-of-sections-down.sql │ ├── 20160714113658-cascading-delete-of-sections-up.sql │ ├── 20160812141926-BiocDownloads-down.sql │ ├── 20160812141926-BiocDownloads-up.sql │ ├── 20160821202039-stars-down.sql │ ├── 20160821202039-stars-up.sql │ ├── 20160822080118-examples-down.sql │ ├── 20160822080118-examples-up.sql │ ├── 20160830084534-percentiles-down.sql │ ├── 20160830084534-percentiles-up.sql │ ├── 20170809033252-parser-version-down.sql │ ├── 20170809033252-parser-version-up.sql │ ├── 20170809222533-parsing-jobs-down.sql │ └── 20170809222533-parsing-jobs-up.sql ├── newrelic.js ├── package-lock.json ├── package.json ├── proxy └── conf.d │ └── default.conf ├── tasks ├── README.md ├── config │ ├── apidoc.js │ ├── clean.js │ ├── coffee.js │ ├── concat.js │ ├── copy.js │ ├── cssmin.js │ ├── jst.js │ ├── sails-linker.js │ ├── sails-tasks.js │ ├── sass.js │ ├── sync.js │ ├── uglify.js │ ├── versioning.js │ └── watch.js ├── pipeline.js └── register │ ├── build.js │ ├── buildProd.js │ ├── compileAssets.js │ ├── default.js │ ├── linkAssets.js │ ├── linkAssetsBuild.js │ ├── linkAssetsBuildProd.js │ ├── prod.js │ └── syncAssets.js ├── test └── test-version-ordering.js └── views ├── 403.ejs ├── 404.ejs ├── 500.ejs ├── README.md ├── auth ├── login.ejs ├── modalLogin.ejs └── register.ejs ├── badges ├── downloads_badge.ejs └── version_badge.ejs ├── campus └── help.ejs ├── collaborator └── show.ejs ├── homepage.ejs ├── inner_layout.ejs ├── layout.ejs ├── package └── show.ejs ├── package_version ├── _details.ejs ├── _header.ejs ├── readme.ejs ├── show.ejs ├── source.ejs └── vignette.ejs ├── rStudio ├── list_options.ejs ├── make_default.ejs ├── package_not_found.ejs ├── topic_not_found.ejs ├── update.ejs └── view.ejs ├── rstudio_layout.ejs ├── search ├── function_results.ejs ├── keyword_result.ejs ├── package_results.ejs └── result.ejs ├── shared ├── _dc_footer.ejs ├── _example.ejs ├── _flash.ejs ├── _footer.ejs ├── _loader.ejs ├── _navbar.ejs ├── _navigation.ejs ├── _percentile.ejs ├── _post_example.ejs └── _snowplow.ejs ├── task_view ├── _sidebar.ejs ├── index.ejs └── show.ejs ├── topic ├── _header.ejs └── show.ejs ├── trends └── show.ejs └── user └── show.ejs /.dockerignore: -------------------------------------------------------------------------------- 1 | .tmp/ 2 | node_modules/ 3 | .env 4 | .newrelic_agent.log 5 | Procfile 6 | docker-compose.yml 7 | err.log 8 | -------------------------------------------------------------------------------- /.ebextensions/10docker.config: -------------------------------------------------------------------------------- 1 | files: 2 | "/etc/cron.d/docker-cleanup": 3 | mode: "000644" 4 | owner: root 5 | group: root 6 | content: "0 * * * * root /var/lib/docker-cleanup/docker_cleanup.sh --actually-run 3" 7 | 8 | "/var/lib/docker-cleanup/docker_cleanup.sh": 9 | mode: "000755" 10 | owner: root 11 | group: root 12 | source: https://bitbucket.org/datamind/docker-cleanup/raw/master/docker_cleanup.sh 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | ELASTICSEARCH_URL=http://elasticsearch_url 2 | AWS_BUCKET=assets.rdocumentation.org 3 | BASE_URL=http://localhost:3000 4 | PORT=3000 5 | 6 | DATABASE_HOST=127.0.0.1 7 | DATABASE_USERNAME=root 8 | DATABASE_PASSWORD=password 9 | DATABASE_NAME=rdocs 10 | DATABASE_PORT=3306 11 | 12 | REDIS_URL=redis://127.0.0.1:6379 13 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-es5", 3 | "globals": { 4 | "BiocDownloadStatistics": false, 5 | "Package": false, 6 | "PackageVersion": false, 7 | "ElasticSearchService": false, 8 | "Collaborator": false, 9 | "Dependency": false, 10 | "Repository": false, 11 | "Percentile": false, 12 | "PackageService": false, 13 | "PackageVersionService": false, 14 | "DownloadStatistic": false, 15 | "Example": false, 16 | "RedisService": false, 17 | "FlashService": false, 18 | "Utils": false, 19 | "TaskView": false, 20 | "Star": false, 21 | "Promise": false, 22 | "ParsingJob": false, 23 | "sequelize": false, 24 | "Sequelize": false, 25 | "sails": false, 26 | "s3Service": false, 27 | "Review": false, 28 | "es": false 29 | }, 30 | "rules": { 31 | "no-shadow": [ 32 | 2, 33 | { 34 | "allow": ["packages"] 35 | } 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /.sailsrc: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "modules": {} 4 | }, 5 | 6 | "hooks": { 7 | "orm": false, 8 | "blueprints": false, 9 | "pubsub": false, 10 | "sockets":false 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:8.17 2 | 3 | RUN sed -i -e 's/deb.debian.org/archive.debian.org/g' -e 's|security.debian.org|archive.debian.org/|g' -e '/stretch-updates/d' /etc/apt/sources.list && \ 4 | apt-get update && \ 5 | apt-get install -y python3 build-essential 6 | 7 | RUN npm install -g pm2 node-gyp sails grunt bower jake npm-check-updates 8 | 9 | ARG VERSION 10 | ENV VERSION=${VERSION} 11 | 12 | ENV NODE_ENV production 13 | 14 | # use changes to package.json to force Docker not to use the cache 15 | # when we change our application's nodejs dependencies: 16 | ADD package.json /tmp/package.json 17 | ADD package-lock.json /tmp/package-lock.json 18 | RUN cd /tmp && npm install --unsafe-perm --production 19 | RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/ 20 | 21 | # From here we load our application's code in, therefore the previous docker 22 | # "layer" thats been cached will be used if possible 23 | WORKDIR /opt/app 24 | ADD . /opt/app 25 | 26 | #Expose port 27 | EXPOSE 3000 28 | 29 | CMD bash -c "npm start" 30 | -------------------------------------------------------------------------------- /Dockerrun.aws.json.in: -------------------------------------------------------------------------------- 1 | { 2 | "AWSEBDockerrunVersion": 2, 3 | 4 | "authentication": { 5 | "bucket": "elasticbeanstalk-us-west-1-352211034136", 6 | "key": "resources/dockercfg" 7 | }, 8 | 9 | "volumes": [ 10 | { 11 | "name": "nginx-proxy-conf", 12 | "host": { 13 | "sourcePath": "/var/app/current/proxy/conf.d" 14 | } 15 | } 16 | ], 17 | 18 | "containerDefinitions": [ 19 | { 20 | "name": "rdocsv2", 21 | "image": "dockerhub.datacamp.com:443/rdocsv2:$version", 22 | "environment": [ ], 23 | "essential": true, 24 | "memory": $memory, 25 | "portMappings": [ 26 | { 27 | "hostPort": 1337, 28 | "containerPort": 1337 29 | } 30 | ], 31 | "mountPoints": [ ] 32 | }, 33 | { 34 | "name": "nginx-proxy", 35 | "image": "nginx", 36 | "essential": true, 37 | "memory": 128, 38 | "portMappings": [ 39 | { 40 | "hostPort": 80, 41 | "containerPort": 80 42 | }, 43 | { 44 | "hostPort": 81, 45 | "containerPort": 81 46 | } 47 | ], 48 | "links": [ 49 | "rdocsv2" 50 | ], 51 | "mountPoints": [ 52 | { 53 | "sourceVolume": "nginx-proxy-conf", 54 | "containerPath": "/etc/nginx/conf.d", 55 | "readOnly": true 56 | }, 57 | { 58 | "sourceVolume": "awseb-logs-nginx-proxy", 59 | "containerPath": "/var/log/nginx" 60 | } 61 | ] 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 DataCamp Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: NODE_ENV=production PORT=5000 node app.js 2 | dev: NODE_ENV=locals PORT=5000 node app.js 3 | migrate: node -r dotenv/config node_modules/db-migrate/bin/db-migrate up 4 | debug: NODE_ENV=production PORT=5000 node -r dotenv/config node_modules/sails/bin/sails debug 5 | console: node -r dotenv/config node_modules/sails/bin/sails console 6 | clean-task: grunt sails_tasks:authorCleaning 7 | recover-maintainers: grunt sails_tasks:maintainerRecover 8 | -------------------------------------------------------------------------------- /api/_apidoc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @apiDefine Timestamps 3 | * 4 | * @apiSuccess {DateTime} created_at Date of creation 5 | * @apiSuccess {DateTime} updated_at Date of last update 6 | 7 | */ 8 | -------------------------------------------------------------------------------- /api/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/api/controllers/.gitkeep -------------------------------------------------------------------------------- /api/controllers/AuthController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AuthController 3 | * 4 | */ 5 | var passport = require('passport'); 6 | module.exports = { 7 | 8 | login: function(req, res) { 9 | if (req.allParams().rdr) { 10 | req.session.rdr = req.allParams().rdr; 11 | } 12 | res.view(); 13 | }, 14 | 15 | modalLogin: function(req, res) { 16 | if (req.allParams().rdr) { 17 | req.session.rdr = req.allParams().rdr; 18 | } 19 | res.view('auth/modalLogin.ejs', {layout: null}); 20 | }, 21 | 22 | register: function(req, res) { 23 | req.session.rdr = req.allParams().rdr; 24 | res.view(); 25 | }, 26 | 27 | process: function(req, res) { 28 | var successRedirect = req.session.rdr || '/'; 29 | passport.authenticate('local', { 30 | failureRedirect: '/login', 31 | failureFlash: 'Invalid Username or password.' 32 | })(req, res, function() { 33 | return res.rstudio_redirect(303, successRedirect); 34 | }); 35 | }, 36 | 37 | rstudioProcess: function(req, res) { 38 | req.session.rdr || '/'; 39 | passport.authenticate('local', function cb(err, user) { 40 | if (err || !user) { 41 | return res.json({status: 'invalid', message: 'Not Logged'}); 42 | } 43 | req.logIn(user, function(err) { 44 | if (err) { return res.json({status: "invalid", message: "Not Logged"}) } 45 | return res.json({status :"succes", message: "Logged"}) 46 | }); 47 | return null; 48 | })(req, res); 49 | }, 50 | 51 | modalProcess: function(req, res) { 52 | passport.authenticate('local', function cb(err, user) { 53 | if (err) { 54 | return res.json({ status: 'error' }); 55 | } 56 | if (!user) { 57 | return res.json({ status: 'invalid' }); 58 | } 59 | req.logIn(user, function(error) { 60 | if (error) { return res.json({ status: 'error' }); } 61 | return res.json({ status: 'success' }); 62 | }); 63 | return null; 64 | })(req, res); 65 | }, 66 | 67 | logout: function(req, res) { 68 | req.session.rdr = null; // Reset the session rdr 69 | req.logout(); 70 | res.rstudio_redirect(303, '/'); 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /api/controllers/CampusController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * CampusController 3 | * 4 | * @description :: Server-side logic for the integration of the campus-app with Rdocs 5 | */ 6 | 7 | module.exports = { 8 | 9 | /** 10 | * @api {get} /campus/help 11 | * @apiName Get help in the campus-app via Rdocumentation-> needs to redirect or do an ajax request to retrieve the credentials 12 | * @apiGroup Rstudio 13 | * 14 | * @apiParam {String} query 15 | */ 16 | help: function(req, res) { 17 | return res.redirect(302, 'https://rdocumentation.org/campus/help/' + req.param('package') + '/' + req.param('topic')); 18 | }, 19 | 20 | path: function(req, res) { 21 | res.ok({ path: req.param('path')}, 'campus/help'); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /api/controllers/HomeController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * HomeController 3 | * 4 | * @description :: Server-side logic for the home page statistics 5 | * @help :: See http://sailsjs.org/#!/documentation/concepts/Controllers 6 | */ 7 | var Promise = require('bluebird'); 8 | var numeral = require('numeral'); 9 | 10 | module.exports = { 11 | 12 | index: function(req, res) { 13 | return res.redirect(302, "https://rdocumentation.org"); 14 | }, 15 | 16 | status: function(req, res) { 17 | return res.send(200, 'ok'); 18 | } 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /api/hooks/aws/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function aws_init(sails) { 2 | global['AWS'] = require('aws-sdk'); 3 | AWS.config.setPromisesDependency(require('bluebird')); 4 | 5 | return { 6 | 7 | initialize: function(next) { 8 | var s3 = new AWS.S3(); 9 | global['s3'] = s3; 10 | 11 | next(); 12 | } 13 | 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /api/hooks/elasticsearch/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function es_init(sails) { 2 | global['Elasticsearch'] = require('elasticsearch'); 3 | 4 | return { 5 | 6 | initialize: function(next) { 7 | var config = sails.config[this.configKey]; 8 | var host = config.host; 9 | if (host === null) { 10 | throw new Error('Host not found in config/elasticsearch'); 11 | } 12 | 13 | var es = new Elasticsearch.Client(config); 14 | global['es'] = es; 15 | 16 | next(); 17 | } 18 | 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /api/hooks/redis/index.js: -------------------------------------------------------------------------------- 1 | var bluebird = require('bluebird'); 2 | 3 | module.exports = function redis_init(sails) { 4 | global['Redis'] = require('redis'); 5 | 6 | return { 7 | 8 | initialize: function(next) { 9 | var config = sails.config[this.configKey]; 10 | var url = config.url; 11 | var options = config.options; 12 | 13 | bluebird.promisifyAll(Redis.RedisClient.prototype); 14 | bluebird.promisifyAll(Redis.Multi.prototype); 15 | 16 | var redisClient; 17 | if (url) { 18 | redisClient = Redis.createClient(url, options); 19 | } else { 20 | redisClient = Redis.createClient(options); 21 | } 22 | 23 | global['RedisClient'] = redisClient; 24 | 25 | if(config.logging) { 26 | redisClient.on('error', function (err) { 27 | console.log('Error ' + err); 28 | }); 29 | } 30 | 31 | // redisClient.flushdb(); 32 | // redisClient.flushall(); 33 | if(process.env.NODE_ENV === 'production') { 34 | redisClient.flushdb(); 35 | redisClient.flushall(); 36 | } 37 | 38 | next(); 39 | } 40 | 41 | }; 42 | }; 43 | -------------------------------------------------------------------------------- /api/hooks/worker/index.js: -------------------------------------------------------------------------------- 1 | var cron = require('node-cron'); 2 | 3 | module.exports = function worker(sails) { 4 | 5 | return { 6 | 7 | initialize: function (next) { 8 | 9 | if (process.env.NODE_ENV === 'worker') { 10 | cron.schedule('0 */12 * * *', function() { 11 | console.log('Indexing latest stats'); 12 | CronService.indexDownloadCounts().then(function(resp) { 13 | console.log('Latest stats indexed.'); 14 | }).catch({ message: 'empty' }, function() { 15 | console.log('No stats for this time range yet'); 16 | }); 17 | }); 18 | 19 | cron.schedule('30 */12 * * *', function() { 20 | console.log('Updating percentiles'); 21 | CronService.updatePercentile().then(function(resp) { 22 | console.log("Updated percentiles"); 23 | }); 24 | }); 25 | } 26 | next(); 27 | } 28 | 29 | }; 30 | }; 31 | -------------------------------------------------------------------------------- /api/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/api/models/.gitkeep -------------------------------------------------------------------------------- /api/models/ApiToken.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ApiToken.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | attributes: { 11 | 12 | token: { 13 | type: Sequelize.STRING, 14 | unique: true, 15 | allowNull: false 16 | }, 17 | 18 | can_create: { 19 | type: Sequelize.BOOLEAN, 20 | allowNull: false 21 | }, 22 | 23 | can_update: { 24 | type: Sequelize.BOOLEAN, 25 | allowNull: false 26 | }, 27 | 28 | can_delete: { 29 | type: Sequelize.BOOLEAN, 30 | allowNull: false 31 | } 32 | 33 | }, 34 | 35 | options: { 36 | underscored: true, 37 | timestamps: false 38 | } 39 | }; 40 | 41 | -------------------------------------------------------------------------------- /api/models/Argument.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Argument.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | attributes: { 11 | 12 | description: { 13 | type: Sequelize.TEXT, 14 | }, 15 | 16 | name: { 17 | type: Sequelize.STRING, 18 | allowNull: false 19 | } 20 | 21 | }, 22 | 23 | options: { 24 | underscored: true, 25 | timestamps: false 26 | } 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /api/models/BiocDownloadStatistics.js: -------------------------------------------------------------------------------- 1 | /** 2 | * BiocDownloadStatistic.js 3 | * 4 | * @description :: downloadstatistics for the bioconductor packages 5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | attributes: { 11 | 12 | package_name: { 13 | type: Sequelize.STRING, 14 | allowNull: false 15 | }, 16 | 17 | date: { 18 | type: Sequelize.DATE, 19 | allowNull: false 20 | }, 21 | 22 | distinct_ips: { 23 | type: Sequelize.INTEGER, 24 | allowNull: false 25 | }, 26 | downloads: { 27 | type: Sequelize.INTEGER, 28 | allowNull: false 29 | } 30 | }, 31 | 32 | associations: function() { 33 | BiocDownloadStatistics.belongsTo(Package, 34 | { 35 | as: 'package', 36 | foreignKey: { 37 | allowNull: false, 38 | name: 'package_name', 39 | as: 'package' 40 | }, 41 | onDelete: 'CASCADE' 42 | }); 43 | }, 44 | 45 | 46 | options: { 47 | underscored: true, 48 | 49 | indexes: [ 50 | { 51 | type: 'UNIQUE', 52 | fields: ['package_name', 'date' ] 53 | } 54 | ], 55 | classMethods:{ 56 | lastYearsSplittedDownloadsPerMonth:function(package_name,years){ 57 | return BiocDownloadStatistics.findAll({ 58 | where:{ 59 | package_name:package_name, 60 | date:{ 61 | $gte:new Date(new Date()-years*365*24*60*60*1000), 62 | $lt:new Date() 63 | } 64 | }, 65 | }); 66 | }, 67 | getMonthlySplittedDownloads:function(package_name){ 68 | return BiocDownloadStatistics.findAll({ 69 | where:{ 70 | package_name:package_name, 71 | date:{ 72 | $gte: sequelize.literal("current_date() - interval '1' month") 73 | } 74 | }, 75 | }); 76 | } 77 | } 78 | } 79 | }; 80 | 81 | -------------------------------------------------------------------------------- /api/models/Example.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Example.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | attributes: { 11 | 12 | example: { 13 | type: Sequelize.TEXT, 14 | allowNull: false 15 | } 16 | 17 | }, 18 | 19 | associations: function() { 20 | 21 | Example.belongsTo(Topic, { 22 | foreignKey: 'topic_id', 23 | as: 'topic' 24 | }); 25 | 26 | Example.belongsTo(User, { 27 | foreignKey: 'user_id', 28 | as: 'user' 29 | }); 30 | }, 31 | 32 | 33 | options: { 34 | underscored: true, 35 | 36 | classMethods: { 37 | findPackageExamples: function(packageName, topic) { 38 | return Example.findAll({ 39 | include:[ 40 | { model: Topic, as: 'topic', where: { name: topic }, attributes:['package_version_id'], required:true, 41 | include: [{ model: PackageVersion, as: 'package_version', where: { package_name: packageName }, required: true }] 42 | }, 43 | { model: User, as: 'user', attributes: ['username'] } 44 | ], 45 | 46 | }); 47 | } 48 | } 49 | } 50 | }; 51 | 52 | -------------------------------------------------------------------------------- /api/models/ParsingJob.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ParsingJob.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models 6 | */ 7 | 8 | module.exports = { 9 | autoCreatedAt: false, 10 | autoUpdatedAt: false, 11 | attributes: { 12 | package_name: { 13 | type: Sequelize.STRING, 14 | allowNull: false 15 | }, 16 | 17 | package_version: { 18 | type: Sequelize.STRING, 19 | allowNull: false 20 | }, 21 | 22 | parser_version: { 23 | type: Sequelize.INTEGER 24 | }, 25 | 26 | parsed_at: { 27 | type: Sequelize.DATE, 28 | allowNull: false 29 | }, 30 | 31 | parsing_status: { 32 | type: Sequelize.TEXT, 33 | allowNull: false 34 | }, 35 | 36 | error: { 37 | type: Sequelize.TEXT, 38 | }, 39 | 40 | }, 41 | options: { 42 | indexes: [ 43 | { 44 | type: 'UNIQUE', 45 | fields: ['package_name', 'package_version'] 46 | } 47 | ], 48 | timestamps: false 49 | }, 50 | } 51 | -------------------------------------------------------------------------------- /api/models/Percentile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * DownloadStatistic.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | attributes: { 11 | 12 | id: { 13 | type: Sequelize.INTEGER, 14 | primaryKey: true, 15 | allowNull: false, 16 | unique: true 17 | }, 18 | 19 | percentile: { 20 | type: Sequelize.DOUBLE, 21 | allowNull: false, 22 | unique: true 23 | }, 24 | 25 | value: { 26 | type: Sequelize.INTEGER, 27 | allowNull: false 28 | } 29 | 30 | }, 31 | 32 | 33 | options: { 34 | underscored: true 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /api/models/Repository.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Repository.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | attributes: { 11 | name: { 12 | type: Sequelize.STRING, 13 | required: true, 14 | } 15 | }, 16 | 17 | options: { 18 | underscored: true, 19 | timestamps: false 20 | } 21 | }; 22 | 23 | -------------------------------------------------------------------------------- /api/models/Review.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Review.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | attributes: { 11 | 12 | rating: { 13 | type: Sequelize.INTEGER, 14 | allowNull: false, 15 | validate: { min: 1, max: 5 } 16 | }, 17 | 18 | title: { 19 | type: Sequelize.STRING, 20 | allowNull: true 21 | }, 22 | 23 | text: { 24 | type: Sequelize.TEXT, 25 | allowNull: true 26 | }, 27 | 28 | reviewable: Sequelize.STRING, 29 | 30 | reviewable_id: { 31 | type: Sequelize.INTEGER, 32 | allowNull: false 33 | }, 34 | 35 | user_id: { 36 | type: Sequelize.INTEGER, 37 | allowNull: false 38 | } 39 | }, 40 | 41 | associations: function() { 42 | Review.belongsTo(PackageVersion, { 43 | foreignKey: 'reviewable_id', 44 | constraints: false, 45 | as: 'package_version' 46 | }); 47 | 48 | Review.belongsTo(Topic, { 49 | foreignKey: 'reviewable_id', 50 | constraints: false, 51 | as: 'topic' 52 | }); 53 | 54 | Review.belongsTo(User, { 55 | foreignKey: 'user_id', 56 | as: 'user' 57 | }); 58 | }, 59 | 60 | options: { 61 | indexes: [ 62 | { 63 | type: 'UNIQUE', 64 | fields: ['user_id', 'reviewable', 'reviewable_id'] 65 | } 66 | ], 67 | underscored: true 68 | } 69 | }; 70 | 71 | -------------------------------------------------------------------------------- /api/models/Section.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Section.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | attributes: { 11 | 12 | description: { 13 | type: Sequelize.TEXT, 14 | }, 15 | 16 | name: { 17 | type: Sequelize.STRING, 18 | allowNull: false 19 | } 20 | 21 | }, 22 | 23 | 24 | associations: function() { 25 | 26 | }, 27 | 28 | options: { 29 | underscored: true, 30 | timestamps: false 31 | } 32 | }; 33 | 34 | -------------------------------------------------------------------------------- /api/models/Star.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | 4 | 5 | attributes: { 6 | 7 | user_id: { 8 | type: Sequelize.INTEGER, 9 | allowNull: false, 10 | primaryKey: true 11 | }, 12 | 13 | package_name: { 14 | type: Sequelize.STRING, 15 | allowNull: false, 16 | primaryKey: true 17 | } 18 | 19 | }, 20 | 21 | 22 | associations: function() { 23 | 24 | }, 25 | 26 | options: { 27 | underscored: true 28 | } 29 | 30 | 31 | }; 32 | -------------------------------------------------------------------------------- /api/models/Tag.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Tag.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | attributes: { 11 | 12 | name: { 13 | type: Sequelize.STRING, 14 | allowNull: false, 15 | unique: true 16 | } 17 | 18 | }, 19 | 20 | associations: function() { 21 | Tag.belongsToMany(Topic, { as: 'tags', foreignKey: 'tag_id', through: 'TopicTags', timestamps: false}); 22 | }, 23 | 24 | options: { 25 | underscored: true, 26 | timestamps: false 27 | } 28 | }; 29 | 30 | -------------------------------------------------------------------------------- /api/models/TaskView.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TaskView.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/documentation/concepts/models-and-orm/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | attributes: { 11 | name: { 12 | type: Sequelize.STRING, 13 | unique: true, 14 | allowNull: false 15 | }, 16 | 17 | url: { 18 | type: Sequelize.STRING, 19 | allowNull: false 20 | } 21 | 22 | }, 23 | associations: function() { 24 | 25 | TaskView.belongsToMany(Package, 26 | { 27 | as: 'packages', 28 | through: 'TaskViewPackages', 29 | foreignKey: 'task_id', 30 | timestamps: false 31 | }); 32 | }, 33 | 34 | options: { 35 | underscored: true 36 | } 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /api/policies/api_auth.js: -------------------------------------------------------------------------------- 1 | var passport = require('passport'); 2 | /** 3 | * sessionAuth 4 | * 5 | * @module :: Policy 6 | * @description :: Simple policy to check authorization through token 7 | * 8 | */ 9 | module.exports = function(req, res, next) { 10 | if(req.method === 'GET' || req.method === 'HEAD') return next(); 11 | passport.authenticate('bearer', function(err, authorizations, info) { 12 | if (err) { return next(err); } 13 | if (!authorizations) { return res.send(401, info); } 14 | else { 15 | var authorized; 16 | switch (req.method) { 17 | case 'POST': 18 | authorized = authorizations.can_create === true; 19 | break; 20 | case 'PUT': 21 | authorized = authorizations.can_update === true; 22 | break; 23 | case 'DELETE': 24 | authorized = authorizations.can_delete === true; 25 | break; 26 | } 27 | if (authorized) { 28 | next(); 29 | } else { 30 | res.send(403); 31 | } 32 | } 33 | })(req, res, next); 34 | }; 35 | -------------------------------------------------------------------------------- /api/policies/flash.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | 3 | // flash.js policy 4 | module.exports = function(req, res, next) { 5 | res.locals.messages = { success: [], error: [], warning: [] }; 6 | 7 | if(!req.session.messages) { 8 | req.session.messages = { success: [], error: [], warning: [] }; 9 | return next(); 10 | } 11 | 12 | if(req.session.flash) { 13 | res.locals.messages = _.clone(_.merge(req.session.messages, req.session.flash)); 14 | req.session.flash = {}; 15 | } else { 16 | res.locals.messages = _.clone(req.session.messages); 17 | } 18 | 19 | // Clear flash 20 | req.session.messages = { success: [], error: [], warning: [] }; 21 | 22 | return next(); 23 | }; 24 | -------------------------------------------------------------------------------- /api/policies/sessionAuth.js: -------------------------------------------------------------------------------- 1 | /** 2 | * sessionAuth 3 | * 4 | * @module :: Policy 5 | * @description :: Simple policy to allow any authenticated user 6 | * Assumes that your login action in one of your controllers sets `req.session.authenticated = true;` 7 | * @docs :: http://sailsjs.org/#!/documentation/concepts/Policies 8 | * 9 | */ 10 | module.exports = function(req, res, next) { 11 | 12 | // User is allowed, proceed to the next policy, 13 | // or if this is the last policy, the controller 14 | if (req.isAuthenticated()) { 15 | return next(); 16 | } 17 | 18 | // User is not allowed 19 | // (default res.forbidden() behavior can be overridden in `config/403.js`) 20 | return res.forbidden('You are not permitted to perform this action.'); 21 | }; 22 | -------------------------------------------------------------------------------- /api/responses/created.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 201 (CREATED) Response 3 | * 4 | * Usage: 5 | * return res.created(); 6 | * return res.created(data); 7 | * return res.created(data, 'auth/login'); 8 | * 9 | * @param {Object} data 10 | * @param {String|Object} options 11 | * - pass string to render specified view 12 | */ 13 | 14 | module.exports = function created (data, options) { 15 | 16 | // Get access to `req`, `res`, & `sails` 17 | var req = this.req; 18 | var res = this.res; 19 | var sails = req._sails; 20 | 21 | sails.log.silly('res.created() :: Sending 201 ("CREATED") response'); 22 | 23 | // Set status code 24 | res.status(201); 25 | 26 | // If appropriate, serve data as JSON(P) 27 | // If views are disabled, revert to json 28 | if (req.wantsJSON || sails.config.hooks.views === false) { 29 | return res.jsonx(data); 30 | } 31 | 32 | // If second argument is a string, we take that to mean it refers to a view. 33 | // If it was omitted, use an empty object (`{}`) 34 | options = (typeof options === 'string') ? { view: options } : options || {}; 35 | 36 | // Attempt to prettify data for views, if it's a non-error object 37 | var viewData = data; 38 | if (!(viewData instanceof Error) && 'object' == typeof viewData) { 39 | try { 40 | viewData = require('util').inspect(data, {depth: null}); 41 | } 42 | catch(e) { 43 | viewData = undefined; 44 | } 45 | } 46 | 47 | // If a view was provided in options, serve it. 48 | // Otherwise try to guess an appropriate view, or if that doesn't 49 | // work, just send JSON. 50 | if (options.view) { 51 | return res.view(options.view, { data: viewData, title: 'Created' }); 52 | } 53 | 54 | // If no second argument provided, try to serve the implied view, 55 | // but fall back to sending JSON(P) if no view can be inferred. 56 | else return res.guessView({ data: viewData, title: 'Created' }, function couldNotGuessView () { 57 | return res.jsonx(data); 58 | }); 59 | 60 | }; 61 | -------------------------------------------------------------------------------- /api/responses/ok.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 200 (OK) Response 3 | * 4 | * Usage: 5 | * return res.ok(); 6 | * return res.ok(data); 7 | * return res.ok(data, 'auth/login'); 8 | * 9 | * @param {Object} data 10 | * @param {String|Object} options 11 | * - pass string to render specified view 12 | */ 13 | 14 | module.exports = function sendOK (data, options) { 15 | 16 | // Get access to `req`, `res`, & `sails` 17 | var req = this.req; 18 | var res = this.res; 19 | var sails = req._sails; 20 | 21 | sails.log.silly('res.ok() :: Sending 200 ("OK") response'); 22 | 23 | // Set status code 24 | res.status(200); 25 | 26 | if(req.path.startsWith('/api/')) { 27 | return res.jsonx(data); 28 | } 29 | 30 | // If appropriate, serve data as JSON(P) 31 | // If views are disabled, revert to json 32 | // if (req.wantsJSON || sails.config.hooks.views === false) { 33 | // return res.jsonx(data); 34 | // } 35 | 36 | // If second argument is a string, we take that to mean it refers to a view. 37 | // If it was omitted, use an empty object (`{}`) 38 | options = (typeof options === 'string') ? { view: options } : options || {}; 39 | 40 | // If a view was provided in options, serve it. 41 | // Otherwise try to guess an appropriate view, or if that doesn't 42 | // work, just send JSON. 43 | if (options.view) { 44 | return res.view(options.view, { data: data, cache: true }); 45 | } 46 | 47 | // If no second argument provided, try to serve the implied view, 48 | // but fall back to sending JSON(P) if no view can be inferred. 49 | else return res.guessView({ data: viewData }, function couldNotGuessView () { 50 | return res.jsonx(data); 51 | }); 52 | 53 | }; 54 | -------------------------------------------------------------------------------- /api/responses/rstudio_redirect.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 303 (See Other) Handler for Rstudio-api (passes parameters) 3 | * 4 | * Usage: 5 | * return res.rstudio_redirect(uri) 6 | * 7 | * e.g.: 8 | * ``` 9 | * return res.rstudio_redirect(uri) 10 | * ``` 11 | * 12 | * NOTE: 13 | * This response is needed if the viewer_pane parameter, the Rstudio_port and/or the session_shared_secret for Rstudio or important 14 | * This is for example the case when refering to topics, as topic/show.ejs has viewer_pane-specifid code. 15 | */ 16 | 17 | module.exports = function rstudio_redirect(code,uri) { 18 | 19 | // Get access to `req`, `res`, & `sails` 20 | var req = this.req; 21 | var res = this.res; 22 | var sails = req._sails; 23 | 24 | var fromRstudio = req.headers['x-rstudio-ajax'] === 'true'; 25 | var urlParams= ['viewer_pane'].map(function(p) { 26 | return req.param(p) ? p + '=' + encodeURIComponent(req.param(p)) : ''; 27 | }).filter(function(p) { 28 | return p !== ''; 29 | }).join('&'); 30 | if(uri.indexOf('?')>0){ 31 | var redirectURL = uri.substring(0,uri.indexOf('?')) 32 | } 33 | else{ 34 | var redirectURL = uri 35 | } 36 | 37 | 38 | sails.log.silly('res.rstudio_redirect() :: Sending '+code+ ' (redirect) response'); 39 | 40 | if(fromRstudio) { 41 | res.location(redirectURL); 42 | res.set('X-RStudio-Redirect', redirectURL); 43 | res.json({ status: 'success'}); 44 | } else { 45 | res.redirect(code,uri+ (urlParams.length > 0 ? "?"+ urlParams : "")); 46 | } 47 | 48 | }; 49 | -------------------------------------------------------------------------------- /api/services/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/api/services/.gitkeep -------------------------------------------------------------------------------- /api/services/CronService.js: -------------------------------------------------------------------------------- 1 | // CronService.js - in api/services 2 | 3 | /** 4 | * All async tasks 5 | */ 6 | 7 | var Promise = require('bluebird'); 8 | 9 | module.exports = { 10 | 11 | indexDownloadCounts: function () { 12 | return DownloadStatistic.getNotIndexedDates().then(function (days) { 13 | return days.map(function (day) { 14 | var date = new Date(day.absents); 15 | return date; 16 | }); 17 | }).then(function (diffs) { 18 | if (diffs.length <= 0) { 19 | console.log("Nothing new"); 20 | return res.send(200, "done"); 21 | } 22 | DownloadStatsService.reverseDependenciesCache = {}; //clean old cache 23 | return Promise.map(diffs, function (day) { 24 | console.log(`Started indexing for ${day}.`); 25 | return Promise.promisify(DownloadStatsService.getDailyDownloads)(day) 26 | .catch({ message: "empty" }, function () { 27 | console.log("No stats for this time range yet"); 28 | return 1; 29 | }) 30 | .catch(function (err) { 31 | console.log("Undefined response"); 32 | return 1; 33 | }); 34 | }, { concurrency: 1 }) 35 | .then(function (result) { 36 | console.log("Finished indexing splitted stats"); 37 | DownloadStatsService.reverseDependenciesCache = {}; //clean cache 38 | }) 39 | 40 | }).catch(function (err) { 41 | console.error(err); 42 | }); 43 | 44 | }, 45 | 46 | updatePercentile: function () { 47 | return DownloadStatsService.updateLastMonthPercentiles().then(function () { 48 | console.log("Finished updating percentiles"); 49 | }).catch(function (err) { 50 | console.error(err); 51 | }); 52 | } 53 | 54 | }; 55 | 56 | 57 | -------------------------------------------------------------------------------- /api/services/FlashService.js: -------------------------------------------------------------------------------- 1 | // FlashService.js 2 | module.exports = { 3 | success: function(req, message) { 4 | req.session.messages['success'].push(message); 5 | }, 6 | warning: function(req, message) { 7 | req.session.messages['warning'].push(message); 8 | }, 9 | error: function(req, message) { 10 | req.session.messages['error'].push(message); 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /api/services/PackageVersionService.js: -------------------------------------------------------------------------------- 1 | function getSourceList(res, package_name, version) { 2 | var key = 'rdocs_source_' + package_name + '_' + version + '_tree'; 3 | return RedisService.getJSONFromCache(key, res, RedisService.DAILY, function () { 4 | var prefix = "rpackages/unarchived/" + package_name + "/" + version + "/R/"; 5 | return s3Service.getAllFilesInFolder(prefix, true) 6 | .then(function (data) { 7 | var url = process.env.BASE_URL + "/packages/" + package_name + "/versions/" + version 8 | + "/source/"; 9 | 10 | var list = data.list.map(function (item) { 11 | var name = item.Key.substring(prefix.length, item.Key.length); 12 | var parts = name.split('/'); 13 | return { 14 | 'name': name, 15 | 'parts': parts 16 | } 17 | }); 18 | var data = {}; 19 | for (var item of list) { 20 | setObjectValue(data, item.parts, item.name); 21 | } 22 | var tree = []; 23 | toTreeStructure(tree, data); 24 | return { 25 | tree: tree 26 | } 27 | }); 28 | 29 | }); 30 | } 31 | 32 | function setObjectValue(obj, indices, value) { 33 | if (indices.length == 1) 34 | return obj[indices[0]] = value; 35 | else if (indices.length == 0) 36 | return obj; 37 | else { 38 | if (obj[indices[0]] === undefined) 39 | obj[indices[0]] = {}; 40 | return setObjectValue(obj[indices[0]], indices.slice(1), value); 41 | } 42 | } 43 | 44 | function toTreeStructure(tree, data) { 45 | if (typeof (data) !== 'object') 46 | return; 47 | for (var key of Object.keys(data)) { 48 | var nodes = []; 49 | toTreeStructure(nodes, data[key]); 50 | var node = { 51 | text: key, 52 | selectable: nodes.length === 0, 53 | state: { 54 | selected: false 55 | } 56 | }; 57 | if (nodes.length === 0) 58 | node.href = data[key]; 59 | else 60 | node.nodes = nodes; 61 | tree.push(node); 62 | } 63 | } 64 | module.exports = { 65 | getSourceList, 66 | setObjectValue, 67 | toTreeStructure 68 | } 69 | -------------------------------------------------------------------------------- /api/services/RedisService.js: -------------------------------------------------------------------------------- 1 | // RedisService.js - in api/services 2 | 3 | /** 4 | * Abstract away boilerplate code to work with Redis 5 | */ 6 | 7 | var Promise = require('bluebird'); 8 | 9 | 10 | module.exports = { 11 | 12 | DAILY: 86400, 13 | 14 | WEEKLY: 604800, 15 | 16 | // missFn must be a function that return either a json or a Promise resolving to a json 17 | // it will be executed if nothing is found in cache 18 | getJSONFromCache: function(key, res, expire, missFn) { 19 | var env = process.env.AWS_ENV || 'dev'; 20 | //if (env === 'dev') return Promise.resolve(missFn()); 21 | key = env + '_' + key; 22 | return RedisClient.getAsync(key).then(function(response){ 23 | if(res) res.set('Cache-Control', 'max-age=' + expire); 24 | if(response) { 25 | var json = JSON.parse(response); 26 | json.fromCache = true; 27 | if(res) res.set('X-Cache', 'hit'); 28 | return json; 29 | } else { 30 | return Promise.resolve(missFn()).then(function(value) { 31 | if (value) RedisClient.set(key, JSON.stringify(value)); 32 | if(res) res.set('X-Cache', 'miss'); 33 | RedisClient.expire(key, expire); 34 | return value; 35 | }); 36 | } 37 | }); 38 | }, 39 | 40 | del: function(key) { 41 | var env = process.env.AWS_ENV || 'dev'; 42 | key = env + '_' + key; 43 | RedisClient.del(key); 44 | }, 45 | 46 | delPrefix: function(prefix){ 47 | var env = process.env.AWS_ENV || 'dev'; 48 | var key = env + '_' + prefix + '*'; 49 | RedisClient.keys(key,function(err,rows){ 50 | Promise.map(rows,function(row){ 51 | RedisClient.del(row); 52 | }); 53 | }) 54 | }, 55 | 56 | invalidateTopicById: function(id) { 57 | RedisService.del('view_topic_' + id); 58 | Topic.findById(id, { include: [{model: PackageVersion, as: 'package_version'}]}).then(function(topic) { 59 | if (topic) { 60 | RedisService.del('view_topic_' + topic.package_version.package_name + '_' + topic.package_version.version + '_' + topic.name); 61 | } 62 | }); 63 | } 64 | 65 | 66 | }; 67 | -------------------------------------------------------------------------------- /apidoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Rdocumentation JSON API", 3 | "version": "0.1.0", 4 | "title": "Rdocumentation JSON API", 5 | "url" : "http://rdocumentation.org/api" 6 | } 7 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * app.js 3 | * 4 | * Use `app.js` to run your app without `sails lift`. 5 | * To start the server, run: `node app.js`. 6 | * 7 | * This is handy in situations where the sails CLI is not relevant or useful. 8 | * 9 | * For example: 10 | * => `node app.js` 11 | * => `forever start app.js` 12 | * => `node debug app.js` 13 | * => `modulus deploy` 14 | * => `heroku scale` 15 | * 16 | * 17 | * The same command-line arguments are supported, e.g.: 18 | * `node app.js --silent --port=80 --prod` 19 | */ 20 | 21 | // Ensure we're in the project directory, so relative paths work as expected 22 | // no matter where we actually lift from. 23 | process.chdir(__dirname); 24 | // Ensure a "sails" can be located: 25 | //var newrelic = require('newrelic'); 26 | require('dotenv').config({silent: true}); 27 | 28 | (function() { 29 | var sails; 30 | try { 31 | sails = require('sails'); 32 | } catch (e) { 33 | console.error('To run an app using `node app.js`, you usually need to have a version of `sails` installed in the same directory as your app.'); 34 | console.error('To do that, run `npm install sails`'); 35 | console.error(''); 36 | console.error('Alternatively, if you have sails installed globally (i.e. you did `npm install -g sails`), you can use `sails lift`.'); 37 | console.error('When you run `sails lift`, your app will still use a local `./node_modules/sails` dependency if it exists,'); 38 | console.error('but if it doesn\'t, the app will run with the global sails instead!'); 39 | return; 40 | } 41 | 42 | // Try to get `rc` dependency 43 | var rc; 44 | try { 45 | rc = require('rc'); 46 | } catch (e0) { 47 | try { 48 | rc = require('sails/node_modules/rc'); 49 | } catch (e1) { 50 | console.error('Could not find dependency: `rc`.'); 51 | console.error('Your `.sailsrc` file(s) will be ignored.'); 52 | console.error('To resolve this, run:'); 53 | console.error('npm install rc --save'); 54 | rc = function () { return {}; }; 55 | } 56 | } 57 | 58 | 59 | // Start server 60 | sails.lift(rc('sails')); 61 | })(); 62 | -------------------------------------------------------------------------------- /assets/css/bootstrap-treeview.css: -------------------------------------------------------------------------------- 1 | /* ========================================================= 2 | * bootstrap-treeview.css v1.2.0 3 | * ========================================================= 4 | * Copyright 2013 Jonathan Miles 5 | * Project URL : http://www.jondmiles.com/bootstrap-treeview 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ========================================================= */ 19 | 20 | .treeview .list-group-item { 21 | cursor: pointer; 22 | } 23 | 24 | .treeview span.indent { 25 | margin-left: 10px; 26 | margin-right: 10px; 27 | } 28 | 29 | .treeview span.icon { 30 | width: 12px; 31 | margin-right: 5px; 32 | } 33 | 34 | .treeview .node-disabled { 35 | color: silver; 36 | cursor: not-allowed; 37 | } -------------------------------------------------------------------------------- /assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/assets/favicon.ico -------------------------------------------------------------------------------- /assets/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/assets/images/.gitkeep -------------------------------------------------------------------------------- /assets/images/GitHub-Mark-32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/assets/images/GitHub-Mark-32px.png -------------------------------------------------------------------------------- /assets/images/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/assets/images/logo-dark.png -------------------------------------------------------------------------------- /assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/assets/images/logo.png -------------------------------------------------------------------------------- /assets/images/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/assets/images/placeholder.png -------------------------------------------------------------------------------- /assets/js/helpers/boot.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | 3 | $(window).on("load", function() { 4 | window.boot(); 5 | }); 6 | 7 | window.boot = function() { 8 | bootDownloadStats(); 9 | bootListTableFiltering(); 10 | bootToggle(); 11 | bootCollaborator(); 12 | bootTaskViews(); 13 | bootRstudioNavigator(); 14 | bootAsyncLoader(); 15 | bootPackage(); 16 | bootExamples(); 17 | bootTrending(); 18 | bootUser(); 19 | bootSource(); 20 | bindUpvoteButton(); 21 | window.bindFade(); 22 | window.counter(); 23 | window.dcFooter(); 24 | hljs.initHighlighting.called = false; 25 | hljs.initHighlighting(); 26 | }; 27 | 28 | })($jq); 29 | 30 | -------------------------------------------------------------------------------- /assets/js/helpers/list-table-filtering.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 3 | var addExpr = function(){ 4 | // Make :eq case insensitive 5 | $.expr[':'].containsRaw = function(a, i, m) { 6 | return $(a).text().toUpperCase() 7 | .indexOf(m[3].toUpperCase()) >= 0; 8 | }; 9 | }; 10 | 11 | function filterFunction(index) { 12 | return function () { 13 | addExpr(); 14 | var indexColumn = index, // Search for values in the first column 15 | searchWords = this.value.split(" "), 16 | rows = $("#filterableItems").find("tr").not(".no-results"); 17 | 18 | rows.hide(); 19 | //Recusively filter the jquery object to get results. 20 | var filteredRows = rows.filter(function (i, v) { 21 | var $t = $(this).children(":eq("+indexColumn+")"); 22 | for (var d = 0; d < searchWords.length; ++d) { 23 | if ($t.is(":containsRaw('" + searchWords[d].toLowerCase() + "')")) { 24 | return true; 25 | } 26 | } 27 | return false; 28 | }); 29 | 30 | if(filteredRows.length === 0) { 31 | $('.no-results').show(); 32 | } else { 33 | $('.no-results').hide(); 34 | filteredRows.show(); 35 | } 36 | }; 37 | } 38 | 39 | window.tableSort = function() { 40 | $("table.packagetable").tablesorter(); 41 | }; 42 | 43 | window.bindFilter = function() { 44 | $('#filter').keyup(filterFunction(0)); 45 | $('#packagefilter').keyup(filterFunction(1)); 46 | }; 47 | 48 | window.bootListTableFiltering = function() { 49 | window.bindFilter(); 50 | window.tableSort(); 51 | }; 52 | })($jq); 53 | -------------------------------------------------------------------------------- /assets/js/helpers/toggle.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | bootToggle = function() { 3 | $('[data-toggle]').click(function(event){ 4 | event.preventDefault(); 5 | var target = $($(this).data('target')), 6 | toggledText = $(this).data('toggled-text'); 7 | 8 | $(this).data('toggled-text', $(this).text()); 9 | $(this).text(toggledText); 10 | 11 | if(target.data('toggle-hidden') === true){ 12 | target.show(); 13 | target.data('toggle-hidden', false); 14 | } else { 15 | target.hide(); 16 | target.data('toggle-hidden', true); 17 | } 18 | }); 19 | }; 20 | })($jq); 21 | -------------------------------------------------------------------------------- /assets/js/libs/experiment.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | window.Experiment = function(experimentName, experimentClass) { 3 | this.EXPERIMENT_NAME = experimentName; 4 | this.variants = []; 5 | this.experimentClass = experimentClass; 6 | 7 | this.addVariant = function(name, weight) { 8 | this.variants.push({ 9 | experiment_name: this.EXPERIMENT_NAME, 10 | name: name, 11 | weight: weight 12 | }) 13 | } 14 | 15 | this.chooseVariant = function() { 16 | var savedVariant = window.localStorage.getItem(this.EXPERIMENT_NAME); 17 | if(savedVariant) { return savedVariant } 18 | 19 | // Use a CDF to select a variant based on weight. 20 | var total = 0; 21 | var weights = []; 22 | for(i = 0; i < this.variants.length; i++) { 23 | total += this.variants[i].weight; 24 | weights[i] = total; 25 | } 26 | var random = Math.random() * weights[weights.length - 1]; 27 | selectedVariantIndex = weights.findIndex(function(weight) { 28 | return random < weight; 29 | }); 30 | var selectedVariant = this.variants[selectedVariantIndex]; 31 | this.variant = selectedVariant; 32 | window.localStorage.setItem(this.EXPERIMENT_NAME, selectedVariant.name); 33 | this.sendSnowplowTrackingEvent(); 34 | return selectedVariant.name; 35 | } 36 | 37 | this.sendSnowplowTrackingEvent = function() { 38 | // Snowplow requires variant weights to be integers, so let's 10x them until they are. 39 | while(this.variants.some(function(variant) { return variant.weight % 1 !== 0 })) { 40 | this.variants.forEach(function(variant) { variant.weight *= 10 }) 41 | } 42 | 43 | window.snowplow('trackSelfDescribingEvent', { 44 | schema: 'iglu:com.datacamp/experiment/jsonschema/1-0-0', 45 | data: { 46 | name: this.EXPERIMENT_NAME, 47 | status: 'start', 48 | alternative: this.variant, 49 | alternatives: this.variants, 50 | } 51 | }); 52 | } 53 | 54 | this.execute = function() { 55 | this.experimentClass.execute(this.chooseVariant()); 56 | } 57 | } 58 | })(); 59 | -------------------------------------------------------------------------------- /assets/js/libs/jquery.cookie-1.4.1.min.js: -------------------------------------------------------------------------------- 1 | /*! jquery.cookie v1.4.1 | MIT */ 2 | !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?a(require("jquery")):a(jQuery)}(function(a){function b(a){return h.raw?a:encodeURIComponent(a)}function c(a){return h.raw?a:decodeURIComponent(a)}function d(a){return b(h.json?JSON.stringify(a):String(a))}function e(a){0===a.indexOf('"')&&(a=a.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return a=decodeURIComponent(a.replace(g," ")),h.json?JSON.parse(a):a}catch(b){}}function f(b,c){var d=h.raw?b:e(b);return a.isFunction(c)?c(d):d}var g=/\+/g,h=a.cookie=function(e,g,i){if(void 0!==g&&!a.isFunction(g)){if(i=a.extend({},h.defaults,i),"number"==typeof i.expires){var j=i.expires,k=i.expires=new Date;k.setTime(+k+864e5*j)}return document.cookie=[b(e),"=",d(g),i.expires?"; expires="+i.expires.toUTCString():"",i.path?"; path="+i.path:"",i.domain?"; domain="+i.domain:"",i.secure?"; secure":""].join("")}for(var l=e?void 0:{},m=document.cookie?document.cookie.split("; "):[],n=0,o=m.length;o>n;n++){var p=m[n].split("="),q=c(p.shift()),r=p.join("=");if(e&&e===q){l=f(r,g);break}e||void 0===(r=f(r))||(l[q]=r)}return l};h.defaults={},a.removeCookie=function(b,c){return void 0===a.cookie(b)?!1:(a.cookie(b,"",a.extend({},c,{expires:-1})),!a.cookie(b))}}); -------------------------------------------------------------------------------- /assets/js/pages/collaborator.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | bootCollaborator = function(){ 3 | var depsyurl = $(".depsy").data("url"); 4 | if(depsyurl) { 5 | $.get(depsyurl,function(data){ 6 | if(data.impact) { 7 | $("#impactnr").html(Math.round(data.impact*100)+"th"); 8 | $(".depsy").show(); 9 | } else { 10 | $(".depsy").css('visibility', 'hidden'); 11 | } 12 | 13 | if(data.top_collabs) { 14 | $(".top-collab-list").append("

Top collaborators

"); 15 | data.top_collabs.forEach(function(collab){ 16 | $(".top-collab-list").append(""+collab.name+""); 17 | }); 18 | } 19 | 20 | if(data.icon) { 21 | $('#collaborator-gravatar').attr('src', data.icon); 22 | } 23 | 24 | if(data.github_login) { 25 | $('#collaborator_github_link').attr('href', "https://github.com/"+ data.github_login); 26 | } 27 | $(document).trigger('content-changed'); 28 | }); 29 | } 30 | 31 | var downurl = $(".direct-downloads").data("url"); 32 | if(downurl) { 33 | $.get(downurl,function(data){ 34 | if(data.totalStr){ 35 | $("#direct-downloadsnr").html(data.totalStr); 36 | $(".direct-downloads").show(); 37 | } 38 | }); 39 | } 40 | 41 | $('span.collaborator-type i.fa.fa-user').tooltip(); 42 | $('span.collaborator-type i.fa.fa-users').tooltip(); 43 | $('.impact-info').tooltip(); 44 | }; 45 | })($jq); 46 | -------------------------------------------------------------------------------- /assets/js/pages/user.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | 3 | window.User = { 4 | bindButtons: function() { 5 | User.bindDeleteButton(); 6 | User.bindEditButton(); 7 | }, 8 | 9 | bindEditButton: function() { 10 | $(".edit-example").click(function(){ 11 | $(this).unbind("click"); 12 | var $example = $(this).parents(".example"); 13 | var $text = $example.find(".example--text"); 14 | $text.replaceWith(""); 15 | 16 | var $element = $example.find("textarea")[0]; 17 | 18 | var simplemde = Examples.loadMDEWidget($element); 19 | 20 | $example.find(".example--body").append("
"); 21 | $example.find(".submit-edit").click(function(){ 22 | $this = $(this); 23 | var value = simplemde.value(); 24 | $.post("/api/examples/"+$example.data("exampleid"),{text: value},function(response){ 25 | var string = "

"+value+"

"; 26 | $example.find(".example--body").html(string); 27 | 28 | Examples.renderExamples('.example--text'); 29 | User.bindEditButton(); 30 | }); 31 | }); 32 | }); 33 | }, 34 | 35 | bindDeleteButton: function() { 36 | $(".delete-example").click(function(){ 37 | var $this = $(this); 38 | var confimed = confirm("Are you sure you want to delete this example ?"); 39 | if (!confimed) return; 40 | $.ajax({ 41 | url: "api/examples/"+$(this).parents(".example").data("exampleid"), 42 | type: "delete", 43 | success: function(response){ 44 | if(response.status === "done"){ 45 | $this.parents(".example-wrapper").remove(); 46 | } 47 | } 48 | }); 49 | }); 50 | } 51 | }; 52 | 53 | bootUser = function(){ 54 | User.bindButtons(); 55 | }; 56 | 57 | })($jq); 58 | -------------------------------------------------------------------------------- /assets/robots.txt: -------------------------------------------------------------------------------- 1 | # The robots.txt file is used to control how search engines index your live URLs. 2 | # See http://sailsjs.org/documentation/anatomy/my-app/assets/robots-txt for more information. 3 | 4 | 5 | 6 | # To prevent search engines from seeing the site altogether, uncomment the next two lines: 7 | # User-Agent: * 8 | # Disallow: / 9 | -------------------------------------------------------------------------------- /assets/sitemap/sitemap-1.xml.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/assets/sitemap/sitemap-1.xml.gz -------------------------------------------------------------------------------- /assets/sitemap/sitemap-2.xml.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/assets/sitemap/sitemap-2.xml.gz -------------------------------------------------------------------------------- /assets/sitemap/sitemap-3.xml.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/assets/sitemap/sitemap-3.xml.gz -------------------------------------------------------------------------------- /assets/sitemap/sitemap-4.xml.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/assets/sitemap/sitemap-4.xml.gz -------------------------------------------------------------------------------- /assets/sitemap/sitemap-5.xml.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/assets/sitemap/sitemap-5.xml.gz -------------------------------------------------------------------------------- /assets/sitemap/sitemapindex.xml.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/assets/sitemap/sitemapindex.xml.gz -------------------------------------------------------------------------------- /assets/styles/application.scss: -------------------------------------------------------------------------------- 1 | @import "styleguide/normalize"; 2 | @import "styleguide/globals"; 3 | @import "styleguide/base"; 4 | 5 | @import "styleguide/partials/*"; 6 | @import "widgets/*"; 7 | @import "pages/*"; 8 | @import "jquery-ui/*"; 9 | -------------------------------------------------------------------------------- /assets/styles/jquery-ui/core.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery UI CSS Framework @VERSION 3 | * http://jqueryui.com 4 | * 5 | * Copyright jQuery Foundation and other contributors 6 | * Released under the MIT license. 7 | * http://jquery.org/license 8 | * 9 | * http://api.jqueryui.com/category/theming/ 10 | */ 11 | 12 | /* Layout helpers 13 | ----------------------------------*/ 14 | .ui-helper-hidden { 15 | display: none; 16 | } 17 | .ui-helper-hidden-accessible { 18 | border: 0; 19 | clip: rect(0 0 0 0); 20 | height: 1px; 21 | margin: -1px; 22 | overflow: hidden; 23 | padding: 0; 24 | position: absolute; 25 | width: 1px; 26 | } 27 | .ui-helper-reset { 28 | margin: 0; 29 | padding: 0; 30 | border: 0; 31 | outline: 0; 32 | line-height: 1.3; 33 | text-decoration: none; 34 | font-size: 100%; 35 | list-style: none; 36 | } 37 | .ui-helper-clearfix:before, 38 | .ui-helper-clearfix:after { 39 | content: ""; 40 | display: table; 41 | border-collapse: collapse; 42 | } 43 | .ui-helper-clearfix:after { 44 | clear: both; 45 | } 46 | .ui-helper-zfix { 47 | width: 100%; 48 | height: 100%; 49 | top: 0; 50 | left: 0; 51 | position: absolute; 52 | opacity: 0; 53 | filter:Alpha(Opacity=0); /* support: IE8 */ 54 | } 55 | 56 | .ui-front { 57 | z-index: 100; 58 | } 59 | 60 | 61 | /* Interaction Cues 62 | ----------------------------------*/ 63 | .ui-state-disabled { 64 | cursor: default !important; 65 | pointer-events: none; 66 | } 67 | 68 | 69 | /* Icons 70 | ----------------------------------*/ 71 | .ui-icon { 72 | display: inline-block; 73 | vertical-align: middle; 74 | margin-top: -.25em; 75 | position: relative; 76 | text-indent: -99999px; 77 | overflow: hidden; 78 | background-repeat: no-repeat; 79 | } 80 | 81 | .ui-widget-icon-block { 82 | left: 50%; 83 | margin-left: -8px; 84 | display: block; 85 | } 86 | 87 | /* Misc visuals 88 | ----------------------------------*/ 89 | 90 | /* Overlays */ 91 | .ui-widget-overlay { 92 | position: fixed; 93 | top: 0; 94 | left: 0; 95 | width: 100%; 96 | height: 100%; 97 | } 98 | -------------------------------------------------------------------------------- /assets/styles/jquery-ui/tabs.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery UI Tabs @VERSION 3 | * http://jqueryui.com 4 | * 5 | * Copyright jQuery Foundation and other contributors 6 | * Released under the MIT license. 7 | * http://jquery.org/license 8 | * 9 | * http://api.jqueryui.com/tabs/#theming 10 | */ 11 | .ui-tabs { 12 | position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ 13 | padding: .2em; 14 | } 15 | .ui-tabs .ui-tabs-nav { 16 | margin: 0; 17 | padding: .2em .2em 0; 18 | } 19 | .ui-tabs .ui-tabs-nav li { 20 | list-style: none; 21 | float: left; 22 | position: relative; 23 | top: 0; 24 | margin: 1px .2em 0 0; 25 | border-bottom-width: 0; 26 | padding: 0; 27 | white-space: nowrap; 28 | } 29 | .ui-tabs .ui-tabs-nav .ui-tabs-anchor { 30 | float: left; 31 | padding: .5em 1em; 32 | text-decoration: none; 33 | } 34 | .ui-tabs .ui-tabs-nav li.ui-tabs-active { 35 | margin-bottom: -1px; 36 | padding-bottom: 1px; 37 | } 38 | .ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor, 39 | .ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor, 40 | .ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor { 41 | cursor: text; 42 | } 43 | .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor { 44 | cursor: pointer; 45 | } 46 | .ui-tabs .ui-tabs-panel { 47 | display: block; 48 | border-width: 0; 49 | padding: 1em 1.4em; 50 | background: none; 51 | } 52 | -------------------------------------------------------------------------------- /assets/styles/pages/_authentication.scss: -------------------------------------------------------------------------------- 1 | .authentication { 2 | min-height: 82%; 3 | .container { 4 | margin-top: $default-space; 5 | } 6 | } 7 | 8 | .authentication--form { 9 | fieldset { 10 | width: 100%; 11 | } 12 | 13 | fieldset .btn { 14 | width: auto; 15 | } 16 | } 17 | 18 | .authentication--title { 19 | margin-bottom: $default-space; 20 | text-align: center; 21 | } -------------------------------------------------------------------------------- /assets/styles/pages/_error-page.scss: -------------------------------------------------------------------------------- 1 | .error-page { 2 | min-height: 85%; 3 | display: flex; 4 | 5 | h1 { 6 | margin-bottom: 2 * $default-space; 7 | font-size: 7rem; 8 | } 9 | 10 | .error-page--content { 11 | margin: auto; 12 | text-align: center; 13 | } 14 | } -------------------------------------------------------------------------------- /assets/styles/pages/_examples.scss: -------------------------------------------------------------------------------- 1 | .user-examples { 2 | margin-top: $default-space; 3 | h3 { 4 | margin-bottom: $default-space / 2.0; 5 | } 6 | } 7 | // ******************** 8 | // One review 9 | // ******************** 10 | .example { 11 | margin-bottom: 1rem; 12 | border: 2px solid $primary-lighter; 13 | border-radius: 4px; 14 | } 15 | 16 | .example.old { 17 | border: 2px solid #efefef; 18 | } 19 | 20 | .example--title { 21 | padding: 1rem; 22 | background-color: $primary-extra-light; 23 | border-bottom: 2px solid $primary-lighter; 24 | .rating { 25 | margin: 0 1rem; 26 | } 27 | } 28 | 29 | .example.old .example--title { 30 | border: 2px solid #efefef; 31 | background-color: #efefef; 32 | } 33 | 34 | .example--body { 35 | p { 36 | margin: 0; 37 | white-space: pre-wrap; 38 | } 39 | } 40 | .markdown-body { 41 | box-sizing: border-box; 42 | margin: 0 auto; 43 | padding: 10px 20px; 44 | font-size: 14px; 45 | } 46 | 47 | // ******************** 48 | // Placeholder if there are no examples 49 | // ******************** 50 | .example--placeholder { 51 | border: 1px solid $primary-extra-light; 52 | border-radius: 4px; 53 | padding: 1rem; 54 | background-color: $primary-ultra-light; 55 | margin-bottom: 1rem; 56 | } 57 | 58 | // ******************** 59 | // Form to create a example 60 | // ******************** 61 | .example--form { 62 | margin-top: $default-space; 63 | fieldset { 64 | width: 100%; 65 | } 66 | } 67 | 68 | $filled-star-color: black; 69 | $empty-star-color: black; 70 | $star-size: 17px; 71 | 72 | .example--form-title { 73 | padding: 1rem; 74 | background-color: $primary-ultra-light; 75 | border-bottom: 1px solid $primary-extra-light; 76 | } 77 | 78 | .example--form-body { 79 | padding: 1rem 0; 80 | } 81 | 82 | .editor-toolbar.fullscreen, .CodeMirror-fullscreen, .editor-preview-side { 83 | margin-top: 30px !important; 84 | } 85 | 86 | .buttons{ 87 | margin-left: 1rem; 88 | float : right; 89 | } 90 | 91 | .submit-edit{ 92 | margin-top: 1.5em; 93 | } 94 | 95 | .edit-example:hover, .delete-example:hover{ 96 | cursor: pointer; 97 | } 98 | -------------------------------------------------------------------------------- /assets/styles/pages/_package-readme.scss: -------------------------------------------------------------------------------- 1 | .package--readme { 2 | img { 3 | max-width: 100%; 4 | } 5 | a { 6 | border-bottom: none; 7 | } 8 | } 9 | 10 | .package--readme .markdown-container { 11 | border: 1px solid #efefef; 12 | } 13 | -------------------------------------------------------------------------------- /assets/styles/pages/_package-source.scss: -------------------------------------------------------------------------------- 1 | .source--explorer { 2 | flex: 1 1 auto; 3 | display: flex; 4 | margin-bottom: 5px; 5 | } 6 | .source--tree { 7 | overflow-y: scroll; 8 | width: 240px; 9 | } 10 | 11 | .source--code { 12 | overflow-y: scroll; 13 | flex-grow: 1; 14 | background-color: #f6f7f9; 15 | } 16 | #tree { 17 | .list-group { 18 | margin-top: -0.5px; 19 | overflow: hidden; 20 | li:last-child { 21 | margin-bottom: 0px; 22 | } 23 | } 24 | .node-tree:not(.node-selected){ 25 | .glyphicon:before{ 26 | color: #3ac; 27 | } 28 | } 29 | } 30 | .source-header { 31 | width: 100%; 32 | height: 45px; 33 | flex-shrink: 0; 34 | } 35 | 36 | #source-container { 37 | pre{ 38 | margin-top: 0px; 39 | } 40 | td.hljs-ln-numbers { 41 | -webkit-touch-callout: none; 42 | -webkit-user-select: none; 43 | -khtml-user-select: none; 44 | -moz-user-select: none; 45 | -ms-user-select: none; 46 | user-select: none; 47 | 48 | text-align: center; 49 | color: #ccc; 50 | border-right: 1px solid #CCC; 51 | vertical-align: top; 52 | padding-right: 5px; 53 | 54 | /* your custom style here */ 55 | } 56 | td.hljs-ln-code { 57 | padding-left: 10px; 58 | } 59 | pre code.hljs{ 60 | padding: 0px; 61 | } 62 | tr:nth-of-type(2n){ 63 | background: #f6f7f9; 64 | } 65 | } 66 | #source-not-found { 67 | display:none; 68 | } 69 | .source{ 70 | display: flex; 71 | flex-direction: column; 72 | height: 100%; 73 | } 74 | 75 | .scroll::-webkit-scrollbar { 76 | width: 5px; 77 | margin-top: -5px; 78 | } 79 | 80 | .scroll::-webkit-scrollbar-track { 81 | background: #ddd; 82 | } 83 | 84 | .scroll::-webkit-scrollbar-thumb { 85 | background: #666; 86 | } 87 | -------------------------------------------------------------------------------- /assets/styles/pages/_package-vignettes.scss: -------------------------------------------------------------------------------- 1 | .package--vignette { 2 | img { 3 | max-width: 100%; 4 | } 5 | a { 6 | border-bottom: none; 7 | } 8 | } 9 | 10 | .package--vignette .markdown-container { 11 | border: 1px solid #efefef; 12 | } 13 | 14 | .vignette-header { 15 | @include clearfix; 16 | 17 | h1 { 18 | display: inline-block; 19 | vertical-align: middle; 20 | } 21 | 22 | .vignette--header-content { 23 | padding-top: 15px; 24 | border-bottom: 2px solid #ebf4f7; 25 | padding-bottom: 10px; 26 | } 27 | } 28 | 29 | .ph-flex-position { 30 | display: flex; 31 | flex-flow: row wrap; 32 | align-items: center; 33 | justify-content: space-between; 34 | } 35 | 36 | .vignette--title--container { 37 | display: flex; 38 | align-items: baseline; 39 | margin-bottom: 1rem; 40 | } 41 | 42 | .vignette--title { 43 | margin: 0; 44 | font-size: 2rem; 45 | } 46 | -------------------------------------------------------------------------------- /assets/styles/pages/_package.scss: -------------------------------------------------------------------------------- 1 | .package { 2 | min-height: 85%; 3 | 4 | .package--badge { 5 | margin-top: $default-space; 6 | } 7 | .content { 8 | margin-top: 1rem; 9 | } 10 | } 11 | 12 | .anchor { 13 | visibility: hidden; 14 | top: -70px; 15 | position: relative; 16 | } 17 | 18 | i.fa.fa-user{ 19 | font-size: 2rem; 20 | } 21 | 22 | #show:hover { 23 | cursor: pointer; 24 | } 25 | #info.col-md-8 { 26 | float:right; 27 | dd{ 28 | margin-left: 0px; 29 | } 30 | dl{ 31 | -webkit-margin-after: 0.4em; 32 | } 33 | .links{ 34 | -webkit-margin-before: 0.2em; 35 | } 36 | } 37 | 38 | .table-title{ 39 | display: inline-block; 40 | margin-right: 1rem; 41 | margin-left: auto; 42 | } 43 | 44 | .table-top{ 45 | position: absolute; 46 | left: 50%; 47 | transform: translateX(-50%); 48 | } 49 | 50 | #filter{ 51 | display:inline-block; 52 | } 53 | 54 | .package--stats { 55 | dd a { 56 | margin-right: $default-space / 3.0; 57 | &:last-child { 58 | margin-right: 0; 59 | } 60 | } 61 | } 62 | 63 | .package--dependencies { 64 | margin-top: $default-space; 65 | } 66 | 67 | .package--details-container { 68 | min-height: 400px; 69 | margin-top: 1rem; 70 | } 71 | .package-description { 72 | margin-top: $default-space; 73 | } 74 | 75 | .rating { 76 | display: inline-block; 77 | } 78 | 79 | .icon-green { 80 | color: #00cc00; 81 | font-size: 1.5em; 82 | margin-right: 0.5rem; 83 | } 84 | -------------------------------------------------------------------------------- /assets/styles/pages/_shared.scss: -------------------------------------------------------------------------------- 1 | .body { 2 | height: 100%; 3 | } 4 | 5 | #content { 6 | height: 100%; 7 | } 8 | 9 | .page-wrap { 10 | bottom: 55px; 11 | top: 30px; 12 | left: 0; 13 | right: 0; 14 | position: static; /* TODO: Remove after promo? */ 15 | overflow-y: scroll; 16 | } 17 | 18 | .stats { 19 | dd a { 20 | margin-right: $default-space / 3; 21 | &:last-child { 22 | margin-right: 0; 23 | } 24 | } 25 | } 26 | 27 | .no-padding { 28 | padding: 0; 29 | } 30 | 31 | .fading-text { 32 | line-height: 1.5rem; 33 | position: relative; 34 | height: 4.5rem; 35 | } 36 | 37 | .fading-text:after { 38 | content: ""; 39 | text-align: right; 40 | position: absolute; 41 | bottom: 0; 42 | right: 0; 43 | width: 70%; 44 | height: 1.5rem; 45 | background: linear-gradient( 46 | to right, 47 | rgba(255, 255, 255, 0), 48 | rgba(255, 255, 255, 1) 50% 49 | ); 50 | } 51 | 52 | .downloads, 53 | .percentile-widget { 54 | visibility: hidden; 55 | vertical-align: middle; 56 | margin-left: 0.2rem; 57 | display: inline-block; 58 | p { 59 | -webkit-margin-before: -0.7em; 60 | -webkit-margin-after: 0em; 61 | } 62 | i { 63 | font-size: 1.4rem; 64 | margin-left: 0.6rem; 65 | } 66 | } 67 | 68 | .percentile-task { 69 | visibility: hidden; 70 | } 71 | 72 | .downloads-nr, 73 | .percentile-th { 74 | display: flex; 75 | align-items: center; 76 | span:first-child { 77 | font-size: $h3-size; 78 | } 79 | 80 | &.small span:first-child { 81 | font-size: $h3-size; 82 | } 83 | } 84 | 85 | .downloads-ind { 86 | display: block; 87 | span { 88 | font-weight: bold; 89 | } 90 | } 91 | .downloads-credits { 92 | font-size: 0.6rem; 93 | } 94 | 95 | .table-list { 96 | input { 97 | width: 300px; 98 | padding: 0.375em 0.75em; 99 | margin: $default-space auto $default-space / 2 auto; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /assets/styles/pages/_task-view-sidebar.scss: -------------------------------------------------------------------------------- 1 | .sliding-sidebar{ 2 | position: fixed; 3 | height: 100%; 4 | width:265px; 5 | padding-right: 15px; 6 | overflow-y: auto; 7 | } 8 | 9 | .sidebar-slider-icon{ 10 | font-size: 2.5rem; 11 | position: absolute; 12 | top: 50%; 13 | right: 0; 14 | transform: translateY(-50%); 15 | cursor: pointer; 16 | } 17 | 18 | .list-group-item { 19 | position:relative; 20 | display:block; 21 | padding:10px 15px; 22 | margin-bottom:-1px; 23 | background-color:#fff; 24 | border:1px solid #ddd 25 | } 26 | 27 | a.list-group-item{ 28 | color: #666666; 29 | } 30 | 31 | .list-group{ 32 | padding-left:0; 33 | overflow-y: scroll; 34 | } 35 | 36 | .list-group-item.highlight{ 37 | background-color: #f5f5f5 38 | } 39 | 40 | .list-group .list-group-item:hover{ 41 | background-color: #f5f5f5 42 | } 43 | -------------------------------------------------------------------------------- /assets/styles/pages/_task-views.scss: -------------------------------------------------------------------------------- 1 | .view { 2 | position: relative; 3 | margin-left: 265px; 4 | width: calc(100% - 265px); 5 | padding: 1rem; 6 | } 7 | .percentile-number{ 8 | font-size:1.5rem; 9 | } 10 | .view td[data-column="2"] { 11 | width: 115px; 12 | } 13 | -------------------------------------------------------------------------------- /assets/styles/pages/_topic-header.scss: -------------------------------------------------------------------------------- 1 | .topic-header { 2 | margin-top: 2rem; 3 | margin-bottom:15px; 4 | } 5 | 6 | .th--flex-position { 7 | display: flex; 8 | align-items: center; 9 | justify-content: space-between; 10 | margin-top: 20px; 11 | flex-flow: row wrap; 12 | } 13 | 14 | .th--pkg-info { 15 | font-size: 1rem; 16 | background-color: #ebf4f7; 17 | border-radius: 5px; 18 | padding: 6px; 19 | display: flex; 20 | align-items: center; 21 | } 22 | 23 | .th--origin span { 24 | display: block; 25 | } 26 | 27 | .th--percentile { 28 | margin-left: 20px; 29 | font-weight: 200; 30 | } 31 | -------------------------------------------------------------------------------- /assets/styles/pages/_topic.scss: -------------------------------------------------------------------------------- 1 | .topic { 2 | min-height: 84%; 3 | 4 | h5 { 5 | text-transform: capitalize; 6 | } 7 | .run-example { 8 | display: block; 9 | margin: 10px 0; 10 | } 11 | } 12 | 13 | .topic--title { 14 | margin-top: $default-space; 15 | } 16 | 17 | // Override and support custom entries in topic--value (?) 18 | .topic--value { 19 | dl { 20 | dd { 21 | float: none; 22 | } 23 | dt { 24 | float: none; 25 | } 26 | } 27 | ul { 28 | @include clearfix; 29 | display: block; 30 | list-style: none; 31 | margin-top: 1em; 32 | margin-bottom: 1em; 33 | margin-left: 0; 34 | margin-right: 0; 35 | padding-left: 0; 36 | 37 | li { 38 | margin-bottom: 1rem; 39 | name { 40 | display: block; 41 | font-weight: bold; 42 | float: left; 43 | } 44 | 45 | .description { 46 | display: block; 47 | margin-left: 40px; 48 | margin-left: 130px; 49 | } 50 | } 51 | } 52 | } 53 | 54 | 55 | // Override DCL style 56 | .topic .powered-by-datacamp { 57 | background: white; 58 | margin: 0; 59 | a { 60 | margin-left: 5px; 61 | margin-top: 5px; 62 | display: inline-flex; 63 | font-size: 12px !important; 64 | } 65 | .logo { 66 | height: 18px; 67 | max-resolution: 0; 68 | } 69 | } 70 | 71 | .topic .dcl-exercise-area .clearfix:before{ 72 | content: none; 73 | } 74 | -------------------------------------------------------------------------------- /assets/styles/pages/_trends.scss: -------------------------------------------------------------------------------- 1 | .trends { 2 | #topkeywords { 3 | height: 400px; 4 | } 5 | #packagesperrange { 6 | height: 400px; 7 | } 8 | h1{ 9 | margin-top: .65em; 10 | } 11 | 12 | .previous, .next{ 13 | margin-top:10px; 14 | } 15 | 16 | #dependencygraph { 17 | height: 900px; 18 | overflow-y: auto; 19 | } 20 | 21 | .graph { 22 | margin-top: 2em; 23 | margin-bottom: 5em; 24 | } 25 | 26 | .data .fa{ 27 | padding-left: 2px; 28 | display: inline; 29 | } 30 | 31 | .row.top10{ 32 | margin-top: 2em; 33 | } 34 | 35 | .row.metrics { 36 | margin-top: 3rem; 37 | margin-bottom: 5rem; 38 | } 39 | 40 | .info-trends{ 41 | float: right; 42 | margin-top :0em; 43 | margin-bottom :0em; 44 | } 45 | 46 | .transp { 47 | display: none; 48 | position:absolute; 49 | left:0; 50 | top:0; 51 | background: rgba(255,255,255,.5); 52 | width:100%; 53 | height:100%; 54 | } 55 | } 56 | 57 | @media (max-width: 991px){ 58 | .trends .col-md-6{ 59 | margin-bottom: 4.2rem; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /assets/styles/pages/_user.scss: -------------------------------------------------------------------------------- 1 | .user { 2 | min-height: 82%; 3 | .container { 4 | margin-top: $default-space; 5 | } 6 | 7 | header { 8 | margin-bottom: $default-space; 9 | } 10 | } 11 | 12 | .user--reviews { 13 | h3 { 14 | margin-bottom: $default-space / 2.0; 15 | } 16 | } 17 | 18 | .example { 19 | .clearfix:before, .container:before, .container-fluid:before, .row:before{ 20 | display: none; 21 | } 22 | } -------------------------------------------------------------------------------- /assets/styles/styleguide/partials/_labels.scss: -------------------------------------------------------------------------------- 1 | .label { 2 | color: $text-invert; 3 | display: inline-block; 4 | font-size: $small-font-size; 5 | margin-left: 5px; 6 | padding: 0.25em 0.4375em; 7 | position: relative; 8 | text-transform: uppercase; 9 | top: -3px; 10 | border-radius: 0; 11 | font-weight: 400; 12 | } 13 | 14 | .label-accent { 15 | background-color: $accent; 16 | } -------------------------------------------------------------------------------- /assets/styles/styleguide/partials/_lists.scss: -------------------------------------------------------------------------------- 1 | ul.no-style, 2 | ol.no-style { 3 | list-style: none; 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | 9 | ul.inline, 10 | ol.inline { 11 | list-style: none; 12 | margin: 0; 13 | padding: 0; 14 | @include clearfix; 15 | li { 16 | float: left; 17 | margin-right:10px; 18 | } 19 | 20 | li:last-child { 21 | margin-right: 0; 22 | } 23 | } -------------------------------------------------------------------------------- /assets/styles/styleguide/partials/_rstudio.scss: -------------------------------------------------------------------------------- 1 | html.rstudio { 2 | font-size: 14px; 3 | 4 | .topic { 5 | h1 {font-size: $h1-size * 0.6} 6 | h2 {font-size: $h2-size * 0.7} 7 | h3 {font-size: $h3-size * 0.7} 8 | h4 {font-size: $h4-size * 0.6} 9 | h5 {font-size: $h5-size * 0.9} 10 | .container-fluid { 11 | margin-top: 0.5rem; 12 | } 13 | } 14 | 15 | } 16 | 17 | -------------------------------------------------------------------------------- /assets/styles/styleguide/partials/_tables.scss: -------------------------------------------------------------------------------- 1 | table { 2 | border-collapse: collapse; 3 | text-align: left; 4 | width: 100% 5 | } 6 | 7 | thead { 8 | font-weight: bold; 9 | } 10 | tr { 11 | border-bottom: $table-border-width solid $primary-extra-light; 12 | } 13 | tr:nth-of-type(2n) { 14 | background: $primary-ultra-light; 15 | } 16 | th { 17 | border-bottom: $table-border-width solid $text-tertiary; 18 | color: $primary; 19 | } 20 | td, 21 | th { 22 | padding: $table-spacing; 23 | } 24 | td { 25 | color: $text-secondary; 26 | } 27 | 28 | tr.no-results { 29 | border-bottom: none; 30 | text-align: center; 31 | display: none; 32 | td { 33 | padding: $default-space 0; 34 | } 35 | } -------------------------------------------------------------------------------- /assets/styles/widgets/_big-number.scss: -------------------------------------------------------------------------------- 1 | .big-number { 2 | .number { 3 | line-height: 9rem; 4 | height: 100%; 5 | text-align: center; 6 | display: block; 7 | font-size: 9rem; 8 | } 9 | .big-number-label { 10 | display: block; 11 | text-align: center; 12 | line-height: 2rem; 13 | font-size: 2rem; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /assets/styles/widgets/_loader.scss: -------------------------------------------------------------------------------- 1 | .loader-outer { 2 | display: table; 3 | height: 100%; 4 | width: 100%; 5 | } 6 | 7 | .loader-middle { 8 | display: table-cell; 9 | vertical-align: middle; 10 | } 11 | 12 | .loader { 13 | margin-left: auto; 14 | margin-right: auto; 15 | border: 16px solid #f3f3f3; /* Light grey */ 16 | border-top: 16px solid $primary; 17 | border-radius: 50%; 18 | width: 120px; 19 | height: 120px; 20 | animation: spin 2s linear infinite; 21 | } 22 | 23 | @keyframes spin { 24 | 0% { transform: rotate(0deg); } 25 | 100% { transform: rotate(360deg); } 26 | } 27 | -------------------------------------------------------------------------------- /assets/styles/widgets/_modal.scss: -------------------------------------------------------------------------------- 1 | .jquery-modal.blocker{ 2 | z-index:1050; 3 | .modal a.close-modal{ 4 | border-bottom: none; 5 | } 6 | } 7 | 8 | .jquery-modal .modal{ 9 | width:550px; 10 | } 11 | 12 | @media(max-width: 600px){ 13 | .jquery-modal .modal{ 14 | width: 92%; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /assets/styles/widgets/mono-blue.css: -------------------------------------------------------------------------------- 1 | /* 2 | Five-color theme from a single blue hue. 3 | */ 4 | .hljs { 5 | display: block; 6 | overflow-x: auto; 7 | padding: 0.5em; 8 | background: #eaeef3; 9 | } 10 | 11 | .hljs { 12 | color: #00193a; 13 | } 14 | 15 | .hljs-keyword, 16 | .hljs-selector-tag, 17 | .hljs-title, 18 | .hljs-section, 19 | .hljs-doctag, 20 | .hljs-name, 21 | .hljs-strong { 22 | font-weight: bold; 23 | } 24 | 25 | .hljs-comment { 26 | color: #738191; 27 | } 28 | 29 | .hljs-string, 30 | .hljs-title, 31 | .hljs-section, 32 | .hljs-built_in, 33 | .hljs-literal, 34 | .hljs-type, 35 | .hljs-addition, 36 | .hljs-tag, 37 | .hljs-quote, 38 | .hljs-name, 39 | .hljs-selector-id, 40 | .hljs-selector-class { 41 | color: #0048ab; 42 | } 43 | 44 | .hljs-meta, 45 | .hljs-subst, 46 | .hljs-symbol, 47 | .hljs-regexp, 48 | .hljs-attribute, 49 | .hljs-deletion, 50 | .hljs-variable, 51 | .hljs-template-variable, 52 | .hljs-link, 53 | .hljs-bullet { 54 | color: #4c81c9; 55 | } 56 | 57 | .hljs-emphasis { 58 | font-style: italic; 59 | } 60 | -------------------------------------------------------------------------------- /assets/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/assets/templates/.gitkeep -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | if [ -n "$(git status --porcelain)" ]; then 5 | echo "Your git directory is not clean, commit your changes before building"; 6 | exit 1; 7 | fi 8 | 9 | docker login --username="$1" --password="$2" --email=a dockerhub.datacamp.com:443 10 | #build new docker image 11 | docker build -t dockerhub.datacamp.com:443/rdocsv2:$BUILD_NUMBER . 12 | #push image to docker registery 13 | docker push dockerhub.datacamp.com:443/rdocsv2:$BUILD_NUMBER 14 | 15 | sed -e "s/\$version/$BUILD_NUMBER/" -e "s/\$memory/1500/" < Dockerrun.aws.json.in > Dockerrun.aws.json 16 | 17 | -------------------------------------------------------------------------------- /catalog-info.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | description: "rdoc-app service, code: rdocumentation-app infra: RDocumentation-app-infra " 5 | name: rdoc-app 6 | annotations: 7 | github.com/project-slug: "datacamp/rdocumentation-app" 8 | circleci.com/project-slug: "github/datacamp/rdocumentation-app" 9 | tags: 10 | - infrastructure-data 11 | spec: 12 | lifecycle: "production" 13 | owner: "infrastructure-data" 14 | type: "service" 15 | -------------------------------------------------------------------------------- /config/bootstrap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bootstrap 3 | * (sails.config.bootstrap) 4 | * 5 | * An asynchronous bootstrap function that runs before your Sails app gets lifted. 6 | * This gives you an opportunity to set up your data model, run jobs, or perform some special logic. 7 | * 8 | * For more information on bootstrapping your app, check out: 9 | * http://sailsjs.org/#!/documentation/reference/sails.config/sails.config.bootstrap.html 10 | */ 11 | 12 | var _ = require('lodash'); 13 | module.exports.bootstrap = function(cb) { 14 | 15 | // It's very important to trigger this callback method when you are finished 16 | // with the bootstrap! (otherwise your server will never lift, since it's waiting on the bootstrap) 17 | _.extend(sails.hooks.http.app.locals, sails.config.http.locals); 18 | cb(); 19 | }; 20 | -------------------------------------------------------------------------------- /config/elasticsearch.js: -------------------------------------------------------------------------------- 1 | var bluebird = require('bluebird'); 2 | 3 | module.exports.elasticsearch = { 4 | 5 | host: process.env.ELASTICSEARCH_URL, 6 | 7 | log: 'error', 8 | 9 | defer: function () { 10 | return bluebird.defer(); 11 | } 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /config/env/development.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Development environment settings 3 | * 4 | * This file can include shared settings for a development team, 5 | * such as API keys or remote database passwords. If you're using 6 | * a version control solution for your Sails app, this file will 7 | * be committed to your repository unless you add it to your .gitignore 8 | * file. If your repository will be publicly viewable, don't add 9 | * any private information to this file! 10 | * 11 | */ 12 | 13 | module.exports = { 14 | 15 | /*************************************************************************** 16 | * Set the default database connection for models in the development * 17 | * environment (see config/connections.js and config/models.js ) * 18 | ***************************************************************************/ 19 | connections: { 20 | sequelize_mysql: { 21 | database: process.env.DATABASE_NAME, 22 | user: process.env.DATABASE_USERNAME, 23 | password: process.env.DATABASE_PASSWORD, 24 | options: { 25 | dialect: 'mysql', 26 | host: process.env.DATABASE_HOST, 27 | port: process.env.DATABASE_PORT, 28 | pool: { 29 | max: 10, 30 | min: 4, 31 | idle: 10000 32 | } 33 | } 34 | } 35 | }, 36 | 37 | models: { 38 | migrate: 'safe' 39 | }, 40 | 41 | session: { 42 | secret: '652c68f88144e6a99b9522ea1193a645' 43 | }, 44 | 45 | redis: { 46 | 47 | logging: true, 48 | 49 | url: process.env.REDIS_URL 50 | 51 | }, 52 | 53 | cors: { 54 | allRoutes: true, 55 | 56 | origin: '*', 57 | 58 | credentials: true, 59 | 60 | exposeHeaders: 'X-RStudio-Ajax, X-RStudio-Redirect, X-Rstudio-Session', 61 | 62 | methods: 'GET, POST, PUT, DELETE, OPTIONS, HEAD', 63 | 64 | headers: 'Content-Type, Accept-Encoding, X-Shared-Secret, X-Requested-With, Cache-Control, X-RStudio-Ajax, X-RStudio-Redirect, X-Rstudio-Session' 65 | } 66 | 67 | }; 68 | -------------------------------------------------------------------------------- /config/env/docker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Development environment settings 3 | * 4 | * This file can include shared settings for a development team, 5 | * such as API keys or remote database passwords. If you're using 6 | * a version control solution for your Sails app, this file will 7 | * be committed to your repository unless you add it to your .gitignore 8 | * file. If your repository will be publicly viewable, don't add 9 | * any private information to this file! 10 | * 11 | */ 12 | 13 | module.exports = { 14 | 15 | /*************************************************************************** 16 | * Set the default database connection for models in the development * 17 | * environment (see config/connections.js and config/models.js ) * 18 | ***************************************************************************/ 19 | connections: { 20 | sequelize_mysql: { 21 | database: process.env.DATABASE_NAME, 22 | user: process.env.DATABASE_USERNAME, 23 | password: process.env.DATABASE_PASSWORD, 24 | options: { 25 | dialect: 'mysql', 26 | host : process.env.DATABASE_HOST, 27 | port : process.env.DATABASE_PORT, 28 | pool: { 29 | max: 10, 30 | min: 4, 31 | idle: 10000 32 | } 33 | } 34 | } 35 | }, 36 | 37 | models: { 38 | migrate: 'safe' 39 | }, 40 | 41 | session: { 42 | url: 'redis://redis:6379', 43 | prefix: 'sess:' 44 | }, 45 | 46 | grunt: { 47 | _hookTimeout: 60000 48 | }, 49 | 50 | routes: { 51 | 'post /tasks': 'WorkerController.processMessage', 52 | 'get /last-day-splitted-stats': 'WorkerController.lastDaySplittedDownloads' 53 | } 54 | 55 | 56 | }; 57 | -------------------------------------------------------------------------------- /config/env/production.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Production environment settings 3 | * 4 | * This file can include shared settings for a production environment, 5 | * such as API keys or remote database passwords. If you're using 6 | * a version control solution for your Sails app, this file will 7 | * be committed to your repository unless you add it to your .gitignore 8 | * file. If your repository will be publicly viewable, don't add 9 | * any private information to this file! 10 | * 11 | */ 12 | 13 | module.exports = { 14 | 15 | connections: { 16 | sequelize_mysql: { 17 | database: process.env.DATABASE_NAME, 18 | user: process.env.DATABASE_USERNAME, 19 | password: process.env.DATABASE_PASSWORD, 20 | options: { 21 | dialect: 'mysql', 22 | host : process.env.DATABASE_HOST, 23 | port : process.env.DATABASE_PORT, 24 | pool: { 25 | max: 15, 26 | min: 4, 27 | idle: 10000 28 | } 29 | } 30 | }, 31 | 32 | }, 33 | 34 | models: { 35 | migrate: 'safe' 36 | }, 37 | 38 | session: { 39 | url: process.env.REDIS_URL, 40 | prefix: 'sess:', 41 | }, 42 | 43 | grunt: { 44 | _hookTimeout: 60000 45 | } 46 | 47 | 48 | }; 49 | -------------------------------------------------------------------------------- /config/env/staging.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Staging environment settings 3 | * 4 | * This file can include shared settings for a staging environment, 5 | * such as API keys or remote database passwords. If you're using 6 | * a version control solution for your Sails app, this file will 7 | * be committed to your repository unless you add it to your .gitignore 8 | * file. If your repository will be publicly viewable, don't add 9 | * any private information to this file! 10 | * 11 | */ 12 | 13 | module.exports = { 14 | 15 | connections: { 16 | sequelize_mysql: { 17 | database: process.env.DATABASE_NAME, 18 | user: process.env.DATABASE_USERNAME, 19 | password: process.env.DATABASE_PASSWORD, 20 | options: { 21 | dialect: 'mysql', 22 | host : process.env.DATABASE_HOST, 23 | port : process.env.DATABASE_PORT, 24 | pool: { 25 | max: 5, 26 | min: 2, 27 | idle: 10000 28 | }, 29 | benchmark:true 30 | } 31 | }, 32 | 33 | }, 34 | 35 | models: { 36 | migrate: 'safe' 37 | }, 38 | 39 | session: { 40 | url: process.env.REDIS_URL, 41 | prefix: 'sess:' 42 | }, 43 | 44 | grunt: { 45 | _hookTimeout: 60000 46 | }, 47 | 48 | cors: { 49 | allRoutes: true, 50 | origin: '*', 51 | credentials: true, 52 | exposeHeaders: 'X-RStudio-Ajax, X-RStudio-Redirect, X-Rstudio-Session', 53 | methods: 'GET, POST, PUT, DELETE, OPTIONS, HEAD', 54 | headers: 'Content-Type, Accept-Encoding, X-Shared-Secret, X-Requested-With, Cache-Control, X-RStudio-Ajax, X-RStudio-Redirect, X-Rstudio-Session' 55 | } 56 | 57 | }; 58 | -------------------------------------------------------------------------------- /config/env/worker.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | 4 | connections: { 5 | sequelize_mysql: { 6 | database: process.env.DATABASE_NAME, 7 | user: process.env.DATABASE_USERNAME, 8 | password: process.env.DATABASE_PASSWORD, 9 | options: { 10 | dialect: 'mysql', 11 | host : process.env.DATABASE_HOST, 12 | port : process.env.DATABASE_PORT, 13 | pool: { 14 | max: 10, 15 | min: 3, 16 | idle: 10000 17 | } 18 | } 19 | }, 20 | 21 | }, 22 | 23 | models: { 24 | migrate: 'safe' 25 | }, 26 | 27 | grunt: { 28 | _hookTimeout: 60000 29 | }, 30 | 31 | 32 | session: { 33 | url: process.env.REDIS_URL, 34 | prefix: 'sess:' 35 | }, 36 | 37 | routes: { 38 | 'post /tasks': 'WorkerController.processMessage', 39 | 'get /status': 'HomeController.status' 40 | } 41 | 42 | }; 43 | -------------------------------------------------------------------------------- /config/locales/_README.md: -------------------------------------------------------------------------------- 1 | # Internationalization / Localization Settings 2 | 3 | > Also see the official docs on internationalization/localization: 4 | > http://links.sailsjs.org/docs/config/locales 5 | 6 | ## Locales 7 | All locale files live under `config/locales`. Here is where you can add translations 8 | as JSON key-value pairs. The name of the file should match the language that you are supporting, which allows for automatic language detection based on request headers. 9 | 10 | Here is an example locale stringfile for the Spanish language (`config/locales/es.json`): 11 | ```json 12 | { 13 | "Hello!": "Hola!", 14 | "Hello %s, how are you today?": "¿Hola %s, como estas?", 15 | } 16 | ``` 17 | ## Usage 18 | Locales can be accessed in controllers/policies through `res.i18n()`, or in views through the `__(key)` or `i18n(key)` functions. 19 | Remember that the keys are case sensitive and require exact key matches, e.g. 20 | 21 | ```ejs 22 |

<%= __('Welcome to PencilPals!') %>

23 |

<%= i18n('Hello %s, how are you today?', 'Pencil Maven') %>

24 |

<%= i18n('That\'s right-- you can use either i18n() or __()') %>

25 | ``` 26 | 27 | ## Configuration 28 | Localization/internationalization config can be found in `config/i18n.js`, from where you can set your supported locales. 29 | -------------------------------------------------------------------------------- /config/locales/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "Welcome": "Willkommen", 3 | "A brand new app.": "Eine neue App." 4 | } 5 | -------------------------------------------------------------------------------- /config/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "Welcome": "Welcome", 3 | "A brand new app.": "A brand new app." 4 | } 5 | -------------------------------------------------------------------------------- /config/locales/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "Welcome": "Bienvenido", 3 | "A brand new app.": "Una nueva aplicación." 4 | } 5 | -------------------------------------------------------------------------------- /config/locales/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "Welcome": "Bienvenue", 3 | "A brand new app.": "Une toute nouvelle application." 4 | } 5 | -------------------------------------------------------------------------------- /config/log.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Built-in Log Configuration 3 | * (sails.config.log) 4 | * 5 | * Configure the log level for your app, as well as the transport 6 | * (Underneath the covers, Sails uses Winston for logging, which 7 | * allows for some pretty neat custom transports/adapters for log messages) 8 | * 9 | * For more information on the Sails logger, check out: 10 | * http://sailsjs.org/#!/documentation/concepts/Logging 11 | */ 12 | 13 | module.exports.log = { 14 | 15 | /*************************************************************************** 16 | * * 17 | * Valid `level` configs: i.e. the minimum log level to capture with * 18 | * sails.log.*() * 19 | * * 20 | * The order of precedence for log levels from lowest to highest is: * 21 | * silly, verbose, info, debug, warn, error * 22 | * * 23 | * You may also set the level to "silent" to suppress all logs. * 24 | * * 25 | ***************************************************************************/ 26 | 27 | // level: 'info' 28 | 29 | }; 30 | -------------------------------------------------------------------------------- /config/models.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Default model configuration 3 | * (sails.config.models) 4 | * 5 | * Unless you override them, the following properties will be included 6 | * in each of your models. 7 | * 8 | * For more info on Sails models, see: 9 | * http://sailsjs.org/#!/documentation/concepts/ORM 10 | */ 11 | 12 | module.exports.models = { 13 | 14 | /*************************************************************************** 15 | * * 16 | * Your app's default connection. i.e. the name of one of your app's * 17 | * connections (see `config/connections.js`) * 18 | * * 19 | ***************************************************************************/ 20 | connection: 'sequelize_mysql', 21 | 22 | /*************************************************************************** 23 | * * 24 | * How and whether Sails will attempt to automatically rebuild the * 25 | * tables/collections/etc. in your schema. * 26 | * * 27 | * See http://sailsjs.org/#!/documentation/concepts/ORM/model-settings.html * 28 | * * 29 | ***************************************************************************/ 30 | migrate: 'alter' 31 | 32 | }; 33 | -------------------------------------------------------------------------------- /config/redis.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports.redis = { 3 | 4 | logging:true, 5 | 6 | url: process.env.REDIS_URL, 7 | 8 | options: { 9 | 10 | } 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /cron.yaml: -------------------------------------------------------------------------------- 1 | version: 1 2 | cron: 3 | - name: "last-day-splitted-stats" # required - unique across all entries in this file 4 | url: "/last-day-splitted-stats" # required - does not need to be unique 5 | schedule: "0 */12 * * *" # required - does not need to be unique 6 | - name: "update-percentile" # required - unique across all entries in this file 7 | url: "/update-percentile" # required - does not need to be unique 8 | schedule: "0 */12 * * *" # required - does not need to be unique 9 | -------------------------------------------------------------------------------- /database.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultEnv": "development", 3 | 4 | "docker": { 5 | "driver": "mysql", 6 | "host": { "ENV": "DATABASE_HOST" }, 7 | "user": { "ENV": "DATABASE_USERNAME" }, 8 | "password": { "ENV": "DATABASE_PASSWORD" }, 9 | "database": { "ENV": "DATABASE_NAME" }, 10 | "port": { "ENV": "DATABASE_PORT" }, 11 | "multipleStatements": true 12 | }, 13 | 14 | "development": { 15 | "driver": "mysql", 16 | "host": { "ENV": "DATABASE_HOST" }, 17 | "user": { "ENV": "DATABASE_USERNAME" }, 18 | "password": { "ENV": "DATABASE_PASSWORD" }, 19 | "database": { "ENV": "DATABASE_NAME" }, 20 | "port": { "ENV": "DATABASE_PORT" }, 21 | "multipleStatements": true 22 | }, 23 | 24 | "staging": { 25 | "driver": "mysql", 26 | "host": { "ENV": "DATABASE_HOST" }, 27 | "user": { "ENV": "DATABASE_USERNAME" }, 28 | "password": { "ENV": "DATABASE_PASSWORD" }, 29 | "database": { "ENV": "DATABASE_NAME" }, 30 | "port": { "ENV": "DATABASE_PORT" }, 31 | "multipleStatements": true 32 | }, 33 | 34 | "worker": { 35 | "driver": "mysql", 36 | "host": { "ENV": "DATABASE_HOST" }, 37 | "user": { "ENV": "DATABASE_USERNAME" }, 38 | "password": { "ENV": "DATABASE_PASSWORD" }, 39 | "database": { "ENV": "DATABASE_NAME" }, 40 | "port": { "ENV": "DATABASE_PORT" }, 41 | "multipleStatements": true 42 | }, 43 | 44 | "production": { 45 | "driver": "mysql", 46 | "host": { "ENV": "DATABASE_HOST" }, 47 | "user": { "ENV": "DATABASE_USERNAME" }, 48 | "password": { "ENV": "DATABASE_PASSWORD" }, 49 | "database": { "ENV": "DATABASE_NAME" }, 50 | "port": { "ENV": "DATABASE_PORT" }, 51 | "multipleStatements": true 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /deploy_worker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | if [ -n "$(git status --porcelain)" ]; then 5 | echo "Your git directory is not clean, commit your changes before building"; 6 | exit 1; 7 | fi 8 | 9 | BUILD_NUMBER=$(git rev-parse --short HEAD) 10 | #build new docker image 11 | docker build -t dockerhub.datacamp.com:443/rdocsv2:$BUILD_NUMBER . 12 | #push image to docker registery 13 | docker push dockerhub.datacamp.com:443/rdocsv2:$BUILD_NUMBER 14 | 15 | sed -e "s/\$version/$BUILD_NUMBER/" -e "s/\$memory/1500/" < Dockerrun.aws.json.in > Dockerrun.aws.json 16 | 17 | zip -r build/release.zip Dockerrun.aws.json proxy .ebextensions cron.yaml 18 | 19 | eb deploy rdocsv2-workers 20 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | db: 4 | image: mysql:latest 5 | ports: 6 | - "3306:3306" 7 | environment: 8 | MYSQL_ROOT_PASSWORD: password 9 | MYSQL_USER: rdoc 10 | MYSQL_PASSWORD: password 11 | MYSQL_DATABASE: rdocs 12 | redis: 13 | image: redis 14 | ports: 15 | - "6379:6379" 16 | -------------------------------------------------------------------------------- /ecs.worker.json: -------------------------------------------------------------------------------- 1 | { 2 | "cluster": "${CLUSTER}", 3 | "servicePort": 1337, 4 | "serviceProtocol": "HTTP", 5 | "desiredCount": ${DESIRED_COUNT}, 6 | "loadBalancer": "datacamp-services-internal", 7 | "containers": [ 8 | { 9 | "containerName": "${SERVICE}-worker", 10 | "containerImage": "${CONTAINER_IMAGE}", 11 | "containerTag": "${CIRCLE_SHA1}", 12 | "containerPort": 1337, 13 | "memoryReservation": 4000, 14 | "cpu": 256, 15 | "essential": true 16 | }, 17 | { 18 | "containerName": "${SERVICE}-sqsd", 19 | "containerImage": "sqsd", 20 | "containerTag": "latest", 21 | "memoryReservation": 128, 22 | "essential": true, 23 | "containerCommand": [ 24 | "bash", 25 | "-c", 26 | "eval $(aws-env) && node run-cli.js" 27 | ] 28 | } 29 | ], 30 | "healthCheck": { 31 | "healthyThreshold": 3, 32 | "unhealthyThreshold": 5, 33 | "path": "/status", 34 | "interval": 60, 35 | "matcher": "200" 36 | }, 37 | "ruleConditions": [ 38 | { 39 | "hostname": "rdoc-worker", 40 | "listeners": [ 41 | "https" 42 | ] 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /jake/sails-lifter.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = { 4 | 5 | lift: function(done) { 6 | var sails = require('sails'); 7 | require('dotenv').config({silent: true}); 8 | var liftSails = function (config, cb) { 9 | if (sails.config) { 10 | return cb(); 11 | } 12 | 13 | config.hooks = { 14 | blueprints: false, 15 | controllers: false, 16 | cors: false, 17 | csrf: false, 18 | grunt: false, 19 | http: false, 20 | i18n: false, 21 | logger: false, 22 | orm:false, 23 | policies: false, 24 | pubsub: false, 25 | request: false, 26 | responses: false, 27 | //services: leave default hook, 28 | session: false, 29 | sockets: false, 30 | views: false 31 | }; 32 | // Start server 33 | sails.load(config, cb); 34 | }; 35 | 36 | liftSails({ 37 | port: 1338, 38 | environment: process.env.NODE_ENV, 39 | tasks: true 40 | }, done); 41 | } 42 | 43 | }; 44 | -------------------------------------------------------------------------------- /migrations/20160603105133-initial.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var Promise; 9 | 10 | /** 11 | * We receive the dbmigrate dependency from dbmigrate initially. 12 | * This enables us to not have to rely on NODE_PATH. 13 | */ 14 | exports.setup = function(options, seedLink) { 15 | dbm = options.dbmigrate; 16 | type = dbm.dataType; 17 | seed = seedLink; 18 | Promise = options.Promise; 19 | }; 20 | 21 | exports.up = function(db) { 22 | var filePath = path.join(__dirname + '/sqls/20160603105133-migration-name-up.sql'); 23 | return new Promise( function( resolve, reject ) { 24 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 25 | if (err) return reject(err); 26 | console.log('received data: ' + data); 27 | 28 | resolve(data); 29 | }); 30 | }) 31 | .then(function(data) { 32 | return db.runSql(data); 33 | }); 34 | }; 35 | 36 | exports.down = function(db) { 37 | var filePath = path.join(__dirname + '/sqls/20160603105133-migration-name-down.sql'); 38 | return new Promise( function( resolve, reject ) { 39 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 40 | if (err) return reject(err); 41 | console.log('received data: ' + data); 42 | 43 | resolve(data); 44 | }); 45 | }) 46 | .then(function(data) { 47 | return db.runSql(data); 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /migrations/20160607121610-indexAliases.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | 7 | /** 8 | * We receive the dbmigrate dependency from dbmigrate initially. 9 | * This enables us to not have to rely on NODE_PATH. 10 | */ 11 | exports.setup = function(options, seedLink) { 12 | dbm = options.dbmigrate; 13 | type = dbm.dataType; 14 | seed = seedLink; 15 | }; 16 | 17 | exports.up = function(db, callback) { 18 | db.addIndex('Aliases', 'name_index', 'name', callback); 19 | }; 20 | 21 | exports.down = function(db) { 22 | return null; 23 | }; 24 | -------------------------------------------------------------------------------- /migrations/20160609193515-title-allow-null.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var Promise; 9 | 10 | /** 11 | * We receive the dbmigrate dependency from dbmigrate initially. 12 | * This enables us to not have to rely on NODE_PATH. 13 | */ 14 | exports.setup = function(options, seedLink) { 15 | dbm = options.dbmigrate; 16 | type = dbm.dataType; 17 | seed = seedLink; 18 | Promise = options.Promise; 19 | }; 20 | 21 | exports.up = function(db) { 22 | var filePath = path.join(__dirname + '/sqls/20160609193515-title-allow-null-up.sql'); 23 | return new Promise( function( resolve, reject ) { 24 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 25 | if (err) return reject(err); 26 | console.log('received data: ' + data); 27 | 28 | resolve(data); 29 | }); 30 | }) 31 | .then(function(data) { 32 | return db.runSql(data); 33 | }); 34 | }; 35 | 36 | exports.down = function(db) { 37 | var filePath = path.join(__dirname + '/sqls/20160609193515-title-allow-null-down.sql'); 38 | return new Promise( function( resolve, reject ) { 39 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 40 | if (err) return reject(err); 41 | console.log('received data: ' + data); 42 | 43 | resolve(data); 44 | }); 45 | }) 46 | .then(function(data) { 47 | return db.runSql(data); 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /migrations/20160610094821-argument-description.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var Promise; 9 | 10 | /** 11 | * We receive the dbmigrate dependency from dbmigrate initially. 12 | * This enables us to not have to rely on NODE_PATH. 13 | */ 14 | exports.setup = function(options, seedLink) { 15 | dbm = options.dbmigrate; 16 | type = dbm.dataType; 17 | seed = seedLink; 18 | Promise = options.Promise; 19 | }; 20 | 21 | exports.up = function(db) { 22 | var filePath = path.join(__dirname + '/sqls/20160610094821-argument-description-up.sql'); 23 | return new Promise( function( resolve, reject ) { 24 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 25 | if (err) return reject(err); 26 | console.log('received data: ' + data); 27 | 28 | resolve(data); 29 | }); 30 | }) 31 | .then(function(data) { 32 | return db.runSql(data); 33 | }); 34 | }; 35 | 36 | exports.down = function(db) { 37 | var filePath = path.join(__dirname + '/sqls/20160610094821-argument-description-down.sql'); 38 | return new Promise( function( resolve, reject ) { 39 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 40 | if (err) return reject(err); 41 | console.log('received data: ' + data); 42 | 43 | resolve(data); 44 | }); 45 | }) 46 | .then(function(data) { 47 | return db.runSql(data); 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /migrations/20160612100705-users.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | 7 | /** 8 | * We receive the dbmigrate dependency from dbmigrate initially. 9 | * This enables us to not have to rely on NODE_PATH. 10 | */ 11 | exports.setup = function(options, seedLink) { 12 | dbm = options.dbmigrate; 13 | type = dbm.dataType; 14 | seed = seedLink; 15 | }; 16 | 17 | exports.up = function(db, cb) { 18 | db.createTable('Users', { 19 | id: { type: 'int', primaryKey: true, autoIncrement: true }, 20 | username: { type: 'string', unique: true, notNull: true}, 21 | password: { type: 'string', notNull: true }, 22 | created_at: { type: 'datetime', notNull: true}, 23 | updated_at: { type: 'datetime', notNull: true} 24 | }, cb); 25 | }; 26 | 27 | exports.down = function(db, cb) { 28 | db.dropTable('Users', { ifExists: true }, cb); 29 | }; 30 | -------------------------------------------------------------------------------- /migrations/20160612150901-package-type.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var Promise; 9 | 10 | /** 11 | * We receive the dbmigrate dependency from dbmigrate initially. 12 | * This enables us to not have to rely on NODE_PATH. 13 | */ 14 | exports.setup = function(options, seedLink) { 15 | dbm = options.dbmigrate; 16 | type = dbm.dataType; 17 | seed = seedLink; 18 | Promise = options.Promise; 19 | }; 20 | 21 | exports.up = function(db) { 22 | var filePath = path.join(__dirname + '/sqls/20160612150901-package-type-up.sql'); 23 | return new Promise( function( resolve, reject ) { 24 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 25 | if (err) return reject(err); 26 | console.log('received data: ' + data); 27 | 28 | resolve(data); 29 | }); 30 | }) 31 | .then(function(data) { 32 | return db.runSql(data); 33 | }); 34 | }; 35 | 36 | exports.down = function(db) { 37 | var filePath = path.join(__dirname + '/sqls/20160612150901-package-type-down.sql'); 38 | return new Promise( function( resolve, reject ) { 39 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 40 | if (err) return reject(err); 41 | console.log('received data: ' + data); 42 | 43 | resolve(data); 44 | }); 45 | }) 46 | .then(function(data) { 47 | return db.runSql(data); 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /migrations/20160612161712-package-type-allow-null.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var Promise; 9 | 10 | /** 11 | * We receive the dbmigrate dependency from dbmigrate initially. 12 | * This enables us to not have to rely on NODE_PATH. 13 | */ 14 | exports.setup = function(options, seedLink) { 15 | dbm = options.dbmigrate; 16 | type = dbm.dataType; 17 | seed = seedLink; 18 | Promise = options.Promise; 19 | }; 20 | 21 | exports.up = function(db) { 22 | var filePath = path.join(__dirname + '/sqls/20160612161712-package-type-allow-null-up.sql'); 23 | return new Promise( function( resolve, reject ) { 24 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 25 | if (err) return reject(err); 26 | console.log('received data: ' + data); 27 | 28 | resolve(data); 29 | }); 30 | }) 31 | .then(function(data) { 32 | return db.runSql(data); 33 | }); 34 | }; 35 | 36 | exports.down = function(db) { 37 | var filePath = path.join(__dirname + '/sqls/20160612161712-package-type-allow-null-down.sql'); 38 | return new Promise( function( resolve, reject ) { 39 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 40 | if (err) return reject(err); 41 | console.log('received data: ' + data); 42 | 43 | resolve(data); 44 | }); 45 | }) 46 | .then(function(data) { 47 | return db.runSql(data); 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /migrations/20160612162625-topic-add-sourceJSON.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var Promise; 9 | 10 | /** 11 | * We receive the dbmigrate dependency from dbmigrate initially. 12 | * This enables us to not have to rely on NODE_PATH. 13 | */ 14 | exports.setup = function(options, seedLink) { 15 | dbm = options.dbmigrate; 16 | type = dbm.dataType; 17 | seed = seedLink; 18 | Promise = options.Promise; 19 | }; 20 | 21 | exports.up = function(db) { 22 | var filePath = path.join(__dirname + '/sqls/20160612162625-topic-add-sourceJSON-up.sql'); 23 | return new Promise( function( resolve, reject ) { 24 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 25 | if (err) return reject(err); 26 | console.log('received data: ' + data); 27 | 28 | resolve(data); 29 | }); 30 | }) 31 | .then(function(data) { 32 | return db.runSql(data); 33 | }); 34 | }; 35 | 36 | exports.down = function(db) { 37 | var filePath = path.join(__dirname + '/sqls/20160612162625-topic-add-sourceJSON-down.sql'); 38 | return new Promise( function( resolve, reject ) { 39 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 40 | if (err) return reject(err); 41 | console.log('received data: ' + data); 42 | 43 | resolve(data); 44 | }); 45 | }) 46 | .then(function(data) { 47 | return db.runSql(data); 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /migrations/20160613085210-comments.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var Promise; 9 | 10 | /** 11 | * We receive the dbmigrate dependency from dbmigrate initially. 12 | * This enables us to not have to rely on NODE_PATH. 13 | */ 14 | exports.setup = function(options, seedLink) { 15 | dbm = options.dbmigrate; 16 | type = dbm.dataType; 17 | seed = seedLink; 18 | Promise = options.Promise; 19 | }; 20 | 21 | exports.up = function(db) { 22 | var filePath = path.join(__dirname + '/sqls/20160613085210-comments-up.sql'); 23 | return new Promise( function( resolve, reject ) { 24 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 25 | if (err) return reject(err); 26 | console.log('received data: ' + data); 27 | 28 | resolve(data); 29 | }); 30 | }) 31 | .then(function(data) { 32 | return db.runSql(data); 33 | }); 34 | }; 35 | 36 | exports.down = function(db) { 37 | var filePath = path.join(__dirname + '/sqls/20160613085210-comments-down.sql'); 38 | return new Promise( function( resolve, reject ) { 39 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 40 | if (err) return reject(err); 41 | console.log('received data: ' + data); 42 | 43 | resolve(data); 44 | }); 45 | }) 46 | .then(function(data) { 47 | return db.runSql(data); 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /migrations/20160614083536-review-model.js: -------------------------------------------------------------------------------- 1 | var dbm = global.dbm || require('db-migrate'); 2 | var type = dbm.dataType; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | exports.up = function(db, callback) { 7 | var filePath = path.join(__dirname + '/sqls/20160614083536-review-model-up.sql'); 8 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 9 | if (err) return callback(err); 10 | console.log('received data: ' + data); 11 | 12 | db.runSql(data, function(err) { 13 | if (err) return callback(err); 14 | callback(); 15 | }); 16 | }); 17 | }; 18 | 19 | exports.down = function(db, callback) { 20 | var filePath = path.join(__dirname + '/sqls/20160614083536-review-model-down.sql'); 21 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 22 | if (err) return callback(err); 23 | console.log('received data: ' + data); 24 | 25 | db.runSql(data, function(err) { 26 | if (err) return callback(err); 27 | callback(); 28 | }); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /migrations/20160621104843-task-views.js: -------------------------------------------------------------------------------- 1 | var dbm = global.dbm || require('db-migrate'); 2 | var type = dbm.dataType; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | exports.up = function(db, callback) { 7 | var filePath = path.join(__dirname + '/sqls/20160621104843-task-views-up.sql'); 8 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 9 | if (err) return callback(err); 10 | console.log('received data: ' + data); 11 | 12 | db.runSql(data, function(err) { 13 | if (err) return callback(err); 14 | callback(); 15 | }); 16 | }); 17 | }; 18 | 19 | exports.down = function(db, callback) { 20 | var filePath = path.join(__dirname + '/sqls/20160621104843-task-views-down.sql'); 21 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 22 | if (err) return callback(err); 23 | console.log('received data: ' + data); 24 | 25 | db.runSql(data, function(err) { 26 | if (err) return callback(err); 27 | callback(); 28 | }); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /migrations/20160624081405-download-statistics.js: -------------------------------------------------------------------------------- 1 | var dbm = global.dbm || require('db-migrate'); 2 | var type = dbm.dataType; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | exports.up = function(db, callback) { 7 | var filePath = path.join(__dirname + '/sqls/20160624081405-download-statistics-up.sql'); 8 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 9 | if (err) return callback(err); 10 | console.log('received data: ' + data); 11 | 12 | db.runSql(data, function(err) { 13 | if (err) return callback(err); 14 | callback(); 15 | }); 16 | }); 17 | }; 18 | 19 | exports.down = function(db, callback) { 20 | var filePath = path.join(__dirname + '/sqls/20160624081405-download-statistics-down.sql'); 21 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 22 | if (err) return callback(err); 23 | console.log('received data: ' + data); 24 | 25 | db.runSql(data, function(err) { 26 | if (err) return callback(err); 27 | callback(); 28 | }); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /migrations/20160626120528-token-table.js: -------------------------------------------------------------------------------- 1 | var dbm = global.dbm || require('db-migrate'); 2 | var type = dbm.dataType; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | exports.up = function(db, callback) { 7 | var filePath = path.join(__dirname + '/sqls/20160626120528-token-table-up.sql'); 8 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 9 | if (err) return callback(err); 10 | console.log('received data: ' + data); 11 | 12 | db.runSql(data, function(err) { 13 | if (err) return callback(err); 14 | callback(); 15 | }); 16 | }); 17 | }; 18 | 19 | exports.down = function(db, callback) { 20 | var filePath = path.join(__dirname + '/sqls/20160626120528-token-table-down.sql'); 21 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 22 | if (err) return callback(err); 23 | console.log('received data: ' + data); 24 | 25 | db.runSql(data, function(err) { 26 | if (err) return callback(err); 27 | callback(); 28 | }); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /migrations/20160626154713-unique-review.js: -------------------------------------------------------------------------------- 1 | var dbm = global.dbm || require('db-migrate'); 2 | var type = dbm.dataType; 3 | 4 | exports.up = function(db, callback) { 5 | db.addIndex('Reviews', 'review_user', ['reviewable', 'reviewable_id', 'user_id'], true, callback); 6 | }; 7 | 8 | exports.down = function(db, callback) { 9 | callback(); 10 | }; 11 | -------------------------------------------------------------------------------- /migrations/20160708081226-readme-in-versions.js: -------------------------------------------------------------------------------- 1 | var dbm = global.dbm || require('db-migrate'); 2 | var type = dbm.dataType; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | exports.up = function(db, callback) { 7 | var filePath = path.join(__dirname + '/sqls/20160708081226-readme-in-versions-up.sql'); 8 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 9 | if (err) return callback(err); 10 | console.log('received data: ' + data); 11 | 12 | db.runSql(data, function(err) { 13 | if (err) return callback(err); 14 | callback(); 15 | }); 16 | }); 17 | }; 18 | 19 | exports.down = function(db, callback) { 20 | var filePath = path.join(__dirname + '/sqls/20160708081226-readme-in-versions-down.sql'); 21 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 22 | if (err) return callback(err); 23 | console.log('received data: ' + data); 24 | 25 | db.runSql(data, function(err) { 26 | if (err) return callback(err); 27 | callback(); 28 | }); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /migrations/20160711142622-splitted-downloads.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var Promise; 9 | 10 | /** 11 | * We receive the dbmigrate dependency from dbmigrate initially. 12 | * This enables us to not have to rely on NODE_PATH. 13 | */ 14 | exports.setup = function(options, seedLink) { 15 | dbm = options.dbmigrate; 16 | type = dbm.dataType; 17 | seed = seedLink; 18 | Promise = options.Promise; 19 | }; 20 | 21 | exports.up = function(db) { 22 | var filePath = path.join(__dirname + '/sqls/20160711142622-splitted-downloads-up.sql'); 23 | return new Promise( function( resolve, reject ) { 24 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 25 | if (err) return reject(err); 26 | console.log('received data: ' + data); 27 | 28 | resolve(data); 29 | }); 30 | }) 31 | .then(function(data) { 32 | return db.runSql(data); 33 | }); 34 | }; 35 | 36 | exports.down = function(db) { 37 | var filePath = path.join(__dirname + '/sqls/20160711142622-splitted-downloads-down.sql'); 38 | return new Promise( function( resolve, reject ) { 39 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 40 | if (err) return reject(err); 41 | console.log('received data: ' + data); 42 | 43 | resolve(data); 44 | }); 45 | }) 46 | .then(function(data) { 47 | return db.runSql(data); 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /migrations/20160714072116-downloads-per-day.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var Promise; 9 | 10 | /** 11 | * We receive the dbmigrate dependency from dbmigrate initially. 12 | * This enables us to not have to rely on NODE_PATH. 13 | */ 14 | exports.setup = function(options, seedLink) { 15 | dbm = options.dbmigrate; 16 | type = dbm.dataType; 17 | seed = seedLink; 18 | Promise = options.Promise; 19 | }; 20 | 21 | exports.up = function(db) { 22 | var filePath = path.join(__dirname + '/sqls/20160714072116-downloads-per-day-up.sql'); 23 | return new Promise( function( resolve, reject ) { 24 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 25 | if (err) return reject(err); 26 | console.log('received data: ' + data); 27 | 28 | resolve(data); 29 | }); 30 | }) 31 | .then(function(data) { 32 | return db.runSql(data); 33 | }); 34 | }; 35 | 36 | exports.down = function(db) { 37 | var filePath = path.join(__dirname + '/sqls/20160714072116-downloads-per-day-down.sql'); 38 | return new Promise( function( resolve, reject ) { 39 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 40 | if (err) return reject(err); 41 | console.log('received data: ' + data); 42 | 43 | resolve(data); 44 | }); 45 | }) 46 | .then(function(data) { 47 | return db.runSql(data); 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /migrations/20160714100838-stringToText.js: -------------------------------------------------------------------------------- 1 | var dbm = global.dbm || require('db-migrate'); 2 | var type = dbm.dataType; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | exports.up = function(db, callback) { 7 | var filePath = path.join(__dirname + '/sqls/20160714100838-stringToText-up.sql'); 8 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 9 | if (err) return callback(err); 10 | console.log('received data: ' + data); 11 | 12 | db.runSql(data, function(err) { 13 | if (err) return callback(err); 14 | callback(); 15 | }); 16 | }); 17 | }; 18 | 19 | exports.down = function(db, callback) { 20 | var filePath = path.join(__dirname + '/sqls/20160714100838-stringToText-down.sql'); 21 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 22 | if (err) return callback(err); 23 | console.log('received data: ' + data); 24 | 25 | db.runSql(data, function(err) { 26 | if (err) return callback(err); 27 | callback(); 28 | }); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /migrations/20160714102013-add-dependency-enum.js: -------------------------------------------------------------------------------- 1 | var dbm = global.dbm || require('db-migrate'); 2 | var type = dbm.dataType; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | exports.up = function(db, callback) { 7 | var filePath = path.join(__dirname + '/sqls/20160714102013-add-dependency-enum-up.sql'); 8 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 9 | if (err) return callback(err); 10 | console.log('received data: ' + data); 11 | 12 | db.runSql(data, function(err) { 13 | if (err) return callback(err); 14 | callback(); 15 | }); 16 | }); 17 | }; 18 | 19 | exports.down = function(db, callback) { 20 | var filePath = path.join(__dirname + '/sqls/20160714102013-add-dependency-enum-down.sql'); 21 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 22 | if (err) return callback(err); 23 | console.log('received data: ' + data); 24 | 25 | db.runSql(data, function(err) { 26 | if (err) return callback(err); 27 | callback(); 28 | }); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /migrations/20160714113658-cascading-delete-of-sections.js: -------------------------------------------------------------------------------- 1 | var dbm = global.dbm || require('db-migrate'); 2 | var type = dbm.dataType; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | exports.up = function(db, callback) { 7 | var filePath = path.join(__dirname + '/sqls/20160714113658-cascading-delete-of-sections-up.sql'); 8 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 9 | if (err) return callback(err); 10 | console.log('received data: ' + data); 11 | 12 | db.runSql(data, function(err) { 13 | if (err) return callback(err); 14 | callback(); 15 | }); 16 | }); 17 | }; 18 | 19 | exports.down = function(db, callback) { 20 | var filePath = path.join(__dirname + '/sqls/20160714113658-cascading-delete-of-sections-down.sql'); 21 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 22 | if (err) return callback(err); 23 | console.log('received data: ' + data); 24 | 25 | db.runSql(data, function(err) { 26 | if (err) return callback(err); 27 | callback(); 28 | }); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /migrations/20160812141926-BiocDownloads.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var Promise; 9 | 10 | /** 11 | * We receive the dbmigrate dependency from dbmigrate initially. 12 | * This enables us to not have to rely on NODE_PATH. 13 | */ 14 | exports.setup = function(options, seedLink) { 15 | dbm = options.dbmigrate; 16 | type = dbm.dataType; 17 | seed = seedLink; 18 | Promise = options.Promise; 19 | }; 20 | 21 | exports.up = function(db) { 22 | var filePath = path.join(__dirname + '/sqls/20160812141926-BiocDownloads-up.sql'); 23 | return new Promise( function( resolve, reject ) { 24 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 25 | if (err) return reject(err); 26 | console.log('received data: ' + data); 27 | 28 | resolve(data); 29 | }); 30 | }) 31 | .then(function(data) { 32 | return db.runSql(data); 33 | }); 34 | }; 35 | 36 | exports.down = function(db) { 37 | var filePath = path.join(__dirname + '/sqls/20160812141926-BiocDownloads-down.sql'); 38 | return new Promise( function( resolve, reject ) { 39 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 40 | if (err) return reject(err); 41 | console.log('received data: ' + data); 42 | 43 | resolve(data); 44 | }); 45 | }) 46 | .then(function(data) { 47 | return db.runSql(data); 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /migrations/20160821202039-stars.js: -------------------------------------------------------------------------------- 1 | var dbm = global.dbm || require('db-migrate'); 2 | var type = dbm.dataType; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | exports.up = function(db, callback) { 7 | var filePath = path.join(__dirname + '/sqls/20160821202039-stars-up.sql'); 8 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 9 | if (err) return callback(err); 10 | console.log('received data: ' + data); 11 | 12 | db.runSql(data, function(err) { 13 | if (err) return callback(err); 14 | callback(); 15 | }); 16 | }); 17 | }; 18 | 19 | exports.down = function(db, callback) { 20 | var filePath = path.join(__dirname + '/sqls/20160821202039-stars-down.sql'); 21 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 22 | if (err) return callback(err); 23 | console.log('received data: ' + data); 24 | 25 | db.runSql(data, function(err) { 26 | if (err) return callback(err); 27 | callback(); 28 | }); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /migrations/20160822080118-examples.js: -------------------------------------------------------------------------------- 1 | var dbm = global.dbm || require('db-migrate'); 2 | var type = dbm.dataType; 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | exports.up = function(db, callback) { 7 | var filePath = path.join(__dirname + '/sqls/20160822080118-examples-up.sql'); 8 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 9 | if (err) return callback(err); 10 | console.log('received data: ' + data); 11 | 12 | db.runSql(data, function(err) { 13 | if (err) return callback(err); 14 | callback(); 15 | }); 16 | }); 17 | }; 18 | 19 | exports.down = function(db, callback) { 20 | var filePath = path.join(__dirname + '/sqls/20160822080118-examples-down.sql'); 21 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 22 | if (err) return callback(err); 23 | console.log('received data: ' + data); 24 | 25 | db.runSql(data, function(err) { 26 | if (err) return callback(err); 27 | callback(); 28 | }); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /migrations/20160830084534-percentiles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var Promise; 9 | 10 | /** 11 | * We receive the dbmigrate dependency from dbmigrate initially. 12 | * This enables us to not have to rely on NODE_PATH. 13 | */ 14 | exports.setup = function(options, seedLink) { 15 | dbm = options.dbmigrate; 16 | type = dbm.dataType; 17 | seed = seedLink; 18 | Promise = options.Promise; 19 | }; 20 | 21 | exports.up = function(db) { 22 | var filePath = path.join(__dirname + '/sqls/20160830084534-percentiles-up.sql'); 23 | return new Promise( function( resolve, reject ) { 24 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 25 | if (err) return reject(err); 26 | console.log('received data: ' + data); 27 | 28 | resolve(data); 29 | }); 30 | }) 31 | .then(function(data) { 32 | return db.runSql(data); 33 | }); 34 | }; 35 | 36 | exports.down = function(db) { 37 | var filePath = path.join(__dirname + '/sqls/20160830084534-percentiles-down.sql'); 38 | return new Promise( function( resolve, reject ) { 39 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 40 | if (err) return reject(err); 41 | console.log('received data: ' + data); 42 | 43 | resolve(data); 44 | }); 45 | }) 46 | .then(function(data) { 47 | return db.runSql(data); 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /migrations/20170809033252-parser-version.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var Promise; 9 | 10 | /** 11 | * We receive the dbmigrate dependency from dbmigrate initially. 12 | * This enables us to not have to rely on NODE_PATH. 13 | */ 14 | exports.setup = function(options, seedLink) { 15 | dbm = options.dbmigrate; 16 | type = dbm.dataType; 17 | seed = seedLink; 18 | Promise = options.Promise; 19 | }; 20 | 21 | exports.up = function(db) { 22 | var filePath = path.join(__dirname, 'sqls', '20170809033252-parser-version-up.sql'); 23 | return new Promise( function( resolve, reject ) { 24 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 25 | if (err) return reject(err); 26 | console.log('received data: ' + data); 27 | 28 | resolve(data); 29 | }); 30 | }) 31 | .then(function(data) { 32 | return db.runSql(data); 33 | }); 34 | }; 35 | 36 | exports.down = function(db) { 37 | var filePath = path.join(__dirname, 'sqls', '20170809033252-parser-version-down.sql'); 38 | return new Promise( function( resolve, reject ) { 39 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 40 | if (err) return reject(err); 41 | console.log('received data: ' + data); 42 | 43 | resolve(data); 44 | }); 45 | }) 46 | .then(function(data) { 47 | return db.runSql(data); 48 | }); 49 | }; 50 | 51 | exports._meta = { 52 | "version": 1 53 | }; 54 | -------------------------------------------------------------------------------- /migrations/20170809222533-parsing-jobs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dbm; 4 | var type; 5 | var seed; 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var Promise; 9 | 10 | /** 11 | * We receive the dbmigrate dependency from dbmigrate initially. 12 | * This enables us to not have to rely on NODE_PATH. 13 | */ 14 | exports.setup = function(options, seedLink) { 15 | dbm = options.dbmigrate; 16 | type = dbm.dataType; 17 | seed = seedLink; 18 | Promise = options.Promise; 19 | }; 20 | 21 | exports.up = function(db) { 22 | var filePath = path.join(__dirname, 'sqls', '20170809222533-parsing-jobs-up.sql'); 23 | return new Promise( function( resolve, reject ) { 24 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 25 | if (err) return reject(err); 26 | console.log('received data: ' + data); 27 | 28 | resolve(data); 29 | }); 30 | }) 31 | .then(function(data) { 32 | return db.runSql(data); 33 | }); 34 | }; 35 | 36 | exports.down = function(db) { 37 | var filePath = path.join(__dirname, 'sqls', '20170809222533-parsing-jobs-down.sql'); 38 | return new Promise( function( resolve, reject ) { 39 | fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){ 40 | if (err) return reject(err); 41 | console.log('received data: ' + data); 42 | 43 | resolve(data); 44 | }); 45 | }) 46 | .then(function(data) { 47 | return db.runSql(data); 48 | }); 49 | }; 50 | 51 | exports._meta = { 52 | "version": 1 53 | }; 54 | -------------------------------------------------------------------------------- /migrations/sqls/20160603105133-migration-name-down.sql: -------------------------------------------------------------------------------- 1 | # ************************************************************ 2 | # Sequel Pro SQL dump 3 | # Version 4541 4 | # 5 | # http://www.sequelpro.com/ 6 | # https://github.com/sequelpro/sequelpro 7 | # 8 | # Host: 192.168.99.100 (MySQL 5.7.12) 9 | # Database: rdoc 10 | # Generation Time: 2016-06-03 16:54:29 +0000 11 | # ************************************************************ 12 | 13 | 14 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 15 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 16 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 17 | /*!40101 SET NAMES utf8 */; 18 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 19 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 20 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 21 | 22 | 23 | # Dump of table Aliases 24 | # ------------------------------------------------------------ 25 | 26 | DROP TABLE IF EXISTS `Aliases`; 27 | 28 | DROP TABLE IF EXISTS `Arguments`; 29 | 30 | DROP TABLE IF EXISTS `Collaborations`; 31 | 32 | DROP TABLE IF EXISTS `Collaborators`; 33 | 34 | DROP TABLE IF EXISTS `Dependencies`; 35 | 36 | DROP TABLE IF EXISTS `Packages`; 37 | 38 | DROP TABLE IF EXISTS `PackageVersions`; 39 | 40 | DROP TABLE IF EXISTS `Sections`; 41 | 42 | DROP TABLE IF EXISTS `Tags`; 43 | 44 | DROP TABLE IF EXISTS `Topics`; 45 | 46 | DROP TABLE IF EXISTS `TopicTags`; 47 | 48 | 49 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 50 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 51 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 52 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 53 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 54 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 55 | -------------------------------------------------------------------------------- /migrations/sqls/20160609193515-title-allow-null-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160609193515-title-allow-null-up.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `PackageVersions` MODIFY `title` varchar(255) DEFAULT NULL; 2 | -------------------------------------------------------------------------------- /migrations/sqls/20160610094821-argument-description-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160610094821-argument-description-up.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `Arguments` MODIFY `description` TEXT DEFAULT NULL; 2 | -------------------------------------------------------------------------------- /migrations/sqls/20160612150901-package-type-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160612150901-package-type-up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `Repositories` ( 2 | `id` int(11) NOT NULL AUTO_INCREMENT, 3 | `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 6 | 7 | INSERT INTO Repositories (name) VALUES ('cran'),('bioconductor'),('github'); 8 | 9 | ALTER TABLE `Packages` ADD COLUMN `type_id` int(11) NOT NULL; 10 | 11 | UPDATE `Packages` SET `type_id` = (SELECT id from `Repositories` Where `name` = 'cran'); 12 | 13 | ALTER TABLE `Packages` ADD CONSTRAINT fk_type_id FOREIGN KEY (type_id) REFERENCES Repositories(id); 14 | -------------------------------------------------------------------------------- /migrations/sqls/20160612161712-package-type-allow-null-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160612161712-package-type-allow-null-up.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `PackageVersions` ADD COLUMN `sourceJSON` TEXT DEFAULT NULL; 2 | 3 | ALTER TABLE `Packages` MODIFY `type_id` int(11) DEFAULT NULL; 4 | -------------------------------------------------------------------------------- /migrations/sqls/20160612162625-topic-add-sourceJSON-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160612162625-topic-add-sourceJSON-up.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `Topics` ADD COLUMN `sourceJSON` TEXT DEFAULT NULL; 2 | -------------------------------------------------------------------------------- /migrations/sqls/20160613085210-comments-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160613085210-comments-up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `Comments` ( 2 | `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 | `description` TEXT COLLATE utf8_unicode_ci NOT NULL, 4 | `commentable` varchar(255) NOT NULL, 5 | `commentable_id` int(11) NOT NULL, 6 | `created_at` datetime NOT NULL, 7 | `updated_at` datetime NOT NULL, 8 | `user_id` int(11) NOT NULL REFERENCES Users(id) ON DELETE CASCADE ON UPDATE CASCADE 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 10 | -------------------------------------------------------------------------------- /migrations/sqls/20160614083536-review-model-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160614083536-review-model-up.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `Comments`; 2 | 3 | CREATE TABLE `Reviews` ( 4 | `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 5 | `rating` TINYINT NOT NULL, 6 | `title` varchar(255) DEFAULT NULL, 7 | `text` TEXT COLLATE utf8_unicode_ci DEFAULT NULL, 8 | `reviewable` varchar(255) NOT NULL, 9 | `reviewable_id` int(11) NOT NULL, 10 | `created_at` datetime NOT NULL, 11 | `updated_at` datetime NOT NULL, 12 | `user_id` int(11) NOT NULL REFERENCES Users(id) ON DELETE CASCADE ON UPDATE CASCADE 13 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 14 | -------------------------------------------------------------------------------- /migrations/sqls/20160621104843-task-views-down.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/migrations/sqls/20160621104843-task-views-down.sql -------------------------------------------------------------------------------- /migrations/sqls/20160621104843-task-views-up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `TaskViews` ( 2 | `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 | `name` varchar(255) NOT NULL, 4 | `url` varchar(255) NOT NULL, 5 | `created_at` datetime NOT NULL, 6 | `updated_at` datetime NOT NULL, 7 | UNIQUE KEY `task_name_unique` (`name`) 8 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 9 | 10 | CREATE TABLE `TaskViewPackages` ( 11 | `task_id` int(11) NOT NULL, 12 | `package_name` varchar(255) NOT NULL, 13 | PRIMARY KEY (`task_id`,`package_name`), 14 | CONSTRAINT `TaskViews_ibfk_1` FOREIGN KEY (`task_id`) REFERENCES `TaskViews` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 15 | CONSTRAINT `TaskViewPackages_ibfk_1` FOREIGN KEY (`package_name`) REFERENCES `Packages` (`name`) ON DELETE CASCADE ON UPDATE CASCADE 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 17 | -------------------------------------------------------------------------------- /migrations/sqls/20160624081405-download-statistics-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160624081405-download-statistics-up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `DownloadStatistics` ( 2 | `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 | `package_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 4 | `last_month_downloads` int(11) NOT NULL, 5 | `created_at` datetime NOT NULL, 6 | `updated_at` datetime NOT NULL, 7 | UNIQUE KEY `package` (`package_name`), 8 | FOREIGN KEY (`package_name`) REFERENCES `Packages` (`name`) ON DELETE CASCADE ON UPDATE CASCADE 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 10 | -------------------------------------------------------------------------------- /migrations/sqls/20160626120528-token-table-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160626120528-token-table-up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `ApiTokens` ( 2 | `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 | `token` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 4 | `can_create` BOOL NOT NULL DEFAULT 0, 5 | `can_update` BOOL NOT NULL DEFAULT 0, 6 | `can_delete` BOOL NOT NULL DEFAULT 0, 7 | `expire_at` datetime NOT NULL, 8 | UNIQUE KEY `token_unq` (`token`) 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 10 | -------------------------------------------------------------------------------- /migrations/sqls/20160708081226-readme-in-versions-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160708081226-readme-in-versions-up.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ 2 | 3 | ALTER TABLE PackageVersions ADD readmemd TEXT DEFAULT NULL AFTER copyright; 4 | -------------------------------------------------------------------------------- /migrations/sqls/20160711142622-splitted-downloads-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160711142622-splitted-downloads-up.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ 2 | ALTER TABLE DownloadStatistics 3 | ADD (`last_month_downloads_direct` int(11) NOT NULL, 4 | `last_month_downloads_indirect` int(11) NOT NULL); 5 | -------------------------------------------------------------------------------- /migrations/sqls/20160714072116-downloads-per-day-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160714072116-downloads-per-day-up.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ 2 | ALTER TABLE `DownloadStatistics` 3 | DROP `last_month_downloads_direct`, 4 | DROP `last_month_downloads_indirect`, 5 | DROP `last_month_downloads`; 6 | 7 | ALTER TABLE DownloadStatistics 8 | ADD (`direct_downloads` int(11) NOT NULL, 9 | `indirect_downloads` int(11) NOT NULL, 10 | `date` DATE NOT NULL); 11 | 12 | CREATE INDEX package_name_index ON DownloadStatistics(package_name); 13 | CREATE UNIQUE INDEX package_month ON DownloadStatistics(package_name,date); 14 | ALTER TABLE DownloadStatistics DROP INDEX package; 15 | -------------------------------------------------------------------------------- /migrations/sqls/20160714100838-stringToText-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160714100838-stringToText-up.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ 2 | 3 | ALTER TABLE `PackageVersions` MODIFY `license` TEXT DEFAULT NULL; 4 | ALTER TABLE `PackageVersions` MODIFY `title` TEXT DEFAULT NULL; 5 | ALTER TABLE `PackageVersions` MODIFY `copyright` TEXT DEFAULT NULL; 6 | -------------------------------------------------------------------------------- /migrations/sqls/20160714102013-add-dependency-enum-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160714102013-add-dependency-enum-up.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ 2 | 3 | ALTER TABLE Dependencies CHANGE type type ENUM('depends','imports','suggests','enhances', 'linkingto'); 4 | -------------------------------------------------------------------------------- /migrations/sqls/20160714113658-cascading-delete-of-sections-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160714113658-cascading-delete-of-sections-up.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ 2 | 3 | ALTER TABLE Aliases DROP FOREIGN KEY `Aliases_ibfk_1`; 4 | 5 | ALTER TABLE Aliases ADD CONSTRAINT `Aliases_ibfk_1` FOREIGN KEY (`topic_id`) 6 | REFERENCES `Topics` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; 7 | 8 | ALTER TABLE Arguments DROP FOREIGN KEY `Arguments_ibfk_1`; 9 | 10 | ALTER TABLE Arguments ADD CONSTRAINT `Arguments_ibfk_1` FOREIGN KEY (`topic_id`) 11 | REFERENCES `Topics` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; 12 | 13 | ALTER TABLE Sections DROP FOREIGN KEY `Sections_ibfk_1`; 14 | 15 | ALTER TABLE Sections ADD CONSTRAINT `Sections_ibfk_1` FOREIGN KEY (`topic_id`) 16 | REFERENCES `Topics` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; 17 | 18 | DELETE FROM Aliases WHERE topic_id IS NULL; 19 | DELETE FROM Arguments WHERE topic_id IS NULL; 20 | DELETE FROM Sections WHERE topic_id IS NULL; 21 | -------------------------------------------------------------------------------- /migrations/sqls/20160812141926-BiocDownloads-down.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/rdocumentation-app/3642111a3bfcae6c934e8aca4889c005ca90167d/migrations/sqls/20160812141926-BiocDownloads-down.sql -------------------------------------------------------------------------------- /migrations/sqls/20160812141926-BiocDownloads-up.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ 2 | -- 3 | -- Table structure for table `BiocDownloadStatistics` 4 | -- 5 | 6 | DROP TABLE IF EXISTS `BiocDownloadStatistics`; 7 | /*!40101 SET @saved_cs_client = @@character_set_client */; 8 | /*!40101 SET character_set_client = utf8 */; 9 | CREATE TABLE `BiocDownloadStatistics` ( 10 | `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 11 | `package_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 12 | `distinct_ips` int(11) NOT NULL, 13 | `downloads` int(11) NOT NULL, 14 | `created_at` datetime NOT NULL, 15 | `updated_at` datetime NOT NULL, 16 | `date` DATE NOT NULL, 17 | FOREIGN KEY (`package_name`) REFERENCES `Packages` (`name`) ON DELETE CASCADE ON UPDATE CASCADE 18 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 19 | 20 | CREATE UNIQUE INDEX bioc_package_month ON BiocDownloadStatistics(package_name,date); 21 | -------------------------------------------------------------------------------- /migrations/sqls/20160821202039-stars-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160821202039-stars-up.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ 2 | -- 3 | -- Table structure for table `BiocDownloadStatistics` 4 | -- 5 | 6 | DROP TABLE IF EXISTS `Stars`; 7 | /*!40101 SET @saved_cs_client = @@character_set_client */; 8 | /*!40101 SET character_set_client = utf8 */; 9 | CREATE TABLE `Stars` ( 10 | `user_id` int(11) NOT NULL, 11 | `package_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 12 | `created_at` datetime NOT NULL, 13 | `updated_at` datetime NOT NULL, 14 | FOREIGN KEY (`package_name`) REFERENCES `Packages` (`name`) ON DELETE CASCADE ON UPDATE CASCADE, 15 | FOREIGN KEY (`user_id`) REFERENCES `Users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 16 | PRIMARY KEY (`user_id`,`package_name`) 17 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 18 | -------------------------------------------------------------------------------- /migrations/sqls/20160822080118-examples-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160822080118-examples-up.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ 2 | -- 3 | -- Table structure for table `BiocDownloadStatistics` 4 | -- 5 | 6 | DROP TABLE IF EXISTS `Examples`; 7 | /*!40101 SET @saved_cs_client = @@character_set_client */; 8 | /*!40101 SET character_set_client = utf8 */; 9 | CREATE TABLE `Examples` ( 10 | `id` int(11) NOT NULL AUTO_INCREMENT, 11 | `user_id` int(11) NOT NULL, 12 | `topic_id` int(11) NOT NULL, 13 | `example` text NOT NULL COLLATE utf8_unicode_ci, 14 | `created_at` datetime NOT NULL, 15 | `updated_at` datetime NOT NULL, 16 | FOREIGN KEY (`topic_id`) REFERENCES `Topics` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 17 | FOREIGN KEY (`user_id`) REFERENCES `Users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 18 | PRIMARY KEY (`id`) 19 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 20 | -------------------------------------------------------------------------------- /migrations/sqls/20160830084534-percentiles-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20160830084534-percentiles-up.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `Percentiles`; 2 | 3 | CREATE TABLE `Percentiles` ( 4 | `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 5 | `percentile` double(5,2) NOT NULL, 6 | `value` int(11) NOT NULL, 7 | `created_at` datetime NOT NULL, 8 | `updated_at` datetime NOT NULL, 9 | UNIQUE (percentile) 10 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -------------------------------------------------------------------------------- /migrations/sqls/20170809033252-parser-version-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20170809033252-parser-version-up.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ 2 | ALTER TABLE `PackageVersions` ADD COLUMN `parser_version` int(11) DEFAULT 0; 3 | -------------------------------------------------------------------------------- /migrations/sqls/20170809222533-parsing-jobs-down.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ -------------------------------------------------------------------------------- /migrations/sqls/20170809222533-parsing-jobs-up.sql: -------------------------------------------------------------------------------- 1 | /* Replace with your SQL commands */ 2 | ALTER TABLE `PackageVersions` DROP COLUMN `parser_version`; 3 | 4 | CREATE TABLE `ParsingJobs` ( 5 | `package_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 6 | `package_version` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 7 | `parser_version` int(11) DEFAULT 0, 8 | `parsed_at` datetime NOT NULL, 9 | `parsing_status` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 10 | `error` text COLLATE utf8_unicode_ci DEFAULT NULL, 11 | PRIMARY KEY(`package_name`, `package_version`) 12 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 13 | 14 | INSERT INTO `ParsingJobs` (`package_name`, `package_version`, `parsed_at`, `parsing_status`) 15 | SELECT `package_name`, `version`, NOW(), "succes" 16 | FROM `PackageVersions` 17 | -------------------------------------------------------------------------------- /newrelic.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | app_name: [process.env.NEW_RELIC_APP], 3 | license_key: 'e6cd6d8afacfcc7191c34c933af26309dfa57cc6', 4 | logging: { 5 | level: 'warn', // can be error, warn, info, debug or trace 6 | rules: { 7 | ignore: ['^/socket.io/*/xhr-polling'] 8 | } 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /tasks/config/apidoc.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = function(grunt) { 3 | 4 | grunt.config.set('apidoc',{ 5 | doc: { 6 | src: "api/", 7 | dest: ".tmp/public/docs", 8 | options: { 9 | includeFilters: [ ".*\\.js$" ], 10 | } 11 | } 12 | }); 13 | 14 | grunt.loadNpmTasks('grunt-apidoc'); 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /tasks/config/clean.js: -------------------------------------------------------------------------------- 1 | /** 2 | * `clean` 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * Remove the files and folders in your Sails app's web root 7 | * (conventionally a hidden directory called `.tmp/public`). 8 | * 9 | * For usage docs see: 10 | * https://github.com/gruntjs/grunt-contrib-clean 11 | * 12 | */ 13 | module.exports = function(grunt) { 14 | 15 | grunt.config.set('clean', { 16 | dev: ['.tmp/public/**'], 17 | build: ['www'] 18 | }); 19 | 20 | grunt.loadNpmTasks('grunt-contrib-clean'); 21 | }; 22 | -------------------------------------------------------------------------------- /tasks/config/coffee.js: -------------------------------------------------------------------------------- 1 | /** 2 | * `coffee` 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * Compile CoffeeScript files located in `assets/js` into Javascript 7 | * and generate new `.js` files in `.tmp/public/js`. 8 | * 9 | * For usage docs see: 10 | * https://github.com/gruntjs/grunt-contrib-coffee 11 | * 12 | */ 13 | module.exports = function(grunt) { 14 | 15 | grunt.config.set('coffee', { 16 | dev: { 17 | options: { 18 | bare: true, 19 | sourceMap: true, 20 | sourceRoot: './' 21 | }, 22 | files: [{ 23 | expand: true, 24 | cwd: 'assets/js/', 25 | src: ['**/*.coffee'], 26 | dest: '.tmp/public/js/', 27 | ext: '.js' 28 | }] 29 | } 30 | }); 31 | 32 | grunt.loadNpmTasks('grunt-contrib-coffee'); 33 | }; 34 | -------------------------------------------------------------------------------- /tasks/config/concat.js: -------------------------------------------------------------------------------- 1 | /** 2 | * `concat` 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * Concatenates the contents of multiple JavaScript and/or CSS files 7 | * into two new files, each located at `concat/production.js` and 8 | * `concat/production.css` respectively in `.tmp/public/concat`. 9 | * 10 | * This is used as an intermediate step to generate monolithic files 11 | * that can then be passed in to `uglify` and/or `cssmin` for minification. 12 | * 13 | * For usage docs see: 14 | * https://github.com/gruntjs/grunt-contrib-concat 15 | * 16 | */ 17 | module.exports = function(grunt) { 18 | 19 | grunt.config.set('concat', { 20 | js: { 21 | src: require('../pipeline').jsFilesToInject, 22 | dest: '.tmp/public/concat/production.js' 23 | }, 24 | css: { 25 | src: require('../pipeline').cssFilesToInject, 26 | dest: '.tmp/public/concat/production.css' 27 | } 28 | }); 29 | 30 | grunt.loadNpmTasks('grunt-contrib-concat'); 31 | }; 32 | -------------------------------------------------------------------------------- /tasks/config/copy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * `copy` 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * Copy files and/or folders from your `assets/` directory into 7 | * the web root (`.tmp/public`) so they can be served via HTTP, 8 | * and also for further pre-processing by other Grunt tasks. 9 | * 10 | * #### Normal usage (`sails lift`) 11 | * Copies all directories and files (except CoffeeScript and LESS) 12 | * from the `assets/` folder into the web root -- conventionally a 13 | * hidden directory located `.tmp/public`. 14 | * 15 | * #### Via the `build` tasklist (`sails www`) 16 | * Copies all directories and files from the .tmp/public directory into a www directory. 17 | * 18 | * For usage docs see: 19 | * https://github.com/gruntjs/grunt-contrib-copy 20 | * 21 | */ 22 | module.exports = function(grunt) { 23 | 24 | grunt.config.set('copy', { 25 | dev: { 26 | files: [{ 27 | expand: true, 28 | cwd: './assets', 29 | src: ['**/*.!(coffee|scss)'], 30 | dest: '.tmp/public' 31 | } 32 | ] 33 | }, 34 | build: { 35 | files: [{ 36 | expand: true, 37 | cwd: '.tmp/public', 38 | src: ['**/*'], 39 | dest: 'www' 40 | }] 41 | } 42 | }); 43 | 44 | grunt.loadNpmTasks('grunt-contrib-copy'); 45 | }; 46 | -------------------------------------------------------------------------------- /tasks/config/cssmin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Compress CSS files. 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * Minify the intermediate concatenated CSS stylesheet which was 7 | * prepared by the `concat` task at `.tmp/public/concat/production.css`. 8 | * 9 | * Together with the `concat` task, this is the final step that minifies 10 | * all CSS files from `assets/styles/` (and potentially your LESS importer 11 | * file from `assets/styles/importer.less`) 12 | * 13 | * For usage docs see: 14 | * https://github.com/gruntjs/grunt-contrib-cssmin 15 | * 16 | */ 17 | module.exports = function(grunt) { 18 | 19 | grunt.config.set('cssmin', { 20 | dist: { 21 | src: ['.tmp/public/concat/production.css'], 22 | dest: '.tmp/public/min/production.min.css' 23 | } 24 | }); 25 | 26 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 27 | }; 28 | -------------------------------------------------------------------------------- /tasks/config/jst.js: -------------------------------------------------------------------------------- 1 | /** 2 | * `jst` 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * Precompile HTML templates using Underscore/Lodash notation into 7 | * functions, creating a `.jst` file. This can be brought into your HTML 8 | * via a 49 | 50 | -------------------------------------------------------------------------------- /views/task_view/_sidebar.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Task View

4 |
5 |
6 | <% for(var i = 0; i 7 | <%- data[i].name %> 8 | <% } %> 9 |
10 | 11 |
12 | -------------------------------------------------------------------------------- /views/task_view/index.ejs: -------------------------------------------------------------------------------- 1 |
2 | <%- include ../task_view/_sidebar.ejs %> 3 |
4 |
5 | -------------------------------------------------------------------------------- /views/task_view/show.ejs: -------------------------------------------------------------------------------- 1 | <% var view = data; %> 2 |
3 |
4 |
5 |

<%- view.name %>

6 | More info on CRAN 7 |
8 |
9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | <% for(var i = 0; i < view.packages.length; i++) { %> 22 | <% var package = view.packages[i]; %> 23 | 24 | 25 | 26 | 31 | 36 | 37 | <% } %> 38 | 39 | 40 |
Name Description Percentile Stars
<%= package.name %> <%= package.latest_version ? package.latest_version.title : package.name %> 27 | 28 | 0th 29 | 30 | 32 |
33 | <%= package.stars.length %> 34 |
35 |
No Results!
41 |
42 |
43 | -------------------------------------------------------------------------------- /views/topic/_header.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |

<%- topic.name %>

7 |
8 |
9 |
10 |
11 | From <%- topic.package_version.package_name %> v<%- topic.package_version.version %> 12 | <% if(topic.package_version.maintainer) { %> 13 | by <%- topic.package_version.maintainer.name %> 14 | <% } %> 15 |
16 |
17 | <% var percentilePath = "/api/packages/"+topic.package_version.package_name+"/percentile" %> 18 | <%- include ../shared/_percentile.ejs %> 19 |
20 |
21 |
22 |
23 |
24 |
25 | -------------------------------------------------------------------------------- /views/user/show.ejs: -------------------------------------------------------------------------------- 1 | <% var user = data; %> 2 | <% var user_examples = user.examples; %> 3 |
4 |
5 |
6 |

<%- user.username %>

7 |
8 | 9 |
10 |

My Examples

11 |
12 | <% if(user_examples.length === 0) { %> 13 |
Looks like there are no examples yet.
14 | <% } %> 15 | <% for(var i=0; i < user_examples.length; i++) { %> 16 | <% var exampleUser = null; %> 17 | <% var exampleTarget = (user_examples[i].topic); %> 18 | <%- include ../shared/_example.ejs %> 19 | <% } %> 20 |
21 |
22 | 23 |
24 |
25 | --------------------------------------------------------------------------------