diff --git a/src/pyDataVizDay.py b/src/pyDataVizDay.py index 5ff4139..d6a80aa 100644 --- a/src/pyDataVizDay.py +++ b/src/pyDataVizDay.py @@ -141,13 +141,22 @@ class score_timeseries(Resource): .rename(columns={'imdb_score': 'IMDB Score'}) ) df['DATE'] = df.index + df['DATE'] = df['DATE'].astype('str').fillna('1900-01-01') print(df.head()) score_timeseries = {'columns':[['IMDB Score'] + df['IMDB Score'].values.tolist(), ['gross'] + df['gross'].values.tolist(), - ['x'] + df.index.values.tolist()]} + ['x'] + df.DATE.astype(str).values.tolist()], + # ['x'] + df.index.values.tolist()], + 'colors':{ + 'IMDB Score': '#6998A6', + 'gross': '#966001', + 'x': '#08414C' + }} return jsonify(score_timeseries) if __name__ == '__main__': + app.jinja_env.auto_reload = True + app.config['TEMPLATES_AUTO_RELOAD'] = True port = int(os.environ.get("PORT", 5000)) app.run(host='0.0.0.0', port=port, debug=True) \ No newline at end of file diff --git a/src/static/css/custom.css b/src/static/css/custom.css index 7a53a02..79a8538 100644 --- a/src/static/css/custom.css +++ b/src/static/css/custom.css @@ -36,3 +36,11 @@ body{ max-width: 300px; } +.container{ + float:center; +} + +.centered{ + float: none; + margin: 0 auto; +} \ No newline at end of file diff --git a/src/static/js/enthusiast.js b/src/static/js/enthusiast.js index 4d2cbda..84e7094 100644 --- a/src/static/js/enthusiast.js +++ b/src/static/js/enthusiast.js @@ -1,4 +1,5 @@ var score_timeseries = document.getElementById('timeseries'); +var mil = d3.format('$.3s') var data = { 'size': { 'height': 300 @@ -44,6 +45,7 @@ var data = { 'axis': { 'rotated': false, 'x': { + 'type': 'timeseries', 'tick': { 'count': 10, 'values': false, @@ -61,12 +63,46 @@ var data = { 'show': true } }, - 'zoom': {} + 'zoom': {'enabled': true}, + 'tooltip': { + 'contents': function (data) + { + var date = Date(data[0]['x']) + var year = data[0]['x'].getYear()+1900 + var score = data[0].value + var gross = mil(data[1].value) + $('#year').html(year) + $('#score').html(score) + $('#gross').html(gross) + update_words_year(year) + t = data + } + } }; + +word_coud_settings = { + width: 500, + height: 350, + classPattern: null, + colors: ['#bd0026', '#e31a1c', '#800026', '#fc4e2a', '#fd8d3c', '#feb24c', '#fed976'],// '#ffeda0', '#ffffcc'], + fontSize: { + from: 0.1, + to: 0.02 + } + } + + data['axis']['y']['tick']['format'] = d3.format('$.3s') data['axis']['y2']['tick']['format'] = d3.format('.3s') data['bindto']='#timeseries-chart' +var _top = $('#top') +var language = $('#language') +var country = $('#country') +var genre = $('#genre') +var start_year = $('#start_year') +var end_year = $('#end_year') + $('#top').change(function(){update_all()}) $('#language').change(function(){update_all()}) @@ -78,6 +114,7 @@ $('#end_year').change(function(){update_all()}) jQuery(document).ready(function(){ jQuery(".chosen").chosen(); score_timeseries = c3.generate(data); + $('#word_cloud').jQCloud([{'text':'pyDataVizDay', 'weight':1}], word_coud_settings) update_all() }); @@ -87,61 +124,60 @@ function update_all(){ update_ts() } -function update_ts(){ - var _top = $('#top').val() - var language = $('#language').val() - var country = $('#country').val() - var genre = $('#genre').val() - var start_year = $('#start_year').val() - var end_year = $('#end_year').val() - - url = '/api/score_timeseries?' - - if (_top.length>0){url = url + 'top=' + _top + '&'} - if (language.length>0){url = url + 'language=' + language + '&'} - if (country.length>0){url = url + 'country=' + country + '&'} - if (genre.length>0){url = url + 'genre=' + genre + '&'} - if (start_year.length>0){url = url + 'start_year=' + start_year + '&'} - if (end_year.length>0){url = url + 'end_year=' + end_year + '&'} +function url_params(base) +{ + var url = base + if (_top.val().length>0){url = url + 'top=' + _top.val() + '&'} + if (language.val().length>0){url = url + 'language=' + language.val() + '&'} + if (country.val().length>0){url = url + 'country=' + country.val() + '&'} + if (genre.val().length>0){url = url + 'genre=' + genre.val() + '&'} + if (start_year.val().length>0){url = url + 'start_year=' + start_year.val() + '&'} + if (end_year.val().length>0){url = url + 'end_year=' + end_year.val() + '&'} + + return url +} +function update_ts() +{ + url = url_params('/api/score_timeseries?') + score_timeseries.unload() var updatedData = $.get(url); - updatedData.done(function(results){ - console.log(updatedData.responseJSON) + updatedData.done(function(results) + { score_timeseries.load(updatedData.responseJSON) }); } -function update_words(){ - var _top = $('#top').val() - var language = $('#language').val() - var country = $('#country').val() - var genre = $('#genre').val() - var start_year = $('#start_year').val() - var end_year = $('#end_year').val() - url = '/api/keywords?' - - if (_top.length>0){url = url + 'top=' + _top + '&'} - if (language.length>0){url = url + 'language=' + language + '&'} - if (country.length>0){url = url + 'country=' + country + '&'} - if (genre.length>0){url = url + 'genre=' + genre + '&'} - if (start_year.length>0){url = url + 'start_year=' + start_year + '&'} - if (end_year.length>0){url = url + 'end_year=' + end_year + '&'} +function update_words() +{ + url = url_params('/api/keywords?') var words = $.get(url) - words.done(function(data){ - $('#word_cloud').html('') - $('#word_cloud').jQCloud(words.responseJSON, { - width: 500, - height: 350, - classPattern: null, - colors: ['#800026', '#bd0026', '#e31a1c', '#fc4e2a', '#fd8d3c', '#feb24c', '#fed976', '#ffeda0', '#ffffcc'], - fontSize: { - from: 0.1, - to: 0.02 - } -}); + words.done(function(data) + { + $('#word_cloud').jQCloud('update', words.responseJSON) + }) +} + + + + +function update_words_year(year) +{ + + var url = '/api/keywords?start_year=' + String(parseInt(year) - 1) + '&end_year=' + String(parseInt(year) + 1) + '&' + if (_top.val().length>0){url = url + 'top=' + _top.val() + '&'} + if (language.val().length>0){url = url + 'language=' + language.val() + '&'} + if (country.val().length>0){url = url + 'country=' + country.val() + '&'} + if (genre.val().length>0){url = url + 'genre=' + genre.val() + '&'} + + var words = $.get(url) + words.done(function(data) + { + // $('#word_cloud').html('') + $('#word_cloud').jQCloud('update', words.responseJSON); }) } diff --git a/src/static/node_modules/jqcloud2/.jshintrc b/src/static/node_modules/jqcloud2/.jshintrc new file mode 100644 index 0000000..b6a8229 --- /dev/null +++ b/src/static/node_modules/jqcloud2/.jshintrc @@ -0,0 +1,3 @@ +{ + "-W055": true // non standard constructor name +} \ No newline at end of file diff --git a/src/static/node_modules/jqcloud2/.npmignore b/src/static/node_modules/jqcloud2/.npmignore new file mode 100644 index 0000000..1d357ac --- /dev/null +++ b/src/static/node_modules/jqcloud2/.npmignore @@ -0,0 +1,6 @@ +/.idea +/*.iml +/.sass-cache +/bower_components +/node_modules +/npm-debug.log \ No newline at end of file diff --git a/src/static/node_modules/jqcloud2/.scss-lint.yml b/src/static/node_modules/jqcloud2/.scss-lint.yml new file mode 100644 index 0000000..7822a12 --- /dev/null +++ b/src/static/node_modules/jqcloud2/.scss-lint.yml @@ -0,0 +1,6 @@ +linters: + ColorVariable: + enabled: false + + HexLength: + enabled: false \ No newline at end of file diff --git a/src/static/node_modules/jqcloud2/Gruntfile.js b/src/static/node_modules/jqcloud2/Gruntfile.js new file mode 100644 index 0000000..7566521 --- /dev/null +++ b/src/static/node_modules/jqcloud2/Gruntfile.js @@ -0,0 +1,140 @@ +'use strict'; + +module.exports = function(grunt) { + require('time-grunt')(grunt); + require('jit-grunt')(grunt, { + scsslint: 'grunt-scss-lint' + }); + + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + + banner: '/*!\n' + + ' * jQCloud <%= pkg.version %>\n' + + ' * Copyright 2011 Luca Ongaro (http://www.lucaongaro.eu)\n' + + ' * Copyright 2013 Daniel White (http://www.developerdan.com)\n' + + ' * Copyright 2014-<%= grunt.template.today("yyyy") %> Damien "Mistic" Sorel (http://www.strangeplanet.fr)\n' + + ' * Licensed under MIT (http://opensource.org/licenses/MIT)\n' + + ' */', + + // add UMD + wrap: { + js: { + src: 'src/jqcloud.js', + dest: 'dist/jqcloud.js', + options: { + separator: '', + wrapper: function() { + return grunt.file.read('src/.wrapper.js').replace(/\r\n/g, '\n').split(/@@js\n/); + } + } + } + }, + + // add banner + concat: { + options: { + banner: '<%= banner %>\n', + stripBanners: false + }, + js: { + src: 'dist/jqcloud.js', + dest: 'dist/jqcloud.js' + }, + css: { + src: 'dist/jqcloud.css', + dest: 'dist/jqcloud.css' + } + }, + + // compress js + uglify: { + options: { + banner: '<%= banner %>\n' + }, + dist: { + src: 'dist/jqcloud.js', + dest: 'dist/jqcloud.min.js' + } + }, + + // parse scss + sass: { + options: { + sourcemap: 'none', + style: 'expanded' + }, + dist: { + src: 'src/jqcloud.scss', + dest: 'dist/jqcloud.css' + } + }, + + // compress css + cssmin: { + options: { + banner: '<%= banner %>', + keepSpecialComments: 0 + }, + dist: { + src: 'dist/jqcloud.css', + dest: 'dist/jqcloud.min.css' + } + }, + + // jshint tests + jshint: { + lib: { + options: { + jshintrc: '.jshintrc' + }, + src: 'src/jqcloud.js' + } + }, + + // scss tests + scsslint: { + lib: { + options: { + config: '.scss-lint.yml' + }, + src: 'src/jqcloud.scss' + } + }, + + // qunit test suite + qunit: { + all: { + options: { + urls: ['test/index.html'], + noGlobals: true + } + } + } + }); + + + grunt.registerTask('build_js', [ + 'wrap', + 'concat:js', + 'uglify' + ]); + + grunt.registerTask('build_css', [ + 'sass', + 'concat:css', + 'cssmin' + ]); + + grunt.registerTask('default', [ + 'build_js', + 'build_css' + ]); + + grunt.registerTask('test', [ + 'jshint', + 'scsslint', + 'default', + 'qunit' + ]); +}; \ No newline at end of file diff --git a/src/static/node_modules/jqcloud2/LICENSE.txt b/src/static/node_modules/jqcloud2/LICENSE.txt new file mode 100644 index 0000000..4f2397e --- /dev/null +++ b/src/static/node_modules/jqcloud2/LICENSE.txt @@ -0,0 +1,24 @@ +The MIT License (MIT) + +Copyright (c) 2011 Luca Ongaro +Copyright (c) 2013 Daniel White +Copyright (c) 2014-2016 Damien Sorel + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/static/node_modules/jqcloud2/README.md b/src/static/node_modules/jqcloud2/README.md new file mode 100644 index 0000000..7cc6f87 --- /dev/null +++ b/src/static/node_modules/jqcloud2/README.md @@ -0,0 +1,17 @@ +# jQCloud + +[![Bower version](https://img.shields.io/bower/v/jqcloud2.svg?style=flat-square)](http://mistic100.github.io/jQCloud) +[![NPM version](https://img.shields.io/npm/v/jqcloud2.svg?style=flat-square)](https://www.npmjs.com/package/jqcloud2) + +## Beautiful word clouds with jQuery + +jQCloud is a jQuery plugin that builds neat and pure HTML + CSS word clouds and tag clouds that are actually shaped like a cloud (otherwise, why would we call them 'word clouds'?). + +Also available as [AngularJS directive](https://github.com/mistic100/angular-jqcloud) + +## Documentation + +http://mistic100.github.io/jQCloud + +## License +This library is available under the MIT license. diff --git a/src/static/node_modules/jqcloud2/bower.json b/src/static/node_modules/jqcloud2/bower.json new file mode 100644 index 0000000..35b5b54 --- /dev/null +++ b/src/static/node_modules/jqcloud2/bower.json @@ -0,0 +1,43 @@ +{ + "name": "jqcloud2", + "homepage": "https://github.com/mistic100/jQCloud", + "description": "jQuery plugin for drawing neat word clouds that actually look like clouds", + "authors": [{ + "name": "Luca Ongaro", + "homepage": "http://www.lucaongaro.eu" + }, { + "name": "Daniel White", + "homepage": "http://www.developerdan.com" + }, { + "name": "Damien \"Mistic\" Sorel", + "email": "contact@git.strangeplanet.fr", + "homepage": "http://www.strangeplanet.fr" + }], + "main": [ + "dist/jqcloud.js", + "dist/jqcloud.css" + ], + "dependencies" : { + "jquery": ">= 1.9.0" + }, + "keywords": [ + "cloud", + "jquery", + "keyword", + "tag" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "git://github.com/mistic100/jQCloud.git" + }, + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests", + "package.json", + "Gruntfile.js" + ] +} diff --git a/src/static/node_modules/jqcloud2/package.json b/src/static/node_modules/jqcloud2/package.json new file mode 100644 index 0000000..062b930 --- /dev/null +++ b/src/static/node_modules/jqcloud2/package.json @@ -0,0 +1,116 @@ +{ + "_args": [ + [ + { + "raw": "jqcloud2", + "scope": null, + "escapedName": "jqcloud2", + "name": "jqcloud2", + "rawSpec": "", + "spec": "latest", + "type": "tag" + }, + "C:\\Box Sync\\pyDataVizDay\\src\\static" + ] + ], + "_from": "jqcloud2@latest", + "_id": "jqcloud2@2.0.3", + "_inCache": true, + "_location": "/jqcloud2", + "_nodeVersion": "6.9.1", + "_npmOperationalInternal": { + "host": "packages-18-east.internal.npmjs.com", + "tmp": "tmp/jqcloud2-2.0.3.tgz_1493060216703_0.7756482642143965" + }, + "_npmUser": { + "name": "mistic100", + "email": "contact@git.strangeplanet.fr" + }, + "_npmVersion": "3.10.9", + "_phantomChildren": {}, + "_requested": { + "raw": "jqcloud2", + "scope": null, + "escapedName": "jqcloud2", + "name": "jqcloud2", + "rawSpec": "", + "spec": "latest", + "type": "tag" + }, + "_requiredBy": [ + "#USER" + ], + "_resolved": "https://registry.npmjs.org/jqcloud2/-/jqcloud2-2.0.3.tgz", + "_shasum": "9b1691f85513d2902a5ec63ead49318b85a0c478", + "_shrinkwrap": null, + "_spec": "jqcloud2", + "_where": "C:\\Box Sync\\pyDataVizDay\\src\\static", + "authors": [ + { + "name": "Luca Ongaro", + "homepage": "http://www.lucaongaro.eu" + }, + { + "name": "Daniel White", + "homepage": "http://www.developerdan.com" + }, + { + "name": "Damien \"Mistic\" Sorel", + "email": "contact@git.strangeplanet.fr", + "homepage": "http://www.strangeplanet.fr" + } + ], + "bugs": { + "url": "https://github.com/mistic100/jQCloud/issues" + }, + "dependencies": { + "jquery": ">= 1.9.0" + }, + "description": "jQuery plugin for drawing neat word clouds that actually look like clouds", + "devDependencies": { + "grunt": "^1.0.0", + "grunt-contrib-concat": "^1.0.0", + "grunt-contrib-cssmin": "^1.0.0", + "grunt-contrib-jshint": "^1.0.0", + "grunt-contrib-qunit": "^0.7.0", + "grunt-contrib-sass": "^1.0.0", + "grunt-contrib-uglify": "^1.0.0", + "grunt-scss-lint": "^0.3.8", + "grunt-wrap": "^0.3.0", + "jit-grunt": "^0.10.0", + "qunitjs": "^1.23.0", + "time-grunt": "^1.3.0" + }, + "directories": {}, + "dist": { + "shasum": "9b1691f85513d2902a5ec63ead49318b85a0c478", + "tarball": "https://registry.npmjs.org/jqcloud2/-/jqcloud2-2.0.3.tgz" + }, + "gitHead": "5d2dbbe7d6f6e87683325f6029ee45822a6544d5", + "homepage": "https://github.com/mistic100/jQCloud", + "keywords": [ + "cloud", + "jquery", + "keyword", + "tag" + ], + "license": "MIT", + "main": "dist/jqcloud.js", + "maintainers": [ + { + "name": "mistic100", + "email": "contact@git.strangeplanet.fr" + } + ], + "name": "jqcloud2", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git://github.com/mistic100/jQCloud.git" + }, + "scripts": { + "test": "grunt test" + }, + "version": "2.0.3" +} diff --git a/src/static/node_modules/jqcloud2/src/.wrapper.js b/src/static/node_modules/jqcloud2/src/.wrapper.js new file mode 100644 index 0000000..970003a --- /dev/null +++ b/src/static/node_modules/jqcloud2/src/.wrapper.js @@ -0,0 +1,16 @@ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['jquery'], factory); + } + else if (typeof module === 'object' && module.exports) { + module.exports = factory(require('jquery')); + } + else { + factory(root.jQuery); + } +}(this, function($) { +'use strict'; + +@@js + +})); \ No newline at end of file diff --git a/src/static/node_modules/jqcloud2/src/jqcloud.js b/src/static/node_modules/jqcloud2/src/jqcloud.js new file mode 100644 index 0000000..a41b422 --- /dev/null +++ b/src/static/node_modules/jqcloud2/src/jqcloud.js @@ -0,0 +1,524 @@ +/* + * Plugin class + */ +var jQCloud = function(element, word_array, options) { + this.$element = $(element); + + this.word_array = word_array || []; + this.options = options; + + this.sizeGenerator = null; + this.colorGenerator = null; + + // Data used internally + this.data = { + placed_words: [], + timeouts: {}, + namespace: null, + step: null, + angle: null, + aspect_ratio: null, + max_weight: null, + min_weight: null, + sizes: [], + colors: [] + }; + + this.initialize(); +}; + +jQCloud.DEFAULTS = { + width: 100, + height: 100, + center: { x: 0.5, y: 0.5 }, + steps: 10, + delay: null, + shape: 'elliptic', + classPattern: 'w{n}', + encodeURI: true, + removeOverflowing: true, + afterCloudRender: null, + autoResize: false, + colors: null, + fontSize: null, + template: null +}; + +jQCloud.prototype = { + initialize: function() { + // Set/Get dimensions + if (this.options.width) { + this.$element.width(this.options.width); + } + else { + this.options.width = this.$element.width(); + } + if (this.options.height) { + this.$element.height(this.options.height); + } + else { + this.options.height = this.$element.height(); + } + + // Default options value + this.options = $.extend(true, {}, jQCloud.DEFAULTS, this.options); + + // Ensure delay + if (this.options.delay === null) { + this.options.delay = this.word_array.length > 50 ? 10 : 0; + } + + // Backward compatibility + if (this.options.center.x > 1) { + this.options.center.x = this.options.center.x / this.options.width; + this.options.center.y = this.options.center.y / this.options.height; + } + + // Create colorGenerator function from options + // Direct function + if (typeof this.options.colors == 'function') { + this.colorGenerator = this.options.colors; + } + // Array of sizes + else if ($.isArray(this.options.colors)) { + var cl = this.options.colors.length; + if (cl > 0) { + // Fill the sizes array to X items + if (cl < this.options.steps) { + for (var i = cl; i < this.options.steps; i++) { + this.options.colors[i] = this.options.colors[cl - 1]; + } + } + + this.colorGenerator = function(weight) { + return this.options.colors[this.options.steps - weight]; + }; + } + } + + // Create sizeGenerator function from options + // Direct function + if (typeof this.options.fontSize == 'function') { + this.sizeGenerator = this.options.fontSize; + } + // Object with 'from' and 'to' + else if ($.isPlainObject(this.options.fontSize)) { + this.sizeGenerator = function(width, height, weight) { + var max = width * this.options.fontSize.from, + min = width * this.options.fontSize.to; + return Math.round(min + (max - min) * 1.0 / (this.options.steps - 1) * (weight - 1)) + 'px'; + }; + } + // Array of sizes + else if ($.isArray(this.options.fontSize)) { + var sl = this.options.fontSize.length; + if (sl > 0) { + // Fill the sizes array to X items + if (sl < this.options.steps) { + for (var j = sl; j < this.options.steps; j++) { + this.options.fontSize[j] = this.options.fontSize[sl - 1]; + } + } + + this.sizeGenerator = function(width, height, weight) { + return this.options.fontSize[this.options.steps - weight]; + }; + } + } + + this.data.angle = Math.random() * 6.28; + this.data.step = (this.options.shape === 'rectangular') ? 18.0 : 2.0; + this.data.aspect_ratio = this.options.width / this.options.height; + this.clearTimeouts(); + + // Namespace word ids to avoid collisions between multiple clouds + this.data.namespace = (this.$element.attr('id') || Math.floor((Math.random() * 1000000)).toString(36)) + '_word_'; + + this.$element.addClass('jqcloud'); + + // Container's CSS position cannot be 'static' + if (this.$element.css('position') === 'static') { + this.$element.css('position', 'relative'); + } + + // Delay execution so that the browser can render the page before the computatively intensive word cloud drawing + this.createTimeout($.proxy(this.drawWordCloud, this), 10); + + // Attach window resize event + if (this.options.autoResize) { + $(window).on('resize.' + this.data.namespace, throttle(this.resize, 50, this)); + } + }, + + // Helper function to keep track of timeouts so they can be destroyed + createTimeout: function(callback, time) { + var timeout = setTimeout($.proxy(function() { + delete this.data.timeouts[timeout]; + callback(); + }, this), time); + this.data.timeouts[timeout] = true; + }, + + // Destroy all timeouts + clearTimeouts: function() { + $.each(this.data.timeouts, function(key) { + clearTimeout(key); + }); + this.data.timeouts = {}; + }, + + // Pairwise overlap detection + overlapping: function(a, b) { + if (Math.abs(2.0 * a.left + a.width - 2.0 * b.left - b.width) < a.width + b.width) { + if (Math.abs(2.0 * a.top + a.height - 2.0 * b.top - b.height) < a.height + b.height) { + return true; + } + } + return false; + }, + + // Helper function to test if an element overlaps others + hitTest: function(elem) { + // Check elements for overlap one by one, stop and return false as soon as an overlap is found + for (var i = 0, l = this.data.placed_words.length; i < l; i++) { + if (this.overlapping(elem, this.data.placed_words[i])) { + return true; + } + } + return false; + }, + + // Initialize the drawing of the whole cloud + drawWordCloud: function() { + var i, l; + + this.$element.children('[id^="' + this.data.namespace + '"]').remove(); + + if (this.word_array.length === 0) { + return; + } + + // Make sure every weight is a number before sorting + for (i = 0, l = this.word_array.length; i < l; i++) { + this.word_array[i].weight = parseFloat(this.word_array[i].weight, 10); + } + + // Sort word_array from the word with the highest weight to the one with the lowest + this.word_array.sort(function(a, b) { + return b.weight - a.weight; + }); + + // Kepp trace of bounds + this.data.max_weight = this.word_array[0].weight; + this.data.min_weight = this.word_array[this.word_array.length - 1].weight; + + // Generate colors + this.data.colors = []; + if (this.colorGenerator) { + for (i = 0; i < this.options.steps; i++) { + this.data.colors.push(this.colorGenerator(i + 1)); + } + } + + // Generate font sizes + this.data.sizes = []; + if (this.sizeGenerator) { + for (i = 0; i < this.options.steps; i++) { + this.data.sizes.push(this.sizeGenerator(this.options.width, this.options.height, i + 1)); + } + } + + // Iterate drawOneWord on every word, immediately or with delay + if (this.options.delay > 0) { + this.drawOneWordDelayed(); + } + else { + for (i = 0, l = this.word_array.length; i < l; i++) { + this.drawOneWord(i, this.word_array[i]); + } + + if (typeof this.options.afterCloudRender === 'function') { + this.options.afterCloudRender.call(this.$element); + } + } + }, + + // Function to draw a word, by moving it in spiral until it finds a suitable empty place + drawOneWord: function(index, word) { + var word_id = this.data.namespace + index, + word_selector = '#' + word_id, + + // option.shape == 'elliptic' + angle = this.data.angle, + radius = 0.0, + + // option.shape == 'rectangular' + steps_in_direction = 0.0, + quarter_turns = 0.0, + + weight = Math.floor(this.options.steps / 2), + word_span, + word_size, + word_style; + + // Create word attr object + word.attr = $.extend({}, word.html, { id: word_id }); + + // Linearly map the original weight to a discrete scale from 1 to 10 + // Only if weights are different + if (this.data.max_weight != this.data.min_weight) { + weight = Math.round((word.weight - this.data.min_weight) * 1.0 * (this.options.steps - 1) / (this.data.max_weight - this.data.min_weight)) + 1; + } + word_span = $('').attr(word.attr); + + word_span.addClass('jqcloud-word'); + + // Apply class + if (this.options.classPattern) { + word_span.addClass(this.options.classPattern.replace('{n}', weight)); + } + + // Apply color + if (this.data.colors.length) { + word_span.css('color', this.data.colors[weight - 1]); + } + + // Apply color from word property + if (word.color) { + word_span.css('color', word.color); + } + + // Apply size + if (this.data.sizes.length) { + word_span.css('font-size', this.data.sizes[weight - 1]); + } + + //Render using template function if provided. + if (this.options.template) { + word_span.html(this.options.template(word)); + } else if (word.link) { + // Append link if word.link attribute was set + // If link is a string, then use it as the link href + if (typeof word.link === 'string') { + word.link = { href: word.link }; + } + + if (this.options.encodeURI) { + word.link.href = encodeURI(word.link.href).replace(/'/g, '%27'); + } + + word_span.append($('').attr(word.link).text(word.text)); + } + else { + word_span.text(word.text); + } + + // Bind handlers to words + if (word.handlers) { + word_span.on(word.handlers); + } + + this.$element.append(word_span); + + word_size = { + width: word_span.outerWidth(), + height: word_span.outerHeight() + }; + word_size.left = this.options.center.x * this.options.width - word_size.width / 2.0; + word_size.top = this.options.center.y * this.options.height - word_size.height / 2.0; + + // Save a reference to the style property, for better performance + word_style = word_span[0].style; + word_style.position = 'absolute'; + word_style.left = word_size.left + 'px'; + word_style.top = word_size.top + 'px'; + + while (this.hitTest(word_size)) { + // option shape is 'rectangular' so move the word in a rectangular spiral + if (this.options.shape === 'rectangular') { + steps_in_direction++; + + if (steps_in_direction * this.data.step > (1 + Math.floor(quarter_turns / 2.0)) * this.data.step * ((quarter_turns % 4 % 2) === 0 ? 1 : this.data.aspect_ratio)) { + steps_in_direction = 0.0; + quarter_turns++; + } + + switch (quarter_turns % 4) { + case 1: + word_size.left += this.data.step * this.data.aspect_ratio + Math.random() * 2.0; + break; + case 2: + word_size.top -= this.data.step + Math.random() * 2.0; + break; + case 3: + word_size.left -= this.data.step * this.data.aspect_ratio + Math.random() * 2.0; + break; + case 0: + word_size.top += this.data.step + Math.random() * 2.0; + break; + } + } + // Default settings: elliptic spiral shape + else { + radius += this.data.step; + angle += (index % 2 === 0 ? 1 : -1) * this.data.step; + + word_size.left = this.options.center.x * this.options.width - (word_size.width / 2.0) + (radius * Math.cos(angle)) * this.data.aspect_ratio; + word_size.top = this.options.center.y * this.options.height + radius * Math.sin(angle) - (word_size.height / 2.0); + } + word_style.left = word_size.left + 'px'; + word_style.top = word_size.top + 'px'; + } + + // Don't render word if part of it would be outside the container + if (this.options.removeOverflowing && ( + word_size.left < 0 || word_size.top < 0 || + (word_size.left + word_size.width) > this.options.width || + (word_size.top + word_size.height) > this.options.height + ) + ) { + word_span.remove(); + return; + } + + // Save position for further usage + this.data.placed_words.push(word_size); + + if (typeof word.afterWordRender === 'function') { + word.afterWordRender.call(word_span); + } + }, + + // Draw one word then recall the function after a delay + drawOneWordDelayed: function(index) { + index = index || 0; + + // if not visible then do not attempt to draw + if (!this.$element.is(':visible')) { + this.createTimeout($.proxy(function() { + this.drawOneWordDelayed(index); + }, this), 10); + + return; + } + + if (index < this.word_array.length) { + this.drawOneWord(index, this.word_array[index]); + + this.createTimeout($.proxy(function() { + this.drawOneWordDelayed(index + 1); + }, this), this.options.delay); + } + else { + if (typeof this.options.afterCloudRender == 'function') { + this.options.afterCloudRender.call(this.$element); + } + } + }, + + // Destroy any data and objects added by the plugin + destroy: function() { + if (this.options.autoResize) { + $(window).off('resize.' + this.data.namespace); + } + + this.clearTimeouts(); + this.$element.removeClass('jqcloud'); + this.$element.removeData('jqcloud'); + this.$element.children('[id^="' + this.data.namespace + '"]').remove(); + }, + + // Update the list of words + update: function(word_array) { + this.word_array = word_array; + this.data.placed_words = []; + + this.clearTimeouts(); + this.drawWordCloud(); + }, + + resize: function() { + var new_size = { + width: this.$element.width(), + height: this.$element.height() + }; + + if (new_size.width != this.options.width || new_size.height != this.options.height) { + this.options.width = new_size.width; + this.options.height = new_size.height; + this.data.aspect_ratio = this.options.width / this.options.height; + + this.update(this.word_array); + } + }, +}; + +/* + * Apply throttling to a callback + * @param callback {function} + * @param delay {int} milliseconds + * @param context {object|null} + * @return {function} + */ +function throttle(callback, delay, context) { + var state = { + pid: null, + last: 0 + }; + + return function() { + var elapsed = new Date().getTime() - state.last, + args = arguments, + that = this; + + function exec() { + state.last = new Date().getTime(); + return callback.apply(context || that, Array.prototype.slice.call(args)); + } + + if (elapsed > delay) { + return exec(); + } + else { + clearTimeout(state.pid); + state.pid = setTimeout(exec, delay - elapsed); + } + }; +} + +/* + * jQuery plugin + */ +$.fn.jQCloud = function(word_array, option) { + var args = arguments; + + return this.each(function() { + var $this = $(this), + data = $this.data('jqcloud'); + + if (!data && word_array === 'destroy') { + // Don't even try to initialize when called with 'destroy' + return; + } + if (!data) { + var options = typeof option === 'object' ? option : {}; + $this.data('jqcloud', (data = new jQCloud(this, word_array, options))); + } + else if (typeof word_array === 'string') { + data[word_array].apply(data, Array.prototype.slice.call(args, 1)); + } + }); +}; + +$.fn.jQCloud.defaults = { + set: function(options) { + $.extend(true, jQCloud.DEFAULTS, options); + }, + get: function(key) { + var options = jQCloud.DEFAULTS; + if (key) { + options = options[key]; + } + return $.extend(true, {}, options); + } +}; diff --git a/src/static/node_modules/jqcloud2/src/jqcloud.scss b/src/static/node_modules/jqcloud2/src/jqcloud.scss new file mode 100644 index 0000000..ef5b435 --- /dev/null +++ b/src/static/node_modules/jqcloud2/src/jqcloud.scss @@ -0,0 +1,45 @@ +$jqcloud-font: 10px "Helvetica", "Arial", sans-serif; + +$jqcloud-link-hover-color: #00ccff; + +$jqcloud-words: ( + w1: (100%, #aab5f0), + w2: (150%, #99ccee), + w3: (200%, #a0ddff), + w4: (250%, #90c5f0), + w5: (300%, #90a0dd), + w6: (350%, #90c5f0), + w7: (400%, #3399dd), + w8: (450%, #00ccff), + w9: (500%, #00ccff), + w10: (550%, #00ccff) +) !default; + +.jqcloud { + font: $jqcloud-font; + line-height: normal; + overflow: hidden; + position: relative; +} + +.jqcloud-word { + margin: 0; + padding: 0; + + @each $word, $config in $jqcloud-words { + &.#{$word} { + color: nth($config, 2); + font-size: nth($config, 1); + } + } + + a { + color: inherit; + font-size: inherit; + text-decoration: none; + + &:hover { + color: $jqcloud-link-hover-color; + } + } +} diff --git a/src/static/node_modules/jqcloud2/test/core_tests.js b/src/static/node_modules/jqcloud2/test/core_tests.js new file mode 100644 index 0000000..fb2d6fe --- /dev/null +++ b/src/static/node_modules/jqcloud2/test/core_tests.js @@ -0,0 +1,261 @@ +$(function() { + var $c = $('#cloud'); + + QUnit.module('core', { + afterEach: function() { + $c.jQCloud('destroy'); + } + }); + + var some_words = [ + { + text: 'Zero', + weight: 0, + html: { 'test': 'just testing' } + }, + { + text: 'Minus three', + weight: -3, + link: '#' + }, + { + text: 'Minus point fiftyfive', + weight: -0.55 + }, + { + text: 'Two', + weight: '2.0', + link: { href: '#', test: "testing" }, + handlers: { + click: function() { + $(this).data("testHandler", "Handler works!"); + } + }, + afterWordRender: function() { + this.data("testCallback", "Callback works!"); + }, + html: { "class": "mycustomclass" } + } + ]; + + var some_other_words = [ + { text: 'Abc', weight: 1 }, + { text: 'Def', weight: 2 }, + { text: 'Ghi', weight: 3 } + ]; + + var words_with_same_weight = [ + { text: 'Abc', weight: 1 }, + { text: 'Def', weight: 1 }, + { text: 'Ghi', weight: 1 } + ]; + + var encoded_words = [ + { text: "John's Bday", weight: 1, link: "/posts?tag=John%27s+Bday" } + ]; + + var words_with_color = [ + { text: 'Abc', weight: 0, color: '#000' }, + { text: 'Def', weight: 1, color: '#ccc' }, + { text: 'Ghi', weight: 2, color: '#eee' } + ]; + + + QUnit.test('Layout', function(assert) { + var done = assert.async(); + + $c.jQCloud(some_words, { + afterCloudRender: function() { + var text = $c.text(); + assert.ok(text.search(/Zero/) >= 0, "'Zero' is in the cloud"); + assert.ok(text.search(/Minus three/) >= 0, "'Minus three' is in the cloud"); + assert.ok(text.search(/Minus point fiftyfive/) >= 0, "'Minus point five' is in the cloud"); + assert.ok(text.search(/Two/) >= 0, "'Two' is in the cloud, even if the weight was a string"); + + var biggest = $("#cloud_word_0"); + assert.equal(some_words[0].text, "Two", "'Two', having the biggest weight, becomes the first element in the array"); + assert.equal(biggest.text(), "Two", "'Two', having the biggest weight, gets wrapped in an element of id cloud_word_0"); + assert.ok(biggest.hasClass("w10"), "the element with the biggest weight gets wrapped in an element of class w10"); + + var smallest = $("#cloud_word_" + (some_words.length - 1)); + assert.equal(some_words[(some_words.length - 1)].text, "Minus three", "'Minus three', having the smallest weight, becomes the last element in the array"); + assert.equal(smallest.text(), "Minus three", "'Minus three', having the smallest weight, gets wrapped in an element of id cloud_word_" + (some_words.length - 1)); + assert.ok(smallest.hasClass("w1"), "the element with the smallest weight gets wrapped in an element of class w1"); + + var middle = $("#cloud_word_2"); + assert.equal(middle.text(), "Minus point fiftyfive", "'Minus point fiftyfive' should get wrapped in an element of id cloud_word_2"); + assert.ok(middle.hasClass("w5") && middle.text() == "Minus point fiftyfive", "'Minus zero point fiftyfive', having a weight in the middle of the range, should get wrapped in an element of class w5"); + + done(); + } + }); + }); + + QUnit.test('Links', function(assert) { + var done = assert.async(); + + $c.jQCloud(some_words, { + afterCloudRender: function() { + assert.ok($c.find("span:contains('Minus three') a[href='#']").length == 1, "If 'link' option is specified and is a string, an html anchor pointing to that URL is created."); + assert.ok($c.find("span:contains('Two') a[href='#']").length == 1, "If 'link' option is specified and is an object, an html anchor pointing to link.href is created."); + assert.equal($c.find("span:contains('Two') a").attr("test"), "testing", "If 'link' option is specified and is an object, custom attributes should be set."); + + done(); + } + }); + }); + + QUnit.test('Event handlers', function(assert) { + var done = assert.async(); + + $c.jQCloud(some_words, { + afterCloudRender: function() { + $c.find("span:contains('Two')").trigger("click"); + assert.equal($c.find("span:contains('Two')").data("testHandler"), "Handler works!", "Event handlers should be triggered."); + + done(); + } + }); + }); + + QUnit.test('Callbacks', function(assert) { + var done = assert.async(); + + $c.jQCloud(some_words, { + afterCloudRender: function() { + assert.equal($c.find("span:contains('Two')").data("testCallback"), "Callback works!", "afterWordRender callback should be called, and 'this' should be the word element."); + + done(); + } + }); + }); + + QUnit.test('Attributes', function(assert) { + var done = assert.async(); + + $c.jQCloud(some_words, { + afterCloudRender: function() { + assert.ok($c.find("span:contains('Two')").hasClass("mycustomclass"), "Custom classes should be set via html.class attribute"); + assert.equal($c.find("span:contains('Zero')").attr("test"), "just testing", "Custom attributes should be set via the html option"); + + done(); + } + }); + }); + + QUnit.test('Cloud rendering with with delay > 0', function(assert) { + var done = assert.async(); + + $c.jQCloud(some_other_words, { + delay: 10, + afterCloudRender: function() { + var text = $c.text(); + assert.ok(text.search(/Abc/) >= 0, "'Abc' is in the second cloud"); + assert.ok(text.search(/Def/) >= 0, "'Def' is in the second cloud"); + assert.ok(text.search(/Ghi/) >= 0, "'Ghi' is in the second cloud"); + assert.ok(text.search(/Zero/) < 0, "'Zero' is not in the second cloud"); + + done(); + } + }); + }); + + QUnit.test('Words with equal weight', function(assert) { + var done = assert.async(); + + $c.jQCloud(words_with_same_weight, { + afterCloudRender: function() { + assert.ok($c.find(".w5").length == 3, "There should be three words with equal weight."); + + done(); + } + }); + }); + + QUnit.test('Words render when delay is positive and container is visible', function(assert) { + assert.expect(4); + var done1 = assert.async(); + var done2 = assert.async(); + + $c.hide(); + + $c.jQCloud(some_words, { + delay: 10, + afterCloudRender: function() { + assert.ok($c.is(':visible'), "Container is visible"); + assert.ok($c.find("span").length, "Words are rendered"); + + done1(); + } + }); + + setTimeout(function() { + assert.ok(!$c.is(':visible'), "Container is not visible"); + assert.ok($c.find("span").length === 0, "There should be no spans in the container"); + + // now set container4 to visible so that the corresponding visibility test executes + $c.show(); + + done2(); + }, 20); + }); + + + QUnit.test('Links encoding', function(assert) { + assert.expect(2); + var done1 = assert.async(); + var done2 = assert.async(); + + $c.jQCloud($.extend(true, [], encoded_words), { + encodeURI: false, + afterCloudRender: function() { + assert.equal($c.find("span a").attr('href'), '/posts?tag=John%27s+Bday', 'encodeURI is turned off'); + + done1(); + + $c.jQCloud('destroy'); + + $c.jQCloud($.extend(true, [], encoded_words), { + encodeURI: true, + afterCloudRender: function() { + assert.equal($c.find("span a").attr('href'), '/posts?tag=John%2527s+Bday', 'encodeURI is turned on'); + + done2(); + } + }); + } + }); + }); + + QUnit.test('Custom class, colors and fontSize', function(assert) { + var done = assert.async(); + + $c.jQCloud(some_words, { + classPattern: 'word-{n}', + colors: ["#800026", "#bd0026", "#e31a1c", "#fc4e2a", "#fd8d3c", "#feb24c", "#fed976", "#ffeda0", "#ffffcc"], + fontSize: ['50px', '40px', '20px'], + afterCloudRender: function() { + var first = $('#cloud_word_0'); + assert.ok(first.hasClass('word-10')); + assert.equal(first.css('color'), "rgb(128, 0, 38)"); + assert.equal(first.css('font-size'), "50px"); + + done(); + } + }); + }); + + QUnit.test('Word specific color', function(assert) { + var done = assert.async(); + + $c.jQCloud(words_with_color, { + afterCloudRender: function() { + assert.equal($('#cloud_word_2').css('color'), "rgb(0, 0, 0)"); + assert.equal($('#cloud_word_1').css('color'), "rgb(204, 204, 204)"); + assert.equal($('#cloud_word_0').css('color'), "rgb(238, 238, 238)"); + + done(); + } + }); + }); +}); \ No newline at end of file diff --git a/src/static/node_modules/jqcloud2/test/index.html b/src/static/node_modules/jqcloud2/test/index.html new file mode 100644 index 0000000..2c958b7 --- /dev/null +++ b/src/static/node_modules/jqcloud2/test/index.html @@ -0,0 +1,32 @@ + + + + jQCloud + + + + + + + + + + + + + + + + +
+
+ +
+ + + diff --git a/src/static/node_modules/jquery/AUTHORS.txt b/src/static/node_modules/jquery/AUTHORS.txt new file mode 100644 index 0000000..c32c25f --- /dev/null +++ b/src/static/node_modules/jquery/AUTHORS.txt @@ -0,0 +1,301 @@ +Authors ordered by first contribution. + +John Resig +Gilles van den Hoven +Michael Geary +Stefan Petre +Yehuda Katz +Corey Jewett +Klaus Hartl +Franck Marcia +Jörn Zaefferer +Paul Bakaus +Brandon Aaron +Mike Alsup +Dave Methvin +Ed Engelhardt +Sean Catchpole +Paul Mclanahan +David Serduke +Richard D. Worth +Scott González +Ariel Flesler +Jon Evans +TJ Holowaychuk +Michael Bensoussan +Robert Katić +Louis-Rémi Babé +Earle Castledine +Damian Janowski +Rich Dougherty +Kim Dalsgaard +Andrea Giammarchi +Mark Gibson +Karl Swedberg +Justin Meyer +Ben Alman +James Padolsey +David Petersen +Batiste Bieler +Alexander Farkas +Rick Waldron +Filipe Fortes +Neeraj Singh +Paul Irish +Iraê Carvalho +Matt Curry +Michael Monteleone +Noah Sloan +Tom Viner +Douglas Neiner +Adam J. Sontag +Dave Reed +Ralph Whitbeck +Carl Fürstenberg +Jacob Wright +J. Ryan Stinnett +unknown +temp01 +Heungsub Lee +Colin Snover +Ryan W Tenney +Pinhook +Ron Otten +Jephte Clain +Anton Matzneller +Alex Sexton +Dan Heberden +Henri Wiechers +Russell Holbrook +Julian Aubourg +Gianni Alessandro Chiappetta +Scott Jehl +James Burke +Jonas Pfenniger +Xavi Ramirez +Jared Grippe +Sylvester Keil +Brandon Sterne +Mathias Bynens +Timmy Willison <4timmywil@gmail.com> +Corey Frang +Digitalxero +Anton Kovalyov +David Murdoch +Josh Varner +Charles McNulty +Jordan Boesch +Jess Thrysoee +Michael Murray +Lee Carpenter +Alexis Abril +Rob Morgan +John Firebaugh +Sam Bisbee +Gilmore Davidson +Brian Brennan +Xavier Montillet +Daniel Pihlstrom +Sahab Yazdani +avaly +Scott Hughes +Mike Sherov +Greg Hazel +Schalk Neethling +Denis Knauf +Timo Tijhof +Steen Nielsen +Anton Ryzhov +Shi Chuan +Berker Peksag +Toby Brain +Matt Mueller +Justin +Daniel Herman +Oleg Gaidarenko +Richard Gibson +Rafaël Blais Masson +cmc3cn <59194618@qq.com> +Joe Presbrey +Sindre Sorhus +Arne de Bree +Vladislav Zarakovsky +Andrew E Monat +Oskari +Joao Henrique de Andrade Bruni +tsinha +Matt Farmer +Trey Hunner +Jason Moon +Jeffery To +Kris Borchers +Vladimir Zhuravlev +Jacob Thornton +Chad Killingsworth +Nowres Rafid +David Benjamin +Uri Gilad +Chris Faulkner +Elijah Manor +Daniel Chatfield +Nikita Govorov +Wesley Walser +Mike Pennisi +Markus Staab +Dave Riddle +Callum Macrae +Benjamin Truyman +James Huston +Erick Ruiz de Chávez +David Bonner +Akintayo Akinwunmi +MORGAN +Ismail Khair +Carl Danley +Mike Petrovich +Greg Lavallee +Daniel Gálvez +Sai Lung Wong +Tom H Fuertes +Roland Eckl +Jay Merrifield +Allen J Schmidt Jr +Jonathan Sampson +Marcel Greter +Matthias Jäggli +David Fox +Yiming He +Devin Cooper +Paul Ramos +Rod Vagg +Bennett Sorbo +Sebastian Burkhard +Zachary Adam Kaplan +nanto_vi +nanto +Danil Somsikov +Ryunosuke SATO +Jean Boussier +Adam Coulombe +Andrew Plummer +Mark Raddatz +Isaac Z. Schlueter +Karl Sieburg +Pascal Borreli +Nguyen Phuc Lam +Dmitry Gusev +Michał Gołębiowski +Li Xudong +Steven Benner +Tom H Fuertes +Renato Oliveira dos Santos +ros3cin +Jason Bedard +Kyle Robinson Young +Chris Talkington +Eddie Monge +Terry Jones +Jason Merino +Jeremy Dunck +Chris Price +Guy Bedford +Amey Sakhadeo +Mike Sidorov +Anthony Ryan +Dominik D. Geyer +George Kats +Lihan Li +Ronny Springer +Chris Antaki +Marian Sollmann +njhamann +Ilya Kantor +David Hong +John Paul +Jakob Stoeck +Christopher Jones +Forbes Lindesay +S. Andrew Sheppard +Leonardo Balter +Roman Reiß +Benjy Cui +Rodrigo Rosenfeld Rosas +John Hoven +Philip Jägenstedt +Christian Kosmowski +Liang Peng +TJ VanToll +Senya Pugach +Aurelio De Rosa +Nazar Mokrynskyi +Amit Merchant +Jason Bedard +Arthur Verschaeve +Dan Hart +Bin Xin +David Corbacho +Veaceslav Grimalschi +Daniel Husar +Frederic Hemberger +Ben Toews +Aditya Raghavan +Victor Homyakov +Shivaji Varma +Nicolas HENRY +Anne-Gaelle Colom +George Mauer +Leonardo Braga +Stephen Edgar +Thomas Tortorini +Winston Howes +Jon Hester +Alexander O'Mara +Bastian Buchholz +Arthur Stolyar +Calvin Metcalf +Mu Haibao +Richard McDaniel +Chris Rebert +Gabriel Schulhof +Gilad Peleg +Martin Naumann +Marek Lewandowski +Bruno Pérel +Reed Loden +Daniel Nill +Yongwoo Jeon +Sean Henderson +Richard Kraaijenhagen +Connor Atherton +Gary Ye +Christian Grete +Liza Ramo +Julian Alexander Murillo +Joelle Fleurantin +Jae Sung Park +Jun Sun +Josh Soref +Henry Wong +Jon Dufresne +Martijn W. van der Lee +Devin Wilson +Steve Mao +Zack Hall +Bernhard M. Wiedemann +Todor Prikumov +Jha Naman +William Robinet +Alexander Lisianoi +Vitaliy Terziev +Joe Trumbull +Alexander K +Damian Senn +Ralin Chimev +Felipe Sateler +Christophe Tafani-Dereeper +Manoj Kumar +David Broder-Rodgers +Alex Louden +Alex Padilla +南漂一卒 +karan-96 diff --git a/src/static/node_modules/jquery/LICENSE.txt b/src/static/node_modules/jquery/LICENSE.txt new file mode 100644 index 0000000..e4e5e00 --- /dev/null +++ b/src/static/node_modules/jquery/LICENSE.txt @@ -0,0 +1,36 @@ +Copyright JS Foundation and other contributors, https://js.foundation/ + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/jquery/jquery + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +All files located in the node_modules and external directories are +externally maintained libraries used by this software which have their +own licenses; we recommend you read them, as their terms may differ from +the terms above. diff --git a/src/static/node_modules/jquery/README.md b/src/static/node_modules/jquery/README.md new file mode 100644 index 0000000..09a4273 --- /dev/null +++ b/src/static/node_modules/jquery/README.md @@ -0,0 +1,67 @@ +# jQuery + +> jQuery is a fast, small, and feature-rich JavaScript library. + +For information on how to get started and how to use jQuery, please see [jQuery's documentation](http://api.jquery.com/). +For source files and issues, please visit the [jQuery repo](https://github.com/jquery/jquery). + +If upgrading, please see the [blog post for 3.2.1](https://blog.jquery.com/2017/03/20/jquery-3-2-1-now-available/). This includes notable differences from the previous version and a more readable changelog. + +## Including jQuery + +Below are some of the most common ways to include jQuery. + +### Browser + +#### Script tag + +```html + +``` + +#### Babel + +[Babel](http://babeljs.io/) is a next generation JavaScript compiler. One of the features is the ability to use ES6/ES2015 modules now, even though browsers do not yet support this feature natively. + +```js +import $ from "jquery"; +``` + +#### Browserify/Webpack + +There are several ways to use [Browserify](http://browserify.org/) and [Webpack](https://webpack.github.io/). For more information on using these tools, please refer to the corresponding project's documention. In the script, including jQuery will usually look like this... + +```js +var $ = require("jquery"); +``` + +#### AMD (Asynchronous Module Definition) + +AMD is a module format built for the browser. For more information, we recommend [require.js' documentation](http://requirejs.org/docs/whyamd.html). + +```js +define(["jquery"], function($) { + +}); +``` + +### Node + +To include jQuery in [Node](nodejs.org), first install with npm. + +```sh +npm install jquery +``` + +For jQuery to work in Node, a window with a document is required. Since no such window exists natively in Node, one can be mocked by tools such as [jsdom](https://github.com/tmpvar/jsdom). This can be useful for testing purposes. + +```js +require("jsdom").env("", function(err, window) { + if (err) { + console.error(err); + return; + } + + var $ = require("jquery")(window); +}); +``` diff --git a/src/static/node_modules/jquery/bower.json b/src/static/node_modules/jquery/bower.json new file mode 100644 index 0000000..95798d5 --- /dev/null +++ b/src/static/node_modules/jquery/bower.json @@ -0,0 +1,14 @@ +{ + "name": "jquery", + "main": "dist/jquery.js", + "license": "MIT", + "ignore": [ + "package.json" + ], + "keywords": [ + "jquery", + "javascript", + "browser", + "library" + ] +} \ No newline at end of file diff --git a/src/static/node_modules/jquery/external/sizzle/LICENSE.txt b/src/static/node_modules/jquery/external/sizzle/LICENSE.txt new file mode 100644 index 0000000..dd7ce94 --- /dev/null +++ b/src/static/node_modules/jquery/external/sizzle/LICENSE.txt @@ -0,0 +1,36 @@ +Copyright jQuery Foundation and other contributors, https://jquery.org/ + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/jquery/sizzle + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +All files located in the node_modules and external directories are +externally maintained libraries used by this software which have their +own licenses; we recommend you read them, as their terms may differ from +the terms above. diff --git a/src/static/node_modules/jquery/package.json b/src/static/node_modules/jquery/package.json new file mode 100644 index 0000000..f281ac6 --- /dev/null +++ b/src/static/node_modules/jquery/package.json @@ -0,0 +1,169 @@ +{ + "_args": [ + [ + { + "raw": "jquery@>= 1.9.0", + "scope": null, + "escapedName": "jquery", + "name": "jquery", + "rawSpec": ">= 1.9.0", + "spec": ">=1.9.0", + "type": "range" + }, + "C:\\Box Sync\\pyDataVizDay\\src\\static\\node_modules\\jqcloud2" + ] + ], + "_from": "jquery@>=1.9.0", + "_id": "jquery@3.2.1", + "_inCache": true, + "_location": "/jquery", + "_nodeVersion": "7.7.3", + "_npmOperationalInternal": { + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/jquery-3.2.1.tgz_1490036530067_0.19497186387889087" + }, + "_npmUser": { + "name": "timmywil", + "email": "4timmywil@gmail.com" + }, + "_npmVersion": "4.4.4", + "_phantomChildren": {}, + "_requested": { + "raw": "jquery@>= 1.9.0", + "scope": null, + "escapedName": "jquery", + "name": "jquery", + "rawSpec": ">= 1.9.0", + "spec": ">=1.9.0", + "type": "range" + }, + "_requiredBy": [ + "/jqcloud2" + ], + "_resolved": "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz", + "_shasum": "5c4d9de652af6cd0a770154a631bba12b015c787", + "_shrinkwrap": null, + "_spec": "jquery@>= 1.9.0", + "_where": "C:\\Box Sync\\pyDataVizDay\\src\\static\\node_modules\\jqcloud2", + "author": { + "name": "JS Foundation and other contributors", + "url": "https://github.com/jquery/jquery/blob/3.2.1/AUTHORS.txt" + }, + "bugs": { + "url": "https://github.com/jquery/jquery/issues" + }, + "commitplease": { + "nohook": true, + "components": [ + "Docs", + "Tests", + "Build", + "Support", + "Release", + "Core", + "Ajax", + "Attributes", + "Callbacks", + "CSS", + "Data", + "Deferred", + "Deprecated", + "Dimensions", + "Effects", + "Event", + "Manipulation", + "Offset", + "Queue", + "Selector", + "Serialize", + "Traversing", + "Wrap" + ], + "markerPattern": "^((clos|fix|resolv)(e[sd]|ing))|^(refs?)", + "ticketPattern": "^((Closes|Fixes) ([a-zA-Z]{2,}-)[0-9]+)|^(Refs? [^#])" + }, + "dependencies": {}, + "description": "JavaScript library for DOM operations", + "devDependencies": { + "babel-preset-es2015": "6.6.0", + "commitplease": "2.6.1", + "core-js": "2.2.2", + "cross-spawn": "2.2.3", + "eslint-config-jquery": "1.0.0", + "grunt": "1.0.1", + "grunt-babel": "6.0.0", + "grunt-cli": "1.2.0", + "grunt-compare-size": "0.4.2", + "grunt-contrib-uglify": "1.0.1", + "grunt-contrib-watch": "1.0.0", + "grunt-eslint": "19.0.0", + "grunt-git-authors": "3.2.0", + "grunt-jsonlint": "1.0.7", + "grunt-newer": "1.2.0", + "grunt-npmcopy": "0.1.0", + "gzip-js": "0.3.2", + "husky": "0.11.4", + "insight": "0.8.1", + "jsdom": "5.6.1", + "load-grunt-tasks": "3.5.0", + "native-promise-only": "0.8.1", + "promises-aplus-tests": "2.1.2", + "q": "1.4.1", + "qunit-assert-step": "1.0.3", + "qunitjs": "1.23.1", + "requirejs": "2.2.0", + "sinon": "1.17.3", + "sizzle": "2.3.3", + "strip-json-comments": "2.0.1", + "testswarm": "1.1.0" + }, + "directories": {}, + "dist": { + "shasum": "5c4d9de652af6cd0a770154a631bba12b015c787", + "tarball": "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz" + }, + "gitHead": "77d2a51d0520d2ee44173afdf4e40a9201f5964e", + "homepage": "https://jquery.com", + "keywords": [ + "jquery", + "javascript", + "browser", + "library" + ], + "license": "MIT", + "main": "dist/jquery.js", + "maintainers": [ + { + "name": "dmethvin", + "email": "dave.methvin@gmail.com" + }, + { + "name": "mgol", + "email": "m.goleb@gmail.com" + }, + { + "name": "scott.gonzalez", + "email": "scott.gonzalez@gmail.com" + }, + { + "name": "timmywil", + "email": "4timmywil@gmail.com" + } + ], + "name": "jquery", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+https://github.com/jquery/jquery.git" + }, + "scripts": { + "build": "npm install && grunt", + "commitmsg": "node node_modules/commitplease", + "precommit": "grunt lint:newer", + "start": "grunt watch", + "test": "grunt && grunt test:slow" + }, + "title": "jQuery", + "version": "3.2.1" +} diff --git a/src/static/node_modules/jquery/src/.eslintrc.json b/src/static/node_modules/jquery/src/.eslintrc.json new file mode 100644 index 0000000..3a4a3d2 --- /dev/null +++ b/src/static/node_modules/jquery/src/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "root": true, + + "extends": "../.eslintrc-browser.json" +} diff --git a/src/static/node_modules/jquery/src/ajax.js b/src/static/node_modules/jquery/src/ajax.js new file mode 100644 index 0000000..36f707d --- /dev/null +++ b/src/static/node_modules/jquery/src/ajax.js @@ -0,0 +1,855 @@ +define( [ + "./core", + "./var/document", + "./var/rnothtmlwhite", + "./ajax/var/location", + "./ajax/var/nonce", + "./ajax/var/rquery", + + "./core/init", + "./ajax/parseXML", + "./event/trigger", + "./deferred", + "./serialize" // jQuery.param +], function( jQuery, document, rnothtmlwhite, location, nonce, rquery ) { + +"use strict"; + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +return jQuery; +} ); diff --git a/src/static/node_modules/jquery/src/ajax/jsonp.js b/src/static/node_modules/jquery/src/ajax/jsonp.js new file mode 100644 index 0000000..8c406e7 --- /dev/null +++ b/src/static/node_modules/jquery/src/ajax/jsonp.js @@ -0,0 +1,102 @@ +define( [ + "../core", + "./var/nonce", + "./var/rquery", + "../ajax" +], function( jQuery, nonce, rquery ) { + +"use strict"; + +var oldCallbacks = [], + rjsonp = /(=)\?(?=&|$)|\?\?/; + +// Default jsonp settings +jQuery.ajaxSetup( { + jsonp: "callback", + jsonpCallback: function() { + var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); + this[ callback ] = true; + return callback; + } +} ); + +// Detect, normalize options and install callbacks for jsonp requests +jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { + + var callbackName, overwritten, responseContainer, + jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? + "url" : + typeof s.data === "string" && + ( s.contentType || "" ) + .indexOf( "application/x-www-form-urlencoded" ) === 0 && + rjsonp.test( s.data ) && "data" + ); + + // Handle iff the expected data type is "jsonp" or we have a parameter to set + if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { + + // Get callback name, remembering preexisting value associated with it + callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? + s.jsonpCallback() : + s.jsonpCallback; + + // Insert callback into url or form data + if ( jsonProp ) { + s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); + } else if ( s.jsonp !== false ) { + s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; + } + + // Use data converter to retrieve json after script execution + s.converters[ "script json" ] = function() { + if ( !responseContainer ) { + jQuery.error( callbackName + " was not called" ); + } + return responseContainer[ 0 ]; + }; + + // Force json dataType + s.dataTypes[ 0 ] = "json"; + + // Install callback + overwritten = window[ callbackName ]; + window[ callbackName ] = function() { + responseContainer = arguments; + }; + + // Clean-up function (fires after converters) + jqXHR.always( function() { + + // If previous value didn't exist - remove it + if ( overwritten === undefined ) { + jQuery( window ).removeProp( callbackName ); + + // Otherwise restore preexisting value + } else { + window[ callbackName ] = overwritten; + } + + // Save back as free + if ( s[ callbackName ] ) { + + // Make sure that re-using the options doesn't screw things around + s.jsonpCallback = originalSettings.jsonpCallback; + + // Save the callback name for future use + oldCallbacks.push( callbackName ); + } + + // Call if it was a function and we have a response + if ( responseContainer && jQuery.isFunction( overwritten ) ) { + overwritten( responseContainer[ 0 ] ); + } + + responseContainer = overwritten = undefined; + } ); + + // Delegate to script + return "script"; + } +} ); + +} ); diff --git a/src/static/node_modules/jquery/src/ajax/load.js b/src/static/node_modules/jquery/src/ajax/load.js new file mode 100644 index 0000000..3ce3a5a --- /dev/null +++ b/src/static/node_modules/jquery/src/ajax/load.js @@ -0,0 +1,76 @@ +define( [ + "../core", + "../core/stripAndCollapse", + "../core/parseHTML", + "../ajax", + "../traversing", + "../manipulation", + "../selector" +], function( jQuery, stripAndCollapse ) { + +"use strict"; + +/** + * Load a url into a page + */ +jQuery.fn.load = function( url, params, callback ) { + var selector, type, response, + self = this, + off = url.indexOf( " " ); + + if ( off > -1 ) { + selector = stripAndCollapse( url.slice( off ) ); + url = url.slice( 0, off ); + } + + // If it's a function + if ( jQuery.isFunction( params ) ) { + + // We assume that it's the callback + callback = params; + params = undefined; + + // Otherwise, build a param string + } else if ( params && typeof params === "object" ) { + type = "POST"; + } + + // If we have elements to modify, make the request + if ( self.length > 0 ) { + jQuery.ajax( { + url: url, + + // If "type" variable is undefined, then "GET" method will be used. + // Make value of this field explicit since + // user can override it through ajaxSetup method + type: type || "GET", + dataType: "html", + data: params + } ).done( function( responseText ) { + + // Save response for use in complete callback + response = arguments; + + self.html( selector ? + + // If a selector was specified, locate the right elements in a dummy div + // Exclude scripts to avoid IE 'Permission Denied' errors + jQuery( "
" ).append( jQuery.parseHTML( responseText ) ).find( selector ) : + + // Otherwise use the full result + responseText ); + + // If the request succeeds, this function gets "data", "status", "jqXHR" + // but they are ignored because response was set above. + // If it fails, this function gets "jqXHR", "status", "error" + } ).always( callback && function( jqXHR, status ) { + self.each( function() { + callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] ); + } ); + } ); + } + + return this; +}; + +} ); diff --git a/src/static/node_modules/jquery/src/ajax/parseXML.js b/src/static/node_modules/jquery/src/ajax/parseXML.js new file mode 100644 index 0000000..acf7ab2 --- /dev/null +++ b/src/static/node_modules/jquery/src/ajax/parseXML.js @@ -0,0 +1,30 @@ +define( [ + "../core" +], function( jQuery ) { + +"use strict"; + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + +return jQuery.parseXML; + +} ); diff --git a/src/static/node_modules/jquery/src/ajax/script.js b/src/static/node_modules/jquery/src/ajax/script.js new file mode 100644 index 0000000..6e0d21e --- /dev/null +++ b/src/static/node_modules/jquery/src/ajax/script.js @@ -0,0 +1,77 @@ +define( [ + "../core", + "../var/document", + "../ajax" +], function( jQuery, document ) { + +"use strict"; + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " - + - + @@ -19,14 +19,33 @@ {% block body %} {{ super ()}} {{ form | safe }} -
+
+ +
+
+
+ Year:
+
+
+
+ Score:
+
+
+
+ Gross:
+
+
+
+
+
-
+
+
-
+
diff --git a/src/templates/layout.html b/src/templates/layout.html index 94fbdde..7beed75 100644 --- a/src/templates/layout.html +++ b/src/templates/layout.html @@ -9,7 +9,7 @@ - + diff --git a/src/templates/slides.md b/src/templates/slides.md index 28b25ee..91d8b34 100644 --- a/src/templates/slides.md +++ b/src/templates/slides.md @@ -1,7 +1,7 @@ # pyDataVizDay *a python implementation for Data Viz Day* -![python](https://www.python.org/static/opengraph-icon-200x200.png) +![python](https://s3.amazonaws.com/files.dezyre.com/images/blog/Python+for+Data+Science+vs.+Python+for+Web+Development/Python+for+Data+Science+vs+Web+Devlopment.png) ---- @@ -17,22 +17,112 @@ ---- -## Pros +## Pros of Python * Fast High Level Data Science +* reusable * Powerful Web stack * Testing * Documentation * Free +--- + +### Fast High Level Data Science + +python has a vast ecosysytem for data wrangling + +``` python +import pandas as pd +import glob, os + +path = "C:/reports" +files = glob.glob(path + os.sep + '*_report.csv*') + +frames = [] +for file in files: + frames.append(pd.read_csv(file)) + +all_reports = (pd.concat(frames) + .dropna() + .query('DIVISION == ACCOUNTING') + ) + +``` + +--- + +### Reusability + +Python libraries, and objects are very easily written and reused + +``` +import etl + +data = etl.Data() +data.update() + +``` + +--- + +### Testing + +The ability to easily reuse code/datasets/plot gives us the ability to spend time making large projects more . + + +``` python +class Testdata(unittest.TestCase): + """ + Test suite for my dataframe data + """ + + def test_cols(self): + for col in important_cols: + self.assertLess(len(data[data[col].isnull()]), 0, msg=f'column {col} has unexpected null values') + self.assertIn(col, data.columns.tolist(), msg=f'column {col} is missing - check the /data/raw/shipments.csv file to ensure logistics has not changed the data format') + +``` + +--- + +### Testing *(cont.)* + +Alert us of an error before it becomes an issue + +``` python +suite = unittest.TestLoader().loadTestsFromModule(Testdata()) +results = unittest.TextTestRunner().run(suite) +if test_results.wasSuccessful(): + data.to_csv(settings.processed_data_dir + os.sep + 'processed_reports.csv') +else: + print('test failed, not saving reports') +``` + +--- + +## Documentation + +* docstrings + * help() + * ? + * fully rendered sphinx docs +* comments when absolutely necessary + +--- + +### Free + +*enough said* ---- -## Cons +## Cons on python * No GUI (Drag and Drop Environment) * Longer Learning Curve -* +* slow runtime compared to statically typed languages (c, java) +* Latest ML aglorithms are typically developed in R ---- @@ -45,6 +135,7 @@ * C3 * reveal * jquery + * jqcloud * HTML * Bootstrap @@ -65,6 +156,8 @@ * Many plugins (including reveal) * Data/viz/slides All in one place +![jupyter notebook](http://jupyter.org/assets/jupyterpreview.png) + --- ### Jupyter Dashboards @@ -80,18 +173,3 @@ * released in June ![dash](https://camo.githubusercontent.com/a1be75b74d4a47c50df7018e914d63a2e232e503/68747470733a2f2f63646e2d696d616765732d312e6d656469756d2e636f6d2f6d61782f3830302f312a44455441517136572d7079746c4e6f487a4c496144412e706e67) - ----- - -# Example -* making sure highlighting works - -``` python -import pandas as pd - -l = [1, 2, 3] - -for item in l: -print('this is an item from l') -print(l) -``` \ No newline at end of file