├── .gitignore
├── images
├── icon.png
├── icon128.png
├── icon16.png
└── icon48.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
└── glyphicons-halflings-regular.svg
├── screenshots
├── V1.2
│ ├── 1.PNG
│ ├── 2.png
│ ├── 3.png
│ └── 4.png
├── Chrome Settings Menu.PNG
├── Duolingo Notes Version.PNG
├── Set up shortcut key 1.png
├── Set up shortcut key 2.png
├── V1.0
│ ├── Add to Duolingo Notes.png
│ └── Duolingo Notes Popup.png
├── Force Chrome Update Extensions.PNG
├── Right Duolingo Notes Action Button.PNG
└── Duolingo Notes Version On Google Web Store.PNG
├── js
├── jqueryFunctions.js
├── app.js
├── contextScript.addToNotes.js
├── popupCtrl.js
├── html2csv.js
├── underscore-min.js
├── guessLanguage.js
└── bootstrap.min.js
├── css
├── angular-csp.css
├── main.css
├── bootstrap-theme.min.css
└── font-awesome.min.css
├── manifest.json
├── LICENSE
├── README.md
└── popup.html
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .DS_Store
3 |
--------------------------------------------------------------------------------
/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/images/icon.png
--------------------------------------------------------------------------------
/images/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/images/icon128.png
--------------------------------------------------------------------------------
/images/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/images/icon16.png
--------------------------------------------------------------------------------
/images/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/images/icon48.png
--------------------------------------------------------------------------------
/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/screenshots/V1.2/1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/screenshots/V1.2/1.PNG
--------------------------------------------------------------------------------
/screenshots/V1.2/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/screenshots/V1.2/2.png
--------------------------------------------------------------------------------
/screenshots/V1.2/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/screenshots/V1.2/3.png
--------------------------------------------------------------------------------
/screenshots/V1.2/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/screenshots/V1.2/4.png
--------------------------------------------------------------------------------
/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/screenshots/Chrome Settings Menu.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/screenshots/Chrome Settings Menu.PNG
--------------------------------------------------------------------------------
/screenshots/Duolingo Notes Version.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/screenshots/Duolingo Notes Version.PNG
--------------------------------------------------------------------------------
/screenshots/Set up shortcut key 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/screenshots/Set up shortcut key 1.png
--------------------------------------------------------------------------------
/screenshots/Set up shortcut key 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/screenshots/Set up shortcut key 2.png
--------------------------------------------------------------------------------
/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/screenshots/V1.0/Add to Duolingo Notes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/screenshots/V1.0/Add to Duolingo Notes.png
--------------------------------------------------------------------------------
/screenshots/V1.0/Duolingo Notes Popup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/screenshots/V1.0/Duolingo Notes Popup.png
--------------------------------------------------------------------------------
/screenshots/Force Chrome Update Extensions.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/screenshots/Force Chrome Update Extensions.PNG
--------------------------------------------------------------------------------
/screenshots/Right Duolingo Notes Action Button.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/screenshots/Right Duolingo Notes Action Button.PNG
--------------------------------------------------------------------------------
/screenshots/Duolingo Notes Version On Google Web Store.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeLin/DuolingoNotes/HEAD/screenshots/Duolingo Notes Version On Google Web Store.PNG
--------------------------------------------------------------------------------
/js/jqueryFunctions.js:
--------------------------------------------------------------------------------
1 | // Using Jquery inside the controller is considered as bad practice in Angular JS
2 | // Use a separate file to place Jquery stuff. Do things quickly but they should be done in Controller.
3 | $(function() {
4 | $('#exportToCsv').click(function(){
5 | $('#notesTable').table2CSV({header:['Question','Duolingo\'s answer','Your answer','Comments']});
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/css/angular-csp.css:
--------------------------------------------------------------------------------
1 | /* Include this file in your html if you are using the CSP mode. */
2 |
3 | @charset "UTF-8";
4 |
5 | [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
6 | .ng-cloak, .x-ng-cloak,
7 | .ng-hide {
8 | display: none !important;
9 | }
10 |
11 | ng\:form {
12 | display: block;
13 | }
14 |
15 | /* The styles below ensure that the CSS transition will ALWAYS
16 | * animate and close. A nasty bug occurs with CSS transitions where
17 | * when the active class isn't set, or if the active class doesn't
18 | * contain any styles to transition to, then, if ngAnimate is used,
19 | * it will appear as if the webpage is broken due to the forever hanging
20 | * animations. The border-spacing (!ie) and zoom (ie) CSS properties are
21 | * used below since they trigger a transition without making the browser
22 | * animate anything and they're both highly underused CSS properties */
23 | .ng-animate-start { border-spacing:1px 1px; -ms-zoom:1.0001; }
24 | .ng-animate-active { border-spacing:0px 0px; -ms-zoom:1; }
25 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 |
4 | "name": "Duolingo Notes",
5 | "description": "Help you learn Duolingo faster and better",
6 | "version": "2.0",
7 |
8 | "browser_action": {
9 | "default_icon": "images/icon.png",
10 | "default_popup": "popup.html"
11 | },
12 | "permissions": [
13 | "https://*.duolingo.com/",
14 | "http://*.duolingo.com/",
15 | "activeTab",
16 | "storage",
17 | "unlimitedStorage",
18 | "notifications",
19 | "clipboardWrite",
20 | "contextMenus"
21 | ],
22 | "background": {
23 | "scripts": ["js/jquery-2.1.0.min.js", "js/app.js"]
24 | },
25 | "commands": {
26 | "add-to-notes": {
27 | "suggested_key": {
28 | "default": "Alt+A"
29 | },
30 | "description": "Add to Duolingo Notes"
31 | }
32 | },
33 | "icons": {
34 | "16": "images/icon16.png",
35 | "48": "images/icon48.png",
36 | "128": "images/icon128.png"
37 | },
38 | "web_accessible_resources": [
39 | "images/icon.png"
40 | ]
41 | }
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Jake Lin
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.
--------------------------------------------------------------------------------
/js/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Jake Lin on 5/2/2014.
3 | */
4 |
5 | function addToNotes(info, tab) {
6 | chrome.tabs.executeScript(null, { file: "js/jquery-2.1.0.min.js" }, function() {
7 | chrome.tabs.executeScript(null, { file: "js/contextScript.addToNotes.js" }, function (result) {
8 | // console.log(result);
9 | });
10 | });
11 | }
12 |
13 | var showForPages = ["https://www.duolingo.com/skill/*", "http://www.duolingo.com/skill/*","https://www.duolingo.com/practice/*", "http://www.duolingo.com/practice/*"];
14 | var contexts = ["page","selection","link","editable","image","video","audio"];
15 |
16 | chrome.contextMenus.create({"title": "Add to Duolingo Notes",
17 | "documentUrlPatterns":showForPages,
18 | "contexts":contexts,
19 | "onclick": addToNotes});
20 |
21 | chrome.commands.onCommand.addListener(function(command) {
22 | console.log('Command:', command);
23 | if (command == "add-to-notes") {
24 | addToNotes();
25 | }
26 | });
27 |
28 | // Migrate all data from chrome.storage.sync to chrome.storage.local due to storage limit problem.
29 | // Can be removed in the future.
30 | console.log("Migration starts"); // TODO: will be removed
31 | chrome.storage.sync.get('notes', function (result){
32 | var notes = result['notes'];
33 | console.log("notes");
34 | console.log(notes);
35 | if (notes) {
36 | chrome.storage.local.set({'notes': notes}, function() {});
37 | chrome.storage.sync.set({'notes': null}, function() {});
38 | }
39 | });
40 |
--------------------------------------------------------------------------------
/css/main.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Jake Lin on 5/2/2014.
3 | */
4 |
5 | /* Base styles (regardless of theme) */
6 | .bs-callout {
7 | margin: 20px 0;
8 | padding: 15px 30px 15px 15px;
9 | border-left: 5px solid #eee;
10 | }
11 | .bs-callout h4 {
12 | margin-top: 0;
13 | }
14 | .bs-callout p:last-child {
15 | margin-bottom: 0;
16 | }
17 | .bs-callout code,
18 | .bs-callout .highlight {
19 | background-color: #fff;
20 | }
21 |
22 | /* Themes for different contexts */
23 | .bs-callout-danger {
24 | background-color: #fcf2f2;
25 | border-color: #dFb5b4;
26 | }
27 | .bs-callout-warning {
28 | background-color: #fefbed;
29 | border-color: #f1e7bc;
30 | }
31 | .bs-callout-info {
32 | background-color: #f0f7fd;
33 | border-color: #d0e3f0;
34 | }
35 |
36 | .bs-callout-danger h4 {
37 | color: #B94A48;
38 | }
39 |
40 | .bs-callout-warning h4 {
41 | color: #C09853;
42 | }
43 |
44 | .bs-callout-info h4 {
45 | color: #3A87AD;
46 | }
47 |
48 | body {
49 | min-width: 780px;
50 | overflow-x: hidden;
51 | }
52 |
53 | .btn-margin {
54 | margin-right: 5px;
55 | }
56 |
57 | #search {
58 | margin: 15px 0;
59 | }
60 |
61 | .round-btn {
62 | border-radius:100%;
63 | }
64 |
65 | .word_image {
66 | width: 60px;
67 | height: 60px;
68 | margin: 0 5px 5px;
69 | }
70 |
71 | .word_image:hover {
72 | cursor: pointer;
73 | transform:matrix(3, 0, 0, 3, 60, 0);
74 | -ms-transform:matrix(3, 0, 0, 3, 60, 0); /* IE 9 */
75 | -moz-transform:matrix(3, 0, 0, 3, 60, 0); /* Firefox */
76 | -webkit-transform:matrix(3, 0, 0, 3, 60, 0); /* Safari and Chrome */
77 | -o-transform:matrix(3, 0, 0, 3, 60, 0); /* Opera */
78 | }
79 |
80 | .action-buttons {
81 | margin: 20px 20px 0;
82 | }
83 |
84 | .action-buttons .btn {
85 | margin: 0 15px;
86 | }
87 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Duolingo Notes
2 |
3 | Duolingo Notes is a Google Chrome Extension can help the duolingo users save notes during learning.
4 |
5 | This Extension is free on [Google Web Store | Duolingo Notes](https://chrome.google.com/webstore/detail/duolingo-notes/fdhafjdcofficgjebiflfamofkoedieh).
6 |
7 | User Guide is availabe on [Duolingo | Duolingo Notes App - Help you learn Duolingo faster and better](https://www.duolingo.com/comment/2976444).
8 |
9 | ### Features
10 | * bookmark the question and answer during learning.
11 | * Review your bookmarked notes.
12 | * Copy the note.
13 | * Speak the note.
14 | * Add personal comments.
15 | * Search the note.
16 | * Delete the note.
17 | * Delete all notes.
18 | * Export notes to CSV.
19 | * Use shortcut key (Alt+A) to add note.
20 |
21 | ### Design Considerations
22 | * I use chrome.storage (chrome.storage.sync) instead of IndexedDB because I want to sync the notes across different Google Chrome browsers easily. Due to storage limit, I have changed to use chrome.storage.local to replace chrome.storage.sync.
23 |
24 | ### License
25 | The app is under MIT License. The duolingo trademark and the owl logo are owned by Duolingo. And the third party libraries are owned by original vendors.
26 |
27 | ### Release Notes
28 | * V2.0
29 | Add shortcut key (Alt+A) to add note. Thanks to [northernguy](https://www.duolingo.com/northernguy) for suggesting these features.
30 |
31 | * V1.9
32 | Add delete all notes button. Add export notes to CSV feature. Thanks to [northernguy](https://www.duolingo.com/northernguy) for suggesting these features.
33 |
34 | * V1.8
35 | Support image select question.
36 |
37 | * V1.7
38 | Improve User Experience, show bigger image when mouse hover over, add tooltip for buttons, resize the popup and display better for Windows users.
39 |
40 | * V1.6
41 | Use chrome.storage.local to replace chrome.storage.sync due to the storage limit of chrome.storage.sync (https://developer.chrome.com/extensions/storage#type-StorageArea). Thanks to [northernguy](https://www.duolingo.com/northernguy) for reporting that.
42 |
43 | * V1.5
44 | Added Support to Practice Lesson(practicing/strengthening a lesson). The user can add notes during Practice Lesson. Thanks to [jan williams](https://www.duolingo.com/willijanb) for reporting that.
45 |
46 | * V1.4
47 | Added tooltip for personal comments. Thanks to [Dessamator](https://www.duolingo.com/Dessamator) for suggesting this feature.
48 |
49 | * V1.3
50 | Added personal comments box.
51 |
52 | * V1.2
53 | Added speech button.
54 |
--------------------------------------------------------------------------------
/js/contextScript.addToNotes.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Jake Lin on 4/30/2014.
3 | */
4 |
5 | function guid() {
6 | function _p8(s) {
7 | var p = (Math.random().toString(16)+"000000000").substr(2,8);
8 | return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
9 | }
10 | return _p8() + _p8(true) + _p8(true) + _p8();
11 | }
12 |
13 | var type = undefined, question = undefined, userAnswer = undefined, duolingoAnswer = undefined, correct = undefined;
14 |
15 | console.log('add to notes');
16 |
17 | if($('#app.listen')[0] !== undefined){
18 | // Type what you hear
19 | type = 'listen';
20 | question = '♪';
21 | userAnswer = $('#graded-word-input').text();
22 | }
23 | else if ($('#app.translate')[0] !== undefined){
24 | // Text translation
25 | type = 'translate';
26 | question = $('#session-element-container .text-to-translate .token').text();
27 | userAnswer = $('#graded-text-input').text();
28 | }
29 | else if ($('#app.name')[0] !== undefined){
30 | // Type what you see (pictures)
31 | type = 'name';
32 | question = [];
33 | $('.list-tilted-images li').each(function( index ) {
34 | var bg = $(this).css('background-image');
35 | bg = bg.replace('url(','').replace(')','');
36 | question.push(bg);
37 | // console.log( bg );
38 | });
39 |
40 | userAnswer = $('#graded-word-input').text();
41 | }
42 | else if ($('#app.judge')[0] !== undefined){
43 | // Multiple choice with text
44 | type = 'judge';
45 | question = $('.judge-row .col-left').text();
46 | userAnswer = $('.judge-row .col-right .white-label.active').text();
47 | }
48 | else if ($('#app.select')[0] !== undefined){
49 | // Multiple choice with text and pictures
50 | type = 'select';
51 | question = $('.challenge-select .player').text();
52 | userAnswer = $('.challenge-select .select-images li.selected .select-images-frame').css('background-image');
53 | userAnswer = userAnswer.replace('url(','').replace(')','');
54 |
55 | duolingoAnswer = $('.challenge-select .select-images li.correct .select-images-frame').css('background-image');
56 | duolingoAnswer = duolingoAnswer.replace('url(','').replace(')','');
57 | }
58 | else if ($('#app.reverse_speak')[0] !== undefined){
59 | // Say something after translating it to the language you're learning
60 | type = 'reverse_speak';
61 | question = $('#original-text').text();
62 | duolingoAnswer = userAnswer = '♪';
63 | }
64 | else if ($('#app.speak')[0] !== undefined){
65 | // Read something in the language you're learning
66 | type = 'speak';
67 | question = $('#original-text').text();
68 | duolingoAnswer = userAnswer = '♪';
69 | }
70 | else if ($('#app.form')[0] !== undefined){
71 | // Fill in the blank using a drop down
72 | type = 'form';
73 | }
74 |
75 | correct = ($('#grade .icon-wrong-big')[0] === undefined);
76 | if(!duolingoAnswer) {
77 | duolingoAnswer = $('#grade .lighter').text();
78 | }
79 |
80 | if(correct === true && !duolingoAnswer){
81 | duolingoAnswer = userAnswer;
82 | }
83 |
84 | console.log("type: " + type + ", question: " + question + ", userAnswer:" + userAnswer + ", duolingoAnswer:" + duolingoAnswer + ", correct:" + correct);
85 | if (question && userAnswer && duolingoAnswer) {
86 | chrome.storage.local.get('notes', function (result){
87 | var notes = result['notes'] || {};
88 | var id = guid();
89 | notes[id] = {id: id, d:Date.now(), t: type, q:question, ua:userAnswer, da:duolingoAnswer, r: correct, c: ''};
90 | console.log(notes[id]);
91 | chrome.storage.local.set({'notes': notes}, function() {});
92 | });
93 | }
94 |
--------------------------------------------------------------------------------
/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Duolingo Notes
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
Duolingo Notes - Help you learn Duolingo faster and better
14 |
15 |
16 |
17 | | Question |
18 | Duolingo's answer |
19 | Your answer |
20 | Comments |
21 | |
22 |
23 |
24 | |
25 |
26 | {{ note.q }}
27 | |
28 |
29 |
30 | {{ note.da }}
31 | |
32 |
33 |
34 | {{ note.ua }}
35 | |
36 | |
37 | |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
If there is the first time to use the app. Please check out the
User Guide on Duolingo. Version: {{versionNumber()}}
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/js/popupCtrl.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Jake Lin on 5/2/2014.
3 | */
4 |
5 | 'use strict';
6 | var duolingoApp = angular.module('duolingoApp', []);
7 |
8 | duolingoApp.controller('PopupController', ['$scope', function($scope) {
9 | // Binding variables
10 | $scope.notes = [];
11 |
12 | /** Methods **/
13 | // Check whether display 'Speak' button or not
14 | $scope.showSpeakButton = function (text) {
15 | if (typeof popup.showSpeakButton === 'undefined') {
16 | if ('speechSynthesis' in window) {
17 | popup.showSpeakButton = true;
18 | } else {
19 | popup.showSpeakButton = false;
20 | }
21 | }
22 | // console.log(popup.showSpeakButton);
23 | // Check the text, if equals to '♪' then hide the button
24 | if(typeof text !== 'undefined' && text === '♪') {
25 | return false;
26 | }
27 |
28 | return popup.showSpeakButton;
29 | };
30 |
31 | // Check whether display the button.
32 | $scope.showButton = function (text) {
33 | // text is not null, undefined or empty or '♪'
34 | return (text && text !== '♪');
35 | };
36 |
37 | $scope.versionNumber = function () {
38 | var manifest = chrome.runtime.getManifest();
39 | return manifest.version;
40 | };
41 |
42 | $scope.clickCopy = function (text) {
43 | var copyDiv = document.createElement('div');
44 | copyDiv.contentEditable = true;
45 | document.body.appendChild(copyDiv);
46 | copyDiv.innerHTML = text;
47 | copyDiv.unselectable = "off";
48 | copyDiv.focus();
49 | document.execCommand('SelectAll');
50 | document.execCommand("Copy", false, null);
51 | document.body.removeChild(copyDiv);
52 | };
53 |
54 | $scope.clickSpeak = function (text) {
55 | // Create a new instance of SpeechSynthesisUtterance.
56 | var msg = new SpeechSynthesisUtterance();
57 |
58 | // Set the text.
59 | msg.text = text;
60 |
61 | guessLanguage.detect(text, function(language) {
62 | console.log('Detected language of provided text is [' + language + ']');
63 | // Find the voice and set the utterance instance's voice attribute.
64 | msg.voice = speechSynthesis.getVoices().filter(function(voice) { return voice.name == popup.LANGUAGE_MAP[language]; })[0]; msg.voice = speechSynthesis.getVoices().filter(function(voice) { return voice.name == popup.LANGUAGE_MAP[language]; })[0];
65 | // Queue this utterance.
66 | window.speechSynthesis.speak(msg);
67 | });
68 | };
69 |
70 | $scope.clickDelete = function (id) {
71 | chrome.storage.local.get('notes', function (result){
72 | var notes = result['notes'];
73 | delete notes[id];
74 | chrome.storage.local.set({'notes': notes}, function() { popup.loadNotes();});
75 | });
76 | };
77 |
78 | $scope.clickDeleteAll = function () {
79 | chrome.storage.local.get('notes', function (result){
80 | chrome.storage.local.set({'notes': null}, function() { popup.loadNotes();});
81 | });
82 | };
83 |
84 | $scope.changeComment = function (id, comment) {
85 | chrome.storage.local.get('notes', function (result){
86 | var notes = result['notes'];
87 | notes[id]['c'] = comment;
88 | chrome.storage.local.set({'notes': notes}, function() { });
89 | });
90 | };
91 |
92 | // Private stuff
93 | var popup = {};
94 | popup.LANGUAGE_MAP = {
95 | 'en' : 'Google US English',
96 | 'es' : 'Google Español',
97 | 'fr' : 'Google Français',
98 | 'ja' : 'Google 日本人',
99 | 'ko' : 'Google 한국의',
100 | 'zh' : 'Google 中国的',
101 | 'zh_TW' : 'Google 中国的',
102 | 'it' : 'Google Italiano',
103 | 'de' : 'Google Deutsch'
104 | };
105 |
106 | popup.loadNotes = function () {
107 | chrome.storage.local.get('notes', function (result){
108 |
109 | // Flaten the object to an array for bidding.
110 | var notes = [];
111 | for(var guid in result['notes']) {
112 | var note = result['notes'][guid];
113 |
114 | // set the diplay color for the user answer
115 | if(note.r === true) {
116 | note.textColor = 'blue';
117 | }
118 | else if (note.r === false) {
119 | note.textColor = 'red';
120 | }
121 | notes.push(note);
122 | }
123 |
124 | // Sort by created datetime descendingly.
125 | $scope.notes = _.sortBy(notes, function(note){
126 | return -(new Date(note.d));
127 | });
128 |
129 | $scope.$apply();
130 | });
131 | };
132 |
133 | popup.init = function () {
134 | popup.loadNotes();
135 | };
136 |
137 | popup.init();
138 | }]);
139 |
--------------------------------------------------------------------------------
/js/html2csv.js:
--------------------------------------------------------------------------------
1 | /* FileSaver.js
2 | * A saveAs() FileSaver implementation.
3 | * 2014-05-27
4 | *
5 | * By Eli Grey, http://eligrey.com
6 | * License: X11/MIT
7 | * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
8 | */
9 |
10 | /*global self */
11 | /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
12 |
13 | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
14 |
15 | var saveAs = saveAs
16 | // IE 10+ (native saveAs)
17 | || (typeof navigator !== "undefined" &&
18 | navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))
19 | // Everyone else
20 | || (function(view) {
21 | "use strict";
22 | // IE <10 is explicitly unsupported
23 | if (typeof navigator !== "undefined" &&
24 | /MSIE [1-9]\./.test(navigator.userAgent)) {
25 | return;
26 | }
27 | var
28 | doc = view.document
29 | // only get URL when necessary in case Blob.js hasn't overridden it yet
30 | , get_URL = function() {
31 | return view.URL || view.webkitURL || view;
32 | }
33 | , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
34 | , can_use_save_link = !view.externalHost && "download" in save_link
35 | , click = function(node) {
36 | var event = doc.createEvent("MouseEvents");
37 | event.initMouseEvent(
38 | "click", true, false, view, 0, 0, 0, 0, 0
39 | , false, false, false, false, 0, null
40 | );
41 | node.dispatchEvent(event);
42 | }
43 | , webkit_req_fs = view.webkitRequestFileSystem
44 | , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
45 | , throw_outside = function(ex) {
46 | (view.setImmediate || view.setTimeout)(function() {
47 | throw ex;
48 | }, 0);
49 | }
50 | , force_saveable_type = "application/octet-stream"
51 | , fs_min_size = 0
52 | , deletion_queue = []
53 | , process_deletion_queue = function() {
54 | var i = deletion_queue.length;
55 | while (i--) {
56 | var file = deletion_queue[i];
57 | if (typeof file === "string") { // file is an object URL
58 | get_URL().revokeObjectURL(file);
59 | } else { // file is a File
60 | file.remove();
61 | }
62 | }
63 | deletion_queue.length = 0; // clear queue
64 | }
65 | , dispatch = function(filesaver, event_types, event) {
66 | event_types = [].concat(event_types);
67 | var i = event_types.length;
68 | while (i--) {
69 | var listener = filesaver["on" + event_types[i]];
70 | if (typeof listener === "function") {
71 | try {
72 | listener.call(filesaver, event || filesaver);
73 | } catch (ex) {
74 | throw_outside(ex);
75 | }
76 | }
77 | }
78 | }
79 | , FileSaver = function(blob, name) {
80 | // First try a.download, then web filesystem, then object URLs
81 | var
82 | filesaver = this
83 | , type = blob.type
84 | , blob_changed = false
85 | , object_url
86 | , target_view
87 | , get_object_url = function() {
88 | var object_url = get_URL().createObjectURL(blob);
89 | deletion_queue.push(object_url);
90 | return object_url;
91 | }
92 | , dispatch_all = function() {
93 | dispatch(filesaver, "writestart progress write writeend".split(" "));
94 | }
95 | // on any filesys errors revert to saving with object URLs
96 | , fs_error = function() {
97 | // don't create more object URLs than needed
98 | if (blob_changed || !object_url) {
99 | object_url = get_object_url(blob);
100 | }
101 | if (target_view) {
102 | target_view.location.href = object_url;
103 | } else {
104 | window.open(object_url, "_blank");
105 | }
106 | filesaver.readyState = filesaver.DONE;
107 | dispatch_all();
108 | }
109 | , abortable = function(func) {
110 | return function() {
111 | if (filesaver.readyState !== filesaver.DONE) {
112 | return func.apply(this, arguments);
113 | }
114 | };
115 | }
116 | , create_if_not_found = {create: true, exclusive: false}
117 | , slice
118 | ;
119 | filesaver.readyState = filesaver.INIT;
120 | if (!name) {
121 | name = "download";
122 | }
123 | if (can_use_save_link) {
124 | object_url = get_object_url(blob);
125 | save_link.href = object_url;
126 | save_link.download = name;
127 | click(save_link);
128 | filesaver.readyState = filesaver.DONE;
129 | dispatch_all();
130 | return;
131 | }
132 | // Object and web filesystem URLs have a problem saving in Google Chrome when
133 | // viewed in a tab, so I force save with application/octet-stream
134 | // http://code.google.com/p/chromium/issues/detail?id=91158
135 | if (view.chrome && type && type !== force_saveable_type) {
136 | slice = blob.slice || blob.webkitSlice;
137 | blob = slice.call(blob, 0, blob.size, force_saveable_type);
138 | blob_changed = true;
139 | }
140 | // Since I can't be sure that the guessed media type will trigger a download
141 | // in WebKit, I append .download to the filename.
142 | // https://bugs.webkit.org/show_bug.cgi?id=65440
143 | if (webkit_req_fs && name !== "download") {
144 | name += ".download";
145 | }
146 | if (type === force_saveable_type || webkit_req_fs) {
147 | target_view = view;
148 | }
149 | if (!req_fs) {
150 | fs_error();
151 | return;
152 | }
153 | fs_min_size += blob.size;
154 | req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
155 | fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
156 | var save = function() {
157 | dir.getFile(name, create_if_not_found, abortable(function(file) {
158 | file.createWriter(abortable(function(writer) {
159 | writer.onwriteend = function(event) {
160 | target_view.location.href = file.toURL();
161 | deletion_queue.push(file);
162 | filesaver.readyState = filesaver.DONE;
163 | dispatch(filesaver, "writeend", event);
164 | };
165 | writer.onerror = function() {
166 | var error = writer.error;
167 | if (error.code !== error.ABORT_ERR) {
168 | fs_error();
169 | }
170 | };
171 | "writestart progress write abort".split(" ").forEach(function(event) {
172 | writer["on" + event] = filesaver["on" + event];
173 | });
174 | writer.write(blob);
175 | filesaver.abort = function() {
176 | writer.abort();
177 | filesaver.readyState = filesaver.DONE;
178 | };
179 | filesaver.readyState = filesaver.WRITING;
180 | }), fs_error);
181 | }), fs_error);
182 | };
183 | dir.getFile(name, {create: false}, abortable(function(file) {
184 | // delete file if it already exists
185 | file.remove();
186 | save();
187 | }), abortable(function(ex) {
188 | if (ex.code === ex.NOT_FOUND_ERR) {
189 | save();
190 | } else {
191 | fs_error();
192 | }
193 | }));
194 | }), fs_error);
195 | }), fs_error);
196 | }
197 | , FS_proto = FileSaver.prototype
198 | , saveAs = function(blob, name) {
199 | return new FileSaver(blob, name);
200 | }
201 | ;
202 | FS_proto.abort = function() {
203 | var filesaver = this;
204 | filesaver.readyState = filesaver.DONE;
205 | dispatch(filesaver, "abort");
206 | };
207 | FS_proto.readyState = FS_proto.INIT = 0;
208 | FS_proto.WRITING = 1;
209 | FS_proto.DONE = 2;
210 |
211 | FS_proto.error =
212 | FS_proto.onwritestart =
213 | FS_proto.onprogress =
214 | FS_proto.onwrite =
215 | FS_proto.onabort =
216 | FS_proto.onerror =
217 | FS_proto.onwriteend =
218 | null;
219 |
220 | view.addEventListener("unload", process_deletion_queue, false);
221 | saveAs.unload = function() {
222 | process_deletion_queue();
223 | view.removeEventListener("unload", process_deletion_queue, false);
224 | };
225 | return saveAs;
226 | }(
227 | typeof self !== "undefined" && self
228 | || typeof window !== "undefined" && window
229 | || this.content
230 | ));
231 | // `self` is undefined in Firefox for Android content script context
232 | // while `this` is nsIContentFrameMessageManager
233 | // with an attribute `content` that corresponds to the window
234 |
235 | if (typeof module !== "undefined" && module !== null) {
236 | module.exports = saveAs;
237 | } else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
238 | define([], function() {
239 | return saveAs;
240 | });
241 | }
242 |
243 | jQuery.fn.table2CSV = function(options) {
244 | var options = jQuery.extend({
245 | separator: ',',
246 | header: [],
247 | delivery: 'download' // popup, value, download
248 | },
249 | options);
250 |
251 | var csvData = [];
252 | var headerArr = [];
253 | var el = this;
254 |
255 | //header
256 | var numCols = options.header.length;
257 | var tmpRow = []; // construct header avalible array
258 |
259 | if (numCols > 0) {
260 | for (var i = 0; i < numCols; i++) {
261 | tmpRow[tmpRow.length] = formatData(options.header[i]);
262 | }
263 | } else {
264 | $(el).filter(':visible').find('th').each(function() {
265 | if ($(this).css('display') != 'none') tmpRow[tmpRow.length] = formatData($(this).html());
266 | });
267 | }
268 |
269 | row2CSV(tmpRow);
270 |
271 | // actual data
272 | $(el).find('tr').each(function() {
273 | var tmpRow = [];
274 | $(this).filter(':visible').find('td').each(function() {
275 | if ($(this).css('display') != 'none') tmpRow[tmpRow.length] = formatData($(this).html());
276 | });
277 | row2CSV(tmpRow);
278 | });
279 | if (options.delivery == 'popup') {
280 | var mydata = csvData.join('\n');
281 | return popup(mydata);
282 | }
283 | else if (options.delivery == 'download') {
284 | var mydata = csvData.join('\n');
285 | return download(mydata);
286 | }
287 | else {
288 | var mydata = csvData.join('\n');
289 | return mydata;
290 | }
291 |
292 | function row2CSV(tmpRow) {
293 | var tmp = tmpRow.join('') // to remove any blank rows
294 | if (tmpRow.length > 0 && tmp != '') {
295 | var mystr = tmpRow.join(options.separator);
296 | csvData.push(mystr);
297 | }
298 | }
299 | function formatData(input) {
300 | // replace " with “
301 | var regexp = new RegExp(/["]/g);
302 | var output = input.replace(regexp, "“");
303 | //HTML
304 | var regexp = new RegExp(/\<[^\<]+\>/g);
305 | var output = output.replace(regexp, "");
306 | output = output.trim();
307 | if (output == "") return '';
308 | return '"' + output + '"';
309 | }
310 | function popup(data) {
311 | var generator = window.open('', 'csv', 'height=400,width=600');
312 | generator.document.write('CSV');
313 | generator.document.write('');
314 | generator.document.write('');
317 | generator.document.write('');
318 | generator.document.close();
319 | return true;
320 | }
321 | function download(data) {
322 | var blob = new Blob([data], {
323 | type: "text/plain;charset=utf-8;",
324 | });
325 | saveAs(blob, "DuolingoNotes.csv");
326 | }
327 | };
328 |
--------------------------------------------------------------------------------
/css/bootstrap-theme.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v3.1.1 (http://getbootstrap.com)
3 | * Copyright 2011-2014 Twitter, Inc.
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 | */
6 |
7 | .btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn:active,.btn.active{background-image:none}.btn-default{background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;text-shadow:0 1px 0 #fff;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-color:#e8e8e8}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-color:#357ebd}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);border-color:#3278b3}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0)}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)}
--------------------------------------------------------------------------------
/js/underscore-min.js:
--------------------------------------------------------------------------------
1 | // Underscore.js 1.6.0
2 | // http://underscorejs.org
3 | // (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
4 | // Underscore may be freely distributed under the MIT license.
5 | (function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,g=e.filter,d=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,w=Object.keys,_=i.bind,j=function(n){return n instanceof j?n:this instanceof j?void(this._wrapped=n):new j(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=j),exports._=j):n._=j,j.VERSION="1.6.0";var A=j.each=j.forEach=function(n,t,e){if(null==n)return n;if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a=j.keys(n),u=0,i=a.length;i>u;u++)if(t.call(e,n[a[u]],a[u],n)===r)return;return n};j.map=j.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e.push(t.call(r,n,u,i))}),e)};var O="Reduce of empty array with no initial value";j.reduce=j.foldl=j.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=j.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},j.reduceRight=j.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=j.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=j.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},j.find=j.detect=function(n,t,r){var e;return k(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},j.filter=j.select=function(n,t,r){var e=[];return null==n?e:g&&n.filter===g?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&e.push(n)}),e)},j.reject=function(n,t,r){return j.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},j.every=j.all=function(n,t,e){t||(t=j.identity);var u=!0;return null==n?u:d&&n.every===d?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var k=j.some=j.any=function(n,t,e){t||(t=j.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};j.contains=j.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:k(n,function(n){return n===t})},j.invoke=function(n,t){var r=o.call(arguments,2),e=j.isFunction(t);return j.map(n,function(n){return(e?t:n[t]).apply(n,r)})},j.pluck=function(n,t){return j.map(n,j.property(t))},j.where=function(n,t){return j.filter(n,j.matches(t))},j.findWhere=function(n,t){return j.find(n,j.matches(t))},j.max=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.max.apply(Math,n);var e=-1/0,u=-1/0;return A(n,function(n,i,a){var o=t?t.call(r,n,i,a):n;o>u&&(e=n,u=o)}),e},j.min=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.min.apply(Math,n);var e=1/0,u=1/0;return A(n,function(n,i,a){var o=t?t.call(r,n,i,a):n;u>o&&(e=n,u=o)}),e},j.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=j.random(r++),e[r-1]=e[t],e[t]=n}),e},j.sample=function(n,t,r){return null==t||r?(n.length!==+n.length&&(n=j.values(n)),n[j.random(n.length-1)]):j.shuffle(n).slice(0,Math.max(0,t))};var E=function(n){return null==n?j.identity:j.isFunction(n)?n:j.property(n)};j.sortBy=function(n,t,r){return t=E(t),j.pluck(j.map(n,function(n,e,u){return{value:n,index:e,criteria:t.call(r,n,e,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var F=function(n){return function(t,r,e){var u={};return r=E(r),A(t,function(i,a){var o=r.call(e,i,a,t);n(u,o,i)}),u}};j.groupBy=F(function(n,t,r){j.has(n,t)?n[t].push(r):n[t]=[r]}),j.indexBy=F(function(n,t,r){n[t]=r}),j.countBy=F(function(n,t){j.has(n,t)?n[t]++:n[t]=1}),j.sortedIndex=function(n,t,r,e){r=E(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;r.call(e,n[o])t?[]:o.call(n,0,t)},j.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},j.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},j.rest=j.tail=j.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},j.compact=function(n){return j.filter(n,j.identity)};var M=function(n,t,r){return t&&j.every(n,j.isArray)?c.apply(r,n):(A(n,function(n){j.isArray(n)||j.isArguments(n)?t?a.apply(r,n):M(n,t,r):r.push(n)}),r)};j.flatten=function(n,t){return M(n,t,[])},j.without=function(n){return j.difference(n,o.call(arguments,1))},j.partition=function(n,t){var r=[],e=[];return A(n,function(n){(t(n)?r:e).push(n)}),[r,e]},j.uniq=j.unique=function(n,t,r,e){j.isFunction(t)&&(e=r,r=t,t=!1);var u=r?j.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:j.contains(a,r))||(a.push(r),i.push(n[e]))}),i},j.union=function(){return j.uniq(j.flatten(arguments,!0))},j.intersection=function(n){var t=o.call(arguments,1);return j.filter(j.uniq(n),function(n){return j.every(t,function(t){return j.contains(t,n)})})},j.difference=function(n){var t=c.apply(e,o.call(arguments,1));return j.filter(n,function(n){return!j.contains(t,n)})},j.zip=function(){for(var n=j.max(j.pluck(arguments,"length").concat(0)),t=new Array(n),r=0;n>r;r++)t[r]=j.pluck(arguments,""+r);return t},j.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},j.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=j.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},j.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},j.range=function(n,t,r){arguments.length<=1&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=new Array(e);e>u;)i[u++]=n,n+=r;return i};var R=function(){};j.bind=function(n,t){var r,e;if(_&&n.bind===_)return _.apply(n,o.call(arguments,1));if(!j.isFunction(n))throw new TypeError;return r=o.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(o.call(arguments)));R.prototype=n.prototype;var u=new R;R.prototype=null;var i=n.apply(u,r.concat(o.call(arguments)));return Object(i)===i?i:u}},j.partial=function(n){var t=o.call(arguments,1);return function(){for(var r=0,e=t.slice(),u=0,i=e.length;i>u;u++)e[u]===j&&(e[u]=arguments[r++]);for(;r=f?(clearTimeout(a),a=null,o=l,i=n.apply(e,u),e=u=null):a||r.trailing===!1||(a=setTimeout(c,f)),i}},j.debounce=function(n,t,r){var e,u,i,a,o,c=function(){var l=j.now()-a;t>l?e=setTimeout(c,t-l):(e=null,r||(o=n.apply(i,u),i=u=null))};return function(){i=this,u=arguments,a=j.now();var l=r&&!e;return e||(e=setTimeout(c,t)),l&&(o=n.apply(i,u),i=u=null),o}},j.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},j.wrap=function(n,t){return j.partial(t,n)},j.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},j.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},j.keys=function(n){if(!j.isObject(n))return[];if(w)return w(n);var t=[];for(var r in n)j.has(n,r)&&t.push(r);return t},j.values=function(n){for(var t=j.keys(n),r=t.length,e=new Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},j.pairs=function(n){for(var t=j.keys(n),r=t.length,e=new Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},j.invert=function(n){for(var t={},r=j.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},j.functions=j.methods=function(n){var t=[];for(var r in n)j.isFunction(n[r])&&t.push(r);return t.sort()},j.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},j.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},j.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)j.contains(r,u)||(t[u]=n[u]);return t},j.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]===void 0&&(n[r]=t[r])}),n},j.clone=function(n){return j.isObject(n)?j.isArray(n)?n.slice():j.extend({},n):n},j.tap=function(n,t){return t(n),n};var S=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof j&&(n=n._wrapped),t instanceof j&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==String(t);case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;var a=n.constructor,o=t.constructor;if(a!==o&&!(j.isFunction(a)&&a instanceof a&&j.isFunction(o)&&o instanceof o)&&"constructor"in n&&"constructor"in t)return!1;r.push(n),e.push(t);var c=0,f=!0;if("[object Array]"==u){if(c=n.length,f=c==t.length)for(;c--&&(f=S(n[c],t[c],r,e)););}else{for(var s in n)if(j.has(n,s)&&(c++,!(f=j.has(t,s)&&S(n[s],t[s],r,e))))break;if(f){for(s in t)if(j.has(t,s)&&!c--)break;f=!c}}return r.pop(),e.pop(),f};j.isEqual=function(n,t){return S(n,t,[],[])},j.isEmpty=function(n){if(null==n)return!0;if(j.isArray(n)||j.isString(n))return 0===n.length;for(var t in n)if(j.has(n,t))return!1;return!0},j.isElement=function(n){return!(!n||1!==n.nodeType)},j.isArray=x||function(n){return"[object Array]"==l.call(n)},j.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){j["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),j.isArguments(arguments)||(j.isArguments=function(n){return!(!n||!j.has(n,"callee"))}),"function"!=typeof/./&&(j.isFunction=function(n){return"function"==typeof n}),j.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},j.isNaN=function(n){return j.isNumber(n)&&n!=+n},j.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},j.isNull=function(n){return null===n},j.isUndefined=function(n){return n===void 0},j.has=function(n,t){return f.call(n,t)},j.noConflict=function(){return n._=t,this},j.identity=function(n){return n},j.constant=function(n){return function(){return n}},j.property=function(n){return function(t){return t[n]}},j.matches=function(n){return function(t){if(t===n)return!0;for(var r in n)if(n[r]!==t[r])return!1;return!0}},j.times=function(n,t,r){for(var e=Array(Math.max(0,n)),u=0;n>u;u++)e[u]=t.call(r,u);return e},j.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},j.now=Date.now||function(){return(new Date).getTime()};var T={escape:{"&":"&","<":"<",">":">",'"':""","'":"'"}};T.unescape=j.invert(T.escape);var I={escape:new RegExp("["+j.keys(T.escape).join("")+"]","g"),unescape:new RegExp("("+j.keys(T.unescape).join("|")+")","g")};j.each(["escape","unescape"],function(n){j[n]=function(t){return null==t?"":(""+t).replace(I[n],function(t){return T[n][t]})}}),j.result=function(n,t){if(null==n)return void 0;var r=n[t];return j.isFunction(r)?r.call(n):r},j.mixin=function(n){A(j.functions(n),function(t){var r=j[t]=n[t];j.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),z.call(this,r.apply(j,n))}})};var N=0;j.uniqueId=function(n){var t=++N+"";return n?n+t:t},j.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var q=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\t|\u2028|\u2029/g;j.template=function(n,t,r){var e;r=j.defaults({},r,j.templateSettings);var u=new RegExp([(r.escape||q).source,(r.interpolate||q).source,(r.evaluate||q).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(D,function(n){return"\\"+B[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=new Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,j);var c=function(n){return e.call(this,n,j)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},j.chain=function(n){return j(n).chain()};var z=function(n){return this._chain?j(n).chain():n};j.mixin(j),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];j.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],z.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];j.prototype[n]=function(){return z.call(this,t.apply(this._wrapped,arguments))}}),j.extend(j.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}}),"function"==typeof define&&define.amd&&define("underscore",[],function(){return j})}).call(this);
6 | //# sourceMappingURL=underscore-min.map
--------------------------------------------------------------------------------
/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"}
--------------------------------------------------------------------------------
/js/guessLanguage.js:
--------------------------------------------------------------------------------
1 | /* Guess the natural language of a text
2 | * Copyright (c) 2012, Rich Tibbett
3 | * http://github.com/richtr/guessLanguage.js/
4 | *
5 | * Original Python package:
6 | * Copyright (c) 2008, Kent S Johnson
7 | * http://code.google.com/p/guess-language/
8 | *
9 | * Original C++ version for KDE:
10 | * Copyright (c) 2006 Jacob R Rideout
11 | * http://websvn.kde.org/branches/work/sonnet-refactoring/common/nlp/guesslanguage.cpp?view=markup
12 | *
13 | * Original Language::Guess Perl module:
14 | * Copyright (c) 2004-2006 Maciej Ceglowski
15 | * http://web.archive.org/web/20090228163219/http://languid.cantbedone.org/
16 | *
17 | * Note: Language::Guess is GPL-licensed. KDE developers received permission
18 | * from the author to distribute their port under LGPL:
19 | * http://lists.kde.org/?l=kde-sonnet&m=116910092228811&w=2
20 | *
21 | * This program is free software: you can redistribute it and/or modify it
22 | * under the terms of the GNU Lesser General Public License as published
23 | * by the Free Software Foundation, either version 3 of the License,
24 | * or (at your option) any later version.
25 | *
26 | * This program is distributed in the hope that it will be useful,
27 | * but WITHOUT ANY WARRANTY; without even the implied warranty
28 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
29 | * See the GNU Lesser General Public License for more details.
30 | *
31 | * You should have received a copy of the GNU Lesser General Public License
32 | * along with this program. If not, see .
33 | */
34 |
35 | (function(global, undefined) {
36 |
37 | var guessLanguage = function() {
38 |
39 | var models = global._languageData || {};
40 |
41 | if (typeof module === "object" && module.exports === global) {
42 | models = require('./_languageData') || {};
43 | }
44 |
45 | var MAX_LENGTH = 4096;
46 | var MIN_LENGTH = 20;
47 | var MAX_GRAMS = 300;
48 |
49 | var NAME_MAP = {
50 | "ab": "Abkhazian",
51 | "af": "Afrikaans",
52 | "ar": "Arabic",
53 | "az": "Azeri",
54 | "be": "Belarusian",
55 | "bg": "Bulgarian",
56 | "bn": "Bengali",
57 | "bo": "Tibetan",
58 | "br": "Breton",
59 | "ca": "Catalan",
60 | "ceb": "Cebuano",
61 | "cs": "Czech",
62 | "cy": "Welsh",
63 | "da": "Danish",
64 | "de": "German",
65 | "el": "Greek",
66 | "en": "English",
67 | "eo": "Esperanto",
68 | "es": "Spanish",
69 | "et": "Estonian",
70 | "eu": "Basque",
71 | "fa": "Farsi",
72 | "fi": "Finnish",
73 | "fo": "Faroese",
74 | "fr": "French",
75 | "fy": "Frisian",
76 | "gd": "Scots Gaelic",
77 | "gl": "Galician",
78 | "gu": "Gujarati",
79 | "ha": "Hausa",
80 | "haw": "Hawaiian",
81 | "he": "Hebrew",
82 | "hi": "Hindi",
83 | "hr": "Croatian",
84 | "hu": "Hungarian",
85 | "hy": "Armenian",
86 | "id": "Indonesian",
87 | "is": "Icelandic",
88 | "it": "Italian",
89 | "ja": "Japanese",
90 | "ka": "Georgian",
91 | "kk": "Kazakh",
92 | "km": "Cambodian",
93 | "ko": "Korean",
94 | "ku": "Kurdish",
95 | "ky": "Kyrgyz",
96 | "la": "Latin",
97 | "lt": "Lithuanian",
98 | "lv": "Latvian",
99 | "mg": "Malagasy",
100 | "mk": "Macedonian",
101 | "ml": "Malayalam",
102 | "mn": "Mongolian",
103 | "mr": "Marathi",
104 | "ms": "Malay",
105 | "nd": "Ndebele",
106 | "ne": "Nepali",
107 | "nl": "Dutch",
108 | "nn": "Nynorsk",
109 | "no": "Norwegian",
110 | "nso": "Sepedi",
111 | "pa": "Punjabi",
112 | "pl": "Polish",
113 | "ps": "Pashto",
114 | "pt": "Portuguese",
115 | "pt_PT": "Portuguese (Portugal)",
116 | "pt_BR": "Portuguese (Brazil)",
117 | "ro": "Romanian",
118 | "ru": "Russian",
119 | "sa": "Sanskrit",
120 | "sh": "Serbo-Croatian",
121 | "sk": "Slovak",
122 | "sl": "Slovene",
123 | "so": "Somali",
124 | "sq": "Albanian",
125 | "sr": "Serbian",
126 | "sv": "Swedish",
127 | "sw": "Swahili",
128 | "ta": "Tamil",
129 | "te": "Telugu",
130 | "th": "Thai",
131 | "tl": "Tagalog",
132 | "tlh": "Klingon",
133 | "tn": "Setswana",
134 | "tr": "Turkish",
135 | "ts": "Tsonga",
136 | "tw": "Twi",
137 | "uk": "Ukrainian",
138 | "ur": "Urdu",
139 | "uz": "Uzbek",
140 | "ve": "Venda",
141 | "vi": "Vietnamese",
142 | "xh": "Xhosa",
143 | "zh": "Chinese",
144 | "zh_TW": "Traditional Chinese (Taiwan)",
145 | "zu": "Zulu",
146 | };
147 |
148 | var IANA_MAP = {
149 | "ab": 12026,
150 | "af": 40,
151 | "ar": 26020,
152 | "az": 26030,
153 | "be": 11890,
154 | "bg": 26050,
155 | "bn": 26040,
156 | "bo": 26601,
157 | "br": 1361,
158 | "ca": 3,
159 | "ceb": 26060,
160 | "cs": 26080,
161 | "cy": 26560,
162 | "da": 26090,
163 | "de": 26160,
164 | "el": 26165,
165 | "en": 26110,
166 | "eo": 11933,
167 | "es": 26460,
168 | "et": 26120,
169 | "eu": 1232,
170 | "fa": 26130,
171 | "fi": 26140,
172 | "fo": 11817,
173 | "fr": 26150,
174 | "fy": 1353,
175 | "gd": 65555,
176 | "gl": 1252,
177 | "gu": 26599,
178 | "ha": 26170,
179 | "haw": 26180,
180 | "he": 26592,
181 | "hi": 26190,
182 | "hr": 26070,
183 | "hu": 26200,
184 | "hy": 26597,
185 | "id": 26220,
186 | "is": 26210,
187 | "it": 26230,
188 | "ja": 26235,
189 | "ka": 26600,
190 | "kk": 26240,
191 | "km": 1222,
192 | "ko": 26255,
193 | "ku": 11815,
194 | "ky": 26260,
195 | "la": 26280,
196 | "lt": 26300,
197 | "lv": 26290,
198 | "mg": 1362,
199 | "mk": 26310,
200 | "ml": 26598,
201 | "mn": 26320,
202 | "mr": 1201,
203 | "ms": 1147,
204 | "ne": 26330,
205 | "nl": 26100,
206 | "nn": 172,
207 | "no": 26340,
208 | "pa": 65550,
209 | "pl": 26380,
210 | "ps": 26350,
211 | "pt": 26390,
212 | "ro": 26400,
213 | "ru": 26410,
214 | "sa": 1500,
215 | "sh": 1399,
216 | "sk": 26430,
217 | "sl": 26440,
218 | "so": 26450,
219 | "sq": 26010,
220 | "sr": 26420,
221 | "sv": 26480,
222 | "sw": 26470,
223 | "ta": 26595,
224 | "te": 26596,
225 | "th": 26594,
226 | "tl": 26490,
227 | "tlh": 26250,
228 | "tn": 65578,
229 | "tr": 26500,
230 | "tw": 1499,
231 | "uk": 26520,
232 | "ur": 26530,
233 | "uz": 26540,
234 | "vi": 26550,
235 | "zh": 26065,
236 | "zh_TW": 22,
237 | };
238 |
239 | var SINGLETONS = [
240 | ["Armenian", "hy"],
241 | ["Hebrew", "he"],
242 | ["Bengali", "bn"],
243 | ["Gurmukhi", "pa"],
244 | ["Greek", "el"],
245 | ["Gujarati", "gu"],
246 | ["Oriya", "or"],
247 | ["Tamil", "ta"],
248 | ["Telugu", "te"],
249 | ["Kannada", "kn"],
250 | ["Malayalam", "ml"],
251 | ["Sinhala", "si"],
252 | ["Thai", "th"],
253 | ["Lao", "lo"],
254 | ["Tibetan", "bo"],
255 | ["Burmese", "my"],
256 | ["Georgian", "ka"],
257 | ["Mongolian", "mn"],
258 | ["Khmer", "km"]
259 | ];
260 |
261 | var UNKNOWN = 'unknown';
262 |
263 | var BASIC_LATIN = ["en", "ceb", "ha", "so", "tlh", "id", "haw", "la", "sw", "eu", "nr", "nso", "zu", "xh", "ss", "st", "tn", "ts"];
264 | var EXTENDED_LATIN = ["cs", "af", "pl", "hr", "ro", "sk", "sl", "tr", "hu", "az", "et", "sq", "ca", "es", "fr", "de", "nl", "it", "da", "is", "no", "sv", "fi", "lv", "pt", "ve", "lt", "tl", "cy", "vi"];
265 | var ALL_LATIN = BASIC_LATIN.concat(EXTENDED_LATIN);
266 | var CYRILLIC = ["ru", "uk", "kk", "uz", "mn", "sr", "mk", "bg", "ky"];
267 | var ARABIC = ["ar", "fa", "ps", "ur"];
268 | var DEVANAGARI = ["hi", "ne"];
269 | var PT = ["pt_BR", "pt_PT"];
270 |
271 | // Unicode char greedy regex block range matchers
272 | var unicodeBlockTests = {
273 | "Basic Latin": /[\u0000-\u007F]/g,
274 | "Latin-1 Supplement": /[\u0080-\u00FF]/g,
275 | "Latin Extended-A": /[\u0100-\u017F]/g,
276 | "Latin Extended-B": /[\u0180-\u024F]/g,
277 | "IPA Extensions": /[\u0250-\u02AF]/g,
278 | "Spacing Modifier Letters": /[\u02B0-\u02FF]/g,
279 | "Combining Diacritical Marks": /[\u0300-\u036F]/g,
280 | "Greek and Coptic": /[\u0370-\u03FF]/g,
281 | "Cyrillic": /[\u0400-\u04FF]/g,
282 | "Cyrillic Supplement": /[\u0500-\u052F]/g,
283 | "Armenian": /[\u0530-\u058F]/g,
284 | "Hebrew": /[\u0590-\u05FF]/g,
285 | "Arabic": /[\u0600-\u06FF]/g,
286 | "Syriac": /[\u0700-\u074F]/g,
287 | "Arabic Supplement": /[\u0750-\u077F]/g,
288 | "Thaana": /[\u0780-\u07BF]/g,
289 | "NKo": /[\u07C0-\u07FF]/g,
290 | "Devanagari": /[\u0900-\u097F]/g,
291 | "Bengali": /[\u0980-\u09FF]/g,
292 | "Gurmukhi": /[\u0A00-\u0A7F]/g,
293 | "Gujarati": /[\u0A80-\u0AFF]/g,
294 | "Oriya": /[\u0B00-\u0B7F]/g,
295 | "Tamil": /[\u0B80-\u0BFF]/g,
296 | "Telugu": /[\u0C00-\u0C7F]/g,
297 | "Kannada": /[\u0C80-\u0CFF]/g,
298 | "Malayalam": /[\u0D00-\u0D7F]/g,
299 | "Sinhala": /[\u0D80-\u0DFF]/g,
300 | "Thai": /[\u0E00-\u0E7F]/g,
301 | "Lao": /[\u0E80-\u0EFF]/g,
302 | "Tibetan": /[\u0F00-\u0FFF]/g,
303 | "Myanmar": /[\u1000-\u109F]/g,
304 | "Georgian": /[\u10A0-\u10FF]/g,
305 | "Hangul Jamo": /[\u1100-\u11FF]/g,
306 | "Ethiopic": /[\u1200-\u137F]/g,
307 | "Ethiopic Supplement": /[\u1380-\u139F]/g,
308 | "Cherokee": /[\u13A0-\u13FF]/g,
309 | "Unified Canadian Aboriginal Syllabics": /[\u1400-\u167F]/g,
310 | "Ogham": /[\u1680-\u169F]/g,
311 | "Runic": /[\u16A0-\u16FF]/g,
312 | "Tagalog": /[\u1700-\u171F]/g,
313 | "Hanunoo": /[\u1720-\u173F]/g,
314 | "Buhid": /[\u1740-\u175F]/g,
315 | "Tagbanwa": /[\u1760-\u177F]/g,
316 | "Khmer": /[\u1780-\u17FF]/g,
317 | "Mongolian": /[\u1800-\u18AF]/g,
318 | "Limbu": /[\u1900-\u194F]/g,
319 | "Tai Le": /[\u1950-\u197F]/g,
320 | "New Tai Lue": /[\u1980-\u19DF]/g,
321 | "Khmer Symbols": /[\u19E0-\u19FF]/g,
322 | "Buginese": /[\u1A00-\u1A1F]/g,
323 | "Balinese": /[\u1B00-\u1B7F]/g,
324 | "Phonetic Extensions": /[\u1D00-\u1D7F]/g,
325 | "Phonetic Extensions Supplement": /[\u1D80-\u1DBF]/g,
326 | "Combining Diacritical Marks Supplement": /[\u1DC0-\u1DFF]/g,
327 | "Latin Extended Additional": /[\u1E00-\u1EFF]/g,
328 | "Greek Extended": /[\u1F00-\u1FFF]/g,
329 | "General Punctuation": /[\u2000-\u206F]/g,
330 | "Superscripts and Subscripts": /[\u2070-\u209F]/g,
331 | "Currency Symbols": /[\u20A0-\u20CF]/g,
332 | "Combining Diacritical Marks for Symbols": /[\u20D0-\u20FF]/g,
333 | "Letterlike Symbols": /[\u2100-\u214F]/g,
334 | "Number Forms": /[\u2150-\u218F]/g,
335 | "Arrows": /[\u2190-\u21FF]/g,
336 | "Mathematical Operators": /[\u2200-\u22FF]/g,
337 | "Miscellaneous Technical": /[\u2300-\u23FF]/g,
338 | "Control Pictures": /[\u2400-\u243F]/g,
339 | "Optical Character Recognition": /[\u2440-\u245F]/g,
340 | "Enclosed Alphanumerics": /[\u2460-\u24FF]/g,
341 | "Box Drawing": /[\u2500-\u257F]/g,
342 | "Block Elements": /[\u2580-\u259F]/g,
343 | "Geometric Shapes": /[\u25A0-\u25FF]/g,
344 | "Miscellaneous Symbols": /[\u2600-\u26FF]/g,
345 | "Dingbats": /[\u2700-\u27BF]/g,
346 | "Miscellaneous Mathematical Symbols-A": /[\u27C0-\u27EF]/g,
347 | "Supplemental Arrows-A": /[\u27F0-\u27FF]/g,
348 | "Braille Patterns": /[\u2800-\u28FF]/g,
349 | "Supplemental Arrows-B": /[\u2900-\u297F]/g,
350 | "Miscellaneous Mathematical Symbols-B": /[\u2980-\u29FF]/g,
351 | "Supplemental Mathematical Operators": /[\u2A00-\u2AFF]/g,
352 | "Miscellaneous Symbols and Arrows": /[\u2B00-\u2BFF]/g,
353 | "Glagolitic": /[\u2C00-\u2C5F]/g,
354 | "Latin Extended-C": /[\u2C60-\u2C7F]/g,
355 | "Coptic": /[\u2C80-\u2CFF]/g,
356 | "Georgian Supplement": /[\u2D00-\u2D2F]/g,
357 | "Tifinagh": /[\u2D30-\u2D7F]/g,
358 | "Ethiopic Extended": /[\u2D80-\u2DDF]/g,
359 | "Supplemental Punctuation": /[\u2E00-\u2E7F]/g,
360 | "CJK Radicals Supplement": /[\u2E80-\u2EFF]/g,
361 | "KangXi Radicals": /[\u2F00-\u2FDF]/g,
362 | "Ideographic Description Characters": /[\u2FF0-\u2FFF]/g,
363 | "CJK Symbols and Punctuation": /[\u3000-\u303F]/g,
364 | "Hiragana": /[\u3040-\u309F]/g,
365 | "Katakana": /[\u30A0-\u30FF]/g,
366 | "Bopomofo": /[\u3100-\u312F]/g,
367 | "Hangul Compatibility Jamo": /[\u3130-\u318F]/g,
368 | "Kanbun": /[\u3190-\u319F]/g,
369 | "Bopomofo Extended": /[\u31A0-\u31BF]/g,
370 | "CJK Strokes": /[\u31C0-\u31EF]/g,
371 | "Katakana Phonetic Extensions": /[\u31F0-\u31FF]/g,
372 | "Enclosed CJK Letters and Months": /[\u3200-\u32FF]/g,
373 | "CJK Compatibility": /[\u3300-\u33FF]/g,
374 | "CJK Unified Ideographs Extension A": /[\u3400-\u4DBF]/g,
375 | "Yijing Hexagram Symbols": /[\u4DC0-\u4DFF]/g,
376 | "CJK Unified Ideographs": /[\u4E00-\u9FFF]/g,
377 | "Yi Syllables": /[\uA000-\uA48F]/g,
378 | "Yi Radicals": /[\uA490-\uA4CF]/g,
379 | "Modifier Tone Letters": /[\uA700-\uA71F]/g,
380 | "Latin Extended-D": /[\uA720-\uA7FF]/g,
381 | "Syloti Nagri": /[\uA800-\uA82F]/g,
382 | "Phags-pa": /[\uA840-\uA87F]/g,
383 | "Hangul Syllables": /[\uAC00-\uD7AF]/g,
384 | "High Surrogates": /[\uD800-\uDB7F]/g,
385 | "High Private Use Surrogates": /[\uDB80-\uDBFF]/g,
386 | "Low Surrogates": /[\uDC00-\uDFFF]/g,
387 | "Private Use Area": /[\uE000-\uF8FF]/g,
388 | "CJK Compatibility Ideographs": /[\uF900-\uFAFF]/g,
389 | "Alphabetic Presentation Forms": /[\uFB00-\uFB4F]/g,
390 | "Arabic Presentation Forms-A": /[\uFB50-\uFDFF]/g,
391 | "Variation Selectors": /[\uFE00-\uFE0F]/g,
392 | "Vertical Forms": /[\uFE10-\uFE1F]/g,
393 | "Combining Half Marks": /[\uFE20-\uFE2F]/g,
394 | "CJK Compatibility Forms": /[\uFE30-\uFE4F]/g,
395 | "Small Form Variants": /[\uFE50-\uFE6F]/g,
396 | "Arabic Presentation Forms-B": /[\uFE70-\uFEFF]/g,
397 | "Halfwidth and Fullwidth Forms": /[\uFF00-\uFFEF]/g,
398 | "Specials": /[\uFFF0-\uFFFF]/g/*,
399 | "Linear B Syllabary": /[\u10000-\u1007F]/g,
400 | "Linear B Ideograms": /[\u10080-\u100FF]/g,
401 | "Aegean Numbers": /[\u10100-\u1013F]/g,
402 | "Ancient Greek Numbers": /[\u10140-\u1018F]/g,
403 | "Old Italic": /[\u10300-\u1032F]/g,
404 | "Gothic": /[\u10330-\u1034F]/g,
405 | "Ugaritic": /[\u10380-\u1039F]/g,
406 | "Old Persian": /[\u103A0-\u103DF]/g,
407 | "Deseret": /[\u10400-\u1044F]/g,
408 | "Shavian": /[\u10450-\u1047F]/g,
409 | "Osmanya": /[\u10480-\u104AF]/g,
410 | "Cypriot Syllabary": /[\u10800-\u1083F]/g,
411 | "Phoenician": /[\u10900-\u1091F]/g,
412 | "Kharoshthi": /[\u10A00-\u10A5F]/g,
413 | "Cuneiform": /[\u12000-\u123FF]/g,
414 | "Cuneiform Numbers and Punctuation": /[\u12400-\u1247F]/g,
415 | "Byzantine Musical Symbols": /[\u1D000-\u1D0FF]/g,
416 | "Musical Symbols": /[\u1D100-\u1D1FF]/g,
417 | "Ancient Greek Musical Notation": /[\u1D200-\u1D24F]/g,
418 | "Tai Xuan Jing Symbols": /[\u1D300-\u1D35F]/g,
419 | "Counting Rod Numerals": /[\u1D360-\u1D37F]/g,
420 | "Mathematical Alphanumeric Symbols": /[\u1D400-\u1D7FF]/g,
421 | "CJK Unified Ideographs Extension B": /[\u20000-\u2A6DF]/g,
422 | "CJK Compatibility Ideographs Supplement": /[\u2F800-\u2FA1F]/g,
423 | "Tags": /[\uE0000-\uE007F]/g,
424 | "Variation Selectors Supplement": /[\uE0100-\uE01EF]/g,
425 | "Supplementary Private Use Area-A": /[\uF0000-\uFFFFF]/g,
426 | "Supplementary Private Use Area-B": /[\u100000-\u10FFFF]/g*/
427 | };
428 |
429 | function findRuns(text) {
430 |
431 | var relevant_runs = {};
432 |
433 | for (var key in unicodeBlockTests) {
434 |
435 | // Count the number of characters in each character block.
436 | var charCount = text.match(unicodeBlockTests[key]);
437 |
438 | // return run types that used for 40% or more of the string
439 | // always return basic latin if found more than 15%
440 | // and extended additional latin if over 10% (for Vietnamese)
441 | var pct = (charCount ? charCount.length : 0) / text.length;
442 |
443 | relevant_runs[key] = pct;
444 |
445 | }
446 |
447 | return relevant_runs;
448 | }
449 |
450 | function identify(text, callback) {
451 |
452 | var scripts = findRuns(text);
453 |
454 | // Identify the language.
455 | if (scripts["Hangul Syllables"] + scripts["Hangul Jamo"] + scripts["Hangul Compatibility Jamo"] >= 0.4) {
456 | callback.apply(undefined, ["ko"]);
457 | return;
458 | }
459 |
460 | if (scripts["Greek and Coptic"] >= 0.4) {
461 | callback.apply(undefined, ["el"]);
462 | return;
463 | }
464 |
465 | if (scripts["Hiragana"] + scripts["Katakana"] + scripts["Katakana Phonetic Extensions"] >= 0.2) {
466 | callback.apply(undefined, ["ja"]);
467 | return;
468 | }
469 |
470 | if (scripts["CJK Unified Ideographs"] + scripts["Bopomofo"] + scripts["Bopomofo Extended"] + scripts["KangXi Radicals"] >= 0.4) {
471 | callback.apply(undefined, ["zh"]);
472 | return;
473 | }
474 |
475 | if (scripts["Cyrillic"] >= 0.4) {
476 | check(text, CYRILLIC, callback);
477 | return;
478 | }
479 |
480 | if (scripts["Arabic"] + scripts["Arabic Presentation Forms-A"] + scripts["Arabic Presentation Forms-B"] >= 0.4) {
481 | check(text, ARABIC, callback);
482 | return;
483 | }
484 |
485 | if (scripts["Devanagari"] >= 0.4) {
486 | check(text, DEVANAGARI, callback);
487 | return;
488 | }
489 |
490 | // Try languages with unique scripts
491 | for (var i = 0, l = SINGLETONS.length; i < l; i++) {
492 | if (scripts[SINGLETONS[i][0]] >= 0.4) {
493 | callback.apply(undefined, [SINGLETONS[i][1]]);
494 | return;
495 | }
496 | }
497 |
498 | // Extended Latin
499 | if (scripts["Latin-1 Supplement"] + scripts["Latin Extended-A"] + scripts["IPA Extensions"] >= 0.4) {
500 | check(text, EXTENDED_LATIN, function(latin_lang) {
501 | if (latin_lang == "pt") {
502 | check(text, PT, callback);
503 | } else {
504 | callback.apply(undefined, [latin_lang]);
505 | }
506 | });
507 | return;
508 | }
509 |
510 | if (scripts["Basic Latin"] >= 0.15) {
511 | check(text, ALL_LATIN, callback);
512 | return;
513 | }
514 |
515 | callback.apply(undefined, [UNKNOWN]);
516 | // return;
517 | }
518 |
519 | function check(sample, langs, callback) {
520 |
521 | if (sample.length < MIN_LENGTH) {
522 | callback.apply(undefined, [UNKNOWN]);
523 | return;
524 | }
525 |
526 | var scores = {};
527 | var model = createOrderedModel(sample)
528 | for (var i = 0, l = langs.length; i < l; i++) {
529 |
530 | var lkey = langs[i].toLowerCase();
531 |
532 | var known_model = models[lkey] || null;
533 |
534 | if (!known_model) {
535 | continue;
536 | }
537 |
538 | scores[lkey] = distance(model, known_model);
539 |
540 | }
541 |
542 | var scoresArr = [];
543 | for (var index in scores) {
544 | scoresArr.push([index, scores[index]]);
545 | }
546 |
547 | if (scoresArr.length == 0) {
548 | callback.apply(undefined, [UNKNOWN]);
549 | return;
550 | }
551 |
552 | // we want the lowest score, less distance = greater chance of match
553 | var sortedScores = scoresArr.sort(function(objA, objB) {
554 | return objA[1] - objB[1]; // sort low-to-high
555 | });
556 |
557 | // return the best match we've now calculated
558 | callback.apply(undefined, [sortedScores[0][0]]);
559 | //return;
560 | }
561 |
562 | function createOrderedModel(content) {
563 | // Create a list of trigrams in content sorted by frequency.
564 | var trigrams = {},
565 | sortedTrigrams = [];
566 | var content = content.toLowerCase();
567 |
568 | var contentArr = content.split("");
569 | for (var i = 0, l = contentArr.length - 2; i < l; i++) {
570 | var trigramKey = contentArr[i] + contentArr[i + 1] + contentArr[i + 2] + "";
571 | if (!trigrams[trigramKey]) {
572 | trigrams[trigramKey] = 1;
573 | } else {
574 | trigrams[trigramKey] += 1;
575 | }
576 | }
577 |
578 | // convert object to array
579 | for (var i in trigrams) {
580 | sortedTrigrams[sortedTrigrams.length] = [i, trigrams[i]];
581 | }
582 |
583 | // sort array results
584 | return sortedTrigrams.sort(function(objA, objB) {
585 | return objB[1] - objA[1]; // sort high-to-low
586 | });
587 | }
588 |
589 | function distance(model, known_model) {
590 | // Calculate the distance to the known model.
591 | var dist = 0;
592 |
593 | for (var i = 0, l = model.length; i < l; i++) {
594 |
595 | if (known_model[model[i][0]]) {
596 |
597 | dist += Math.abs(model[i][1] - known_model[model[i][0]]);
598 |
599 | } else {
600 |
601 | dist += MAX_GRAMS;
602 |
603 | }
604 |
605 | }
606 |
607 | return dist;
608 | }
609 |
610 | return {
611 | detect: function(text, callback) {
612 | // Return the ISO 639-2 language identifier, i.e. 'en'.
613 |
614 | if (!text) {
615 | callback.apply(undefined, [UNKNOWN]);
616 | return;
617 | }
618 |
619 | text = text.substr(0, MAX_LENGTH).replace(/[\u0021-\u0040]/g, '');
620 |
621 | identify(text, callback);
622 |
623 | },
624 | info: function(text, callback) {
625 | // Return language info tuple (id, code, name), i.e. ('en', 26110, 'English').
626 |
627 | this.detect(text, function(language) {
628 |
629 | if (language === UNKNOWN) {
630 | callback.apply(undefined, [[ UNKNOWN, UNKNOWN, UNKNOWN ]]);
631 | return;
632 | }
633 |
634 | callback.apply(undefined, [
635 |
636 | [ language, IANA_MAP[language], NAME_MAP[language] ]
637 |
638 | ]);;
639 |
640 | });
641 |
642 | },
643 | code: function(text, callback) {
644 | // Return the language IANA code, i.e. 26110.
645 |
646 | this.detect(text, function(language) {
647 |
648 | if (language === UNKNOWN) {
649 | callback.apply(undefined, [ -1 ]);;
650 | return;
651 | }
652 |
653 | callback.apply(undefined, [
654 |
655 | IANA_MAP[language]
656 |
657 | ]);
658 |
659 | });
660 |
661 | },
662 | name: function(text, callback) {
663 | // Return the full language name, i.e. 'English'.
664 |
665 | this.detect(text, function(language) {
666 |
667 | if (language === UNKNOWN) {
668 | callback.apply(undefined, [ UNKNOWN ]);;
669 | return;
670 | }
671 |
672 | callback.apply(undefined, [
673 |
674 | NAME_MAP[language]
675 |
676 | ]);
677 |
678 | });
679 |
680 | }
681 | };
682 |
683 | };
684 |
685 | global.guessLanguage = (global.module || {}).exports = new guessLanguage();
686 |
687 | })(this);
688 |
--------------------------------------------------------------------------------
/js/bootstrap.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v3.1.1 (http://getbootstrap.com)
3 | * Copyright 2011-2014 Twitter, Inc.
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 | */
6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(jQuery),+function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.isLoading=!1};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",f.resetText||d.data("resetText",d[e]()),d[e](f[b]||this.options[b]),setTimeout(a.proxy(function(){"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},b.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}a&&this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}if(e.hasClass("active"))return this.sliding=!1;var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});return this.$element.trigger(j),j.isDefaultPrevented()?void 0:(this.sliding=!0,f&&this.pause(),this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid.bs.carousel",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")?(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid.bs.carousel")},0)}).emulateTransitionEnd(1e3*d.css("transition-duration").slice(0,-1))):(d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid.bs.carousel")),f&&this.cycle(),this)};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data()),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("collapse in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?void this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);!e&&f.toggle&&"show"==c&&(c=!c),e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(jQuery),+function(a){"use strict";function b(b){a(d).remove(),a(e).each(function(){var d=c(a(this)),e={relatedTarget:this};d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown",e)),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown",e))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('').insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;f.toggleClass("open").trigger("shown.bs.dropdown",h),e.focus()}return!1}},f.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var f=c(d),g=f.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&f.find(e).focus(),d.click();var h=" li:not(.divider):visible a",i=f.find("[role=menu]"+h+", [role=listbox]"+h);if(i.length){var j=i.index(i.filter(":focus"));38==b.keyCode&&j>0&&j--,40==b.keyCode&&j').appendTo(document.body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),d&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;d?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()):b&&b()};var c=a.fn.modal;a.fn.modal=function(c,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},b.DEFAULTS,e.data(),"object"==typeof c&&c);f||e.data("bs.modal",f=new b(this,g)),"string"==typeof c?f[c](d):g.show&&f.show(d)})},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());c.is("a")&&b.preventDefault(),e.modal(f,this).one("hide",function(){c.is(":visible")&&c.focus()})}),a(document).on("show.bs.modal",".modal",function(){a(document.body).addClass("modal-open")}).on("hidden.bs.modal",".modal",function(){a(document.body).removeClass("modal-open")})}(jQuery),+function(a){"use strict";var b=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};b.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},b.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},b.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},b.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show()},b.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},b.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){if(this.$element.trigger(b),b.isDefaultPrevented())return;var c=this,d=this.tip();this.setContent(),this.options.animation&&d.addClass("fade");var e="function"==typeof this.options.placement?this.options.placement.call(this,d[0],this.$element[0]):this.options.placement,f=/\s?auto?\s?/i,g=f.test(e);g&&(e=e.replace(f,"")||"top"),d.detach().css({top:0,left:0,display:"block"}).addClass(e),this.options.container?d.appendTo(this.options.container):d.insertAfter(this.$element);var h=this.getPosition(),i=d[0].offsetWidth,j=d[0].offsetHeight;if(g){var k=this.$element.parent(),l=e,m=document.documentElement.scrollTop||document.body.scrollTop,n="body"==this.options.container?window.innerWidth:k.outerWidth(),o="body"==this.options.container?window.innerHeight:k.outerHeight(),p="body"==this.options.container?0:k.offset().left;e="bottom"==e&&h.top+h.height+j-m>o?"top":"top"==e&&h.top-m-j<0?"bottom":"right"==e&&h.right+i>n?"left":"left"==e&&h.left-i'}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;(e||"destroy"!=c)&&(e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]())})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(a(c).is("body")?window:c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.offsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);{var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})}},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);if(g&&b<=e[0])return g!=(a=f[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parentsUntil(this.options.target,".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=this.pinnedOffset=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(b.RESET).addClass("affix");var a=this.$window.scrollTop(),c=this.$element.offset();return this.pinnedOffset=c.top-a},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"top"==this.affixed&&(e.top+=d),"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top(this.$element)),"function"==typeof h&&(h=f.bottom(this.$element));var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;if(this.affixed!==i){this.unpin&&this.$element.css("top","");var j="affix"+(i?"-"+i:""),k=a.Event(j+".bs.affix");this.$element.trigger(k),k.isDefaultPrevented()||(this.affixed=i,this.unpin="bottom"==i?this.getPinnedOffset():null,this.$element.removeClass(b.RESET).addClass(j).trigger(a.Event(j.replace("affix","affixed"))),"bottom"==i&&this.$element.offset({top:c-h-this.$element.height()}))}}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(jQuery);
--------------------------------------------------------------------------------
/fonts/glyphicons-halflings-regular.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------