├── .npmignore ├── Procfile ├── web ├── assets │ ├── img │ │ ├── api.jpg │ │ ├── die.png │ │ ├── remob.jpg │ │ ├── robot.jpg │ │ ├── sfw.jpg │ │ ├── slack.png │ │ ├── recycle.png │ │ ├── t-back.jpg │ │ ├── megaphone.png │ │ ├── sos_icon.png │ │ ├── apisettings.png │ │ ├── demogif │ │ │ ├── help.gif │ │ │ ├── last.gif │ │ │ ├── sfw.gif │ │ │ ├── public.gif │ │ │ ├── random.gif │ │ │ ├── audioclip.gif │ │ │ └── UserPreferences.gif │ │ ├── UrbanSlackLogo.png │ │ ├── kitten_headphones.png │ │ └── user_profile_boy.png │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ ├── css │ │ ├── images │ │ │ └── prettyPhoto │ │ │ │ ├── default │ │ │ │ ├── loader.gif │ │ │ │ ├── sprite.png │ │ │ │ ├── sprite_x.png │ │ │ │ ├── sprite_y.png │ │ │ │ ├── default_thumb.png │ │ │ │ ├── sprite_next.png │ │ │ │ └── sprite_prev.png │ │ │ │ ├── facebook │ │ │ │ ├── btnNext.png │ │ │ │ ├── loader.gif │ │ │ │ ├── sprite.png │ │ │ │ ├── btnPrevious.png │ │ │ │ ├── contentPatternTop.png │ │ │ │ ├── default_thumbnail.gif │ │ │ │ ├── contentPatternLeft.png │ │ │ │ ├── contentPatternRight.png │ │ │ │ └── contentPatternBottom.png │ │ │ │ ├── dark_square │ │ │ │ ├── loader.gif │ │ │ │ ├── sprite.png │ │ │ │ ├── btnNext.png │ │ │ │ └── btnPrevious.png │ │ │ │ ├── dark_rounded │ │ │ │ ├── btnNext.png │ │ │ │ ├── loader.gif │ │ │ │ ├── sprite.png │ │ │ │ ├── btnPrevious.png │ │ │ │ └── contentPattern.png │ │ │ │ ├── light_rounded │ │ │ │ ├── btnNext.png │ │ │ │ ├── loader.gif │ │ │ │ ├── sprite.png │ │ │ │ └── btnPrevious.png │ │ │ │ └── light_square │ │ │ │ ├── btnNext.png │ │ │ │ ├── sprite.png │ │ │ │ └── btnPrevious.png │ │ ├── style.css │ │ ├── font-awesome.min.css │ │ └── prettyPhoto.css │ └── js │ │ ├── qsParser.js │ │ ├── custom.js │ │ ├── jquery.hoverex.min.js │ │ ├── retina-1.1.0.js │ │ ├── jquery.hoverdir.js │ │ └── jquery.isotope.min.js └── views │ ├── partial │ ├── header.ejs │ ├── footer.ejs │ └── featureGallery.ejs │ ├── history.ejs │ ├── add-success.ejs │ ├── add-fail.ejs │ ├── contributors.ejs │ ├── privacy.ejs │ ├── howto.ejs │ └── index.ejs ├── secrets.js ├── app.json ├── lib ├── feedbackConfirmation.js ├── userSettingsConfirmation.js ├── mLabHelper.js ├── slack-command-parser.js ├── urban-parser.js └── helpPage.js ├── README.md ├── .gitignore ├── LICENSE ├── package.json ├── settings.js ├── examples └── urban-api-result.json ├── test ├── sampledata.js └── tests.js └── server.js /.npmignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: node server.js 2 | -------------------------------------------------------------------------------- /web/assets/img/api.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/api.jpg -------------------------------------------------------------------------------- /web/assets/img/die.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/die.png -------------------------------------------------------------------------------- /web/assets/img/remob.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/remob.jpg -------------------------------------------------------------------------------- /web/assets/img/robot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/robot.jpg -------------------------------------------------------------------------------- /web/assets/img/sfw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/sfw.jpg -------------------------------------------------------------------------------- /web/assets/img/slack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/slack.png -------------------------------------------------------------------------------- /web/assets/img/recycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/recycle.png -------------------------------------------------------------------------------- /web/assets/img/t-back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/t-back.jpg -------------------------------------------------------------------------------- /web/assets/img/megaphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/megaphone.png -------------------------------------------------------------------------------- /web/assets/img/sos_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/sos_icon.png -------------------------------------------------------------------------------- /web/assets/img/apisettings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/apisettings.png -------------------------------------------------------------------------------- /web/assets/img/demogif/help.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/demogif/help.gif -------------------------------------------------------------------------------- /web/assets/img/demogif/last.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/demogif/last.gif -------------------------------------------------------------------------------- /web/assets/img/demogif/sfw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/demogif/sfw.gif -------------------------------------------------------------------------------- /web/assets/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /web/assets/img/UrbanSlackLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/UrbanSlackLogo.png -------------------------------------------------------------------------------- /web/assets/img/demogif/public.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/demogif/public.gif -------------------------------------------------------------------------------- /web/assets/img/demogif/random.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/demogif/random.gif -------------------------------------------------------------------------------- /web/assets/img/demogif/audioclip.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/demogif/audioclip.gif -------------------------------------------------------------------------------- /web/assets/img/kitten_headphones.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/kitten_headphones.png -------------------------------------------------------------------------------- /web/assets/img/user_profile_boy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/user_profile_boy.png -------------------------------------------------------------------------------- /web/assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /web/assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /web/assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /web/assets/img/demogif/UserPreferences.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/img/demogif/UserPreferences.gif -------------------------------------------------------------------------------- /web/assets/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /web/assets/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /web/assets/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/default/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/default/loader.gif -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/default/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/default/sprite.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/default/sprite_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/default/sprite_x.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/default/sprite_y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/default/sprite_y.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/facebook/btnNext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/facebook/btnNext.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/facebook/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/facebook/loader.gif -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/facebook/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/facebook/sprite.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/dark_square/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/dark_square/loader.gif -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/dark_square/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/dark_square/sprite.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/dark_rounded/btnNext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/dark_rounded/btnNext.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/dark_rounded/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/dark_rounded/loader.gif -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/dark_rounded/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/dark_rounded/sprite.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/dark_square/btnNext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/dark_square/btnNext.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/default/default_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/default/default_thumb.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/default/sprite_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/default/sprite_next.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/default/sprite_prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/default/sprite_prev.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/facebook/btnPrevious.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/facebook/btnPrevious.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/light_rounded/btnNext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/light_rounded/btnNext.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/light_rounded/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/light_rounded/loader.gif -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/light_rounded/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/light_rounded/sprite.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/light_square/btnNext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/light_square/btnNext.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/light_square/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/light_square/sprite.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/dark_square/btnPrevious.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/dark_square/btnPrevious.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/dark_rounded/btnPrevious.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/dark_rounded/btnPrevious.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/facebook/contentPatternTop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/facebook/contentPatternTop.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/facebook/default_thumbnail.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/facebook/default_thumbnail.gif -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/light_rounded/btnPrevious.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/light_rounded/btnPrevious.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/light_square/btnPrevious.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/light_square/btnPrevious.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/dark_rounded/contentPattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/dark_rounded/contentPattern.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/facebook/contentPatternLeft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/facebook/contentPatternLeft.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/facebook/contentPatternRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/facebook/contentPatternRight.png -------------------------------------------------------------------------------- /web/assets/css/images/prettyPhoto/facebook/contentPatternBottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matijaabicic/urban-slack/HEAD/web/assets/css/images/prettyPhoto/facebook/contentPatternBottom.png -------------------------------------------------------------------------------- /secrets.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | secret_slack_client_ID : "13455138151.25936209731", 3 | secret_slack_client_secret : "3ee871c03671b3a402683e0302692fa5", 4 | mLabApiKey : "aNodXH4adiiyJQ3Y8JEThoi-VOOc0Y7K" 5 | }; 6 | -------------------------------------------------------------------------------- /web/assets/js/qsParser.js: -------------------------------------------------------------------------------- 1 | function qs(search_for) { 2 | var query = window.location.search.substring(1); 3 | var parms = query.split('&'); 4 | for (var i=0; i 0 && search_for == parms[i].substring(0,pos)) { 7 | return parms[i].substring(pos+1); 8 | } 9 | } 10 | return ""; 11 | } 12 | -------------------------------------------------------------------------------- /web/assets/js/custom.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 3 | // prettyPhoto 4 | jQuery(document).ready(function(){ 5 | jQuery('a[data-gal]').each(function() { 6 | jQuery(this).attr('rel', jQuery(this).data('gal')); 7 | }); 8 | jQuery("a[data-rel^='prettyPhoto']").prettyPhoto({animationSpeed:'slow',theme:'light_square',slideshow:false,overlay_gallery: false,social_tools:false,deeplinking:false}); 9 | }); 10 | 11 | 12 | })(jQuery); -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Urban Slack", 3 | "description": "Urban Dictionary Slack Bot", 4 | "repository": "https://github.com/matijaabicic/urban-slack", 5 | "logo": "https://urban-slack.herokuapps.com/assets/img/UrbanSlackLogo.png", 6 | "keywords": ["Urban", "Dictionary", "Slack", "Bot", "Node", "NodeJS"], 7 | "env": { 8 | "secret_slack_client_ID": "-- your own Slack Client ID --", 9 | "secret_slack_client_secret": "-- your own Slack Client Secret --" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/feedbackConfirmation.js: -------------------------------------------------------------------------------- 1 | exports.confirm = function (){ 2 | var returnData = {}; 3 | returnData.response_type = 'ephemeral'; 4 | returnData.username = "UrbanSlack"; 5 | 6 | // #43 in v1.1.0 - implemented in-app feedback with --feedback switch 7 | returnData.text = "Your feedback is much appreciated!! Thank you for asking to make Urban Slack better. Feel free to get in touch with @matijaabicic on Twitter and don't forget to check out https://urban-slack.herokuapp.com for details on how to get involved."; 8 | return returnData; 9 | }; 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # urban-slack 2 | #### Urban Dictionary Slack Bot 3 | 4 | Check it out at [Urban Slack Webpage](https://urban-slack.herokuapp.com) 5 | 6 | 7 | Is your team on a free plan and you're all out of integrations? No problem. You can use Urban Slack as a Service by pointing your manual Slack slash commands at: 8 | ``` 9 | https://urban-slack.herokuapp.com/api 10 | ``` 11 | 12 | Usage tip: `/urban ?` will give you a list of available commands. 13 | 14 | .urban-slack responds to your slack channel under UrbanSlack username. 15 | 16 | Check **[Issues](https://github.com/matijaabicic/urban-slack/issues)** page for bugs and feature requests. 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | 35 | # Secret files and other stuff 36 | secrets.js 37 | app.json 38 | .env 39 | .node-xmlhttprequest* 40 | package-lock.json 41 | 42 | # OS X stuff 43 | *DS_Store 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Matija Abicic 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. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "urban-slack", 3 | "version": "1.3.0", 4 | "description": "Urban Dictionary Slack bot", 5 | "main": "server.js", 6 | "directories": { 7 | "example": "examples" 8 | }, 9 | "scripts": { 10 | "test": "mocha test/tests.js", 11 | "start": "node server.js" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/matijaabicic/urban-slack.git" 16 | }, 17 | "keywords": [ 18 | "urban-slack", 19 | "urban", 20 | "dictionary", 21 | "urban", 22 | "dictionary", 23 | "slack", 24 | "bot" 25 | ], 26 | "author": "@matijaabicic", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/matijaabicic/urban-slack/issues" 30 | }, 31 | "homepage": "https://github.com/matijaabicic/urban-slack", 32 | "dependencies": { 33 | "body-parser": "latest", 34 | "ejs": "latest", 35 | "express": "^4.17.1", 36 | "fs": "latest", 37 | "hashmap": "latest", 38 | "http": "0.0.0", 39 | "mongolab-data-api": "latest", 40 | "node-supervisor": "^1.0.2", 41 | "request": "latest", 42 | "supervisor": "^0.12.0", 43 | "swearjar": "latest", 44 | "universal-analytics": "latest" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /web/views/partial/header.ejs: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /web/views/partial/footer.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

Contact the Creator

6 |
7 |

Feel free to contact me regarding any bugs, feature requests, help, support and general questions via one of the following channels:

8 |

9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |

18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /settings.js: -------------------------------------------------------------------------------- 1 | //app-specific sentence 2 | 3 | module.exports = { 4 | debug : false, 5 | serverPort : 5000, 6 | GA : 'UA-74299720-1', // Google analytics tracking ID 7 | urbanAPI : 'http://api.urbandictionary.com/v0/define?term=', 8 | randomUrbanAPI : 'http://api.urbandictionary.com/v0/random', 9 | gaIgnoreHosts : ['localhost:8080', 'localhost:5000', 'urban-slack.com'], //list of hosts to be ignored on API paths 10 | 11 | //slack response modes: 12 | // ephemeral - only visible to user who isseus the slash command 13 | // in_channel - visible to everyone in the chat window (direct, group, channel) 14 | defaultSlackResponseMode : 'ephemeral', 15 | 16 | //slackOAuthURI : 'https://slack.com/api/oauth.access', 17 | slackOAuthURI : 'https://slack.com/oauth/v2/authorize?client_id=', 18 | slackRedirectURI_local : 'http://localhost:5000/AddSlack', 19 | slackRedirectURI_heroku : 'https://urban-slack.herokuapp.com/AddSlack', 20 | mongoDBName : 'urbanslack', 21 | 22 | //by default, do not filter out profanity. 23 | defaultRating : 'nsfw', 24 | 25 | //by default, do not randomize responses 26 | defaultRandomSetting : false, 27 | 28 | // #43 - frequency for prompting for feedback. 29 | feedbackPromptInterval : 50 30 | }; 31 | -------------------------------------------------------------------------------- /lib/userSettingsConfirmation.js: -------------------------------------------------------------------------------- 1 | exports.confirm = function (settings){ 2 | var returnData = {}; 3 | returnData.response_type = 'ephemeral'; 4 | returnData.username = "UrbanSlack"; 5 | 6 | // #41 in v1.0.2 - check that the user has indeed set defaults 7 | if (!settings){ 8 | returnData.text = "You have no default settings. Use --set switch to set your settings. See help page for more info."; 9 | } 10 | else { 11 | returnData.text = (settings.getSettings) ? 'You have previously set default user settings.' : 'Default user settings are now confirmed.'; 12 | var privacy = (settings.responseType == "ephemeral") ? "Empemeral (only you can see)" : "In-channel (everone can see)"; 13 | var cleanliness = (settings.rating == "nsfw") ? "NSFW (not safe for work)" : "SFW (safe for work)"; 14 | var randomness = settings.random ? "Random matching phrase" : "Non-random, best match"; 15 | 16 | returnData.attachments = [ 17 | { 18 | "pretext" : "Your default settings are", 19 | "fields" : [ 20 | { 21 | "title":"Privacy", 22 | "value":privacy, 23 | "short":true 24 | }, 25 | { 26 | "title":"Cleanliness", 27 | "value":cleanliness, 28 | "short":true 29 | }, 30 | { 31 | "title":"Randomness", 32 | "value":randomness, 33 | "short":true 34 | } 35 | ] 36 | } 37 | ]; 38 | } 39 | return returnData; 40 | }; 41 | -------------------------------------------------------------------------------- /examples/urban-api-result.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags": [ 3 | "beer", 4 | "drunk", 5 | "the office", 6 | "bintang", 7 | "breezy time", 8 | "brew", 9 | "alcohol", 10 | "andy", 11 | "beer run", 12 | "beers" 13 | ], 14 | "result_type": "exact", 15 | "list": [ 16 | { 17 | "defid": 2398646, 18 | "word": "beer me", 19 | "author": "Bench", 20 | "permalink": "http://beer-me.urbanup.com/2398646", 21 | "definition": "Besides the obvious \"give me a beer,\" it is used to ask someone to pass or hand an object to you. It also can be used in a more figurative sense as a request or plea.\r\n\r\nUsed by character Andy in \"Product Recall\" ep. of \"The Office\" (\"the joke only gets a laugh 25% of the time\").", 22 | "example": "Hey, beer me that torque wrench.\r\n\r\nLord, beer me strength.", 23 | "thumbs_up": 6160, 24 | "thumbs_down": 1940, 25 | "current_vote": "" 26 | }, 27 | { 28 | "defid": 2389055, 29 | "word": "beer me", 30 | "author": "Elias Creed", 31 | "permalink": "http://beer-me.urbanup.com/2389055", 32 | "definition": "1.) Generally used to ask for another beer.\r\n\r\n2.) Can be substituted for the term \"give me\" (if you're a total [dutchbag]) ala The Office\r\n", 33 | "example": "\"Mike, you're closest to the fridge, fucking beer me bro.\"\r\n\r\n\"Hey Jim, beer me that water\"\r\n\r\n\"God beer me strength\"", 34 | "thumbs_up": 271, 35 | "thumbs_down": 151, 36 | "current_vote": "" 37 | }, 38 | { 39 | "defid": 2013245, 40 | "word": "beer me", 41 | "author": "Pompous Smurf", 42 | "permalink": "http://beer-me.urbanup.com/2013245", 43 | "definition": "Slang for get me a beer....the act of needing a beer, espically when somebody is on their way to the fridge to get another. ", 44 | "example": "I'm runnin low, beer me.", 45 | "thumbs_up": 102, 46 | "thumbs_down": 53, 47 | "current_vote": "" 48 | }, 49 | { 50 | "defid": 2391548, 51 | "word": "beer me", 52 | "author": "z-d", 53 | "permalink": "http://beer-me.urbanup.com/2391548", 54 | "definition": "1. vi. An invitation to hand or throw the speaker a beer.\r\n2. vt. An invitation to hand or throw the speaker an object.", 55 | "example": "1. I'm so getting wasted tonight. Beer me.\r\n2. Hey, can you beer me that CD? My girlfriend's compiled an awesome mix.", 56 | "thumbs_up": 42, 57 | "thumbs_down": 43, 58 | "current_vote": "" 59 | } 60 | ], 61 | "sounds": [] 62 | } 63 | -------------------------------------------------------------------------------- /web/assets/js/jquery.hoverex.min.js: -------------------------------------------------------------------------------- 1 | !function(a){var b={fn:{moveZoom:function(a,b){var i,c=a.height(),d=a.width(),e=b.pageY-a.offset().top,f=b.pageX-a.offset().left,g=a.find("img"),h=a.data("zoom");h&&"auto"!=h?(i=parseFloat(h),g.css({width:d*i+"px",height:c*i+"px",top:-e*(i-1)+"px",left:-f*(i-1)+"px"})):(i=g.width()/d,g.css({top:-e*(i-1)+"px",left:-f*(i-1)+"px"}))},changeZoom:function(a,c,d,e,f){var i,j,k,l,m,n,g=a.find("img"),h=a.data("zoom");h="auto"==h?g.width()/a.width():parseFloat(h),i=a.data("zoomstep"),i=i?parseFloat(i):.5,j=a.data("zoomrange"),j=j?j.split(","):"1,4",k=parseFloat(j[0]),l=parseFloat(j[1])>h?parseFloat(j[1]):h,m=f>0?1:-1,n=Math.round(10*(h+i*m))/10,n>=k&&l>=n&&(a.data("zoom",n),b.fn.showZoomState(a,n),b.fn.moveZoom(a,c))},showZoomState:function(b,c){var d=b.find(".he-zoomstate");0==d.length&&(d=a(''+c+"X").appendTo(b)),d.text(c+"X").stop(!0,!0).fadeIn(300).delay(200).fadeOut(300)},switchImg:function(a,b){var d,e,c=a.data("animate");c=c?c:"random","random"==c&&(d=["fadeIn","fadeInLeft","fadeInRight","fadeInUp","fadeInDown","rotateIn","rotateInLeft","rotateInRight","rotateInUp","rotateInDown","bounce","bounceInLeft","bounceInRight","bounceInUp","bounceInDown","elasticInLeft","elasticInRight","elasticInUp","elasticInDown","zoomIn","zoomInLeft","zoomInRight","zoomInUp","zoomInDown","jellyInLeft","jellyInRight","jellyInDown","jellyInUp","flipInLeft","flipInRight","flipInUp","flipInDown","flipInV","flipInH"],c=d[Math.floor(Math.random()*d.length)]),e=a.find("img"),e.length>1&&(b>0?(e.eq(0).attr("class","a0").appendTo(a),e.eq(1).attr("class","a0 "+c)):(e.eq(e.length-1).attr("class","a0 "+c).prependTo(a),e.eq(0).attr("class","a0")))}}};a(function(){a(document).on("mouseenter",".he-wrap",function(){var b=a(this).find(".he-view").addClass("he-view-show");a("[data-animate]",b).each(function(){var b=a(this).data("animate");a(this).addClass(b)}),a(this).find(".he-zoom").addClass("he-view-show")}).on("mouseleave",".he-wrap",function(){var b=a(this).find(".he-view").removeClass("he-view-show");a("[data-animate]",b).each(function(){var b=a(this).data("animate");a(this).removeClass(b)}),a(this).find(".he-zoom").removeClass("he-view-show")}).on("mousewheel",".he-wrap",function(c,d,e,f){var g,h,i;1==a(this).find(".he-sliders").length?(g=a(this).find(".he-sliders"),h=f>0?1:-1,b.fn.switchImg(g,h),c.preventDefault()):1==a(this).find(".he-zoom").length&&(i=a(this).find(".he-zoom"),b.fn.changeZoom(i,c,d,e,f),c.preventDefault())}).on("mousemove",".he-zoom",function(c){b.fn.moveZoom(a(this),c)}).on("click",".he-pre",function(){var c=a(this).parents(".he-wrap").find(".he-sliders");b.fn.switchImg(c,-1)}).on("click",".he-next",function(){var c=a(this).parents(".he-wrap").find(".he-sliders");b.fn.switchImg(c,1)})})}(jQuery),function(a){function d(b){var c=b||window.event,d=[].slice.call(arguments,1),e=0,g=0,h=0;return b=a.event.fix(c),b.type="mousewheel",c.wheelDelta&&(e=c.wheelDelta/120),c.detail&&(e=-c.detail/3),h=e,void 0!==c.axis&&c.axis===c.HORIZONTAL_AXIS&&(h=0,g=-1*e),void 0!==c.wheelDeltaY&&(h=c.wheelDeltaY/120),void 0!==c.wheelDeltaX&&(g=-1*c.wheelDeltaX/120),d.unshift(b,e,g,h),(a.event.dispatch||a.event.handle).apply(this,d)}var c,b=["DOMMouseScroll","mousewheel"];if(a.event.fixHooks)for(c=b.length;c;)a.event.fixHooks[b[--c]]=a.event.mouseHooks;a.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=b.length;a;)this.addEventListener(b[--a],d,!1);else this.onmousewheel=d},teardown:function(){if(this.removeEventListener)for(var a=b.length;a;)this.removeEventListener(b[--a],d,!1);else this.onmousewheel=null}},a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})}(jQuery); -------------------------------------------------------------------------------- /lib/mLabHelper.js: -------------------------------------------------------------------------------- 1 | var settings = require("../settings"); 2 | var secrets = require('../secrets'); 3 | var mLabKey = (process.env.mLabApiKey ? process.env.mLabApiKey : secrets.mLabApiKey); 4 | var mlab = require('mongolab-data-api')(mLabKey); 5 | 6 | // GetLastQuery 7 | // Returns the latest query that returned exact results 8 | exports.GetLastQuery = function(){ 9 | var result = null; 10 | var queryOptions = { 11 | "database" : settings.mongoDBName, 12 | "collectionName" : "phrases", 13 | "query" : '{"result_type" : "exact"}', 14 | "limit" : 1, 15 | "sortOrder" : '{"datetime":-1}' 16 | }; 17 | 18 | mlab.listDocuments(queryOptions, function(err, data){ 19 | if(!err){ 20 | result = JSON.stringify(data[0].queryText); 21 | } 22 | else{ 23 | result = err; 24 | } 25 | }); 26 | return result; 27 | }; 28 | //end GetLastQuery 29 | 30 | exports.GetLastQueryForUser = function(team_id, user_id){ 31 | var result = null; 32 | 33 | var queryOptions = { 34 | "database" : settings.mongoDBName, 35 | "collectionName" : "phrases", 36 | "query" : '{"team_id" : "' + team_id +'","user_id" : "' + user_id + '"}', 37 | "limit" : 1, 38 | "sortOrder" : '{"datetime":-1}' 39 | }; 40 | 41 | mlab.listDocuments(queryOptions, function(err, data){ 42 | if(!err){ 43 | //get rid of " marks 44 | result = JSON.stringify(data[0].queryText).replace(/\"/g, ''); 45 | } 46 | else { 47 | result = err; 48 | } 49 | }); 50 | 51 | return result; 52 | }; 53 | 54 | //update user settings 55 | exports.UpdateUserSettings = function(userKey, userSettings) 56 | { 57 | //prepare mongo api query 58 | var queryOptions = { 59 | "database" : settings.mongoDBName, 60 | "collectionName" : "userSettings", 61 | "data" : { 62 | "userKey" :userKey, 63 | "userValue" : userSettings 64 | }, 65 | "query" : '{"userKey" : "' + userKey +'"}', 66 | "upsert" : true 67 | }; 68 | 69 | //fire off the mogno api query 70 | mlab.updateDocuments(queryOptions, function(err, data){ 71 | //debug only 72 | if(!err){ 73 | //console.log("Saved user settings successfully."); 74 | } 75 | else { 76 | //console.log("Something went wrong"); 77 | } 78 | }); 79 | }; 80 | //end updating user settings 81 | 82 | 83 | //return all user settings 84 | exports.GetAllUserSettings = function(){ 85 | var result = null; 86 | 87 | //hit up mongo and return all user settings. 88 | var queryOptions = { 89 | "database" : settings.mongoDBName, 90 | "collectionName" : "userSettings", 91 | }; 92 | 93 | mlab.listDocuments(queryOptions, function(err, data){ 94 | if(!err) 95 | { 96 | result = data; 97 | } 98 | else{ 99 | console.log("Error getting default user settings from database"); 100 | } 101 | }); 102 | 103 | return result; 104 | }; 105 | //end of all user settings 106 | 107 | // #43 - insert user feedback 108 | exports.insertUserFeedback = function(userFeedback){ 109 | //set the query to write to feedback collection 110 | var queryOptions = { 111 | "database" : settings.mongoDBName, 112 | "collectionName" : "feedback", 113 | "documents" : 114 | { 115 | "feedback" : userFeedback 116 | } 117 | }; 118 | // write to mLabKey 119 | mlab.insertDocuments(queryOptions, function(err, data){ 120 | if(err){console.log(err);} 121 | }); 122 | }; 123 | 124 | // built for #43 - periodically prompt people for feedback 125 | exports.getTotalNumberOfUserQueries = function(){ 126 | 127 | var queryOptions = { 128 | "database" : settings.mongoDBName, 129 | "collectionName" : "phrases", 130 | "resultCount" : true 131 | }; 132 | mlab.listDocuments(queryOptions, function(err, data){ 133 | if(!err){ 134 | return data; 135 | } 136 | else return -1; 137 | }); 138 | }; 139 | -------------------------------------------------------------------------------- /lib/slack-command-parser.js: -------------------------------------------------------------------------------- 1 | var settings = require('../settings'); 2 | 3 | //sanitizer helper. 4 | var sanitizer = function(input){ 5 | var output = ''; 6 | 7 | //convert & to %26 8 | output = input.replace('&', '%26'); 9 | 10 | return output; 11 | }; 12 | 13 | // Added userDefaults in v1.0.0 to address #26 - User default settings 14 | module.exports.parse = function (preParsedCommandText, userDefaultSettings){ 15 | var result = {}; 16 | var commandText = preParsedCommandText; 17 | //look for "public and private switches switch" 18 | //there is a hierarhy implied here 19 | // - first look for private, then public, default to settings.js 20 | // — is the os x autocorrection of -- 21 | if (commandText.match(/--private/g) || commandText.match(/—private/g)){ 22 | result.responseType = 'ephemeral'; 23 | //remove switch from response 24 | commandText = commandText.replace(/--private/g, '').replace(/—private/g, ''); 25 | } 26 | else if (commandText.match(/--public/g) || commandText.match(/—public/g)) 27 | { 28 | result.responseType = "in_channel"; 29 | commandText = commandText.replace(/--public/g, '').replace(/—public/g, ''); 30 | } 31 | // Added userDefaults in v1.0.0 to address #26 - User default settings 32 | else if (userDefaultSettings) 33 | { 34 | result.responseType = userDefaultSettings.responseType; 35 | } 36 | else{ 37 | result.responseType = settings.defaultSlackResponseMode; 38 | } 39 | 40 | // #43 - accept feedback with --feedback switch 41 | if (commandText.match(/--feedback/g) || commandText.match(/—feedback/g)){ 42 | result.feedback = true; 43 | commandText = commandText.replace(/—feedback/g, '').replace(/--feedback/g,''); 44 | } 45 | 46 | // #45 - ability to produce a random (surprise) definition 47 | if (commandText.match(/--surprise/g) || commandText.match(/—surprise/g)){ 48 | result.surprise = true; 49 | } 50 | 51 | //look for "sfw" switch. will be used to censor the output. 52 | if (commandText.match(/--sfw/g) || commandText.match(/—sfw/g)){ 53 | result.rating = 'sfw'; 54 | commandText = commandText.replace(/--sfw/g, '').replace(/—sfw/g, ''); 55 | } 56 | else if (commandText.match(/--nsfw/g) || commandText.match(/—nsfw/g)){ 57 | result.rating = 'nsfw'; 58 | commandText = commandText.replace(/—nsfw/g, '').replace(/--nsfw/g,''); 59 | } 60 | // Added userDefaults in v1.0.0 to address #26 - User default settings 61 | else if (userDefaultSettings) 62 | { 63 | result.rating = userDefaultSettings.rating; 64 | } 65 | else{ 66 | result.rating = settings.defaultRating; 67 | } 68 | 69 | //look for "random" switch. will be used to censor the output. 70 | if (commandText.match(/--random/g) || commandText.match(/—random/g)){ 71 | result.random = true; 72 | commandText = commandText.replace(/—random/g, '').replace(/--random/g,''); 73 | } 74 | // Also parsing --norandom in v1.0.0, to support switching default values in #26 75 | else if (commandText.match(/--norandom/g) || commandText.match(/—norandom/g)){ 76 | result.random = false; 77 | commandText = commandText.replace(/—norandom/g, '').replace(/--norandom/g,''); 78 | } 79 | // Added userDefaults in v1.0.0 to address #26 - User default settings 80 | else if (userDefaultSettings) 81 | { 82 | result.random = userDefaultSettings.random; 83 | } 84 | else{ 85 | result.random = settings.defaultRandomSetting; 86 | } 87 | 88 | //look for "last" switch. will be used to retrieve user's last query 89 | if (commandText.match(/--last/g) || commandText.match(/—last/g)){ 90 | result.last = true; 91 | commandText = ""; 92 | } 93 | 94 | // #26 - look for --set switch. will be used to set defaults for the user 95 | if (commandText.match(/--set/g) || commandText.match(/—set/g)){ 96 | result.defaults = true; 97 | commandText = commandText.replace(/—set/g, '').replace(/--set/g,''); 98 | } 99 | // #41 - return user settings with --mysettings switch 100 | if (commandText.match(/--mysettings/g) || commandText.match(/—mysettings/g)){ 101 | result.mysettings = true; 102 | commandText = commandText.replace(/—mysettings/g, '').replace(/--mysettings/g,''); 103 | } 104 | 105 | //now that we have picked up the switches and switches have been stripped out 106 | //return the cleaned-up command 107 | result.Command = sanitizer(commandText); 108 | return result; 109 | }; 110 | -------------------------------------------------------------------------------- /web/assets/js/retina-1.1.0.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Retina.js v1.1.0 3 | * 4 | * Copyright 2013 Imulus, LLC 5 | * Released under the MIT license 6 | * 7 | * Retina.js is an open source script that makes it easy to serve 8 | * high-resolution images to devices with retina displays. 9 | */ 10 | (function() { 11 | 12 | var root = (typeof exports == 'undefined' ? window : exports); 13 | 14 | var config = { 15 | // Ensure Content-Type is an image before trying to load @2x image 16 | // https://github.com/imulus/retinajs/pull/45) 17 | check_mime_type: true 18 | }; 19 | 20 | 21 | 22 | root.Retina = Retina; 23 | 24 | function Retina() {} 25 | 26 | Retina.configure = function(options) { 27 | if (options == null) options = {}; 28 | for (var prop in options) config[prop] = options[prop]; 29 | }; 30 | 31 | Retina.init = function(context) { 32 | if (context == null) context = root; 33 | 34 | var existing_onload = context.onload || new Function; 35 | 36 | context.onload = function() { 37 | var images = document.getElementsByTagName("img"), retinaImages = [], i, image; 38 | for (i = 0; i < images.length; i++) { 39 | image = images[i]; 40 | retinaImages.push(new RetinaImage(image)); 41 | } 42 | existing_onload(); 43 | } 44 | }; 45 | 46 | Retina.isRetina = function(){ 47 | var mediaQuery = "(-webkit-min-device-pixel-ratio: 1.5),\ 48 | (min--moz-device-pixel-ratio: 1.5),\ 49 | (-o-min-device-pixel-ratio: 3/2),\ 50 | (min-resolution: 1.5dppx)"; 51 | 52 | if (root.devicePixelRatio > 1) 53 | return true; 54 | 55 | if (root.matchMedia && root.matchMedia(mediaQuery).matches) 56 | return true; 57 | 58 | return false; 59 | }; 60 | 61 | 62 | root.RetinaImagePath = RetinaImagePath; 63 | 64 | function RetinaImagePath(path, at_2x_path) { 65 | this.path = path; 66 | if (typeof at_2x_path !== "undefined" && at_2x_path !== null) { 67 | this.at_2x_path = at_2x_path; 68 | this.perform_check = false; 69 | } else { 70 | this.at_2x_path = path.replace(/\.\w+$/, function(match) { return "@2x" + match; }); 71 | this.perform_check = true; 72 | } 73 | } 74 | 75 | RetinaImagePath.confirmed_paths = []; 76 | 77 | RetinaImagePath.prototype.is_external = function() { 78 | return !!(this.path.match(/^https?\:/i) && !this.path.match('//' + document.domain) ) 79 | } 80 | 81 | RetinaImagePath.prototype.check_2x_variant = function(callback) { 82 | var http, that = this; 83 | if (this.is_external()) { 84 | return callback(false); 85 | } else if (!this.perform_check && typeof this.at_2x_path !== "undefined" && this.at_2x_path !== null) { 86 | return callback(true); 87 | } else if (this.at_2x_path in RetinaImagePath.confirmed_paths) { 88 | return callback(true); 89 | } else { 90 | http = new XMLHttpRequest; 91 | http.open('HEAD', this.at_2x_path); 92 | http.onreadystatechange = function() { 93 | if (http.readyState != 4) { 94 | return callback(false); 95 | } 96 | 97 | if (http.status >= 200 && http.status <= 399) { 98 | if (config.check_mime_type) { 99 | var type = http.getResponseHeader('Content-Type'); 100 | if (type == null || !type.match(/^image/i)) { 101 | return callback(false); 102 | } 103 | } 104 | 105 | RetinaImagePath.confirmed_paths.push(that.at_2x_path); 106 | return callback(true); 107 | } else { 108 | return callback(false); 109 | } 110 | } 111 | http.send(); 112 | } 113 | } 114 | 115 | 116 | 117 | function RetinaImage(el) { 118 | this.el = el; 119 | this.path = new RetinaImagePath(this.el.getAttribute('src'), this.el.getAttribute('data-at2x')); 120 | var that = this; 121 | this.path.check_2x_variant(function(hasVariant) { 122 | if (hasVariant) that.swap(); 123 | }); 124 | } 125 | 126 | root.RetinaImage = RetinaImage; 127 | 128 | RetinaImage.prototype.swap = function(path) { 129 | if (typeof path == 'undefined') path = this.path.at_2x_path; 130 | 131 | var that = this; 132 | function load() { 133 | if (! that.el.complete) { 134 | setTimeout(load, 5); 135 | } else { 136 | that.el.setAttribute('width', that.el.offsetWidth); 137 | that.el.setAttribute('height', that.el.offsetHeight); 138 | that.el.setAttribute('src', path); 139 | } 140 | } 141 | load(); 142 | } 143 | 144 | 145 | 146 | 147 | if (Retina.isRetina()) { 148 | Retina.init(root); 149 | } 150 | 151 | })(); 152 | 153 | -------------------------------------------------------------------------------- /lib/urban-parser.js: -------------------------------------------------------------------------------- 1 | var swearjar = require('swearjar'); 2 | 3 | //module.exports.parse = function (bodyString, responseType, filter){ 4 | // changed in v0.4.1 to pass back the entire parsed Command 5 | exports.parse = function (bodyString, parsedCommand){ 6 | 7 | //prepare the data to return to Slack 8 | var returnData = {}; 9 | var chosenDefinition = 0; 10 | returnData.response_type = parsedCommand.responseType; 11 | returnData.username = "UrbanSlack"; 12 | 13 | if(bodyString){ 14 | //return bodyString.list[0].definition; 15 | var data = JSON.parse(bodyString); 16 | 17 | switch(data.result_type) 18 | { 19 | // #45 - random lookup don't come with result type element. 20 | // added in v1.2.0 as a special case 21 | case (undefined && parsedCommand.surprise): 22 | case "exact": 23 | { 24 | var numberOfDefinitions = data.list.length; 25 | 26 | if (numberOfDefinitions > 0) 27 | { 28 | 29 | //#33 implemented here in v0.4.2 30 | if(parsedCommand.random) 31 | { 32 | //choose a random number between 0 and [number of definitions returned 33 | // from dictionary] 34 | chosenDefinition = Math.floor(Math.random() * numberOfDefinitions); 35 | } 36 | 37 | var definition = data.list[chosenDefinition].definition; 38 | var example = data.list[chosenDefinition].example; 39 | var permalink = data.list[chosenDefinition].permalink; 40 | 41 | //if we need to censor out NSFW stuff...better get to it before we send a response back. 42 | if (parsedCommand.rating=="sfw"){ 43 | definition = swearjar.censor(definition); 44 | example = swearjar.censor(example); 45 | } 46 | var promptForFeedbackString = ""; 47 | if (parsedCommand.prompt) 48 | { 49 | promptForFeedbackString = "This is a random prompt for feedback. Feel free to use `/urban --feedback Your Feedback Here` to tell us what you think about Urban Slack.\n"; 50 | } 51 | returnData.text = promptForFeedbackString + '*DEFINITION (' + (chosenDefinition + 1) + ' of ' + numberOfDefinitions +'):* ' + definition; 52 | 53 | returnData.attachments = [ 54 | { 55 | "title":"Example use", "text": example 56 | }]; 57 | 58 | //add a sound if it's contained in the response 59 | // #45 - random (surprise) results don't return the sounds node. safe check. 60 | if (!parsedCommand.surprise && data.sounds){ 61 | if (data.sounds.length > 0){ 62 | //#33 randomize the sounds as well in v0.4.2 63 | if(parsedCommand.random) 64 | { 65 | //choose a random number between 0 and [number of definitions returned 66 | // from dictionary] 67 | chosenDefinition = Math.floor(Math.random() * data.sounds.length); 68 | } 69 | 70 | returnData.attachments.push({ 71 | "title" : "Hear it :sound:", 72 | "title_link" : data.sounds[chosenDefinition], 73 | "short" : true 74 | }); 75 | } 76 | } 77 | 78 | // #10 implemented in v0.5 - add link for more definitions 79 | if(numberOfDefinitions > 1){ 80 | returnData.attachments.push({ 81 | "title" : "See more definitions", 82 | "title_link" : permalink, 83 | "short" : true 84 | }); 85 | } 86 | 87 | } 88 | else 89 | { 90 | returnData.text = 'No definitions found. Use /urban ? for help or go to https://urban-slack.herokuapp.com for help.'; 91 | } 92 | } 93 | break; 94 | 95 | case "no_results": 96 | { 97 | returnData.text = 'No definitions found. Use /urban ? for help or go to https://urban-slack.herokuapp.com for help.'; 98 | } 99 | break; 100 | 101 | default: 102 | { 103 | returnData.text = "No definitions found. Use /urban ? for help or go to https://urban-slack.herokuapp.com for help."; // throw "Unexpected behaviour."; 104 | } 105 | } 106 | } 107 | else //service should return response even if there are no entries so I conclude there is something wrong with it 108 | { 109 | returnData.text = 'Dictionary service unavailable.'; 110 | } 111 | 112 | //return slack response. 113 | return returnData; 114 | }; 115 | -------------------------------------------------------------------------------- /web/views/history.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Urban 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | <%- include ("./partial/header") -%> 42 | 43 | 44 | 45 | 48 |
49 |
50 |
51 |
52 |

Version History

53 |
54 |
55 |
56 |
57 | 58 | 61 |
62 |
63 |
64 | <% if (releases.length > 0) { %> 65 | 66 | <% releases.forEach(function(release) { %> 67 | 68 | 69 | 70 | 71 | 72 | <% }); %> 73 |
Release <%= release.tag_name %>

<%=release.name %>


<%=release.body %>

<%=release.created_at %>

74 | <% } else { %> 75 |

PROBLEM OCCURED WHILE GETTING DATA FROM GITHUB

76 |

Head over to Urban Github Repo and see the list while we deal with the problem

77 | <% } %> 78 |
79 |
80 |
81 | 82 | 84 | 85 | <%- include ("./partial/footer") -%> 86 | 87 | 88 | 89 | 90 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /lib/helpPage.js: -------------------------------------------------------------------------------- 1 | module.exports.help = function (responseType, req_command){ 2 | var returnData = {}; 3 | returnData.response_type = responseType; 4 | returnData.username = "UrbanSlack"; 5 | returnData.text = 'Usage: ' + req_command + ' [switch] phrase. For more see https://urban-slack.herokuapp.com/howto'; 6 | returnData.attachments = [ 7 | { 8 | "pretext" : "Response type switches available (Default: --private - visible only to user issuing the query)", 9 | "fields" : [ 10 | { 11 | "title":"Publically visible", 12 | "value":"--public", 13 | "short":true 14 | }, 15 | { 16 | "title":"Private", 17 | "value":"--private", 18 | "short":true 19 | } 20 | ] 21 | }, 22 | { 23 | "pretext" : "Profanity filtering switches available (Default: --nsfw - Not safe for work. Because it's more fun that way.). If you use --sfw switch, all naughty-naughty words will be f**** censored", 24 | "fields" : [ 25 | { 26 | "title":"Safe For Work (SFW)", 27 | "value":"--sfw", 28 | "short":true 29 | }, 30 | { 31 | "title":"Not Safe For Work (NSFW)", 32 | "value":"--nsfw", 33 | "short":true 34 | } 35 | ] 36 | }, 37 | { 38 | "pretext" : "Random factor always makes things more fun. This will return a random definition for a search query instead of the most-upvoted one.", 39 | "fields" : [ 40 | { 41 | "title":"Random", 42 | "value":"--random", 43 | "short":true 44 | }, 45 | { 46 | "title":"Non-Random", 47 | "value":"--norandom", 48 | "short":true 49 | } 50 | ] 51 | }, 52 | { 53 | "pretext" : "Feeling lucky? Why not --surprise yourself and yoru channel. --surprise gives you a completely random phrase.", 54 | "fields" : [ 55 | { 56 | "title" : "Surprise", 57 | "value" : "--surprise", 58 | "short" : true 59 | } 60 | ] 61 | }, 62 | { 63 | "pretext" : "Don't botheer retyping that long phrase just to make make it --public. Just use --last", 64 | "fields" : [ 65 | { 66 | "title" : "Last", 67 | "value" : "--last", 68 | "short" : true 69 | } 70 | ] 71 | }, 72 | { 73 | "pretext" : "Tell Urban Slack to remember your user preferences. It's easy.", 74 | "fields" : [ 75 | { 76 | "title" : "User Preferences", 77 | "value" : "--set " 78 | } 79 | ] 80 | }, 81 | { 82 | "pretext" : "Example use cases", 83 | "fields" : [ 84 | { 85 | "title":"Example use 1:", 86 | "value":req_command + ' FOMO', 87 | "short":true 88 | }, 89 | { 90 | "title":"Example use 2:", 91 | "value":req_command + ' --public FOMO --random', 92 | "short":true 93 | }, 94 | { 95 | "title":"Example use 3:", 96 | "value":req_command + ' --private FOMO', 97 | "short":true 98 | }, 99 | { 100 | "title":"Example use 4:", 101 | "value":req_command + ' --sfw --random FOMO', 102 | "short":true 103 | }, 104 | { 105 | "title":"Example use 5:", 106 | "value":req_command + ' --public --sfw FOMO', 107 | "short":true 108 | }, 109 | { 110 | "title":"Example use 6:", 111 | "value":req_command + ' --private --nsfw FOMO', 112 | "short":true 113 | }, 114 | { 115 | "title":"Example use 7:", 116 | "value":req_command + ' --set --private --random', 117 | "short":true 118 | }, 119 | { 120 | "title":"Example use 8:", 121 | "value":req_command + ' --set --public --norandom --sfw', 122 | "short":true 123 | }, 124 | { 125 | "title":"Example use 9:", 126 | "value":req_command + ' --surprise --public --sfw', 127 | "short":true 128 | } 129 | ] 130 | } 131 | 132 | ]; 133 | 134 | return returnData; 135 | }; 136 | -------------------------------------------------------------------------------- /web/views/add-success.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Urban 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | <%- include ("./partial/header") -%> 42 | 43 | 44 | 45 | 48 |
49 |
50 |
51 |
52 |

URBAN

53 |
Urban Dictionary Slack Bot
54 |
55 |

ADDED SUCCESSFULLY

56 |
57 |
58 |
59 |
60 | 61 |
62 |
63 |
64 |
65 | 66 | 69 |
70 |
71 |
72 |
73 | 74 |

Urban

75 |

Urban is your Urban Dictionary Slack bot. Use /urban command to decipher all the pop-culture references your team colleagues throw around Slack channels ever so freely, assuming that everyone understands them.

76 |


More Info Coming Soon...

77 |
78 |
79 | 80 |

Add to Slack

81 |

Urban is super-easy to add to your slack team. Hit the add-to-slack button, authorize your team to use Urban and you can start using /urban command within seconds inside your Slack team.

82 |


Add to Slack

83 |
84 |
85 | 86 |

Bugs and feature requests

87 |

Urban is an open-source project under MIT license. Report bugs, submit feature request and contribute to the project at GitHub. All ideas suggestions and pull requests are more than welcome :)

88 |


View on GitHub

89 |
90 |
91 |
92 |
93 | 94 | 96 | 97 | <%- include ("./partial/footer") -%> 98 | 99 | 100 | 101 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /web/assets/js/jquery.hoverdir.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jquery.hoverdir.js v1.1.0 3 | * http://www.codrops.com 4 | * 5 | * Licensed under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright 2012, Codrops 9 | * http://www.codrops.com 10 | */ 11 | ;( function( $, window, undefined ) { 12 | 13 | 'use strict'; 14 | 15 | $.HoverDir = function( options, element ) { 16 | 17 | this.$el = $( element ); 18 | this._init( options ); 19 | 20 | }; 21 | 22 | // the options 23 | $.HoverDir.defaults = { 24 | speed : 300, 25 | easing : 'ease', 26 | hoverDelay : 0, 27 | inverse : false 28 | }; 29 | 30 | $.HoverDir.prototype = { 31 | 32 | _init : function( options ) { 33 | 34 | // options 35 | this.options = $.extend( true, {}, $.HoverDir.defaults, options ); 36 | // transition properties 37 | this.transitionProp = 'all ' + this.options.speed + 'ms ' + this.options.easing; 38 | // support for CSS transitions 39 | this.support = Modernizr.csstransitions; 40 | // load the events 41 | this._loadEvents(); 42 | 43 | }, 44 | _loadEvents : function() { 45 | 46 | var self = this; 47 | 48 | this.$el.on( 'mouseenter.hoverdir, mouseleave.hoverdir', function( event ) { 49 | 50 | var $el = $( this ), 51 | $hoverElem = $el.find( 'div' ), 52 | direction = self._getDir( $el, { x : event.pageX, y : event.pageY } ), 53 | styleCSS = self._getStyle( direction ); 54 | 55 | if( event.type === 'mouseenter' ) { 56 | 57 | $hoverElem.hide().css( styleCSS.from ); 58 | clearTimeout( self.tmhover ); 59 | 60 | self.tmhover = setTimeout( function() { 61 | 62 | $hoverElem.show( 0, function() { 63 | 64 | var $el = $( this ); 65 | if( self.support ) { 66 | $el.css( 'transition', self.transitionProp ); 67 | } 68 | self._applyAnimation( $el, styleCSS.to, self.options.speed ); 69 | 70 | } ); 71 | 72 | 73 | }, self.options.hoverDelay ); 74 | 75 | } 76 | else { 77 | 78 | if( self.support ) { 79 | $hoverElem.css( 'transition', self.transitionProp ); 80 | } 81 | clearTimeout( self.tmhover ); 82 | self._applyAnimation( $hoverElem, styleCSS.from, self.options.speed ); 83 | 84 | } 85 | 86 | } ); 87 | 88 | }, 89 | // credits : http://stackoverflow.com/a/3647634 90 | _getDir : function( $el, coordinates ) { 91 | 92 | // the width and height of the current div 93 | var w = $el.width(), 94 | h = $el.height(), 95 | 96 | // calculate the x and y to get an angle to the center of the div from that x and y. 97 | // gets the x value relative to the center of the DIV and "normalize" it 98 | x = ( coordinates.x - $el.offset().left - ( w/2 )) * ( w > h ? ( h/w ) : 1 ), 99 | y = ( coordinates.y - $el.offset().top - ( h/2 )) * ( h > w ? ( w/h ) : 1 ), 100 | 101 | // the angle and the direction from where the mouse came in/went out clockwise (TRBL=0123); 102 | // first calculate the angle of the point, 103 | // add 180 deg to get rid of the negative values 104 | // divide by 90 to get the quadrant 105 | // add 3 and do a modulo by 4 to shift the quadrants to a proper clockwise TRBL (top/right/bottom/left) **/ 106 | direction = Math.round( ( ( ( Math.atan2(y, x) * (180 / Math.PI) ) + 180 ) / 90 ) + 3 ) % 4; 107 | 108 | return direction; 109 | 110 | }, 111 | _getStyle : function( direction ) { 112 | 113 | var fromStyle, toStyle, 114 | slideFromTop = { left : '0px', top : '-100%' }, 115 | slideFromBottom = { left : '0px', top : '100%' }, 116 | slideFromLeft = { left : '-100%', top : '0px' }, 117 | slideFromRight = { left : '100%', top : '0px' }, 118 | slideTop = { top : '0px' }, 119 | slideLeft = { left : '0px' }; 120 | 121 | switch( direction ) { 122 | case 0: 123 | // from top 124 | fromStyle = !this.options.inverse ? slideFromTop : slideFromBottom; 125 | toStyle = slideTop; 126 | break; 127 | case 1: 128 | // from right 129 | fromStyle = !this.options.inverse ? slideFromRight : slideFromLeft; 130 | toStyle = slideLeft; 131 | break; 132 | case 2: 133 | // from bottom 134 | fromStyle = !this.options.inverse ? slideFromBottom : slideFromTop; 135 | toStyle = slideTop; 136 | break; 137 | case 3: 138 | // from left 139 | fromStyle = !this.options.inverse ? slideFromLeft : slideFromRight; 140 | toStyle = slideLeft; 141 | break; 142 | }; 143 | 144 | return { from : fromStyle, to : toStyle }; 145 | 146 | }, 147 | // apply a transition or fallback to jquery animate based on Modernizr.csstransitions support 148 | _applyAnimation : function( el, styleCSS, speed ) { 149 | 150 | $.fn.applyStyle = this.support ? $.fn.css : $.fn.animate; 151 | el.stop().applyStyle( styleCSS, $.extend( true, [], { duration : speed + 'ms' } ) ); 152 | 153 | }, 154 | 155 | }; 156 | 157 | var logError = function( message ) { 158 | 159 | if ( window.console ) { 160 | 161 | window.console.error( message ); 162 | 163 | } 164 | 165 | }; 166 | 167 | $.fn.hoverdir = function( options ) { 168 | 169 | var instance = $.data( this, 'hoverdir' ); 170 | 171 | if ( typeof options === 'string' ) { 172 | 173 | var args = Array.prototype.slice.call( arguments, 1 ); 174 | 175 | this.each(function() { 176 | 177 | if ( !instance ) { 178 | 179 | logError( "cannot call methods on hoverdir prior to initialization; " + 180 | "attempted to call method '" + options + "'" ); 181 | return; 182 | 183 | } 184 | 185 | if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) { 186 | 187 | logError( "no such method '" + options + "' for hoverdir instance" ); 188 | return; 189 | 190 | } 191 | 192 | instance[ options ].apply( instance, args ); 193 | 194 | }); 195 | 196 | } 197 | else { 198 | 199 | this.each(function() { 200 | 201 | if ( instance ) { 202 | 203 | instance._init(); 204 | 205 | } 206 | else { 207 | 208 | instance = $.data( this, 'hoverdir', new $.HoverDir( options, this ) ); 209 | 210 | } 211 | 212 | }); 213 | 214 | } 215 | 216 | return instance; 217 | 218 | }; 219 | 220 | } )( jQuery, window ); 221 | -------------------------------------------------------------------------------- /test/sampledata.js: -------------------------------------------------------------------------------- 1 | { 2 | "urbanparser": { 3 | "apiresponse": { 4 | 5 | "tags": [], 6 | "result_type": "exact", 7 | "list": [{ 8 | "defid": 6394950, 9 | "word": "asdasdasd", 10 | "author": "etymologynerd1950", 11 | "permalink": "http://asdasdasd.urbanup.com/6394950", 12 | "definition": "left handed three finger pinkie to middle typing boredom filler like tapping those fingers on a table, similar dick to\n\nal;sdkjf;aslkdjf;alskdjf;alskdjf;alsdkjf, the alternating eight finger pinky to forefinger right and left hand keyboard doodling", 13 | "example": "asdasdasdasdsdasdasdadasdsd", 14 | "thumbs_up": 187, 15 | "thumbs_down": 65, 16 | "current_vote": "" 17 | }], 18 | "sounds": [] 19 | 20 | }, 21 | "correctoutput": { 22 | "response_type": "ephemeral", 23 | "username": "UrbanSlack", 24 | "text": "*DEFINITION (1 of 1):* left handed three finger pinkie to middle typing boredom filler like tapping those fingers on a table, similar dick to\n\nal;sdkjf;aslkdjf;alskdjf;alskdjf;alsdkjf, the alternating eight finger pinky to forefinger right and left hand keyboard doodling", 25 | "attachments": [{ 26 | "title": "Example use", 27 | "text": "asdasdasdasdsdasdasdadasdsd" 28 | }] 29 | }, 30 | "sfwOutput":{ 31 | "response_type": "ephemeral", 32 | "username": "UrbanSlack", 33 | "text": "*DEFINITION (1 of 1):* left handed three finger pinkie to middle typing boredom filler like tapping those fingers on a table, similar **** to\n\nal;sdkjf;aslkdjf;alskdjf;alskdjf;alsdkjf, the alternating eight finger pinky to forefinger right and left hand keyboard doodling", 34 | "attachments": [{ 35 | "title": "Example use", 36 | "text": "asdasdasdasdsdasdasdadasdsd" 37 | }] 38 | }, 39 | "publicOutput":{ 40 | "response_type": "in_channel", 41 | "username": "UrbanSlack", 42 | "text": "*DEFINITION (1 of 1):* left handed three finger pinkie to middle typing boredom filler like tapping those fingers on a table, similar **** to\n\nal;sdkjf;aslkdjf;alskdjf;alskdjf;alsdkjf, the alternating eight finger pinky to forefinger right and left hand keyboard doodling", 43 | "attachments": [{ 44 | "title": "Example use", 45 | "text": "asdasdasdasdsdasdasdadasdsd" 46 | }] 47 | }, 48 | "feedbackOutput":{ 49 | "response_type": "in_channel", 50 | "username": "UrbanSlack", 51 | "text": "Your feedback is much appreciated!! Thank you for asking to make Urban Slack better. Feel free to get in touch with @matijaabicic on Twitter and don't forget to check out https://urban-slack.herokuapp.com for details on how to get involved." 52 | } 53 | }, 54 | "commandparser": { 55 | "helpRequest" : "/urban ?", 56 | "helpRequest_result" : {"responseType":"ephemeral","rating":"nsfw","random":false,"Command":"\"/urban ?\""}, 57 | "publicHelpRequest" : "/urban ? --public", 58 | "publicHelpRequest_result" : {"responseType":"in_channel","rating":"nsfw","random":false,"Command":"\"/urban ? \""}, 59 | "sfwRequest" : "/urban kevin --sfw", 60 | "sfwRequest_result" : {"responseType":"ephemeral","rating":"sfw","random":false,"Command":"\"/urban kevin \""}, 61 | "randomRequest" : "/urban kevin --random", 62 | "randomRequest_result" : {"responseType":"ephemeral","rating":"nsfw","random":true,"Command":"\"/urban kevin \""}, 63 | "norandomRequest" : "/urban kevin --norandom", 64 | "norandomRequest_result" : {"responseType":"ephemeral","rating":"nsfw","random":false,"Command":"\"/urban kevin \""}, 65 | "comboRequest" : "/urban hello --random --public --sfw", 66 | "comboRequest_result" : {"responseType":"in_channel","rating":"sfw","random":true,"Command":"\"/urban hello \""}, 67 | "lastRequest" : "/urban --last", 68 | "lastRequest_result" : {"responseType":"ephemeral","rating":"nsfw","random":false,"last":true,"Command":""}, 69 | "ampRequest" : "/urban f&f", 70 | "ampRequest_result" : {"responseType":"ephemeral","rating":"nsfw","random":false,"Command":"\"/urban f%26f\""}, 71 | "defaultsPublicRequest" : "/urban --set --public", 72 | "defaultsPublicRequest_result" : {"responseType":"in_channel","rating":"nsfw","random":false,"defaults":true,"Command":"\"/urban \""}, 73 | "defaultsRequest" : "/urban --set", 74 | "defaultsRequest_result" : {"responseType":"ephemeral","rating":"nsfw","random":false,"defaults":true,"Command":"\"/urban \""}, 75 | "defaultsPrivateRequest" : "/urban --set --private", 76 | "defaultsPrivateRequest_result" : {"responseType":"ephemeral","rating":"nsfw","random":false,"defaults":true,"Command":"\"/urban \""}, 77 | "defaultsSfwRequest" : "/urban --set --sfw", 78 | "defaultsSfwRequest_result" : {"responseType":"ephemeral","rating":"sfw","random":false,"defaults":true,"Command":"\"/urban \""}, 79 | "defaultsNsfwRequest" : "/urban --set --nsfw", 80 | "defaultsNsfwRequest_result" : {"responseType":"ephemeral","rating":"nsfw","random":false,"defaults":true,"Command":"\"/urban \""}, 81 | "defaultsRandomRequest" : "/urban --set --random", 82 | "defaultsRandomRequest_result" : {"responseType":"ephemeral","rating":"nsfw","random":true,"defaults":true,"Command":"\"/urban \""}, 83 | "defaults3SwitchesRequest" : "/urban --set --random --public --nsfw", 84 | "defaults3SwitchesRequest_result" : {"responseType":"in_channel","rating":"nsfw","random":true,"defaults":true,"Command":"\"/urban \""}, 85 | "defaultsChecker" : "/urban --mysettings", 86 | "defaultsChecker_result" : {"responseType":"ephemeral","rating":"nsfw","random":false,"mysettings":true,"Command":"\"/urban \""}, 87 | "userFeedback" : "/urban --feedback Here's some feedback!!", 88 | "userFeedback_result" : {"responseType":"ephemeral","feedback":true,"rating":"nsfw","random":false,"Command":"\"/urban Here's some feedback!!\""}, 89 | "surprise" : "/urban --surprise", 90 | "surprise_result" : {"responseType":"ephemeral","rating":"nsfw","random":false,"Command":"\"/urban --surprise\""} 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /web/views/add-fail.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Urban 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | <%- include ("./partial/header") -%> 43 | 44 | 45 | 46 | 49 |
50 |
51 |
52 |
53 |

URBAN

54 |
Urban Dictionary Slack Bot
55 |
56 |

CANNOT ADD TO SLACK.

57 |

Error: <%= errorMessage %>

58 |
Please try again OR direct your custom /slash slack command to:
59 |

https://urban-slack.herokuapp.com/api

60 |
61 | Add to Slack 62 |
63 |
64 |
65 |
66 |
67 |
68 | 69 | 72 |
73 |
74 |
75 |
76 | 77 |

Urban

78 |

Urban is your Urban Dictionary Slack bot. Use /urban command to decipher all the pop-culture references your team colleagues throw around Slack channels ever so freely, assuming that everyone understands them.

79 |


More Info Coming Soon...

80 |
81 |
82 | 83 |

Add to Slack

84 |

Urban is super-easy to add to your slack team. Hit the add-to-slack button, authorize your team to use Urban and you can start using /urban command within seconds inside your Slack team.

85 |


Add to Slack

86 |
87 |
88 | 89 |

Bugs and feature requests

90 |

Urban Slack is an open-source project under MIT license. Report bugs, submit feature request and contribute to the project at GitHub. All ideas suggestions and pull requests are more than welcome :)

91 |


View on GitHub

92 |
93 |
94 |
95 |
96 | 97 | 99 | 100 | <%- include ("./partial/footer") -%> 101 | 102 | 103 | 104 | 105 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /web/views/contributors.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Urban 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | <%- include ("./partial/header") -%> 42 | 43 | 44 | 45 | 48 |
49 |
50 |
51 |
52 |

CREATORS AND CONTRIBUTORS

53 |
Everyone is invited.
54 |
55 |
56 |
57 |
58 | 59 | 62 |
63 |
64 |
65 |

CONTRIBUTE

66 |

Head over to Urban Github Repo and join the list below

67 |
68 |
69 |
70 |
71 | <% if (contributors.length > 0) { %> 72 | 73 | <% contributors.forEach(function(contributor) { %> 74 | 75 | 78 | 79 | 80 | 81 | <% }); %> 82 |
76 | 77 |

<%=contributor.login %>

Contributions: <%=contributor.contributions %>

83 | <% } else { %> 84 |

PROBLEM OCCURED WHILE GETTING DATA FROM GITHUB

85 |

Head over to Urban Github Repo and see the list while we deal with the problem

86 | <% } %> 87 |
88 |
89 |
90 |
91 |
92 | 93 |
94 |
95 |
96 |
97 |

THINGS THAT WERE SHAMELESLY STOLEN

98 |

Bootstrap theme: SOLID by Blacktie.

99 |

Graphics credits: Amy Nicole Schwartz, Sergey Arzamastsev, Andrew Colin Beck, Michael B. Myers Jr., Justin Spinozzi, Alen Pavlovic and Dennis Camacho .

100 |
101 |
102 |
103 | 104 | 106 | 107 | <%- include ("./partial/footer") -%> 108 | 109 | 110 | 111 | 112 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /web/views/privacy.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Urban 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | <%- include ("./partial/header") -%> 42 | 43 | 44 | 45 | 48 |
49 |
50 |
51 |
52 |

PRIVACY POLICY

53 |
Urban stores the minimum required amount of data needed to improve the service delivered to the users. The code is completely open and you can view all the details at Github.
54 |
55 |
56 |
57 |
58 | 59 | 62 |
63 |
64 |
65 |
66 |
67 |
Stored Data
68 |
For purposes of better understanding our users, we store certain details from /urban requests. We keep track of --sfw vs --nsfw requests, --public and --private, as well as ? (help) requests to understand ways in which Urban is best used. We also keep track the usage distribution across teams and users to understand whether Urban is used by lots of teams and small number of people, few teams and a lot of people, lots of teams and everyone in them or....no one at all. We only keep the annonymized, numeric IDs, we DO NOT store any team, channel or user names.
69 |
70 |
Analytics
71 |
Urban uses Google Analytics for better understanding of our users. We pass two types of data to our Google Analtyics tracker: website visits (to understand who is visiting us and who is refering us) and API access from slack. Regarding the API, we only collect the "api triggered" event in Google Analytics, to help us understand the frequency and usage. When /urban command is triggered from slack, all we see is a hit at our API endpoint and that the request is coming from Slack servers, our Google Analytics tracker does not know who you are and where you are coming from, what you are searching etc. See Google Analytics Terms for all details.
72 |
73 |
3rd Party Services
74 |
Urban runs on the Heroku Platform. See Heroku Privacy Policy for more details.
75 |
Urban also uses mLab Mongo-as-a-Service. See mLab Privacy Policy for more details.
76 |
77 |
Advertising
78 |
Urban does not display advertisments. Not on the web page, not in Slack responses. We also do not share the data with any advertisers, intermediaries...how should we put it to close all the loopholes: we don't sahre the data with anyone.
79 |
80 |
Data transfer
81 |
We NEVER share or sell any stored data. To anyone. Ever.
82 |
83 |
Privacy policy
84 |
This privacy policy may change over time.
85 |
86 |
87 |
88 |
89 |
90 | 91 | 93 | 94 | <%- include ("./partial/footer") -%> 95 | 96 | 97 | 98 | 99 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /web/views/partial/featureGallery.ejs: -------------------------------------------------------------------------------- 1 |
2 |

THIS THING HAS FEATURES !!

3 |
4 |
5 | 6 |
7 |
8 | 9 |
10 |
11 |

HELP !!!

12 | 13 |
14 | 15 |
16 | 17 |
18 | 19 |
20 | 21 | 22 |
23 |
24 | 25 |
26 |
27 |

Make it Public.

28 | 29 |
30 | 31 |
32 | 33 |
34 | 35 |
36 | 37 | 38 |
39 |
40 | 41 |
42 |
43 |

Safe For Work (SFW)

44 | 45 |
46 | 47 |
48 | 49 |
50 | 51 |
52 | 53 | 54 |
55 |
56 | 57 |
58 |
59 |

Make it random.

60 | 61 |
62 | 63 |
64 | 65 |
66 | 67 |
68 | 69 | 70 |
71 |
72 | 73 |
74 |
75 |

Repeat.

76 | 77 |
78 | 79 |
80 | 81 |
82 | 83 |
84 | 85 | 86 |
87 |
88 | 89 |
90 |
91 |

Sound Clips

92 | 93 |
94 | 95 |
96 | 97 |
98 | 99 |
100 | 101 | 102 |
103 |
104 | 105 |
106 |
107 |

Slash Command API

108 | 109 | 110 |
111 | 112 |
113 | 114 |
115 | 116 |
117 | 118 | 119 |
120 |
121 | 122 |
123 |
124 |

User Preferences

125 | 126 |
127 | 128 |
129 | 130 |
131 | 132 |
133 | 134 |
135 | 136 |
137 |
138 | 139 | -------------------------------------------------------------------------------- /test/tests.js: -------------------------------------------------------------------------------- 1 | 2 | var settings = require("../settings.js"); 3 | var assert = require("assert"); 4 | var parser = require("../lib/urban-parser.js"); 5 | var commandParser = require("../lib/slack-command-parser.js"); 6 | var fs = require("fs"); 7 | 8 | var obj = JSON.parse(fs.readFileSync('test/sampledata.js', 'utf8')); 9 | 10 | describe("Internal testing", function() { 11 | 12 | // Urban Parser testing (responder) 13 | describe("Response parser testing (urban-parser.js)", function() { 14 | it("Parses simple, private response", function() { 15 | var api_result = JSON.stringify(obj.urbanparser.apiresponse); 16 | 17 | var expected_output = JSON.stringify(obj.urbanparser.correctoutput); 18 | var parse_result = JSON.stringify(parser.parse(api_result, JSON.parse('{"responseType":"ephemeral"}'))); 19 | 20 | assert.equal(parse_result, expected_output); 21 | }); 22 | it("Censors NSFW content", function (){ 23 | //test data 24 | var api_result = JSON.stringify(obj.urbanparser.apiresponse); 25 | //expected data 26 | var expected_output = JSON.stringify(obj.urbanparser.sfwOutput); 27 | //actual result 28 | var parse_result = JSON.stringify(parser.parse(api_result, JSON.parse('{"responseType":"ephemeral","rating":"sfw","random":false}'))); 29 | //compare and assert test 30 | assert.equal(parse_result, expected_output); 31 | }); 32 | it("Responds with NSFW content", function (){ 33 | //test data 34 | var api_result = JSON.stringify(obj.urbanparser.apiresponse); 35 | //expected data 36 | var expected_output = JSON.stringify(obj.urbanparser.correctoutput); 37 | //actual result 38 | var parse_result = JSON.stringify(parser.parse(api_result, JSON.parse('{"responseType":"ephemeral","rating":"nsfw","random":false}'))); 39 | //compare and assert test 40 | assert.equal(parse_result, expected_output); 41 | }); 42 | it("Responds publically in channel", function (){ 43 | //test data 44 | var api_result = JSON.stringify(obj.urbanparser.apiresponse); 45 | //expected data 46 | var expected_output = JSON.stringify(obj.urbanparser.publicOutput); 47 | //actual result 48 | var parse_result = JSON.stringify(parser.parse(api_result, JSON.parse('{"responseType":"in_channel","rating":"sfw","random":false}'))); 49 | //compare and assert test 50 | assert.equal(parse_result, expected_output); 51 | }); 52 | it("Parses special character &", function(){ 53 | var commandRequest =JSON.stringify(obj.commandparser.ampRequest); 54 | var expected_output = JSON.stringify(obj.commandparser.ampRequest_result); 55 | 56 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 57 | }); 58 | }); 59 | 60 | describe("Command parser testing (slack-command-parser.js)", function() { 61 | it("Parses help request", function(){ 62 | var commandRequest = JSON.stringify(obj.commandparser.helpRequest); 63 | var expected_output = JSON.stringify(obj.commandparser.helpRequest_result); 64 | 65 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)),expected_output); 66 | }); 67 | it("Parses public help request", function(){ 68 | var commandRequest =JSON.stringify(obj.commandparser.publicHelpRequest); 69 | var expected_output = JSON.stringify(obj.commandparser.publicHelpRequest_result); 70 | 71 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 72 | }); 73 | it("Parses SFW requests", function(){ 74 | var commandRequest = JSON.stringify(obj.commandparser.sfwRequest); 75 | var expected_output= JSON.stringify(obj.commandparser.sfwRequest_result); 76 | 77 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 78 | }); 79 | it("Parses random requests", function(){ 80 | var commandRequest = JSON.stringify(obj.commandparser.randomRequest); 81 | var expected_output = JSON.stringify(obj.commandparser.randomRequest_result); 82 | 83 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 84 | }); 85 | it("Parses norandom requests", function(){ 86 | var commandRequest = JSON.stringify(obj.commandparser.norandomRequest); 87 | var expected_output = JSON.stringify(obj.commandparser.norandomRequest_result); 88 | 89 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 90 | }); 91 | it("Parses combined requests", function(){ 92 | var commandRequest = JSON.stringify(obj.commandparser.comboRequest); 93 | var expected_output = JSON.stringify(obj.commandparser.comboRequest_result); 94 | 95 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 96 | }); 97 | it("Parses --last switch", function(){ 98 | var commandRequest = JSON.stringify(obj.commandparser.lastRequest); 99 | var expected_output = JSON.stringify(obj.commandparser.lastRequest_result); 100 | 101 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 102 | }); 103 | it("Parses --set switch", function(){ 104 | var commandRequest = JSON.stringify(obj.commandparser.defaultsRequest); 105 | var expected_output = JSON.stringify(obj.commandparser.defaultsRequest_result); 106 | 107 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 108 | }); 109 | it("Parses --set switch with --public switch", function(){ 110 | var commandRequest = JSON.stringify(obj.commandparser.defaultsPublicRequest); 111 | var expected_output = JSON.stringify(obj.commandparser.defaultsPublicRequest_result); 112 | 113 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 114 | }); 115 | it("Parses --set switch with --private switch", function(){ 116 | var commandRequest = JSON.stringify(obj.commandparser.defaultsPrivateRequest); 117 | var expected_output = JSON.stringify(obj.commandparser.defaultsPrivateRequest_result); 118 | 119 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 120 | }); 121 | it("Parses --set switch with --sfw switch", function(){ 122 | var commandRequest = JSON.stringify(obj.commandparser.defaultsSfwRequest); 123 | var expected_output = JSON.stringify(obj.commandparser.defaultsSfwRequest_result); 124 | 125 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 126 | }); 127 | it("Parses --set switch with --nsfw switch", function(){ 128 | var commandRequest = JSON.stringify(obj.commandparser.defaultsNsfwRequest); 129 | var expected_output = JSON.stringify(obj.commandparser.defaultsNsfwRequest_result); 130 | 131 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 132 | }); 133 | it("Parses --set switch with --random switch", function(){ 134 | var commandRequest = JSON.stringify(obj.commandparser.defaultsRandomRequest); 135 | var expected_output = JSON.stringify(obj.commandparser.defaultsRandomRequest_result); 136 | 137 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 138 | }); 139 | it("Parses --set switch with --random --public --nsfw switches", function(){ 140 | var commandRequest = JSON.stringify(obj.commandparser.defaults3SwitchesRequest); 141 | var expected_output = JSON.stringify(obj.commandparser.defaults3SwitchesRequest_result); 142 | 143 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 144 | }); 145 | it("Parses --mysettings switch", function(){ 146 | var commandRequest = JSON.stringify(obj.commandparser.defaultsChecker); 147 | var expected_output = JSON.stringify(obj.commandparser.defaultsChecker_result); 148 | 149 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 150 | }); 151 | it("Parses --feedback switch", function(){ 152 | var commandRequest = JSON.stringify(obj.commandparser.userFeedback); 153 | var expected_output = JSON.stringify(obj.commandparser.userFeedback_result); 154 | 155 | assert.equal(JSON.stringify(commandParser.parse(commandRequest)), expected_output); 156 | }); 157 | }); 158 | }); 159 | -------------------------------------------------------------------------------- /web/assets/css/style.css: -------------------------------------------------------------------------------- 1 | /* ################################################################ 2 | 3 | Author: Carlos Alvarez 4 | URL: http://alvarez.is 5 | 6 | Project Name: SOLID - Bootstrap 3 Theme 7 | Version: 1.0 8 | URL: http://alvarez.is 9 | 10 | ################################################################# */ 11 | @import url(http://fonts.googleapis.com/css?family=Raleway:400,700,900); 12 | @import url(http://fonts.googleapis.com/css?family=Lato:400,900); 13 | @import url("prettyPhoto.css") screen; 14 | @import url("hoverex-all.css") screen; 15 | 16 | /* ################################################################ 17 | 1. GENERAL STRUCTURES 18 | ################################################################# */ 19 | * { 20 | margin: 0; 21 | padding: 0px; 22 | } 23 | 24 | body { 25 | background: #ffffff; 26 | margin: 0; 27 | height: 100%; 28 | color: #384452; 29 | font-family: 'Lato', sans-serif; 30 | font-weight: 400; 31 | } 32 | 33 | h1, h2, h3, h4, h5, h6 { 34 | font-family: 'Raleway', sans-serif; 35 | font-weight: 700; 36 | } 37 | 38 | p { 39 | padding: 0; 40 | margin-bottom: 12px; 41 | font-family: 'Lato', sans-serif; 42 | font-weight: 400; 43 | font-size: 14px; 44 | line-height: 24px; 45 | color: #384452; 46 | margin-top: 10px; 47 | } 48 | 49 | img { 50 | height: auto; 51 | max-width: 100%; 52 | } 53 | 54 | a { 55 | padding: 0; 56 | margin: 0; 57 | text-decoration: none; 58 | -webkit-transition: background-color .4s linear, color .4s linear; 59 | -moz-transition: background-color .4s linear, color .4s linear; 60 | -o-transition: background-color .4s linear, color .4s linear; 61 | -ms-transition: background-color .4s linear, color .4s linear; 62 | transition: background-color .4s linear, color .4s linear; 63 | } 64 | a:hover, 65 | a:focus { 66 | text-decoration: none; 67 | color:#01b2fe; 68 | } 69 | 70 | ::-moz-selection { 71 | color: #fff; 72 | text-shadow:none; 73 | background:#2B2E31; 74 | } 75 | ::selection { 76 | color: #fff; 77 | text-shadow:none; 78 | background:#2B2E31; 79 | } 80 | 81 | .centered { 82 | text-align: center 83 | } 84 | 85 | /* ################################################################ 86 | BOOTSTRAP MODIFICATIONS & TWEAKS 87 | ################################################################# */ 88 | .navbar { 89 | min-height: 70px; 90 | padding-top: 10px; 91 | margin-bottom: 0px; 92 | } 93 | 94 | .navbar-brand { 95 | font-family: 'Raleway', sans-serif; 96 | font-weight: 900; 97 | } 98 | 99 | .navbar-header .navbar-brand { 100 | color: white; 101 | } 102 | 103 | .navbar-default .navbar-nav > li > a { 104 | color: white; 105 | font-weight: 700; 106 | font-size: 12px; 107 | } 108 | 109 | .navbar-default .navbar-nav > li > a:hover { 110 | color: #00b3fe; 111 | } 112 | 113 | .navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus { 114 | color: #00b3fe; 115 | background-color: transparent; 116 | } 117 | 118 | .navbar-default { 119 | background-color: #384452; 120 | border-color: transparent; 121 | } 122 | 123 | .dropdown-menu { 124 | background: #384452; 125 | } 126 | 127 | .dropdown-menu > li > a { 128 | color: white; 129 | font-weight: 700; 130 | font-size: 12px; 131 | } 132 | 133 | .btn-theme { 134 | color: #fff; 135 | background-color: #384452; 136 | border-color: #384452; 137 | margin: 4px; 138 | } 139 | .btn-theme:hover, 140 | .btn-theme:focus, 141 | .btn-theme:active, 142 | .btn-theme.active, 143 | .open .dropdown-toggle.btn-theme { 144 | color: #fff; 145 | background-color: #00b3fe; 146 | border-color: #00b3fe; 147 | } 148 | 149 | .dmbutton:hover, 150 | .dmbutton:active, 151 | .dmbutton:focus{ 152 | color: #ffffff; 153 | background-color: #222222; 154 | border-color: #ffffff; 155 | } 156 | .dmbutton { 157 | background:rgba(0, 0, 0, 0); 158 | border: 1px solid #ffffff; 159 | color: #ffffff; 160 | -webkit-border-radius: 2px; 161 | border-radius: 2px; 162 | padding-top: 1.025rem; 163 | padding-right: 2.25rem; 164 | letter-spacing:0.85px; 165 | padding-bottom: 1.0875rem; 166 | padding-left: 2.25rem; 167 | font-size: 1.55rem; 168 | cursor: pointer; 169 | font-weight: normal; 170 | line-height: normal; 171 | margin: 0 0 1.25rem; 172 | text-decoration: none; 173 | text-align: center; 174 | display: inline-block; 175 | -webkit-transition: background-color 300ms ease-out; 176 | -moz-transition: background-color 300ms ease-out; 177 | transition: background-color 300ms ease-out; 178 | -webkit-appearance: none; 179 | font-weight: normal !important; 180 | } 181 | 182 | .mtb { 183 | margin-top: 80px; 184 | margin-bottom: 80px; 185 | } 186 | 187 | .mb { 188 | margin-bottom: 60px; 189 | } 190 | 191 | .mt { 192 | margin-top: 60px; 193 | } 194 | 195 | .hline { 196 | border-bottom: 2px solid #384452; 197 | } 198 | 199 | .hline-w { 200 | border-bottom: 2px solid #ffffff; 201 | margin-bottom: 25px; 202 | } 203 | /* ################################################################ 204 | SITE WRAPS 205 | ################################################################# */ 206 | 207 | #headerwrap { 208 | background-color: #00b3fe; 209 | min-height: 250px; 210 | padding-top: 100px; 211 | padding-bottom: 0px; 212 | text-align: center; 213 | } 214 | 215 | #headerwrap h3, h5 { 216 | color: white; 217 | font-weight: 400; 218 | } 219 | 220 | #headerwrap h1 { 221 | color: white; 222 | margin-bottom: 25px; 223 | } 224 | 225 | #headerwrap .img-responsive { 226 | margin: 0 auto; 227 | } 228 | 229 | /* Services Wrap */ 230 | #service { 231 | margin-top: 100px; 232 | margin-bottom: 80px; 233 | } 234 | 235 | #service i { 236 | color: #00b3fe; 237 | font-size: 60px; 238 | padding: 15px; 239 | } 240 | 241 | /* Portfolio Wrap */ 242 | #portfoliowrap { 243 | padding-top: 60px; 244 | margin-bottom: 60px; 245 | display: block; 246 | text-align: center 247 | } 248 | 249 | #portfoliowrap h3 { 250 | margin-bottom: 25px; 251 | } 252 | 253 | .portfolio { 254 | padding:0 !important; 255 | margin:0 !important; 256 | display:block; 257 | } 258 | 259 | 260 | .portfolio-item .title:before {border-radius:0; display:none} 261 | .portfolio-item p {margin:0px 0 30px;} 262 | .portfolio-item h3 {margin:-10px 0 10px; font-size:16px; text-transform:uppercase;} 263 | 264 | 265 | .tpl6 h3 266 | { 267 | color:#fff; 268 | margin:0; 269 | padding:40px 5px 0; 270 | font-size:16px; 271 | text-transform:uppercase; 272 | } 273 | .tpl6 .dmbutton 274 | { 275 | display:inline-block; 276 | margin:30px 5px 20px 5px; 277 | font-size:13px; 278 | } 279 | 280 | .tpl6 .bg 281 | { 282 | height:100%; 283 | width:100%; 284 | background-color:#00b3fe; 285 | background-color:rgba(0,179,254,.9); 286 | text-align:center; 287 | } 288 | 289 | /* Testimonials Wrap */ 290 | #twrap { 291 | background: url(../img/t-back.jpg) no-repeat center top; 292 | margin-top: 0px; 293 | padding-top:60px; 294 | text-align:center; 295 | background-attachment: relative; 296 | background-position: center center; 297 | min-height: 450px; 298 | width: 100%; 299 | 300 | -webkit-background-size: 100%; 301 | -moz-background-size: 100%; 302 | -o-background-size: 100%; 303 | background-size: 100%; 304 | 305 | -webkit-background-size: cover; 306 | -moz-background-size: cover; 307 | -o-background-size: cover; 308 | background-size: cover; 309 | } 310 | 311 | #twrap i { 312 | font-size: 50px; 313 | color: white; 314 | margin-bottom: 25px; 315 | } 316 | 317 | #twrap p { 318 | color: white; 319 | font-size: 15px; 320 | line-height: 30px; 321 | } 322 | 323 | /* clients logo */ 324 | #cwrap { 325 | background: #f7f7f7; 326 | margin-top: 0px; 327 | padding-top: 80px; 328 | padding-bottom: 100px; 329 | } 330 | 331 | #cwrap h3 { 332 | margin-bottom: 60px; 333 | } 334 | 335 | /* Footer */ 336 | #footerwrap { 337 | padding-top: 60px; 338 | padding-bottom: 60px; 339 | background: #384452; 340 | } 341 | 342 | #footerwrap p { 343 | color: #bfc9d3; 344 | } 345 | 346 | #footerwrap h4 { 347 | color: white; 348 | } 349 | 350 | #footerwrap i { 351 | font-size: 30px; 352 | color: #bfc9d3; 353 | padding-right: 25px; 354 | } 355 | 356 | #footerwrap i:hover { 357 | color: #00b3fe 358 | } 359 | 360 | /* ################################################################ 361 | PAGE CONFIGURATIONS 362 | ################################################################# */ 363 | /* General Tweaks */ 364 | 365 | #blue { 366 | background: #00b3fe; 367 | margin-top: 60px; 368 | margin-bottom: 60px; 369 | padding-top: 25px; 370 | padding-bottom: 25px; 371 | } 372 | 373 | #blue h3 { 374 | color: white; 375 | margin-left: 15px; 376 | } 377 | 378 | .ctitle { 379 | color: #00b3fe; 380 | font-weight: 700; 381 | margin-bottom: 15px; 382 | } 383 | 384 | csmall { 385 | font-size: 12px; 386 | color: #b3b3b3; 387 | } 388 | csmall2 { 389 | font-size: 12px; 390 | color: #f39c12 391 | } 392 | 393 | .spacing { 394 | margin-top: 40px; 395 | margin-bottom: 40px; 396 | } 397 | 398 | .badge-theme { 399 | background: #00b3fe; 400 | } 401 | 402 | /* Contact Page */ 403 | #contactwrap { 404 | background: url(../img/contact.jpg) no-repeat center top; 405 | margin-top: -60px; 406 | padding-top:0px; 407 | text-align:center; 408 | background-attachment: relative; 409 | background-position: center center; 410 | min-height: 400px; 411 | width: 100%; 412 | 413 | -webkit-background-size: 100%; 414 | -moz-background-size: 100%; 415 | -o-background-size: 100%; 416 | background-size: 100%; 417 | 418 | -webkit-background-size: cover; 419 | -moz-background-size: cover; 420 | -o-background-size: cover; 421 | background-size: cover; 422 | } 423 | 424 | /* Blog Page */ 425 | .popular-posts { 426 | margin: 0px; 427 | padding-left: 0px; 428 | } 429 | 430 | .popular-posts li { 431 | list-style: none; 432 | margin-bottom: 20px; 433 | min-height: 70px; 434 | } 435 | .popular-posts li a, 436 | .popular-posts li a:hover { 437 | color:#2f2f2f; 438 | text-decoration: none; 439 | } 440 | 441 | .popular-posts li img { 442 | float: left; 443 | margin-right: 20px; 444 | } 445 | 446 | .popular-posts li em { 447 | font-family: 'Lato', sans-serif; 448 | font-size: 12px; 449 | color: #b3b3b3 450 | } 451 | 452 | .popular-posts p { 453 | line-height: normal; 454 | margin-bottom: auto; 455 | } 456 | 457 | .share i { 458 | padding-right: 15px; 459 | font-size: 18px; 460 | } 461 | -------------------------------------------------------------------------------- /web/views/howto.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Urban 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | <%- include ("./partial/header") -%> 42 | 43 | 44 | 45 | 48 |
49 |
50 |
51 |
52 |

HOW-TO

53 |
A quick guide on how to use Urban Slack bot.
54 |
55 |
56 |
57 |
58 | 59 | 62 |
63 |
64 |
65 |
66 |
67 |
Ask for Help
68 |
/urban ?
69 |
Urban will give you a quick glance at all available commands
70 |
71 |
Make it public
72 |
/urban --public ?
73 |
Urban will post both your "?" request and the response publically into your current channel.
74 |
75 |
Phrases
76 |
/urban FOMO or /urban what's up ...
77 |
You will see an Urban Dictionary definition for your search term.
78 |
79 |
Sketchy Phrases
80 |
/urban --sfw kevin
81 |
This will tell you that kevin has a huge ****. You can always try /urban kevin without the --sfw part, but that's at your own discretion..and peril.
82 |
83 |
Randomize
84 |
/urban --random FOMO
85 |
Urban Dictionary contains mutliple, crowd-sourced definitions for many expressions. By default, Urban Bot will show you the first, most-upvoted definition. This switch will give you a random phrase every time you request it. Same goes for the sound phrases, they will be randomized as well.
86 |
87 |
Get last phrase
88 |
/urban --last
89 |
Recalls the last phrase for the current user. Ideal when doing /urban really really long phrase. Instead of re-typing, just to get it into a public channel, just use /urban --last --public.
90 |
91 |
Combinations
92 |
/urban --sfw --public kevin or /urban --public --sfw kevin or /urban --random kevin --sfw --public or /urban --sfw kevin --public or...well, you get the point.
93 |
All these above examples will take the naughty code returned by Urban Dictionary, censosor it and then output it into a public channel, private conversation or a group.
94 |
95 |
User Preferences
96 |
/urban --set --public or /urban --set --sfw --public --random or /urban --set --norandom --private...again, you get the point.
97 |
Urban now remembers your preferences. You can use --set switch in combination with --private, --public, --nsfw, --nsfw, --random, --norandom or any combination of these switches to set your user preferences.
98 |
99 |
For the forgetful
100 |
/urban --mysettings
101 |
It might come in handy checking your settings before that --NSFW definition --randomly goes into a --public channel.
102 |
103 |
Surprise !!
104 |
/urban --surprise
105 |
Picks a completely random phrase. For those rare moments when you're bored and uninspired, just go /urban --public --surprise and hope for the best.
106 |
107 |
Say it like it is
108 |
/urban --feedback This is Awesome
109 |
Tell us what you think at any time with --feedback switch without leaving slack
110 |
111 |
System Defaults
112 |
/urban --nsfw --private kevin
113 |
This is the default response type; meaning - only you can see the response and that response will be non-filtered. /urban kevin is the equivalent to above.
114 |
115 |
Look with our eyes
116 |
Below, you can see the features in action (GIF).
117 |
118 |
119 |
120 |
121 |
122 | 123 |
124 | <%- include ("./partial/featureGallery") -%> 125 | 126 | 128 | 129 | <%- include ("./partial/footer") -%> 130 | 131 | 132 | 133 | 134 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 228 | 229 | 239 | 240 | 241 | -------------------------------------------------------------------------------- /web/views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Urban 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | <%- include ("./partial/header") -%> 36 | 37 | 38 | 39 |
40 |
41 |
42 |
43 |

URBAN

44 |
Urban Dictionary Slack Bot
45 |
46 | Add to Slack 47 |
48 |
49 | 50 |
51 |
52 |
53 | 54 | 55 | 56 | 59 |
60 | 61 |
62 |
63 |
64 |
65 | 66 |
67 | 68 |
69 |
70 | 71 |
72 |
73 | 74 |
75 | 76 |
77 | 78 |
79 |
80 | 81 | 82 |
83 |
84 |
85 |
86 |
87 |

<%= latestQuery %>

88 |
Latest definition lookup by Slack user community.
89 |
90 |
91 |
92 |
93 |
94 | 95 |

Urban

96 |

Urban is your Urban Dictionary Slack bot. Use /urban command to decipher all the pop-culture references your team colleagues throw around Slack channels ever so freely, assuming that everyone understands them.

97 |

98 |
How to use Urban

99 |
100 |
101 | 102 |

Add to Slack

103 |

Urban is super-easy to add to your slack team. Hit the add-to-slack button, authorize your team to use Urban and you can start using /urban command within seconds inside your Slack team.

104 |

105 |
106 | Add to Slack 107 |

108 |
109 |
110 | 111 |

Bugs and feature requests

112 |

Urban is an open-source project under MIT license. Report bugs, submit feature request and contribute to the project at GitHub. All ideas suggestions and pull requests are more than welcome :)

113 |

114 |
View on GitHub

115 |
116 |
117 |
118 | 119 |
120 | 121 | 122 | 123 | 124 |
125 |
126 |
127 |
128 |
129 |
130 |

Please Donate To Bitcoin Address: [[address]]

131 |
132 |
Donation of [[value]] BTC Received. Thank You.
133 |
[[error]]
134 |
135 |
136 |
137 |
138 | 139 | 140 | 141 | <%- include ("./partial/featureGallery") -%> 142 | 143 | 144 | 145 | <%- include ("./partial/footer") -%> 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 238 | 239 | 255 | 256 | 257 | 258 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | // add http module and client 2 | var http = require('http'); 3 | var express = require('express'); 4 | var request = require('request'); 5 | var Hashmap = require('hashmap'); 6 | var ua = require('universal-analytics'); 7 | var bodyParser = require('body-parser'); 8 | 9 | var settings = require('./settings'); 10 | var secrets = require('./secrets'); 11 | 12 | var urbanParser = require('./lib/urban-parser'); 13 | var commandParser = require('./lib/slack-command-parser'); 14 | var helper = require('./lib/helpPage'); 15 | var mLabHelper = require('./lib/mLabHelper'); 16 | var settingsConfirmation = require('./lib/userSettingsConfirmation'); 17 | var feedbackConfirmation = require('./lib/feedbackConfirmation'); 18 | 19 | var mLabKey = (process.env.mLabApiKey ? process.env.mLabApiKey : secrets.mLabApiKey); 20 | var mlab = require('mongolab-data-api')(mLabKey); 21 | 22 | //let the server port be configurable. 23 | var PORT = settings.serverPort; 24 | 25 | //initialize Google Analytics 26 | var visitor = ua(settings.GA); 27 | 28 | //initiate the express web app 29 | var app = express(); 30 | app.use(express.static(__dirname + '/web')); 31 | app.use(ua.middleware(settings.GA)); 32 | app.use(bodyParser.json()); 33 | app.use(bodyParser.urlencoded({extended:true})); 34 | app.set('view engine', 'ejs'); 35 | app.set('views', __dirname+'/web/views'); 36 | 37 | //initiate global variables 38 | var lastPhrase = null; 39 | var userDefaults = new Hashmap(); 40 | var numberOfQueries = null; 41 | 42 | //standard web homepage route 43 | app.get('/', function(req, res){ 44 | res.render('index', {latestQuery: lastPhrase}); 45 | }); 46 | 47 | //privacy route 48 | app.get('/privacy', function(req, res){ 49 | res.render('privacy'); 50 | }); 51 | 52 | //howto route 53 | app.get('/howto', function(req,res){ 54 | res.render('howto'); 55 | }); 56 | 57 | //cretids route 58 | app.get('/contributors', function(req,res){ 59 | //request data from github. 60 | var gh_request_options = { 61 | uri: 'https://api.github.com/repos/matijaabicic/urban-slack/contributors', 62 | method: 'GET', 63 | headers: {'User-Agent':'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)'} 64 | }; 65 | 66 | request(gh_request_options, function callback (error, response, body){ 67 | if(!error && response.statusCode==200) 68 | { 69 | 70 | //pass data to contributors page. 71 | res.render('contributors', {contributors: JSON.parse(body)}); 72 | } 73 | else{ 74 | console.log("Failed request to github."); 75 | console.log(error); 76 | //glitch with github. No data to pass, catch this scenario in contributors.ejs 77 | res.render('contributors', {contributors: []}); 78 | } 79 | }); 80 | 81 | }); 82 | 83 | // history route added in v0.5.1 84 | app.get('/history', function(req,res){ 85 | //request data from github. 86 | var gh_request_options = { 87 | uri: 'https://api.github.com/repos/matijaabicic/urban-slack/releases', 88 | method: 'GET', 89 | headers: {'User-Agent':'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)'} 90 | }; 91 | 92 | request(gh_request_options, function callback(error, response, body){ 93 | if (!error && response.statusCode==200){ 94 | //pass data to history page 95 | res.render('history', {releases : JSON.parse(body)}); 96 | } 97 | else { 98 | console.log("Failed request to github."); 99 | console.log(error); 100 | //glitch with github. no data to pass, catch this scenario in history.ejs 101 | res.render('history',{releases : []}); 102 | } 103 | }); 104 | 105 | }); 106 | 107 | //add to slack success route 108 | app.get('/AddSlack', function(req, res){ 109 | visitor.pageview("/AddSlack").send(); 110 | 111 | if (req.query.error) 112 | { 113 | visitor.pageview("/AddSlack/Error").send(); 114 | res.render('add-fail', { errorMessage: "Authorization Failed"}); 115 | } 116 | else { 117 | visitor.pageview("/AddSlack/Success").send(); 118 | //return code will be needed for registering with the team 119 | var code = req.query.code; 120 | //get ready to issue request to Urban API 121 | 122 | //look for secrets first in proc file, then in secrets js. 123 | 124 | var slack_client_ID = (process.env.secret_slack_client_ID ? process.env.secret_slack_client_ID : secrets.secret_slack_client_ID); 125 | var slack_client_secret = (process.env.secret_slack_client_secret ? process.env.secret_slack_client_secret : secrets.secret_slack_client_secret); 126 | 127 | // #51 - Update Scopes 128 | var slack_authorization = settings.slackOAuthURI + process.env.secret_slack_client_ID + '&scope=commands' 129 | '?client_id=' + slack_client_ID 130 | /* #51 - changed authorization process 131 | '&client_secret=' + slack_client_secret + 132 | '&code=' + code + 133 | '&redirect_uri=' + settings.slackRedirectURI_heroku; 134 | end of #51 */ 135 | 136 | //set urban api url; 137 | var options = { 138 | url: slack_authorization 139 | }; 140 | //hit up urban dictionary API 141 | request(options, function callback (error, response, body){ 142 | 143 | var bodyJson = JSON.parse(body); 144 | 145 | if (!(bodyJson.ok)){ 146 | visitor.pageview("/AddSlack/Error").send(); 147 | 148 | res.render('add-fail', {errorMessage : bodyJson.error}); 149 | } 150 | else { 151 | res.render('add-success'); 152 | } 153 | }); 154 | 155 | } 156 | }); 157 | 158 | //api route 159 | app.post('/api', function(req, res){ 160 | //google pageview tracking 161 | visitor.pageview("/api").send(); 162 | 163 | //capture request details and prepare for Urban API request 164 | var req_command = req.body.command; 165 | var req_text = req.body.text; 166 | var req_team_id = req.body.team_id; 167 | var req_team_domain = req.body.team_domain; 168 | var req_channel_id = req.body.channel_id; 169 | var req_channel_name = req.body.channel_name; 170 | var req_user_id = req.body.user_id; 171 | var req_user_name = req.body.user_name; 172 | 173 | 174 | // define userKey that we will need for dealing with default user settings 175 | var userKey = req_team_id + "~" + req_user_id; 176 | 177 | //parse command and look for switches 178 | // added userDefaults in v1.0.0 to address #26 - User Default settings 179 | var parsedCommand = commandParser.parse(req_text, userDefaults.get(userKey)); 180 | 181 | 182 | //record current datetime 183 | var currentDate = new Date(); 184 | 185 | //record requests in mLab 186 | var mlabOptions = { 187 | "database" : settings.mongoDBName, 188 | "collectionName" : "phrases", 189 | "documents" : { 190 | "responseType" : parsedCommand.responseType, 191 | "queryText" : (parsedCommand.last ? mLabHelper.GetLastQueryForUser(req_team_id, req_user_id) : parsedCommand.Command), 192 | "filter" : parsedCommand.rating, 193 | "random" : parsedCommand.random, 194 | "last" : parsedCommand.last, 195 | "more" : parsedCommand.more, 196 | "datetime" : currentDate, 197 | "team_id" : req_team_id, 198 | "cahnnel_id" : req_channel_id, 199 | "user_id" : req_user_id, 200 | } 201 | }; 202 | 203 | //if command is "?", just return the help page. no need to call urban API 204 | //sanitize whitespaces and see if all we have left is ? 205 | //should be able to post this publically and privately 206 | if (parsedCommand.Command.replace(/ /g,'') == '?'){ 207 | res.send(helper.help(parsedCommand.responseType, req_command)); 208 | mlabOptions.documents.result_type = "help"; 209 | 210 | //now insert help data to mLab 211 | mlab.insertDocuments(mlabOptions, function(err, data){ 212 | if(err){ 213 | console.log(err); 214 | } 215 | else { 216 | //debug only 217 | //console.log("Mongo insert ok."); 218 | } 219 | }); 220 | } 221 | // #26 - implemented in v1.0.0 - setting user defaults 222 | // do not query urban dictionary in this case, just set the defaults for the user 223 | else if (parsedCommand.defaults){ 224 | // 1. construct team-user keyboard 225 | var userValue = {"rating":parsedCommand.rating, "random":parsedCommand.random,"responseType":parsedCommand.responseType}; 226 | 227 | // 2. store team-user default values in memory 228 | userDefaults.set(userKey, userValue); 229 | 230 | // 3. write team-user default values to database 231 | mLabHelper.UpdateUserSettings(userKey, userValue); 232 | 233 | // 4. return confirmation message to the user 234 | res.send(settingsConfirmation.confirm(userValue)); 235 | } 236 | // #41 implemented in 1.0.2 - return user settings with --mysettings switch 237 | else if (parsedCommand.mysettings){ 238 | // 1. pick the current user values 239 | var userSettingValue = userDefaults.get(userKey); 240 | // 2. add --mysetgings flag 241 | if (userSettingValue) userSettingValue.getSettings = true; 242 | // 2. run it throuhg the helper function 243 | // 3. return to user 244 | res.send(settingsConfirmation.confirm(userSettingValue)); 245 | } 246 | // #43 - implemented in v1.1.0 - ability to receive in-app feedback with --feedback switch 247 | else if (parsedCommand.feedback) 248 | { 249 | // 1. record the feedback to data store 250 | //1a. record query type for general tracking 251 | mlabOptions.documents.result_type = "feedback"; 252 | mlab.insertDocuments(mlabOptions, function(err, data){ 253 | if(err){console.log(err); 254 | } 255 | }); 256 | //1b. record specific feedback into separate collection 257 | mLabHelper.insertUserFeedback(parsedCommand.Command); 258 | // 2. return a thank you response to the user. 259 | res.send(feedbackConfirmation.confirm()); 260 | } 261 | 262 | //otherwise, we have a real request. 263 | else{ 264 | //if requesting last, we need to fetch it from the DB first 265 | //this can be moved to in-memory later 266 | //get ready to issue request to Urban API 267 | 268 | var urban_request = ""; 269 | // #45 - Random (surprise) phrase. Added in v1.2.0 270 | if (parsedCommand.surprise){ 271 | urban_request = settings.randomUrbanAPI; 272 | } 273 | else { 274 | urban_request = settings.urbanAPI + mlabOptions.documents.queryText; // (parsedCommand.last ? mLabHelper.GetLastQueryForUser(req_team_id, req_user_id) : parsedCommand.Command); 275 | } 276 | //set urban api url; 277 | var options = { 278 | url: urban_request 279 | }; 280 | //hit up urban dictionary API 281 | request(options, function callback (error, response, body){ 282 | if (!error && response.statusCode==200){ 283 | //#43 - increment total number of queries 284 | numberOfQueries += 1; 285 | 286 | if (numberOfQueries % settings.feedbackPromptInterval === 0){ 287 | parsedCommand.prompt = true; 288 | } 289 | //send the cleaned-up command and response type to parser 290 | //res.send(urbanParser.parse(body, parsedCommand.responseType, parsedCommand.rating)); 291 | // changed in v0.4.1 to pass back the entire parsedCommand 292 | res.send(urbanParser.parse(body, parsedCommand)); 293 | 294 | } 295 | else { 296 | console.error(); 297 | } 298 | 299 | //save the type of response from UD API 300 | var result_type = JSON.parse(body).result_type; 301 | // added in v1.2.0 - #45 - treat random surprise queries separately 302 | if (parsedCommand.surprise) result_type = 'surprise'; 303 | 304 | //update lastPhrase if we've got an exact response 305 | if(result_type=="exact"){ 306 | lastPhrase = mlabOptions.documents.queryText; 307 | } 308 | 309 | //record the result we got from UD API 310 | mlabOptions.documents.result_type = result_type; 311 | 312 | //now insert response data to mLab 313 | mlab.insertDocuments(mlabOptions, function(err, data){ 314 | if(err){ 315 | console.log(err); 316 | } 317 | else { 318 | //debug only 319 | //console.log("Mongo insert ok."); 320 | } 321 | }); 322 | }); 323 | } 324 | }); 325 | 326 | 327 | //start the server and listen on the designated port 328 | var server = app.listen(process.env.PORT || PORT, function(){ 329 | console.log("Server started at localhost:%s", PORT); 330 | 331 | lastPhrase = mLabHelper.GetLastQuery(); 332 | //numberOfQueries = mLabHelper.getTotalNumberOfUserQueries(); // for some reason this returns as undefined. investigate later. 333 | mlab.listDocuments({"database":settings.mongoDBName, "collectionName":"phrases","resultCount":true}, function(err, data){ 334 | if(!err){ 335 | numberOfQueries = data; 336 | } 337 | else numberOfQueries = -1; 338 | }); 339 | 340 | // #26 - v1.0.0 - reload the team member defaults. 341 | // first load all user settings from db 342 | var persistentUserSettings = mLabHelper.GetAllUserSettings(); 343 | //then add them all to the hashmap 344 | for (var i = 0, len = persistentUserSettings.length; i"+d+"{#modernizr{height:3px}}"+"").appendTo("head"),f=b('
').appendTo("html");a=f.height()===3,f.remove(),e.remove()}return a},csstransitions:function(){return!!j}},l;if(e)for(l in k)e.hasOwnProperty(l)||e.addTest(l,k[l]);else{e=a.Modernizr={_version:"1.6ish: miniModernizr for Isotope"};var m=" ",n;for(l in k)n=k[l](),e[l]=n,m+=" "+(n?"":"no-")+l;b("html").addClass(m)}if(e.csstransforms){var o=e.csstransforms3d?{translate:function(a){return"translate3d("+a[0]+"px, "+a[1]+"px, 0) "},scale:function(a){return"scale3d("+a+", "+a+", 1) "}}:{translate:function(a){return"translate("+a[0]+"px, "+a[1]+"px) "},scale:function(a){return"scale("+a+") "}},p=function(a,c,d){var e=b.data(a,"isoTransform")||{},f={},g,h={},j;f[c]=d,b.extend(e,f);for(g in e)j=e[g],h[g]=o[g](j);var k=h.translate||"",l=h.scale||"",m=k+l;b.data(a,"isoTransform",e),a.style[i]=m};b.cssNumber.scale=!0,b.cssHooks.scale={set:function(a,b){p(a,"scale",b)},get:function(a,c){var d=b.data(a,"isoTransform");return d&&d.scale?d.scale:1}},b.fx.step.scale=function(a){b.cssHooks.scale.set(a.elem,a.now+a.unit)},b.cssNumber.translate=!0,b.cssHooks.translate={set:function(a,b){p(a,"translate",b)},get:function(a,c){var d=b.data(a,"isoTransform");return d&&d.translate?d.translate:[0,0]}}}var q,r;e.csstransitions&&(q={WebkitTransitionProperty:"webkitTransitionEnd",MozTransitionProperty:"transitionend",OTransitionProperty:"oTransitionEnd otransitionend",transitionProperty:"transitionend"}[j],r=h("transitionDuration"));var s=b.event,t=b.event.handle?"handle":"dispatch",u;s.special.smartresize={setup:function(){b(this).bind("resize",s.special.smartresize.handler)},teardown:function(){b(this).unbind("resize",s.special.smartresize.handler)},handler:function(a,b){var c=this,d=arguments;a.type="smartresize",u&&clearTimeout(u),u=setTimeout(function(){s[t].apply(c,d)},b==="execAsap"?0:100)}},b.fn.smartresize=function(a){return a?this.bind("smartresize",a):this.trigger("smartresize",["execAsap"])},b.Isotope=function(a,c,d){this.element=b(c),this._create(a),this._init(d)};var v=["width","height"],w=b(a);b.Isotope.settings={resizable:!0,layoutMode:"masonry",containerClass:"isotope",itemClass:"isotope-item",hiddenClass:"isotope-hidden",hiddenStyle:{opacity:0,scale:.001},visibleStyle:{opacity:1,scale:1},containerStyle:{position:"relative",overflow:"hidden"},animationEngine:"best-available",animationOptions:{queue:!1,duration:800},sortBy:"original-order",sortAscending:!0,resizesContainer:!0,transformsEnabled:!0,itemPositionDataEnabled:!1},b.Isotope.prototype={_create:function(a){this.options=b.extend({},b.Isotope.settings,a),this.styleQueue=[],this.elemCount=0;var c=this.element[0].style;this.originalStyle={};var d=v.slice(0);for(var e in this.options.containerStyle)d.push(e);for(var f=0,g=d.length;fg?1:f0&&(i=function(a,b){b.$el[d](b.style,f).one(q,k)},j=!1)}}b.each(this.styleQueue,i),j&&k(),this.styleQueue=[]},resize:function(){this["_"+this.options.layoutMode+"ResizeChanged"]()&&this.reLayout()},reLayout:function(a){this["_"+this.options.layoutMode+"Reset"](),this.layout(this.$filteredAtoms,a)},addItems:function(a,b){var c=this._getAtoms(a);this.$allAtoms=this.$allAtoms.add(c),b&&b(c)},insert:function(a,b){this.element.append(a);var c=this;this.addItems(a,function(a){var d=c._filter(a);c._addHideAppended(d),c._sort(),c.reLayout(),c._revealAppended(d,b)})},appended:function(a,b){var c=this;this.addItems(a,function(a){c._addHideAppended(a),c.layout(a),c._revealAppended(a,b)})},_addHideAppended:function(a){this.$filteredAtoms=this.$filteredAtoms.add(a),a.addClass("no-transition"),this._isInserting=!0,this.styleQueue.push({$el:a,style:this.options.hiddenStyle})},_revealAppended:function(a,b){var c=this;setTimeout(function(){a.removeClass("no-transition"),c.styleQueue.push({$el:a,style:c.options.visibleStyle}),c._isInserting=!1,c._processStyleQueue(a,b)},10)},reloadItems:function(){this.$allAtoms=this._getAtoms(this.element.children())},remove:function(a,b){this.$allAtoms=this.$allAtoms.not(a),this.$filteredAtoms=this.$filteredAtoms.not(a);var c=this,d=function(){a.remove(),b&&b.call(c.element)};a.filter(":not(."+this.options.hiddenClass+")").length?(this.styleQueue.push({$el:a,style:this.options.hiddenStyle}),this._sort(),this.reLayout(d)):d()},shuffle:function(a){this.updateSortData(this.$allAtoms),this.options.sortBy="random",this._sort(),this.reLayout(a)},destroy:function(){var a=this.usingTransforms,b=this.options;this.$allAtoms.removeClass(b.hiddenClass+" "+b.itemClass).each(function(){var b=this.style;b.position="",b.top="",b.left="",b.opacity="",a&&(b[i]="")});var c=this.element[0].style;for(var d in this.originalStyle)c[d]=this.originalStyle[d];this.element.unbind(".isotope").undelegate("."+b.hiddenClass,"click").removeClass(b.containerClass).removeData("isotope"),w.unbind(".isotope")},_getSegments:function(a){var b=this.options.layoutMode,c=a?"rowHeight":"columnWidth",d=a?"height":"width",e=a?"rows":"cols",g=this.element[d](),h,i=this.options[b]&&this.options[b][c]||this.$filteredAtoms["outer"+f(d)](!0)||g;h=Math.floor(g/i),h=Math.max(h,1),this[b][e]=h,this[b][c]=i},_checkIfSegmentsChanged:function(a){var b=this.options.layoutMode,c=a?"rows":"cols",d=this[b][c];return this._getSegments(a),this[b][c]!==d},_masonryReset:function(){this.masonry={},this._getSegments();var a=this.masonry.cols;this.masonry.colYs=[];while(a--)this.masonry.colYs.push(0)},_masonryLayout:function(a){var c=this,d=c.masonry;a.each(function(){var a=b(this),e=Math.ceil(a.outerWidth(!0)/d.columnWidth);e=Math.min(e,d.cols);if(e===1)c._masonryPlaceBrick(a,d.colYs);else{var f=d.cols+1-e,g=[],h,i;for(i=0;id&&(e.x=0,e.y=e.height),c._pushPosition(a,e.x,e.y),e.height=Math.max(e.y+g,e.height),e.x+=f})},_fitRowsGetContainerSize:function(){return{height:this.fitRows.height}},_fitRowsResizeChanged:function(){return!0},_cellsByRowReset:function(){this.cellsByRow={index:0},this._getSegments(),this._getSegments(!0)},_cellsByRowLayout:function(a){var c=this,d=this.cellsByRow;a.each(function(){var a=b(this),e=d.index%d.cols,f=Math.floor(d.index/d.cols),g=(e+.5)*d.columnWidth-a.outerWidth(!0)/2,h=(f+.5)*d.rowHeight-a.outerHeight(!0)/2;c._pushPosition(a,g,h),d.index++})},_cellsByRowGetContainerSize:function(){return{height:Math.ceil(this.$filteredAtoms.length/this.cellsByRow.cols)*this.cellsByRow.rowHeight+this.offset.top}},_cellsByRowResizeChanged:function(){return this._checkIfSegmentsChanged()},_straightDownReset:function(){this.straightDown={y:0}},_straightDownLayout:function(a){var c=this;a.each(function(a){var d=b(this);c._pushPosition(d,0,c.straightDown.y),c.straightDown.y+=d.outerHeight(!0)})},_straightDownGetContainerSize:function(){return{height:this.straightDown.y}},_straightDownResizeChanged:function(){return!0},_masonryHorizontalReset:function(){this.masonryHorizontal={},this._getSegments(!0);var a=this.masonryHorizontal.rows;this.masonryHorizontal.rowXs=[];while(a--)this.masonryHorizontal.rowXs.push(0)},_masonryHorizontalLayout:function(a){var c=this,d=c.masonryHorizontal;a.each(function(){var a=b(this),e=Math.ceil(a.outerHeight(!0)/d.rowHeight);e=Math.min(e,d.rows);if(e===1)c._masonryHorizontalPlaceBrick(a,d.rowXs);else{var f=d.rows+1-e,g=[],h,i;for(i=0;id&&(e.x=e.width,e.y=0),c._pushPosition(a,e.x,e.y),e.width=Math.max(e.x+f,e.width),e.y+=g})},_fitColumnsGetContainerSize:function(){return{width:this.fitColumns.width}},_fitColumnsResizeChanged:function(){return!0},_cellsByColumnReset:function(){this.cellsByColumn={index:0},this._getSegments(),this._getSegments(!0)},_cellsByColumnLayout:function(a){var c=this,d=this.cellsByColumn;a.each(function(){var a=b(this),e=Math.floor(d.index/d.rows),f=d.index%d.rows,g=(e+.5)*d.columnWidth-a.outerWidth(!0)/2,h=(f+.5)*d.rowHeight-a.outerHeight(!0)/2;c._pushPosition(a,g,h),d.index++})},_cellsByColumnGetContainerSize:function(){return{width:Math.ceil(this.$filteredAtoms.length/this.cellsByColumn.rows)*this.cellsByColumn.columnWidth}},_cellsByColumnResizeChanged:function(){return this._checkIfSegmentsChanged(!0)},_straightAcrossReset:function(){this.straightAcross={x:0}},_straightAcrossLayout:function(a){var c=this;a.each(function(a){var d=b(this);c._pushPosition(d,c.straightAcross.x,0),c.straightAcross.x+=d.outerWidth(!0)})},_straightAcrossGetContainerSize:function(){return{width:this.straightAcross.x}},_straightAcrossResizeChanged:function(){return!0}},b.fn.imagesLoaded=function(a){function h(){a.call(c,d)}function i(a){var c=a.target;c.src!==f&&b.inArray(c,g)===-1&&(g.push(c),--e<=0&&(setTimeout(h),d.unbind(".imagesLoaded",i)))}var c=this,d=c.find("img").add(c.filter("img")),e=d.length,f="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==",g=[];return e||h(),d.bind("load.imagesLoaded error.imagesLoaded",i).each(function(){var a=this.src;this.src=f,this.src=a}),c};var x=function(b){a.console&&a.console.error(b)};b.fn.isotope=function(a,c){if(typeof a=="string"){var d=Array.prototype.slice.call(arguments,1);this.each(function(){var c=b.data(this,"isotope");if(!c){x("cannot call methods on isotope prior to initialization; attempted to call method '"+a+"'");return}if(!b.isFunction(c[a])||a.charAt(0)==="_"){x("no such method '"+a+"' for isotope instance");return}c[a].apply(c,d)})}else this.each(function(){var d=b.data(this,"isotope");d?(d.option(a),d._init(c)):b.data(this,"isotope",new b.Isotope(a,this,c))});return this}})(window,jQuery); -------------------------------------------------------------------------------- /web/assets/css/font-awesome.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.0.3');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.3333333333333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.2857142857142858em;text-align:center}.fa-ul{padding-left:0;margin-left:2.142857142857143em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;top:.14285714285714285em;text-align:center}.fa-li.fa-lg{left:-1.8571428571428572em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0,mirror=1);-webkit-transform:scale(-1,1);-moz-transform:scale(-1,1);-ms-transform:scale(-1,1);-o-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2,mirror=1);-webkit-transform:scale(1,-1);-moz-transform:scale(1,-1);-ms-transform:scale(1,-1);-o-transform:scale(1,-1);transform:scale(1,-1)}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-asc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-desc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-reply-all:before{content:"\f122"}.fa-mail-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"} -------------------------------------------------------------------------------- /web/assets/css/prettyPhoto.css: -------------------------------------------------------------------------------- 1 | div.pp_default .pp_top,div.pp_default .pp_top .pp_middle,div.pp_default .pp_top .pp_left,div.pp_default .pp_top .pp_right,div.pp_default .pp_bottom,div.pp_default .pp_bottom .pp_left,div.pp_default .pp_bottom .pp_middle,div.pp_default .pp_bottom .pp_right{height:13px} 2 | div.pp_default .pp_top .pp_left{background:url("images/prettyPhoto/default/sprite.png") -78px -93px no-repeat} 3 | div.pp_default .pp_top .pp_middle{background:url("images/prettyPhoto/default/sprite_x.png") top left repeat-x} 4 | div.pp_default .pp_top .pp_right{background:url("images/prettyPhoto/default/sprite.png") -112px -93px no-repeat} 5 | div.pp_default .pp_content .ppt{color:#f8f8f8} 6 | div.pp_default .pp_content_container .pp_left{background:url("images/prettyPhoto/default/sprite_y.png") -7px 0 repeat-y;padding-left:13px} 7 | div.pp_default .pp_content_container .pp_right{background:url("images/prettyPhoto/default/sprite_y.png") top right repeat-y;padding-right:13px} 8 | div.pp_default .pp_next:hover{background:url("images/prettyPhoto/default/sprite_next.png") center right no-repeat;cursor:pointer} 9 | div.pp_default .pp_previous:hover{background:url("images/prettyPhoto/default/sprite_prev.png") center left no-repeat;cursor:pointer} 10 | div.pp_default .pp_expand{background:url("images/prettyPhoto/default/sprite.png") 0 -29px no-repeat;cursor:pointer;width:28px;height:28px} 11 | div.pp_default .pp_expand:hover{background:url("images/prettyPhoto/default/sprite.png") 0 -56px no-repeat;cursor:pointer} 12 | div.pp_default .pp_contract{background:url("images/prettyPhoto/default/sprite.png") 0 -84px no-repeat;cursor:pointer;width:28px;height:28px} 13 | div.pp_default .pp_contract:hover{background:url("images/prettyPhoto/default/sprite.png") 0 -113px no-repeat;cursor:pointer} 14 | div.pp_default .pp_close{width:30px;height:30px;background:url("images/prettyPhoto/default/sprite.png") 2px 1px no-repeat;cursor:pointer} 15 | div.pp_default .pp_gallery ul li a{background:url("images/prettyPhoto/default/default_thumb.png") center center #f8f8f8;border:1px solid #aaa} 16 | div.pp_default .pp_social{margin-top:7px} 17 | div.pp_default .pp_gallery a.pp_arrow_previous,div.pp_default .pp_gallery a.pp_arrow_next{position:static;left:auto} 18 | div.pp_default .pp_nav .pp_play,div.pp_default .pp_nav .pp_pause{background:url("images/prettyPhoto/default/sprite.png") -51px 1px no-repeat;height:30px;width:30px} 19 | div.pp_default .pp_nav .pp_pause{background-position:-51px -29px} 20 | div.pp_default a.pp_arrow_previous,div.pp_default a.pp_arrow_next{background:url("images/prettyPhoto/default/sprite.png") -31px -3px no-repeat;height:20px;width:20px;margin:4px 0 0} 21 | div.pp_default a.pp_arrow_next{left:52px;background-position:-82px -3px} 22 | div.pp_default .pp_content_container .pp_details{margin-top:5px} 23 | div.pp_default .pp_nav{clear:none;height:30px;width:110px;position:relative} 24 | div.pp_default .pp_nav .currentTextHolder{font-family:Georgia;font-style:italic;color:#999;font-size:11px;left:75px;line-height:25px;position:absolute;top:2px;margin:0;padding:0 0 0 10px} 25 | div.pp_default .pp_close:hover,div.pp_default .pp_nav .pp_play:hover,div.pp_default .pp_nav .pp_pause:hover,div.pp_default .pp_arrow_next:hover,div.pp_default .pp_arrow_previous:hover{opacity:0.7} 26 | div.pp_default .pp_description{font-size:11px;font-weight:700;line-height:14px;margin:5px 50px 5px 0} 27 | div.pp_default .pp_bottom .pp_left{background:url("images/prettyPhoto/default/sprite.png") -78px -127px no-repeat} 28 | div.pp_default .pp_bottom .pp_middle{background:url("images/prettyPhoto/default/sprite_x.png") bottom left repeat-x} 29 | div.pp_default .pp_bottom .pp_right{background:url("images/prettyPhoto/default/sprite.png") -112px -127px no-repeat} 30 | div.pp_default .pp_loaderIcon{background:url("images/prettyPhoto/default/loader.gif") center center no-repeat} 31 | div.light_rounded .pp_top .pp_left{background:url("images/prettyPhoto/light_rounded/sprite.png") -88px -53px no-repeat} 32 | div.light_rounded .pp_top .pp_right{background:url("images/prettyPhoto/light_rounded/sprite.png") -110px -53px no-repeat} 33 | div.light_rounded .pp_next:hover{background:url("images/prettyPhoto/light_rounded/btnNext.png") center right no-repeat;cursor:pointer} 34 | div.light_rounded .pp_previous:hover{background:url("images/prettyPhoto/light_rounded/btnPrevious.png") center left no-repeat;cursor:pointer} 35 | div.light_rounded .pp_expand{background:url("images/prettyPhoto/light_rounded/sprite.png") -31px -26px no-repeat;cursor:pointer} 36 | div.light_rounded .pp_expand:hover{background:url("images/prettyPhoto/light_rounded/sprite.png") -31px -47px no-repeat;cursor:pointer} 37 | div.light_rounded .pp_contract{background:url("images/prettyPhoto/light_rounded/sprite.png") 0 -26px no-repeat;cursor:pointer} 38 | div.light_rounded .pp_contract:hover{background:url("images/prettyPhoto/light_rounded/sprite.png") 0 -47px no-repeat;cursor:pointer} 39 | div.light_rounded .pp_close{width:75px;height:22px;background:url("images/prettyPhoto/light_rounded/sprite.png") -1px -1px no-repeat;cursor:pointer} 40 | div.light_rounded .pp_nav .pp_play{background:url("images/prettyPhoto/light_rounded/sprite.png") -1px -100px no-repeat;height:15px;width:14px} 41 | div.light_rounded .pp_nav .pp_pause{background:url("images/prettyPhoto/light_rounded/sprite.png") -24px -100px no-repeat;height:15px;width:14px} 42 | div.light_rounded .pp_arrow_previous{background:url("images/prettyPhoto/light_rounded/sprite.png") 0 -71px no-repeat} 43 | div.light_rounded .pp_arrow_next{background:url("images/prettyPhoto/light_rounded/sprite.png") -22px -71px no-repeat} 44 | div.light_rounded .pp_bottom .pp_left{background:url("images/prettyPhoto/light_rounded/sprite.png") -88px -80px no-repeat} 45 | div.light_rounded .pp_bottom .pp_right{background:url("images/prettyPhoto/light_rounded/sprite.png") -110px -80px no-repeat} 46 | div.dark_rounded .pp_top .pp_left{background:url("images/prettyPhoto/dark_rounded/sprite.png") -88px -53px no-repeat} 47 | div.dark_rounded .pp_top .pp_right{background:url("images/prettyPhoto/dark_rounded/sprite.png") -110px -53px no-repeat} 48 | div.dark_rounded .pp_content_container .pp_left{background:url("images/prettyPhoto/dark_rounded/contentPattern.png") top left repeat-y} 49 | div.dark_rounded .pp_content_container .pp_right{background:url("images/prettyPhoto/dark_rounded/contentPattern.png") top right repeat-y} 50 | div.dark_rounded .pp_next:hover{background:url("images/prettyPhoto/dark_rounded/btnNext.png") center right no-repeat;cursor:pointer} 51 | div.dark_rounded .pp_previous:hover{background:url("images/prettyPhoto/dark_rounded/btnPrevious.png") center left no-repeat;cursor:pointer} 52 | div.dark_rounded .pp_expand{background:url("images/prettyPhoto/dark_rounded/sprite.png") -31px -26px no-repeat;cursor:pointer} 53 | div.dark_rounded .pp_expand:hover{background:url("images/prettyPhoto/dark_rounded/sprite.png") -31px -47px no-repeat;cursor:pointer} 54 | div.dark_rounded .pp_contract{background:url("images/prettyPhoto/dark_rounded/sprite.png") 0 -26px no-repeat;cursor:pointer} 55 | div.dark_rounded .pp_contract:hover{background:url("images/prettyPhoto/dark_rounded/sprite.png") 0 -47px no-repeat;cursor:pointer} 56 | div.dark_rounded .pp_close{width:75px;height:22px;background:url("images/prettyPhoto/dark_rounded/sprite.png") -1px -1px no-repeat;cursor:pointer} 57 | div.dark_rounded .pp_description{margin-right:85px;color:#fff} 58 | div.dark_rounded .pp_nav .pp_play{background:url("images/prettyPhoto/dark_rounded/sprite.png") -1px -100px no-repeat;height:15px;width:14px} 59 | div.dark_rounded .pp_nav .pp_pause{background:url("images/prettyPhoto/dark_rounded/sprite.png") -24px -100px no-repeat;height:15px;width:14px} 60 | div.dark_rounded .pp_arrow_previous{background:url("images/prettyPhoto/dark_rounded/sprite.png") 0 -71px no-repeat} 61 | div.dark_rounded .pp_arrow_next{background:url("images/prettyPhoto/dark_rounded/sprite.png") -22px -71px no-repeat} 62 | div.dark_rounded .pp_bottom .pp_left{background:url("images/prettyPhoto/dark_rounded/sprite.png") -88px -80px no-repeat} 63 | div.dark_rounded .pp_bottom .pp_right{background:url("images/prettyPhoto/dark_rounded/sprite.png") -110px -80px no-repeat} 64 | div.dark_rounded .pp_loaderIcon{background:url("images/prettyPhoto/dark_rounded/loader.gif") center center no-repeat} 65 | div.dark_square .pp_left,div.dark_square .pp_middle,div.dark_square .pp_right,div.dark_square .pp_content{background:#000} 66 | div.dark_square .pp_description{color:#fff;margin:0 85px 0 0} 67 | div.dark_square .pp_loaderIcon{background:url("images/prettyPhoto/dark_square/loader.gif") center center no-repeat} 68 | div.dark_square .pp_expand{background:url("images/prettyPhoto/dark_square/sprite.png") -31px -26px no-repeat;cursor:pointer} 69 | div.dark_square .pp_expand:hover{background:url("images/prettyPhoto/dark_square/sprite.png") -31px -47px no-repeat;cursor:pointer} 70 | div.dark_square .pp_contract{background:url("images/prettyPhoto/dark_square/sprite.png") 0 -26px no-repeat;cursor:pointer} 71 | div.dark_square .pp_contract:hover{background:url("images/prettyPhoto/dark_square/sprite.png") 0 -47px no-repeat;cursor:pointer} 72 | div.dark_square .pp_close{width:75px;height:22px;background:url("images/prettyPhoto/dark_square/sprite.png") -1px -1px no-repeat;cursor:pointer} 73 | div.dark_square .pp_nav{clear:none} 74 | div.dark_square .pp_nav .pp_play{background:url("images/prettyPhoto/dark_square/sprite.png") -1px -100px no-repeat;height:15px;width:14px} 75 | div.dark_square .pp_nav .pp_pause{background:url("images/prettyPhoto/dark_square/sprite.png") -24px -100px no-repeat;height:15px;width:14px} 76 | div.dark_square .pp_arrow_previous{background:url("images/prettyPhoto/dark_square/sprite.png") 0 -71px no-repeat} 77 | div.dark_square .pp_arrow_next{background:url("images/prettyPhoto/dark_square/sprite.png") -22px -71px no-repeat} 78 | div.dark_square .pp_next:hover{background:url("images/prettyPhoto/dark_square/btnNext.png") center right no-repeat;cursor:pointer} 79 | div.dark_square .pp_previous:hover{background:url("images/prettyPhoto/dark_square/btnPrevious.png") center left no-repeat;cursor:pointer} 80 | div.light_square .pp_expand{background:url("images/prettyPhoto/light_square/sprite.png") -31px -26px no-repeat;cursor:pointer} 81 | div.light_square .pp_expand:hover{background:url("images/prettyPhoto/light_square/sprite.png") -31px -47px no-repeat;cursor:pointer} 82 | div.light_square .pp_contract{background:url("images/prettyPhoto/light_square/sprite.png") 0 -26px no-repeat;cursor:pointer} 83 | div.light_square .pp_contract:hover{background:url("images/prettyPhoto/light_square/sprite.png") 0 -47px no-repeat;cursor:pointer} 84 | div.light_square .pp_close{width:75px;height:22px;background:url("images/prettyPhoto/light_square/sprite.png") -1px -1px no-repeat;cursor:pointer} 85 | div.light_square .pp_nav .pp_play{background:url("images/prettyPhoto/light_square/sprite.png") -1px -100px no-repeat;height:15px;width:14px} 86 | div.light_square .pp_nav .pp_pause{background:url("images/prettyPhoto/light_square/sprite.png") -24px -100px no-repeat;height:15px;width:14px} 87 | div.light_square .pp_arrow_previous{background:url("images/prettyPhoto/light_square/sprite.png") 0 -71px no-repeat} 88 | div.light_square .pp_arrow_next{background:url("images/prettyPhoto/light_square/sprite.png") -22px -71px no-repeat} 89 | div.light_square .pp_next:hover{background:url("images/prettyPhoto/light_square/btnNext.png") center right no-repeat;cursor:pointer} 90 | div.light_square .pp_previous:hover{background:url("images/prettyPhoto/light_square/btnPrevious.png") center left no-repeat;cursor:pointer} 91 | div.facebook .pp_top .pp_left{background:url("images/prettyPhoto/facebook/sprite.png") -88px -53px no-repeat} 92 | div.facebook .pp_top .pp_middle{background:url("images/prettyPhoto/facebook/contentPatternTop.png") top left repeat-x} 93 | div.facebook .pp_top .pp_right{background:url("images/prettyPhoto/facebook/sprite.png") -110px -53px no-repeat} 94 | div.facebook .pp_content_container .pp_left{background:url("images/prettyPhoto/facebook/contentPatternLeft.png") top left repeat-y} 95 | div.facebook .pp_content_container .pp_right{background:url("images/prettyPhoto/facebook/contentPatternRight.png") top right repeat-y} 96 | div.facebook .pp_expand{background:url("images/prettyPhoto/facebook/sprite.png") -31px -26px no-repeat;cursor:pointer} 97 | div.facebook .pp_expand:hover{background:url("images/prettyPhoto/facebook/sprite.png") -31px -47px no-repeat;cursor:pointer} 98 | div.facebook .pp_contract{background:url("images/prettyPhoto/facebook/sprite.png") 0 -26px no-repeat;cursor:pointer} 99 | div.facebook .pp_contract:hover{background:url("images/prettyPhoto/facebook/sprite.png") 0 -47px no-repeat;cursor:pointer} 100 | div.facebook .pp_close{width:22px;height:22px;background:url("images/prettyPhoto/facebook/sprite.png") -1px -1px no-repeat;cursor:pointer} 101 | div.facebook .pp_description{margin:0 37px 0 0} 102 | div.facebook .pp_loaderIcon{background:url("images/prettyPhoto/facebook/loader.gif") center center no-repeat} 103 | div.facebook .pp_arrow_previous{background:url("images/prettyPhoto/facebook/sprite.png") 0 -71px no-repeat;height:22px;margin-top:0;width:22px} 104 | div.facebook .pp_arrow_previous.disabled{background-position:0 -96px;cursor:default} 105 | div.facebook .pp_arrow_next{background:url("images/prettyPhoto/facebook/sprite.png") -32px -71px no-repeat;height:22px;margin-top:0;width:22px} 106 | div.facebook .pp_arrow_next.disabled{background-position:-32px -96px;cursor:default} 107 | div.facebook .pp_nav{margin-top:0} 108 | div.facebook .pp_nav p{font-size:15px;padding:0 3px 0 4px} 109 | div.facebook .pp_nav .pp_play{background:url("images/prettyPhoto/facebook/sprite.png") -1px -123px no-repeat;height:22px;width:22px} 110 | div.facebook .pp_nav .pp_pause{background:url("images/prettyPhoto/facebook/sprite.png") -32px -123px no-repeat;height:22px;width:22px} 111 | div.facebook .pp_next:hover{background:url("images/prettyPhoto/facebook/btnNext.png") center right no-repeat;cursor:pointer} 112 | div.facebook .pp_previous:hover{background:url("images/prettyPhoto/facebook/btnPrevious.png") center left no-repeat;cursor:pointer} 113 | div.facebook .pp_bottom .pp_left{background:url("images/prettyPhoto/facebook/sprite.png") -88px -80px no-repeat} 114 | div.facebook .pp_bottom .pp_middle{background:url("images/prettyPhoto/facebook/contentPatternBottom.png") top left repeat-x} 115 | div.facebook .pp_bottom .pp_right{background:url("images/prettyPhoto/facebook/sprite.png") -110px -80px no-repeat} 116 | div.pp_pic_holder a:focus{outline:none} 117 | div.pp_overlay{background:#000;display:none;left:0;position:absolute;top:0;width:100%;z-index:9500} 118 | div.pp_pic_holder{display:none;position:absolute;width:100px;z-index:10000} 119 | .pp_content{height:40px;min-width:40px} 120 | * html .pp_content{width:40px} 121 | .pp_content_container{position:relative;text-align:left;width:100%} 122 | .pp_content_container .pp_left{padding-left:20px} 123 | .pp_content_container .pp_right{padding-right:20px} 124 | .pp_content_container .pp_details{float:left;margin:10px 0 2px} 125 | .pp_description{display:none;margin:0} 126 | .pp_social{float:left;margin:0} 127 | .pp_social .facebook{float:left;margin-left:5px;width:55px;overflow:hidden} 128 | .pp_social .twitter{float:left} 129 | .pp_nav{clear:right;float:left;margin:3px 10px 0 0} 130 | .pp_nav p{float:left;white-space:nowrap;margin:2px 4px} 131 | .pp_nav .pp_play,.pp_nav .pp_pause{float:left;margin-right:4px;text-indent:-10000px} 132 | a.pp_arrow_previous,a.pp_arrow_next{display:block;float:left;height:15px;margin-top:3px;overflow:hidden;text-indent:-10000px;width:14px} 133 | .pp_hoverContainer{position:absolute;top:0;width:100%;z-index:2000} 134 | .pp_gallery{display:none;left:50%;margin-top:-50px;position:absolute;z-index:10000} 135 | .pp_gallery div{float:left;overflow:hidden;position:relative} 136 | .pp_gallery ul{float:left;height:35px;position:relative;white-space:nowrap;margin:0 0 0 5px;padding:0} 137 | .pp_gallery ul a{border:1px rgba(0,0,0,0.5) solid;display:block;float:left;height:33px;overflow:hidden} 138 | .pp_gallery ul a img{border:0} 139 | .pp_gallery li{display:block;float:left;margin:0 5px 0 0;padding:0} 140 | .pp_gallery li.default a{background:url("images/prettyPhoto/facebook/default_thumbnail.gif") 0 0 no-repeat;display:block;height:33px;width:50px} 141 | .pp_gallery .pp_arrow_previous,.pp_gallery .pp_arrow_next{margin-top:7px!important} 142 | a.pp_next{background:url("images/prettyPhoto/light_rounded/btnNext.png") 10000px 10000px no-repeat;display:block;float:right;height:100%;text-indent:-10000px;width:49%} 143 | a.pp_previous{background:url("images/prettyPhoto/light_rounded/btnNext.png") 10000px 10000px no-repeat;display:block;float:left;height:100%;text-indent:-10000px;width:49%} 144 | a.pp_expand,a.pp_contract{cursor:pointer;display:none;height:20px;position:absolute;right:30px;text-indent:-10000px;top:10px;width:20px;z-index:20000} 145 | a.pp_close{position:absolute;right:0;top:0;display:block;line-height:22px;text-indent:-10000px} 146 | .pp_loaderIcon{display:block;height:24px;left:50%;position:absolute;top:50%;width:24px;margin:-12px 0 0 -12px} 147 | #pp_full_res{line-height:1!important} 148 | #pp_full_res .pp_inline{text-align:left} 149 | #pp_full_res .pp_inline p{margin:0 0 15px} 150 | div.ppt{color:#fff;display:none;font-size:17px;z-index:9999;margin:0 0 5px 15px} 151 | div.pp_default .pp_content,div.light_rounded .pp_content{background-color:#fff} 152 | div.pp_default #pp_full_res .pp_inline,div.light_rounded .pp_content .ppt,div.light_rounded #pp_full_res .pp_inline,div.light_square .pp_content .ppt,div.light_square #pp_full_res .pp_inline,div.facebook .pp_content .ppt,div.facebook #pp_full_res .pp_inline{color:#000} 153 | div.pp_default .pp_gallery ul li a:hover,div.pp_default .pp_gallery ul li.selected a,.pp_gallery ul a:hover,.pp_gallery li.selected a{border-color:#fff} 154 | div.pp_default .pp_details,div.light_rounded .pp_details,div.dark_rounded .pp_details,div.dark_square .pp_details,div.light_square .pp_details,div.facebook .pp_details{position:relative} 155 | div.light_rounded .pp_top .pp_middle,div.light_rounded .pp_content_container .pp_left,div.light_rounded .pp_content_container .pp_right,div.light_rounded .pp_bottom .pp_middle,div.light_square .pp_left,div.light_square .pp_middle,div.light_square .pp_right,div.light_square .pp_content,div.facebook .pp_content{background:#fff} 156 | div.light_rounded .pp_description,div.light_square .pp_description{margin-right:85px} 157 | div.light_rounded .pp_gallery a.pp_arrow_previous,div.light_rounded .pp_gallery a.pp_arrow_next,div.dark_rounded .pp_gallery a.pp_arrow_previous,div.dark_rounded .pp_gallery a.pp_arrow_next,div.dark_square .pp_gallery a.pp_arrow_previous,div.dark_square .pp_gallery a.pp_arrow_next,div.light_square .pp_gallery a.pp_arrow_previous,div.light_square .pp_gallery a.pp_arrow_next{margin-top:12px!important} 158 | div.light_rounded .pp_arrow_previous.disabled,div.dark_rounded .pp_arrow_previous.disabled,div.dark_square .pp_arrow_previous.disabled,div.light_square .pp_arrow_previous.disabled{background-position:0 -87px;cursor:default} 159 | div.light_rounded .pp_arrow_next.disabled,div.dark_rounded .pp_arrow_next.disabled,div.dark_square .pp_arrow_next.disabled,div.light_square .pp_arrow_next.disabled{background-position:-22px -87px;cursor:default} 160 | div.light_rounded .pp_loaderIcon,div.light_square .pp_loaderIcon{background:url("images/prettyPhoto/light_rounded/loader.gif") center center no-repeat} 161 | div.dark_rounded .pp_top .pp_middle,div.dark_rounded .pp_content,div.dark_rounded .pp_bottom .pp_middle{background:url("images/prettyPhoto/dark_rounded/contentPattern.png") top left repeat} 162 | div.dark_rounded .currentTextHolder,div.dark_square .currentTextHolder{color:#c4c4c4} 163 | div.dark_rounded #pp_full_res .pp_inline,div.dark_square #pp_full_res .pp_inline{color:#fff} 164 | .pp_top,.pp_bottom{height:20px;position:relative} 165 | * html .pp_top,* html .pp_bottom{padding:0 20px} 166 | .pp_top .pp_left,.pp_bottom .pp_left{height:20px;left:0;position:absolute;width:20px} 167 | .pp_top .pp_middle,.pp_bottom .pp_middle{height:20px;left:20px;position:absolute;right:20px} 168 | * html .pp_top .pp_middle,* html .pp_bottom .pp_middle{left:0;position:static} 169 | .pp_top .pp_right,.pp_bottom .pp_right{height:20px;left:auto;position:absolute;right:0;top:0;width:20px} 170 | .pp_fade,.pp_gallery li.default a img{display:none} --------------------------------------------------------------------------------