├── .gitignore ├── favicon.ico ├── docs ├── broken.png ├── history.png ├── autocomplete.png ├── requestformat.png └── syntaxhighlighting.png ├── icons ├── logo128.png ├── logo16.png ├── logo19.png ├── logo38.png └── logo48.png ├── package.sh ├── lib ├── font-awesome │ └── font │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff ├── bootstrap │ ├── img │ │ ├── glyphicons-halflings.png │ │ └── glyphicons-halflings-white.png │ └── js │ │ └── bootstrap.min.js ├── jqueryui │ └── jquery-ui-1.9.2.custom.min.css ├── src-noconflict │ ├── theme-monokai.js │ └── mode-json.js └── moment.min.js ├── src ├── background.js ├── curl.js ├── kb.js ├── history.js ├── mappings.js ├── utils.js └── base.js ├── .travis.yml ├── README.md ├── tests ├── src │ ├── autocomplete_tests.js │ ├── kb_tests.js │ ├── curl_tests.js │ ├── utils_tests.js │ ├── mapping_tests.js │ └── tokenization_tests.js ├── index.html ├── phantomjs.runner.js └── lib │ └── qunit-1.10.0.css ├── kb ├── globals.js ├── templates.js ├── warmers.js ├── misc.js ├── aliases.js ├── cluster.js ├── indices.js ├── settings.js ├── search.js ├── facets.js ├── mappings.js ├── filter.js └── query.js ├── manifest.json ├── welcome.html ├── sense.css └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/favicon.ico -------------------------------------------------------------------------------- /docs/broken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/docs/broken.png -------------------------------------------------------------------------------- /docs/history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/docs/history.png -------------------------------------------------------------------------------- /icons/logo128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/icons/logo128.png -------------------------------------------------------------------------------- /icons/logo16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/icons/logo16.png -------------------------------------------------------------------------------- /icons/logo19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/icons/logo19.png -------------------------------------------------------------------------------- /icons/logo38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/icons/logo38.png -------------------------------------------------------------------------------- /icons/logo48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/icons/logo48.png -------------------------------------------------------------------------------- /docs/autocomplete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/docs/autocomplete.png -------------------------------------------------------------------------------- /docs/requestformat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/docs/requestformat.png -------------------------------------------------------------------------------- /package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | zip -r "$1" icons kb lib src favicon.ico *.html manifest.json sense.css 3 | -------------------------------------------------------------------------------- /docs/syntaxhighlighting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/docs/syntaxhighlighting.png -------------------------------------------------------------------------------- /lib/font-awesome/font/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/lib/font-awesome/font/FontAwesome.otf -------------------------------------------------------------------------------- /lib/bootstrap/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/lib/bootstrap/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /lib/font-awesome/font/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/lib/font-awesome/font/fontawesome-webfont.eot -------------------------------------------------------------------------------- /lib/font-awesome/font/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/lib/font-awesome/font/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /lib/font-awesome/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/lib/font-awesome/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /lib/bootstrap/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleskes/sense_old/HEAD/lib/bootstrap/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /src/background.js: -------------------------------------------------------------------------------- 1 | chrome.browserAction.onClicked.addListener(function (tab) { 2 | chrome.tabs.create({'url': chrome.extension.getURL('index.html')}, function (tab) { 3 | }); 4 | }); 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | before_script: 5 | - python -m SimpleHTTPServer & 6 | - sleep 3 7 | 8 | script: phantomjs tests/phantomjs.runner.js http://localhost:8000/tests/ 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Sense is now part of Marvel 3 | ===== 4 | 5 | The development of Sense has moved into Elasticsearch Marvel, you can find it here: http://www.elasticsearch.org/overview/marvel/ 6 | 7 | If you have any question or find an issue, feel free to post on the elasticsearch user group: http://groups.google.com/forum/#!forum/elasticsearch 8 | -------------------------------------------------------------------------------- /tests/src/autocomplete_tests.js: -------------------------------------------------------------------------------- 1 | var global = window; 2 | 3 | module("Autocomplete", { 4 | setup: function () { 5 | if (!global.sense) 6 | global.sense = {}; 7 | var sense = global.sense; 8 | sense.tests = {}; 9 | }, 10 | 11 | teardown: function () { 12 | sense.tests = {}; 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /kb/globals.js: -------------------------------------------------------------------------------- 1 | sense.kb.addGlobalAutocompleteRules("highlight", { 2 | pre_tags: {}, post_tags: {}, tags_schema: {}, 3 | fields: { "$FIELD$": { "fragment_size": {}, "number_of_fragments": {} }} 4 | } 5 | ); 6 | 7 | // only used with scope links as there is no common name for scripts 8 | sense.kb.addGlobalAutocompleteRules("SCRIPT_ENV", { 9 | __template: { "script": ""}, 10 | script: "", 11 | lang: "", 12 | params: {} 13 | } 14 | ); 15 | -------------------------------------------------------------------------------- /kb/templates.js: -------------------------------------------------------------------------------- 1 | sense.kb.addEndpointDescription('_template', { 2 | match: /\/?_template/, 3 | def_method: "PUT", 4 | methods: ["GET", "PUT", "DELETE"], 5 | endpoint_autocomplete: [ 6 | "_template/TEMPLATE_ID" 7 | ], 8 | indices_mode: "none", 9 | types_mode: "none", 10 | doc_id_mode: "none", 11 | 12 | data_autocomplete_rules: { 13 | template: "index*", 14 | warmers: { __scope_link: "_warmer" }, 15 | mappings: {}, 16 | settings: {} 17 | } 18 | }); -------------------------------------------------------------------------------- /kb/warmers.js: -------------------------------------------------------------------------------- 1 | sense.kb.addEndpointDescription('_warmer', { 2 | match: /_warmer/, 3 | def_method: "PUT", 4 | methods: ["GET", "PUT", "DELETE"], 5 | endpoint_autocomplete: [ 6 | "_warmer", "_warmer/WARMER_ID" 7 | ], 8 | indices_mode: "required_multi", 9 | types_mode: "none", 10 | doc_id_mode: "none", 11 | data_autocomplete_rules: { 12 | query: { 13 | // populated by a global rule 14 | }, 15 | facets: { 16 | // populated by a global rule 17 | } 18 | } 19 | }); -------------------------------------------------------------------------------- /kb/misc.js: -------------------------------------------------------------------------------- 1 | sense.kb.addEndpointDescription('_stats', { 2 | methods: ["GET"], 3 | endpoint_autocomplete: ['_stats'], 4 | indices_mode: "multi", 5 | types_mode: "none", 6 | doc_id_mode: "none" 7 | }); 8 | 9 | sense.kb.addEndpointDescription('_cache/clear', { 10 | methods: ["GET"], 11 | endpoint_autocomplete: ['_cache/clear'], 12 | indices_mode: "multi", 13 | types_mode: "none", 14 | doc_id_mode: "none" 15 | }); 16 | sense.kb.addEndpointDescription('_status', { 17 | methods: ["GET"], 18 | indices_mode: "multi", 19 | types_mode: "none", 20 | doc_id_mode: "none", 21 | endpoint_autocomplete: ['_status'] 22 | }); 23 | 24 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | 4 | "name": "Sense (Beta)", 5 | "description": "A JSON aware developer console to ElasticSearch.", 6 | "version": "0.9.0", 7 | 8 | "icons": { 9 | "16": "icons/logo16.png", 10 | "48": "icons/logo48.png", 11 | "128": "icons/logo128.png" 12 | }, 13 | 14 | "permissions": [ 15 | "https://*/", 16 | "http://*/", 17 | "tabs", 18 | "clipboardWrite" 19 | ], 20 | "browser_action": { 21 | "default_icon": { 22 | "19": "icons/logo19.png", 23 | "38": "icons/logo38.png" 24 | } 25 | }, 26 | "background": { 27 | "scripts": ["src/background.js"] 28 | }, 29 | "content_security_policy": "script-src 'self' https://ssl.google-analytics.com; object-src 'self'" 30 | } -------------------------------------------------------------------------------- /kb/aliases.js: -------------------------------------------------------------------------------- 1 | sense.kb.addEndpointDescription('_aliases', { 2 | match: /_aliases/, 3 | def_method: "GET", 4 | methods: ["GET", "POST"], 5 | endpoint_autocomplete: [ 6 | "_aliases" 7 | ], 8 | indices_mode: "multi", 9 | types_mode: "none", 10 | doc_id_mode: "none", 11 | data_autocomplete_rules: { 12 | "actions": { 13 | __template: [ 14 | { "add": { "index": "test1", "alias": "alias1" } } 15 | ], 16 | __any_of: [ 17 | { 18 | add: { 19 | index: "$INDEX$", 20 | alias: "", 21 | filter: {}, 22 | routing: "1", 23 | search_routing: "1,2", 24 | index_routing: "1" 25 | }, 26 | remove: { 27 | index: "", 28 | alias: "" 29 | } 30 | } 31 | ] 32 | } 33 | } 34 | }); -------------------------------------------------------------------------------- /kb/cluster.js: -------------------------------------------------------------------------------- 1 | sense.kb.addEndpointDescription('_cluster/nodes/stats', { 2 | methods: ["GET"], 3 | indices_mode: "none", 4 | types_mode: "none" 5 | }); 6 | sense.kb.addEndpointDescription('_cluster/state', { 7 | methods: ["GET"], 8 | endpoint_autocomplete: ['_cluster/state'], 9 | indices_mode: "none", 10 | types_mode: "none" 11 | }); 12 | 13 | sense.kb.addEndpointDescription('_cluster/health', { 14 | methods: ["GET"], 15 | endpoint_autocomplete: ['_cluster/health'], 16 | indices_mode: "none", 17 | types_mode: "none" 18 | }); 19 | 20 | sense.kb.addEndpointDescription('_cluster/settings', { 21 | methods: ["GET", "PUT"], 22 | endpoint_autocomplete: ['_cluster/settings'], 23 | indices_mode: "none", 24 | types_mode: "none", 25 | data_autocomplete_rules: { 26 | persistent: { 27 | "routing.allocation.same_shard.host" : { __one_of: [ false, true ]} 28 | }, 29 | 30 | transient: { 31 | __scope_link: ".persistent" 32 | } 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /kb/indices.js: -------------------------------------------------------------------------------- 1 | sense.kb.addEndpointDescription('_refresh', { 2 | def_method: "POST", 3 | methods: ["POST"], 4 | endpoint_autocomplete: [ 5 | "_refresh" 6 | ], 7 | indices_mode: "multi" 8 | }); 9 | 10 | sense.kb.addEndpointDescription('_stats', { 11 | def_method: "GET", 12 | methods: ["GET"], 13 | endpoint_autocomplete: [ 14 | "_stats" 15 | ], 16 | indices_mode: "multi" 17 | }); 18 | 19 | sense.kb.addEndpointDescription('_segments', { 20 | def_method: "GET", 21 | methods: ["GET"], 22 | endpoint_autocomplete: [ 23 | "_segments" 24 | ], 25 | indices_mode: "multi" 26 | }); 27 | 28 | sense.kb.addEndpointDescription('__create_index__', { 29 | methods: ["PUT", "DELETE"], 30 | indices_mode: "single", 31 | types_mode: "none", 32 | match: "^/?$", 33 | endpoint_autocomplete: [ 34 | "" 35 | ], 36 | data_autocomplete_rules: { 37 | mappings: { 38 | __scope_link: "_mapping" 39 | }, 40 | settings: { 41 | __scope_link: "_settings.index" 42 | } 43 | } 44 | 45 | 46 | 47 | }); -------------------------------------------------------------------------------- /welcome.html: -------------------------------------------------------------------------------- 1 |

Quick intro to the UI

2 | 3 |

Sense is split into two panes: an editor pane (white) and a response pane (black). 4 | Use the editor to type requests and submit them to Elasticsearch. The results will be displayed in 5 | the response pane on the right side. 6 |

7 | 8 |

Sense understands requests in a compact format, similar to cURL: 9 |

10 | 11 |

While typing a request, Sense will make suggestions which you can than accept by hitting Enter/Tab. 12 | These suggestions are made based on the request structure as well as your indices and types. 13 |

14 | 15 | 16 |

A few quick tips, while I have your attention

17 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /kb/settings.js: -------------------------------------------------------------------------------- 1 | sense.kb.addEndpointDescription('_settings', { 2 | match: /_settings/, 3 | methods: ["GET", "PUT"], 4 | endpoint_autocomplete: ['_settings'], 5 | indices_mode: "multi", 6 | types_mode: "none", 7 | doc_id_mode: "none", 8 | data_autocomplete_rules: { 9 | index: { 10 | refresh_interval: "1s", 11 | number_of_replicas: 1, 12 | "blocks.read_only": { __one_of: [ false, true ]}, 13 | "blocks.read": { __one_of: [ true, false ]}, 14 | "blocks.write": { __one_of: [ true, false ]}, 15 | "blocks.metadata": { __one_of: [ true, false] }, 16 | term_index_interval: 32, 17 | term_index_divisor: 1, 18 | "translog.flush_threshold_ops": 5000, 19 | "translog.flush_threshold_size": "200mb", 20 | "translog.flush_threshold_period": "30m", 21 | "translog.disable_flush": { __one_of: [ true, false ]}, 22 | "cache.filter.max_size": "2gb", 23 | "cache.filter.expire": "2h", 24 | "gateway.snapshot_interval": "10s", 25 | routing: { 26 | allocation: { 27 | include: { tag: "" }, 28 | exclude: { tag: ""}, 29 | require: { tag: ""}, 30 | total_shards_per_node: -1 31 | } 32 | }, 33 | "recovery.initial_shards": { __one_of: ["quorum", "quorum-1", "half", "full", "full-1" ]}, 34 | "ttl.disable_purge": { __one_of: [ true, false ]}, 35 | analysis: { 36 | analyzer: {}, 37 | tokenizer: {}, 38 | filter: {}, 39 | char_filter: {} 40 | } 41 | 42 | 43 | } 44 | } 45 | }); 46 | -------------------------------------------------------------------------------- /kb/search.js: -------------------------------------------------------------------------------- 1 | sense.kb.addEndpointDescription('_search', { 2 | def_method: "POST", 3 | methods: ["GET", "POST"], 4 | endpoint_autocomplete: [ 5 | "_search" 6 | ], 7 | indices_mode: "multi", 8 | types_mode: "multi", 9 | doc_id_mode: "none", 10 | data_autocomplete_rules: { 11 | query: { 12 | // populated by a global rule 13 | }, 14 | facets: { 15 | __template: { 16 | "NAME": { 17 | "TYPE": { 18 | } 19 | } 20 | } 21 | // populated by a global rule 22 | }, 23 | filter: { 24 | // added by global rules. 25 | }, 26 | size: { __template: 20 }, 27 | from: {}, 28 | sort: { 29 | __template: [ 30 | { "FIELD": { "order": "desc"} } 31 | ], 32 | __any_of: [ 33 | { 34 | "$FIELD$": { 35 | "order": { __one_of: ["desc", "asc"]} 36 | } 37 | }, 38 | "$FIELD$", 39 | "_score" 40 | ] 41 | }, 42 | search_type: {}, 43 | fields: [ "$FIELD$" ], 44 | script_fields: { 45 | __template: { "FIELD": { 46 | "script": "" 47 | }}, 48 | "*": { 49 | __scope_link: "GLOBAL.SCRIPT_ENV" 50 | } 51 | }, 52 | partial_fields: { 53 | __template: { 54 | "NAME": { include: [] } 55 | }, 56 | "*": { 57 | include: [], 58 | exclude: [] 59 | } 60 | }, 61 | highlight: { 62 | // populated by a global rule 63 | }, 64 | explain: { __one_of: [ true, false ]}, 65 | stats: [ "" ] 66 | 67 | } 68 | }); -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Sense unittests 6 | 7 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /lib/jqueryui/jquery-ui-1.9.2.custom.min.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.9.2 - 2012-12-17 2 | * http://jqueryui.com 3 | * Includes: jquery.ui.core.css, jquery.ui.autocomplete.css, jquery.ui.menu.css 4 | * Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */ 5 | 6 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{zoom:1}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:absolute;top:0;left:0;width:100%;height:100%}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}* html .ui-autocomplete{width:1px}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:none}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;zoom:1;width:100%}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;zoom:1;font-weight:normal}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px}.ui-menu .ui-state-disabled{font-weight:normal;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right} -------------------------------------------------------------------------------- /src/curl.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var global = window; 3 | if (!global.sense) 4 | global.sense = {}; 5 | 6 | function detectCURL(text) { 7 | // returns true if text matches a curl request 8 | if (!text) return false; 9 | return text.match(/^\s*?curl\s+(-X[A-Z]+)?\s*['"]?.*?['"]?(\s*$|\s+?-d\s*?['"])/); 10 | 11 | } 12 | 13 | function parseCURL(text) { 14 | var matches = text.match(/^\s*?curl\s+(?:-s\s+)?(-X\s*[A-Z]+)?\s*/); 15 | var ret = { 16 | method: "", 17 | server: "", 18 | endpoint: "", 19 | data: "" 20 | }; 21 | if (matches[1]) { 22 | ret.method = matches[1].substring(2).trim(); // strip -X 23 | } 24 | text = text.substring(matches[0].length); // strip everything so far. 25 | if (text.length == 0) return ret; 26 | if (text[0] == '"') { 27 | matches = text.match(/^"([^"]*)"/); 28 | } 29 | else if (text[0] == "'") { 30 | matches = text.match(/^'([^']*)'/); 31 | } 32 | else { 33 | matches = text.match(/^(\S*)/); 34 | } 35 | 36 | if (!matches) return ret; 37 | var url = matches[1]; 38 | 39 | if (!url.match(/:\/\//)) url = "http://" + url; // inject http as curl does 40 | 41 | var urlAnchor = document.createElement("a"); 42 | urlAnchor.href = url; 43 | 44 | ret.server = (urlAnchor.protocol || "http") + "//" + urlAnchor.hostname; 45 | if (urlAnchor.port && urlAnchor.port != 0) ret.server += ":" + urlAnchor.port; 46 | ret.url = (urlAnchor.pathname || "") + (urlAnchor.search || ""); 47 | 48 | text = text.substring(matches[0].length); 49 | 50 | // now search for -d 51 | matches = text.match(/.*-d\s*?'/); 52 | if (matches) { 53 | ret.data = text.substring(matches[0].length).replace(/'\s*$/, ''); 54 | } 55 | else { 56 | matches = text.match(/.*-d\s*?"/); 57 | if (matches) { 58 | ret.data = text.substring(matches[0].length).replace(/"\s*$/, ''); 59 | ret.data = ret.data.replace(/\\(.)/gi, "$1"); 60 | } 61 | } 62 | 63 | if (ret.data) { 64 | ret.data = ret.data.trim(); 65 | } 66 | 67 | return ret; 68 | } 69 | 70 | 71 | global.sense.curl = {}; 72 | global.sense.curl.parseCURL = parseCURL; 73 | global.sense.curl.detectCURL = detectCURL; 74 | 75 | })(); 76 | -------------------------------------------------------------------------------- /kb/facets.js: -------------------------------------------------------------------------------- 1 | sense.kb.addGlobalAutocompleteRules("facets", { 2 | "*": { 3 | terms: { 4 | __template: { 5 | field: "FIELD", 6 | size: 10 7 | }, 8 | field: "$FIELD$", 9 | fields: ["$FIELD$"], 10 | size: 10, 11 | script: "", 12 | script_field: "", 13 | order: { __one_of: ["count", "term", "reverse_count", "reverse_term"]}, 14 | all_terms: { __one_of: [false, true]}, 15 | exclude: ["TERM"], 16 | regex: "", 17 | regex_flags: "" 18 | }, 19 | range: { 20 | __template: { 21 | field: "FIELD", 22 | ranges: [ 23 | { "to": 50 }, 24 | { "from": 20, "to": 70 }, 25 | { "from": 70, "to": 120 }, 26 | { "from": 150 } 27 | ] 28 | }, 29 | field: "$FIELD$", 30 | ranges: [ 31 | { to: 10, from: 20} 32 | ] 33 | }, 34 | histogram: { 35 | __template: { 36 | field: "FIELD", interval: 100 37 | }, 38 | field: "$FIELD$", 39 | interval: 100, 40 | time_interval: "1.5h", 41 | key_field: "$FIELD$", 42 | value_field: "$FIELD$", 43 | key_script: "", 44 | value_script: "", 45 | params: {} 46 | }, 47 | date_histogram: { 48 | __template: { 49 | field: "FIELD", 50 | "interval": "day" 51 | }, 52 | field: "$FIELD$", 53 | interval: { __one_of: ["year", "quarter", "month", "week", "day", "hour", "minute", "1h", "1d", "1w"]}, 54 | post_zone: -1, 55 | pre_zone: -1, 56 | factor: 1000, 57 | pre_offset: "1d", 58 | post_offset: "1d", 59 | key_field: "$FIELD$", 60 | value_field: "$FIELD$", 61 | value_script: "" 62 | }, 63 | filter: { 64 | }, 65 | query: { 66 | }, 67 | facet_filter: { 68 | __scope_link: "GLOBAL.filter" 69 | }, 70 | statistical: { 71 | __template: { 72 | field: "FIELD" 73 | }, 74 | field: "$FIELD$", 75 | fields: ["$FIELD$"], 76 | script: "" 77 | }, 78 | terms_stats: { 79 | __template: { 80 | key_field: "FIELD", 81 | value_field: "FIELD" 82 | }, 83 | key_field: "$FIELD$", 84 | value_field: "$FIELD$", 85 | value_script: "", 86 | size: 10, 87 | order: {__one_of: ["count", "term", "reverse_term", "reverse_count", "total", "reverse_total", 88 | "min", "reverse_min", "max", "reverse_max", "mean", "reverse_mean"]} 89 | } 90 | } 91 | } 92 | ); 93 | -------------------------------------------------------------------------------- /tests/src/kb_tests.js: -------------------------------------------------------------------------------- 1 | var global = window; 2 | 3 | module("Knowledge base", { 4 | setup: function () { 5 | var sense = global.sense; 6 | sense.mappings.clear(); 7 | sense.tests = {}; 8 | }, 9 | 10 | teardown: function () { 11 | sense.tests = {}; 12 | } 13 | }); 14 | 15 | 16 | test("Index mode filters", function () { 17 | global.sense.mappings.clear(); 18 | global.sense.kb.clear(); 19 | global.sense.kb.addEndpointDescription("_multi_indices", { 20 | indices_mode: "multi" 21 | }); 22 | global.sense.kb.addEndpointDescription("_one_or_more_indices", { 23 | indices_mode: "required_multi" 24 | }); 25 | global.sense.kb.addEndpointDescription("_single_index", { 26 | match: "_single_index", 27 | endpoint_autocomplete: [ 28 | "_single_index" 29 | ], 30 | indices_mode: "single" 31 | }); 32 | global.sense.kb.addEndpointDescription("_no_index", { 33 | indices_mode: "none" 34 | }); 35 | 36 | deepEqual(global.sense.kb.getEndpointAutocomplete([], [], null).sort(), ["_multi_indices", "_no_index" ]); 37 | deepEqual(global.sense.kb.getEndpointAutocomplete(["index"], [], null).sort(), ["_multi_indices", "_one_or_more_indices", "_single_index"]); 38 | deepEqual(global.sense.kb.getEndpointAutocomplete(["index1", "index2"], [], null).sort(), ["_multi_indices", "_one_or_more_indices"]); 39 | deepEqual(global.sense.kb.getEndpointAutocomplete(["index1", "index2"], ["type"], null).sort(), ["_multi_indices", "_one_or_more_indices"]); 40 | }); 41 | 42 | test("Type mode filters", function () { 43 | global.sense.mappings.clear(); 44 | global.sense.kb.clear(); 45 | global.sense.kb.addEndpointDescription("_multi_types", { 46 | indices_mode: "single", 47 | types_mode: "multi" 48 | }); 49 | global.sense.kb.addEndpointDescription("_single_type", { 50 | endpoint_autocomplete: [ 51 | "_single_type" 52 | ], 53 | indices_mode: "single", 54 | types_mode: "single" 55 | }); 56 | global.sense.kb.addEndpointDescription("_no_types", { 57 | indices_mode: "single", 58 | types_mode: "none" 59 | 60 | }); 61 | 62 | deepEqual(global.sense.kb.getEndpointAutocomplete(["index"], [], null).sort(), ["_multi_types", "_no_types" ]); 63 | deepEqual(global.sense.kb.getEndpointAutocomplete(["index"], ["type"], null).sort(), ["_multi_types", "_single_type"]); 64 | deepEqual(global.sense.kb.getEndpointAutocomplete(["index"], ["type", "type1"], null).sort(), ["_multi_types"]); 65 | }); 66 | 67 | test("Id mode filters", function () { 68 | global.sense.kb.clear(); 69 | global.sense.kb.addEndpointDescription("_single_id", { 70 | indices_mode: "single", 71 | types_mode: "single", 72 | doc_id_mode: "required_single" 73 | }); 74 | global.sense.kb.addEndpointDescription("_no_id", { 75 | indices_mode: "single", 76 | types_mode: "single", 77 | doc_id_mode: "none" 78 | 79 | }); 80 | 81 | deepEqual(global.sense.kb.getEndpointAutocomplete(["index"], ["type"], null).sort(), ["_no_id"].sort()); 82 | deepEqual(global.sense.kb.getEndpointAutocomplete(["index"], ["type"], "123").sort(), ["_single_id"].sort()); 83 | }); 84 | 85 | test("Get active scheme by doc id", function () { 86 | global.sense.kb.clear(); 87 | global.sense.kb.addEndpointDescription("_single_id", { 88 | match: ".*", 89 | indices_mode: "single", 90 | types_mode: "single", 91 | doc_id_mode: "required_single" 92 | }); 93 | global.sense.kb.addEndpointDescription("_no_id", { 94 | match: ".*", 95 | indices_mode: "single", 96 | types_mode: "single", 97 | doc_id_mode: "none" 98 | 99 | }); 100 | 101 | deepEqual(global.sense.kb.getEndpointDescriptionByPath("bla", ["index"], ["type"], null).doc_id_mode, "none"); 102 | deepEqual(global.sense.kb.getEndpointDescriptionByPath("bla", ["index"], ["type"], "123").doc_id_mode, "required_single"); 103 | }); 104 | -------------------------------------------------------------------------------- /tests/phantomjs.runner.js: -------------------------------------------------------------------------------- 1 | /* 2 | * QtWebKit-powered headless test runner using PhantomJS 3 | * 4 | * PhantomJS binaries: http://phantomjs.org/download.html 5 | * Requires PhantomJS 1.6+ (1.7+ recommended) 6 | * 7 | * Run with: 8 | * phantomjs runner.js [url-of-your-qunit-testsuite] 9 | * 10 | * e.g. 11 | * phantomjs runner.js http://localhost/qunit/test/index.html 12 | */ 13 | 14 | /*jshint latedef:false */ 15 | /*global phantom:false, require:false, console:false, window:false, QUnit:false */ 16 | 17 | (function () { 18 | 'use strict'; 19 | 20 | var args = require('system').args; 21 | 22 | // arg[0]: scriptName, args[1...]: arguments 23 | if (args.length !== 2) { 24 | console.error('Usage:\n phantomjs runner.js [url-of-your-qunit-testsuite]'); 25 | phantom.exit(1); 26 | } 27 | 28 | var url = args[1], 29 | page = require('webpage').create(); 30 | 31 | // Route `console.log()` calls from within the Page context to the main Phantom context (i.e. current `this`) 32 | page.onConsoleMessage = function (msg) { 33 | console.log(msg); 34 | }; 35 | 36 | page.onInitialized = function () { 37 | page.evaluate(addLogging); 38 | }; 39 | 40 | page.onCallback = function (message) { 41 | var result, 42 | failed; 43 | 44 | if (message) { 45 | if (message.name === 'QUnit.done') { 46 | result = message.data; 47 | failed = !result || result.failed; 48 | 49 | phantom.exit(failed ? 1 : 0); 50 | } 51 | } 52 | }; 53 | 54 | page.open(url, function (status) { 55 | if (status !== 'success') { 56 | console.error('Unable to access network: ' + status); 57 | phantom.exit(1); 58 | } else { 59 | // Cannot do this verification with the 'DOMContentLoaded' handler because it 60 | // will be too late to attach it if a page does not have any script tags. 61 | var qunitMissing = page.evaluate(function () { 62 | return (typeof QUnit === 'undefined' || !QUnit); 63 | }); 64 | if (qunitMissing) { 65 | console.error('The `QUnit` object is not present on this page.'); 66 | phantom.exit(1); 67 | } 68 | 69 | // Do nothing... the callback mechanism will handle everything! 70 | } 71 | }); 72 | 73 | function addLogging() { 74 | window.document.addEventListener('DOMContentLoaded', function () { 75 | var current_test_assertions = []; 76 | 77 | QUnit.log(function (details) { 78 | var response; 79 | 80 | // Ignore passing assertions 81 | if (details.result) { 82 | return; 83 | } 84 | 85 | response = details.message || ''; 86 | 87 | if (typeof details.expected !== 'undefined') { 88 | if (response) { 89 | response += ', '; 90 | } 91 | 92 | response += 'expected: ' + details.expected + ', but was: ' + details.actual; 93 | if (details.source) { 94 | response += "\n" + details.source; 95 | } 96 | } 97 | 98 | current_test_assertions.push('Failed assertion: ' + response); 99 | }); 100 | 101 | QUnit.testDone(function (result) { 102 | var i, 103 | len, 104 | name = result.module + ': ' + result.name; 105 | 106 | if (result.failed) { 107 | console.log('Test failed: ' + name); 108 | 109 | for (i = 0, len = current_test_assertions.length; i < len; i++) { 110 | console.log(' ' + current_test_assertions[i]); 111 | } 112 | } 113 | 114 | current_test_assertions.length = 0; 115 | }); 116 | 117 | QUnit.done(function (result) { 118 | console.log('Took ' + result.runtime + 'ms to run ' + result.total + ' tests. ' + result.passed + ' passed, ' + result.failed + ' failed.'); 119 | 120 | if (typeof window.callPhantom === 'function') { 121 | window.callPhantom({ 122 | 'name': 'QUnit.done', 123 | 'data': result 124 | }); 125 | } 126 | }); 127 | }, false); 128 | } 129 | })(); -------------------------------------------------------------------------------- /kb/mappings.js: -------------------------------------------------------------------------------- 1 | sense.kb.addEndpointDescription('_mapping', { 2 | def_method: "GET", 3 | methods: ["GET", "PUT"], 4 | indices_mode: "multi", 5 | types_mode: "multi", 6 | data_autocomplete_rules: { 7 | "$TYPE$": { 8 | __template: { 9 | properties: { 10 | "FIELD": {} 11 | } 12 | }, 13 | "_parent": { 14 | __template: { 15 | "type": "" 16 | }, 17 | "type": "$TYPE$" 18 | }, 19 | "index_analyzer": "standard", 20 | "search_analyzer": "standard", 21 | "analyzer": "standard", 22 | "dynamic_date_formats": ["yyyy-MM-dd"], 23 | "date_detection": { __one_of: [ true, false ]}, 24 | "numeric_detection": { __one_of: [ true, false ]}, 25 | "properties": { 26 | "*": { 27 | type: { __one_of: ["string", "float", "double", "byte", "short", "integer", "long", "date", "boolean", 28 | "binary", "object", "nested", "multi_field"]}, 29 | 30 | // strings 31 | index_name: "", 32 | store: { __one_of: ["no", "yes"]}, 33 | index: { __one_of: ["analyzed", "not_analyzed", "no"]}, 34 | term_vector: { __one_of: ["no", "yes", "with_offsets", "with_positions", "with_positions_offsets"]}, 35 | boost: 1.0, 36 | null_value: "", 37 | omit_norms: { __one_of: [ true, false]}, 38 | index_options: { __one_of: [ "docs", "freqs", "positions"]}, 39 | analyzer: "standard", 40 | index_analyzer: "standard", 41 | search_analyzer: "standard", 42 | include_in_all: { __one_of: [ false, true]}, 43 | ignore_above: 10, 44 | position_offset_gap: 0, 45 | 46 | // numeric 47 | precision_step: 4, 48 | ignore_malformed: { __one_of: [ true, false]}, 49 | 50 | // dates 51 | format: { __one_of: [ "basic_date", "basic_date_time", "basic_date_time_no_millis", 52 | "basic_ordinal_date", "basic_ordinal_date_time", "basic_ordinal_date_time_no_millis", 53 | "basic_time", "basic_time_no_millis", "basic_t_time", "basic_t_time_no_millis", 54 | "basic_week_date", "basic_week_date_time", "basic_week_date_time_no_millis", 55 | "date", "date_hour", "date_hour_minute", "date_hour_minute_second", "date_hour_minute_second_fraction", 56 | "date_hour_minute_second_millis", "date_optional_time", "date_time", "date_time_no_millis", 57 | "hour", "hour_minute", "hour_minute_second", "hour_minute_second_fraction", "hour_minute_second_millis", 58 | "ordinal_date", "ordinal_date_time", "ordinal_date_time_no_millis", "time", "time_no_millis", 59 | "t_time", "t_time_no_millis", "week_date", "week_date_time", "weekDateTimeNoMillis", "week_year", 60 | "weekyearWeek", "weekyearWeekDay", "year", "year_month", "year_month_day"]}, 61 | 62 | fielddata: { 63 | filter: { 64 | regex: "", 65 | frequency: { 66 | min: 0.001, 67 | max: 0.1, 68 | min_segment_size: 500 69 | } 70 | } 71 | }, 72 | postings_format: { __one_of: ["direct", "memory", "pulsing", "bloom_default", "bloom_pulsing", "default"]}, 73 | similarity: { __one_of: [ "default", "BM25" ]}, 74 | 75 | // objects 76 | properties: { 77 | __scope_link: "_mapping.$TYPE$.properties" 78 | }, 79 | 80 | // multi_field 81 | path: { __one_of: [ "just_name", "full"]}, 82 | fields: { 83 | "*": { 84 | __scope_link: "_mapping.$TYPE$.properties.$FIELD$" 85 | } 86 | } 87 | } 88 | 89 | 90 | } 91 | } 92 | } 93 | }); 94 | -------------------------------------------------------------------------------- /tests/src/curl_tests.js: -------------------------------------------------------------------------------- 1 | var global = window; 2 | 3 | module("CURL", { 4 | setup: function () { 5 | if (!global.sense) 6 | global.sense = {}; 7 | var sense = global.sense; 8 | sense.tests = {}; 9 | }, 10 | 11 | teardown: function () { 12 | sense.tests = {}; 13 | } 14 | }); 15 | 16 | var notCURLS = [ 17 | 'sldhfsljfhs', 18 | 's;kdjfsldkfj curl -XDELETE ""', 19 | '{ "hello": 1 }' 20 | ]; 21 | 22 | var CURLS = [ 23 | { 24 | "curl": "curl -XPUT 'http://localhost:9200/twitter/tweet/1' -d '{ \ 25 | \"user\" : \"kimchy\", \ 26 | \"post_date\" : \"2009-11-15T14:12:12\",\ 27 | \"message\" : \"trying out Elastic Search\"\ 28 | }'", 29 | "ret": { 30 | "server": "http://localhost:9200", 31 | "method": "PUT", 32 | "url": "/twitter/tweet/1", 33 | "data": "{ \ 34 | \"user\" : \"kimchy\", \ 35 | \"post_date\" : \"2009-11-15T14:12:12\",\ 36 | \"message\" : \"trying out Elastic Search\"\ 37 | }" 38 | } 39 | }, 40 | { 41 | "curl": "curl -XGET \"localhost/twitter/tweet/1?version=2\" -d '{ \ 42 | \"message\" : \"elasticsearch now has versioning support, double cool!\"\ 43 | }'", 44 | "ret": { 45 | "server": "http://localhost", 46 | "method": "GET", 47 | "url": "/twitter/tweet/1?version=2", 48 | "data": "{ \ 49 | \"message\" : \"elasticsearch now has versioning support, double cool!\"\ 50 | }" 51 | } 52 | }, 53 | { 54 | "curl": "curl -XPOST https://localhost/twitter/tweet/1?version=2 -d '{ \n\ 55 | \"message\" : \"elasticsearch now has versioning support, double cool!\"\n\ 56 | }'", 57 | "ret": { 58 | "server": "https://localhost", 59 | "method": "POST", 60 | "url": "/twitter/tweet/1?version=2", 61 | "data": "{ \n\ 62 | \"message\" : \"elasticsearch now has versioning support, double cool!\"\n\ 63 | }" 64 | } 65 | }, 66 | { 67 | "curl": "curl -XPOST https://localhost/twitter", 68 | "ret": { 69 | "server": "https://localhost", 70 | "method": "POST", 71 | "url": "/twitter", 72 | "data": "" 73 | } 74 | }, 75 | { 76 | "curl": "curl -X POST https://localhost/twitter/", 77 | "ret": { 78 | "server": "https://localhost", 79 | "method": "POST", 80 | "url": "/twitter/", 81 | "data": "" 82 | } 83 | }, 84 | { 85 | "curl": "curl -s -XPOST localhost:9200/missing-test -d'\n\ 86 | { \n\ 87 | \"mappings\": {\n\ 88 | }\n\ 89 | }'", 90 | "ret": { 91 | "server": "http://localhost:9200", 92 | "method": "POST", 93 | "url": "/missing-test", 94 | "data": "{ \n\ 95 | \"mappings\": {\n\ 96 | }\n\ 97 | }" 98 | } 99 | }, 100 | { 101 | "curl": "curl 'localhost:9200/missing-test/doc/_search?pretty' -d'\n\ 102 | {\n\ 103 | \"query\": {\n\ 104 | },\n\ 105 | }'", 106 | "ret": { 107 | "server": "http://localhost:9200", 108 | "method": "", 109 | "url": "/missing-test/doc/_search?pretty", 110 | "data": "{\n\ 111 | \"query\": {\n\ 112 | },\n\ 113 | }" 114 | } 115 | }, 116 | { 117 | "curl": 'curl localhost:9200/ -d"\n\ 118 | {\n\ 119 | \\"query\\": {\n\ 120 | },\n\ 121 | }"', 122 | "ret": { 123 | "server": "http://localhost:9200", 124 | "method": "", 125 | "url": "/", 126 | "data": "{\n\ 127 | \"query\": {\n\ 128 | },\n\ 129 | }" 130 | } 131 | } 132 | ]; 133 | 134 | 135 | function compareCURL(result, expected) { 136 | deepEqual(result.server, expected.server); 137 | deepEqual(result.method, expected.method); 138 | deepEqual(result.url, expected.url); 139 | deepEqual(result.data, expected.data); 140 | } 141 | 142 | for (var i = 0; i < notCURLS.length; i++) 143 | 144 | test("cURL Detection - broken strings " + i, function (c) { 145 | return function () { 146 | ok(!global.sense.curl.detectCURL(notCURLS[c]), "marked as curl while it wasn't:" + notCURLS[c]); 147 | } 148 | }(i) 149 | ); 150 | 151 | for (var i = 0; i < CURLS.length; i++) 152 | 153 | 154 | test("cURL Detection - correct strings " + i, function (c) { 155 | return function () { 156 | ok(global.sense.curl.detectCURL(CURLS[c].curl), "marked as not curl while it was:" + CURLS[c].curl); 157 | var r = global.sense.curl.parseCURL(CURLS[c].curl); 158 | compareCURL(r, CURLS[c].ret); 159 | } 160 | }(i) 161 | ); 162 | 163 | -------------------------------------------------------------------------------- /src/kb.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | var global = window; 4 | var GLOBAL_AUTOCOMPLETE_RULES = {}, ES_SCHEME_BY_ENDPOINT = {}; 5 | 6 | function escapeRegex(text) { 7 | return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 8 | } 9 | 10 | function addGlobalAutocompleteRules(parentNode, rules) { 11 | GLOBAL_AUTOCOMPLETE_RULES[parentNode] = rules; 12 | } 13 | 14 | function getGlobalAutocompleteRules() { 15 | return GLOBAL_AUTOCOMPLETE_RULES; 16 | } 17 | 18 | 19 | function addEndpointDescription(endpoint, description) { 20 | if (!description.endpoint_autocomplete) 21 | description.endpoint_autocomplete = [endpoint]; 22 | 23 | if (!description.match) { 24 | var l = $.map(description.endpoint_autocomplete, escapeRegex); 25 | description.match = "(?:" + l.join(")|(?:") + ")"; 26 | } 27 | 28 | if (typeof description.match == "string") description.match = new RegExp(description.match); 29 | 30 | var copiedDescription = {}; 31 | $.extend(copiedDescription, description); 32 | copiedDescription._id = endpoint; 33 | 34 | ES_SCHEME_BY_ENDPOINT[endpoint] = copiedDescription; 35 | } 36 | 37 | function getEndpointDescriptionByEndpoint(endpoint) { 38 | return ES_SCHEME_BY_ENDPOINT[endpoint]; 39 | } 40 | 41 | function getEndpointsForIndicesTypesAndId(indices, types, id) { 42 | var ret = []; 43 | var index_mode = "none"; 44 | if (indices && indices.length > 0) { 45 | indices = sense.mappings.expandAliases(indices); 46 | index_mode = typeof indices == "string" ? "single" : "multi"; 47 | } 48 | 49 | var type_mode = "none"; 50 | if (types && types.length > 0) type_mode = types.length > 1 ? "multi" : "single"; 51 | var id_mode = "none"; 52 | if (id && id.length > 0) id_mode = "single"; 53 | 54 | for (var endpoint in ES_SCHEME_BY_ENDPOINT) { 55 | var scheme = ES_SCHEME_BY_ENDPOINT[endpoint]; 56 | switch (scheme.indices_mode) { 57 | case "none": 58 | if (index_mode !== "none") continue; 59 | break; 60 | case "single": 61 | if (index_mode !== "single") continue; 62 | break; 63 | case "required_multi": 64 | if (index_mode === "none") continue; 65 | break; 66 | case "multi": // always good 67 | break; 68 | } 69 | switch (scheme.types_mode) { 70 | case "none": 71 | if (type_mode !== "none") continue; 72 | break; 73 | case "single": 74 | if (type_mode !== "single") continue; 75 | break; 76 | case "multi": // always good 77 | break; 78 | } 79 | 80 | switch (scheme.doc_id_mode) { 81 | case "none": 82 | if (id_mode !== "none") continue; 83 | break; 84 | case "required_single": 85 | if (id_mode === "none") continue; 86 | break; 87 | } 88 | 89 | ret.push(endpoint); 90 | } 91 | return ret; 92 | } 93 | 94 | function getEndpointDescriptionByPath(path, indices, types, id) { 95 | var endpoints = getEndpointsForIndicesTypesAndId(indices, types, id); 96 | for (var i = 0; i < endpoints.length; i++) { 97 | var scheme = ES_SCHEME_BY_ENDPOINT[endpoints[i]]; 98 | if (scheme.match.test(path || "")) return scheme; 99 | } 100 | return null; 101 | } 102 | 103 | function getEndpointAutocomplete(indices, types, id) { 104 | var ret = []; 105 | var endpoints = getEndpointsForIndicesTypesAndId(indices, types, id); 106 | for (var i = 0; i < endpoints.length; i++) { 107 | var scheme = ES_SCHEME_BY_ENDPOINT[endpoints[i]]; 108 | ret.push.apply(ret, scheme.endpoint_autocomplete); 109 | } 110 | return ret; 111 | } 112 | 113 | function clear() { 114 | ES_SCHEME_BY_ENDPOINT = {}; 115 | GLOBAL_AUTOCOMPLETE_RULES = {}; 116 | } 117 | 118 | if (!global.sense) global.sense = {}; 119 | global.sense.kb = {}; 120 | global.sense.kb.addGlobalAutocompleteRules = addGlobalAutocompleteRules; 121 | global.sense.kb.getGlobalAutocompleteRules = getGlobalAutocompleteRules; 122 | global.sense.kb.addEndpointDescription = addEndpointDescription; 123 | global.sense.kb.getEndpointAutocomplete = getEndpointAutocomplete; 124 | global.sense.kb.getEndpointDescriptionByPath = getEndpointDescriptionByPath; 125 | global.sense.kb.getEndpointDescriptionByEndpoint = getEndpointDescriptionByEndpoint; 126 | global.sense.kb.clear = clear; 127 | 128 | 129 | })(); -------------------------------------------------------------------------------- /lib/src-noconflict/theme-monokai.js: -------------------------------------------------------------------------------- 1 | /* ***** BEGIN LICENSE BLOCK ***** 2 | * Distributed under the BSD license: 3 | * 4 | * Copyright (c) 2010, Ajax.org B.V. 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Ajax.org B.V. nor the 15 | * names of its contributors may be used to endorse or promote products 16 | * derived from this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * ***** END LICENSE BLOCK ***** */ 30 | 31 | ace.define('ace/theme/monokai', ['require', 'exports', 'module' , 'ace/lib/dom'], function(require, exports, module) { 32 | 33 | exports.isDark = true; 34 | exports.cssClass = "ace-monokai"; 35 | exports.cssText = ".ace-monokai .ace_gutter {\ 36 | background: #2f3129;\ 37 | color: #f1f1f1\ 38 | }\ 39 | .ace-monokai .ace_print-margin {\ 40 | width: 1px;\ 41 | background: #555651\ 42 | }\ 43 | .ace-monokai .ace_scroller {\ 44 | background-color: #272822\ 45 | }\ 46 | .ace-monokai .ace_text-layer {\ 47 | color: #F8F8F2\ 48 | }\ 49 | .ace-monokai .ace_cursor {\ 50 | border-left: 2px solid #F8F8F0\ 51 | }\ 52 | .ace-monokai .ace_overwrite-cursors .ace_cursor {\ 53 | border-left: 0px;\ 54 | border-bottom: 1px solid #F8F8F0\ 55 | }\ 56 | .ace-monokai .ace_marker-layer .ace_selection {\ 57 | background: #49483E\ 58 | }\ 59 | .ace-monokai.ace_multiselect .ace_selection.ace_start {\ 60 | box-shadow: 0 0 3px 0px #272822;\ 61 | border-radius: 2px\ 62 | }\ 63 | .ace-monokai .ace_marker-layer .ace_step {\ 64 | background: rgb(102, 82, 0)\ 65 | }\ 66 | .ace-monokai .ace_marker-layer .ace_bracket {\ 67 | margin: -1px 0 0 -1px;\ 68 | border: 1px solid #49483E\ 69 | }\ 70 | .ace-monokai .ace_marker-layer .ace_active-line {\ 71 | background: #202020\ 72 | }\ 73 | .ace-monokai .ace_gutter-active-line {\ 74 | background-color: #272727\ 75 | }\ 76 | .ace-monokai .ace_marker-layer .ace_selected-word {\ 77 | border: 1px solid #49483E\ 78 | }\ 79 | .ace-monokai .ace_invisible {\ 80 | color: #49483E\ 81 | }\ 82 | .ace-monokai .ace_entity.ace_name.ace_tag,\ 83 | .ace-monokai .ace_keyword,\ 84 | .ace-monokai .ace_meta,\ 85 | .ace-monokai .ace_storage {\ 86 | color: #F92672\ 87 | }\ 88 | .ace-monokai .ace_constant.ace_character,\ 89 | .ace-monokai .ace_constant.ace_language,\ 90 | .ace-monokai .ace_constant.ace_numeric,\ 91 | .ace-monokai .ace_constant.ace_other {\ 92 | color: #AE81FF\ 93 | }\ 94 | .ace-monokai .ace_invalid {\ 95 | color: #F8F8F0;\ 96 | background-color: #F92672\ 97 | }\ 98 | .ace-monokai .ace_invalid.ace_deprecated {\ 99 | color: #F8F8F0;\ 100 | background-color: #AE81FF\ 101 | }\ 102 | .ace-monokai .ace_support.ace_constant,\ 103 | .ace-monokai .ace_support.ace_function {\ 104 | color: #66D9EF\ 105 | }\ 106 | .ace-monokai .ace_fold {\ 107 | background-color: #A6E22E;\ 108 | border-color: #F8F8F2\ 109 | }\ 110 | .ace-monokai .ace_storage.ace_type,\ 111 | .ace-monokai .ace_support.ace_class,\ 112 | .ace-monokai .ace_support.ace_type {\ 113 | font-style: italic;\ 114 | color: #66D9EF\ 115 | }\ 116 | .ace-monokai .ace_entity.ace_name.ace_function,\ 117 | .ace-monokai .ace_entity.ace_other.ace_attribute-name,\ 118 | .ace-monokai .ace_variable {\ 119 | color: #A6E22E\ 120 | }\ 121 | .ace-monokai .ace_variable.ace_parameter {\ 122 | font-style: italic;\ 123 | color: #FD971F\ 124 | }\ 125 | .ace-monokai .ace_string {\ 126 | color: #E6DB74\ 127 | }\ 128 | .ace-monokai .ace_comment {\ 129 | color: #75715E\ 130 | }\ 131 | .ace-monokai .ace_markup.ace_underline {\ 132 | text-decoration: underline\ 133 | }\ 134 | .ace-monokai .ace_indent-guide {\ 135 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNQ11D6z7Bq1ar/ABCKBG6g04U2AAAAAElFTkSuQmCC) right repeat-y\ 136 | }"; 137 | 138 | var dom = require("../lib/dom"); 139 | dom.importCssString(exports.cssText, exports.cssClass); 140 | }); 141 | -------------------------------------------------------------------------------- /sense.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | overflow: hidden; 4 | } 5 | 6 | .pull-right-btn { 7 | float: right; 8 | margin-right: 5px; 9 | } 10 | 11 | .pull-right-btn:first-of-type { 12 | margin-right: 0; 13 | } 14 | 15 | #es_method { 16 | width: 100px; 17 | } 18 | 19 | #editor_actions { 20 | position: absolute; 21 | top: 47px; 22 | right: 100%; 23 | margin-right: -481px; 24 | z-index: 100; 25 | } 26 | 27 | #editor_actions > .btn-group > a { 28 | padding: 2px 4px; 29 | } 30 | 31 | #editor_actions > .btn-group > a:hover { 32 | padding: 2px 4px; 33 | text-decoration: none; 34 | } 35 | 36 | #request_wrench { 37 | color: rgb(51, 51, 51); 38 | } 39 | 40 | #send { 41 | color: rgb(112, 186, 86); 42 | } 43 | 44 | .editor_position { 45 | position: absolute; 46 | top: 50px; 47 | bottom: 0; 48 | left: 0; 49 | width: 484px; 50 | } 51 | 52 | .overlay { 53 | background-color: #000; 54 | opacity: 0.5; 55 | z-index: 100; 56 | } 57 | 58 | #output { 59 | position: absolute; 60 | top: 50px; 61 | bottom: 0; 62 | left: 484px; 63 | right: 0; 64 | min-width: 700px; 65 | } 66 | 67 | #autocomplete { 68 | visibility: hidden; 69 | position: absolute; 70 | z-index: 1000; 71 | margin-top: 22px; 72 | /*font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;*/ 73 | /*font-size: 12px;*/ 74 | /*max-height: 100px;*/ 75 | /*overflow-y: auto;*/ 76 | /* prevent horizontal scrollbar */ 77 | /*overflow-x: hidden;*/ 78 | } 79 | 80 | .ui-menu { 81 | background-color: white; 82 | border: 1px solid #CCC 83 | } 84 | 85 | .ui-state-focus { 86 | color: white; 87 | background-color: #08C; 88 | margin: auto !important; 89 | } 90 | 91 | #history_popup { 92 | width: 90%; 93 | margin-left: -45%; 94 | height: 90%; 95 | top: 5%; 96 | margin-top: 0; 97 | } 98 | 99 | #history_popup .modal-body { 100 | } 101 | 102 | #history_popup .modal-header { 103 | position: absolute; 104 | top: 0; 105 | left: 0; 106 | right: 0; 107 | } 108 | 109 | #history_popup .modal-footer { 110 | position: absolute; 111 | bottom: 0; 112 | left: 0; 113 | right: 0; 114 | } 115 | 116 | #history_popup .nav { 117 | position: absolute; 118 | width: 400px; 119 | left: 0; 120 | top: 60px; 121 | bottom: 70px; 122 | overflow-y: auto; 123 | } 124 | 125 | #example_editor_container { 126 | width: 100%; 127 | height: 10em; 128 | margin: 10px 0; 129 | position: relative; 130 | } 131 | 132 | #example_editor_container #example_editor { 133 | top: 0; 134 | bottom: 0; 135 | right: 0; 136 | left: 0; 137 | } 138 | 139 | .icon-chevron-right { 140 | position: absolute; 141 | right: 10px; 142 | margin-top: 2px; 143 | margin-right: -6px; 144 | opacity: .25; 145 | } 146 | 147 | #history_popup .nav a { 148 | display: block; 149 | margin: 0 0 -1px; 150 | padding: 8px 14px; 151 | border: 1px solid #e5e5e5; 152 | white-space: nowrap; 153 | position: relative; 154 | overflow: hidden; 155 | } 156 | 157 | #history_popup .nav li:first-child > a { 158 | -webkit-border-radius: 6px 6px 0 0; 159 | -moz-border-radius: 6px 6px 0 0; 160 | border-radius: 6px 6px 0 0; 161 | } 162 | 163 | #history_popup .nav li:last-child > a { 164 | -webkit-border-radius: 0 0 6px 6px; 165 | -moz-border-radius: 0 0 6px 6px; 166 | border-radius: 0 0 6px 6px; 167 | } 168 | 169 | #history_viewer { 170 | position: absolute; 171 | left: 430px; 172 | right: 0; 173 | margin-right: 9px; 174 | top: 60px; 175 | bottom: 70px; 176 | } 177 | 178 | #welcome_popup { 179 | top: 40%; 180 | } 181 | 182 | #welcome_popup .modal-body { 183 | max-height: 600px; 184 | } 185 | 186 | .ui-autocomplete { 187 | z-index: 400 !important; 188 | } 189 | 190 | .out_of_screen { 191 | width: 1px; 192 | height: 1px; 193 | overflow: hidden; 194 | margin-left: -1000px; 195 | } 196 | 197 | .ace_url { 198 | color: #0088cc; 199 | } 200 | 201 | .ace_url.ace_param { 202 | color: rgb(49, 132, 149); 203 | } 204 | 205 | .ace_url.ace_value { 206 | color: rgb(3, 106, 7); 207 | } 208 | 209 | .ace_method { 210 | color: rgb(197, 6, 11); 211 | } 212 | 213 | .ace_snippet-marker { 214 | box-sizing: border-box; 215 | background: rgba(194, 193, 208, 0.20); 216 | /*border: 1px dotted rgba(211, 208, 235, 0.62); */ 217 | position: absolute; 218 | width: 100% !important; 219 | } 220 | 221 | .ace_snippet-marker.ace_start { 222 | border-top: dotted 1px rgba(194, 193, 208, 0.80); 223 | } 224 | 225 | .ace_snippet-marker.ace_start + .ace_snippet-marker { 226 | border-bottom: dotted 1px rgba(194, 193, 208, 0.80); 227 | } 228 | 229 | .ui-resizable-e { 230 | cursor: ew-resize; 231 | width: 10px; 232 | right: -5px; 233 | top: 0; 234 | bottom: 0; 235 | background-color: transparent; 236 | position: absolute; 237 | z-index: 50 !important; 238 | } 239 | 240 | .ui-resizable-e:hover { 241 | background-color: rgba(194, 193, 208, 0.80); 242 | } 243 | 244 | .ui-resizable-e.active { 245 | background-color: rgba(194, 193, 208, 100); 246 | } -------------------------------------------------------------------------------- /tests/src/utils_tests.js: -------------------------------------------------------------------------------- 1 | var sense = window.sense; 2 | var utils = sense.utils; 3 | 4 | module("Utils", { 5 | setup: function () { 6 | sense.tests = {}; 7 | sense.tests.editor_div = $('
').appendTo($('body')); 8 | sense.tests.editor = ace.edit("editor"); 9 | ace.require("ace/mode/sense"); 10 | sense.tests.editor.getSession().setMode("ace/mode/sense"); 11 | sense.tests.editor.getSession().setValue("hello"); 12 | 13 | }, 14 | 15 | teardown: function () { 16 | sense.tests.editor_div.remove(); 17 | sense.tests = {}; 18 | } 19 | }); 20 | 21 | var testCount = 0; 22 | 23 | function utils_test(name, prefix, data, test) { 24 | if (data && typeof data != "string") data = JSON.stringify(data, null, 3); 25 | if (data) { 26 | if (prefix) data = prefix + "\n" + data; 27 | } else { 28 | data = prefix; 29 | } 30 | 31 | QUnit.asyncTest("Utils test " + testCount++ + ":" + name, 32 | function () { 33 | var editor = sense.tests.editor; 34 | utils.updateEditorAndCallWhenUpdated(data, editor, function () { 35 | test(editor); 36 | start(); 37 | }); 38 | 39 | }); 40 | } 41 | 42 | var simple_request = 43 | { prefix: 'POST _search', 44 | data: '{\n' + 45 | ' "query": { "match_all": {} }\n' + 46 | '}' 47 | }; 48 | 49 | var single_line_request = 50 | { prefix: 'POST _search', 51 | data: '{ "query": { "match_all": {} } }' 52 | }; 53 | 54 | 55 | utils_test("simple request range", simple_request.prefix, simple_request.data, 56 | function (editor) { 57 | var range = utils.getCurrentRequestRange(editor); 58 | var expected = new (ace.require("ace/range").Range)( 59 | 0, 0, 60 | 3, 1 61 | ); 62 | deepEqual(range, expected); 63 | } 64 | ); 65 | 66 | utils_test("single line request range", single_line_request.prefix, single_line_request.data, 67 | function (editor) { 68 | var range = utils.getCurrentRequestRange(editor); 69 | var expected = new (ace.require("ace/range").Range)( 70 | 0, 0, 71 | 1, 32 72 | ); 73 | deepEqual(range, expected); 74 | } 75 | ); 76 | 77 | utils_test("simple request data", simple_request.prefix, simple_request.data, 78 | function (editor) { 79 | var request = utils.getCurrentRequest(editor); 80 | var expected = { 81 | method: "POST", 82 | url: "_search", 83 | data: [simple_request.data] 84 | }; 85 | 86 | deepEqual(request, expected); 87 | } 88 | ); 89 | 90 | utils_test("single line request data", single_line_request.prefix, single_line_request.data, 91 | function (editor) { 92 | var request = utils.getCurrentRequest(editor); 93 | var expected = { 94 | method: "POST", 95 | url: "_search", 96 | data: [single_line_request.data] 97 | }; 98 | 99 | deepEqual(request, expected); 100 | } 101 | ); 102 | 103 | 104 | var get_request_no_data = 105 | { prefix: 'GET _stats' 106 | }; 107 | 108 | utils_test("request with no data followed by a new line", get_request_no_data.prefix, "\n", 109 | function (editor) { 110 | var range = utils.getCurrentRequestRange(editor); 111 | var expected = new (ace.require("ace/range").Range)( 112 | 0, 0, 113 | 0, 10 114 | ); 115 | deepEqual(range, expected); 116 | } 117 | ); 118 | 119 | utils_test("request with no data followed by a new line (data)", get_request_no_data.prefix, "\n", 120 | function (editor) { 121 | var range = utils.getCurrentRequest(editor); 122 | var expected = { 123 | method: "GET", 124 | url: "_stats", 125 | data: [] 126 | }; 127 | 128 | deepEqual(range, expected); 129 | } 130 | ); 131 | 132 | 133 | utils_test("request with no data", get_request_no_data.prefix, get_request_no_data.data, 134 | function (editor) { 135 | var range = utils.getCurrentRequestRange(editor); 136 | var expected = new (ace.require("ace/range").Range)( 137 | 0, 0, 138 | 0, 10 139 | ); 140 | deepEqual(range, expected); 141 | } 142 | ); 143 | 144 | utils_test("request with no data (data)", get_request_no_data.prefix, get_request_no_data.data, 145 | function (editor) { 146 | var range = utils.getCurrentRequest(editor); 147 | var expected = { 148 | method: "GET", 149 | url: "_stats", 150 | data: [] 151 | }; 152 | 153 | deepEqual(range, expected); 154 | } 155 | ); 156 | 157 | 158 | var multi_doc_request = 159 | { prefix: 'POST _bulk', 160 | data_as_array: ['{ "index": { "_index": "index", "_type":"type" } }', 161 | '{ "field": 1 }' 162 | ] 163 | }; 164 | multi_doc_request.data = multi_doc_request.data_as_array.join("\n"); 165 | 166 | utils_test("multi doc request range", multi_doc_request.prefix, multi_doc_request.data, 167 | function (editor) { 168 | var range = utils.getCurrentRequestRange(editor); 169 | var expected = new (ace.require("ace/range").Range)( 170 | 0, 0, 171 | 2, 14 172 | ); 173 | deepEqual(range, expected); 174 | } 175 | ); 176 | 177 | utils_test("multi doc request data", multi_doc_request.prefix, multi_doc_request.data, 178 | function (editor) { 179 | var request = utils.getCurrentRequest(editor); 180 | var expected = { 181 | method: "POST", 182 | url: "_bulk", 183 | data: multi_doc_request.data_as_array 184 | }; 185 | 186 | deepEqual(request, expected); 187 | } 188 | ); 189 | -------------------------------------------------------------------------------- /tests/src/mapping_tests.js: -------------------------------------------------------------------------------- 1 | var global = window; 2 | 3 | module("Mappings", { 4 | setup: function () { 5 | if (!global.sense) 6 | global.sense = {}; 7 | var sense = global.sense; 8 | sense.tests = {}; 9 | }, 10 | 11 | teardown: function () { 12 | sense.tests = {}; 13 | } 14 | }); 15 | 16 | 17 | test("Multi fields", function () { 18 | global.sense.mappings.loadMappings({ 19 | "index": { 20 | "tweet": { 21 | "properties": { 22 | "first_name": { 23 | "type": "multi_field", 24 | "path": "just_name", 25 | "fields": { 26 | "first_name": {"type": "string", "index": "analyzed"}, 27 | "any_name": {"type": "string", "index": "analyzed"} 28 | } 29 | }, 30 | "last_name": { 31 | "type": "multi_field", 32 | "path": "just_name", 33 | "fields": { 34 | "last_name": {"type": "string", "index": "analyzed"}, 35 | "any_name": {"type": "string", "index": "analyzed"} 36 | } 37 | } 38 | } 39 | }} 40 | }); 41 | 42 | deepEqual(global.sense.mappings.getFields("index").sort(), ["any_name", "first_name", "last_name" ]); 43 | }); 44 | 45 | test("Simple fields", function () { 46 | global.sense.mappings.loadMappings({ 47 | "index": { 48 | "tweet": { 49 | "properties": { 50 | "str": { 51 | "type": "string" 52 | }, 53 | "number": { 54 | "type": "int" 55 | } 56 | } 57 | }} 58 | }); 59 | 60 | deepEqual(global.sense.mappings.getFields("index").sort(), ["number", "str" ]); 61 | }); 62 | 63 | 64 | test("Nested fields", function () { 65 | global.sense.mappings.loadMappings({ 66 | "index": { 67 | "tweet": { 68 | "properties": { 69 | "person": { 70 | "type": "object", 71 | "properties": { 72 | "name": { 73 | "properties": { 74 | "first_name": {"type": "string"}, 75 | "last_name": {"type": "string"} 76 | } 77 | }, 78 | "sid": {"type": "string", "index": "not_analyzed"} 79 | } 80 | }, 81 | "message": {"type": "string"} 82 | } 83 | } 84 | }}); 85 | 86 | deepEqual(global.sense.mappings.getFields("index", ["tweet"]).sort(), 87 | ["message", "person.name.first_name", "person.name.last_name", "person.sid" ]); 88 | }); 89 | 90 | test("Enabled fields", function () { 91 | global.sense.mappings.loadMappings({ 92 | "index": { 93 | "tweet": { 94 | "properties": { 95 | "person": { 96 | "type": "object", 97 | "properties": { 98 | "name": { 99 | "type": "object", 100 | "enabled": false 101 | }, 102 | "sid": {"type": "string", "index": "not_analyzed"} 103 | } 104 | }, 105 | "message": {"type": "string"} 106 | } 107 | } 108 | } 109 | }); 110 | 111 | deepEqual(global.sense.mappings.getFields("index", ["tweet"]).sort(), 112 | ["message", "person.sid" ]); 113 | }); 114 | 115 | 116 | test("Path tests", function () { 117 | global.sense.mappings.loadMappings({ 118 | "index": { 119 | "person": { 120 | "properties": { 121 | "name1": { 122 | "type": "object", 123 | "path": "just_name", 124 | "properties": { 125 | "first1": {"type": "string"}, 126 | "last1": {"type": "string", "index_name": "i_last_1"} 127 | } 128 | }, 129 | "name2": { 130 | "type": "object", 131 | "path": "full", 132 | "properties": { 133 | "first2": {"type": "string"}, 134 | "last2": {"type": "string", "index_name": "i_last_2"} 135 | } 136 | } 137 | } 138 | } 139 | } 140 | }); 141 | 142 | deepEqual(global.sense.mappings.getFields().sort(), 143 | ["first1", "i_last_1", "name2.first2", "name2.i_last_2" ]); 144 | }); 145 | 146 | test("Use index_name tests", function () { 147 | global.sense.mappings.loadMappings({ 148 | "index": { 149 | "person": { 150 | "properties": { 151 | "last1": {"type": "string", "index_name": "i_last_1"} 152 | } 153 | } 154 | } 155 | }); 156 | 157 | deepEqual(global.sense.mappings.getFields().sort(), 158 | [ "i_last_1" ]); 159 | }); 160 | 161 | test("Aliases", function () { 162 | global.sense.mappings.loadAliases({ 163 | "test_index1": { 164 | "aliases": { 165 | "alias1": {} 166 | } 167 | }, 168 | "test_index2": { 169 | "aliases": { 170 | "alias2": { 171 | "filter": { 172 | "term": { 173 | "FIELD": "VALUE" 174 | } 175 | } 176 | }, 177 | "alias1": {} 178 | } 179 | } 180 | }); 181 | global.sense.mappings.loadMappings({ 182 | "test_index1": { 183 | "type1": { 184 | "properties": { 185 | "last1": {"type": "string", "index_name": "i_last_1"} 186 | } 187 | } 188 | }, 189 | "test_index2": { 190 | "type2": { 191 | "properties": { 192 | "last1": {"type": "string", "index_name": "i_last_1"} 193 | } 194 | } 195 | } 196 | }); 197 | 198 | deepEqual(global.sense.mappings.getIndices().sort(), 199 | [ "_all", "alias1", "alias2", "test_index1", "test_index2" ] 200 | ); 201 | deepEqual(global.sense.mappings.getIndices(false).sort(), 202 | ["test_index1", "test_index2" ] 203 | ); 204 | deepEqual(global.sense.mappings.expandAliases(["alias1", "test_index2"]).sort(), 205 | ["test_index1", "test_index2" ] 206 | ); 207 | deepEqual(global.sense.mappings.expandAliases("alias2"), "test_index2"); 208 | }); 209 | 210 | -------------------------------------------------------------------------------- /tests/lib/qunit-1.10.0.css: -------------------------------------------------------------------------------- 1 | /** 2 | * QUnit v1.10.0 - A JavaScript Unit Testing Framework 3 | * 4 | * http://qunitjs.com 5 | * 6 | * Copyright 2012 jQuery Foundation and other contributors 7 | * Released under the MIT license. 8 | * http://jquery.org/license 9 | */ 10 | 11 | /** Font Family and Sizes */ 12 | 13 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { 14 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; 15 | } 16 | 17 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { 18 | font-size: small; 19 | } 20 | 21 | #qunit-tests { 22 | font-size: smaller; 23 | } 24 | 25 | /** Resets */ 26 | 27 | #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { 28 | margin: 0; 29 | padding: 0; 30 | } 31 | 32 | /** Header */ 33 | 34 | #qunit-header { 35 | padding: 0.5em 0 0.5em 1em; 36 | 37 | color: #8699a4; 38 | background-color: #0d3349; 39 | 40 | font-size: 1.5em; 41 | line-height: 1em; 42 | font-weight: normal; 43 | 44 | border-radius: 5px 5px 0 0; 45 | -moz-border-radius: 5px 5px 0 0; 46 | -webkit-border-top-right-radius: 5px; 47 | -webkit-border-top-left-radius: 5px; 48 | } 49 | 50 | #qunit-header a { 51 | text-decoration: none; 52 | color: #c2ccd1; 53 | } 54 | 55 | #qunit-header a:hover, 56 | #qunit-header a:focus { 57 | color: #fff; 58 | } 59 | 60 | #qunit-testrunner-toolbar label { 61 | display: inline-block; 62 | padding: 0 .5em 0 .1em; 63 | } 64 | 65 | #qunit-banner { 66 | height: 5px; 67 | } 68 | 69 | #qunit-testrunner-toolbar { 70 | padding: 0.5em 0 0.5em 2em; 71 | color: #5E740B; 72 | background-color: #eee; 73 | overflow: hidden; 74 | } 75 | 76 | #qunit-userAgent { 77 | padding: 0.5em 0 0.5em 2.5em; 78 | background-color: #2b81af; 79 | color: #fff; 80 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 81 | } 82 | 83 | #qunit-modulefilter-container { 84 | float: right; 85 | } 86 | 87 | /** Tests: Pass/Fail */ 88 | 89 | #qunit-tests { 90 | list-style-position: inside; 91 | } 92 | 93 | #qunit-tests li { 94 | padding: 0.4em 0.5em 0.4em 2.5em; 95 | border-bottom: 1px solid #fff; 96 | list-style-position: inside; 97 | } 98 | 99 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { 100 | display: none; 101 | } 102 | 103 | #qunit-tests li strong { 104 | cursor: pointer; 105 | } 106 | 107 | #qunit-tests li a { 108 | padding: 0.5em; 109 | color: #c2ccd1; 110 | text-decoration: none; 111 | } 112 | 113 | #qunit-tests li a:hover, 114 | #qunit-tests li a:focus { 115 | color: #000; 116 | } 117 | 118 | #qunit-tests ol { 119 | margin-top: 0.5em; 120 | padding: 0.5em; 121 | 122 | background-color: #fff; 123 | 124 | border-radius: 5px; 125 | -moz-border-radius: 5px; 126 | -webkit-border-radius: 5px; 127 | } 128 | 129 | #qunit-tests table { 130 | border-collapse: collapse; 131 | margin-top: .2em; 132 | } 133 | 134 | #qunit-tests th { 135 | text-align: right; 136 | vertical-align: top; 137 | padding: 0 .5em 0 0; 138 | } 139 | 140 | #qunit-tests td { 141 | vertical-align: top; 142 | } 143 | 144 | #qunit-tests pre { 145 | margin: 0; 146 | white-space: pre-wrap; 147 | word-wrap: break-word; 148 | } 149 | 150 | #qunit-tests del { 151 | background-color: #e0f2be; 152 | color: #374e0c; 153 | text-decoration: none; 154 | } 155 | 156 | #qunit-tests ins { 157 | background-color: #ffcaca; 158 | color: #500; 159 | text-decoration: none; 160 | } 161 | 162 | /*** Test Counts */ 163 | 164 | #qunit-tests b.counts { 165 | color: black; 166 | } 167 | 168 | #qunit-tests b.passed { 169 | color: #5E740B; 170 | } 171 | 172 | #qunit-tests b.failed { 173 | color: #710909; 174 | } 175 | 176 | #qunit-tests li li { 177 | padding: 5px; 178 | background-color: #fff; 179 | border-bottom: none; 180 | list-style-position: inside; 181 | } 182 | 183 | /*** Passing Styles */ 184 | 185 | #qunit-tests li li.pass { 186 | color: #3c510c; 187 | background-color: #fff; 188 | border-left: 10px solid #C6E746; 189 | } 190 | 191 | #qunit-tests .pass { 192 | color: #528CE0; 193 | background-color: #D2E0E6; 194 | } 195 | 196 | #qunit-tests .pass .test-name { 197 | color: #366097; 198 | } 199 | 200 | #qunit-tests .pass .test-actual, 201 | #qunit-tests .pass .test-expected { 202 | color: #999999; 203 | } 204 | 205 | #qunit-banner.qunit-pass { 206 | background-color: #C6E746; 207 | } 208 | 209 | /*** Failing Styles */ 210 | 211 | #qunit-tests li li.fail { 212 | color: #710909; 213 | background-color: #fff; 214 | border-left: 10px solid #EE5757; 215 | white-space: pre; 216 | } 217 | 218 | #qunit-tests > li:last-child { 219 | border-radius: 0 0 5px 5px; 220 | -moz-border-radius: 0 0 5px 5px; 221 | -webkit-border-bottom-right-radius: 5px; 222 | -webkit-border-bottom-left-radius: 5px; 223 | } 224 | 225 | #qunit-tests .fail { 226 | color: #000000; 227 | background-color: #EE5757; 228 | } 229 | 230 | #qunit-tests .fail .test-name, 231 | #qunit-tests .fail .module-name { 232 | color: #000000; 233 | } 234 | 235 | #qunit-tests .fail .test-actual { 236 | color: #EE5757; 237 | } 238 | 239 | #qunit-tests .fail .test-expected { 240 | color: green; 241 | } 242 | 243 | #qunit-banner.qunit-fail { 244 | background-color: #EE5757; 245 | } 246 | 247 | /** Result */ 248 | 249 | #qunit-testresult { 250 | padding: 0.5em 0.5em 0.5em 2.5em; 251 | 252 | color: #2b81af; 253 | background-color: #D2E0E6; 254 | 255 | border-bottom: 1px solid white; 256 | } 257 | 258 | #qunit-testresult .module-name { 259 | font-weight: bold; 260 | } 261 | 262 | /** Fixture */ 263 | 264 | #qunit-fixture { 265 | position: absolute; 266 | top: -10000px; 267 | left: -10000px; 268 | width: 1000px; 269 | height: 1000px; 270 | } 271 | -------------------------------------------------------------------------------- /kb/filter.js: -------------------------------------------------------------------------------- 1 | sense.kb.addGlobalAutocompleteRules("filter", { 2 | and: { 3 | __template: { 4 | filters: [ 5 | {} 6 | ] 7 | }, 8 | filters: [ 9 | { __scope_link: ".filter" } 10 | ], 11 | _cache: {__one_of: [ false, true ]} 12 | }, 13 | bool: { 14 | must: [ 15 | { __scope_link: ".filter"} 16 | ], 17 | must_not: [ 18 | { __scope_link: ".filter"} 19 | ], 20 | should: [ 21 | { __scope_link: ".filter"} 22 | ], 23 | _cache: {__one_of: [ false, true ]} 24 | }, 25 | exists: { 26 | __template: { "FIELD": "VALUE"}, 27 | "$FIELD$": "" 28 | }, 29 | ids: { 30 | __template: { "values": ["ID"] }, 31 | "type": "$TYPE$", 32 | "values": [""] 33 | }, 34 | limit: { 35 | __template: { value: 100}, 36 | value: 100 37 | }, 38 | type: { 39 | __template: { value: "TYPE"}, 40 | value: "$TYPE$" 41 | }, 42 | geo_bounding_box: { 43 | __template: { 44 | "FIELD": { 45 | "top_left": { 46 | "lat": 40.73, 47 | "lon": -74.1 48 | }, 49 | "bottom_right": { 50 | "lat": 40.717, 51 | "lon": -73.99 52 | } 53 | } 54 | }, 55 | 56 | "$FIELD$": { 57 | top_left: { lat: 40.73, lon: -74.1 }, 58 | bottom_right: { lat: 40.73, lon: -74.1 } 59 | }, 60 | type: { __one_of: ["memory", "indexed"]}, 61 | _cache: {__one_of: [ false, true ]} 62 | }, 63 | geo_distance: { 64 | __template: { 65 | distance: 100, 66 | distance_unit: "km", 67 | "FIELD": { lat: 40.73, lon: -74.1 } 68 | }, 69 | distance: 100, 70 | distance_unit: { __one_of: [ "km", "miles"]}, 71 | distance_type: { __one_of: [ "arc", "plane"]}, 72 | optimize_bbox: { __one_of: [ "memory", "indexed", "none"]}, 73 | "$FIELD$": { lat: 40.73, lon: -74.1 }, 74 | _cache: {__one_of: [ false, true ]} 75 | }, 76 | geo_distance_range: { 77 | __template: { 78 | from: 100, 79 | to: 200, 80 | distance_unit: "km", 81 | "FIELD": { lat: 40.73, lon: -74.1 } 82 | }, 83 | from: 100, 84 | to: 200, 85 | 86 | distance_unit: { __one_of: [ "km", "miles"]}, 87 | distance_type: { __one_of: [ "arc", "plane"]}, 88 | include_lower: { __one_of: [ true, false]}, 89 | include_upper: { __one_of: [ true, false]}, 90 | 91 | "$FIELD$": { lat: 40.73, lon: -74.1 }, 92 | _cache: {__one_of: [ false, true ]} 93 | }, 94 | geo_polygon: { 95 | __template: { 96 | "FIELD": { 97 | "points": [ 98 | { lat: 40.73, lon: -74.1 }, 99 | { lat: 40.83, lon: -75.1 } 100 | ] 101 | } 102 | }, 103 | "$FIELD$": { 104 | points: [ 105 | { lat: 40.73, lon: -74.1 } 106 | ] 107 | }, 108 | _cache: {__one_of: [ false, true ]} 109 | }, 110 | geo_shape: { 111 | __template: { 112 | "FIELD": { 113 | shape: { 114 | type: "envelope", 115 | coordinates: [ 116 | [-45, 45], 117 | [45, -45] 118 | ] 119 | }, 120 | "relation": "within" 121 | } 122 | }, 123 | "$FIELD$": { 124 | shape: { 125 | type: "", 126 | coordinates: [] 127 | }, 128 | indexed_shape: { 129 | id: "", 130 | index: "$INDEX$", 131 | type: "$TYPE$", 132 | shape_field_name: "shape" 133 | }, 134 | relation: { __one_of: ["within", "intersects", "disjoint"]} 135 | } 136 | }, 137 | has_child: { 138 | __template: { 139 | type: "TYPE", 140 | query: {} 141 | }, 142 | type: "$TYPE$", 143 | query: {}, 144 | _scope: "" 145 | }, 146 | has_parent: { 147 | __template: { 148 | type: "TYPE", 149 | query: {} 150 | }, 151 | type: "$TYPE$", 152 | query: {}, 153 | _scope: "" 154 | }, 155 | match_all: { }, 156 | missing: { 157 | __template: { 158 | field: "FIELD" 159 | }, 160 | existence: { __one_of: [ true, false]}, 161 | null_value: { __one_of: [ true, false]}, 162 | field: "$FIELD$" 163 | }, 164 | not: { 165 | __template: { 166 | filter: {} 167 | }, 168 | filter: { __scope_link: ".filter"}, 169 | _cache: { __one_of: [ true, false]} 170 | }, 171 | numeric_range: { 172 | __template: { 173 | "FIELD": { 174 | from: 10, 175 | to: 20 176 | } 177 | }, 178 | from: 1, 179 | to: 20, 180 | include_lower: { __one_of: [ true, false]}, 181 | include_upper: { __one_of: [ true, false]} 182 | }, 183 | or: { 184 | __template: { 185 | filters: [ 186 | {} 187 | ] 188 | }, 189 | filters: [ 190 | { __scope_link: ".filter" } 191 | ], 192 | _cache: {__one_of: [ false, true ]} 193 | }, 194 | prefix: { 195 | __template: { 196 | "FIELD": "VALUE" 197 | }, 198 | "$FIELD$": "", 199 | _cache: { __one_of: [ true, false]} 200 | }, 201 | query: { __scope_link: ".query"}, 202 | fquery: { 203 | __template: { 204 | query: {}, 205 | _cache: true 206 | }, 207 | query: { __scope_link: ".query"}, 208 | _cache: { __one_of: [ true, false]} 209 | }, 210 | range: { 211 | __template: { 212 | "FIELD": { 213 | from: 10, 214 | to: 20 215 | } 216 | }, 217 | from: 1, 218 | to: 20, 219 | include_lower: { __one_of: [ true, false]}, 220 | include_upper: { __one_of: [ true, false]}, 221 | _cache: { __one_of: [ false, true ]} 222 | }, 223 | script: { 224 | __template: { 225 | script: "SCRIPT", 226 | params: {} 227 | }, 228 | script: "", 229 | params: {}, 230 | _cache: { __one_of: [ true, false]} 231 | }, 232 | term: { 233 | __template: { 234 | "FIELD": "VALUE" 235 | }, 236 | "$FIELD$": "", 237 | _cache: { __one_of: [ false, true]} 238 | }, 239 | terms: { 240 | __template: { "FIELD": ["VALUE1", "VALUE2"]}, 241 | field: [ "$FIELD$"], 242 | execution: { __one_of: [ "plain", "bool", "and", "or", "bool_nocache", "and_nocache", "or_nocache"]}, 243 | _cache: { __one_of: [ false, true ]} 244 | }, 245 | nested: { 246 | __template: { 247 | path: "path_to_nested_doc", 248 | query: {} 249 | }, 250 | query: {}, 251 | path: "", 252 | _cache: { __one_of: [ true, false]}, 253 | _name: "" 254 | } 255 | }); 256 | -------------------------------------------------------------------------------- /src/history.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | var global = window; 4 | 5 | var history_viewer, history_popup; 6 | 7 | function getHistoryKeys() { 8 | var keys = []; 9 | for (var i = 0; i < localStorage.length; i++) { 10 | var k = localStorage.key(i); 11 | if (k.indexOf("hist_elem") == 0) { 12 | keys.push(k); 13 | } 14 | } 15 | 16 | keys.sort(); 17 | keys.reverse(); 18 | return keys; 19 | } 20 | 21 | function getHistory() { 22 | var hist_items = []; 23 | $.each(getHistoryKeys(), function (i, key) { 24 | hist_items.push(JSON.parse(localStorage.getItem(key))); 25 | }); 26 | 27 | return hist_items; 28 | } 29 | 30 | function getHistoricalServers() { 31 | var servers = {}; 32 | $.each(getHistory(), function (i, h) { 33 | servers[h.server] = 1; 34 | }); 35 | 36 | var server_list = []; 37 | for (var s in servers) server_list.push(s); 38 | 39 | return server_list; 40 | } 41 | 42 | function populateHistElem(hist_elem) { 43 | var s = hist_elem.method + " " + hist_elem.endpoint + "\n" + (hist_elem.data || ""); 44 | history_viewer.setValue(s); 45 | history_viewer.clearSelection(); 46 | } 47 | 48 | function applyHistElem(hist_elem) { 49 | var session = sense.editor.getSession(); 50 | var pos = sense.editor.getCursorPosition(); 51 | var prefix = ""; 52 | var suffix = "\n"; 53 | if (sense.utils.isStartRequestRow(pos.row)) { 54 | pos.column = 0; 55 | suffix += "\n"; 56 | } 57 | else if (sense.utils.isEndRequestRow(pos.row)) { 58 | var line = session.getLine(pos.row); 59 | pos.column = line.length; 60 | prefix = "\n\n"; 61 | } 62 | else if (sense.utils.isInBetweenRequestsRow(pos.row)) { 63 | pos.column = 0; 64 | } 65 | else { 66 | pos = sense.utils.nextRequestEnd(pos); 67 | prefix = "\n\n"; 68 | } 69 | 70 | var s = prefix + hist_elem.method + " " + hist_elem.endpoint; 71 | if (hist_elem.data) s += "\n" + hist_elem.data; 72 | 73 | s += suffix; 74 | 75 | session.insert(pos, s); 76 | sense.editor.clearSelection(); 77 | sense.editor.moveCursorTo(pos.row + prefix.length, 0); 78 | sense.editor.focus(); 79 | } 80 | 81 | function init() { 82 | 83 | history_popup = $("#history_popup"); 84 | 85 | 86 | history_popup.on('shown', function () { 87 | _gaq.push(['_trackEvent', "history", 'shown']); 88 | $('
No history available
').appendTo(history_popup.find(".modal-body")); 89 | 90 | history_viewer = ace.edit("history_viewer"); 91 | history_viewer.getSession().setMode("ace/mode/sense"); 92 | // history_viewer.setTheme("ace/theme/monokai"); 93 | history_viewer.getSession().setFoldStyle('markbeginend'); 94 | history_viewer.setReadOnly(true); 95 | history_viewer.renderer.setShowPrintMargin(false); 96 | sense.editor.getSession().setUseWrapMode(true); 97 | 98 | $.each(getHistory(), function (i, hist_elem) { 99 | var li = $('
  • '); 100 | var disc = hist_elem.endpoint; 101 | var date = moment(hist_elem.time); 102 | if (date.diff(moment(), "days") < -7) 103 | disc += " (" + date.format("MMM D") + ")"; 104 | else 105 | disc += " (" + date.fromNow() + ")"; 106 | 107 | li.find("span").text(disc); 108 | li.attr("title", disc); 109 | 110 | li.find("a").click(function () { 111 | history_popup.find('.modal-body .nav li').removeClass("active"); 112 | li.addClass("active"); 113 | populateHistElem(hist_elem); 114 | return false; 115 | }); 116 | 117 | li.dblclick(function () { 118 | li.addClass("active"); 119 | history_popup.find(".btn-primary").click(); 120 | }); 121 | 122 | li.hover(function () { 123 | populateHistElem(hist_elem); 124 | return false; 125 | }, function () { 126 | history_popup.find(".modal-body .nav li.active a").click(); 127 | }); 128 | 129 | li.bind('apply', function () { 130 | _gaq.push(['_trackEvent', "history", 'applied']); 131 | applyHistElem(hist_elem); 132 | }); 133 | 134 | 135 | li.appendTo(history_popup.find(".modal-body .nav")); 136 | }); 137 | 138 | history_popup.find(".modal-body .nav li:first a").click(); 139 | 140 | }); 141 | 142 | history_popup.on('hidden', function () { 143 | history_popup.find('.modal-body #history_viewer').remove(); 144 | history_popup.find('.modal-body .nav li').remove(); 145 | history_viewer = null; 146 | }); 147 | 148 | history_popup.find(".btn-primary").click(function () { 149 | history_popup.find(".modal-body .nav li.active").trigger("apply"); 150 | }); 151 | 152 | history_popup.find("#hist_clear").click(function () { 153 | var keys = getHistoryKeys(); 154 | $.each(keys, function (i, k) { 155 | localStorage.removeItem(k); 156 | }); 157 | history_popup.find(".modal-body .nav").html(""); 158 | history_viewer.getSession().setValue("No history available"); 159 | }) 160 | 161 | } 162 | 163 | function addToHistory(server, endpoint, method, data) { 164 | var keys = getHistoryKeys(); 165 | keys.splice(0, 500); // only maintain most recent X; 166 | $.each(keys, function (i, k) { 167 | localStorage.removeItem(k); 168 | }); 169 | 170 | var timestamp = new Date().getTime(); 171 | var k = "hist_elem_" + timestamp; 172 | localStorage.setItem(k, JSON.stringify( 173 | { 'time': timestamp, 'server': server, 'endpoint': endpoint, 'method': method, 'data': data })); 174 | } 175 | 176 | function saveCurrentEditorState(server, content) { 177 | var timestamp = new Date().getTime(); 178 | localStorage.setItem("editor_state", JSON.stringify( 179 | { 'time': timestamp, 'server': server, 'content': content })); 180 | 181 | } 182 | 183 | function getSavedEditorState(server, content) { 184 | return JSON.parse(localStorage.getItem("editor_state")); 185 | } 186 | 187 | global.sense.history = { 188 | init: init, 189 | addToHistory: addToHistory, 190 | getHistoricalServers: getHistoricalServers, 191 | saveCurrentEditorState: saveCurrentEditorState, 192 | getSavedEditorState: getSavedEditorState 193 | }; 194 | 195 | })(); 196 | 197 | 198 | 199 | 200 | 201 | -------------------------------------------------------------------------------- /tests/src/tokenization_tests.js: -------------------------------------------------------------------------------- 1 | var sense = window.sense; 2 | var utils = sense.utils; 3 | 4 | module("Tokenization", { 5 | setup: function () { 6 | 7 | sense.tests = {}; 8 | sense.tests.editor_div = $('
    ').appendTo($('body')); 9 | sense.tests.editor = ace.edit("editor"); 10 | ace.require("ace/mode/sense"); 11 | sense.tests.editor.getSession().setMode("ace/mode/sense"); 12 | sense.tests.editor.getSession().setValue("hello"); 13 | 14 | }, 15 | 16 | teardown: function () { 17 | sense.tests.editor_div.remove(); 18 | sense.tests = {}; 19 | } 20 | }); 21 | 22 | function tokensAsList(editor) { 23 | var iter = new (ace.require("ace/token_iterator").TokenIterator)(editor.getSession(), 0, 0); 24 | var ret = []; 25 | var t = iter.getCurrentToken(); 26 | if (utils.isEmptyToken(t)) t = utils.nextNonEmptyToken(iter); 27 | while (t) { 28 | ret.push({ value: t.value, type: t.type }); 29 | t = utils.nextNonEmptyToken(iter); 30 | } 31 | 32 | return ret; 33 | } 34 | 35 | var testCount = 0; 36 | 37 | function token_test(token_list, prefix, data) { 38 | if (data && typeof data != "string") data = JSON.stringify(data, null, 3); 39 | if (data) { 40 | if (prefix) data = prefix + "\n" + data; 41 | } else { 42 | data = prefix; 43 | } 44 | 45 | QUnit.asyncTest("Token test " + testCount++ + " prefix: " + prefix, function () { 46 | var editor = sense.tests.editor; 47 | 48 | utils.updateEditorAndCallWhenUpdated(data, editor, function () { 49 | var tokens = tokensAsList(editor); 50 | var normTokenList = []; 51 | for (var i = 0; i < token_list.length; i++) { 52 | normTokenList.push({ type: token_list[i++], value: token_list[i] }); 53 | } 54 | 55 | deepEqual(tokens, normTokenList, "Doc:\n" + data); 56 | start(); 57 | }); 58 | 59 | }); 60 | } 61 | 62 | token_test( 63 | [ "method", "GET", "url.endpoint", "_search" ], 64 | "GET _search" 65 | ); 66 | 67 | token_test( 68 | [ "method", "GET", "url.slash", "/", "url.endpoint", "_search" ], 69 | "GET /_search" 70 | ); 71 | 72 | 73 | token_test( 74 | [ "method", "GET", "url.endpoint", "_cluster", "url.slash", "/", "url.part" , "nodes" ], 75 | "GET _cluster/nodes" 76 | ); 77 | 78 | token_test( 79 | [ "method", "GET", "url.slash", "/", "url.endpoint", "_cluster", "url.slash", "/", "url.part" , "nodes" ], 80 | "GET /_cluster/nodes" 81 | ); 82 | 83 | 84 | token_test( 85 | [ "method", "GET", "url.index", "index", "url.slash", "/", "url.endpoint", "_search" ], 86 | "GET index/_search" 87 | ); 88 | 89 | token_test( 90 | [ "method", "GET", "url.index", "index" ], 91 | "GET index" 92 | ); 93 | 94 | token_test( 95 | [ "method", "GET", "url.index", "index", "url.slash", "/", "url.type", "type" ], 96 | "GET index/type" 97 | ); 98 | 99 | token_test( 100 | [ "method", "GET", "url.slash", "/", "url.index", "index", "url.slash", "/", "url.type", "type", "url.slash", "/" ], 101 | "GET /index/type/" 102 | ); 103 | 104 | token_test( 105 | [ "method", "GET", "url.index", "index", "url.slash", "/", "url.type", "type", "url.slash", "/", "url.endpoint", "_search" ], 106 | "GET index/type/_search" 107 | ); 108 | 109 | token_test( 110 | [ "method", "GET", "url.index", "index", "url.slash", "/", "url.type", "type", "url.slash", "/", "url.endpoint", "_search", 111 | "url.questionmark", "?", "url.param", "value", "url.equal", "=", "url.value", "1" 112 | ], 113 | "GET index/type/_search?value=1" 114 | ); 115 | 116 | 117 | token_test( 118 | [ "method", "GET", "url.index", "index", "url.slash", "/", "url.type", "type", "url.slash", "/", "url.id", "1" ], 119 | "GET index/type/1" 120 | ); 121 | 122 | 123 | token_test( 124 | [ "method", "GET", "url.slash", "/", "url.index", "index1", "url.comma", ",", "url.index", "index2", "url.slash", "/" ], 125 | "GET /index1,index2/" 126 | ); 127 | 128 | token_test( 129 | [ "method", "GET", "url.slash", "/", "url.index", "index1", "url.comma", ",", "url.index", "index2", "url.slash", "/", 130 | "url.endpoint", "_search"], 131 | "GET /index1,index2/_search" 132 | ); 133 | 134 | token_test( 135 | [ "method", "GET", "url.index", "index1", "url.comma", ",", "url.index", "index2", "url.slash", "/", 136 | "url.endpoint", "_search"], 137 | "GET index1,index2/_search" 138 | ); 139 | 140 | token_test( 141 | [ "method", "GET", "url.slash", "/", "url.index", "index1", "url.comma", ",", "url.index", "index2" ], 142 | "GET /index1,index2" 143 | ); 144 | 145 | token_test( 146 | [ "method", "GET", "url.index", "index1", "url.comma", ",", "url.index", "index2" ], 147 | "GET index1,index2" 148 | ); 149 | 150 | token_test( 151 | [ "method", "GET", "url.slash", "/", "url.index", "index1", "url.comma", "," ], 152 | "GET /index1," 153 | ); 154 | 155 | 156 | token_test( 157 | [ "method", "PUT", "url.slash", "/", "url.index", "index", "url.slash", "/" ], 158 | "PUT /index/" 159 | ); 160 | 161 | token_test( 162 | [ "method", "PUT", "url.slash", "/", "url.index", "index" ], 163 | "PUT /index" 164 | ); 165 | 166 | token_test( 167 | [ "method", "PUT", "url.slash", "/", "url.index", "index1", "url.comma", ",", "url.index", "index2", 168 | "url.slash", "/", "url.type", "type1", "url.comma", ",", "url.type", "type2"], 169 | "PUT /index1,index2/type1,type2" 170 | ); 171 | 172 | token_test( 173 | [ "method", "PUT", "url.slash", "/", "url.index", "index1", 174 | "url.slash", "/", "url.type", "type1", "url.comma", ",", "url.type", "type2", "url.comma", ","], 175 | "PUT /index1/type1,type2," 176 | ); 177 | 178 | token_test( 179 | [ "method", "PUT", "url.index", "index1", "url.comma", ",", "url.index", "index2", 180 | "url.slash", "/", "url.type", "type1", "url.comma", ",", "url.type", "type2", "url.slash", "/", 181 | "url.id", "1234"], 182 | "PUT index1,index2/type1,type2/1234" 183 | ); 184 | 185 | 186 | token_test( 187 | [ "method", "POST", "url.endpoint", "_search", "paren.lparen", "{", "variable", '"q"', "punctuation.colon", ":", 188 | "paren.lparen", "{", "paren.rparen", "}", "paren.rparen", "}" 189 | ], 190 | 'POST _search\n' + 191 | '{\n' + 192 | ' "q": {}\n' + 193 | ' \n' + 194 | '}' 195 | ); 196 | 197 | function statesAsList(editor) { 198 | var ret = []; 199 | var session = editor.getSession(); 200 | var maxLine = session.getLength(); 201 | for (var row = 0; row < maxLine; row++) ret.push(session.getState(row)); 202 | 203 | return ret; 204 | } 205 | 206 | 207 | function states_test(states_list, prefix, data) { 208 | if (data && typeof data != "string") data = JSON.stringify(data, null, 3); 209 | if (data) { 210 | if (prefix) data = prefix + "\n" + data; 211 | } else { 212 | data = prefix; 213 | } 214 | 215 | QUnit.asyncTest("States test " + testCount++ + " prefix: " + prefix, function () { 216 | var editor = global.sense.tests.editor; 217 | 218 | utils.updateEditorAndCallWhenUpdated(data, editor, function () { 219 | var modes = statesAsList(editor); 220 | deepEqual(modes, states_list, "Doc:\n" + data); 221 | 222 | start(); 223 | }); 224 | 225 | }); 226 | } 227 | 228 | 229 | function n(name) { 230 | return { name: name}; 231 | } 232 | function nd(name, depth) { 233 | return { name: name, depth: depth }; 234 | } 235 | 236 | states_test( 237 | [n("start"), nd("json", 1), nd("json", 1), nd("start", 0) ], 238 | 'POST _search\n' + 239 | '{\n' + 240 | ' "query": { "match_all": {} }\n' + 241 | '}' 242 | ); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sense - a JSON aware interface to ElasticSearch 5 | 6 | 7 | 8 | 9 | 10 | 11 | 26 |
    27 |
    GET _search 28 | { 29 | "query": { "match_all": {} } 30 | } 31 |
    32 |
    {}
    33 |
    34 |
    35 | 37 | 39 | 43 |
    44 |
    45 | 46 |
    47 | 48 | 49 | 95 | 112 | 113 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /src/mappings.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | var global = window; 4 | 5 | var currentServer; 6 | var per_index_types = {}; 7 | var per_alias_indexes = []; 8 | 9 | 10 | function expandAliases(indicesOrAliases) { 11 | // takes a list of indices or aliases or a string which may be either and returns a list of indices 12 | // returns a list for multiple values or a string for a single. 13 | 14 | if (!indicesOrAliases) return indicesOrAliases; 15 | 16 | if (typeof indicesOrAliases === "string") indicesOrAliases = [indicesOrAliases]; 17 | indicesOrAliases = $.map(indicesOrAliases, function (iOrA) { 18 | if (per_alias_indexes[iOrA]) return per_alias_indexes[iOrA]; 19 | return [iOrA]; 20 | }); 21 | var ret = [].concat.apply([], indicesOrAliases); 22 | ret.sort(); 23 | var last; 24 | ret = $.map(ret, function (v) { 25 | var r = last == v ? null : v; 26 | last = v; 27 | return r; 28 | }); 29 | return ret.length > 1 ? ret : ret[0]; 30 | } 31 | 32 | function getFields(indices, types) { 33 | // get fields for indices and types. Both can be a list, a string or null (meaning all). 34 | var ret = []; 35 | indices = expandAliases(indices); 36 | if (typeof indices == "string") { 37 | 38 | var type_dict = per_index_types[indices]; 39 | if (!type_dict) return []; 40 | 41 | if (typeof types == "string") { 42 | var f = type_dict[types]; 43 | ret = f ? f : []; 44 | } 45 | else { 46 | // filter what we need 47 | $.each(type_dict, function (type, fields) { 48 | if (!types || types.length == 0 || $.inArray(type, types) != -1) 49 | ret.push(fields); 50 | }); 51 | 52 | ret = [].concat.apply([], ret); 53 | } 54 | } 55 | else { 56 | // multi index mode. 57 | $.each(per_index_types, function (index) { 58 | if (!indices || indices.length == 0 || $.inArray(index, indices) != -1) 59 | ret.push(getFields(index, types)); 60 | }); 61 | ret = [].concat.apply([], ret); 62 | } 63 | 64 | return ret; 65 | } 66 | 67 | function getTypes(indices) { 68 | var ret = []; 69 | indices = expandAliases(indices); 70 | if (typeof indices == "string") { 71 | var type_dict = per_index_types[indices]; 72 | if (!type_dict) return []; 73 | 74 | // filter what we need 75 | $.each(type_dict, function (type, fields) { 76 | ret.push(type); 77 | }); 78 | 79 | } 80 | else { 81 | // multi index mode. 82 | $.each(per_index_types, function (index) { 83 | if (!indices || $.inArray(index, indices) != -1) 84 | ret.push(getTypes(index)); 85 | }); 86 | ret = [].concat.apply([], ret); 87 | } 88 | 89 | return ret.filter(function (v, i, a) { 90 | return a.indexOf(v) == i 91 | }); // dedupe array; 92 | 93 | } 94 | 95 | 96 | function getIndices(include_aliases) { 97 | var ret = []; 98 | $.each(per_index_types, function (index) { 99 | ret.push(index); 100 | }); 101 | if (typeof include_aliases === "undefined" ? true : include_aliases) { 102 | $.each(per_alias_indexes, function (alias) { 103 | ret.push(alias); 104 | }); 105 | } 106 | return ret; 107 | } 108 | 109 | function getFieldNamesFromFieldMapping(field_name, field_mapping) { 110 | if (field_mapping['enabled'] == false) return []; 111 | 112 | 113 | function applyPathSettings(nested_field_names) { 114 | var path_type = field_mapping['path'] || "full"; 115 | if (path_type == "full") { 116 | return $.map(nested_field_names, function (f) { 117 | return field_name + "." + f; 118 | }); 119 | } 120 | return nested_field_names; 121 | } 122 | 123 | if (field_mapping["properties"]) { 124 | // derived object type 125 | var nested_fields = getFieldNamesFromTypeMapping(field_mapping); 126 | return applyPathSettings(nested_fields); 127 | } 128 | 129 | if (field_mapping['type'] == 'multi_field') { 130 | var nested_fields = $.map(field_mapping['fields'], function (field_mapping, field_name) { 131 | return getFieldNamesFromFieldMapping(field_name, field_mapping); 132 | }); 133 | 134 | return applyPathSettings(nested_fields); 135 | } 136 | 137 | if (field_mapping["index_name"]) return [field_mapping["index_name"]]; 138 | 139 | return [field_name]; 140 | } 141 | 142 | function getFieldNamesFromTypeMapping(type_mapping) { 143 | var field_list = 144 | $.map(type_mapping['properties'], function (field_mapping, field_name) { 145 | return getFieldNamesFromFieldMapping(field_name, field_mapping); 146 | }); 147 | 148 | // deduping 149 | var last = undefined; 150 | field_list.sort(); 151 | return $.map(field_list, function (f) { 152 | var r = (f === last) ? null : f; 153 | last = f; 154 | return r; 155 | }); 156 | } 157 | 158 | function loadMappings(mappings) { 159 | per_index_types = {}; 160 | $.each(mappings, function (index, index_mapping) { 161 | var normalized_index_mappings = {}; 162 | $.each(index_mapping, function (type_name, type_mapping) { 163 | var field_list = getFieldNamesFromTypeMapping(type_mapping); 164 | normalized_index_mappings[type_name] = field_list; 165 | }); 166 | per_index_types[index] = normalized_index_mappings; 167 | }); 168 | } 169 | 170 | function loadAliases(aliases) { 171 | per_alias_indexes = {} 172 | $.each(aliases, function (index, index_aliases) { 173 | $.each(index_aliases.aliases, function (alias) { 174 | if (alias === index) return; // alias which is identical to index means no index. 175 | var cur_aliases = per_alias_indexes[alias]; 176 | if (!cur_aliases) { 177 | cur_aliases = []; 178 | per_alias_indexes[alias] = cur_aliases; 179 | } 180 | cur_aliases.push(index); 181 | }); 182 | }); 183 | 184 | per_alias_indexes['_all'] = getIndices(false); 185 | } 186 | 187 | function clear() { 188 | per_index_types = {}; 189 | per_alias_indexes = {}; 190 | } 191 | 192 | function retrieveMappingFromServer() { 193 | if (!currentServer) return; 194 | callES(currentServer, "_mapping", "GET", null, function (data, status, xhr) { 195 | loadMappings(data); 196 | }); 197 | callES(currentServer, "_aliases", "GET", null, function (data, status, xhr) { 198 | loadAliases(data); 199 | }); 200 | 201 | } 202 | 203 | function notifyServerChange(newServer) { 204 | if (newServer.indexOf("://") < 0) newServer = "http://" + newServer; 205 | newServer = newServer.trim("/"); 206 | if (newServer === currentServer) return; // already have it. 207 | currentServer = newServer; 208 | retrieveMappingFromServer(); 209 | } 210 | 211 | function mapping_retriever() { 212 | retrieveMappingFromServer(); 213 | setTimeout(function () { 214 | mapping_retriever(); 215 | }, 60000); 216 | } 217 | 218 | mapping_retriever(); 219 | 220 | if (!global.sense) global.sense = {}; 221 | global.sense.mappings = {}; 222 | global.sense.mappings.getFields = getFields; 223 | global.sense.mappings.getIndices = getIndices; 224 | global.sense.mappings.getTypes = getTypes; 225 | global.sense.mappings.loadMappings = loadMappings; 226 | global.sense.mappings.loadAliases = loadAliases; 227 | global.sense.mappings.expandAliases = expandAliases; 228 | global.sense.mappings.clear = clear; 229 | global.sense.mappings.notifyServerChange = notifyServerChange; 230 | 231 | })(); -------------------------------------------------------------------------------- /kb/query.js: -------------------------------------------------------------------------------- 1 | SPAN_QUERIES = { 2 | // TODO add one_of for objects 3 | span_first: {__scope_link: ".query.span_first"}, 4 | span_near: {__scope_link: ".query.span_near"}, 5 | span_or: {__scope_link: ".query.span_or"}, 6 | span_not: {__scope_link: ".query.span_not"}, 7 | span_term: {__scope_link: ".query.span_term"} 8 | }; 9 | 10 | sense.kb.addGlobalAutocompleteRules("query", { 11 | match: { __template: { "FIELD": "TEXT" }, 12 | "$FIELD$": { 13 | "query": "", 14 | "operator": { __one_of: ["and" , "or"]}, 15 | "type": { __one_of: [ "phrase", "phrase_prefix", "boolean"]}, 16 | "max_expansions": 10, 17 | "analyzer": "", 18 | "fuzziness": 1.0, 19 | "prefix_length": 1 20 | } }, 21 | match_phrase: { __template: { "FIELD": "PHRASE" }, 22 | "$FIELD$": { 23 | query: "", 24 | analyzer: "" 25 | } }, 26 | match_phrase_prefix: { __template: { "FIELD": "PREFIX" }, 27 | "$FIELD$": { 28 | query: "", 29 | analyzer: "", 30 | max_expansions: 10, 31 | prefix_length: 1, 32 | fuzziness: 0.1 33 | } }, 34 | multi_match: { __template: { "query": "", "fields": [] }, 35 | query: "", 36 | fields: ["$FIELD$"], 37 | use_dis_max: { __template: true, __one_of: [ true, false ]}, 38 | tie_breaker: 0.0 39 | }, 40 | bool: { 41 | must: [ 42 | { __scope_link: "GLOBAL.query"} 43 | ], 44 | must_not: [ 45 | { __scope_link: "GLOBAL.query"} 46 | ], 47 | should: [ 48 | { __scope_link: "GLOBAL.query" } 49 | ], 50 | minimum_number_should_match: 1, 51 | boost: 1.0 52 | }, 53 | boosting: { 54 | positive: { __scope_link: ".query" }, 55 | negative: { __scope_link: ".query" }, 56 | negative_boost: 0.2 57 | }, 58 | ids: { type: "", values: [] }, 59 | custom_score: { 60 | __template: { query: {}, script: ""}, 61 | query: {}, 62 | script: "", 63 | params: {}, 64 | lang: "mvel" 65 | }, 66 | custom_boost_factor: { 67 | __template: { query: {}, boost_factor: 1.1 }, 68 | query: {}, 69 | boost_factor: 1.1 70 | }, 71 | constant_score: { 72 | __template: { filter: {}, boost: 1.2 }, 73 | query: {}, 74 | filter: {}, 75 | boost: 1.2 76 | }, 77 | dis_max: { 78 | __template: { tie_breaker: 0.7, boost: 1.2, queries: []}, 79 | tie_breaker: 0.7, 80 | boost: 1.2, 81 | queries: [ 82 | { __scope_link: ".query"} 83 | ] 84 | }, 85 | field: { 86 | "$FIELD$": { 87 | query: "", boost: 2.0, 88 | enable_position_increments: { __template: false, __one_of: [ true, false ]} 89 | } }, 90 | filtered: { 91 | __template: { 92 | query: {}, 93 | filter: {} 94 | }, 95 | query: {}, 96 | filter: {} 97 | }, 98 | fuzzy_like_this: { 99 | fields: [], 100 | like_text: "", 101 | max_query_terms: 12 102 | }, 103 | flt: { 104 | __scope_link: ".query.fuzzy_like_this" 105 | }, 106 | fuzzy: { 107 | "$FIELD$": { 108 | "value": "", 109 | "boost": 1.0, 110 | "min_similarity": 0.5, 111 | "prefix_length": 0 112 | } 113 | }, 114 | has_child: { 115 | "type": "$TYPE$", 116 | "score_type": { __one_of: ["none", "max", "sum", "avg"]}, 117 | "_scope": "", 118 | "query": { 119 | } 120 | }, 121 | has_parent: { 122 | "parent_type": "$TYPE$", 123 | "score_type": { __one_of: ["none", "score"]}, 124 | "_scope": "", 125 | "query": { 126 | } 127 | }, 128 | match_all: {}, 129 | more_like_this: { 130 | __template: { 131 | "fields": ["FIELD"], 132 | "like_text": "text like this one", 133 | "min_term_freq": 1, 134 | "max_query_terms": 12 135 | }, 136 | fields: [ "$FIELD$ "], 137 | like_text: "", 138 | percent_terms_to_match: 0.3, 139 | min_term_freq: 2, 140 | max_query_terms: 25, 141 | stop_words: [""], 142 | min_doc_freq: 5, 143 | max_doc_freq: 100, 144 | min_word_len: 0, 145 | max_word_len: 0, 146 | boost_terms: 1, 147 | boost: 1.0, 148 | analyzer: "" 149 | }, 150 | more_like_this_field: { 151 | __template: { 152 | "FIELD": { 153 | "like_text": "text like this one", 154 | "min_term_freq": 1, 155 | "max_query_terms": 12 156 | } }, 157 | "$FIELD$": { 158 | like_text: "", 159 | percent_terms_to_match: 0.3, 160 | min_term_freq: 2, 161 | max_query_terms: 25, 162 | stop_words: [""], 163 | min_doc_freq: 5, 164 | max_doc_freq: 100, 165 | min_word_len: 0, 166 | max_word_len: 0, 167 | boost_terms: 1, 168 | boost: 1.0, 169 | analyzer: "" 170 | } 171 | }, 172 | prefix: { 173 | __template: { 174 | "FIELD": { "value": "" } 175 | }, 176 | "$FIELD$": { 177 | value: "", 178 | boost: 1.0 179 | } 180 | }, 181 | query_string: { 182 | __template: { 183 | "default_field": "FIELD", 184 | "query": "this AND that OR thus" 185 | }, 186 | query: "", 187 | default_field: "$FIELD$", 188 | fields: ["$FIELD$"], 189 | default_operator: { __one_of: ["OR", "AND"] }, 190 | analyzer: "", 191 | allow_leading_wildcard: { __one_of: [ true, false]}, 192 | lowercase_expanded_terms: { __one_of: [ true, false]}, 193 | enable_position_increments: { __one_of: [ true, false]}, 194 | fuzzy_max_expansions: 50, 195 | fuzzy_min_sim: 0.5, 196 | fuzzy_prefix_length: 0, 197 | phrase_slop: 0, 198 | boost: 1.0, 199 | analyze_wildcard: { __one_of: [ false, true ]}, 200 | auto_generate_phrase_queries: { __one_of: [ false, true ]}, 201 | minimum_should_match: "20%", 202 | lenient: { __one_of: [ false, true ]}, 203 | use_dis_max: { __one_of: [ true, false]}, 204 | tie_breaker: 0 205 | }, 206 | range: { 207 | __template: { 208 | "FIELD": { 209 | from: 10, 210 | to: 20 211 | } 212 | }, 213 | "$FIELD$": { 214 | __template: { from: 10, to: 20}, 215 | from: 1, 216 | to: 20, 217 | include_lower: { __one_of: [ true, false]}, 218 | include_upper: { __one_of: [ true, false]}, 219 | boost: 1.0 220 | } 221 | }, 222 | span_first: { 223 | __template: { 224 | "match": { 225 | "span_term": { "FIELD": "VALUE" } 226 | }, 227 | "end": 3 228 | }, 229 | match: SPAN_QUERIES 230 | }, 231 | span_near: { 232 | __template: { 233 | "clauses": [ 234 | { span_term: { "FIELD": { "value": "VALUE"} } } 235 | ], 236 | slop: 12, 237 | in_order: false 238 | }, 239 | clauses: [ 240 | SPAN_QUERIES 241 | ], 242 | slop: 12, 243 | in_order: {__one_of: [ false, true ]}, 244 | collect_payloads: {__one_of: [ false, true ]} 245 | }, 246 | span_term: { 247 | __template: { "FIELD": { "value": "VALUE"}}, 248 | "$FIELD$": { 249 | value: "", 250 | boost: 2.0 251 | } 252 | }, 253 | span_not: { 254 | __template: { 255 | include: { 256 | span_term: { "FIELD": { "value": "VALUE"} } 257 | }, 258 | exclude: { 259 | span_term: { "FIELD": { "value": "VALUE"} } 260 | } 261 | }, 262 | include: SPAN_QUERIES, 263 | exclude: SPAN_QUERIES 264 | }, 265 | span_or: { 266 | __template: { 267 | clauses: [ 268 | { span_term: { "FIELD": { "value": "VALUE"} } } 269 | ] 270 | }, 271 | clauses: [ 272 | SPAN_QUERIES 273 | ] 274 | }, 275 | term: { 276 | __template: { "FIELD": { value: "VALUE" }}, 277 | "$FIELD$": { 278 | value: "", 279 | boost: 2.0 280 | } 281 | }, 282 | terms: { 283 | __template: { 284 | "FIELD": [ "VALUE1", "VALUE2"] 285 | }, 286 | "$FIELD$": [ "" ], 287 | minimum_match: 1 288 | }, 289 | top_children: { 290 | __template: { 291 | type: "CHILD_TYPE", 292 | query: {} 293 | }, 294 | type: "$CHILD_TYPE$", 295 | query: { }, 296 | score: { __one_of: [ "max", "sum", "avg"] }, 297 | factor: 5, 298 | incremental_factor: 2 299 | }, 300 | wildcard: { 301 | __template: { 302 | "FIELD": { value: "VALUE"} 303 | }, 304 | "$FIELD$": { value: "", boost: 2.0 } 305 | }, 306 | nested: { 307 | __template: { 308 | path: "path_to_nested_doc", 309 | query: {} 310 | }, 311 | path: "", 312 | query: {}, 313 | filter: {}, 314 | score_mode: { __one_of: ["avg", "total", "max", "none"]} 315 | }, 316 | custom_filters_score: { 317 | __template: { 318 | query: {}, 319 | filters: [ 320 | { 321 | filter: {} 322 | } 323 | ] 324 | }, 325 | query: {}, 326 | filters: [ 327 | { filter: {}, boost: 2.0, script: ""} 328 | ], 329 | score_mode: { __one_of: [ "first", "min", "max", "total", "avg", "multiply"] }, 330 | max_boost: 2.0, 331 | params: {}, 332 | lang: "" 333 | }, 334 | indices: { 335 | __template: { 336 | indices: ["INDEX1", "INDEX2"], 337 | query: {} 338 | }, 339 | indices: ["$INDEX$"], 340 | query: {}, 341 | no_match_query: { __scope_link: ".query"} 342 | }, 343 | geo_shape: { 344 | __template: { 345 | location: {}, 346 | relation: "within" 347 | }, 348 | __scope_link: ".filter.geo_shape" 349 | } 350 | 351 | }); -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | var global = window; 4 | if (!global.sense) 5 | global.sense = {}; 6 | 7 | var ns = {}; 8 | global.sense.utils = ns; 9 | 10 | var sense = global.sense; 11 | 12 | ROW_PARSE_MODE = { 13 | REQUEST_START: 2, 14 | IN_REQUEST: 4, 15 | MULTI_DOC_CUR_DOC_END: 8, 16 | REQUEST_END: 16, 17 | BETWEEN_REQUESTS: 32 18 | }; 19 | 20 | getRowParseMode = function (row, editor) { 21 | editor = editor || sense.editor; 22 | if (row == null || typeof row == "undefined") row = editor.getCursorPosition().row; 23 | 24 | var session = editor.getSession(); 25 | if (row >= session.getLength()) return ROW_PARSE_MODE.BETWEEN_REQUESTS; 26 | var mode = (session.getState(row) || {}).name; 27 | if (!mode) 28 | return ROW_PARSE_MODE.BETWEEN_REQUESTS; // shouldn't really happen 29 | 30 | 31 | if (mode != "start") return ROW_PARSE_MODE.IN_REQUEST; 32 | var line = (session.getLine(row) || "").trim(); 33 | if (!line) return ROW_PARSE_MODE.BETWEEN_REQUESTS; // empty line waiting for a new req to start 34 | 35 | if (line.indexOf("}", line.length - 1) >= 0) { 36 | // check for a multi doc request (must start a new json doc immediately after this one end. 37 | row++; 38 | if (row < session.getLength()) { 39 | line = (session.getLine(row) || "").trim(); 40 | if (line.indexOf("{") == 0) { // next line is another doc in a multi doc 41 | return ROW_PARSE_MODE.MULTI_DOC_CUR_DOC_END | ROW_PARSE_MODE.IN_REQUEST; 42 | } 43 | 44 | } 45 | return ROW_PARSE_MODE.REQUEST_END | ROW_PARSE_MODE.MULTI_DOC_CUR_DOC_END; // end of request 46 | } 47 | 48 | // check for single line requests 49 | row++; 50 | if (row >= session.getLength()) { 51 | return ROW_PARSE_MODE.REQUEST_START | ROW_PARSE_MODE.REQUEST_END; 52 | } 53 | line = (session.getLine(row) || "").trim(); 54 | if (line.indexOf("{") != 0) { // next line is another request 55 | return ROW_PARSE_MODE.REQUEST_START | ROW_PARSE_MODE.REQUEST_END; 56 | } 57 | 58 | return ROW_PARSE_MODE.REQUEST_START; 59 | }; 60 | 61 | function rowPredicate(row, editor, value) { 62 | var mode = getRowParseMode(row, editor); 63 | return (mode & value) > 0; 64 | } 65 | 66 | ns.isEndRequestRow = function (row, editor) { 67 | return rowPredicate(row, editor, ROW_PARSE_MODE.REQUEST_END); 68 | }; 69 | 70 | ns.isRequestEdge = function (row, editor) { 71 | return rowPredicate(row, editor, ROW_PARSE_MODE.REQUEST_END | ROW_PARSE_MODE.REQUEST_START); 72 | }; 73 | 74 | 75 | ns.isStartRequestRow = function (row, editor) { 76 | return rowPredicate(row, editor, ROW_PARSE_MODE.REQUEST_START); 77 | }; 78 | 79 | ns.isInBetweenRequestsRow = function (row, editor) { 80 | return rowPredicate(row, editor, ROW_PARSE_MODE.BETWEEN_REQUESTS); 81 | }; 82 | 83 | ns.isInRequestsRow = function (row, editor) { 84 | return rowPredicate(row, editor, ROW_PARSE_MODE.IN_REQUEST); 85 | }; 86 | 87 | ns.isMultiDocDocEndRow = function (row, editor) { 88 | return rowPredicate(row, editor, ROW_PARSE_MODE.MULTI_DOC_CUR_DOC_END); 89 | }; 90 | 91 | 92 | ns.iterForCurrentLoc = function (editor) { 93 | editor = editor || sense.editor; 94 | var pos = editor.getCursorPosition(); 95 | return ns.iterForPosition(pos.row, pos.column, editor); 96 | }; 97 | 98 | ns.iterForPosition = function (row, column, editor) { 99 | editor = editor || sense.editor; 100 | return new (ace.require("ace/token_iterator").TokenIterator)(editor.getSession(), row, column); 101 | }; 102 | 103 | ns.isEmptyToken = function (tokenOrTokenIter) { 104 | var token = tokenOrTokenIter && tokenOrTokenIter.getCurrentToken ? tokenOrTokenIter.getCurrentToken() : tokenOrTokenIter; 105 | return !token || token.type == "whitespace" 106 | }; 107 | 108 | ns.isUrlOrMethodToken = function (tokenOrTokenIter) { 109 | var t = tokenOrTokenIter.getCurrentToken ? tokenOrTokenIter.getCurrentToken() : tokenOrTokenIter; 110 | return t && t.type && (t.type == "method" || t.type.indexOf("url") == 0); 111 | }; 112 | 113 | 114 | ns.nextNonEmptyToken = function (tokenIter) { 115 | var t = tokenIter.stepForward(); 116 | while (t && ns.isEmptyToken(t)) t = tokenIter.stepForward(); 117 | return t; 118 | }; 119 | 120 | ns.prevNonEmptyToken = function (tokenIter) { 121 | var t = tokenIter.stepBackward(); 122 | // empty rows return null token. 123 | while ((t || tokenIter.getCurrentTokenRow() > 0) && ns.isEmptyToken(t)) t = tokenIter.stepBackward(); 124 | return t; 125 | }; 126 | 127 | ns.prevRequestStart = function (pos, editor) { 128 | editor = editor || sense.editor; 129 | pos = pos || editor.getCursorPosition(); 130 | var curRow = pos.row; 131 | while (curRow > 0 && !ns.isStartRequestRow(curRow, editor)) curRow--; 132 | 133 | return { row: curRow, column: 0}; 134 | }; 135 | 136 | ns.nextRequestEnd = function (pos, editor) { 137 | editor = editor || sense.editor; 138 | pos = pos || editor.getCursorPosition(); 139 | var session = editor.getSession(); 140 | var curRow = pos.row; 141 | var maxLines = session.getLength(); 142 | for (; curRow < maxLines - 1; curRow++) { 143 | var curRowMode = getRowParseMode(curRow, editor); 144 | if ((curRowMode & ROW_PARSE_MODE.REQUEST_END) > 0) break; 145 | if (curRow != pos.row && (curRowMode & ROW_PARSE_MODE.REQUEST_START) > 0) break; 146 | } 147 | 148 | var column = (session.getLine(curRow) || "").length; 149 | 150 | return { row: curRow, column: column}; 151 | }; 152 | 153 | ns.nextDataDocEnd = function (pos, editor) { 154 | editor = editor || sense.editor; 155 | pos = pos || editor.getCursorPosition(); 156 | var session = editor.getSession(); 157 | var curRow = pos.row; 158 | var maxLines = session.getLength(); 159 | for (; curRow < maxLines - 1; curRow++) { 160 | var curRowMode = getRowParseMode(curRow, editor); 161 | if ((curRowMode & ROW_PARSE_MODE.REQUEST_END) > 0) { 162 | break; 163 | } 164 | if ((curRowMode & ROW_PARSE_MODE.MULTI_DOC_CUR_DOC_END) > 0) break; 165 | if (curRow != pos.row && (curRowMode & ROW_PARSE_MODE.REQUEST_START) > 0) break; 166 | } 167 | 168 | var column = (session.getLine(curRow) || "").length; 169 | 170 | return { row: curRow, column: column }; 171 | }; 172 | 173 | 174 | ns.getCurrentRequestRange = function (editor) { 175 | if (ns.isInBetweenRequestsRow(null, editor)) return null; 176 | 177 | var reqStart = ns.prevRequestStart(null, editor); 178 | var reqEnd = ns.nextRequestEnd(reqStart, editor); 179 | return new (ace.require("ace/range").Range)( 180 | reqStart.row, reqStart.column, 181 | reqEnd.row, reqEnd.column 182 | ); 183 | }; 184 | 185 | ns.getCurrentRequest = function (editor) { 186 | editor = editor || sense.editor; 187 | 188 | if (ns.isInBetweenRequestsRow(null, editor)) return null; 189 | 190 | var request = { 191 | method: "", 192 | data: [], 193 | url: null 194 | }; 195 | 196 | var currentReqRange = ns.getCurrentRequestRange(editor); 197 | 198 | var pos = currentReqRange.start; 199 | var tokenIter = ns.iterForPosition(pos.row, pos.column, editor); 200 | var t = tokenIter.getCurrentToken(); 201 | request.method = t.value; 202 | t = ns.nextNonEmptyToken(tokenIter); 203 | if (!t || t.type == "method") return null; 204 | request.url = ""; 205 | while (t && t.type && t.type.indexOf("url") == 0) { 206 | request.url += t.value; 207 | t = tokenIter.stepForward(); 208 | } 209 | 210 | var bodyStartRow = (t ? 0 : 1) + tokenIter.getCurrentTokenRow(); // artificially increase end of docs. 211 | var bodyStartColumn = 0; 212 | while (bodyStartRow < currentReqRange.end.row || 213 | (bodyStartRow == currentReqRange.end.row && 214 | bodyStartColumn < currentReqRange.end.column 215 | )) { 216 | dataEndPos = ns.nextDataDocEnd({ row: bodyStartRow, column: bodyStartColumn}, editor); 217 | var bodyRange = new (ace.require("ace/range").Range)( 218 | bodyStartRow, bodyStartColumn, 219 | dataEndPos.row, dataEndPos.column 220 | ); 221 | var data = editor.getSession().getTextRange(bodyRange); 222 | request.data.push(data.trim()); 223 | bodyStartRow = dataEndPos.row + 1; 224 | bodyStartColumn = 0; 225 | } 226 | return request; 227 | }; 228 | 229 | ns.textFromRequest = function (request) { 230 | var data = request.data; 231 | if (typeof data != "string") { 232 | data = data.join("\n"); 233 | } 234 | return request.method + " " + request.url + "\n" + data; 235 | }; 236 | 237 | ns.replaceCurrentRequest = function (newRequest, curRequestRange) { 238 | if (!curRequestRange) curRequestRange = ns.getCurrentRequestRange(); 239 | var text = ns.textFromRequest(newRequest); 240 | if (curRequestRange) { 241 | sense.editor.getSession().replace(curRequestRange, text); 242 | } 243 | else { 244 | // just insert where we are 245 | sense.editor.insert(text); 246 | } 247 | }; 248 | 249 | ns.getUrlParam = function (name) { 250 | name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); 251 | var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), 252 | results = regex.exec(location.search); 253 | return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); 254 | }; 255 | 256 | ns.isTokenizationStable = function (editor) { 257 | editor = editor || sense.editor; 258 | return !editor.getSession().bgTokenizer.running; 259 | }; 260 | 261 | ns.updateEditorAndCallWhenUpdated = function (data, editor, callback) { 262 | editor = editor || sense.editor; 263 | var session = editor.getSession(); 264 | 265 | function mycallback() { 266 | session.removeListener(mycallback); 267 | if (session.bgTokenizer.running) { 268 | setTimeout(mycallback, 50); // wait 269 | return; 270 | } 271 | callback(); 272 | } 273 | 274 | session.on('tokenizerUpdate', mycallback); 275 | session.setValue(data); 276 | } 277 | 278 | })(); -------------------------------------------------------------------------------- /lib/moment.min.js: -------------------------------------------------------------------------------- 1 | // moment.js 2 | // version : 1.7.2 3 | // author : Tim Wood 4 | // license : MIT 5 | // momentjs.com 6 | (function(a){function E(a,b,c,d){var e=c.lang();return e[a].call?e[a](c,d):e[a][b]}function F(a,b){return function(c){return K(a.call(this,c),b)}}function G(a){return function(b){var c=a.call(this,b);return c+this.lang().ordinal(c)}}function H(a,b,c){this._d=a,this._isUTC=!!b,this._a=a._a||null,this._lang=c||!1}function I(a){var b=this._data={},c=a.years||a.y||0,d=a.months||a.M||0,e=a.weeks||a.w||0,f=a.days||a.d||0,g=a.hours||a.h||0,h=a.minutes||a.m||0,i=a.seconds||a.s||0,j=a.milliseconds||a.ms||0;this._milliseconds=j+i*1e3+h*6e4+g*36e5,this._days=f+e*7,this._months=d+c*12,b.milliseconds=j%1e3,i+=J(j/1e3),b.seconds=i%60,h+=J(i/60),b.minutes=h%60,g+=J(h/60),b.hours=g%24,f+=J(g/24),f+=e*7,b.days=f%30,d+=J(f/30),b.months=d%12,c+=J(d/12),b.years=c,this._lang=!1}function J(a){return a<0?Math.ceil(a):Math.floor(a)}function K(a,b){var c=a+"";while(c.length70?1900:2e3);break;case"YYYY":c[0]=~~Math.abs(b);break;case"a":case"A":d.isPm=(b+"").toLowerCase()==="pm";break;case"H":case"HH":case"h":case"hh":c[3]=~~b;break;case"m":case"mm":c[4]=~~b;break;case"s":case"ss":c[5]=~~b;break;case"S":case"SS":case"SSS":c[6]=~~(("0."+b)*1e3);break;case"Z":case"ZZ":d.isUTC=!0,e=(b+"").match(x),e&&e[1]&&(d.tzh=~~e[1]),e&&e[2]&&(d.tzm=~~e[2]),e&&e[0]==="+"&&(d.tzh=-d.tzh,d.tzm=-d.tzm)}b==null&&(c[8]=!1)}function W(a,b){var c=[0,0,1,0,0,0,0],d={tzh:0,tzm:0},e=b.match(k),f,g;for(f=0;f0,j[4]=c,Z.apply({},j)}function _(a,c){b.fn[a]=function(a){var b=this._isUTC?"UTC":"";return a!=null?(this._d["set"+b+c](a),this):this._d["get"+b+c]()}}function ab(a){b.duration.fn[a]=function(){return this._data[a]}}function bb(a,c){b.duration.fn["as"+a]=function(){return+this/c}}var b,c="1.7.2",d=Math.round,e,f={},g="en",h=typeof module!="undefined"&&module.exports,i="months|monthsShort|weekdays|weekdaysShort|weekdaysMin|longDateFormat|calendar|relativeTime|ordinal|meridiem".split("|"),j=/^\/?Date\((\-?\d+)/i,k=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|zz?|ZZ?|.)/g,l=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?)/g,m=/([0-9a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)/gi,n=/\d\d?/,o=/\d{1,3}/,p=/\d{3}/,q=/\d{1,4}/,r=/[0-9a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+/i,s=/Z|[\+\-]\d\d:?\d\d/i,t=/T/i,u=/^\s*\d{4}-\d\d-\d\d(T(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,v="YYYY-MM-DDTHH:mm:ssZ",w=[["HH:mm:ss.S",/T\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/T\d\d:\d\d:\d\d/],["HH:mm",/T\d\d:\d\d/],["HH",/T\d\d/]],x=/([\+\-]|\d\d)/gi,y="Month|Date|Hours|Minutes|Seconds|Milliseconds".split("|"),z={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},A={},B="DDD w M D d".split(" "),C="M D H h m s w".split(" "),D={M:function(){return this.month()+1},MMM:function(a){return E("monthsShort",this.month(),this,a)},MMMM:function(a){return E("months",this.month(),this,a)},D:function(){return this.date()},DDD:function(){var a=new Date(this.year(),this.month(),this.date()),b=new Date(this.year(),0,1);return~~((a-b)/864e5+1.5)},d:function(){return this.day()},dd:function(a){return E("weekdaysMin",this.day(),this,a)},ddd:function(a){return E("weekdaysShort",this.day(),this,a)},dddd:function(a){return E("weekdays",this.day(),this,a)},w:function(){var a=new Date(this.year(),this.month(),this.date()-this.day()+5),b=new Date(a.getFullYear(),0,4);return~~((a-b)/864e5/7+1.5)},YY:function(){return K(this.year()%100,2)},YYYY:function(){return K(this.year(),4)},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return~~(this.milliseconds()/100)},SS:function(){return K(~~(this.milliseconds()/10),2)},SSS:function(){return K(this.milliseconds(),3)},Z:function(){var a=-this.zone(),b="+";return a<0&&(a=-a,b="-"),b+K(~~(a/60),2)+":"+K(~~a%60,2)},ZZ:function(){var a=-this.zone(),b="+";return a<0&&(a=-a,b="-"),b+K(~~(10*a/6),4)}};while(B.length)e=B.pop(),D[e+"o"]=G(D[e]);while(C.length)e=C.pop(),D[e+e]=F(D[e],2);D.DDDD=F(D.DDD,3),b=function(c,d){if(c===null||c==="")return null;var e,f;return b.isMoment(c)?new H(new Date(+c._d),c._isUTC,c._lang):(d?M(d)?e=X(c,d):e=W(c,d):(f=j.exec(c),e=c===a?new Date:f?new Date(+f[1]):c instanceof Date?c:M(c)?O(c):typeof c=="string"?Y(c):new Date(c)),new H(e))},b.utc=function(a,c){return M(a)?new H(O(a,!0),!0):(typeof a=="string"&&!s.exec(a)&&(a+=" +0000",c&&(c+=" Z")),b(a,c).utc())},b.unix=function(a){return b(a*1e3)},b.duration=function(a,c){var d=b.isDuration(a),e=typeof a=="number",f=d?a._data:e?{}:a,g;return e&&(c?f[c]=a:f.milliseconds=a),g=new I(f),d&&(g._lang=a._lang),g},b.humanizeDuration=function(a,c,d){return b.duration(a,c===!0?null:c).humanize(c===!0?!0:d)},b.version=c,b.defaultFormat=v,b.lang=function(a,c){var d;if(!a)return g;(c||!f[a])&&P(a,c);if(f[a]){for(d=0;d11?c?"pm":"PM":c?"am":"AM"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},ordinal:function(a){var b=a%10;return~~(a%100/10)===1?"th":b===1?"st":b===2?"nd":b===3?"rd":"th"}}),b.fn=H.prototype={clone:function(){return b(this)},valueOf:function(){return+this._d},unix:function(){return Math.floor(+this._d/1e3)},toString:function(){return this._d.toString()},toDate:function(){return this._d},toArray:function(){var a=this;return[a.year(),a.month(),a.date(),a.hours(),a.minutes(),a.seconds(),a.milliseconds(),!!this._isUTC]},isValid:function(){return this._a?this._a[8]!=null?!!this._a[8]:!N(this._a,(this._a[7]?b.utc(this._a):b(this._a)).toArray()):!isNaN(this._d.getTime())},utc:function(){return this._isUTC=!0,this},local:function(){return this._isUTC=!1,this},format:function(a){return T(this,a?a:b.defaultFormat)},add:function(a,c){var d=c?b.duration(+c,a):b.duration(a);return L(this,d,1),this},subtract:function(a,c){var d=c?b.duration(+c,a):b.duration(a);return L(this,d,-1),this},diff:function(a,c,e){var f=this._isUTC?b(a).utc():b(a).local(),g=(this.zone()-f.zone())*6e4,h=this._d-f._d-g,i=this.year()-f.year(),j=this.month()-f.month(),k=this.date()-f.date(),l;return c==="months"?l=i*12+j+k/30:c==="years"?l=i+(j+k/30)/12:l=c==="seconds"?h/1e3:c==="minutes"?h/6e4:c==="hours"?h/36e5:c==="days"?h/864e5:c==="weeks"?h/6048e5:h,e?l:d(l)},from:function(a,c){return b.duration(this.diff(a)).lang(this._lang).humanize(!c)},fromNow:function(a){return this.from(b(),a)},calendar:function(){var a=this.diff(b().sod(),"days",!0),c=this.lang().calendar,d=c.sameElse,e=a<-6?d:a<-1?c.lastWeek:a<0?c.lastDay:a<1?c.sameDay:a<2?c.nextDay:a<7?c.nextWeek:d;return this.format(typeof e=="function"?e.apply(this):e)},isLeapYear:function(){var a=this.year();return a%4===0&&a%100!==0||a%400===0},isDST:function(){return this.zone()= 0) return url; 46 | if (server.indexOf("://") < 0) server = "http://" + server; 47 | if (server.substr(-1) == "/") { 48 | server = server.substr(0, server.length - 1); 49 | } 50 | if (url.charAt(0) === "/") url = url.substr(1); 51 | 52 | return server + "/" + url; 53 | } 54 | 55 | function callES(server, url, method, data, successCallback, completeCallback) { 56 | 57 | url = constructESUrl(server, url); 58 | var uname_password_re = /^(https?:\/\/)?(?:(?:(.*):)?(.*?)@)?(.*)$/; 59 | var url_parts = url.match(uname_password_re); 60 | 61 | var uname = url_parts[2]; 62 | var password = url_parts[3]; 63 | url = url_parts[1] + url_parts[4]; 64 | console.log("Calling " + url + " (uname: " + uname + " pwd: " + password + ")"); 65 | if (data && method == "GET") method = "POST"; 66 | 67 | $.ajax({ 68 | url: url, 69 | data: method == "GET" ? null : data, 70 | // xhrFields: { 71 | // withCredentials: true 72 | // }, 73 | // headers: { 74 | // "Authorization": "Basic " + btoa(uname + ":" + password) 75 | // }, 76 | // beforeSend: function(xhr){ 77 | // xhr.withCredentials = true; 78 | // xhr.setRequestHeader("Authorization", "Basic " + btoa(uname + ":" + password)); 79 | // }, 80 | 81 | password: password, 82 | username: uname, 83 | crossDomain: true, 84 | type: method, 85 | dataType: "json", 86 | complete: completeCallback, 87 | success: successCallback 88 | }); 89 | } 90 | 91 | function submitCurrentRequestToES() { 92 | var req = sense.utils.getCurrentRequest(); 93 | if (!req) return; 94 | 95 | $("#notification").text("Calling ES....").css("visibility", "visible"); 96 | sense.output.getSession().setValue(''); 97 | 98 | var es_server = $("#es_server").val(), 99 | es_url = req.url, 100 | es_method = req.method, 101 | es_data = req.data.join("\n"); 102 | if (es_data) es_data += "\n"; //append a new line for bulk requests. 103 | 104 | callES(es_server, es_url, es_method, es_data, null, function (xhr, status) { 105 | $("#notification").text("").css("visibility", "hidden"); 106 | if (typeof xhr.status == "number" && 107 | ((xhr.status >= 400 && xhr.status < 600) || 108 | (xhr.status >= 200 && xhr.status < 300) 109 | )) { 110 | // we have someone on the other side. Add to history 111 | sense.history.addToHistory(es_server, es_url, es_method, es_data); 112 | 113 | 114 | var value = xhr.responseText; 115 | try { 116 | value = JSON.stringify(JSON.parse(value), null, 3); 117 | } 118 | catch (e) { 119 | 120 | } 121 | sense.output.getSession().setValue(value); 122 | } 123 | else { 124 | sense.output.getSession().setValue("Request failed to get to the server (status code: " + xhr.status + "):" + xhr.responseText); 125 | } 126 | 127 | } 128 | ); 129 | 130 | saveEditorState(); 131 | 132 | _gaq.push(['_trackEvent', "elasticsearch", 'query']); 133 | } 134 | 135 | submitCurrentRequestToES = autoRetryIfTokenizing(submitCurrentRequestToES); 136 | 137 | function reformatData(data, indent) { 138 | var changed = false; 139 | var formatted_data = []; 140 | for (var i = 0; i < data.length; i++) { 141 | var cur_doc = data[i]; 142 | try { 143 | var new_doc = JSON.stringify(JSON.parse(cur_doc), null, indent ? 3 : 0); 144 | changed = changed || new_doc != cur_doc; 145 | formatted_data.push(new_doc); 146 | } 147 | catch (e) { 148 | console.log(e); 149 | formatted_data.push(cur_doc); 150 | } 151 | } 152 | 153 | return { changed: changed, data: formatted_data} 154 | } 155 | 156 | 157 | function autoIndent() { 158 | var req_range = sense.utils.getCurrentRequestRange(); 159 | if (!req_range) return; 160 | var parsed_req = sense.utils.getCurrentRequest(); 161 | if (parsed_req.data && parsed_req.data.length > 0) { 162 | var indent = parsed_req.data.length == 1; // unindent multi docs by default 163 | var formatted_data = reformatData(parsed_req.data, indent); 164 | if (!formatted_data.changed) { 165 | // toggle. 166 | formatted_data = reformatData(parsed_req.data, !indent); 167 | } 168 | parsed_req.data = formatted_data.data; 169 | 170 | sense.utils.replaceCurrentRequest(parsed_req, req_range); 171 | } 172 | } 173 | 174 | autoIndent = autoRetryIfTokenizing(autoIndent); 175 | 176 | function copyToClipboard(value) { 177 | var currentActive = document.activeElement; 178 | var clipboardStaging = $("#clipboardStaging"); 179 | clipboardStaging.val(value); 180 | clipboardStaging.select(); 181 | document.execCommand("Copy", false); 182 | $(currentActive).focus(); // restore focus. 183 | } 184 | 185 | function copyAsCURL() { 186 | var req = sense.utils.getCurrentRequest(); 187 | if (!req) return; 188 | 189 | _gaq.push(['_trackEvent', "curl", 'copied']); 190 | 191 | var es_server = $("#es_server").val(), 192 | es_url = req.url, 193 | es_method = req.method, 194 | es_data = req.data; 195 | 196 | var url = constructESUrl(es_server, es_url); 197 | 198 | var curl = 'curl -X' + es_method + ' "' + url + '"'; 199 | if (es_data && es_data.length) { 200 | curl += " -d'\n"; 201 | // since Sense doesn't allow single quote json string any single qoute is within a string. 202 | curl += es_data.join("\n").replace(/'/g, '\\"'); 203 | if (es_data.length > 1) curl += "\n"; // end with a new line 204 | curl += "'"; 205 | } 206 | 207 | //console.log(curl); 208 | copyToClipboard(curl); 209 | 210 | } 211 | 212 | copyAsCURL = autoRetryIfTokenizing(copyAsCURL, true); 213 | 214 | 215 | function handleCURLPaste(text) { 216 | _gaq.push(['_trackEvent', "curl", 'pasted']); 217 | var curlInput = sense.curl.parseCURL(text); 218 | if ($("#es_server").val()) curlInput.server = null; // do not override server 219 | 220 | if (!curlInput.method) curlInput.method = "GET"; 221 | 222 | sense.editor.insert(sense.utils.textFromRequest(curlInput)); 223 | 224 | } 225 | 226 | 227 | var CURRENT_REQ_RANGE = null; 228 | 229 | 230 | function saveEditorState() { 231 | try { 232 | var content = sense.editor.getValue(); 233 | var server = $("#es_server").val(); 234 | sense.history.saveCurrentEditorState(server, content); 235 | } 236 | catch (e) { 237 | console.log("Ignoring saving error: " + e) 238 | } 239 | } 240 | 241 | function updateEditorActionsBar() { 242 | var editor_actions = $("#editor_actions"); 243 | 244 | if (CURRENT_REQ_RANGE) { 245 | var row = CURRENT_REQ_RANGE.start.row; 246 | var column = CURRENT_REQ_RANGE.start.column; 247 | var session = sense.editor.session; 248 | var firstLine = session.getLine(row); 249 | var offset = 0; 250 | if (firstLine.length > session.getScreenWidth() - 5) { 251 | // overlap first row 252 | if (row > 0) row--; else row++; 253 | } 254 | var screen_pos = sense.editor.renderer.textToScreenCoordinates(row, column); 255 | offset += screen_pos.pageY - 3; 256 | var end_offset = sense.editor.renderer.textToScreenCoordinates(CURRENT_REQ_RANGE.end.row, 257 | CURRENT_REQ_RANGE.end.column).pageY; 258 | 259 | offset = Math.min(end_offset, Math.max(offset, 47)); 260 | if (offset >= 47) { 261 | editor_actions.css("top", Math.max(offset, 47)); 262 | editor_actions.css('visibility', 'visible'); 263 | } 264 | else { 265 | editor_actions.css("top", 0); 266 | editor_actions.css('visibility', 'hidden'); 267 | } 268 | } 269 | else { 270 | editor_actions.css("top", 0); 271 | editor_actions.css('visibility', 'hidden'); 272 | } 273 | 274 | } 275 | 276 | function highlighCurrentRequestAndUpdateActionBar() { 277 | var session = sense.editor.getSession(); 278 | var new_current_req_range = sense.utils.getCurrentRequestRange(); 279 | if (new_current_req_range == null && CURRENT_REQ_RANGE == null) return; 280 | if (new_current_req_range != null && CURRENT_REQ_RANGE != null && 281 | new_current_req_range.start.row == CURRENT_REQ_RANGE.start.row && 282 | new_current_req_range.end.row == CURRENT_REQ_RANGE.end.row 283 | ) { 284 | // same request, now see if we are on the first line and update the action bar 285 | var cursorRow = sense.editor.getCursorPosition().row; 286 | if (cursorRow == CURRENT_REQ_RANGE.start.row) { 287 | updateEditorActionsBar(); 288 | } 289 | return; // nothing to do.. 290 | } 291 | 292 | if (CURRENT_REQ_RANGE) { 293 | session.removeMarker(CURRENT_REQ_RANGE.marker_id); 294 | } 295 | 296 | CURRENT_REQ_RANGE = new_current_req_range; 297 | if (CURRENT_REQ_RANGE) { 298 | CURRENT_REQ_RANGE.marker_id = session.addMarker(CURRENT_REQ_RANGE, "ace_snippet-marker", "text"); 299 | } 300 | updateEditorActionsBar(); 301 | } 302 | 303 | highlighCurrentRequestAndUpdateActionBar = autoRetryIfTokenizing(highlighCurrentRequestAndUpdateActionBar, true); 304 | 305 | function moveToPreviousRequestEdge() { 306 | var pos = sense.editor.getCursorPosition(); 307 | for (pos.row--; pos.row > 0 && !sense.utils.isRequestEdge(pos.row); pos.row--) { 308 | } 309 | sense.editor.moveCursorTo(pos.row, 0); 310 | } 311 | 312 | moveToPreviousRequestEdge = autoRetryIfTokenizing(moveToPreviousRequestEdge); 313 | 314 | 315 | function moveToNextRequestEdge() { 316 | var pos = sense.editor.getCursorPosition(); 317 | var maxRow = sense.editor.getSession().getLength(); 318 | for (pos.row++; pos.row < maxRow && !sense.utils.isRequestEdge(pos.row); pos.row++) { 319 | } 320 | sense.editor.moveCursorTo(pos.row, 0); 321 | } 322 | 323 | moveToNextRequestEdge = autoRetryIfTokenizing(moveToNextRequestEdge); 324 | 325 | function init() { 326 | 327 | sense.editor = ace.edit("editor"); 328 | ace.require("ace/mode/sense"); 329 | sense.editor.getSession().setMode("ace/mode/sense"); 330 | sense.editor.setShowPrintMargin(false); 331 | sense.editor.getSession().setFoldStyle('markbeginend'); 332 | sense.editor.getSession().setUseWrapMode(true); 333 | sense.editor.commands.addCommand({ 334 | name: 'autocomplete', 335 | bindKey: {win: 'Ctrl-Space', mac: 'Ctrl-Space'}, 336 | exec: sense.autocomplete.editorAutocompleteCommand 337 | }); 338 | sense.editor.commands.addCommand({ 339 | name: 'auto indent request', 340 | bindKey: {win: 'Ctrl-I', mac: 'Command-I'}, 341 | exec: autoIndent 342 | }); 343 | sense.editor.commands.addCommand({ 344 | name: 'send to elasticsearch', 345 | bindKey: {win: 'Ctrl-Enter', mac: 'Command-Enter'}, 346 | exec: submitCurrentRequestToES 347 | }); 348 | 349 | sense.editor.commands.addCommand({ 350 | name: 'copy as cUrl', 351 | bindKey: {win: 'Ctrl-Shift-C', mac: 'Command-Shift-C'}, 352 | exec: copyAsCURL 353 | }); 354 | 355 | sense.editor.commands.addCommand({ 356 | name: 'move to previous request start or end', 357 | bindKey: {win: 'Ctrl-Up', mac: 'Command-Up'}, 358 | exec: moveToPreviousRequestEdge 359 | }); 360 | 361 | sense.editor.commands.addCommand({ 362 | name: 'move to next request start or end', 363 | bindKey: {win: 'Ctrl-Down', mac: 'Command-Down'}, 364 | exec: moveToNextRequestEdge 365 | }); 366 | 367 | 368 | var orig_paste = sense.editor.onPaste; 369 | sense.editor.onPaste = function (text) { 370 | if (text && sense.curl.detectCURL(text)) { 371 | handleCURLPaste(text); 372 | return; 373 | } 374 | orig_paste.call(this, text); 375 | }; 376 | 377 | sense.editor.getSession().on('tokenizerUpdate', function (e) { 378 | highlighCurrentRequestAndUpdateActionBar(); 379 | }); 380 | 381 | sense.editor.getSession().selection.on('changeCursor', function (e) { 382 | highlighCurrentRequestAndUpdateActionBar(); 383 | }); 384 | 385 | 386 | var save_generation = 0; 387 | 388 | function get_save_callback(for_generation) { 389 | return function () { 390 | if (save_generation == for_generation) { 391 | saveEditorState(); 392 | } 393 | } 394 | } 395 | 396 | sense.editor.getSession().on("change", function (e) { 397 | setTimeout(get_save_callback(++save_generation), 500); 398 | }); 399 | 400 | sense.editor.getSession().on("changeScrollTop", updateEditorActionsBar); 401 | 402 | 403 | sense.output = ace.edit("output"); 404 | sense.output.getSession().setMode("ace/mode/json"); 405 | sense.output.getSession().setFoldStyle('markbeginend'); 406 | sense.output.setTheme("ace/theme/monokai"); 407 | sense.output.getSession().setUseWrapMode(true); 408 | sense.output.setShowPrintMargin(false); 409 | sense.output.setReadOnly(true); 410 | 411 | var editorElement = $("#editor"), 412 | outputElement = $("#output"), 413 | editorActions = $("#editor_actions"); 414 | 415 | 416 | editorElement.resizable( 417 | { 418 | autoHide: false, 419 | handles: 'e', 420 | start: function (e, ui) { 421 | editor_resizebar = $(".ui-resizable-e").addClass("active"); 422 | }, 423 | stop: function (e, ui) { 424 | editor_resizebar = $(".ui-resizable-e").removeClass("active"); 425 | 426 | var parent = ui.element.parent(); 427 | var editorSize = ui.element.outerWidth(); 428 | outputElement.css("left", editorSize); 429 | editorActions.css("margin-right", -editorSize + 3); 430 | sense.editor.resize(true); 431 | sense.output.resize(true); 432 | } 433 | }); 434 | 435 | sense.history.init(); 436 | sense.autocomplete.init(); 437 | 438 | $("#send").tooltip(); 439 | $("#send").click(function () { 440 | submitCurrentRequestToES(); 441 | return false; 442 | }); 443 | 444 | $("#copy_as_curl").click(function (e) { 445 | copyAsCURL(); 446 | e.preventDefault(); 447 | }); 448 | 449 | $("#auto_indent").click(function (e) { 450 | autoIndent(); 451 | e.preventDefault(); 452 | }); 453 | 454 | var help_popup = $("#help_popup"); 455 | 456 | help_popup.on('shown', function () { 457 | _gaq.push(['_trackEvent', "help", 'shown']); 458 | $('
    PUT index/type/1\n' 459 | + '{\n' 460 | + ' "body": "here"\n' 461 | + '}\n\n' 462 | + 'GET index/type/1\n' 463 | + '
    ').appendTo(help_popup.find("#example_editor_container")); 464 | 465 | var example_editor = ace.edit("example_editor"); 466 | example_editor.getSession().setMode("ace/mode/sense"); 467 | example_editor.getSession().setFoldStyle('markbeginend'); 468 | example_editor.setReadOnly(true); 469 | example_editor.renderer.setShowPrintMargin(false); 470 | }); 471 | 472 | help_popup.on('hidden', function () { 473 | help_popup.find('#example_editor').remove(); 474 | 475 | }); 476 | 477 | 478 | var es_server = $("#es_server"); 479 | 480 | es_server.blur(function () { 481 | sense.mappings.notifyServerChange(es_server.val()); 482 | }); 483 | 484 | var editor_source = sense.utils.getUrlParam('load_from') || "stored"; 485 | var last_editor_state = sense.history.getSavedEditorState(); 486 | if (editor_source == "stored") { 487 | if (last_editor_state) { 488 | resetToValues(last_editor_state.server, last_editor_state.content); 489 | } 490 | else { 491 | autoIndent(); 492 | } 493 | } 494 | else if (/^https?:\/\//.exec(editor_source)) { 495 | $.get(editor_source, null, function (data) { 496 | resetToValues(null, data); 497 | highlighCurrentRequestAndUpdateActionBar(); 498 | updateEditorActionsBar(); 499 | }); 500 | } 501 | else { 502 | if (last_editor_state) { 503 | resetToValues(last_editor_state.server); 504 | } 505 | } 506 | 507 | if (document.location.pathname && document.location.pathname.indexOf("_plugin") == 1) { 508 | // running as an ES plugin. Always assume we are using that elasticsearch 509 | resetToValues(document.location.host); 510 | } 511 | 512 | sense.editor.focus(); 513 | highlighCurrentRequestAndUpdateActionBar(); 514 | updateEditorActionsBar(); 515 | 516 | if (!localStorage.getItem("version_welcome_shown")) { 517 | localStorage.setItem("version_welcome_shown", sense.VERSION); 518 | var welcome_popup = $("#welcome_popup"); 519 | welcome_popup.modal(); 520 | welcome_popup.on('shown', function () { 521 | $('
    PUT index/type/1\n' 522 | + '{\n' 523 | + ' "body": "here"\n' 524 | + '}\n\n' 525 | + 'GET index/type/1\n' 526 | + '
    ').appendTo(welcome_popup.find("#example_editor_container")); 527 | 528 | var example_editor = ace.edit("example_editor"); 529 | example_editor.getSession().setMode("ace/mode/sense"); 530 | example_editor.getSession().setFoldStyle('markbeginend'); 531 | example_editor.setReadOnly(true); 532 | example_editor.renderer.setShowPrintMargin(false); 533 | }); 534 | 535 | welcome_popup.on('hidden', function () { 536 | welcome_popup.find('#example_editor').remove(); 537 | 538 | }); 539 | // welcome_popup.modal('show'); 540 | 541 | } 542 | } 543 | 544 | $(document).ready(init); 545 | 546 | /* google analytics */ 547 | var _gaq = _gaq || []; 548 | _gaq.push(['_setAccount', 'UA-11830182-16']); 549 | _gaq.push(['_setCustomVar', 550 | 1, // This custom var is set to slot #1. Required parameter. 551 | 'Version', // The name of the custom variable. Required parameter. 552 | sense.VERSION, // The value of the custom variable. Required parameter. 553 | 1 // Sets the scope to visitor-level. Optional parameter. 554 | ]); 555 | 556 | _gaq.push(['_trackPageview']); 557 | 558 | (function () { 559 | var ga = document.createElement('script'); 560 | ga.type = 'text/javascript'; 561 | ga.async = true; 562 | ga.src = 'https://ssl.google-analytics.com/ga.js'; 563 | var s = document.getElementsByTagName('script')[0]; 564 | s.parentNode.insertBefore(ga, s); 565 | })(); 566 | 567 | -------------------------------------------------------------------------------- /lib/src-noconflict/mode-json.js: -------------------------------------------------------------------------------- 1 | /* ***** BEGIN LICENSE BLOCK ***** 2 | * Distributed under the BSD license: 3 | * 4 | * Copyright (c) 2010, Ajax.org B.V. 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Ajax.org B.V. nor the 15 | * names of its contributors may be used to endorse or promote products 16 | * derived from this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * ***** END LICENSE BLOCK ***** */ 30 | 31 | ace.define('ace/mode/json', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/text', 'ace/tokenizer', 'ace/mode/json_highlight_rules', 'ace/mode/matching_brace_outdent', 'ace/mode/behaviour/cstyle', 'ace/mode/folding/cstyle', 'ace/worker/worker_client'], function(require, exports, module) { 32 | 33 | 34 | var oop = require("../lib/oop"); 35 | var TextMode = require("./text").Mode; 36 | var Tokenizer = require("../tokenizer").Tokenizer; 37 | var HighlightRules = require("./json_highlight_rules").JsonHighlightRules; 38 | var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; 39 | var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; 40 | var CStyleFoldMode = require("./folding/cstyle").FoldMode; 41 | var WorkerClient = require("../worker/worker_client").WorkerClient; 42 | 43 | var Mode = function() { 44 | this.$tokenizer = new Tokenizer(new HighlightRules().getRules()); 45 | this.$outdent = new MatchingBraceOutdent(); 46 | this.$behaviour = new CstyleBehaviour(); 47 | this.foldingRules = new CStyleFoldMode(); 48 | }; 49 | oop.inherits(Mode, TextMode); 50 | 51 | (function() { 52 | 53 | this.getNextLineIndent = function(state, line, tab) { 54 | var indent = this.$getIndent(line); 55 | 56 | if (state == "start") { 57 | var match = line.match(/^.*[\{\(\[]\s*$/); 58 | if (match) { 59 | indent += tab; 60 | } 61 | } 62 | 63 | return indent; 64 | }; 65 | 66 | this.checkOutdent = function(state, line, input) { 67 | return this.$outdent.checkOutdent(line, input); 68 | }; 69 | 70 | this.autoOutdent = function(state, doc, row) { 71 | this.$outdent.autoOutdent(doc, row); 72 | }; 73 | 74 | this.createWorker = function(session) { 75 | var worker = new WorkerClient(["ace"], "ace/mode/json_worker", "JsonWorker"); 76 | worker.attachToDocument(session.getDocument()); 77 | 78 | worker.on("error", function(e) { 79 | session.setAnnotations([e.data]); 80 | }); 81 | 82 | worker.on("ok", function() { 83 | session.clearAnnotations(); 84 | }); 85 | 86 | return worker; 87 | }; 88 | 89 | 90 | }).call(Mode.prototype); 91 | 92 | exports.Mode = Mode; 93 | }); 94 | 95 | ace.define('ace/mode/json_highlight_rules', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/text_highlight_rules'], function(require, exports, module) { 96 | 97 | 98 | var oop = require("../lib/oop"); 99 | var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; 100 | 101 | var JsonHighlightRules = function() { 102 | this.$rules = { 103 | "start" : [ 104 | { 105 | token : "variable", // single line 106 | regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]\\s*(?=:)' 107 | }, { 108 | token : "string", // single line 109 | regex : '"', 110 | next : "string" 111 | }, { 112 | token : "constant.numeric", // hex 113 | regex : "0[xX][0-9a-fA-F]+\\b" 114 | }, { 115 | token : "constant.numeric", // float 116 | regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" 117 | }, { 118 | token : "constant.language.boolean", 119 | regex : "(?:true|false)\\b" 120 | }, { 121 | token : "invalid.illegal", // single quoted strings are not allowed 122 | regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" 123 | }, { 124 | token : "invalid.illegal", // comments are not allowed 125 | regex : "\\/\\/.*$" 126 | }, { 127 | token : "paren.lparen", 128 | regex : "[[({]" 129 | }, { 130 | token : "paren.rparen", 131 | regex : "[\\])}]" 132 | }, { 133 | token : "text", 134 | regex : "\\s+" 135 | } 136 | ], 137 | "string" : [ 138 | { 139 | token : "constant.language.escape", 140 | regex : /\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|["\\\/bfnrt])/ 141 | }, { 142 | token : "string", 143 | regex : '[^"\\\\]+', 144 | merge : true 145 | }, { 146 | token : "string", 147 | regex : '"', 148 | next : "start", 149 | merge : true 150 | }, { 151 | token : "string", 152 | regex : "", 153 | next : "start", 154 | merge : true 155 | } 156 | ] 157 | }; 158 | 159 | }; 160 | 161 | oop.inherits(JsonHighlightRules, TextHighlightRules); 162 | 163 | exports.JsonHighlightRules = JsonHighlightRules; 164 | }); 165 | 166 | ace.define('ace/mode/matching_brace_outdent', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) { 167 | 168 | 169 | var Range = require("../range").Range; 170 | 171 | var MatchingBraceOutdent = function() {}; 172 | 173 | (function() { 174 | 175 | this.checkOutdent = function(line, input) { 176 | if (! /^\s+$/.test(line)) 177 | return false; 178 | 179 | return /^\s*\}/.test(input); 180 | }; 181 | 182 | this.autoOutdent = function(doc, row) { 183 | var line = doc.getLine(row); 184 | var match = line.match(/^(\s*\})/); 185 | 186 | if (!match) return 0; 187 | 188 | var column = match[1].length; 189 | var openBracePos = doc.findMatchingBracket({row: row, column: column}); 190 | 191 | if (!openBracePos || openBracePos.row == row) return 0; 192 | 193 | var indent = this.$getIndent(doc.getLine(openBracePos.row)); 194 | doc.replace(new Range(row, 0, row, column-1), indent); 195 | }; 196 | 197 | this.$getIndent = function(line) { 198 | var match = line.match(/^(\s+)/); 199 | if (match) { 200 | return match[1]; 201 | } 202 | 203 | return ""; 204 | }; 205 | 206 | }).call(MatchingBraceOutdent.prototype); 207 | 208 | exports.MatchingBraceOutdent = MatchingBraceOutdent; 209 | }); 210 | 211 | ace.define('ace/mode/behaviour/cstyle', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/behaviour', 'ace/token_iterator'], function(require, exports, module) { 212 | 213 | 214 | var oop = require("../../lib/oop"); 215 | var Behaviour = require("../behaviour").Behaviour; 216 | var TokenIterator = require("../../token_iterator").TokenIterator; 217 | 218 | var autoInsertedBrackets = 0; 219 | var autoInsertedRow = -1; 220 | var autoInsertedLineEnd = ""; 221 | 222 | var CstyleBehaviour = function () { 223 | 224 | CstyleBehaviour.isSaneInsertion = function(editor, session) { 225 | var cursor = editor.getCursorPosition(); 226 | var iterator = new TokenIterator(session, cursor.row, cursor.column); 227 | if (!this.$matchTokenType(iterator.getCurrentToken() || "text", ["text", "paren.rparen"])) { 228 | iterator = new TokenIterator(session, cursor.row, cursor.column + 1); 229 | if (!this.$matchTokenType(iterator.getCurrentToken() || "text", ["text", "paren.rparen"])) 230 | return false; 231 | } 232 | iterator.stepForward(); 233 | return iterator.getCurrentTokenRow() !== cursor.row || 234 | this.$matchTokenType(iterator.getCurrentToken() || "text", ["text", "comment", "paren.rparen"]); 235 | }; 236 | 237 | CstyleBehaviour.$matchTokenType = function(token, types) { 238 | return types.indexOf(token.type || token) > -1; 239 | }; 240 | 241 | CstyleBehaviour.recordAutoInsert = function(editor, session, bracket) { 242 | var cursor = editor.getCursorPosition(); 243 | var line = session.doc.getLine(cursor.row); 244 | if (!this.isAutoInsertedClosing(cursor, line, autoInsertedLineEnd[0])) 245 | autoInsertedBrackets = 0; 246 | autoInsertedRow = cursor.row; 247 | autoInsertedLineEnd = bracket + line.substr(cursor.column); 248 | autoInsertedBrackets++; 249 | }; 250 | 251 | CstyleBehaviour.isAutoInsertedClosing = function(cursor, line, bracket) { 252 | return autoInsertedBrackets > 0 && 253 | cursor.row === autoInsertedRow && 254 | bracket === autoInsertedLineEnd[0] && 255 | line.substr(cursor.column) === autoInsertedLineEnd; 256 | }; 257 | 258 | CstyleBehaviour.popAutoInsertedClosing = function() { 259 | autoInsertedLineEnd = autoInsertedLineEnd.substr(1); 260 | autoInsertedBrackets--; 261 | }; 262 | 263 | this.add("braces", "insertion", function (state, action, editor, session, text) { 264 | if (text == '{') { 265 | var selection = editor.getSelectionRange(); 266 | var selected = session.doc.getTextRange(selection); 267 | if (selected !== "" && selected !== "{") { 268 | return { 269 | text: '{' + selected + '}', 270 | selection: false 271 | }; 272 | } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { 273 | CstyleBehaviour.recordAutoInsert(editor, session, "}"); 274 | return { 275 | text: '{}', 276 | selection: [1, 1] 277 | }; 278 | } 279 | } else if (text == '}') { 280 | var cursor = editor.getCursorPosition(); 281 | var line = session.doc.getLine(cursor.row); 282 | var rightChar = line.substring(cursor.column, cursor.column + 1); 283 | if (rightChar == '}') { 284 | var matching = session.$findOpeningBracket('}', {column: cursor.column + 1, row: cursor.row}); 285 | if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { 286 | CstyleBehaviour.popAutoInsertedClosing(); 287 | return { 288 | text: '', 289 | selection: [1, 1] 290 | }; 291 | } 292 | } 293 | } else if (text == "\n" || text == "\r\n") { 294 | var cursor = editor.getCursorPosition(); 295 | var line = session.doc.getLine(cursor.row); 296 | var rightChar = line.substring(cursor.column, cursor.column + 1); 297 | if (rightChar == '}') { 298 | var openBracePos = session.findMatchingBracket({row: cursor.row, column: cursor.column + 1}); 299 | if (!openBracePos) 300 | return null; 301 | 302 | var indent = this.getNextLineIndent(state, line.substring(0, line.length - 1), session.getTabString()); 303 | var next_indent = this.$getIndent(session.doc.getLine(openBracePos.row)); 304 | 305 | return { 306 | text: '\n' + indent + '\n' + next_indent, 307 | selection: [1, indent.length, 1, indent.length] 308 | }; 309 | } 310 | } 311 | }); 312 | 313 | this.add("braces", "deletion", function (state, action, editor, session, range) { 314 | var selected = session.doc.getTextRange(range); 315 | if (!range.isMultiLine() && selected == '{') { 316 | var line = session.doc.getLine(range.start.row); 317 | var rightChar = line.substring(range.end.column, range.end.column + 1); 318 | if (rightChar == '}') { 319 | range.end.column++; 320 | return range; 321 | } 322 | } 323 | }); 324 | 325 | this.add("parens", "insertion", function (state, action, editor, session, text) { 326 | if (text == '(') { 327 | var selection = editor.getSelectionRange(); 328 | var selected = session.doc.getTextRange(selection); 329 | if (selected !== "") { 330 | return { 331 | text: '(' + selected + ')', 332 | selection: false 333 | }; 334 | } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { 335 | CstyleBehaviour.recordAutoInsert(editor, session, ")"); 336 | return { 337 | text: '()', 338 | selection: [1, 1] 339 | }; 340 | } 341 | } else if (text == ')') { 342 | var cursor = editor.getCursorPosition(); 343 | var line = session.doc.getLine(cursor.row); 344 | var rightChar = line.substring(cursor.column, cursor.column + 1); 345 | if (rightChar == ')') { 346 | var matching = session.$findOpeningBracket(')', {column: cursor.column + 1, row: cursor.row}); 347 | if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { 348 | CstyleBehaviour.popAutoInsertedClosing(); 349 | return { 350 | text: '', 351 | selection: [1, 1] 352 | }; 353 | } 354 | } 355 | } 356 | }); 357 | 358 | this.add("parens", "deletion", function (state, action, editor, session, range) { 359 | var selected = session.doc.getTextRange(range); 360 | if (!range.isMultiLine() && selected == '(') { 361 | var line = session.doc.getLine(range.start.row); 362 | var rightChar = line.substring(range.start.column + 1, range.start.column + 2); 363 | if (rightChar == ')') { 364 | range.end.column++; 365 | return range; 366 | } 367 | } 368 | }); 369 | 370 | this.add("brackets", "insertion", function (state, action, editor, session, text) { 371 | if (text == '[') { 372 | var selection = editor.getSelectionRange(); 373 | var selected = session.doc.getTextRange(selection); 374 | if (selected !== "") { 375 | return { 376 | text: '[' + selected + ']', 377 | selection: false 378 | }; 379 | } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { 380 | CstyleBehaviour.recordAutoInsert(editor, session, "]"); 381 | return { 382 | text: '[]', 383 | selection: [1, 1] 384 | }; 385 | } 386 | } else if (text == ']') { 387 | var cursor = editor.getCursorPosition(); 388 | var line = session.doc.getLine(cursor.row); 389 | var rightChar = line.substring(cursor.column, cursor.column + 1); 390 | if (rightChar == ']') { 391 | var matching = session.$findOpeningBracket(']', {column: cursor.column + 1, row: cursor.row}); 392 | if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { 393 | CstyleBehaviour.popAutoInsertedClosing(); 394 | return { 395 | text: '', 396 | selection: [1, 1] 397 | }; 398 | } 399 | } 400 | } 401 | }); 402 | 403 | this.add("brackets", "deletion", function (state, action, editor, session, range) { 404 | var selected = session.doc.getTextRange(range); 405 | if (!range.isMultiLine() && selected == '[') { 406 | var line = session.doc.getLine(range.start.row); 407 | var rightChar = line.substring(range.start.column + 1, range.start.column + 2); 408 | if (rightChar == ']') { 409 | range.end.column++; 410 | return range; 411 | } 412 | } 413 | }); 414 | 415 | this.add("string_dquotes", "insertion", function (state, action, editor, session, text) { 416 | if (text == '"' || text == "'") { 417 | var quote = text; 418 | var selection = editor.getSelectionRange(); 419 | var selected = session.doc.getTextRange(selection); 420 | if (selected !== "") { 421 | return { 422 | text: quote + selected + quote, 423 | selection: false 424 | }; 425 | } else { 426 | var cursor = editor.getCursorPosition(); 427 | var line = session.doc.getLine(cursor.row); 428 | var leftChar = line.substring(cursor.column-1, cursor.column); 429 | if (leftChar == '\\') { 430 | return null; 431 | } 432 | var tokens = session.getTokens(selection.start.row); 433 | var col = 0, token; 434 | var quotepos = -1; // Track whether we're inside an open quote. 435 | 436 | for (var x = 0; x < tokens.length; x++) { 437 | token = tokens[x]; 438 | if (token.type == "string") { 439 | quotepos = -1; 440 | } else if (quotepos < 0) { 441 | quotepos = token.value.indexOf(quote); 442 | } 443 | if ((token.value.length + col) > selection.start.column) { 444 | break; 445 | } 446 | col += tokens[x].value.length; 447 | } 448 | if (!token || (quotepos < 0 && token.type !== "comment" && (token.type !== "string" || ((selection.start.column !== token.value.length+col-1) && token.value.lastIndexOf(quote) === token.value.length-1)))) { 449 | return { 450 | text: quote + quote, 451 | selection: [1,1] 452 | }; 453 | } else if (token && token.type === "string") { 454 | var rightChar = line.substring(cursor.column, cursor.column + 1); 455 | if (rightChar == quote) { 456 | return { 457 | text: '', 458 | selection: [1, 1] 459 | }; 460 | } 461 | } 462 | } 463 | } 464 | }); 465 | 466 | this.add("string_dquotes", "deletion", function (state, action, editor, session, range) { 467 | var selected = session.doc.getTextRange(range); 468 | if (!range.isMultiLine() && (selected == '"' || selected == "'")) { 469 | var line = session.doc.getLine(range.start.row); 470 | var rightChar = line.substring(range.start.column + 1, range.start.column + 2); 471 | if (rightChar == '"') { 472 | range.end.column++; 473 | return range; 474 | } 475 | } 476 | }); 477 | 478 | }; 479 | 480 | oop.inherits(CstyleBehaviour, Behaviour); 481 | 482 | exports.CstyleBehaviour = CstyleBehaviour; 483 | }); 484 | 485 | ace.define('ace/mode/folding/cstyle', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/range', 'ace/mode/folding/fold_mode'], function(require, exports, module) { 486 | 487 | 488 | var oop = require("../../lib/oop"); 489 | var Range = require("../../range").Range; 490 | var BaseFoldMode = require("./fold_mode").FoldMode; 491 | 492 | var FoldMode = exports.FoldMode = function() {}; 493 | oop.inherits(FoldMode, BaseFoldMode); 494 | 495 | (function() { 496 | 497 | this.foldingStartMarker = /(\{|\[)[^\}\]]*$|^\s*(\/\*)/; 498 | this.foldingStopMarker = /^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/; 499 | 500 | this.getFoldWidgetRange = function(session, foldStyle, row) { 501 | var line = session.getLine(row); 502 | var match = line.match(this.foldingStartMarker); 503 | if (match) { 504 | var i = match.index; 505 | 506 | if (match[1]) 507 | return this.openingBracketBlock(session, match[1], row, i); 508 | 509 | return session.getCommentFoldRange(row, i + match[0].length, 1); 510 | } 511 | 512 | if (foldStyle !== "markbeginend") 513 | return; 514 | 515 | var match = line.match(this.foldingStopMarker); 516 | if (match) { 517 | var i = match.index + match[0].length; 518 | 519 | if (match[1]) 520 | return this.closingBracketBlock(session, match[1], row, i); 521 | 522 | return session.getCommentFoldRange(row, i, -1); 523 | } 524 | }; 525 | 526 | }).call(FoldMode.prototype); 527 | 528 | }); 529 | -------------------------------------------------------------------------------- /lib/bootstrap/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap.js by @fat & @mdo 3 | * Copyright 2012 Twitter, Inc. 4 | * http://www.apache.org/licenses/LICENSE-2.0.txt 5 | */ 6 | !function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()},e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")},e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=n,this.options.slide&&this.slide(this.options.slide),this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},to:function(t){var n=this.$element.find(".item.active"),r=n.parent().children(),i=r.index(n),s=this;if(t>r.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){s.to(t)}):i==t?this.pause().cycle():this.slide(t>i?"next":"prev",e(r[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle()),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0]});if(i.hasClass("active"))return;if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}},e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e(document).on("click.carousel.data-api","[data-slide]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data());i.carousel(s),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning)return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning)return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=typeof n=="object"&&n;i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;return n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=e(n),r.length||(r=t.parent()),r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||(s.toggleClass("open"),n.focus()),!1},keydown:function(t){var n,r,s,o,u,a;if(!/(38|40|27)/.test(t.keyCode))return;n=e(this),t.preventDefault(),t.stopPropagation();if(n.is(".disabled, :disabled"))return;o=i(n),u=o.hasClass("open");if(!u||u&&t.keyCode==27)return n.click();r=e("[role=menu] li:not(.divider) a",o);if(!r.length)return;a=r.index(r.filter(":focus")),t.keyCode==38&&a>0&&a--,t.keyCode==40&&a').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,e.proxy(this.removeBackdrop,this)):this.removeBackdrop()):t&&t()}},e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,this.options.trigger=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):this.options.trigger!="manual"&&(i=this.options.trigger=="hover"?"mouseenter":"focus",s=this.options.trigger=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this))),this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,t,this.$element.data()),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);if(!n.options.delay||!n.options.delay.show)return n.show();clearTimeout(this.timeout),n.hoverState="in",this.timeout=setTimeout(function(){n.hoverState=="in"&&n.show()},n.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var e,t,n,r,i,s,o;if(this.hasContent()&&this.enabled){e=this.tip(),this.setContent(),this.options.animation&&e.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,e[0],this.$element[0]):this.options.placement,t=/in/.test(s),e.detach().css({top:0,left:0,display:"block"}).insertAfter(this.$element),n=this.getPosition(t),r=e[0].offsetWidth,i=e[0].offsetHeight;switch(t?s.split(" ")[1]:s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}e.offset(o).addClass(s).addClass("in")}},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function r(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip();return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?r():n.detach(),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(t){return e.extend({},t?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);n[n.tip().hasClass("in")?"hide":"show"]()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}},e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'
    ',trigger:"hover",title:"",delay:0,html:!1}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content > *")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-content")||(typeof n.content=="function"?n.content.call(t[0]):n.content),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}}),e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'

    '})}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var t=e(this),n=t.data("target")||t.attr("href"),r=/^#\w/.test(n)&&e(n);return r&&r.length&&[[r.position().top,n]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}},e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active:last a")[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}},e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=e(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:t.top+t.height,left:t.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length"+t+""})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=!~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},blur:function(e){var t=this;setTimeout(function(){t.hide()},150)},click:function(e){e.stopPropagation(),e.preventDefault(),this.select()},mouseenter:function(t){this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")}},e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1},e.fn.typeahead.Constructor=t,e(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;t.preventDefault(),n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)).on("click.affix.data-api",e.proxy(function(){setTimeout(e.proxy(this.checkPosition,this),1)},this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))},e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery); --------------------------------------------------------------------------------