├── icon.png
├── icon-dev.png
├── logo128.png
├── logo48.png
├── popup.html
├── github.css
├── options.html
├── options.js
├── LICENSE
├── manifest.json
├── .circleci
└── config.yml
├── README.md
├── circleci-icon.svg
├── background.js
├── logo.svg
├── popup.js
├── github.js
└── vendor
├── algoliasearch-4.1.0.min.js
└── jquery-3.5.1.min.js
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FelicianoTech/pointless/HEAD/icon.png
--------------------------------------------------------------------------------
/icon-dev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FelicianoTech/pointless/HEAD/icon-dev.png
--------------------------------------------------------------------------------
/logo128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FelicianoTech/pointless/HEAD/logo128.png
--------------------------------------------------------------------------------
/logo48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FelicianoTech/pointless/HEAD/logo48.png
--------------------------------------------------------------------------------
/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Getting Started Extension's Popup
5 |
19 |
20 |
21 | More features coming soon. View the roadmap on our GitHub Page.
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/github.css:
--------------------------------------------------------------------------------
1 | a.cci{
2 | margin-left: 0;
3 | }
4 | a.cci.status-dot{
5 | margin: 0 8px 0 0;
6 | }
7 | a.cci span.default-build-status{
8 | display: inline-block;
9 | border-radius: 50%;
10 | background-color: #DEDEDE;
11 | width: 12px;
12 | height: 12px;
13 | transition: background-color 2s;
14 | }
15 | a.cci span.default-build-status.passed{
16 | background-color: green;
17 | }
18 |
19 | a.cci span.default-build-status.failed{
20 | background-color: red;
21 | }
22 |
23 | a.cci span.default-build-status.error{
24 | background-color: black;
25 | }
26 |
27 | a.cci span.default-build-status.running{
28 | background-color: cyan;
29 | }
30 |
31 | img.circleci-icon{
32 | width: 14px;
33 | height: 14px;
34 | vertical-align: text-top;
35 | }
36 |
--------------------------------------------------------------------------------
/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Pointless Settings
5 |
26 |
27 |
28 |
29 | required
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/options.js:
--------------------------------------------------------------------------------
1 | // Saves options to chrome.storage.sync.
2 | function save_options() {
3 | var token = document.getElementById('token').value;
4 | chrome.storage.sync.set({
5 | apiToken: token
6 | }, function() {
7 | // Update status to let user know options were saved.
8 | var status = document.getElementById('status');
9 | status.textContent = 'Options saved.';
10 | setTimeout(function() {
11 | status.textContent = '';
12 | }, 750);
13 | });
14 |
15 | var bgJS = chrome.extension.getBackgroundPage();
16 | bgJS.init();
17 | }
18 |
19 | // Restores select box and checkbox state using the preferences
20 | // stored in chrome.storage.
21 | function restore_options() {
22 | chrome.storage.sync.get({
23 | apiToken: ""
24 | }, function(items) {
25 | document.getElementById('token').value = items.apiToken;
26 | });
27 | }
28 | document.addEventListener('DOMContentLoaded', restore_options);
29 | document.getElementById('save').addEventListener('click',
30 | save_options);
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Ricardo N Feliciano
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 | "name": "Pointless - a CircleCI Chrome Extension",
4 | "short_name": "Pointless",
5 | "version": "9.9.9.9",
6 | "description": "Pointless is a CircleCI extension that enhances browsing experience on websites such as GitHub.",
7 | "author": "Ricardo N Feliciano - https://www.Feliciano.Tech",
8 | "minimum_chrome_version": "75",
9 |
10 | "icons":{
11 | "48": "logo48.png",
12 | "128": "logo128.png"
13 | },
14 |
15 | "background": {
16 | "scripts": [
17 | "vendor/algoliasearch-4.1.0.min.js",
18 | "background.js"
19 | ]
20 | },
21 |
22 | "omnibox": { "keyword": "ci" },
23 |
24 | "options_ui":{
25 | "page": "options.html",
26 | "chrome_style": true
27 | },
28 |
29 | "browser_action":{
30 | "default_icon": "icon-dev.png",
31 | "default_title": "Pointless - a CircleCI Chrome Extension",
32 | "default_popup": "popup.html"
33 | },
34 |
35 | "content_scripts":[
36 | {
37 | "matches": ["https://github.com/*/*"],
38 | "css": ["github.css"],
39 | "js": ["vendor/jquery-3.5.1.min.js", "github.js"]
40 | }
41 | ],
42 |
43 | "homepage_url": "https://github.com/felicianotech/pointless",
44 |
45 | "permissions": [
46 | "activeTab",
47 | "https://ajax.googleapis.com/",
48 | "https://circleci.com/",
49 | "storage"
50 | ],
51 |
52 | "web_accessible_resources": [
53 | "circleci-icon.svg"
54 | ]
55 | }
56 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 | workflows:
3 | main:
4 | jobs:
5 | - build:
6 | filters:
7 | tags:
8 | only: /^\d{4}\.\d+$/
9 | - publish:
10 | requires:
11 | - build
12 | filters:
13 | branches:
14 | ignore: /.*/
15 | tags:
16 | only: /^\d{4}\.\d+$/
17 | jobs:
18 | build:
19 | docker:
20 | - image: cibuilds/chrome-extension:latest
21 | steps:
22 | - checkout
23 | - run:
24 | name: "Prepare Extension For Production"
25 | command: |
26 | if [[ $CIRCLE_TAG != "" ]];then
27 | echo "Applying real version."
28 | jq '.version = env.CIRCLE_TAG' manifest.json | sponge manifest.json
29 | fi
30 | jq '.browser_action.default_icon = "icon.png"' manifest.json | sponge manifest.json
31 | - run:
32 | name: "Filler - Proper CI/CD needs to be implemented."
33 | command: echo "The start of our build process."
34 | - run: apk add --no-cache zip
35 | - run:
36 | name: "Package Extension"
37 | command: zip -r pointless.zip . -x *.git*
38 | - persist_to_workspace:
39 | root: /root/project
40 | paths:
41 | - pointless.zip
42 | publish:
43 | docker:
44 | - image: cibuilds/chrome-extension:latest
45 | environment:
46 | - APP_ID: edmkpfdmophaaeedepooedlhioimljai
47 | steps:
48 | - attach_workspace:
49 | at: /root/workspace
50 | - store_artifacts:
51 | path: "/root/workspace/pointless.zip"
52 | - run:
53 | name: "Publish to the Google Chrome Store"
54 | command: publish /root/workspace/pointless.zip
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pointless - a CircleCI Chrome Extension [](https://circleci.com/gh/felicianotech/pointless) [](https://raw.githubusercontent.com/felicianotech/pointless/master/LICENSE)
2 |
3 |
4 |
5 | Pointless is a CircleCI Chrome Extension that enhances your browsing experience while developing. For example, while viewing a project on GitHub, you can see its build status and follow/unfollow that project on CircleCI right from the GitHub page.
6 |
7 | ## Installing
8 |
9 | Pointless can be installed via the [Chrome Store](https://chrome.google.com/webstore/detail/pointless-a-circleci-chro/edmkpfdmophaaeedepooedlhioimljai).
10 |
11 | ## Configuring
12 |
13 | This extension requires a CircleCI [Personal API Token](https://circleci.com/account/api). Once you create a token on CircleCI's website, you can add it to Pointless by right-clicking the CircleCI icon at the top-right corner of Google Chrome and clicking "Options".
14 |
15 | ## Features
16 |
17 | - **build status** (GitHub) - a colored icon will appear to the right of the project name, showing the CircleCI build status of the default branch.
18 |
19 | - **follow/unfollow projects** (GitHub) - on a repo page, a CircleCI "Follow"/"Unfollow" button will appear next to the "Watch", "Star", and "Fork" GitHub buttons.
20 |
21 | - **docs search** (Omnibox/address bar) - search CircleCI Docs (all of docs or a single section) right from Chrome's Omnibox. Instructions below.
22 |
23 | ## How-To
24 |
25 | ### Searching
26 |
27 | Pointless supports quick, special searches. Currently, only CircleCI Docs can be searched but more search types are on the roadmap.
28 |
29 | ### Search CircleCI Docs
30 |
31 | In the Omnibox (address bar) type `ci` and press tab to activate Pointless' Search. Then, type `d`, a space, and then one or more search terms to search all of CircleCI Docs. You can search 1.0 Docs specifically by using `d1` instead of `d`, for 2.0, `d2`, for API Docs, `da`, and for CCIE Docs, `de`.
32 |
33 | Note that the search results will appear as a suggested page underneath the Omnibox. Hitting `Enter` will bring you to the CircleCi Docs index.
34 |
35 | ### Examples
36 |
37 | Search all of CircleCI Docs for Docker by typing: `ci d docker`
38 |
39 | Search for Yarn in CircleCI 2.0 Docs: `ci d2 yarn`
40 |
--------------------------------------------------------------------------------
/circleci-icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/background.js:
--------------------------------------------------------------------------------
1 | function init(){
2 |
3 | chrome.storage.sync.get({
4 | apiToken: ""
5 | }, function(items){
6 | apiToken = items.apiToken;
7 |
8 | if( apiToken.length == 0 ){
9 | chrome.browserAction.setBadgeText( {text:"!"} );
10 | chrome.browserAction.setBadgeBackgroundColor( {color:[179,58,58,255]} );
11 | }else{
12 | chrome.browserAction.setBadgeText( {text:""} );
13 | }
14 | });
15 |
16 | }
17 |
18 | function navigate( url ){
19 |
20 | chrome.tabs.query( {active: true, currentWindow: true }, function( tabs ){
21 | chrome.tabs.update( tabs[0].id, { url: url } );
22 | });
23 | }
24 |
25 | // Handle search logic specific to CircleCI Docs
26 | function searchDocs( searchType, text, suggest){
27 |
28 | var suggestions = [];
29 |
30 | chrome.omnibox.setDefaultSuggestion({ description: "CircleCI Docs results:" });
31 |
32 | docsIndex.search( text, {
33 | hitsPerPage: 7,
34 | attributesToRetrieve: [ 'title', 'url' ],
35 | filters: "collection:cci2",
36 | }).then(({ hits }) => {
37 | hits.forEach(function( hit ){
38 | suggestions.push({ content: "https://circleci.com/docs" + hit.url, description: "" + hit.title + "" });
39 | });
40 |
41 | suggest( suggestions );
42 | });
43 | }
44 |
45 | // Handle search logic specific to CircleCI Orbs
46 | function searchOrbs( searchType, text, suggest){
47 |
48 | var suggestions = [];
49 |
50 | chrome.omnibox.setDefaultSuggestion({ description: "CircleCI Orb Registry results:" });
51 |
52 | orbIndex.search( text, {
53 | hitsPerPage: 7,
54 | attributesToRetrieve: [ 'objectID', 'url' ],
55 | }).then(({ hits }) => {
56 |
57 | hits.forEach(function( hit ){
58 | suggestions.push( { content: hit.url, description: "" + hit.objectID + "" } );
59 | });
60 |
61 | suggest( suggestions );
62 | });
63 | }
64 |
65 |
66 |
67 | /*-----------------------------------------------------------------------------
68 | * Main
69 | *---------------------------------------------------------------------------*/
70 |
71 | var apiToken = "";
72 |
73 | init();
74 |
75 | // Setup Algolia v4 JavaScript client
76 | //import algoliasearch from 'algoliasearch/lite';
77 | const client = algoliasearch( "U0RXNGRK45", "7fb53cd578f887582b8e3085221a4f65" );
78 | const docsIndex = client.initIndex( "documentation" );
79 | const orbIndex = client.initIndex( "orbs-prod" );
80 |
81 | // Omnibox Search - currently searches CircleCI Docs and Orbs
82 | chrome.omnibox.onInputChanged.addListener( function( text, suggest ){
83 |
84 | var searchType = text.split(" ")[0];
85 | text = text.substring( searchType.length );
86 |
87 | switch( searchType ){
88 | case "d":
89 | // the old docs options below are kept for backwards compatibility
90 | // remove sometime after June 2020
91 | case "d1":
92 | case "d2":
93 | case "de":
94 | case "da":
95 | searchDocs( searchType, text, suggest );
96 | break;
97 | case "o":
98 | searchOrbs( searchType, text, suggest );
99 | break;
100 | default:
101 | chrome.omnibox.setDefaultSuggestion( { description: "Search type not recognized." } );
102 | }
103 | });
104 |
105 |
106 | // Omnibox Search - visit the URL of the slected suggestion
107 | chrome.omnibox.onInputEntered.addListener( function( text, disposition ){
108 | navigate( text );
109 | });
110 |
111 | chrome.runtime.onConnect.addListener(function(port){
112 | console.assert(port.name == "github");
113 | port.onMessage.addListener(function(msg){
114 |
115 | if(msg.request == "api-token"){
116 | port.postMessage({request: "api-token", response: apiToken});
117 | }
118 | });
119 | });
120 |
--------------------------------------------------------------------------------
/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
98 |
--------------------------------------------------------------------------------
/popup.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | /**
6 | * Get the current URL.
7 | *
8 | * @param {function(string)} callback - called when the URL of the current tab
9 | * is found.
10 | */
11 | function getCurrentTabUrl(callback) {
12 | // Query filter to be passed to chrome.tabs.query - see
13 | // https://developer.chrome.com/extensions/tabs#method-query
14 | var queryInfo = {
15 | active: true,
16 | currentWindow: true
17 | };
18 |
19 | chrome.tabs.query(queryInfo, function(tabs) {
20 | // chrome.tabs.query invokes the callback with a list of tabs that match the
21 | // query. When the popup is opened, there is certainly a window and at least
22 | // one tab, so we can safely assume that |tabs| is a non-empty array.
23 | // A window can only have one active tab at a time, so the array consists of
24 | // exactly one tab.
25 | var tab = tabs[0];
26 |
27 | // A tab is a plain object that provides information about the tab.
28 | // See https://developer.chrome.com/extensions/tabs#type-Tab
29 | var url = tab.url;
30 |
31 | // tab.url is only available if the "activeTab" permission is declared.
32 | // If you want to see the URL of other tabs (e.g. after removing active:true
33 | // from |queryInfo|), then the "tabs" permission is required to see their
34 | // "url" properties.
35 | console.assert(typeof url == 'string', 'tab.url should be a string');
36 |
37 | callback(url);
38 | });
39 |
40 | // Most methods of the Chrome extension APIs are asynchronous. This means that
41 | // you CANNOT do something like this:
42 | //
43 | // var url;
44 | // chrome.tabs.query(queryInfo, function(tabs) {
45 | // url = tabs[0].url;
46 | // });
47 | // alert(url); // Shows "undefined", because chrome.tabs.query is async.
48 | }
49 |
50 | /**
51 | * @param {string} searchTerm - Search term for Google Image search.
52 | * @param {function(string,number,number)} callback - Called when an image has
53 | * been found. The callback gets the URL, width and height of the image.
54 | * @param {function(string)} errorCallback - Called when the image is not found.
55 | * The callback gets a string that describes the failure reason.
56 | */
57 | function getImageUrl(searchTerm, callback, errorCallback) {
58 | // Google image search - 100 searches per day.
59 | // https://developers.google.com/image-search/
60 | var searchUrl = 'https://ajax.googleapis.com/ajax/services/search/images' +
61 | '?v=1.0&q=' + encodeURIComponent(searchTerm);
62 | var x = new XMLHttpRequest();
63 | x.open('GET', searchUrl);
64 | // The Google image search API responds with JSON, so let Chrome parse it.
65 | x.responseType = 'json';
66 | x.onload = function() {
67 | // Parse and process the response from Google Image Search.
68 | var response = x.response;
69 | if (!response || !response.responseData || !response.responseData.results ||
70 | response.responseData.results.length === 0) {
71 | errorCallback('No response from Google Image search!');
72 | return;
73 | }
74 | var firstResult = response.responseData.results[0];
75 | // Take the thumbnail instead of the full image to get an approximately
76 | // consistent image size.
77 | var imageUrl = firstResult.tbUrl;
78 | var width = parseInt(firstResult.tbWidth);
79 | var height = parseInt(firstResult.tbHeight);
80 | console.assert(
81 | typeof imageUrl == 'string' && !isNaN(width) && !isNaN(height),
82 | 'Unexpected respose from the Google Image Search API!');
83 | callback(imageUrl, width, height);
84 | };
85 | x.onerror = function() {
86 | errorCallback('Network error.');
87 | };
88 | x.send();
89 | }
90 |
91 | function renderStatus(statusText) {
92 | document.getElementById('status').textContent = statusText;
93 | }
94 |
95 | document.addEventListener('DOMContentLoaded', function() {
96 | getCurrentTabUrl(function(url) {
97 | // Put the image URL in Google search.
98 | renderStatus('Performing Google Image search for ' + url);
99 |
100 | getImageUrl(url, function(imageUrl, width, height) {
101 |
102 | renderStatus('Search term: ' + url + '\n' +
103 | 'Google image search result: ' + imageUrl);
104 | var imageResult = document.getElementById('image-result');
105 | // Explicitly set the width/height to minimize the number of reflows. For
106 | // a single image, this does not matter, but if you're going to embed
107 | // multiple external images in your page, then the absence of width/height
108 | // attributes causes the popup to resize multiple times.
109 | imageResult.width = width;
110 | imageResult.height = height;
111 | imageResult.src = imageUrl;
112 | imageResult.hidden = false;
113 |
114 | }, function(errorMessage) {
115 | renderStatus('Cannot display image. ' + errorMessage);
116 | });
117 | });
118 | });
119 |
--------------------------------------------------------------------------------
/github.js:
--------------------------------------------------------------------------------
1 | function addRepoPageItems(){
2 |
3 | if( $( "h1 svg.octicon-repo ~ strong[itemprop='name'] + a.cci, h1 svg.octicon-lock ~ strong[itemprop='name'] + a.cci" ).length == 0 ){
4 |
5 | // Start with a grey status indicator until we determine the project's build status
6 | $("h1 svg.octicon-repo ~ strong[itemprop='name'], h1 svg.octicon-lock ~ strong[itemprop='name']").after('');
7 | }
8 |
9 | if( $( ".cci.btn" ).length == 0 ){
10 |
11 | // start with a follow button until we determine if we're actually following this project
12 | $("ul.pagehead-actions").prepend(genPageAction);
13 | $( ".cci.btn" ).click(function( e ){
14 |
15 | if( apiToken.length == 0 ){
16 | alert( "Your CircleCI API token must be set in Pointless' Options page to use this feature." );
17 | return
18 | }
19 |
20 | const followConfirm = "Are you sure you want to follow this project on CircleCI?";
21 | const unFollowConfirm = "Are you sure you want to stop following this project? If you are the last person following, the project will stop building. Continue?";
22 | const firstFollowConfirm = "This will start building this project on CircleCI with you following the project. Are you sure?";
23 | const cantFollowAlert = "You do not have the proper permissions to follow this project.";
24 |
25 | if( project.following ){
26 |
27 | if( confirm( unFollowConfirm ) == true ){
28 | $.post( apiURL + "project/github/" + project.org + "/" + project.repo + "/unfollow?circle-token=" + apiToken, function( data ){
29 |
30 | $( ".cci.btn span" ).text( "Follow" );
31 | $( ".cci.btn" ).attr( "title", "Follow this project on CircleCI." );
32 | alert( "You have successfully unfollowed " + project.org + "/" + project.repo + "." );
33 | });
34 | }
35 | } else{
36 | if( project.writable ){
37 |
38 | if( confirm( followConfirm ) == true ){
39 | $.post( apiURL + "project/github/" + project.org + "/" + project.repo + "/follow?circle-token=" + apiToken, function( data ){
40 |
41 | $( ".cci.btn span" ).text( "Unfollow" );
42 | $( ".cci.btn" ).attr( "title", "Unfollow this project on CircleCI." );
43 | alert( "You have successfully followed " + project.org + "/" + project.repo + "." );
44 | });
45 | }
46 | } else{
47 | alert( cantFollowAlert );
48 | }
49 | }
50 |
51 | e.preventDefault();
52 | });
53 | }
54 | }
55 |
56 | function genPageAction(){
57 |
58 | return `
59 |
60 |
61 |
Follow
62 |
63 | `;
64 | }
65 |
66 | function getAPIToken(){
67 |
68 | port = chrome.runtime.connect( {name: "github"} );
69 | port.postMessage( {request: "api-token"} );
70 | port.onMessage.addListener( function( msg ){
71 | if( msg.request == "api-token"){
72 | apiToken = msg.response;
73 |
74 | initGitHub();
75 | }
76 | });
77 | }
78 |
79 | function initGitHub(){
80 |
81 | addRepoPageItems();
82 |
83 | $.getJSON( apiURL + "project/github/" + project.org + "/" + project.repo + "/settings?circle-token=" + apiToken, function( data, httpStatus ){
84 |
85 | project.defaultBranch = data.default_branch;
86 | project.following = data.following;
87 | // The below line is broken. Temp removing it.
88 | //project.writable = data.scopes.includes("write-settings");
89 | project.building = data.has_usable_key;
90 | project.foss = data.oss;
91 |
92 | // Get build status if project is building on CircleCI
93 | if( project.building ){
94 |
95 | // Choose branch based on contex
96 | var curBranch = "";
97 | // if we're on the main page, viewing a non-default branch
98 | if( window.location.pathname.split("/")[3] == "tree" ){
99 | curBranch = window.location.pathname.split("/")[4];
100 | // base branch detection for PRs is causing problems with GitHub's new UI. For now, we'll disable and just use the default.
101 | //}else if( window.location.pathname.split("/")[3] == "pull" ){
102 | // curBranch = $( "div.TableObject-item--primary a.author + span.commit-ref span.css-truncate-target" ).text();
103 | }else{
104 | curBranch = project.defaultBranch;
105 | }
106 |
107 | $.getJSON( apiURL + "project/github/" + project.org + "/" + project.repo + "/tree/" + curBranch + "?circle-token=" + apiToken, function( data ){
108 | lastBuild = data[0].status;
109 |
110 | // check build status of last build that completed
111 | var classStatus;
112 |
113 | switch( lastBuild ){
114 | case "success":
115 | case "fixed":
116 | classStatus = "passed";
117 | break;
118 |
119 | case "failed":
120 | case "timedout":
121 | classStatus = "failed";
122 | break;
123 |
124 | case "running":
125 | classStatus = "running";
126 | break;
127 |
128 | default:
129 | classStatus = "error";
130 | }
131 |
132 | $( "h1 svg.octicon-repo ~ a.cci span, h1 svg.octicon-lock ~ a.cci span" ).addClass( classStatus );
133 | $( "h1 svg.octicon-repo ~ a.cci, h1 svg.octicon-lock ~ a.cci" ).attr({
134 | "href": "https://app.circleci.com/pipelines/github/" + project.org + "/" + project.repo + "?branch=" + curBranch,
135 | "title": curBranch + " branch build status: " + classStatus + ". Click to visit project on CircleCI."
136 | });
137 | });
138 | }
139 |
140 | // update CircleCI pagehead-action with following status if needed
141 | if( project.following ){
142 | $( ".cci.btn span" ).text( "Unfollow" );
143 | $( ".cci.btn" ).attr( "title", "Unfollow this project on CircleCI." );
144 | }else if( !project.writable && !project.foss ){
145 | $( ".cci.btn" ).attr( "title", "You do not have permission to follow this project on CircleCI." );
146 | }else{
147 | $( ".cci.btn" ).attr( "title", "Follow this project on CircleCI." );
148 | }
149 | })
150 | }
151 |
152 | apiURL = "https://circleci.com/api/v1.1/";
153 |
154 | project = {
155 | org: window.location.pathname.split("/")[1],
156 | repo: window.location.pathname.split("/")[2],
157 | defaultBranch: "master", // asume master until told otherwise
158 | following: false,
159 | writable: false, // whether the user has write permission to the repo
160 | building: true, // whether the project is building on CircleCI
161 | foss: false
162 | };
163 |
164 |
165 | var port;
166 | var apiToken;
167 |
168 | $(document).ready(function(){
169 |
170 |
171 | getAPIToken();
172 |
173 | $(document).on('pjax:end', function (t) {
174 | initGitHub();
175 | });
176 |
177 | });
178 |
--------------------------------------------------------------------------------
/vendor/algoliasearch-4.1.0.min.js:
--------------------------------------------------------------------------------
1 | /*! algoliasearch-lite.umd.js | 4.1.0 | © Algolia, inc. | https://github.com/algolia/algoliasearch-client-javascript */
2 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).algoliasearch=t()}(this,(function(){"use strict";function e(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function t(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function r(r){for(var n=1;n=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function o(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if(!(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e)))return;var r=[],n=!0,o=!1,a=void 0;try{for(var u,i=e[Symbol.iterator]();!(n=(u=i.next()).done)&&(r.push(u.value),!t||r.length!==t);n=!0);}catch(e){o=!0,a=e}finally{try{n||null==i.return||i.return()}finally{if(o)throw a}}return r}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function a(e){return function(e){if(Array.isArray(e)){for(var t=0,r=new Array(e.length);t2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return Promise.resolve().then((function(){var r=JSON.stringify(e),n=a()[r];return Promise.all([n||t(),void 0!==n])})).then((function(e){var t=o(e,2),n=t[0],a=t[1];return Promise.all([n,a||r.miss(n)])})).then((function(e){return o(e,1)[0]}))},set:function(e,t){return Promise.resolve().then((function(){var o=a();return o[JSON.stringify(e)]=t,n().setItem(r,JSON.stringify(o)),t}))},delete:function(e){return Promise.resolve().then((function(){var t=a();delete t[JSON.stringify(e)],n().setItem(r,JSON.stringify(t))}))},clear:function(){return Promise.resolve().then((function(){n().removeItem(r)}))}}}function i(e){var t=a(e.caches),r=t.shift();return void 0===r?{get:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},n=t();return n.then((function(e){return Promise.all([e,r.miss(e)])})).then((function(e){return o(e,1)[0]}))},set:function(e,t){return Promise.resolve(t)},delete:function(e){return Promise.resolve()},clear:function(){return Promise.resolve()}}:{get:function(e,n){var o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return r.get(e,n,o).catch((function(){return i({caches:t}).get(e,n,o)}))},set:function(e,n){return r.set(e,n).catch((function(){return i({caches:t}).set(e,n)}))},delete:function(e){return r.delete(e).catch((function(){return i({caches:t}).delete(e)}))},clear:function(){return r.clear().catch((function(){return i({caches:t}).clear()}))}}}function s(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{serializable:!0},t={};return{get:function(r,n){var o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},a=JSON.stringify(r);if(a in t)return Promise.resolve(e.serializable?JSON.parse(t[a]):t[a]);var u=n(),i=o&&o.miss||function(){return Promise.resolve()};return u.then((function(e){return i(e)})).then((function(){return u}))},set:function(r,n){return t[JSON.stringify(r)]=e.serializable?JSON.stringify(n):n,Promise.resolve(n)},delete:function(e){return delete t[JSON.stringify(e)],Promise.resolve()},clear:function(){return t={},Promise.resolve()}}}function c(e){for(var t=e.length-1;t>0;t--){var r=Math.floor(Math.random()*(t+1)),n=e[t];e[t]=e[r],e[r]=n}return e}function l(e,t){return Object.keys(void 0!==t?t:{}).forEach((function(r){e[r]=t[r](e)})),e}function f(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n0?n:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var m={Read:1,Write:2,Any:3},p=1,v=2,g=3;function y(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:p;return r({},e,{status:t,lastUpdate:Date.now()})}function b(e){return{protocol:e.protocol||"https",url:e.url,accept:e.accept||m.Any}}var O="GET",P="POST";function q(e,t){return Promise.all(t.map((function(t){return e.get(t,(function(){return Promise.resolve(y(t))}))}))).then((function(e){var r=e.filter((function(e){return function(e){return e.status===p||Date.now()-e.lastUpdate>12e4}(e)})),n=e.filter((function(e){return function(e){return e.status===g&&Date.now()-e.lastUpdate<=12e4}(e)})),o=[].concat(a(r),a(n));return{getTimeout:function(e,t){return(0===n.length&&0===e?1:n.length+3+e)*t},statelessHosts:o.length>0?o.map((function(e){return b(e)})):t}}))}function j(e,t,n,o){var u=[],i=function(e,t){if(e.method===O||void 0===e.data&&void 0===t.data)return;var n=Array.isArray(e.data)?e.data:r({},e.data,{},t.data);return JSON.stringify(n)}(n,o),s=function(e,t){var n=r({},e.headers,{},t.headers),o={};return Object.keys(n).forEach((function(e){var t=n[e];o[e.toLowerCase()]=t})),o}(e,o),c=n.method,l=n.method!==O?{}:r({},n.data,{},o.data),f=r({"x-algolia-agent":e.userAgent.value},e.queryParameters,{},l,{},o.queryParameters),h=0,d=function t(r,a){var l=r.pop();if(void 0===l)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:A(u)};var d={data:i,headers:s,method:c,url:w(l,n.path,f),connectTimeout:a(h,e.timeouts.connect),responseTimeout:a(h,o.timeout)},m=function(e){var t={request:d,response:e,host:l,triesLeft:r.length};return u.push(t),t},p={onSucess:function(e){return function(e){try{return JSON.parse(e.content)}catch(t){throw function(e,t){return{name:"DeserializationError",message:e,response:t}}(t.message,e)}}(e)},onRetry:function(n){var o=m(n);return n.isTimedOut&&h++,Promise.all([e.logger.info("Retryable failure",x(o)),e.hostsCache.set(l,y(l,n.isTimedOut?g:v))]).then((function(){return t(r,a)}))},onFail:function(e){throw m(e),function(e,t){var r=e.content,n=e.status,o=r;try{o=JSON.parse(r).message}catch(e){}return function(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}(o,n,t)}(e,A(u))}};return e.requester.send(d).then((function(e){return function(e,t){return function(e){var t=e.status;return e.isTimedOut||function(e){var t=e.isTimedOut,r=e.status;return!t&&0==~~r}(e)||2!=~~(t/100)&&4!=~~(t/100)}(e)?t.onRetry(e):2==~~(e.status/100)?t.onSucess(e):t.onFail(e)}(e,p)}))};return q(e.hostsCache,t).then((function(e){return d(a(e.statelessHosts).reverse(),e.getTimeout)}))}function S(e){var t={value:"Algolia for JavaScript (".concat(e,")"),add:function(e){var r="; ".concat(e.segment).concat(void 0!==e.version?" (".concat(e.version,")"):"");return-1===t.value.indexOf(r)&&(t.value="".concat(t.value).concat(r)),t}};return t}function w(e,t,r){var n=T(r),o="".concat(e.protocol,"://").concat(e.url,"/").concat("/"===t.charAt(0)?t.substr(1):t);return n.length&&(o+="?".concat(n)),o}function T(e){return Object.keys(e).map((function(t){return f("%s=%s",t,(r=e[t],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(e[t]):e[t]));var r})).join("&")}function A(e){return e.map((function(e){return x(e)}))}function x(e){var t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return r({},e,{request:r({},e.request,{headers:r({},e.request.headers,{},t)})})}var C=function(e){var t=e.appId,n=function(e,t,r){var n={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers:function(){return e===h.WithinHeaders?n:{}},queryParameters:function(){return e===h.WithinQueryParameters?n:{}}}}(void 0!==e.authMode?e.authMode:h.WithinHeaders,t,e.apiKey),a=function(e){var t=e.hostsCache,r=e.logger,n=e.requester,a=e.requestsCache,u=e.responsesCache,i=e.timeouts,s=e.userAgent,c=e.hosts,l=e.queryParameters,f={hostsCache:t,logger:r,requester:n,requestsCache:a,responsesCache:u,timeouts:i,userAgent:s,headers:e.headers,queryParameters:l,hosts:c.map((function(e){return b(e)})),read:function(e,t){var r=d(t,f.timeouts.read),n=function(){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&m.Read)})),e,r)};if(!0!==(void 0!==r.cacheable?r.cacheable:e.cacheable))return n();var a={request:e,mappedRequestOptions:r,transporter:{queryParameters:f.queryParameters,headers:f.headers}};return f.responsesCache.get(a,(function(){return f.requestsCache.get(a,(function(){return f.requestsCache.set(a,n()).then((function(e){return Promise.all([f.requestsCache.delete(a),e])}),(function(e){return Promise.all([f.requestsCache.delete(a),Promise.reject(e)])})).then((function(e){var t=o(e,2);t[0];return t[1]}))}))}),{miss:function(e){return f.responsesCache.set(a,e)}})},write:function(e,t){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&m.Write)})),e,d(t,f.timeouts.write))}};return f}(r({hosts:[{url:"".concat(t,"-dsn.algolia.net"),accept:m.Read},{url:"".concat(t,".algolia.net"),accept:m.Write}].concat(c([{url:"".concat(t,"-1.algolianet.com")},{url:"".concat(t,"-2.algolianet.com")},{url:"".concat(t,"-3.algolianet.com")}]))},e,{headers:r({},n.headers(),{},{"content-type":"application/x-www-form-urlencoded"},{},e.headers),queryParameters:r({},n.queryParameters(),{},e.queryParameters)}));return l({transporter:a,appId:t,addAlgoliaAgent:function(e,t){a.userAgent.add({segment:e,version:t})},clearCache:function(){return Promise.all([a.requestsCache.clear(),a.responsesCache.clear()]).then((function(){}))}},e.methods)},N=function(e){return function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n={transporter:e.transporter,appId:e.appId,indexName:t};return l(n,r.methods)}},k=function(e){return function(t,n){var o=t.map((function(e){return r({},e,{params:T(e.params||{})})}));return e.transporter.read({method:P,path:"1/indexes/*/queries",data:{requests:o},cacheable:!0},n)}},J=function(e){return function(t,o){return Promise.all(t.map((function(t){var a=t.params,u=a.facetName,i=a.facetQuery,s=n(a,["facetName","facetQuery"]);return N(e)(t.indexName,{methods:{searchForFacetValues:I}}).searchForFacetValues(u,i,r({},o,{},s))})))}},E=function(e){return function(t,r){return e.transporter.read({method:P,path:f("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r)}},I=function(e){return function(t,r,n){return e.transporter.read({method:P,path:f("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},n)}},F=1,R=2,D=3;function W(e,t,n){var o,a={appId:e,apiKey:t,timeouts:{connect:1,read:2,write:30},requester:{send:function(e){return new Promise((function(t){var r=new XMLHttpRequest;r.open(e.method,e.url,!0),Object.keys(e.headers).forEach((function(t){return r.setRequestHeader(t,e.headers[t])}));var n,o=function(e,n){return setTimeout((function(){r.abort(),t({status:0,content:n,isTimedOut:!0})}),1e3*e)},a=o(e.connectTimeout,"Connection timeout");r.onreadystatechange=function(){r.readyState>r.OPENED&&void 0===n&&(clearTimeout(a),n=o(e.responseTimeout,"Socket timeout"))},r.onerror=function(){0===r.status&&(clearTimeout(a),clearTimeout(n),t({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=function(){clearTimeout(a),clearTimeout(n),t({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(e.data)}))}},logger:(o=D,{debug:function(e,t){return F>=o&&console.debug(e,t),Promise.resolve()},info:function(e,t){return R>=o&&console.info(e,t),Promise.resolve()},error:function(e,t){return console.error(e,t),Promise.resolve()}}),responsesCache:s(),requestsCache:s({serializable:!1}),hostsCache:i({caches:[u({key:"".concat("4.1.0","-").concat(e)}),s()]}),userAgent:S("4.1.0").add({segment:"Browser",version:"lite"}),authMode:h.WithinQueryParameters};return C(r({},a,{},n,{methods:{search:k,searchForFacetValues:J,multipleQueries:k,multipleSearchForFacetValues:J,initIndex:function(e){return function(t){return N(e)(t,{methods:{search:E,searchForFacetValues:I}})}}}}))}return W.version="4.1.0",W}));
3 |
--------------------------------------------------------------------------------
/vendor/jquery-3.5.1.min.js:
--------------------------------------------------------------------------------
1 | /*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */
2 | !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,""],col:[2,""],tr:[2,""],td:[3,""],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0