├── .gitignore
├── Cargo.toml
├── LICENSE
├── README.md
├── TODO.md
├── exar-client
├── Cargo.toml
├── README.md
└── src
│ └── lib.rs
├── exar-core
├── Cargo.toml
├── README.md
├── benches
│ └── database.rs
├── src
│ ├── collection.rs
│ ├── config.rs
│ ├── connection.rs
│ ├── database.rs
│ ├── encoding.rs
│ ├── error.rs
│ ├── event.rs
│ ├── lib.rs
│ ├── log.rs
│ ├── logger.rs
│ ├── query.rs
│ ├── routing_strategy.rs
│ ├── scanner.rs
│ ├── subscription.rs
│ ├── util.rs
│ └── validation.rs
└── tests
│ └── lib.rs
├── exar-db
├── Cargo.toml
├── README.md
├── log4rs.toml
└── src
│ ├── config.rs
│ └── main.rs
├── exar-net
├── Cargo.toml
├── README.md
└── src
│ ├── lib.rs
│ ├── message.rs
│ └── stream.rs
├── exar-server
├── Cargo.toml
├── README.md
└── src
│ ├── config.rs
│ ├── credentials.rs
│ ├── handler.rs
│ ├── lib.rs
│ └── server.rs
├── exar-testkit
├── Cargo.toml
└── src
│ ├── collections.rs
│ ├── encoding.rs
│ ├── lib.rs
│ └── net.rs
├── exar-ui
├── .gitignore
├── .npmignore
├── README.md
├── aurelia.protractor.js
├── build.sh
├── build
│ ├── args.js
│ ├── bundles.js
│ ├── export.js
│ ├── paths.js
│ └── tasks
│ │ ├── build.js
│ │ ├── bundle.js
│ │ ├── clean.js
│ │ ├── dev.js
│ │ ├── e2e.js
│ │ ├── export-release.js
│ │ ├── lint.js
│ │ ├── prepare-release.js
│ │ ├── serve.js
│ │ ├── test.js
│ │ └── watch.js
├── config.js
├── custom_typings
│ ├── rx.lite.d.ts
│ ├── tcp-socket.d.ts
│ └── text-encoding.d.ts
├── gulpfile.js
├── index.html
├── index.js
├── karma.conf.js
├── package.json
├── protractor.conf.js
├── src
│ ├── app.html
│ ├── app.ts
│ ├── components
│ │ ├── dialogs
│ │ │ ├── edit-connection.html
│ │ │ └── edit-connection.ts
│ │ └── layout
│ │ │ ├── nav-bar.html
│ │ │ └── nav-bar.ts
│ ├── converters
│ │ └── obfuscate.ts
│ ├── exar
│ │ ├── client.ts
│ │ ├── model.ts
│ │ └── net.ts
│ ├── main.ts
│ ├── models
│ │ └── saved-connection.ts
│ └── views
│ │ ├── connection-handler.html
│ │ ├── connection-handler.ts
│ │ ├── home.html
│ │ ├── home.ts
│ │ ├── manage-connections.html
│ │ └── manage-connections.ts
├── styles
│ └── styles.css
├── test
│ └── unit
│ │ ├── app.spec.ts
│ │ └── setup.ts
├── tsconfig.json
├── tsd.json
├── tslint.json
├── typings.json
├── typings
│ ├── globals
│ │ ├── angular-protractor
│ │ │ ├── index.d.ts
│ │ │ └── typings.json
│ │ ├── aurelia-protractor
│ │ │ ├── index.d.ts
│ │ │ └── typings.json
│ │ ├── bootstrap
│ │ │ ├── index.d.ts
│ │ │ └── typings.json
│ │ ├── jasmine
│ │ │ ├── index.d.ts
│ │ │ └── typings.json
│ │ ├── jquery
│ │ │ ├── index.d.ts
│ │ │ └── typings.json
│ │ ├── selenium-webdriver
│ │ │ ├── index.d.ts
│ │ │ └── typings.json
│ │ ├── url
│ │ │ ├── index.d.ts
│ │ │ └── typings.json
│ │ └── whatwg-fetch
│ │ │ ├── index.d.ts
│ │ │ └── typings.json
│ ├── index.d.ts
│ └── modules
│ │ ├── aurelia-animator-css
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-binding
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-bootstrapper-webpack
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-bootstrapper
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-dependency-injection
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-dialog
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-event-aggregator
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-fetch-client
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-framework
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-history-browser
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-history
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-loader-webpack
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-loader
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-logging-console
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-logging
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-metadata
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-pal-browser
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-pal
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-path
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-polyfills
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-route-recognizer
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-router
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-task-queue
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-templating-binding
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-templating-resources
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ ├── aurelia-templating-router
│ │ ├── index.d.ts
│ │ └── typings.json
│ │ └── aurelia-templating
│ │ ├── index.d.ts
│ │ └── typings.json
└── wallaby.js
└── test-all
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled files
2 | *.o
3 | *.so
4 | *.rlib
5 | *.dll
6 |
7 | # Executables
8 | *.exe
9 |
10 | # Generated by Cargo
11 | target/
12 |
13 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
14 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
15 | Cargo.lock
16 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | members = [
3 | "exar-core",
4 | "exar-testkit",
5 | "exar-net",
6 | "exar-client",
7 | "exar-server",
8 | "exar-db"
9 | ]
10 |
11 | [profile.release]
12 | debug = true
13 | opt-level = 3
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Exar DB
2 |
3 | An event store with streaming support, it uses flat-file based collections.
4 |
5 | ## Modules
6 |
7 | The database is split into the following modules:
8 |
9 | - [exar-core](https://github.com/bfil/exar-db/tree/master/exar-core): the core engine of Exar DB
10 | - [exar-net](https://github.com/bfil/exar-db/tree/master/exar-net): a TCP protocol for Exar DB
11 | - [exar-server](https://github.com/bfil/exar-db/tree/master/exar-server): a TCP server built on top of `exar-net`
12 | - [exar-client](https://github.com/bfil/exar-db/tree/master/exar-client): a TCP client built on top of `exar-net`
13 | - [exar-db](https://github.com/bfil/exar-db/tree/master/exar-db): the main executable of Exar DB
14 |
15 | ## Installation
16 |
17 | Install [`Cargo`](https://crates.io/install), then run:
18 |
19 | ```
20 | cargo install exar-db
21 | ```
22 |
23 | ## Starting the database
24 |
25 | Simply run `exar-db`.
26 |
27 | ## Configuring the database
28 |
29 | The database can be configured using a `TOML` configuration file, example below:
30 |
31 | ```toml
32 | log4rs_path = "/path/to/log4rs.toml"
33 | [database]
34 | logs_path = "~/exar-db/data"
35 | scanners = { nr_of_scanners = 2, sleep_time_in_ms = 10 }
36 | [database.collections.my-collection]
37 | routing_strategy = "Random"
38 | scanners = { nr_of_scanners = 4, sleep_time_in_ms = 5 }
39 | [server]
40 | host = "127.0.0.1"
41 | port = 38580
42 | username = "my-username"
43 | password = "my-secret"
44 | ```
45 |
46 | Then run Exar DB by specifying the config file location: `exar-db --config=/path/to/config.toml`.
47 |
48 | For more information about the `database` and `server` configuration sections,
49 | check the documentation about
50 | [DatabaseConfig](https://bfil.github.io/exar-db/exar/struct.DatabaseConfig.html) and
51 | [ServerConfig](https://bfil.github.io/exar-db/exar_server/struct.ServerConfig.html).
52 |
53 | ## Logging
54 |
55 | Logging can be configured using a [log4rs](https://github.com/sfackler/log4rs) config file in `TOML` format, example below:
56 |
57 | ```toml
58 | [appenders.console]
59 | kind = "console"
60 |
61 | [appenders.console.encoder]
62 | pattern = "[{d(%+)(local)}] [{h({l})}] [{t}] {m}{n}"
63 |
64 | [appenders.file]
65 | kind = "file"
66 | path = "exar-db.log"
67 |
68 | [appenders.file.encoder]
69 | pattern = "[{d(%+)(local)}] [{h({l})}] [{t}] {m}{n}"
70 |
71 | [root]
72 | level = "info"
73 | appenders = ["console", "file"]
74 | ```
75 |
76 | ## Interacting with the database from Rust
77 |
78 | To interact with the database from a rust application use [exar-client](https://github.com/bfil/exar-db/tree/master/exar-client).
79 |
80 | Basic connect/publish/subscribe examples are available at the [exar-client](https://bfil.github.io/exar-db/exar_client/index.html) section of the documentation.
81 |
82 | ## Interacting with the database via TCP
83 |
84 | To interact with the database a very simple TCP protocol can be used even via `telnet`.
85 |
86 | ```
87 | telnet 127.0.0.1 38580
88 | ```
89 |
90 | Once the TCP connection has been established, you can use the commands defined in the
91 | [exar-net](https://bfil.github.io/exar-db/exar_net/index.html)
92 | section of the documentation.
93 |
94 | ## Exar UI
95 |
96 | A simple user interface, built with Electron, useful to interact with the database is available [here](https://github.com/bfil/exar-db/tree/master/exar-ui), but it currently needs to be run from source.
97 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | - Add Architecture Docs
2 |
--------------------------------------------------------------------------------
/exar-client/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "exar-client"
3 | version = "0.1.0"
4 | authors = ["Bruno Filippone "]
5 | description = "Exar DB's TCP client"
6 | keywords = ["exar", "exar-db", "tcp", "client"]
7 | repository = "https://github.com/bfil/exar-db/tree/master/exar-client"
8 | documentation = "https://bfil.github.io/exar-db/exar_client/index.html"
9 | license = "AGPL-3.0"
10 | readme = "README.md"
11 |
12 | [dependencies]
13 | exar = { version = "0.1", path = "../exar-core" }
14 | exar-net = { version = "0.1", path = "../exar-net" }
15 | log = "0.3"
16 |
17 | [dev-dependencies]
18 | exar-testkit = { version = "0.1", path = "../exar-testkit" }
19 |
--------------------------------------------------------------------------------
/exar-client/README.md:
--------------------------------------------------------------------------------
1 | # Exar DB's Client
2 |
3 | A client implementation that uses Exar DB's TCP protocol.
4 |
5 | [](https://crates.io/crates/exar-client)
6 |
7 | [Documentation](https://bfil.github.io/exar-db/exar_client/index.html)
8 |
--------------------------------------------------------------------------------
/exar-core/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "exar"
3 | version = "0.1.0"
4 | authors = ["Bruno Filippone "]
5 | description = "Exar DB's core event store engine with streaming support"
6 | keywords = ["exar", "exar-db", "event", "store", "database"]
7 | repository = "https://github.com/bfil/exar-db/tree/master/exar-core"
8 | documentation = "https://bfil.github.io/exar-db/exar/index.html"
9 | license = "AGPL-3.0"
10 | readme = "README.md"
11 |
12 | [dependencies]
13 | indexed-line-reader = "0.2"
14 | log = "0.3"
15 | rand = "0.3"
16 | time = "0.1"
17 | rustc-serialize = { optional = true, version = "0.3" }
18 | serde = { optional = true, version = "0.9" }
19 | serde_derive = { optional = true, version = "0.9" }
20 |
21 | [features]
22 | rustc-serialization = ["rustc-serialize"]
23 | serde-serialization = ["serde", "serde_derive"]
24 |
25 | [dev-dependencies]
26 | exar-testkit = { version = "0.1", path = "../exar-testkit" }
27 | serde_json = "0.9"
28 |
--------------------------------------------------------------------------------
/exar-core/README.md:
--------------------------------------------------------------------------------
1 | # Exar DB's Core
2 |
3 | An event store with streaming support, it uses flat-file based collections.
4 |
5 | [](https://crates.io/crates/exar)
6 |
7 | [Documentation](https://bfil.github.io/exar-db/exar/index.html)
8 |
--------------------------------------------------------------------------------
/exar-core/benches/database.rs:
--------------------------------------------------------------------------------
1 | #![feature(test)]
2 |
3 | extern crate exar;
4 | extern crate rand;
5 | extern crate test;
6 |
7 | #[cfg(test)]
8 | extern crate exar_testkit;
9 |
10 | use exar::*;
11 | use exar_testkit::*;
12 | use test::Bencher;
13 |
14 | #[bench]
15 | fn bench_publish(b: &mut Bencher) {
16 | let collection_name = &random_collection_name();
17 | let config = DatabaseConfig::default();
18 | let mut db = Database::new(config);
19 | let connection = db.connect(collection_name).unwrap();
20 | b.iter(|| {
21 | let _ = connection.publish(Event::new("data", vec!["tag1"]));
22 | });
23 | assert!(db.drop_collection(collection_name).is_ok());
24 | connection.close();
25 | }
26 |
--------------------------------------------------------------------------------
/exar-core/src/connection.rs:
--------------------------------------------------------------------------------
1 | use super::*;
2 |
3 | use std::sync::{Arc, Mutex};
4 |
5 | /// Exar DB's database connection, which contains a reference to a collection wrapped into an Arc/Mutex.
6 | /// It allows publishing and subscribing to the underling collection of events.
7 | ///
8 | /// # Examples
9 | /// ```no_run
10 | /// extern crate exar;
11 | ///
12 | /// # fn main() {
13 | /// use exar::*;
14 | /// use std::sync::{Arc, Mutex};
15 | ///
16 | /// let collection_name = "test";
17 | /// let collection_config = CollectionConfig::default();
18 | /// let collection = Collection::new(collection_name, &collection_config).unwrap();
19 | /// let connection = Connection::new(Arc::new(Mutex::new(collection)));
20 | /// # }
21 | /// ```
22 | #[derive(Clone, Debug)]
23 | pub struct Connection {
24 | collection: Arc>
25 | }
26 |
27 | impl Connection {
28 | /// Creates a new instance of a connection with the given collection.
29 | pub fn new(collection: Arc>) -> Connection {
30 | Connection {
31 | collection: collection
32 | }
33 | }
34 |
35 | /// Publishes an event into the underlying collection and returns the `id` for the event created
36 | /// or a `DatabaseError` if a failure occurs.
37 | pub fn publish(&self, event: Event) -> Result {
38 | self.collection.lock().unwrap().publish(event)
39 | }
40 |
41 | /// Subscribes to the underlying collection of events using the given query and returns an event stream
42 | /// or a `DatabaseError` if a failure occurs.
43 | pub fn subscribe(&self, query: Query) -> Result {
44 | self.collection.lock().unwrap().subscribe(query)
45 | }
46 |
47 | /// Closes the connection.
48 | pub fn close(self) {
49 | drop(self)
50 | }
51 | }
52 |
53 | #[cfg(test)]
54 | mod tests {
55 | use super::super::*;
56 | use exar_testkit::*;
57 |
58 | #[test]
59 | fn test_connection() {
60 | let mut db = Database::new(DatabaseConfig::default());
61 |
62 | let ref collection_name = random_collection_name();
63 | let collection = db.get_collection(collection_name).expect("Unable to get collection");
64 |
65 | let connection = Connection::new(collection);
66 |
67 | let test_event = Event::new("data", vec!["tag1", "tag2"]);
68 | assert_eq!(connection.publish(test_event.clone()), Ok(1));
69 |
70 | let query = Query::current();
71 | let retrieved_events: Vec<_> = connection.subscribe(query).unwrap().take(1).collect();
72 | let expected_event = test_event.clone().with_id(1).with_timestamp(retrieved_events[0].timestamp);
73 | assert_eq!(retrieved_events, vec![expected_event]);
74 |
75 | connection.close();
76 |
77 | assert!(db.drop_collection(collection_name).is_ok());
78 | assert!(!db.contains_collection(collection_name));
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/exar-core/src/database.rs:
--------------------------------------------------------------------------------
1 | use super::*;
2 |
3 | use std::collections::HashMap;
4 | use std::sync::{Arc, Mutex};
5 |
6 | /// Exar DB's main component, containing the database configuration and the references to the
7 | /// collections of events created. It is used to create new connections.
8 | ///
9 | /// # Examples
10 | /// ```no_run
11 | /// extern crate exar;
12 | ///
13 | /// # fn main() {
14 | /// use exar::*;
15 | ///
16 | /// let config = DatabaseConfig::default();
17 | /// let mut db = Database::new(config);
18 | ///
19 | /// let collection_name = "test";
20 | /// let connection = db.connect(collection_name).unwrap();
21 | /// # }
22 | /// ```
23 | #[derive(Clone, Debug)]
24 | pub struct Database {
25 | config: DatabaseConfig,
26 | collections: HashMap>>
27 | }
28 |
29 | impl Database {
30 | /// Creates a new instance of the database with the given configuration.
31 | pub fn new(config: DatabaseConfig) -> Database {
32 | Database {
33 | config: config,
34 | collections: HashMap::new()
35 | }
36 | }
37 |
38 | /// Returns a connection instance with the given name or a `DatabaseError` if a failure occurs.
39 | pub fn connect(&mut self, collection_name: &str) -> Result {
40 | match self.get_collection(collection_name) {
41 | Ok(collection) => Ok(Connection::new(collection)),
42 | Err(err) => Err(err)
43 | }
44 | }
45 |
46 | /// Returns an existing collection instance with the given name wrapped into an `Arc`/`Mutex`
47 | /// or a `DatabaseError` if a failure occurs, it creates a new collection if it does not exist.
48 | pub fn get_collection(&mut self, collection_name: &str) -> Result>, DatabaseError> {
49 | if !self.contains_collection(collection_name) {
50 | self.create_collection(collection_name)
51 | } else {
52 | match self.collections.get(collection_name) {
53 | Some(collection) => Ok(collection.clone()),
54 | None => unreachable!()
55 | }
56 | }
57 | }
58 |
59 | /// Creates and returns a new collection instance with the given name wrapped into an `Arc`/`Mutex`
60 | /// or a `DatabaseError` if a failure occurs.
61 | pub fn create_collection(&mut self, collection_name: &str) -> Result>, DatabaseError> {
62 | let collection_config = self.config.collection_config(collection_name);
63 | Collection::new(collection_name, &collection_config).and_then(|collection| {
64 | let collection = Arc::new(Mutex::new(collection));
65 | self.collections.insert(collection_name.to_owned(), collection.clone());
66 | Ok(collection)
67 | })
68 | }
69 |
70 | /// Drops the collection with the given name or returns an error if a failure occurs.
71 | pub fn drop_collection(&mut self, collection_name: &str) -> Result<(), DatabaseError> {
72 | self.get_collection(collection_name).and_then(|collection| {
73 | (*collection.lock().unwrap()).drop().and_then(|_| {
74 | self.collections.remove(collection_name);
75 | Ok(())
76 | })
77 | })
78 | }
79 |
80 | /// Returns wether a collection with the given name exists.
81 | pub fn contains_collection(&self, collection_name: &str) -> bool {
82 | self.collections.contains_key(collection_name)
83 | }
84 | }
85 |
86 | #[cfg(test)]
87 | mod tests {
88 | use super::super::*;
89 | use exar_testkit::*;
90 |
91 | #[test]
92 | fn test_constructor() {
93 | let db = Database::new(DatabaseConfig::default());
94 |
95 | assert_eq!(db.config, DatabaseConfig::default());
96 | assert_eq!(db.collections.len(), 0);
97 | }
98 |
99 | #[test]
100 | fn test_connect() {
101 | let mut db = Database::new(DatabaseConfig::default());
102 |
103 | let ref collection_name = random_collection_name();
104 | assert!(db.connect(collection_name).is_ok());
105 | assert!(db.contains_collection(collection_name));
106 | assert!(db.drop_collection(collection_name).is_ok());
107 | }
108 |
109 | #[test]
110 | fn test_connection_failure() {
111 | let mut db = Database::new(DatabaseConfig::default());
112 |
113 | let ref collection_name = invalid_collection_name();
114 | assert!(db.connect(collection_name).is_err());
115 | assert!(!db.contains_collection(collection_name));
116 | assert!(db.drop_collection(collection_name).is_err());
117 | }
118 |
119 | #[test]
120 | fn test_collection_management() {
121 | let mut db = Database::new(DatabaseConfig::default());
122 |
123 | let ref collection_name = random_collection_name();
124 | assert!(!db.contains_collection(collection_name));
125 | assert!(db.get_collection(collection_name).is_ok());
126 | assert!(db.contains_collection(collection_name));
127 | assert_eq!(db.collections.len(), 1);
128 |
129 | assert!(db.get_collection(collection_name).is_ok());
130 | assert!(db.contains_collection(collection_name));
131 | assert_eq!(db.collections.len(), 1);
132 |
133 | assert!(db.drop_collection(collection_name).is_ok());
134 | assert!(!db.contains_collection(collection_name));
135 | assert_eq!(db.collections.len(), 0);
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/exar-core/src/encoding.rs:
--------------------------------------------------------------------------------
1 | #![macro_use]
2 |
3 | use std::fmt::{Debug, Display, Formatter, Result as DisplayResult};
4 | use std::str::{FromStr, SplitN};
5 |
6 | /// Generates a tab separated string from a list of string slices
7 | ///
8 | /// # Examples
9 | /// ```
10 | /// #[macro_use]
11 | /// extern crate exar;
12 | ///
13 | /// # fn main() {
14 | /// let tab_separated_value = tab_separated!("hello", "world");
15 | /// # }
16 | /// ```
17 | #[macro_export]
18 | macro_rules! tab_separated {
19 | ($($x:expr),*) => ({
20 | let vec: Vec = vec![$($x.to_string()),*];
21 | vec.join("\t")
22 | })
23 | }
24 |
25 | /// A trait for serializing a type to a tab-separated string.
26 | pub trait ToTabSeparatedString {
27 | /// Returns a tab-separated string from the value.
28 | fn to_tab_separated_string(&self) -> String;
29 | }
30 |
31 | /// A trait for deserializing a type from a tab-separated string slice.
32 | pub trait FromTabSeparatedStr {
33 | /// Returns an instance of `Self` from a tab-separated string slice
34 | /// or a `ParseError` if a failure occurs while parsing the string.
35 | fn from_tab_separated_str(s: &str) -> Result where Self: Sized;
36 | }
37 |
38 | /// A list specifying categories of parse error.
39 | #[derive(Clone, Debug, PartialEq, Eq)]
40 | pub enum ParseError {
41 | /// The parsing failed because of the given reason.
42 | ParseError(String),
43 | /// The parsing failed because of a missing field at the given position.
44 | MissingField(usize)
45 | }
46 |
47 | impl Display for ParseError {
48 | fn fmt(&self, f: &mut Formatter) -> DisplayResult {
49 | match *self {
50 | ParseError::ParseError(ref description) => write!(f, "{}", description),
51 | ParseError::MissingField(index) => write!(f, "missing field at index {}", index)
52 | }
53 | }
54 | }
55 |
56 | /// A parser for tab-separated strings
57 | ///
58 | /// # Examples
59 | /// ```
60 | /// #[macro_use]
61 | /// extern crate exar;
62 | ///
63 | /// # fn main() {
64 | /// use exar::*;
65 | ///
66 | /// let tab_separated_value = tab_separated!("hello", "world");
67 | /// let mut parser = TabSeparatedParser::new(2, &tab_separated_value);
68 | ///
69 | /// let hello: String = parser.parse_next().unwrap();
70 | /// let world: String = parser.parse_next().unwrap();
71 | /// # }
72 | /// ```
73 | pub struct TabSeparatedParser<'a> {
74 | index: usize,
75 | parts: SplitN<'a, &'a str>
76 | }
77 |
78 | impl<'a> TabSeparatedParser<'a> {
79 | /// Creates a new parser that splits a string up to `n` parts.
80 | pub fn new(n: usize, s: &'a str) -> TabSeparatedParser<'a> {
81 | TabSeparatedParser {
82 | index: 0,
83 | parts: s.splitn(n, "\t")
84 | }
85 | }
86 |
87 | /// Parses the next string slice into the given type `T` and returns it,
88 | /// or returns a `ParseError` if a failure occurs while parsing the value.
89 | pub fn parse_next(&mut self) -> Result where T: FromStr, ::Err: Display + Debug {
90 | match self.parts.next().map(|x| x.parse()) {
91 | Some(Ok(value)) => {
92 | self.index += 1;
93 | Ok(value)
94 | },
95 | Some(Err(err)) => Err(ParseError::ParseError(format!("{}", err))),
96 | None => Err(ParseError::MissingField(self.index))
97 | }
98 | }
99 | }
100 |
101 | #[cfg(test)]
102 | mod tests {
103 | use super::super::*;
104 |
105 | #[test]
106 | fn test_tab_separated_macro() {
107 | let tab_separated_value = tab_separated!("hello", "world", "!");
108 | assert_eq!(tab_separated_value, "hello\tworld\t!");
109 |
110 | let tab_separated_value = tab_separated!(1, 2);
111 | assert_eq!(tab_separated_value, "1\t2");
112 | }
113 |
114 | #[test]
115 | fn test_tab_separated_parser() {
116 | let tab_separated_value = tab_separated!("hello", "world", "!");
117 | let mut parser = TabSeparatedParser::new(3, &tab_separated_value);
118 |
119 | let hello: String = parser.parse_next().expect("Unable to parse value");
120 | let world: String = parser.parse_next().expect("Unable to parse value");
121 | let exclamation_mark: String = parser.parse_next().expect("Unable to parse value");
122 |
123 | assert_eq!(hello, "hello".to_owned());
124 | assert_eq!(world, "world".to_owned());
125 | assert_eq!(exclamation_mark, "!".to_owned());
126 |
127 | let tab_separated_value = tab_separated!(1, 2);
128 | let mut parser = TabSeparatedParser::new(2, &tab_separated_value);
129 |
130 | let one: u8 = parser.parse_next().expect("Unable to parse value");
131 | let two: u8 = parser.parse_next().expect("Unable to parse value");
132 |
133 | assert_eq!(one, 1);
134 | assert_eq!(two, 2);
135 | }
136 |
137 | #[test]
138 | fn test_parse_error() {
139 | let tab_separated_value = tab_separated!("hello", "world");
140 | let mut parser = TabSeparatedParser::new(2, &tab_separated_value);
141 |
142 | assert_eq!(parser.parse_next::(), Err(ParseError::ParseError("invalid digit found in string".to_owned())));
143 | }
144 |
145 | #[test]
146 | fn test_missing_field_error() {
147 | let tab_separated_value = tab_separated!("hello", "world");
148 | let mut parser = TabSeparatedParser::new(2, &tab_separated_value);
149 |
150 | let hello: String = parser.parse_next().expect("Unable to parse value");
151 | let world: String = parser.parse_next().expect("Unable to parse value");
152 |
153 | assert_eq!(hello, "hello".to_owned());
154 | assert_eq!(world, "world".to_owned());
155 |
156 | assert_eq!(parser.parse_next::(), Err(ParseError::MissingField(2)));
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/exar-core/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! # Exar DB
2 | //! Exar DB is an event store with streaming support
3 | //! which uses a flat-file for each collection of events
4 | //!
5 | //! ## Database Initialization
6 | //! ```
7 | //! extern crate exar;
8 | //!
9 | //! # fn main() {
10 | //! use exar::*;
11 | //!
12 | //! let config = DatabaseConfig::default();
13 | //! let mut db = Database::new(config);
14 | //! # }
15 | //! ```
16 | //! ## Publishing events
17 | //! ```no_run
18 | //! extern crate exar;
19 | //!
20 | //! # fn main() {
21 | //! use exar::*;
22 | //!
23 | //! let config = DatabaseConfig::default();
24 | //! let mut db = Database::new(config);
25 | //!
26 | //! let collection_name = "test";
27 | //! let connection = db.connect(collection_name).unwrap();
28 | //!
29 | //! match connection.publish(Event::new("payload", vec!["tag1", "tag2"])) {
30 | //! Ok(event_id) => println!("Published event with ID: {}", event_id),
31 | //! Err(err) => panic!("Unable to publish event: {}", err)
32 | //! };
33 | //! # }
34 | //! ```
35 | //! ## Querying events
36 | //! ```no_run
37 | //! extern crate exar;
38 | //!
39 | //! # fn main() {
40 | //! use exar::*;
41 | //!
42 | //! let config = DatabaseConfig::default();
43 | //! let mut db = Database::new(config);
44 | //!
45 | //! let collection_name = "test";
46 | //! let connection = db.connect(collection_name).unwrap();
47 | //!
48 | //! let query = Query::live().offset(0).limit(10).by_tag("tag1");
49 | //! let event_stream = connection.subscribe(query).unwrap();
50 | //! for event in event_stream {
51 | //! println!("Received event: {}", event);
52 | //! }
53 | //! # }
54 | //! ```
55 |
56 | #[cfg(feature = "rustc-serialization")] extern crate rustc_serialize;
57 | #[cfg(feature = "serde-serialization")] extern crate serde;
58 | #[cfg(feature = "serde-serialization")] #[macro_use] extern crate serde_derive;
59 |
60 | #[cfg(test)] #[macro_use]
61 | extern crate exar_testkit;
62 |
63 | #[macro_use]
64 | extern crate log as logging;
65 |
66 | extern crate indexed_line_reader;
67 | extern crate rand;
68 | extern crate time;
69 |
70 | mod logger;
71 | mod config;
72 | mod collection;
73 | mod connection;
74 | mod database;
75 | mod encoding;
76 | mod error;
77 | mod event;
78 | mod log;
79 | mod query;
80 | mod scanner;
81 | mod routing_strategy;
82 | mod subscription;
83 | mod util;
84 | mod validation;
85 |
86 | pub use self::logger::*;
87 | pub use self::config::*;
88 | pub use self::collection::*;
89 | pub use self::connection::*;
90 | pub use self::database::*;
91 | pub use self::encoding::*;
92 | pub use self::error::*;
93 | pub use self::event::*;
94 | pub use self::log::*;
95 | pub use self::query::*;
96 | pub use self::routing_strategy::*;
97 | pub use self::scanner::*;
98 | pub use self::subscription::*;
99 | pub use self::util::*;
100 | pub use self::validation::*;
101 |
--------------------------------------------------------------------------------
/exar-core/src/query.rs:
--------------------------------------------------------------------------------
1 | use super::*;
2 |
3 | /// Exar DB's subscription query.
4 | ///
5 | /// # Examples
6 | /// ```
7 | /// extern crate exar;
8 | ///
9 | /// # fn main() {
10 | /// use exar::*;
11 | ///
12 | /// let query = Query::new(true, 100, Some(20), Some("tag".to_owned()));
13 | ///
14 | /// // or using the fluent API
15 | /// let fluent_query = Query::live().offset(100).limit(20).by_tag("tag");
16 | /// # }
17 | /// ```
18 | #[derive(Clone, Debug, PartialEq, Eq)]
19 | pub struct Query {
20 | /// Indicates wether the query targets real-time events.
21 | pub live_stream: bool,
22 | /// Indicates the query target offset.
23 | pub offset: u64,
24 | /// Indicates the maximum number of events to be returned by the query, if specified.
25 | pub limit: Option,
26 | /// Indicates the query target event tag, if specified.
27 | pub tag: Option,
28 | position: u64,
29 | count: u64
30 | }
31 |
32 | impl Query {
33 | /// Creates a new `Query` from the given parameters.
34 | pub fn new(live_stream: bool, offset: u64, limit: Option, tag: Option) -> Query {
35 | Query {
36 | offset: offset,
37 | limit: limit,
38 | tag: tag,
39 | live_stream: live_stream,
40 | position: offset,
41 | count: 0
42 | }
43 | }
44 |
45 | /// Initializes a `Query` targeting the current events in the event log.
46 | pub fn current() -> Query {
47 | Query::new(false, 0, None, None)
48 | }
49 |
50 | /// Initializes a `Query` targeting the current and real-time events in the event log.
51 | pub fn live() -> Query {
52 | Query::new(true, 0, None, None)
53 | }
54 |
55 | /// Mutates and returns the query by updating its target offset.
56 | pub fn offset(mut self, offset: u64) -> Query {
57 | self.offset = offset;
58 | self.position = offset;
59 | self
60 | }
61 |
62 | /// Mutates and returns the query by updating its limit.
63 | pub fn limit(mut self, limit: u64) -> Query {
64 | self.limit = Some(limit);
65 | self
66 | }
67 |
68 | /// Mutates and returns the query by updating its target event tag.
69 | pub fn by_tag(mut self, tag: &str) -> Query {
70 | self.tag = Some(tag.to_owned());
71 | self
72 | }
73 |
74 | /// Returns wether a given `Event` matches the query.
75 | pub fn matches(&self, event: &Event) -> bool {
76 | match self.tag {
77 | Some(ref tag) => self.position < event.id && event.tags.contains(tag),
78 | None => self.position < event.id
79 | }
80 | }
81 |
82 | /// Returns wether the query is still active.
83 | pub fn is_active(&self) -> bool {
84 | match self.limit {
85 | Some(limit) => self.count < limit,
86 | None => true
87 | }
88 | }
89 |
90 | /// Updates the internal state of the query given the last matching event `id`.
91 | pub fn update(&mut self, event_id: u64) {
92 | self.position = event_id;
93 | self.count += 1;
94 | }
95 |
96 | /// Returns the offsets interval the query targets.
97 | pub fn interval(&self) -> Interval {
98 | let start = self.position;
99 | let end = if self.limit.is_none() || self.tag.is_some() {
100 | u64::max_value()
101 | } else {
102 | start + self.limit.unwrap()
103 | };
104 | Interval::new(start, end)
105 | }
106 | }
107 |
108 | #[cfg(test)]
109 | mod tests {
110 | use super::super::*;
111 |
112 | #[test]
113 | fn test_constructors_and_modifiers() {
114 | let query = Query::new(true, 100, Some(20), Some("tag".to_owned()));
115 | assert_eq!(query.live_stream, true);
116 | assert_eq!(query.offset, 100);
117 | assert_eq!(query.limit, Some(20));
118 | assert_eq!(query.tag, Some("tag".to_owned()));
119 |
120 | let query = Query::current();
121 | assert_eq!(query.live_stream, false);
122 | assert_eq!(query.offset, 0);
123 | assert_eq!(query.limit, None);
124 | assert_eq!(query.tag, None);
125 |
126 | let query = Query::live();
127 | assert_eq!(query.live_stream, true);
128 | assert_eq!(query.offset, 0);
129 | assert_eq!(query.limit, None);
130 | assert_eq!(query.tag, None);
131 |
132 | let query = query.offset(100);
133 | assert_eq!(query.offset, 100);
134 |
135 | let query = query.limit(20);
136 | assert_eq!(query.limit, Some(20));
137 |
138 | let query = query.by_tag("tag");
139 | assert_eq!(query.tag, Some("tag".to_owned()));
140 | }
141 |
142 | #[test]
143 | fn test_event_matching() {
144 | let mut query = Query::current();
145 |
146 | assert!(query.matches(&Event::new("data", vec!["tag1"]).with_id(1)));
147 |
148 | query.update(1);
149 |
150 | assert!(!query.matches(&Event::new("data", vec!["tag1"]).with_id(1)));
151 |
152 | let mut query = Query::current().by_tag("tag1");
153 |
154 | assert!(query.matches(&Event::new("data", vec!["tag1"]).with_id(1)));
155 | assert!(!query.matches(&Event::new("data", vec!["tag2"]).with_id(1)));
156 |
157 | query.update(1);
158 |
159 | assert!(!query.matches(&Event::new("data", vec!["tag1"]).with_id(1)));
160 | }
161 |
162 | #[test]
163 | fn test_is_active() {
164 | let query = Query::current();
165 |
166 | assert!(query.is_active());
167 |
168 | let mut query = query.limit(3);
169 |
170 | assert!(query.is_active());
171 |
172 | query.update(1);
173 | query.update(2);
174 | query.update(3);
175 |
176 | assert_eq!(query.position, 3);
177 | assert_eq!(query.count, 3);
178 | assert!(!query.is_active());
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/exar-core/src/routing_strategy.rs:
--------------------------------------------------------------------------------
1 | #[cfg(feature = "rustc-serialization")] use rustc_serialize::{Encoder, Encodable, Decoder, Decodable};
2 | #[cfg(feature = "serde-serialization")] use serde::{Serialize, Serializer, Deserialize, Deserializer};
3 | #[cfg(feature = "serde-serialization")] use serde::de::{Error, Visitor};
4 | #[cfg(feature = "serde-serialization")] use std::fmt;
5 |
6 | /// A list specifying categories of routing strategy.
7 | #[derive(Clone, Debug, PartialEq, Eq)]
8 | pub enum RoutingStrategy {
9 | /// The next element is picked at random.
10 | Random,
11 | /// The next element is picked using the round-robin algorithm.
12 | RoundRobin(usize)
13 | }
14 |
15 | #[cfg(feature = "rustc-serialization")]
16 | impl Encodable for RoutingStrategy {
17 | fn encode(&self, s: &mut S) -> Result<(), S::Error> {
18 | match *self {
19 | RoutingStrategy::Random => s.emit_str("Random"),
20 | RoutingStrategy::RoundRobin(_) => s.emit_str("RoundRobin")
21 | }
22 | }
23 | }
24 |
25 | #[cfg(feature = "rustc-serialization")]
26 | impl Decodable for RoutingStrategy {
27 | fn decode(d: &mut D) -> Result {
28 | d.read_str().map(|s| {
29 | match s.as_ref() {
30 | "Random" => RoutingStrategy::Random,
31 | "RoundRobin" => RoutingStrategy::RoundRobin(0),
32 | _ => RoutingStrategy::default()
33 | }
34 | })
35 | }
36 | }
37 |
38 | #[cfg(feature = "serde-serialization")]
39 | impl Serialize for RoutingStrategy {
40 | fn serialize(&self, serializer: S) -> Result {
41 | match *self {
42 | RoutingStrategy::Random => serializer.serialize_str("Random"),
43 | RoutingStrategy::RoundRobin(_) => serializer.serialize_str("RoundRobin")
44 | }
45 | }
46 | }
47 |
48 | #[cfg(feature = "serde-serialization")]
49 | impl Deserialize for RoutingStrategy {
50 | fn deserialize(deserializer: D) -> Result {
51 | deserializer.deserialize_str(RoutingStrategyVisitor)
52 | }
53 | }
54 |
55 | #[cfg(feature = "serde-serialization")]
56 | struct RoutingStrategyVisitor;
57 |
58 | #[cfg(feature = "serde-serialization")]
59 | impl Visitor for RoutingStrategyVisitor {
60 | type Value = RoutingStrategy;
61 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
62 | formatter.write_str("Random or RoundRobin")
63 | }
64 | fn visit_str(self, s: &str) -> Result {
65 | match s {
66 | "Random" => Ok(RoutingStrategy::Random),
67 | "RoundRobin" => Ok(RoutingStrategy::RoundRobin(0)),
68 | _ => Ok(RoutingStrategy::default())
69 | }
70 | }
71 | }
72 |
73 | impl Default for RoutingStrategy {
74 | fn default() -> Self {
75 | RoutingStrategy::RoundRobin(0)
76 | }
77 | }
78 |
79 | #[cfg(test)]
80 | mod tests {
81 | use super::super::*;
82 |
83 | #[cfg(feature = "rustc-serialization")]
84 | use rustc_serialize::json;
85 |
86 | #[cfg(feature = "serde-serialization")]
87 | extern crate serde_json;
88 |
89 | #[test]
90 | fn test_default() {
91 | assert_eq!(RoutingStrategy::default(), RoutingStrategy::RoundRobin(0));
92 | }
93 |
94 | #[test]
95 | #[cfg(feature = "rustc-serialization")]
96 | fn test_rustc_serialization() {
97 | let routing_strategy = RoutingStrategy::Random;
98 | assert_eq!(json::encode(&routing_strategy).unwrap(), "\"Random\"");
99 | assert_eq!(json::decode::("\"Random\"").unwrap(), routing_strategy);
100 |
101 | let routing_strategy = RoutingStrategy::RoundRobin(0);
102 | assert_eq!(json::encode(&routing_strategy).unwrap(), "\"RoundRobin\"");
103 | assert_eq!(json::decode::("\"RoundRobin\"").unwrap(), routing_strategy);
104 | }
105 |
106 | #[test]
107 | #[cfg(feature = "serde-serialization")]
108 | fn test_serde_serialization() {
109 | let routing_strategy = RoutingStrategy::Random;
110 | assert_eq!(serde_json::to_string(&routing_strategy).unwrap(), "\"Random\"");
111 | assert_eq!(serde_json::from_str::("\"Random\"").unwrap(), routing_strategy);
112 |
113 | let routing_strategy = RoutingStrategy::RoundRobin(0);
114 | assert_eq!(serde_json::to_string(&routing_strategy).unwrap(), "\"RoundRobin\"");
115 | assert_eq!(serde_json::from_str::("\"RoundRobin\"").unwrap(), routing_strategy);
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/exar-core/src/subscription.rs:
--------------------------------------------------------------------------------
1 | use super::*;
2 |
3 | use std::sync::mpsc::Sender;
4 |
5 | /// Exar DB's subscription.
6 | ///
7 | /// # Examples
8 | /// ```
9 | /// extern crate exar;
10 | ///
11 | /// # fn main() {
12 | /// use exar::*;
13 | /// use std::sync::mpsc::channel;
14 | ///
15 | /// let (sender, receiver) = channel();
16 | /// let event = Event::new("data", vec!["tag1", "tag2"]);
17 | ///
18 | /// let mut subscription = Subscription::new(sender, Query::current());
19 | /// subscription.send(event).unwrap();
20 | /// let event_stream_message = receiver.recv().unwrap();
21 | /// # }
22 | /// ```
23 | #[derive(Clone, Debug)]
24 | pub struct Subscription {
25 | active: bool,
26 | /// The channel sender used to stream `EventStreamMessage`s back to the subscriber.
27 | pub event_stream_sender: Sender,
28 | /// The query associated to this subscription.
29 | pub query: Query
30 | }
31 |
32 | impl Subscription {
33 | /// Creates a new `Subscription` with the given channel sender and query.
34 | pub fn new(sender: Sender, query: Query) -> Subscription {
35 | Subscription {
36 | active: true,
37 | event_stream_sender: sender,
38 | query: query
39 | }
40 | }
41 |
42 | /// Sends an `Event` to the subscriber or returns a `DatabaseError` if a failure occurs.
43 | pub fn send(&mut self, event: Event) -> Result<(), DatabaseError> {
44 | let event_id = event.id;
45 | match self.event_stream_sender.send(EventStreamMessage::Event(event)) {
46 | Ok(_) => {
47 | self.query.update(event_id);
48 | if !self.is_active() || !self.query.is_active() {
49 | self.active = false;
50 | match self.event_stream_sender.send(EventStreamMessage::End) {
51 | Ok(_) => Ok(()),
52 | Err(_) => Err(DatabaseError::EventStreamError(EventStreamError::Closed))
53 | }
54 | } else {
55 | Ok(())
56 | }
57 | },
58 | Err(_) => {
59 | self.active = false;
60 | Err(DatabaseError::EventStreamError(EventStreamError::Closed))
61 | }
62 | }
63 | }
64 |
65 | /// Returns wether the subscription is still active.
66 | pub fn is_active(&self) -> bool {
67 | self.active
68 | }
69 |
70 | /// Returns wether the subscription is interested in the given `Event`.
71 | pub fn matches_event(&self, event: &Event) -> bool {
72 | self.is_active() && self.query.is_active() && self.query.matches(event)
73 | }
74 | }
75 |
76 | #[cfg(test)]
77 | mod tests {
78 | use super::super::*;
79 |
80 | use std::sync::mpsc::channel;
81 |
82 | #[test]
83 | fn test_simple_subscription() {
84 | let (sender, receiver) = channel();
85 | let event = Event::new("data", vec!["tag1", "tag2"]).with_id(1);
86 |
87 | let mut subscription = Subscription::new(sender, Query::current());
88 |
89 | assert!(subscription.send(event.clone()).is_ok());
90 | assert_eq!(receiver.recv(), Ok(EventStreamMessage::Event(event.clone())));
91 | assert_eq!(subscription.query.interval().start, 1);
92 | assert!(subscription.is_active());
93 |
94 | drop(receiver);
95 |
96 | assert_eq!(subscription.send(event.clone()), Err(DatabaseError::EventStreamError(EventStreamError::Closed)));
97 | assert_eq!(subscription.query.interval().start, 1);
98 | assert!(!subscription.is_active());
99 | }
100 |
101 | #[test]
102 | fn test_subscription_event_stream_end() {
103 | let (sender, receiver) = channel();
104 | let event = Event::new("data", vec!["tag1", "tag2"]).with_id(1);
105 |
106 | let mut subscription = Subscription::new(sender, Query::current().limit(1));
107 |
108 | assert!(subscription.send(event.clone()).is_ok());
109 | assert_eq!(receiver.recv(), Ok(EventStreamMessage::Event(event.clone())));
110 | assert_eq!(receiver.recv(), Ok(EventStreamMessage::End));
111 | assert_eq!(subscription.query.interval().start, 1);
112 | assert!(!subscription.is_active());
113 |
114 | drop(receiver);
115 |
116 | assert_eq!(subscription.send(event.clone()), Err(DatabaseError::EventStreamError(EventStreamError::Closed)));
117 | assert_eq!(subscription.query.interval().start, 1);
118 | assert!(!subscription.is_active());
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/exar-core/src/util.rs:
--------------------------------------------------------------------------------
1 | use std::io::prelude::*;
2 | use std::io::{BufWriter, Result};
3 |
4 | /// A trait for writing a line into a stream.
5 | pub trait WriteLine {
6 | /// Writes a string slice into this writer by appending a new line at the end of it,
7 | /// returning whether the write succeeded.
8 | fn write_line(&mut self, line: &str) -> Result;
9 | }
10 |
11 | impl WriteLine for BufWriter {
12 | fn write_line(&mut self, line: &str) -> Result {
13 | self.write(format!("{}\n", line).as_bytes()).and_then(|bytes_written| {
14 | self.flush().and_then(|_| {
15 | Ok(bytes_written)
16 | })
17 | })
18 | }
19 | }
20 |
21 | /// An interval.
22 | #[derive(Clone, Debug, Eq, PartialEq)]
23 | pub struct Interval {
24 | /// The start of the interval.
25 | pub start: T,
26 | /// The end of the interval.
27 | pub end: T
28 | }
29 |
30 | /// A trait for merging a type.
31 | pub trait Merge: Sized {
32 | fn merge(&mut self);
33 | fn merged(mut self) -> Self {
34 | self.merge();
35 | self
36 | }
37 | }
38 |
39 | impl Interval {
40 | pub fn new(start: T, end: T) -> Interval {
41 | Interval {
42 | start: start,
43 | end: end
44 | }
45 | }
46 | }
47 |
48 | impl Merge for Vec> {
49 | fn merge(&mut self) {
50 | if !self.is_empty() {
51 | self.sort_by(|a, b| a.start.cmp(&b.start));
52 | let mut merged_intervals = vec![ self[0].clone() ];
53 | for interval in self.iter().skip(1) {
54 | let last_pos = merged_intervals.len() - 1;
55 | if merged_intervals[last_pos].end < interval.start {
56 | merged_intervals.push(interval.clone());
57 | } else if merged_intervals[last_pos].end >= interval.start &&
58 | merged_intervals[last_pos].end <= interval.end {
59 | merged_intervals[last_pos].end = interval.end;
60 | }
61 | }
62 | *self = merged_intervals;
63 | }
64 | }
65 | }
66 |
67 | #[cfg(test)]
68 | mod tests {
69 | use super::super::*;
70 |
71 | use std::fs::*;
72 | use std::io::{BufRead, BufReader, BufWriter, Seek, SeekFrom};
73 |
74 | #[test]
75 | fn test_write_line() {
76 | let file = OpenOptions::new().read(true).write(true).create(true)
77 | .open("buf-writer.log").expect("Unable to create file");
78 |
79 | let mut buf_writer = BufWriter::new(file);
80 | assert!(buf_writer.write_line("line 1").is_ok());
81 | assert!(buf_writer.write_line("line 2").is_ok());
82 |
83 | let mut file = buf_writer.into_inner().expect("Unable to extract inner context");
84 | file.seek(SeekFrom::Start(0)).expect("Unable to seek to start");
85 | let mut lines = BufReader::new(file).lines();
86 |
87 | let line = lines.next().expect("Unable to read next line")
88 | .expect("Unable to read next line");
89 |
90 | assert_eq!(line, "line 1".to_owned());
91 |
92 | let line = lines.next().expect("Unable to read next line")
93 | .expect("Unable to read next line");
94 |
95 | assert_eq!(line, "line 2".to_owned());
96 |
97 | assert!(remove_file("buf-writer.log").is_ok());
98 | }
99 |
100 | #[test]
101 | fn test_intervals_merging() {
102 | let intervals = vec![];
103 | assert_eq!(intervals.merged(), vec![]);
104 |
105 | let intervals = vec![
106 | Interval::new(0, 10),
107 | Interval::new(30, 50),
108 | Interval::new(40, 70)
109 | ];
110 | assert_eq!(intervals.merged(), vec![Interval::new(0, 10), Interval::new(30, 70)]);
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/exar-core/src/validation.rs:
--------------------------------------------------------------------------------
1 | use std::fmt::{Display, Formatter, Result as DisplayResult};
2 |
3 | /// A trait for validating a type.
4 | pub trait Validation where Self: Sized {
5 | /// Validates the type or returns a `ValidationError` if validation fails.
6 | fn validate(&self) -> Result<(), ValidationError>;
7 | /// Validates and returns `Self` or a `ValidationError` if validation fails.
8 | fn validated(self) -> Result {
9 | self.validate().and_then(|_| Ok(self))
10 | }
11 | }
12 |
13 | /// A validation error.
14 | #[derive(Clone, Debug, PartialEq, Eq)]
15 | pub struct ValidationError {
16 | /// The validation error's description.
17 | pub description: String
18 | }
19 |
20 | impl ValidationError {
21 | /// Creates a `ValidationError` with the given description.
22 | pub fn new(description: &str) -> ValidationError {
23 | ValidationError {
24 | description: description.to_owned()
25 | }
26 | }
27 | }
28 |
29 | impl Display for ValidationError {
30 | fn fmt(&self, f: &mut Formatter) -> DisplayResult {
31 | write!(f, "{}", self.description)
32 | }
33 | }
34 |
35 | #[cfg(test)]
36 | mod tests {
37 | use super::super::*;
38 |
39 | #[derive(Clone, Debug, PartialEq, Eq)]
40 | struct Test {
41 | pub value: String
42 | }
43 |
44 | impl Validation for Test {
45 | fn validate(&self) -> Result<(), ValidationError> {
46 | if self.value == "invalid" {
47 | return Err(ValidationError::new("invalid value"));
48 | }
49 | Ok(())
50 | }
51 | }
52 |
53 | #[test]
54 | fn test_validation() {
55 | let valid_test = Test { value: "valid".to_owned() };
56 | assert_eq!(valid_test.clone().validate(), Ok(()));
57 |
58 | let valid_test = Test { value: "valid".to_owned() };
59 | assert_eq!(valid_test.clone().validated(), Ok(valid_test));
60 |
61 | let invalid_test = Test { value: "invalid".to_owned() };
62 | assert_eq!(invalid_test.clone().validate(), Err(ValidationError::new("invalid value")));
63 |
64 | assert_eq!(format!("{}", ValidationError::new("invalid value")), "invalid value".to_owned());
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/exar-core/tests/lib.rs:
--------------------------------------------------------------------------------
1 | extern crate exar;
2 | extern crate rand;
3 |
4 | #[cfg(test)]
5 | extern crate exar_testkit;
6 |
7 | use exar::*;
8 | use exar_testkit::*;
9 |
10 | #[test]
11 | fn integration_test() {
12 | let mut db = Database::new(DatabaseConfig::default());
13 |
14 | let collection_name = &random_collection_name();
15 | let connection = db.connect(collection_name).expect("Unable to connect");
16 |
17 | let test_event = Event::new("data", vec!["tag1", "tag2"]);
18 | assert!(connection.publish(test_event.clone()).is_ok());
19 |
20 | let query = Query::current();
21 | let retrieved_events: Vec<_> = connection.subscribe(query).unwrap().take(1).collect();
22 | let expected_event = test_event.clone().with_id(1).with_timestamp(retrieved_events[0].timestamp);
23 | assert_eq!(retrieved_events, vec![expected_event]);
24 |
25 | assert!(db.drop_collection(collection_name).is_ok());
26 | assert!(!db.contains_collection(collection_name));
27 | }
28 |
--------------------------------------------------------------------------------
/exar-db/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "exar-db"
3 | version = "0.1.0"
4 | authors = ["Bruno Filippone "]
5 | description = "Exar DB's event store with streaming support"
6 | keywords = ["exar", "exar-db", "event", "store", "database"]
7 | repository = "https://github.com/bfil/exar-db/tree/master/exar-db"
8 | documentation = "https://bfil.github.io/exar-db/exar_db/index.html"
9 | license = "AGPL-3.0"
10 | readme = "README.md"
11 |
12 | [dependencies]
13 | clap = "2.1"
14 | exar = { version = "0.1", path = "../exar-core", features = ["rustc-serialization"] }
15 | exar-server = { version = "0.1", path = "../exar-server", features = ["rustc-serialization"] }
16 | log = "0.3"
17 | log4rs = { version = "0.6", features = ["toml_format"] }
18 | rustc-serialize = "0.3"
19 | toml-config = "0.4"
20 |
--------------------------------------------------------------------------------
/exar-db/README.md:
--------------------------------------------------------------------------------
1 | # Exar DB
2 |
3 | An event store with streaming support, it uses flat-file based collections.
4 |
5 | [](https://crates.io/crates/exar-db)
6 |
7 | [Documentation](https://bfil.github.io/exar-db/exar_db/index.html)
8 |
9 | ## Installation
10 |
11 | Install [`Cargo`](https://crates.io/install), then run:
12 |
13 | ```
14 | cargo install exar-db
15 | ```
16 |
17 | ## Starting the database
18 |
19 | Simply run `exar-db`.
20 |
21 | ## Configuring the database
22 |
23 | The database can be configured using a `TOML` configuration file, example below:
24 |
25 | ```toml
26 | log4rs_path = "/path/to/log4rs.toml"
27 | [database]
28 | logs_path = "~/exar-db/data"
29 | scanners = { nr_of_scanners = 2, sleep_time_in_ms = 10 }
30 | [database.collections.my-collection]
31 | routing_strategy = "Random"
32 | scanners = { nr_of_scanners = 4, sleep_time_in_ms = 5 }
33 | [server]
34 | host = "127.0.0.1"
35 | port = 38580
36 | username = "my-username"
37 | password = "my-secret"
38 | ```
39 |
40 | Then run Exar DB by specifying the config file location: `exar-db --config=/path/to/config.toml`.
41 |
42 | For more information about the `database` and `server` configuration sections,
43 | check the documentation about
44 | [DatabaseConfig](https://bfil.github.io/exar-db/exar/struct.DatabaseConfig.html) and
45 | [ServerConfig](https://bfil.github.io/exar-db/exar_server/struct.ServerConfig.html).
46 |
47 | ## Logging
48 |
49 | Logging can be configured using a [log4rs](https://github.com/sfackler/log4rs) config file in `TOML` format, example below:
50 |
51 | ```toml
52 | [appenders.console]
53 | kind = "console"
54 |
55 | [appenders.console.encoder]
56 | pattern = "[{d(%+)(local)}] [{h({l})}] [{t}] {m}{n}"
57 |
58 | [appenders.file]
59 | kind = "file"
60 | path = "exar-db.log"
61 |
62 | [appenders.file.encoder]
63 | pattern = "[{d(%+)(local)}] [{h({l})}] [{t}] {m}{n}"
64 |
65 | [root]
66 | level = "info"
67 | appenders = ["console", "file"]
68 | ```
69 |
--------------------------------------------------------------------------------
/exar-db/log4rs.toml:
--------------------------------------------------------------------------------
1 | [appenders.console]
2 | kind = "console"
3 |
4 | [appenders.console.encoder]
5 | pattern = "[{d(%+)(local)}] [{h({l})}] [{t}] {m}{n}"
6 |
7 | [appenders.file]
8 | kind = "file"
9 | path = "exar-db.log"
10 |
11 | [appenders.file.encoder]
12 | pattern = "[{d(%+)(local)}] [{h({l})}] [{t}] {m}{n}"
13 |
14 | [root]
15 | level = "info"
16 | appenders = ["console", "file"]
17 |
--------------------------------------------------------------------------------
/exar-db/src/config.rs:
--------------------------------------------------------------------------------
1 | use exar::*;
2 | use exar_server::*;
3 |
4 | #[derive(RustcEncodable, RustcDecodable)]
5 | #[derive(Clone, Debug, PartialEq, Eq)]
6 | pub struct Config {
7 | pub log4rs_path: String,
8 | pub database: DatabaseConfig,
9 | pub server: ServerConfig
10 | }
11 |
12 | impl Default for Config {
13 | fn default() -> Config {
14 | Config {
15 | log4rs_path: "log4rs.toml".to_owned(),
16 | database: DatabaseConfig::default(),
17 | server: ServerConfig::default()
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/exar-db/src/main.rs:
--------------------------------------------------------------------------------
1 | //! # Exar DB
2 | //! Exar DB is an event store with streaming support
3 | //! which uses a flat-file for each collection of events
4 | //!
5 | //! ## Installation
6 | //!
7 | //! Install [`Cargo`](https://crates.io/install), then run:
8 | //!
9 | //! ```
10 | //! cargo install exar-db
11 | //! ```
12 | //!
13 | //! ## Starting the database
14 | //!
15 | //! Simply run `exar-db`.
16 | //!
17 | //! ## Configuring the database
18 | //!
19 | //! The database can be configured using a `TOML` configuration file, example below:
20 | //!
21 | //! ```toml
22 | //! log4rs_path = "/path/to/log4rs.toml"
23 | //! [database]
24 | //! logs_path = "~/exar-db/data"
25 | //! scanners = { nr_of_scanners = 2, sleep_time_in_ms = 10 }
26 | //! [database.collections.my-collection]
27 | //! routing_strategy = "Random"
28 | //! scanners = { nr_of_scanners = 4, sleep_time_in_ms = 5 }
29 | //! [server]
30 | //! host = "127.0.0.1"
31 | //! port = 38580
32 | //! username = "my-username"
33 | //! password = "my-secret"
34 | //! ```
35 | //!
36 | //! Then run Exar DB by specifying the config file location: `exar-db --config=/path/to/config.toml`.
37 | //!
38 | //! For more information about the `database` and `server` configuration sections,
39 | //! check the documentation about
40 | //! [DatabaseConfig](https://bfil.github.io/exar-db/exar/struct.DatabaseConfig.html) and
41 | //! [ServerConfig](https://bfil.github.io/exar-db/exar_server/struct.ServerConfig.html).
42 | //!
43 | //! ## Logging
44 | //!
45 | //! Logging can be configured using a [log4rs](https://github.com/sfackler/log4rs) config file in `TOML` format, example below:
46 | //!
47 | //! ```toml
48 | //! [appenders.console]
49 | //! kind = "console"
50 | //!
51 | //! [appenders.console.encoder]
52 | //! pattern = "[{d(%+)(local)}] [{h({l})}] [{t}] {m}{n}"
53 | //!
54 | //! [appenders.file]
55 | //! kind = "file"
56 | //! path = "exar-db.log"
57 | //!
58 | //! [appenders.file.encoder]
59 | //! pattern = "[{d(%+)(local)}] [{h({l})}] [{t}] {m}{n}"
60 | //!
61 | //! [root]
62 | //! level = "info"
63 | //! appenders = ["console", "file"]
64 | //! ```
65 |
66 | extern crate clap;
67 | extern crate exar;
68 | extern crate exar_server;
69 | extern crate rustc_serialize;
70 | extern crate toml_config;
71 |
72 | #[macro_use]
73 | extern crate log;
74 | extern crate log4rs;
75 |
76 | mod config;
77 | use config::*;
78 |
79 | use clap::App;
80 | use exar::*;
81 | use exar_server::*;
82 | use log::LogLevelFilter;
83 | use log4rs::append::console::ConsoleAppender;
84 | use log4rs::config::{Appender, Config as Log4rsConfig, Root};
85 | use std::path::Path;
86 | use toml_config::ConfigFactory;
87 |
88 | fn main() {
89 | let matches = App::new("exar-db")
90 | .version("0.1.0")
91 | .author("Bruno Filippone ")
92 | .about("An event store with streaming support which uses a flat-file for each collection of events")
93 | .args_from_usage(
94 | "-c, --config=[FILE] 'Sets a custom config file'")
95 | .get_matches();
96 |
97 | let config = match matches.value_of("config") {
98 | Some(config_file) => ConfigFactory::load(Path::new(config_file)),
99 | None => Config::default()
100 | };
101 |
102 | match log4rs::init_file(config.log4rs_path.clone(), Default::default()) {
103 | Ok(_) => info!("Loaded log4rs config file: {}", config.log4rs_path),
104 | Err(_) => {
105 | let console_appender = Appender::builder()
106 | .build("console".to_owned(), Box::new(ConsoleAppender::builder().build()));
107 | let root = Root::builder()
108 | .appender("console".to_owned())
109 | .build(LogLevelFilter::Info);
110 | let log4rs_config = Log4rsConfig::builder()
111 | .appender(console_appender)
112 | .build(root).expect("Unable to build log4rs config");
113 | log4rs::init_config(log4rs_config).expect("Unable to initialize log4rs config");
114 | info!("Unable to load config file '{}', using default console appender", config.log4rs_path);
115 | }
116 | };
117 |
118 | let db = Database::new(config.database);
119 | match Server::new(config.server.clone(), db) {
120 | Ok(server) => {
121 | info!("ExarDB running at {}", config.server.address());
122 | server.listen();
123 | info!("ExarDB shutting down");
124 | },
125 | Err(err) => error!("Unable to run ExarDB: {}", err)
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/exar-net/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "exar-net"
3 | version = "0.1.0"
4 | authors = ["Bruno Filippone "]
5 | description = "Exar DB's TCP protocol"
6 | keywords = ["exar", "exar-db", "tcp", "protocol"]
7 | repository = "https://github.com/bfil/exar-db/tree/master/exar-net"
8 | documentation = "https://bfil.github.io/exar-db/exar_net/index.html"
9 | license = "AGPL-3.0"
10 | readme = "README.md"
11 |
12 | [dependencies]
13 | exar = { version = "0.1", path = "../exar-core" }
14 |
15 | [dev-dependencies]
16 | exar-testkit = { version = "0.1", path = "../exar-testkit" }
17 |
--------------------------------------------------------------------------------
/exar-net/README.md:
--------------------------------------------------------------------------------
1 | # Exar DB's TCP protocol
2 |
3 | Defines the TCP protocol used by Exar DB.
4 |
5 | [](https://crates.io/crates/exar-net)
6 |
7 | [Documentation](https://bfil.github.io/exar-db/exar_net/index.html)
8 |
--------------------------------------------------------------------------------
/exar-net/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! # Exar DB's TCP protocol
2 | //! This module defines the TCP protocol used by Exar DB.
3 | //!
4 | //! ## Protocol messages
5 | //! The protocol is text-based and uses line-separated messages,
6 | //! each message consists of tab-separated values.
7 | //!
8 | //! ### Connect
9 | //! Message used to initialize a connection to Exar DB.
10 | //!
11 | //! ```text
12 | //! Connect collection [username] [password]
13 | //! ```
14 | //!
15 | //! - The 1st field is the string `Connect`.
16 | //! - The 2nd field is the collection name.
17 | //! - The 3rd field is the authentication username (optional).
18 | //! - The 4th field is the authentication password (optional).
19 | //!
20 | //! ### Connected
21 | //! Message used to acknowledge a successful connection.
22 | //!
23 | //! ```text
24 | //! Connected
25 | //! ```
26 | //!
27 | //! - A single field containing the string `Connected`.
28 | //!
29 | //! ### Publish
30 | //! Message used to publish an event into a collection.
31 | //!
32 | //! *It can be used only after a successful connection has been established*.
33 | //!
34 | //! ```text
35 | //! Publish tag1 tag2 timestamp event_data
36 | //! ```
37 | //!
38 | //! - The 1st field is the string `Publish`.
39 | //! - The 2nd field is a space-separated list of tags, the event must contain at least one tag.
40 | //! - The 3rd field is the event timestamp (in ms), if set to 0 the timestamp will be set by the event logger.
41 | //! - The 4th field is the event data/payload, it can contain tabs (`\t`) but new-lines (`\n`) must be escaped.
42 | //!
43 | //! ### Published
44 | //! Message used to acknowledge a successfully published event.
45 | //!
46 | //! ```text
47 | //! Published event_id
48 | //! ```
49 | //!
50 | //! - The 1st field is the string `Published`.
51 | //! - The 2nd field is the `id` (or sequence number) of the event that has been published.
52 | //!
53 | //! ### Subscribe
54 | //! Message used to subscribe to an event stream.
55 | //!
56 | //! *It can be used only after a successful connection has been established*.
57 | //!
58 | //! ```text
59 | //! Subscribe live offset limit [tag1]
60 | //! ```
61 | //!
62 | //! - The 1st field is the string `Subscribe`.
63 | //! - The 2nd field is a boolean specifying wether to keep the subscription listening to real-time events.
64 | //! - The 3rd field is the query offset.
65 | //! - The 4th field is the maximum number of events to consume, if set to 0 a limit is not set.
66 | //! - The 5th field is the tag the events must contain (optional).
67 | //!
68 | //! ### Subscribed
69 | //! Message used to acknowledge a successful subscription.
70 | //!
71 | //! ```text
72 | //! Subscribed
73 | //! ```
74 | //!
75 | //! - A single field containing the string `Subscribed`.
76 | //!
77 | //! ### Event
78 | //! Message containing an event.
79 | //!
80 | //! *It is received after a successful subscription*.
81 | //!
82 | //! ```text
83 | //! Event event_id tag1 tag2 timestamp event_data
84 | //! ```
85 | //!
86 | //! - The 1st field is the string `Event`.
87 | //! - The 2nd field is the `id` (or sequence number) of the event.
88 | //! - The 3rd field is a space-separated list of event tags.
89 | //! - The 4th field is the event timestamp (in ms).
90 | //! - The 5th field is the event data/payload.
91 | //!
92 | //! ### EndOfEventStream
93 | //! Message signaling the end of an event stream.
94 | //!
95 | //! *It is received after a `Subscribed` or a list of `Event`s*.
96 | //!
97 | //! ```text
98 | //! EndOfEventStream
99 | //! ```
100 | //!
101 | //! - A single field containing the string `EndOfEventStream`.
102 | //!
103 | //! ### Error
104 | //! Message containing an error.
105 | //!
106 | //! *It can be received after a `Connect`, `Publish`, `Subscribe`, or during an event stream*.
107 | //!
108 | //! ```text
109 | //! Error type [subtype] description
110 | //! ```
111 | //!
112 | //! - The 1st field is the string `Error`.
113 | //! - The 2nd field is the type of the error, possible values are:
114 | //! `AuthenticationError`, `ConnectionError`, `EventStreamError`, `IoError`, `ParseError`,
115 | //! `SubscriptionError`, `ValidationError`.
116 | //! - The 3rd field is the sub-type of the error (optional), possible values are:
117 | //! `Empty` or `Closed` if the error type is `EventStreamError`,
118 | //! `ParseError` or `MissingField` if the error type is `ParseError`,
119 | //! or a stringified value of `std::io::ErrorKind` if the error type is `IoError`.
120 | //! - The 4th field is the error message/description.
121 | //!
122 |
123 | #[macro_use]
124 | extern crate exar;
125 |
126 | #[cfg(test)] #[macro_use]
127 | extern crate exar_testkit;
128 |
129 | mod message;
130 | mod stream;
131 |
132 | pub use self::message::*;
133 | pub use self::stream::*;
134 |
--------------------------------------------------------------------------------
/exar-server/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "exar-server"
3 | version = "0.1.0"
4 | authors = ["Bruno Filippone "]
5 | description = "Exar DB's TCP server"
6 | keywords = ["exar", "exar-db", "tcp", "server"]
7 | repository = "https://github.com/bfil/exar-db/tree/master/exar-server"
8 | documentation = "https://bfil.github.io/exar-db/exar_server/index.html"
9 | license = "AGPL-3.0"
10 | readme = "README.md"
11 |
12 | [dependencies]
13 | exar = { version = "0.1", path = "../exar-core" }
14 | exar-net = { version = "0.1", path = "../exar-net" }
15 | log = "0.3"
16 | rustc-serialize = { optional = true, version = "0.3" }
17 | serde = { optional = true, version = "0.9" }
18 | serde_derive = { optional = true, version = "0.9" }
19 |
20 | [features]
21 | rustc-serialization = ["rustc-serialize"]
22 | serde-serialization = ["serde", "serde_derive"]
23 |
24 | [dev-dependencies]
25 | exar-testkit = { version = "0.1", path = "../exar-testkit" }
26 |
--------------------------------------------------------------------------------
/exar-server/README.md:
--------------------------------------------------------------------------------
1 | # Exar DB's Server
2 |
3 | A server implementation that uses Exar DB's TCP protocol.
4 |
5 | [](https://crates.io/crates/exar-server)
6 |
7 | [Documentation](https://bfil.github.io/exar-db/exar_server/index.html)
8 |
--------------------------------------------------------------------------------
/exar-server/src/config.rs:
--------------------------------------------------------------------------------
1 | /// Exar DB's server configuration.
2 | ///
3 | /// # Examples
4 | /// ```
5 | /// extern crate exar_server;
6 | ///
7 | /// # fn main() {
8 | /// use exar_server::*;
9 | ///
10 | /// let config = ServerConfig {
11 | /// host: "127.0.0.1".to_owned(),
12 | /// port: 38580,
13 | /// username: Some("username".to_owned()),
14 | /// password: Some("password".to_owned())
15 | /// };
16 | /// # }
17 | /// ```
18 | #[cfg_attr(feature = "rustc-serialization", derive(RustcEncodable, RustcDecodable))]
19 | #[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
20 | #[derive(Clone, Debug, PartialEq, Eq)]
21 | pub struct ServerConfig {
22 | /// The server host.
23 | pub host: String,
24 | /// The server port.
25 | pub port: u16,
26 | /// The server authentication's username.
27 | pub username: Option,
28 | /// The server authentication's password.
29 | pub password: Option
30 | }
31 |
32 | impl Default for ServerConfig {
33 | fn default() -> ServerConfig {
34 | ServerConfig {
35 | host: "127.0.0.1".to_owned(),
36 | port: 38580,
37 | username: None,
38 | password: None
39 | }
40 | }
41 | }
42 |
43 | impl ServerConfig {
44 | /// Returns a string representation of the server address (`host:port`).
45 | pub fn address(&self) -> String {
46 | format!("{}:{}", self.host, self.port)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/exar-server/src/credentials.rs:
--------------------------------------------------------------------------------
1 | /// A structure containing credentials.
2 | #[derive(Clone, Debug, PartialEq, Eq)]
3 | pub struct Credentials {
4 | /// The username.
5 | pub username: Option,
6 | /// The password.
7 | pub password: Option
8 | }
9 |
10 | impl Credentials {
11 | /// Creates new `Credentials`.
12 | pub fn new(username: &str, password: &str) -> Credentials {
13 | Credentials {
14 | username: Some(username.to_owned()),
15 | password: Some(password.to_owned())
16 | }
17 | }
18 |
19 | /// Returns empty `Credentials`.
20 | pub fn empty() -> Credentials {
21 | Credentials {
22 | username: None,
23 | password: None
24 | }
25 | }
26 | }
27 |
28 | #[cfg(test)]
29 | mod tests {
30 | use super::*;
31 |
32 | #[test]
33 | fn test_constructors() {
34 | let credentials = Credentials::new("username", "password");
35 | assert_eq!(credentials.username, Some("username".to_owned()));
36 | assert_eq!(credentials.password, Some("password".to_owned()));
37 |
38 | let credentials = Credentials::empty();
39 | assert_eq!(credentials.username, None);
40 | assert_eq!(credentials.password, None);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/exar-server/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! # Exar DB's server
2 | //! This module contains a server implementation that uses Exar DB's TCP protocol.
3 | //!
4 | //! It uses the one thread per connection model.
5 | //!
6 | //! ## Server Initialization
7 | //! ```no_run
8 | //! extern crate exar;
9 | //! extern crate exar_server;
10 | //!
11 | //! # fn main() {
12 | //! use exar::*;
13 | //! use exar_server::*;
14 | //!
15 | //! let db = Database::new(DatabaseConfig::default());
16 | //!
17 | //! let server_config = ServerConfig::default();
18 | //! let server = Server::new(server_config.clone(), db).unwrap();
19 | //!
20 | //! println!("ExarDB's server running at {}", server_config.address());
21 | //! server.listen();
22 | //! println!("ExarDB's server shutting down");
23 | //! # }
24 | //! ```
25 |
26 | extern crate exar;
27 | extern crate exar_net;
28 |
29 | #[cfg(feature = "rustc-serialization")] extern crate rustc_serialize;
30 | #[cfg(feature = "serde-serialization")] extern crate serde;
31 | #[cfg(feature = "serde-serialization")] #[macro_use] extern crate serde_derive;
32 |
33 | #[cfg(test)]
34 | extern crate exar_testkit;
35 |
36 | #[macro_use]
37 | extern crate log;
38 |
39 | mod credentials;
40 | mod config;
41 | mod handler;
42 | mod server;
43 |
44 | pub use self::credentials::*;
45 | pub use self::config::*;
46 | pub use self::handler::*;
47 | pub use self::server::*;
48 |
--------------------------------------------------------------------------------
/exar-testkit/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "exar-testkit"
3 | version = "0.1.0"
4 | authors = ["Bruno Filippone "]
5 | description = "Offers some utility methods to facilitate testing Exar DB's modules"
6 | keywords = ["exar", "exar-db", "testkit"]
7 | repository = "https://github.com/bfil/exar-db/tree/master/exar-testkit"
8 | license = "AGPL-3.0"
9 |
10 | [dependencies]
11 | rand = "0.3"
12 |
--------------------------------------------------------------------------------
/exar-testkit/src/collections.rs:
--------------------------------------------------------------------------------
1 | use rand;
2 | use rand::Rng;
3 |
4 | pub fn random_collection_name() -> String {
5 | rand::thread_rng()
6 | .gen_ascii_chars()
7 | .take(10)
8 | .collect::()
9 | }
10 |
11 | pub fn invalid_collection_name() -> String {
12 | "missing-directory/error".to_owned()
13 | }
14 |
--------------------------------------------------------------------------------
/exar-testkit/src/encoding.rs:
--------------------------------------------------------------------------------
1 | #[macro_export]
2 | macro_rules! assert_encoded_eq {
3 | ($left:expr, $right:expr) => ( assert_eq!($left.to_tab_separated_string(), $right) )
4 | }
5 |
6 | #[macro_export]
7 | macro_rules! assert_decoded_eq {
8 | ($left:expr, $right:expr) => (
9 | assert_eq!(FromTabSeparatedStr::from_tab_separated_str($left), Ok($right))
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/exar-testkit/src/lib.rs:
--------------------------------------------------------------------------------
1 | #![feature(const_fn)]
2 |
3 | extern crate rand;
4 |
5 | mod collections;
6 | mod encoding;
7 | mod net;
8 |
9 | pub use self::collections::*;
10 | pub use self::encoding::*;
11 | pub use self::net::*;
12 |
--------------------------------------------------------------------------------
/exar-testkit/src/net.rs:
--------------------------------------------------------------------------------
1 | use std::env;
2 | use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
3 | use std::sync::atomic::{AtomicUsize, Ordering};
4 |
5 | static PORT: AtomicUsize = AtomicUsize::new(0);
6 |
7 | fn base_port() -> u16 {
8 | let cwd = env::current_dir().unwrap();
9 | let dirs = ["32-opt", "32-nopt", "musl-64-opt", "cross-opt",
10 | "64-opt", "64-nopt", "64-opt-vg", "64-debug-opt",
11 | "all-opt", "snap3", "dist"];
12 | dirs.iter().enumerate().find(|&(_, dir)| {
13 | cwd.to_str().unwrap().contains(dir)
14 | }).map(|p| p.0).unwrap_or(0) as u16 * 1000 + 19600
15 | }
16 |
17 | fn next_test_ip4() -> SocketAddr {
18 | let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port();
19 | SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port))
20 | }
21 |
22 | pub fn with_addr(f: &mut FnMut(SocketAddr)) {
23 | f(next_test_ip4());
24 | }
25 |
--------------------------------------------------------------------------------
/exar-ui/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | jspm_packages
3 | bower_components
4 | .idea
5 | .DS_STORE
6 | dist
7 | build/reports
8 | coverage
9 | test/e2e/dist
10 | Exar UI-*
11 |
--------------------------------------------------------------------------------
/exar-ui/.npmignore:
--------------------------------------------------------------------------------
1 | jspm_packages
2 | bower_components
3 | .idea
--------------------------------------------------------------------------------
/exar-ui/README.md:
--------------------------------------------------------------------------------
1 | # Exar UI
2 |
3 | A basic Exar DB's user interface, built with [Aurelia](http://aurelia.io), [Electron](http://electron.atom.io) and [TypeScript](https://www.typescriptlang.org)
4 |
5 | ## Running The App
6 |
7 | To run the app, follow these steps.
8 |
9 | 1. Ensure that [NodeJS](http://nodejs.org/) is installed. This provides the platform on which the build tooling runs.
10 | 2. From the project folder, execute the following command:
11 | ```shell
12 | npm install
13 | ```
14 | 3. Ensure that [Gulp](http://gulpjs.com/) is installed globally. If you need to install it, use the following command:
15 | ```shell
16 | npm install -g gulp
17 | ```
18 | > **Note:** Gulp must be installed globally, but a local version will also be installed to ensure a compatible version is used for the project.
19 | 4. Ensure that [jspm](http://jspm.io/) is installed globally. If you need to install it, use the following command:
20 | ```shell
21 | npm install -g jspm
22 | ```
23 | > **Note:** jspm must be installed globally, but a local version will also be installed to ensure a compatible version is used for the project.
24 |
25 | > **Note:** Sometimes jspm queries GitHub to install packages, but GitHub has a rate limit on anonymous API requests. If you receive a rate limit error, you need to configure jspm with your GitHub credentials. You can do this by executing `jspm registry config github` and following the prompts. If you choose to authorize jspm by an access token instead of giving your password (see GitHub `Settings > Personal Access Tokens`), `public_repo` access for the token is required.
26 | 5. Install the client-side dependencies with jspm:
27 |
28 | ```shell
29 | jspm install -y
30 | ```
31 | >**Note:** Windows users, if you experience an error of "unknown command unzip" you can solve this problem by doing `npm install -g unzip` and then re-running `jspm install`.
32 |
33 | 6. Build the project:
34 |
35 | ```shell
36 | gulp build
37 | ```
38 |
39 | 7. Install [Electron](http://electron.atom.io)
40 |
41 | ```shell
42 | npm install electron-prebuilt -g
43 | ```
44 | 8. To start the app, execute the following command:
45 |
46 | ```shell
47 | electron index.js
48 | ```
49 | >**Note:** If you use electron every time or are packaging and so-forth, Then change this line in package.json from
50 | `"main": "dist/main.js",` to `"main": "index.js",`
51 | Build the app (this will give you a dist directory)
52 | ```shell
53 | gulp build
54 | ```
55 | To start the app, execute the following command:
56 | ```shell
57 | electron .
58 | ```
59 |
60 | ## Development
61 |
62 | 1. Run the app in watch mode, execute the following command:
63 |
64 | ```shell
65 | gulp watch
66 | ```
67 |
68 | 2. Then start the app in electron in a separate terminal, execute the following command:
69 |
70 | ```shell
71 | electron index.js
72 | ```
73 |
74 | ## Running The Unit Tests
75 |
76 | To run the unit tests, first ensure that you have followed the steps above in order to install all dependencies and successfully build the library. Once you have done that, proceed with these additional steps:
77 |
78 | 1. Ensure that the [Karma](http://karma-runner.github.io/) CLI is installed. If you need to install it, use the following command:
79 |
80 | ```shell
81 | npm install -g karma-cli
82 | ```
83 | 2. Install Aurelia libs for test visibility:
84 |
85 | ```shell
86 | jspm install aurelia-framework
87 | jspm install aurelia-http-client
88 | jspm install aurelia-router
89 | ```
90 | 3. You can now run the tests with this command:
91 |
92 | ```shell
93 | karma start
94 | ```
95 |
--------------------------------------------------------------------------------
/exar-ui/aurelia.protractor.js:
--------------------------------------------------------------------------------
1 | /* Aurelia Protractor Plugin */
2 | function addValueBindLocator() {
3 | by.addLocator('valueBind', function (bindingModel, opt_parentElement) {
4 | var using = opt_parentElement || document;
5 | var matches = using.querySelectorAll('*[value\\.bind="' + bindingModel +'"]');
6 | var result;
7 |
8 | if (matches.length === 0) {
9 | result = null;
10 | } else if (matches.length === 1) {
11 | result = matches[0];
12 | } else {
13 | result = matches;
14 | }
15 |
16 | return result;
17 | });
18 | }
19 |
20 | function loadAndWaitForAureliaPage(pageUrl) {
21 | browser.get(pageUrl);
22 | return browser.executeAsyncScript(
23 | 'var cb = arguments[arguments.length - 1];' +
24 | 'document.addEventListener("aurelia-composed", function (e) {' +
25 | ' cb("Aurelia App composed")' +
26 | '}, false);'
27 | ).then(function(result){
28 | console.log(result);
29 | return result;
30 | });
31 | }
32 |
33 | function waitForRouterComplete() {
34 | return browser.executeAsyncScript(
35 | 'var cb = arguments[arguments.length - 1];' +
36 | 'document.querySelector("[aurelia-app]")' +
37 | '.aurelia.subscribeOnce("router:navigation:complete", function() {' +
38 | ' cb(true)' +
39 | '});'
40 | ).then(function(result){
41 | return result;
42 | });
43 | }
44 |
45 | /* Plugin hooks */
46 | exports.setup = function(config) {
47 | // Ignore the default Angular synchronization helpers
48 | browser.ignoreSynchronization = true;
49 |
50 | // add the aurelia specific valueBind locator
51 | addValueBindLocator();
52 |
53 | // attach a new way to browser.get a page and wait for Aurelia to complete loading
54 | browser.loadAndWaitForAureliaPage = loadAndWaitForAureliaPage;
55 |
56 | // wait for router navigations to complete
57 | browser.waitForRouterComplete = waitForRouterComplete;
58 | };
59 |
60 | exports.teardown = function(config) {};
61 | exports.postResults = function(config) {};
62 |
--------------------------------------------------------------------------------
/exar-ui/build.sh:
--------------------------------------------------------------------------------
1 | electron-packager . "Exar UI" --platform=darwin --arch=x64 --version=0.36.11 --overwrite --ignore="node_modules/*"
--------------------------------------------------------------------------------
/exar-ui/build/args.js:
--------------------------------------------------------------------------------
1 | var yargs = require('yargs');
2 |
3 | var argv = yargs.argv;
4 | var validBumpTypes = 'major|minor|patch|prerelease'.split('|');
5 | var bump = (argv.bump || 'patch').toLowerCase();
6 |
7 | if (validBumpTypes.indexOf(bump) === -1) {
8 | throw new Error('Unrecognized bump "' + bump + '".');
9 | }
10 |
11 | module.exports = {
12 | bump: bump,
13 | depth: parseInt(argv.depth || '0')
14 | };
15 |
--------------------------------------------------------------------------------
/exar-ui/build/bundles.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "bundles": {
3 | "dist/app-build": {
4 | "includes": [
5 | "[**/*.js]",
6 | "**/*.html!text",
7 | "**/*.css!text"
8 | ],
9 | "options": {
10 | "inject": true,
11 | "minify": true,
12 | "depCache": true,
13 | "rev": false
14 | }
15 | },
16 | "dist/aurelia": {
17 | "includes": [
18 | "aurelia-framework",
19 | "aurelia-bootstrapper",
20 | "aurelia-fetch-client",
21 | "aurelia-router",
22 | "aurelia-animator-css",
23 | "aurelia-templating-binding",
24 | "aurelia-polyfills",
25 | "aurelia-templating-resources",
26 | "aurelia-templating-router",
27 | "aurelia-loader-default",
28 | "aurelia-history-browser",
29 | "aurelia-logging-console",
30 | "bootstrap",
31 | "bootstrap/css/bootstrap.css!text",
32 | "fetch",
33 | "jquery"
34 | ],
35 | "options": {
36 | "inject": true,
37 | "minify": true,
38 | "depCache": false,
39 | "rev": false
40 | }
41 | }
42 | }
43 | };
44 |
--------------------------------------------------------------------------------
/exar-ui/build/export.js:
--------------------------------------------------------------------------------
1 | // this file provides a list of unbundled files that
2 | // need to be included when exporting the application
3 | // for production.
4 | module.exports = {
5 | 'list': [
6 | 'index.html',
7 | 'config.js',
8 | 'favicon.ico',
9 | 'LICENSE',
10 | 'jspm_packages/system.js',
11 | 'jspm_packages/system-polyfills.js',
12 | 'jspm_packages/system-csp-production.js',
13 | 'styles/styles.css'
14 | ],
15 | // this section lists any jspm packages that have
16 | // unbundled resources that need to be exported.
17 | // these files are in versioned folders and thus
18 | // must be 'normalized' by jspm to get the proper
19 | // path.
20 | 'normalize': [
21 | [
22 | // include font-awesome.css and its fonts files
23 | 'font-awesome', [
24 | '/css/font-awesome.min.css',
25 | '/fonts/*'
26 | ]
27 | ], [
28 | // include bootstrap's font files
29 | 'bootstrap', [
30 | '/fonts/*'
31 | ]
32 | ]
33 | ]
34 | };
35 |
--------------------------------------------------------------------------------
/exar-ui/build/paths.js:
--------------------------------------------------------------------------------
1 | var appRoot = 'src/';
2 | var outputRoot = 'dist/';
3 | var exporSrvtRoot = 'export/'
4 |
5 | module.exports = {
6 | root: appRoot,
7 | source: appRoot + '**/*.ts',
8 | html: appRoot + '**/*.html',
9 | css: appRoot + '**/*.css',
10 | style: 'styles/**/*.css',
11 | output: outputRoot,
12 | exportSrv: exporSrvtRoot,
13 | doc: './doc',
14 | e2eSpecsSrc: 'test/e2e/src/**/*.ts',
15 | e2eSpecsDist: 'test/e2e/dist/',
16 | dtsSrc: [
17 | './typings/**/*.d.ts',
18 | './custom_typings/**/*.d.ts'
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/exar-ui/build/tasks/build.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var runSequence = require('run-sequence');
3 | var changed = require('gulp-changed');
4 | var plumber = require('gulp-plumber');
5 | var sourcemaps = require('gulp-sourcemaps');
6 | var paths = require('../paths');
7 | var assign = Object.assign || require('object.assign');
8 | var notify = require('gulp-notify');
9 | var browserSync = require('browser-sync');
10 | var typescript = require('gulp-typescript');
11 |
12 | // transpiles changed es6 files to SystemJS format
13 | // the plumber() call prevents 'pipe breaking' caused
14 | // by errors from other gulp plugins
15 | // https://www.npmjs.com/package/gulp-plumber
16 | var typescriptCompiler = typescriptCompiler || null;
17 | gulp.task('build-system', function() {
18 | if(!typescriptCompiler) {
19 | typescriptCompiler = typescript.createProject('tsconfig.json', {
20 | "typescript": require('typescript')
21 | });
22 | }
23 | return gulp.src(paths.dtsSrc.concat(paths.source))
24 | .pipe(plumber({errorHandler: notify.onError('Error: <%= error.message %>')}))
25 | .pipe(changed(paths.output, {extension: '.ts'}))
26 | .pipe(sourcemaps.init({loadMaps: true}))
27 | .pipe(typescript(typescriptCompiler))
28 | .pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: '/src'}))
29 | .pipe(gulp.dest(paths.output));
30 | });
31 |
32 | // copies changed html files to the output directory
33 | gulp.task('build-html', function() {
34 | return gulp.src(paths.html)
35 | .pipe(changed(paths.output, {extension: '.html'}))
36 | .pipe(gulp.dest(paths.output));
37 | });
38 |
39 | // copies changed css files to the output directory
40 | gulp.task('build-css', function() {
41 | return gulp.src(paths.css)
42 | .pipe(changed(paths.output, {extension: '.css'}))
43 | .pipe(gulp.dest(paths.output))
44 | .pipe(browserSync.stream());
45 | });
46 |
47 | // this task calls the clean task (located
48 | // in ./clean.js), then runs the build-system
49 | // and build-html tasks in parallel
50 | // https://www.npmjs.com/package/gulp-run-sequence
51 | gulp.task('build', function(callback) {
52 | return runSequence(
53 | 'clean',
54 | ['build-system', 'build-html', 'build-css'],
55 | callback
56 | );
57 | });
58 |
--------------------------------------------------------------------------------
/exar-ui/build/tasks/bundle.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var bundler = require('aurelia-bundler');
3 | var bundles = require('../bundles.js');
4 |
5 | var config = {
6 | force: true,
7 | baseURL: '.',
8 | configPath: './config.js',
9 | bundles: bundles.bundles
10 | };
11 |
12 | gulp.task('bundle', ['build'], function() {
13 | return bundler.bundle(config);
14 | });
15 |
16 | gulp.task('unbundle', function() {
17 | return bundler.unbundle(config);
18 | });
19 |
--------------------------------------------------------------------------------
/exar-ui/build/tasks/clean.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var paths = require('../paths');
3 | var del = require('del');
4 | var vinylPaths = require('vinyl-paths');
5 |
6 | // deletes all files in the output path
7 | gulp.task('clean', ['unbundle'], function() {
8 | return gulp.src([paths.output])
9 | .pipe(vinylPaths(del));
10 | });
11 |
--------------------------------------------------------------------------------
/exar-ui/build/tasks/dev.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var tools = require('aurelia-tools');
3 | var args = require('../args');
4 |
5 | // source code for the tasks called in this file
6 | // is located at: https://github.com/aurelia/tools/blob/master/src/dev.js
7 |
8 | // updates dependencies in this folder
9 | // from folders in the parent directory
10 | gulp.task('update-own-deps', function() {
11 | tools.updateOwnDependenciesFromLocalRepositories(args.depth);
12 | });
13 |
14 | // quickly pulls in all of the aurelia
15 | // github repos, placing them up one directory
16 | // from where the command is executed,
17 | // then runs `npm install`
18 | // and `gulp build` for each repo
19 | gulp.task('build-dev-env', function() {
20 | tools.buildDevEnv();
21 | });
22 |
23 | // quickly pulls in all of the aurelia
24 | // github repos, placing them up one directory
25 | // from where the command is executed
26 | gulp.task('pull-dev-env', function() {
27 | tools.pullDevEnv();
28 | });
29 |
--------------------------------------------------------------------------------
/exar-ui/build/tasks/e2e.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var paths = require('../paths');
3 | var plumber = require('gulp-plumber');
4 | var webdriverUpdate = require('gulp-protractor').webdriver_update;
5 | var webdriverStandalone = require('gulp-protractor').webdriver_standalone;
6 | var protractor = require('gulp-protractor').protractor;
7 | var typescript = require('gulp-typescript');
8 | var assign = Object.assign || require('object.assign');
9 | var del = require('del');
10 |
11 | // for full documentation of gulp-protractor,
12 | // please check https://github.com/mllrsohn/gulp-protractor
13 | gulp.task('webdriver-update', webdriverUpdate);
14 | gulp.task('webdriver-standalone', ['webdriver-update'], webdriverStandalone);
15 |
16 | gulp.task('clean-e2e', function() {
17 | return del(paths.e2eSpecsDist + '*');
18 | });
19 |
20 | // transpiles files in
21 | // /test/e2e/src/ from es6 to es5
22 | // then copies them to test/e2e/dist/
23 | var typescriptCompiler = typescriptCompiler || null;
24 | gulp.task('build-e2e', ['clean-e2e'], function() {
25 | if(!typescriptCompiler) {
26 | typescriptCompiler = typescript.createProject('tsconfig.json', {
27 | "typescript": require('typescript'),
28 | module: 'commonjs'
29 | });
30 | }
31 | return gulp.src(paths.dtsSrc.concat(paths.e2eSpecsSrc))
32 | .pipe(typescript(typescriptCompiler))
33 | .pipe(gulp.dest(paths.e2eSpecsDist));
34 | });
35 |
36 | // runs build-e2e task
37 | // then runs end to end tasks
38 | // using Protractor: http://angular.github.io/protractor/
39 | gulp.task('e2e', ['build-e2e'], function(cb) {
40 | return gulp.src(paths.e2eSpecsDist + '**/*.js')
41 | .pipe(protractor({
42 | configFile: 'protractor.conf.js',
43 | args: ['--baseUrl', 'http://127.0.0.1:9000']
44 | }))
45 | .on('end', function() { process.exit(); })
46 | .on('error', function(e) { throw e; });
47 | });
48 |
--------------------------------------------------------------------------------
/exar-ui/build/tasks/export-release.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const gulp = require('gulp');
4 | const runSequence = require('run-sequence');
5 | const del = require('del');
6 | const vinylPaths = require('vinyl-paths');
7 | const jspm = require('jspm');
8 | const paths = require('../paths');
9 | const bundles = require('../bundles.js');
10 | const resources = require('../export.js');
11 |
12 | function getBundles() {
13 | let bl = [];
14 | for (let b in bundles.bundles) {
15 | bl.push(b + '*.js');
16 | }
17 | return bl;
18 | }
19 |
20 | function getExportList() {
21 | return resources.list.concat(getBundles());
22 | }
23 |
24 | function normalizeExportPaths() {
25 | const pathsToNormalize = resources.normalize;
26 |
27 | let promises = pathsToNormalize.map(pathSet => {
28 | const packageName = pathSet[ 0 ];
29 | const fileList = pathSet[ 1 ];
30 |
31 | return jspm.normalize(packageName).then((normalized) => {
32 | const packagePath = normalized.substring(normalized.indexOf('jspm_packages'), normalized.lastIndexOf('.js'));
33 | return fileList.map(file => packagePath + file);
34 | });
35 | });
36 |
37 | return Promise.all(promises)
38 | .then((normalizedPaths) => {
39 | return normalizedPaths.reduce((prev, curr) => prev.concat(curr), []);
40 | });
41 | }
42 |
43 | // deletes all files in the output path
44 | gulp.task('clean-export', function() {
45 | return gulp.src([ paths.exportSrv ])
46 | .pipe(vinylPaths(del));
47 | });
48 |
49 | gulp.task('export-copy', function() {
50 | return gulp.src(getExportList(), { base: '.' })
51 | .pipe(gulp.dest(paths.exportSrv));
52 | });
53 |
54 | gulp.task('export-normalized-resources', function() {
55 | return normalizeExportPaths().then(normalizedPaths => {
56 | return gulp.src(normalizedPaths, { base: '.' })
57 | .pipe(gulp.dest(paths.exportSrv));
58 | });
59 | });
60 |
61 | // use after prepare-release
62 | gulp.task('export', function(callback) {
63 | return runSequence(
64 | 'bundle',
65 | 'clean-export',
66 | 'export-normalized-resources',
67 | 'export-copy',
68 | callback
69 | );
70 | });
71 |
--------------------------------------------------------------------------------
/exar-ui/build/tasks/lint.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var paths = require('../paths');
3 | var tslint = require('gulp-tslint');
4 |
5 | gulp.task('lint', function() {
6 | return gulp.src(paths.source)
7 | .pipe(tslint())
8 | .pipe(tslint.report('prose', {
9 | emitError: false
10 | }));
11 | });
12 |
--------------------------------------------------------------------------------
/exar-ui/build/tasks/prepare-release.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var runSequence = require('run-sequence');
3 | var paths = require('../paths');
4 | var changelog = require('conventional-changelog');
5 | var fs = require('fs');
6 | var bump = require('gulp-bump');
7 | var args = require('../args');
8 |
9 | // utilizes the bump plugin to bump the
10 | // semver for the repo
11 | gulp.task('bump-version', function() {
12 | return gulp.src(['./package.json'])
13 | .pipe(bump({type: args.bump})) //major|minor|patch|prerelease
14 | .pipe(gulp.dest('./'));
15 | });
16 |
17 | // generates the CHANGELOG.md file based on commit
18 | // from git commit messages
19 | gulp.task('changelog', function(callback) {
20 | var pkg = JSON.parse(fs.readFileSync('./package.json', 'utf-8'));
21 |
22 | return changelog({
23 | repository: pkg.repository.url,
24 | version: pkg.version,
25 | file: paths.doc + '/CHANGELOG.md'
26 | }, function(err, log) {
27 | fs.writeFileSync(paths.doc + '/CHANGELOG.md', log);
28 | });
29 | });
30 |
31 | // calls the listed sequence of tasks in order
32 | gulp.task('prepare-release', function(callback) {
33 | return runSequence(
34 | 'build',
35 | 'lint',
36 | 'bump-version',
37 | 'changelog',
38 | callback
39 | );
40 | });
41 |
--------------------------------------------------------------------------------
/exar-ui/build/tasks/serve.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var browserSync = require('browser-sync');
3 | var historyApiFallback = require('connect-history-api-fallback')
4 |
5 | function enableCORS(req, res, next) {
6 | res.setHeader('Access-Control-Allow-Origin', '*');
7 | res.setHeader('Access-Control-Allow-Methods', 'GET');
8 | res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Connection, Content-Type, Accept, Accept-Encoding, Accept-Language,' +
9 | ' Host, Referer, User-Agent, Overwrite, Destination, Depth, X-Token, X-File-Size, If-Modified-Since, X-File-Name, Cache-Control');
10 | if (req.method.match(/^OPTIONS$/i)) return res.end();
11 | return next();
12 | }
13 |
14 | // this task utilizes the browsersync plugin
15 | // to create a dev server instance
16 | // at http://localhost:8000
17 | gulp.task('serve', ['build'], function(done) {
18 | browserSync({
19 | online: false,
20 | open: false,
21 | port: 8000,
22 | server: {
23 | baseDir: ['.'],
24 | middleware: [ historyApiFallback(), enableCORS ]
25 | }
26 | }, done);
27 | });
28 |
29 | // this task utilizes the browsersync plugin
30 | // to create a dev server instance
31 | // at http://localhost:8000
32 | gulp.task('serve-bundle', ['bundle'], function(done) {
33 | browserSync({
34 | online: false,
35 | open: false,
36 | port: 8000,
37 | server: {
38 | baseDir: ['.'],
39 | middleware: [ historyApiFallback(), enableCORS ]
40 | }
41 | }, done);
42 | });
43 |
44 | // this task utilizes the browsersync plugin
45 | // to create a dev server instance
46 | // at http://localhost:8000
47 | gulp.task('serve-export', ['export'], function(done) {
48 | browserSync({
49 | online: false,
50 | open: false,
51 | port: 8000,
52 | server: {
53 | baseDir: ['./export'],
54 | middleware: [ historyApiFallback(), enableCORS ]
55 | }
56 | }, done);
57 | });
58 |
--------------------------------------------------------------------------------
/exar-ui/build/tasks/test.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var Karma = require('karma').Server;
3 |
4 | /**
5 | * Run test once and exit
6 | */
7 | gulp.task('test', function (done) {
8 | new Karma({
9 | configFile: __dirname + '/../../karma.conf.js',
10 | singleRun: true
11 | }, done).start();
12 | });
13 |
14 | /**
15 | * Watch for file changes and re-run tests on each change
16 | */
17 | gulp.task('tdd', function (done) {
18 | new Karma({
19 | configFile: __dirname + '/../../karma.conf.js'
20 | }, done).start();
21 | });
22 |
--------------------------------------------------------------------------------
/exar-ui/build/tasks/watch.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var paths = require('../paths');
3 | var browserSync = require('browser-sync');
4 |
5 | // outputs changes to files to the console
6 | function reportChange(event) {
7 | console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
8 | }
9 |
10 | // this task wil watch for changes
11 | // to js, html, and css files and call the
12 | // reportChange method. Also, by depending on the
13 | // serve task, it will instantiate a browserSync session
14 | gulp.task('watch', ['serve'], function() {
15 | gulp.watch(paths.source, ['build-system', browserSync.reload]).on('change', reportChange);
16 | gulp.watch(paths.html, ['build-html', browserSync.reload]).on('change', reportChange);
17 | gulp.watch(paths.css, ['build-css', browserSync.reload]).on('change', reportChange);
18 | gulp.watch(paths.style, browserSync.reload).on('change', reportChange);
19 | });
20 |
--------------------------------------------------------------------------------
/exar-ui/custom_typings/tcp-socket.d.ts:
--------------------------------------------------------------------------------
1 | interface TCPSocketStatic {
2 | open(host: string, port: number): TCPSocket;
3 | }
4 |
5 | interface TCPSocket {
6 | send(data: ArrayBufferView);
7 | close();
8 |
9 | onopen: any;
10 | ondata: (ArrayBufferView) => any;
11 | onerror: any;
12 | onclose: any;
13 | ondrain: any;
14 | }
15 |
16 | interface Navigator {
17 | TCPSocket: TCPSocketStatic;
18 | }
19 |
--------------------------------------------------------------------------------
/exar-ui/custom_typings/text-encoding.d.ts:
--------------------------------------------------------------------------------
1 | // Type definitions for text-encoding
2 | // Project: https://github.com/inexorabletash/text-encoding
3 | // Definitions by: MIZUNE Pine
4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped
5 |
6 | declare module TextEncoding {
7 | interface TextDecoderOptions {
8 | fatal?: boolean;
9 | ignoreBOM?: boolean;
10 | }
11 |
12 | interface TextDecodeOptions {
13 | stream?: boolean;
14 | }
15 |
16 | interface TextEncoderOptions {
17 | NONSTANDARD_allowLegacyEncoding?: boolean;
18 | }
19 |
20 | interface TextDecoder {
21 | encoding: string;
22 | fatal: boolean;
23 | ignoreBOM: boolean;
24 | decode(input?: ArrayBufferView, options?: TextDecodeOptions): string;
25 | }
26 |
27 | interface TextEncoder {
28 | encoding: string;
29 | encode(input?: string, options?: TextEncodeOptions): Uint8Array;
30 | }
31 |
32 | interface TextEncodeOptions {
33 | stream?: boolean;
34 | }
35 | }
36 |
37 | declare var TextDecoder: {
38 | (label?: string, options?: TextEncoding.TextDecoderOptions): TextEncoding.TextDecoder;
39 | new (label?: string, options?: TextEncoding.TextDecoderOptions): TextEncoding.TextDecoder;
40 | };
41 |
42 | declare var TextEncoder: {
43 | (utfLabel?: string, options?: TextEncoding.TextEncoderOptions): TextEncoding.TextEncoder;
44 | new (utfLabel?: string, options?: TextEncoding.TextEncoderOptions): TextEncoding.TextEncoder;
45 | };
46 |
--------------------------------------------------------------------------------
/exar-ui/gulpfile.js:
--------------------------------------------------------------------------------
1 | // all gulp tasks are located in the ./build/tasks directory
2 | // gulp configuration is in files in ./build directory
3 | require('require-dir')('build/tasks');
4 |
--------------------------------------------------------------------------------
/exar-ui/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exar UI
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
Loading Exar UI..
13 |
14 |
15 |
16 |
17 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/exar-ui/index.js:
--------------------------------------------------------------------------------
1 | //Note: This file is provided as an aid to help you get up and running with
2 | //Electron for desktop apps. See the readme file for more information.
3 |
4 | 'use strict';
5 |
6 | var app = require('app');
7 | var BrowserWindow = require('browser-window');
8 |
9 | // require('crash-reporter').start();
10 |
11 | var mainWindow = null;
12 |
13 | app.on('window-all-closed', function () {
14 | if (process.platform != 'darwin') {
15 | app.quit();
16 | }
17 | });
18 |
19 | app.on('ready', function () {
20 | mainWindow = new BrowserWindow({
21 | width: 800,
22 | height: 600
23 | });
24 |
25 | // mainWindow.webContents.openDevTools();
26 |
27 | mainWindow.loadURL('file://' + __dirname + '/index.html');
28 | mainWindow.webContents.on('did-finish-load', function () {
29 | mainWindow.setTitle(app.getName());
30 | });
31 | mainWindow.on('closed', function () {
32 | mainWindow = null;
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/exar-ui/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 | config.set({
3 | basePath: '.',
4 | frameworks: ['systemjs', 'jasmine'],
5 | systemjs: {
6 | configFile: 'config.js',
7 | config: {
8 | paths: {
9 | "*": "*",
10 | "src/*": "src/*",
11 | "typescript": "node_modules/typescript/lib/typescript.js",
12 | "systemjs": "node_modules/systemjs/dist/system.js",
13 | 'system-polyfills': 'node_modules/systemjs/dist/system-polyfills.js',
14 | 'es6-module-loader': 'node_modules/es6-module-loader/dist/es6-module-loader.js'
15 | },
16 | packages: {
17 | 'test/unit': {
18 | defaultExtension: 'ts'
19 | },
20 | 'src': {
21 | defaultExtension: 'ts'
22 | }
23 | },
24 | transpiler: 'typescript'
25 | },
26 | serveFiles: [
27 | 'src/**/*.ts',
28 | 'jspm_packages/**/*.js'
29 | ]
30 | },
31 | files: [
32 | 'test/unit/setup.ts',
33 | 'test/unit/*.ts',
34 | 'test/unit/**/*.ts'
35 | ],
36 | exclude: [],
37 | preprocessors: { },
38 | reporters: ['spec'],
39 | port: 9876,
40 | colors: true,
41 | logLevel: config.LOG_INFO,
42 | autoWatch: true,
43 | browsers: ['Chrome'],
44 | singleRun: false
45 | });
46 | };
47 |
--------------------------------------------------------------------------------
/exar-ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "exar-ui",
3 | "version": "0.1.0",
4 | "author": "Bruno Filippone ",
5 | "license": "UNLICENSED",
6 | "main": "index.js",
7 | "repository": {
8 | "type": "git",
9 | "url": "http://github.com/bfil/exar-ui"
10 | },
11 | "scripts": {
12 | "test": "gulp test",
13 | "e2e": "gulp serve e2e"
14 | },
15 | "devDependencies": {
16 | "aurelia-bundler": "^0.4.0",
17 | "aurelia-tools": "^0.2.3",
18 | "browser-sync": "^2.13.0",
19 | "connect-history-api-fallback": "^1.1.0",
20 | "conventional-changelog": "1.1.0",
21 | "del": "^2.2.1",
22 | "es6-module-loader": "^0.17.8",
23 | "gulp": "^3.9.1",
24 | "gulp-bump": "^2.1.0",
25 | "gulp-changed": "^1.3.0",
26 | "gulp-notify": "^2.2.0",
27 | "gulp-plumber": "^1.1.0",
28 | "gulp-protractor": "^2.4.0",
29 | "gulp-sourcemaps": "^1.6.0",
30 | "gulp-tslint": "^5.0.0",
31 | "gulp-typescript": "^2.13.6",
32 | "isparta": "^4.0.0",
33 | "jasmine-core": "^2.4.1",
34 | "jspm": "0.16.15",
35 | "karma": "^0.13.22",
36 | "karma-chrome-launcher": "^1.0.1",
37 | "karma-jasmine": "^1.0.2",
38 | "karma-spec-reporter": "0.0.26",
39 | "karma-systemjs": "^0.14.0",
40 | "object.assign": "^4.0.3",
41 | "require-dir": "^0.3.0",
42 | "run-sequence": "^1.2.1",
43 | "systemjs": "0.19.31",
44 | "tslint": "^3.11.0",
45 | "typescript": "^2.0.0",
46 | "vinyl-paths": "^2.1.0",
47 | "yargs": "^4.7.1"
48 | },
49 | "jspm": {
50 | "dependencies": {
51 | "aurelia-animator-css": "npm:aurelia-animator-css@^1.0.0",
52 | "aurelia-bootstrapper": "npm:aurelia-bootstrapper@^1.0.0",
53 | "aurelia-dialog": "npm:aurelia-dialog@^1.0.0",
54 | "aurelia-fetch-client": "npm:aurelia-fetch-client@^1.0.0",
55 | "aurelia-framework": "npm:aurelia-framework@^1.0.0",
56 | "aurelia-history-browser": "npm:aurelia-history-browser@^1.0.0",
57 | "aurelia-http-client": "npm:aurelia-http-client@^1.0.0",
58 | "aurelia-loader-default": "npm:aurelia-loader-default@^1.0.0",
59 | "aurelia-logging-console": "npm:aurelia-logging-console@^1.0.0",
60 | "aurelia-pal-browser": "npm:aurelia-pal-browser@^1.0.0",
61 | "aurelia-polyfills": "npm:aurelia-polyfills@^1.0.0",
62 | "aurelia-router": "npm:aurelia-router@^1.0.0",
63 | "aurelia-templating-binding": "npm:aurelia-templating-binding@^1.0.0",
64 | "aurelia-templating-resources": "npm:aurelia-templating-resources@^1.0.0",
65 | "aurelia-templating-router": "npm:aurelia-templating-router@^1.0.0",
66 | "bootstrap": "github:twbs/bootstrap@^3.3.7",
67 | "emailjs-tcp-socket": "npm:emailjs-tcp-socket@^1.0.2",
68 | "fetch": "github:github/fetch@^0.10.1",
69 | "font-awesome": "npm:font-awesome@^4.5.0",
70 | "forge": "npm:forge@^2.3.0",
71 | "rx": "npm:rx@^4.1.0",
72 | "text": "github:systemjs/plugin-text@^0.0.3"
73 | },
74 | "devDependencies": {
75 | "core-js": "npm:core-js@^2.0.3",
76 | "traceur": "github:jmcriffey/bower-traceur@0.0.92",
77 | "traceur-runtime": "github:jmcriffey/bower-traceur-runtime@0.0.92"
78 | },
79 | "overrides": {
80 | "npm:core-js@2.0.3": {
81 | "main": "client/shim.min"
82 | }
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/exar-ui/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // An example configuration file.
2 | exports.config = {
3 | directConnect: true,
4 |
5 | // Capabilities to be passed to the webdriver instance.
6 | capabilities: {
7 | 'browserName': 'chrome'
8 | },
9 |
10 | //seleniumAddress: 'http://0.0.0.0:4444',
11 | // add proper version number
12 | seleniumServerJar: './node_modules/gulp-protractor/node_modules/protractor/selenium/selenium-server-standalone-2.44.0.jar',
13 | specs: ['test/e2e/dist/**/*.js'],
14 |
15 | plugins: [{
16 | path: 'aurelia.protractor.js'
17 | }],
18 |
19 |
20 | // Options to be passed to Jasmine-node.
21 | jasmineNodeOpts: {
22 | showColors: true,
23 | defaultTimeoutInterval: 30000
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/exar-ui/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/exar-ui/src/app.ts:
--------------------------------------------------------------------------------
1 | import {Router, RouterConfiguration} from 'aurelia-router';
2 |
3 | export class App {
4 | router: Router;
5 |
6 | configureRouter(config: RouterConfiguration, router: Router) {
7 | config.title = 'Exar UI';
8 | config.map([
9 | { route: '', name: 'home', moduleId: 'views/home', nav: false, title: 'Home' },
10 | { route: 'manage-connections', name: 'manage-connections', moduleId: 'views/manage-connections', nav: false, title: 'Manage Connections' }
11 | ]);
12 | this.router = router;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/exar-ui/src/components/dialogs/edit-connection.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Connection Parameters
5 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/exar-ui/src/components/dialogs/edit-connection.ts:
--------------------------------------------------------------------------------
1 | import {autoinject} from 'aurelia-framework';
2 | import {DialogController} from 'aurelia-dialog';
3 |
4 | import {SavedConnection} from 'models/saved-connection';
5 |
6 | @autoinject
7 | export class EditConnection {
8 | connection: SavedConnection;
9 | dialogController: DialogController;
10 |
11 | constructor(dialogController: DialogController) {
12 | this.dialogController = dialogController;
13 | }
14 |
15 | activate(connection: SavedConnection) {
16 | this.connection = connection;
17 | }
18 |
19 | saveConnection() {
20 | this.dialogController.ok(this.connection);
21 | }
22 |
23 | cancelConnection() {
24 | this.dialogController.cancel()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/exar-ui/src/components/layout/nav-bar.html:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
--------------------------------------------------------------------------------
/exar-ui/src/components/layout/nav-bar.ts:
--------------------------------------------------------------------------------
1 | import {autoinject, bindable} from 'aurelia-framework';
2 | import {Router} from 'aurelia-router';
3 |
4 | @autoinject
5 | export class NavBar {
6 |
7 | @bindable router: Router;
8 |
9 | element: Element;
10 |
11 | constructor(element: Element) {
12 | this.element = element;
13 | }
14 | }
--------------------------------------------------------------------------------
/exar-ui/src/converters/obfuscate.ts:
--------------------------------------------------------------------------------
1 | export class ObfuscateValueConverter {
2 | toView(value) {
3 | if(value) return Array(value.length).join('*');
4 | else return '';
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/exar-ui/src/exar/client.ts:
--------------------------------------------------------------------------------
1 | import {Connection, Event, Query} from 'exar/model';
2 | import {Connect, Connected, Publish, Published, Subscribe, Subscribed, DatabaseError, TcpMessage} from 'exar/net';
3 |
4 | import * as Rx from 'rx';
5 |
6 | export class ExarClient {
7 |
8 | private socket: TCPSocket;
9 | private socketObservable: Rx.ControlledObservable;
10 |
11 | private encoder: TextEncoding.TextEncoder;
12 | private decoder: TextEncoding.TextDecoder;
13 |
14 | constructor() {
15 | this.encoder = new TextEncoder("utf8");
16 | this.decoder = new TextDecoder("utf8");
17 | }
18 |
19 | private encode(data: string): ArrayBufferView {
20 | return this.encoder.encode(data);
21 | }
22 |
23 | private decode(data: ArrayBufferView): string {
24 | return this.decoder.decode(data);
25 | }
26 |
27 | private send(message: TcpMessage) {
28 | this.socket.send(this.encode(message.toTabSeparatedString()));
29 | }
30 |
31 | private requestSubscription: Rx.IDisposable;
32 | private request(message: TcpMessage, handleResponse: (message: string) => T, sendOnOpen: boolean = false) {
33 | return new Promise((resolve, reject) => {
34 | if(this.requestSubscription) this.requestSubscription.dispose();
35 | this.requestSubscription = this.socketObservable.subscribe(message => {
36 | resolve(handleResponse(message));
37 | }, reject);
38 | if(sendOnOpen) this.socket.onopen = () => this.send(message);
39 | else this.send(message);
40 | this.socketObservable.request(1);
41 | });
42 | }
43 |
44 | private createSocketObservable() {
45 | this.socketObservable = Rx.Observable.create(observer => {
46 | this.socket.ondata = message => {
47 | let messages = this.decode(message.data).split('\n').filter(m => !!m);
48 | for(let message of messages) {
49 | if (message.startsWith('Error')) {
50 | observer.onError(DatabaseError.fromTabSeparatedString(message));
51 | this.createSocketObservable();
52 | }
53 | else if (message) observer.onNext(message);
54 | }
55 | };
56 | this.socket.onerror = error => observer.onError(error.data);
57 | }).controlled();
58 | }
59 |
60 | connect(connectionInfo: Connection) {
61 | this.socket = navigator.TCPSocket.open(connectionInfo.host, connectionInfo.port);
62 | this.createSocketObservable();
63 | return this.request(
64 | new Connect(connectionInfo.collection, connectionInfo.username, connectionInfo.password),
65 | Connected.fromTabSeparatedString, true);
66 | }
67 |
68 | onDisconnect(onDisconnect: () => any) {
69 | this.socket.onclose = onDisconnect;
70 | }
71 |
72 | disconnect() {
73 | this.socket.close();
74 | }
75 |
76 | publish(event: Event) {
77 | return this.request(new Publish(event), Published.fromTabSeparatedString);
78 | }
79 |
80 | subscribe(query: Query) {
81 | return this.request(new Subscribe(query), message => {
82 | return Rx.Observable.create(observer => {
83 | let subscription = this.socketObservable.subscribe(message => {
84 | if (message === 'EndOfEventStream') {
85 | observer.onCompleted();
86 | subscription.dispose();
87 | } else {
88 | observer.onNext(Event.fromTabSeparatedString(message));
89 | this.socketObservable.request(1);
90 | }
91 | });
92 | this.socketObservable.request(1);
93 | });
94 | });
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/exar-ui/src/exar/model.ts:
--------------------------------------------------------------------------------
1 | import {TcpMessage, TcpMessageEncoder, TcpMessageDecoder} from 'exar/net';
2 |
3 | export class Connection {
4 | host: string;
5 | port: number;
6 | username: string;
7 | password: string;
8 | collection: string;
9 |
10 | constructor(collection: string, host: string = 'localhost', port: number = 38580, username?: string, password?: string) {
11 | this.collection = collection;
12 | this.host = host;
13 | this.port = port;
14 | this.username = username;
15 | this.password = password;
16 | }
17 | }
18 |
19 | export class Event implements TcpMessage {
20 | id: number = 0;
21 | tags: string[];
22 | timestamp: number = 0;
23 | data: string;
24 |
25 | constructor(data: string, tags: string[]) {
26 | this.data = data;
27 | this.tags = tags;
28 | }
29 |
30 | withId(id: number) {
31 | this.id = id;
32 | return this;
33 | }
34 |
35 | withTimestamp(timestamp: number) {
36 | this.timestamp = timestamp;
37 | return this;
38 | }
39 |
40 | toTabSeparatedString(): string {
41 | return TcpMessageEncoder.toTabSeparatedString('Event',
42 | this.id || 0,
43 | this.timestamp || 0,
44 | this.tags.join(' '),
45 | this.data);
46 | }
47 |
48 | static fromTabSeparatedString(data: string): Event {
49 | let messageParts = TcpMessageDecoder.parseTabSeparatedString(data, 5);
50 | let id = parseInt(messageParts[1]);
51 | let timestamp = parseInt(messageParts[2]);
52 | let tags = messageParts[3].split(' ');
53 | let eventData = messageParts[4];
54 | return new Event(eventData, tags).withId(id).withTimestamp(timestamp);
55 | }
56 | }
57 |
58 | export class Query {
59 | liveStream: boolean;
60 | offset: number;
61 | limit: number;
62 | tag: string;
63 |
64 | constructor(liveStream: boolean, offset: number = 0, limit: number = 0, tag?: string) {
65 | this.liveStream = liveStream;
66 | this.offset = offset;
67 | this.limit = limit;
68 | this.tag = tag;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/exar-ui/src/exar/net.ts:
--------------------------------------------------------------------------------
1 | import {Event, Query} from 'exar/model';
2 |
3 | export class TcpMessageEncoder {
4 | static toTabSeparatedString(...args): string {
5 | return args.filter(arg => typeof arg !== 'undefined').join('\t') + '\n';
6 | }
7 | }
8 |
9 | export class TcpMessageDecoder {
10 | static parseTabSeparatedString(data: string, numberOfParts: number): string[] {
11 | return data.split('\t', numberOfParts);
12 | }
13 | }
14 |
15 | export interface TcpMessage {
16 | toTabSeparatedString(): string;
17 | }
18 |
19 | export class Connect implements TcpMessage {
20 |
21 | private collection: string;
22 | private username: string;
23 | private password: string;
24 |
25 | constructor(collection: string, username?: string, password?: string) {
26 | this.collection = collection;
27 | this.username = username;
28 | this.password = password;
29 | }
30 |
31 | toTabSeparatedString() {
32 | return TcpMessageEncoder.toTabSeparatedString('Connect',
33 | this.collection,
34 | this.username,
35 | this.password);
36 | }
37 |
38 | static fromTabSeparatedString(data: string) {
39 | let messageParts = TcpMessageDecoder.parseTabSeparatedString(data, 4);
40 | let collection = messageParts[1];
41 | let username = messageParts[2];
42 | let password = messageParts[3];
43 | return new Connect(collection, username, password);
44 | }
45 | }
46 |
47 | export class Connected implements TcpMessage {
48 |
49 | toTabSeparatedString() {
50 | return TcpMessageEncoder.toTabSeparatedString('Connected');
51 | }
52 |
53 | static fromTabSeparatedString(data: string) {
54 | let messageParts = TcpMessageDecoder.parseTabSeparatedString(data, 1);
55 | return new Connected();
56 | }
57 | }
58 |
59 | export class Publish implements TcpMessage {
60 |
61 | private event: Event;
62 |
63 | constructor(event: Event) {
64 | this.event = event;
65 | }
66 |
67 | toTabSeparatedString() {
68 | return TcpMessageEncoder.toTabSeparatedString('Publish',
69 | this.event.tags.join(' '),
70 | this.event.timestamp,
71 | this.event.data);
72 | }
73 |
74 | static fromTabSeparatedString(data: string) {
75 | let messageParts = TcpMessageDecoder.parseTabSeparatedString(data, 4);
76 | let tags = messageParts[1].split(' ');
77 | let timestamp = parseInt(messageParts[2]);
78 | let eventData = messageParts[3];
79 | let event = new Event(eventData, tags).withTimestamp(timestamp);
80 | return new Publish(event);
81 | }
82 | }
83 |
84 | export class Published implements TcpMessage {
85 |
86 | private eventId: number;
87 |
88 | constructor(eventId: number) {
89 | this.eventId = eventId;
90 | }
91 |
92 | toTabSeparatedString() {
93 | return TcpMessageEncoder.toTabSeparatedString('Published', this.eventId);
94 | }
95 |
96 | static fromTabSeparatedString(data: string) {
97 | let messageParts = TcpMessageDecoder.parseTabSeparatedString(data, 2);
98 | let eventId = parseInt(messageParts[1]);
99 | return new Published(eventId);
100 | }
101 | }
102 |
103 | export class Subscribe implements TcpMessage {
104 |
105 | private query: Query;
106 |
107 | constructor(query: Query) {
108 | this.query = query;
109 | }
110 |
111 | toTabSeparatedString() {
112 | return TcpMessageEncoder.toTabSeparatedString('Subscribe',
113 | this.query.liveStream,
114 | this.query.offset || 0,
115 | this.query.limit || 0,
116 | this.query.tag);
117 | }
118 |
119 | static fromTabSeparatedString(data: string) {
120 | let messageParts = TcpMessageDecoder.parseTabSeparatedString(data, 5);
121 | let liveStream = messageParts[1] === 'true';
122 | let offset = parseInt(messageParts[2]);
123 | let limit = parseInt(messageParts[3]);
124 | let tag = messageParts[4];
125 | let query = new Query(liveStream, offset, limit, tag);
126 | return new Subscribe(query);
127 | }
128 | }
129 |
130 | export class Subscribed implements TcpMessage {
131 |
132 | toTabSeparatedString() {
133 | return TcpMessageEncoder.toTabSeparatedString('Subscribed');
134 | }
135 |
136 | static fromTabSeparatedString(data: string) {
137 | let messageParts = TcpMessageDecoder.parseTabSeparatedString(data, 1);
138 | return new Subscribed();
139 | }
140 | }
141 |
142 | export class DatabaseError implements TcpMessage {
143 |
144 | private type: string;
145 | private subType: string;
146 | private data: string;
147 |
148 | constructor(type: string, data: string, subType?: string) {
149 | this.type = type;
150 | this.subType = subType;
151 | this.data = data;
152 | }
153 |
154 | toTabSeparatedString() {
155 | return TcpMessageEncoder.toTabSeparatedString('Error', this.type, this.subType, this.data);
156 | }
157 |
158 | toString() {
159 | if(this.type === 'ParseError' && this.subType === 'MissingField') {
160 | return `${this.type}: missing field at position ${this.data}`;
161 | } else if(this.type === 'AuthenticationError') {
162 | return `${this.type}: missing or invalid credentials`;
163 | } return `${this.type}: ${this.data}`;
164 | }
165 |
166 | static fromTabSeparatedString(data: string) {
167 | let messageParts = TcpMessageDecoder.parseTabSeparatedString(data, 4);
168 | let errorData = messageParts[3] || messageParts[2];
169 | let subType = messageParts[3] ? messageParts[2] : undefined;
170 | return new DatabaseError(messageParts[1], errorData, subType);
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/exar-ui/src/main.ts:
--------------------------------------------------------------------------------
1 | import 'bootstrap';
2 | import 'emailjs-tcp-socket';
3 |
4 | import {Aurelia} from 'aurelia-framework';
5 |
6 | export function configure(aurelia: Aurelia) {
7 | aurelia.use
8 | .standardConfiguration()
9 | .developmentLogging()
10 | .plugin('aurelia-animator-css')
11 | .plugin('aurelia-dialog', config => {
12 | config.useDefaults();
13 | config.settings.lock = false;
14 | })
15 | .globalResources([
16 | 'converters/obfuscate'
17 | ]);
18 |
19 | aurelia.start().then(() => aurelia.setRoot());
20 | }
21 |
--------------------------------------------------------------------------------
/exar-ui/src/models/saved-connection.ts:
--------------------------------------------------------------------------------
1 | export class SavedConnection {
2 | alias: string;
3 | requiresAuth: boolean;
4 | host: string = 'localhost';
5 | port: number = 38580;
6 | username: string;
7 | password: string;
8 | }
9 |
--------------------------------------------------------------------------------
/exar-ui/src/views/connection-handler.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Connection
4 |
32 |
33 |
34 | Connected to ${collection}
35 |
37 |
38 |
39 |
46 |
64 |
65 |
66 |
67 | Messages
68 |
69 |
70 |
71 | - ${message.payload}
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/exar-ui/src/views/connection-handler.ts:
--------------------------------------------------------------------------------
1 | import {autoinject, bindable} from 'aurelia-framework';
2 |
3 | import {ExarClient} from 'exar/client';
4 | import {Connection, Event, Query} from 'exar/model';
5 | import {TcpMessage} from 'exar/net';
6 |
7 | import {SavedConnection} from 'models/saved-connection';
8 |
9 | import * as Rx from 'rx';
10 |
11 | @autoinject
12 | export class ConnectionHandler {
13 | exarClient: ExarClient;
14 |
15 | savedConnections: SavedConnection[];
16 | @bindable connection: SavedConnection;
17 | @bindable collection: string;
18 |
19 | data: string;
20 | tags: string;
21 |
22 | liveStream: boolean = false;
23 | offset: string;
24 | limit: string;
25 | tag: string;
26 |
27 | connected: boolean;
28 | subscription: Rx.IDisposable;
29 | messages: { payload: string, className: string }[];
30 |
31 | bind() {
32 | this.savedConnections = localStorage.getItem('connections.saved') ? JSON.parse(localStorage.getItem('connections.saved')) : [];
33 | if(this.savedConnections.length) {
34 | this.connection = this.savedConnections[0];
35 | }
36 | this.connected = false;
37 | this.messages = [];
38 | }
39 |
40 | unbind() {
41 | if(this.exarClient) this.disconnect();
42 | }
43 |
44 | connect(isReconnection: boolean = false) {
45 | this.exarClient = new ExarClient();
46 | this.exarClient.connect(this.initializeConnection(this.collection, this.connection))
47 | .then(connected => {
48 | this.connected = true;
49 | if(!isReconnection) this.logTcpMessage(connected);
50 | }, this.onError.bind(this));
51 | this.exarClient.onDisconnect(() => {
52 | this.connected = false;
53 | if(!isReconnection) this.logMessage(`Disconnected`, false);
54 | });
55 | }
56 |
57 | disconnect() {
58 | this.exarClient.disconnect();
59 | }
60 |
61 | reconnect() {
62 | this.disconnect();
63 | this.connect(true);
64 | }
65 |
66 | publish() {
67 | let event = new Event(this.data, (this.tags || '').split(' '));
68 | this.exarClient.publish(event).then(
69 | published => this.logTcpMessage(published),
70 | this.onError.bind(this)
71 | )
72 | }
73 |
74 | subscribe() {
75 | let query = new Query(this.liveStream, parseInt(this.offset), parseInt(this.limit), this.tag);
76 | this.exarClient.subscribe(query).then(
77 | eventStream => {
78 | this.logMessage('Subscribed', false);
79 | this.subscription = eventStream.subscribe(
80 | this.logTcpMessage.bind(this),
81 | this.onError.bind(this),
82 | () => {
83 | this.logMessage('EndOfEventStream', false);
84 | this.subscription = undefined;
85 | }
86 | );
87 | },
88 | this.onError.bind(this)
89 | )
90 | }
91 |
92 | unsubscribe() {
93 | if(this.subscription) {
94 | this.subscription.dispose();
95 | this.subscription = undefined;
96 | this.logMessage('EndOfEventStream', false);
97 | this.reconnect();
98 | }
99 | }
100 |
101 | selectConnection(connection: SavedConnection) {
102 | this.connection = connection;
103 | }
104 |
105 | onError(error: any) {
106 | this.logMessage(error.toString(), true);
107 | this.unsubscribe();
108 | }
109 |
110 | logMessage(message: string, isError: boolean) {
111 | this.messages.push({
112 | payload: message,
113 | className: isError ? 'text-danger' : ''
114 | });
115 | }
116 |
117 | logTcpMessage(message: TcpMessage) {
118 | this.logMessage(message.toTabSeparatedString(), false);
119 | }
120 |
121 | clearMessages() {
122 | this.messages = [];
123 | }
124 |
125 | initializeConnection(collection: string, connection: SavedConnection): Connection {
126 | let username = connection.requiresAuth ? connection.username : undefined;
127 | let password = connection.requiresAuth ? connection.password : undefined;
128 | return new Connection(collection, connection.host, connection.port, username, password);
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/exar-ui/src/views/home.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
22 |
23 |
--------------------------------------------------------------------------------
/exar-ui/src/views/home.ts:
--------------------------------------------------------------------------------
1 | import {autoinject} from 'aurelia-framework';
2 |
3 | import * as $ from 'jquery';
4 |
5 | import {SavedConnection} from 'models/saved-connection';
6 |
7 | @autoinject
8 | export class Home {
9 | tabs: Tab[] = [];
10 |
11 | addTab() {
12 | this.tabs.push(new Tab());
13 | this.showTab(this.tabs.length - 1);
14 | }
15 |
16 | removeTab(index, event) {
17 | this.tabs.splice(index, 1);
18 | event.stopPropagation();
19 | let selectedTabIndex = this.getSelectedTabIndex();
20 | if(index > selectedTabIndex) this.showTab(selectedTabIndex);
21 | else if(index < selectedTabIndex) this.showTab(selectedTabIndex - 1);
22 | }
23 |
24 | showTab(index) {
25 | setTimeout(() => $(`#tab-${index}`).tab('show'));
26 | }
27 |
28 | getSelectedTabIndex() {
29 | return Number($('.tab-pane.active').attr('id').replace('tab-content-', ''));
30 | }
31 | }
32 |
33 | class Tab {
34 | collection: string;
35 | connection: SavedConnection;
36 |
37 | get name() {
38 | if(this.collection) {
39 | return `${this.collection} @ ${this.connection.alias}`;
40 | } else {
41 | return 'New connection';
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/exar-ui/src/views/manage-connections.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Saved Connections
5 | New
6 |
7 |
8 | No saved connections
9 |
10 |
11 |
12 |
13 | Alias |
14 | Host |
15 | Port |
16 | Username |
17 | Password |
18 | Actions |
19 |
20 |
21 |
22 |
23 | ${connection.alias} |
24 | ${connection.host} |
25 | ${connection.port} |
26 | ${connection.username} |
27 | ${connection.password | obfuscate} |
28 |
29 | Edit
30 |
31 | Delete
32 | |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/exar-ui/src/views/manage-connections.ts:
--------------------------------------------------------------------------------
1 | import {autoinject} from 'aurelia-framework';
2 | import {DialogService} from 'aurelia-dialog';
3 |
4 | import {SavedConnection} from 'models/saved-connection';
5 | import {EditConnection} from 'components/dialogs/edit-connection';
6 |
7 | @autoinject
8 | export class ManageConnections {
9 | savedConnections: SavedConnection[];
10 | dialogService: DialogService;
11 |
12 | constructor(dialogService: DialogService) {
13 | let storedConnections = localStorage.getItem('connections.saved');
14 | this.savedConnections = storedConnections ? JSON.parse(storedConnections) : [];
15 | this.dialogService = dialogService;
16 | }
17 |
18 | newConnection() {
19 | this.dialogService.open({ viewModel: EditConnection, model: new SavedConnection() })
20 | .then(result => {
21 | if(result.output) this.saveConnection(result.output)
22 | });
23 | }
24 |
25 | editConnection(connection) {
26 | this.dialogService.open({ viewModel: EditConnection, model: connection })
27 | .then(result => {
28 | if(result.output) this.saveConnection(result.output)
29 | });
30 | }
31 |
32 | deleteConnection(connection) {
33 | let index = this.savedConnections.indexOf(connection);
34 | this.savedConnections.splice(index, 1);
35 | localStorage.setItem('connections.saved', JSON.stringify(this.savedConnections));
36 | }
37 |
38 | saveConnection(connection: SavedConnection) {
39 | if(this.savedConnections.indexOf(connection) === -1) {
40 | this.savedConnections.push(connection);
41 | }
42 | localStorage.setItem('connections.saved', JSON.stringify(this.savedConnections));
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/exar-ui/styles/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | }
4 |
5 | .splash {
6 | text-align: center;
7 | margin: 10% 0 0 0;
8 | box-sizing: border-box;
9 | }
10 |
11 | .splash .message {
12 | font-size: 24px;
13 | line-height: 24px;
14 | text-shadow: rgba(0, 0, 0, 0.5) 0 0 15px;
15 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
16 | }
17 |
18 | .splash .fa-spinner {
19 | text-align: center;
20 | display: inline-block;
21 | font-size: 34px;
22 | margin-top: 50px;
23 | }
24 |
25 | .page-host {
26 | position: absolute;
27 | left: 0;
28 | right: 0;
29 | top: 50px;
30 | bottom: 0;
31 | overflow-x: hidden;
32 | overflow-y: auto;
33 | }
34 |
35 | @media print {
36 | .page-host {
37 | position: absolute;
38 | left: 10px;
39 | right: 0;
40 | top: 50px;
41 | bottom: 0;
42 | overflow-y: inherit;
43 | overflow-x: inherit;
44 | }
45 | }
46 |
47 | section {
48 | margin: 0 20px;
49 | }
50 |
51 | .navbar-header {
52 | width: 100%;
53 | }
54 |
55 | .navbar-nav {
56 | margin: 0px;
57 | }
58 |
59 | .navbar-nav li.loader {
60 | margin: 12px 6px 0 6px;
61 | }
62 |
63 | ul.nav-tabs li i.fa {
64 | cursor: pointer;
65 | }
66 |
67 | section.au-enter-active {
68 | -webkit-animation: fadeInRight 1s;
69 | animation: fadeInRight 1s;
70 | }
71 |
72 | div.au-stagger {
73 | -webkit-animation-delay: 50ms;
74 | animation-delay: 50ms;
75 | }
76 |
77 | h3 {
78 | margin-bottom: 20px;
79 | }
80 |
--------------------------------------------------------------------------------
/exar-ui/test/unit/app.spec.ts:
--------------------------------------------------------------------------------
1 | import { Container } from 'aurelia-framework';
2 | import { Router, RouterConfiguration } from 'aurelia-router';
3 |
4 | import { App } from 'src/app';
5 |
6 | describe('App', () => {
7 | var app: App,
8 | routerConfig: RouterConfiguration,
9 | router: Router;
10 |
11 | beforeEach(() => {
12 | let container = new Container();
13 |
14 | router = container.get(Router);
15 | routerConfig = container.get(RouterConfiguration);
16 |
17 | spyOn(routerConfig, 'map');
18 |
19 | app = new App();
20 | });
21 |
22 | it('should configure the router correctly', () => {
23 | app.configureRouter(routerConfig, router);
24 |
25 | expect(app.router).toBeDefined();
26 | expect(routerConfig.title).toEqual('Exar UI');
27 | expect(routerConfig.map).toHaveBeenCalled();
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/exar-ui/test/unit/setup.ts:
--------------------------------------------------------------------------------
1 | import {initialize} from 'aurelia-pal-browser'
2 | import 'aurelia-polyfills'
3 |
4 | initialize();
5 |
--------------------------------------------------------------------------------
/exar-ui/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "rootDir": "src/",
6 | "sourceMap": true,
7 | "target": "es5",
8 | "module": "amd",
9 | "declaration": false,
10 | "noImplicitAny": false,
11 | "removeComments": true,
12 | "emitDecoratorMetadata": true,
13 | "experimentalDecorators": true,
14 | "moduleResolution": "classic",
15 | "lib": ["es2015", "dom"]
16 | },
17 | "filesGlob": [
18 | "src/**/*.ts",
19 | "test/**/*.ts",
20 | "custom_typings/**/*.d.ts",
21 | "typings/index.d.ts"
22 | ],
23 | "exclude": [
24 | "node_modules",
25 | "jspm_packages/npm/react-tools@0.13.3/src/modern/class",
26 | "jspm_packages/npm/rx@4.1.0/ts",
27 | "Exar UI-darwin-x64"
28 | ],
29 | "atom": {
30 | "rewriteTsconfig": false
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/exar-ui/tsd.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "v4",
3 | "repo": "borisyankov/DefinitelyTyped",
4 | "ref": "master",
5 | "path": "typings",
6 | "bundle": "typings/tsd.d.ts",
7 | "installed": {
8 | "es6-promise/es6-promise.d.ts": {
9 | "commit": "24e12a7af994afa2226af70fbfae0adc78736a9e"
10 | },
11 | "jasmine/jasmine.d.ts": {
12 | "commit": "16cfc9e52eec782859fc91b413e9866640651395"
13 | },
14 | "angular-protractor/angular-protractor.d.ts": {
15 | "commit": "24e12a7af994afa2226af70fbfae0adc78736a9e"
16 | },
17 | "selenium-webdriver/selenium-webdriver.d.ts": {
18 | "commit": "24e12a7af994afa2226af70fbfae0adc78736a9e"
19 | },
20 | "jquery/jquery.d.ts": {
21 | "commit": "9f0f926a12026287b5a4a229e5672c01e7549313"
22 | },
23 | "text-encoding/text-encoding.d.ts": {
24 | "commit": "0d622d857f97d44ea7dcad2b3edec1f23c48fe9e"
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/exar-ui/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 |
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/exar-ui/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "exar-ui",
3 | "globalDevDependencies": {
4 | "angular-protractor": "registry:dt/angular-protractor",
5 | "aurelia-protractor": "github:aurelia/typings/dist/aurelia-protractor.d.ts",
6 | "jasmine": "registry:dt/jasmine",
7 | "selenium-webdriver": "registry:dt/selenium-webdriver"
8 | },
9 | "globalDependencies": {
10 | "bootstrap": "registry:dt/bootstrap",
11 | "jquery": "registry:dt/jquery",
12 | "url": "github:aurelia/fetch-client/doc/url.d.ts",
13 | "whatwg-fetch": "registry:dt/whatwg-fetch"
14 | },
15 | "dependencies": {
16 | "aurelia-animator-css": "github:aurelia/animator-css",
17 | "aurelia-binding": "github:aurelia/binding",
18 | "aurelia-bootstrapper": "github:aurelia/bootstrapper",
19 | "aurelia-bootstrapper-webpack": "github:aurelia/bootstrapper-webpack",
20 | "aurelia-dependency-injection": "github:aurelia/dependency-injection",
21 | "aurelia-dialog": "github:aurelia/dialog",
22 | "aurelia-event-aggregator": "github:aurelia/event-aggregator",
23 | "aurelia-fetch-client": "github:aurelia/fetch-client",
24 | "aurelia-framework": "github:aurelia/framework",
25 | "aurelia-history": "github:aurelia/history",
26 | "aurelia-history-browser": "github:aurelia/history-browser",
27 | "aurelia-loader": "github:aurelia/loader",
28 | "aurelia-loader-webpack": "github:aurelia/loader-webpack",
29 | "aurelia-logging": "github:aurelia/logging",
30 | "aurelia-logging-console": "github:aurelia/logging-console",
31 | "aurelia-metadata": "github:aurelia/metadata",
32 | "aurelia-pal": "github:aurelia/pal",
33 | "aurelia-pal-browser": "github:aurelia/pal-browser",
34 | "aurelia-path": "github:aurelia/path",
35 | "aurelia-polyfills": "github:aurelia/polyfills",
36 | "aurelia-route-recognizer": "github:aurelia/route-recognizer",
37 | "aurelia-router": "github:aurelia/router",
38 | "aurelia-task-queue": "github:aurelia/task-queue",
39 | "aurelia-templating": "github:aurelia/templating",
40 | "aurelia-templating-binding": "github:aurelia/templating-binding",
41 | "aurelia-templating-resources": "github:aurelia/templating-resources",
42 | "aurelia-templating-router": "github:aurelia/templating-router"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/exar-ui/typings/globals/angular-protractor/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/f9c44651705f574f6d4258fe5e1c335462bdcc19/angular-protractor/angular-protractor.d.ts",
5 | "raw": "registry:dt/angular-protractor#1.5.0+20160425143459",
6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/f9c44651705f574f6d4258fe5e1c335462bdcc19/angular-protractor/angular-protractor.d.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/exar-ui/typings/globals/aurelia-protractor/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/typings/master/dist/aurelia-protractor.d.ts
3 | declare module protractor {
4 | interface IBrowser extends protractor.Protractor {
5 | loadAndWaitForAureliaPage(url: string): protractor.Protractor;
6 | waitForRouterComplete();
7 | }
8 |
9 | interface IProtractorLocatorStrategy {
10 | valueBind(bindTarget: string): webdriver.Locator;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/exar-ui/typings/globals/aurelia-protractor/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/typings/master/dist/aurelia-protractor.d.ts",
5 | "raw": "github:aurelia/typings/dist/aurelia-protractor.d.ts",
6 | "typings": "https://raw.githubusercontent.com/aurelia/typings/master/dist/aurelia-protractor.d.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/exar-ui/typings/globals/bootstrap/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/1f0791147c6c145227b1778bb26781a79d516917/bootstrap/bootstrap.d.ts
3 | interface ModalOptions {
4 | backdrop?: boolean|string;
5 | keyboard?: boolean;
6 | show?: boolean;
7 | remote?: string;
8 | }
9 |
10 | interface ModalOptionsBackdropString {
11 | backdrop?: string; // for "static"
12 | keyboard?: boolean;
13 | show?: boolean;
14 | remote?: string;
15 | }
16 |
17 | interface ScrollSpyOptions {
18 | offset?: number;
19 | target?: string;
20 | }
21 |
22 | interface TooltipOptions {
23 | animation?: boolean;
24 | html?: boolean;
25 | placement?: string | Function;
26 | selector?: string;
27 | title?: string | Function;
28 | trigger?: string;
29 | template?: string;
30 | delay?: number | Object;
31 | container?: string | boolean;
32 | viewport?: string | Function | Object;
33 | }
34 |
35 | interface PopoverOptions {
36 | animation?: boolean;
37 | html?: boolean;
38 | placement?: string | Function;
39 | selector?: string;
40 | trigger?: string;
41 | title?: string | Function;
42 | template?: string;
43 | content?: any;
44 | delay?: number | Object;
45 | container?: string | boolean;
46 | viewport?: string | Function | Object;
47 | }
48 |
49 | interface CollapseOptions {
50 | parent?: any;
51 | toggle?: boolean;
52 | }
53 |
54 | interface CarouselOptions {
55 | interval?: number;
56 | pause?: string;
57 | wrap?: boolean;
58 | keybord?: boolean;
59 | }
60 |
61 | interface TypeaheadOptions {
62 | source?: any;
63 | items?: number;
64 | minLength?: number;
65 | matcher?: (item: any) => boolean;
66 | sorter?: (items: any[]) => any[];
67 | updater?: (item: any) => any;
68 | highlighter?: (item: any) => string;
69 | }
70 |
71 | interface AffixOptions {
72 | offset?: number | Function | Object;
73 | target?: any;
74 | }
75 |
76 | interface TransitionEventNames {
77 | end: string;
78 | }
79 |
80 | interface JQuery {
81 | modal(options?: ModalOptions): JQuery;
82 | modal(options?: ModalOptionsBackdropString): JQuery;
83 | modal(command: string): JQuery;
84 |
85 | dropdown(): JQuery;
86 | dropdown(command: string): JQuery;
87 |
88 | scrollspy(command: string): JQuery;
89 | scrollspy(options?: ScrollSpyOptions): JQuery;
90 |
91 | tab(): JQuery;
92 | tab(command: string): JQuery;
93 |
94 | tooltip(options?: TooltipOptions): JQuery;
95 | tooltip(command: string): JQuery;
96 |
97 | popover(options?: PopoverOptions): JQuery;
98 | popover(command: string): JQuery;
99 |
100 | alert(): JQuery;
101 | alert(command: string): JQuery;
102 |
103 | button(): JQuery;
104 | button(command: string): JQuery;
105 |
106 | collapse(options?: CollapseOptions): JQuery;
107 | collapse(command: string): JQuery;
108 |
109 | carousel(options?: CarouselOptions): JQuery;
110 | carousel(command: string): JQuery;
111 |
112 | typeahead(options?: TypeaheadOptions): JQuery;
113 |
114 | affix(options?: AffixOptions): JQuery;
115 |
116 | emulateTransitionEnd(duration: number): JQuery;
117 | }
118 |
119 | interface JQuerySupport {
120 | transition: boolean | TransitionEventNames;
121 | }
122 |
123 | declare module "bootstrap" {
124 | }
125 |
--------------------------------------------------------------------------------
/exar-ui/typings/globals/bootstrap/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/1f0791147c6c145227b1778bb26781a79d516917/bootstrap/bootstrap.d.ts",
5 | "raw": "registry:dt/bootstrap#3.3.5+20160619023404",
6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/1f0791147c6c145227b1778bb26781a79d516917/bootstrap/bootstrap.d.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/exar-ui/typings/globals/jasmine/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/c49913aa9ea419ea46c1c684e488cf2a10303b1a/jasmine/jasmine.d.ts",
5 | "raw": "registry:dt/jasmine#2.2.0+20160621224255",
6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/c49913aa9ea419ea46c1c684e488cf2a10303b1a/jasmine/jasmine.d.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/exar-ui/typings/globals/jquery/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/6e54cb627506cf64d6effba1fe49b5a091ac4297/jquery/jquery.d.ts",
5 | "raw": "registry:dt/jquery#1.10.0+20160704162008",
6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/6e54cb627506cf64d6effba1fe49b5a091ac4297/jquery/jquery.d.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/exar-ui/typings/globals/selenium-webdriver/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/selenium-webdriver/selenium-webdriver.d.ts",
5 | "raw": "registry:dt/selenium-webdriver#2.44.0+20160317120654",
6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/selenium-webdriver/selenium-webdriver.d.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/exar-ui/typings/globals/url/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/fetch-client/master/doc/url.d.ts
3 | declare class URLSearchParams {
4 | append(name: string, value: string): void;
5 | delete(name: string):void;
6 | get(name: string): string;
7 | getAll(name: string): Array;
8 | has(name: string): boolean;
9 | set(name: string, value: string): void;
10 | }
11 |
--------------------------------------------------------------------------------
/exar-ui/typings/globals/url/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/fetch-client/master/doc/url.d.ts",
5 | "raw": "github:aurelia/fetch-client/doc/url.d.ts",
6 | "typings": "https://raw.githubusercontent.com/aurelia/fetch-client/master/doc/url.d.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/exar-ui/typings/globals/whatwg-fetch/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/d997f92b892040860145a9510504dff22f672a36/whatwg-fetch/whatwg-fetch.d.ts
3 | declare class Request extends Body {
4 | constructor(input: string|Request, init?:RequestInit);
5 | method: string;
6 | url: string;
7 | headers: Headers;
8 | context: RequestContext;
9 | referrer: string;
10 | mode: RequestMode;
11 | redirect: RequestRedirect;
12 | credentials: RequestCredentials;
13 | cache: RequestCache;
14 | }
15 |
16 | interface RequestInit {
17 | method?: string;
18 | headers?: HeaderInit|{ [index: string]: string };
19 | body?: BodyInit;
20 | mode?: RequestMode;
21 | redirect?: RequestRedirect;
22 | credentials?: RequestCredentials;
23 | cache?: RequestCache;
24 | }
25 |
26 | type RequestContext =
27 | "audio" | "beacon" | "cspreport" | "download" | "embed" |
28 | "eventsource" | "favicon" | "fetch" | "font" | "form" | "frame" |
29 | "hyperlink" | "iframe" | "image" | "imageset" | "import" |
30 | "internal" | "location" | "manifest" | "object" | "ping" | "plugin" |
31 | "prefetch" | "script" | "serviceworker" | "sharedworker" |
32 | "subresource" | "style" | "track" | "video" | "worker" |
33 | "xmlhttprequest" | "xslt";
34 | type RequestMode = "same-origin" | "no-cors" | "cors";
35 | type RequestRedirect = "follow" | "error" | "manual";
36 | type RequestCredentials = "omit" | "same-origin" | "include";
37 | type RequestCache =
38 | "default" | "no-store" | "reload" | "no-cache" |
39 | "force-cache" | "only-if-cached";
40 |
41 | declare interface HeadersMap {
42 | [index: string]: string;
43 | }
44 |
45 | declare class Headers {
46 | constructor(headers?:Headers|HeadersMap)
47 | append(name: string, value: string): void;
48 | delete(name: string):void;
49 | get(name: string): string;
50 | getAll(name: string): Array;
51 | has(name: string): boolean;
52 | set(name: string, value: string): void;
53 | forEach(callback: (value: string, name: string) => void): void;
54 | }
55 |
56 | declare class Body {
57 | bodyUsed: boolean;
58 | arrayBuffer(): Promise;
59 | blob(): Promise;
60 | formData(): Promise;
61 | json(): Promise;
62 | json(): Promise;
63 | text(): Promise;
64 | }
65 |
66 | declare class Response extends Body {
67 | constructor(body?: BodyInit, init?: ResponseInit);
68 | static error(): Response;
69 | static redirect(url: string, status: number): Response;
70 | type: ResponseType;
71 | url: string;
72 | status: number;
73 | ok: boolean;
74 | statusText: string;
75 | headers: Headers;
76 | clone(): Response;
77 | }
78 |
79 | type ResponseType = "basic" | "cors" | "default" | "error" | "opaque" | "opaqueredirect";
80 |
81 | interface ResponseInit {
82 | status: number;
83 | statusText?: string;
84 | headers?: HeaderInit;
85 | }
86 |
87 | declare type HeaderInit = Headers|Array;
88 | declare type BodyInit = ArrayBuffer|ArrayBufferView|Blob|FormData|string;
89 | declare type RequestInfo = Request|string;
90 |
91 | interface Window {
92 | fetch(url: string|Request, init?: RequestInit): Promise;
93 | }
94 |
95 | declare var fetch: typeof window.fetch;
96 |
--------------------------------------------------------------------------------
/exar-ui/typings/globals/whatwg-fetch/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/d997f92b892040860145a9510504dff22f672a36/whatwg-fetch/whatwg-fetch.d.ts",
5 | "raw": "registry:dt/whatwg-fetch#0.0.0+20160728142841",
6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/d997f92b892040860145a9510504dff22f672a36/whatwg-fetch/whatwg-fetch.d.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/exar-ui/typings/index.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 | ///
5 | ///
6 | ///
7 | ///
8 | ///
9 | ///
10 | ///
11 | ///
12 | ///
13 | ///
14 | ///
15 | ///
16 | ///
17 | ///
18 | ///
19 | ///
20 | ///
21 | ///
22 | ///
23 | ///
24 | ///
25 | ///
26 | ///
27 | ///
28 | ///
29 | ///
30 | ///
31 | ///
32 | ///
33 | ///
34 | ///
35 | ///
36 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-animator-css/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/animator-css/master/dist/aurelia-animator-css.d.ts
3 | declare module 'aurelia-animator-css' {
4 | import {
5 | animationEvent,
6 | TemplatingEngine
7 | } from 'aurelia-templating';
8 | import {
9 | DOM
10 | } from 'aurelia-pal';
11 | export interface CssAnimation {
12 | className: string;
13 | element: HTMLElement;
14 | }
15 |
16 | /**
17 | * An implementation of the Animator using CSS3-Animations.
18 | */
19 | /**
20 | * An implementation of the Animator using CSS3-Animations.
21 | */
22 | export class CssAnimator {
23 |
24 | /**
25 | * Creates an instance of CssAnimator.
26 | */
27 | constructor();
28 |
29 | /* Public API Begin */
30 | /**
31 | * Execute a single animation.
32 | * @param element Element to animate
33 | * @param className Properties to animate or name of the effect to use. For css animators this represents the className to be added and removed right after the animation is done.
34 | * @param options options for the animation (duration, easing, ...)
35 | * @returns Resolved when the animation is done
36 | */
37 | animate(element: HTMLElement | Array, className: string): Promise;
38 |
39 | /**
40 | * Run a sequence of animations one after the other.
41 | * @param sequence An array of effectNames or classNames
42 | * @returns Resolved when all animations are done
43 | */
44 | runSequence(animations: Array): Promise;
45 |
46 | /**
47 | * Execute an 'enter' animation on an element
48 | * @param element Element to animate
49 | * @returns Resolved when the animation is done
50 | */
51 | enter(element: HTMLElement): Promise;
52 |
53 | /**
54 | * Execute a 'leave' animation on an element
55 | * @param element Element to animate
56 | * @returns Resolved when the animation is done
57 | */
58 | leave(element: HTMLElement): Promise;
59 |
60 | /**
61 | * Add a class to an element to trigger an animation.
62 | * @param element Element to animate
63 | * @param className Properties to animate or name of the effect to use
64 | * @param suppressEvents Indicates whether or not to suppress animation events.
65 | * @returns Resolved when the animation is done
66 | */
67 | removeClass(element: HTMLElement, className: string, suppressEvents?: boolean): Promise;
68 |
69 | /**
70 | * Add a class to an element to trigger an animation.
71 | * @param element Element to animate
72 | * @param className Properties to animate or name of the effect to use
73 | * @param suppressEvents Indicates whether or not to suppress animation events.
74 | * @returns Resolved when the animation is done
75 | */
76 | addClass(element: HTMLElement, className: string, suppressEvents?: boolean): Promise;
77 | }
78 |
79 | /* Public API End */
80 | /**
81 | * Configuires the CssAnimator as the default animator for Aurelia.
82 | * @param config The FrameworkConfiguration instance.
83 | * @param callback A configuration callback provided by the plugin consumer.
84 | */
85 | export function configure(config: Object, callback?: ((animator: CssAnimator) => void)): void;
86 | }
87 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-animator-css/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/animator-css/master/typings.json",
5 | "raw": "github:aurelia/animator-css",
6 | "main": "dist/aurelia-animator-css.d.ts",
7 | "global": false,
8 | "name": "aurelia-animator-css",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-binding/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/binding/master/typings.json",
5 | "raw": "github:aurelia/binding",
6 | "main": "dist/aurelia-binding.d.ts",
7 | "global": false,
8 | "name": "aurelia-binding",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-bootstrapper-webpack/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/bootstrapper-webpack/master/dist/aurelia-bootstrapper-webpack.d.ts
3 | declare module 'aurelia-bootstrapper-webpack' {
4 | import 'aurelia-polyfills';
5 | import {
6 | initialize
7 | } from 'aurelia-pal-browser';
8 | import {
9 | WebpackLoader
10 | } from 'aurelia-loader-webpack';
11 |
12 | /**
13 | * Manually bootstraps an application.
14 | * @param configure A callback which passes an Aurelia instance to the developer to manually configure and start up the app.
15 | * @return A Promise that completes when configuration is done.
16 | */
17 | export function bootstrap(configure: Function): Promise;
18 | }
19 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-bootstrapper-webpack/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/bootstrapper-webpack/master/typings.json",
5 | "raw": "github:aurelia/bootstrapper-webpack",
6 | "main": "dist/aurelia-bootstrapper-webpack.d.ts",
7 | "global": false,
8 | "name": "aurelia-bootstrapper-webpack",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-bootstrapper/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/bootstrapper/master/dist/aurelia-bootstrapper.d.ts
3 | declare module 'aurelia-bootstrapper' {
4 | import 'aurelia-polyfills';
5 | import {
6 | PLATFORM
7 | } from 'aurelia-pal';
8 | import {
9 | initialize
10 | } from 'aurelia-pal-browser';
11 |
12 | /**
13 | * Manually bootstraps an application.
14 | * @param configure A callback which passes an Aurelia instance to the developer to manually configure and start up the app.
15 | * @return A Promise that completes when configuration is done.
16 | */
17 | export function bootstrap(configure: Function): Promise;
18 | }
19 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-bootstrapper/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/bootstrapper/master/typings.json",
5 | "raw": "github:aurelia/bootstrapper",
6 | "main": "dist/aurelia-bootstrapper.d.ts",
7 | "global": false,
8 | "name": "aurelia-bootstrapper",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-dependency-injection/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/dependency-injection/master/typings.json",
5 | "raw": "github:aurelia/dependency-injection",
6 | "main": "dist/aurelia-dependency-injection.d.ts",
7 | "global": false,
8 | "name": "aurelia-dependency-injection",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-dialog/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/dialog/master/typings.json",
5 | "raw": "github:aurelia/dialog",
6 | "main": "dist/aurelia-dialog.d.ts",
7 | "global": false,
8 | "dependencies": {
9 | "aurelia-dependency-injection": {
10 | "src": "https://raw.githubusercontent.com/aurelia/dependency-injection/master/typings.json",
11 | "raw": "github:aurelia/dependency-injection",
12 | "main": "dist/aurelia-dependency-injection.d.ts",
13 | "global": false,
14 | "name": "aurelia-dependency-injection",
15 | "type": "typings"
16 | },
17 | "aurelia-metadata": {
18 | "src": "https://raw.githubusercontent.com/aurelia/metadata/master/typings.json",
19 | "raw": "github:aurelia/metadata",
20 | "main": "dist/aurelia-metadata.d.ts",
21 | "global": false,
22 | "dependencies": {
23 | "aurelia-pal": {
24 | "src": "https://raw.githubusercontent.com/aurelia/pal/master/typings.json",
25 | "raw": "github:aurelia/pal",
26 | "main": "dist/aurelia-pal.d.ts",
27 | "global": false,
28 | "name": "aurelia-pal",
29 | "type": "typings"
30 | }
31 | },
32 | "name": "aurelia-metadata",
33 | "type": "typings"
34 | },
35 | "aurelia-pal": {
36 | "src": "https://raw.githubusercontent.com/aurelia/pal/master/typings.json",
37 | "raw": "github:aurelia/pal",
38 | "main": "dist/aurelia-pal.d.ts",
39 | "global": false,
40 | "name": "aurelia-pal",
41 | "type": "typings"
42 | },
43 | "aurelia-templating": {
44 | "src": "https://raw.githubusercontent.com/aurelia/templating/master/typings.json",
45 | "raw": "github:aurelia/templating",
46 | "main": "dist/aurelia-templating.d.ts",
47 | "global": false,
48 | "name": "aurelia-templating",
49 | "type": "typings"
50 | }
51 | },
52 | "name": "aurelia-dialog",
53 | "type": "typings"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-event-aggregator/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/event-aggregator/master/dist/aurelia-event-aggregator.d.ts
3 | declare module 'aurelia-event-aggregator' {
4 | import * as LogManager from 'aurelia-logging';
5 |
6 | /**
7 | * Represents a disposable subsciption to an EventAggregator event.
8 | */
9 | export interface Subscription {
10 |
11 | /**
12 | * Disposes the subscription.
13 | */
14 | dispose(): void;
15 | }
16 |
17 | /**
18 | * Enables loosely coupled publish/subscribe messaging.
19 | */
20 | /**
21 | * Enables loosely coupled publish/subscribe messaging.
22 | */
23 | export class EventAggregator {
24 |
25 | /**
26 | * Creates an instance of the EventAggregator class.
27 | */
28 | constructor();
29 |
30 | /**
31 | * Publishes a message.
32 | * @param event The event or channel to publish to.
33 | * @param data The data to publish on the channel.
34 | */
35 | publish(event: string | any, data?: any): void;
36 |
37 | /**
38 | * Subscribes to a message channel or message type.
39 | * @param event The event channel or event data type.
40 | * @param callback The callback to be invoked when when the specified message is published.
41 | */
42 | subscribe(event: string | Function, callback: Function): Subscription;
43 |
44 | /**
45 | * Subscribes to a message channel or message type, then disposes the subscription automatically after the first message is received.
46 | * @param event The event channel or event data type.
47 | * @param callback The callback to be invoked when when the specified message is published.
48 | */
49 | subscribeOnce(event: string | Function, callback: Function): Subscription;
50 | }
51 |
52 | /**
53 | * Includes EA functionality into an object instance.
54 | * @param obj The object to mix Event Aggregator functionality into.
55 | */
56 | export function includeEventsIn(obj: Object): EventAggregator;
57 |
58 | /**
59 | * Configures a global EA by merging functionality into the Aurelia instance.
60 | * @param config The Aurelia Framework configuration object used to configure the plugin.
61 | */
62 | export function configure(config: Object): void;
63 | }
64 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-event-aggregator/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/event-aggregator/master/typings.json",
5 | "raw": "github:aurelia/event-aggregator",
6 | "main": "dist/aurelia-event-aggregator.d.ts",
7 | "global": false,
8 | "name": "aurelia-event-aggregator",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-fetch-client/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/fetch-client/master/typings.json",
5 | "raw": "github:aurelia/fetch-client",
6 | "main": "dist/aurelia-fetch-client.d.ts",
7 | "global": false,
8 | "name": "aurelia-fetch-client",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-framework/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/framework/master/typings.json",
5 | "raw": "github:aurelia/framework",
6 | "main": "dist/aurelia-framework.d.ts",
7 | "global": false,
8 | "name": "aurelia-framework",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-history-browser/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/history-browser/master/dist/aurelia-history-browser.d.ts
3 | declare module 'aurelia-history-browser' {
4 | import {
5 | DOM,
6 | PLATFORM
7 | } from 'aurelia-pal';
8 | import {
9 | History
10 | } from 'aurelia-history';
11 |
12 | /**
13 | * Provides information about how to handle an anchor event.
14 | */
15 | export interface AnchorEventInfo {
16 |
17 | /**
18 | * Indicates whether the event should be handled or not.
19 | */
20 | shouldHandleEvent: boolean;
21 |
22 | /**
23 | * The href of the link or null if not-applicable.
24 | */
25 | href: string;
26 |
27 | /**
28 | * The anchor element or null if not-applicable.
29 | */
30 | anchor: Element;
31 | }
32 |
33 | /**
34 | * Class responsible for handling interactions that should trigger browser history navigations.
35 | */
36 | export class LinkHandler {
37 |
38 | /**
39 | * Activate the instance.
40 | *
41 | * @param history The BrowserHistory instance that navigations should be dispatched to.
42 | */
43 | activate(history: BrowserHistory): void;
44 |
45 | /**
46 | * Deactivate the instance. Event handlers and other resources should be cleaned up here.
47 | */
48 | deactivate(): void;
49 | }
50 |
51 | /**
52 | * The default LinkHandler implementation. Navigations are triggered by click events on
53 | * anchor elements with relative hrefs when the history instance is using pushstate.
54 | */
55 | /**
56 | * The default LinkHandler implementation. Navigations are triggered by click events on
57 | * anchor elements with relative hrefs when the history instance is using pushstate.
58 | */
59 | export class DefaultLinkHandler extends LinkHandler {
60 |
61 | /**
62 | * Creates an instance of DefaultLinkHandler.
63 | */
64 | constructor();
65 |
66 | /**
67 | * Activate the instance.
68 | *
69 | * @param history The BrowserHistory instance that navigations should be dispatched to.
70 | */
71 | activate(history: BrowserHistory): void;
72 |
73 | /**
74 | * Deactivate the instance. Event handlers and other resources should be cleaned up here.
75 | */
76 | deactivate(): void;
77 |
78 | /**
79 | * Gets the href and a "should handle" recommendation, given an Event.
80 | *
81 | * @param event The Event to inspect for target anchor and href.
82 | */
83 | static getEventInfo(event: Event): AnchorEventInfo;
84 |
85 | /**
86 | * Finds the closest ancestor that's an anchor element.
87 | *
88 | * @param el The element to search upward from.
89 | * @returns The link element that is the closest ancestor.
90 | */
91 | static findClosestAnchor(el: Element): Element;
92 |
93 | /**
94 | * Gets a value indicating whether or not an anchor targets the current window.
95 | *
96 | * @param target The anchor element whose target should be inspected.
97 | * @returns True if the target of the link element is this window; false otherwise.
98 | */
99 | static targetIsThisWindow(target: Element): boolean;
100 | }
101 |
102 | /**
103 | * Configures the plugin by registering BrowserHistory as the implementation of History in the DI container.
104 | * @param config The FrameworkConfiguration object provided by Aurelia.
105 | */
106 | export function configure(config: Object): void;
107 |
108 | /**
109 | * An implementation of the basic history API.
110 | */
111 | export class BrowserHistory extends History {
112 | static inject: any;
113 |
114 | /**
115 | * Creates an instance of BrowserHistory
116 | * @param linkHandler An instance of LinkHandler.
117 | */
118 | constructor(linkHandler: LinkHandler);
119 |
120 | /**
121 | * Activates the history object.
122 | * @param options The set of options to activate history with.
123 | * @returns Whether or not activation occurred.
124 | */
125 | activate(options?: Object): boolean;
126 |
127 | /**
128 | * Deactivates the history object.
129 | */
130 | deactivate(): void;
131 |
132 | /**
133 | * Returns the fully-qualified root of the current history object.
134 | * @returns The absolute root of the application.
135 | */
136 | getAbsoluteRoot(): string;
137 |
138 | /**
139 | * Causes a history navigation to occur.
140 | *
141 | * @param fragment The history fragment to navigate to.
142 | * @param options The set of options that specify how the navigation should occur.
143 | * @return True if navigation occurred/false otherwise.
144 | */
145 | navigate(fragment?: string, undefined?: any): boolean;
146 |
147 | /**
148 | * Causes the history state to navigate back.
149 | */
150 | navigateBack(): void;
151 |
152 | /**
153 | * Sets the document title.
154 | */
155 | setTitle(title: string): void;
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-history-browser/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/history-browser/master/typings.json",
5 | "raw": "github:aurelia/history-browser",
6 | "main": "dist/aurelia-history-browser.d.ts",
7 | "global": false,
8 | "name": "aurelia-history-browser",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-history/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/history/master/dist/aurelia-history.d.ts
3 | declare module 'aurelia-history' {
4 |
5 | /**
6 | * The options that can be specified as part of a history navigation request.
7 | */
8 | export interface NavigationOptions {
9 |
10 | /**
11 | * Replace the existing route.
12 | */
13 | replace?: boolean;
14 |
15 | /**
16 | * Trigger the router.
17 | */
18 | trigger?: boolean;
19 | }
20 |
21 | /**
22 | * An abstract base class for implementors of the basic history api.
23 | */
24 | export class History {
25 |
26 | /**
27 | * Activates the history object.
28 | *
29 | * @param options The set of options to activate history with.
30 | * @returns Whether or not activation occurred.
31 | */
32 | activate(options: Object): boolean;
33 |
34 | /**
35 | * Deactivates the history object.
36 | */
37 | deactivate(): void;
38 |
39 | /**
40 | * Returns the fully-qualified root of the current history object.
41 | * @returns The absolute root of the application.
42 | */
43 | getAbsoluteRoot(): string;
44 |
45 | /**
46 | * Causes a history navigation to occur.
47 | *
48 | * @param fragment The history fragment to navigate to.
49 | * @param options The set of options that specify how the navigation should occur.
50 | * @returns True if navigation occurred/false otherwise.
51 | */
52 | navigate(fragment: string, options?: NavigationOptions): boolean;
53 |
54 | /**
55 | * Causes the history state to navigate back.
56 | */
57 | navigateBack(): void;
58 |
59 | /**
60 | * Updates the title associated with the current location.
61 | */
62 | setTitle(title: string): void;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-history/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/history/master/typings.json",
5 | "raw": "github:aurelia/history",
6 | "main": "dist/aurelia-history.d.ts",
7 | "global": false,
8 | "name": "aurelia-history",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-loader-webpack/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/loader-webpack/master/dist/aurelia-loader-webpack.d.ts
3 | declare module 'aurelia-loader-webpack' {
4 | import {
5 | Origin
6 | } from 'aurelia-metadata';
7 | import {
8 | Loader
9 | } from 'aurelia-loader';
10 | import {
11 | DOM,
12 | PLATFORM
13 | } from 'aurelia-pal';
14 |
15 | /**
16 | * An implementation of the TemplateLoader interface implemented with text-based loading.
17 | */
18 | export class TextTemplateLoader {
19 |
20 | /**
21 | * Loads a template.
22 | * @param loader The loader that is requesting the template load.
23 | * @param entry The TemplateRegistryEntry to load and populate with a template.
24 | * @return A promise which resolves when the TemplateRegistryEntry is loaded with a template.
25 | */
26 | loadTemplate(loader?: any, entry?: any): any;
27 | }
28 | export function ensureOriginOnExports(executed?: any, moduleId?: any): any;
29 |
30 | /**
31 | * A default implementation of the Loader abstraction which works with webpack (extended common-js style).
32 | */
33 | export class WebpackLoader extends Loader {
34 | constructor();
35 |
36 | /**
37 | * Maps a module id to a source.
38 | * @param id The module id.
39 | * @param source The source to map the module to.
40 | */
41 | map(id?: any, source?: any): any;
42 |
43 | /**
44 | * Normalizes a module id.
45 | * @param moduleId The module id to normalize.
46 | * @param relativeTo What the module id should be normalized relative to.
47 | * @return The normalized module id.
48 | */
49 | normalizeSync(moduleId?: any, relativeTo?: any): any;
50 |
51 | /**
52 | * Normalizes a module id.
53 | * @param moduleId The module id to normalize.
54 | * @param relativeTo What the module id should be normalized relative to.
55 | * @return The normalized module id.
56 | */
57 | normalize(moduleId?: any, relativeTo?: any): any;
58 |
59 | /**
60 | * Instructs the loader to use a specific TemplateLoader instance for loading templates
61 | * @param templateLoader The instance of TemplateLoader to use for loading templates.
62 | */
63 | useTemplateLoader(templateLoader?: any): any;
64 |
65 | /**
66 | * Loads a collection of modules.
67 | * @param ids The set of module ids to load.
68 | * @return A Promise for an array of loaded modules.
69 | */
70 | loadAllModules(ids?: any): any;
71 |
72 | /**
73 | * Loads a module.
74 | * @param id The module id to normalize.
75 | * @return A Promise for the loaded module.
76 | */
77 | loadModule(id?: any): any;
78 |
79 | /**
80 | * Loads a template.
81 | * @param url The url of the template to load.
82 | * @return A Promise for a TemplateRegistryEntry containing the template.
83 | */
84 | loadTemplate(url?: any): any;
85 |
86 | /**
87 | * Loads a text-based resource.
88 | * @param url The url of the text file to load.
89 | * @return A Promise for text content.
90 | */
91 | loadText(url?: any): any;
92 |
93 | /**
94 | * Alters a module id so that it includes a plugin loader.
95 | * @param url The url of the module to load.
96 | * @param pluginName The plugin to apply to the module id.
97 | * @return The plugin-based module id.
98 | */
99 | applyPluginToUrl(url?: any, pluginName?: any): any;
100 |
101 | /**
102 | * Registers a plugin with the loader.
103 | * @param pluginName The name of the plugin.
104 | * @param implementation The plugin implementation.
105 | */
106 | addPlugin(pluginName?: any, implementation?: any): any;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-loader-webpack/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/loader-webpack/master/typings.json",
5 | "raw": "github:aurelia/loader-webpack",
6 | "main": "dist/aurelia-loader-webpack.d.ts",
7 | "global": false,
8 | "name": "aurelia-loader-webpack",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-loader/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/loader/master/dist/aurelia-loader.d.ts
3 | declare module 'aurelia-loader' {
4 | import {
5 | relativeToFile
6 | } from 'aurelia-path';
7 | import {
8 | Origin
9 | } from 'aurelia-metadata';
10 |
11 | /*eslint no-unused-vars:0*/
12 | /**
13 | * Represents a plugin to the module loader.
14 | */
15 | export interface LoaderPlugin {
16 |
17 | /**
18 | * Fetches the resource.
19 | * @param address The address of the resource.
20 | * @return A Promise for the requested resouce.
21 | */
22 | fetch(address: string): Promise;
23 | }
24 |
25 | /**
26 | * Represents a dependency of a template.
27 | */
28 | export class TemplateDependency {
29 |
30 | /**
31 | * The source of the dependency.
32 | */
33 | src: string;
34 |
35 | /**
36 | * The local name of the src when used in the template.
37 | */
38 | name: string;
39 |
40 | /**
41 | * Creates a template dependency.
42 | * @param src The source of the dependency.
43 | * @param name The local name of the src when used in the template.
44 | */
45 | constructor(src: string, name?: string);
46 | }
47 |
48 | /**
49 | * Represents an entry in the template registry.
50 | */
51 | export class TemplateRegistryEntry {
52 |
53 | /**
54 | * The address of the template that this entry represents.
55 | */
56 | address: string;
57 |
58 | /**
59 | * Indicates whether or not the associated template is loaded .
60 | */
61 | templateIsLoaded: boolean;
62 |
63 | /**
64 | * Indicates whether the factory is ready to be used to create instances of the associated template.
65 | */
66 | factoryIsReady: boolean;
67 |
68 | /**
69 | * Sets the resources associated with this entry.
70 | */
71 | resources: Object;
72 |
73 | /**
74 | * The dependencies of the associated template. Dependencies are not available until after the template is loaded.
75 | */
76 | dependencies: TemplateDependency[];
77 |
78 | /**
79 | * Creates an instance of TemplateRegistryEntry.
80 | * @param address The address of the template that this entry represents.
81 | */
82 | constructor(address: string);
83 |
84 | /**
85 | * Gets the template for this registry entry.
86 | */
87 | template: Element;
88 |
89 | /**
90 | * Gets the factory capable of creating instances of this template.
91 | */
92 | factory: any;
93 |
94 | /**
95 | * Adds a dependency to this template registry entry. Cannot be called until after the template is set.
96 | * @param src The dependency instance or a relative path to its module.
97 | * @param name An optional local name by which this dependency is used in the template.
98 | */
99 | addDependency(src: string | Function, name?: string): void;
100 | }
101 |
102 | /**
103 | * A generic resource loader, for loading modules, html, css and more.
104 | */
105 | /**
106 | * A generic resource loader, for loading modules, html, css and more.
107 | */
108 | export class Loader {
109 |
110 | /**
111 | * Creates an instance of Loader.
112 | */
113 | constructor();
114 |
115 | /**
116 | * Maps a module id to a source.
117 | * @param id The module id.
118 | * @param source The source to map the module to.
119 | */
120 | map(id: string, source: string): void;
121 |
122 | /**
123 | * Normalizes a module id.
124 | * @param moduleId The module id to normalize.
125 | * @param relativeTo What the module id should be normalized relative to.
126 | * @return The normalized module id.
127 | */
128 | normalizeSync(moduleId: string, relativeTo: string): string;
129 |
130 | /**
131 | * Normalizes a module id.
132 | * @param moduleId The module id to normalize.
133 | * @param relativeTo What the module id should be normalized relative to.
134 | * @return A promise for the normalized module id.
135 | */
136 | normalize(moduleId: string, relativeTo: string): Promise;
137 |
138 | /**
139 | * Loads a module.
140 | * @param id The module id to normalize.
141 | * @return A Promise for the loaded module.
142 | */
143 | loadModule(id: string): Promise;
144 |
145 | /**
146 | * Loads a collection of modules.
147 | * @param ids The set of module ids to load.
148 | * @return A Promise for an array of loaded modules.
149 | */
150 | loadAllModules(ids: string[]): Promise;
151 |
152 | /**
153 | * Loads a template.
154 | * @param url The url of the template to load.
155 | * @return A Promise for a TemplateRegistryEntry containing the template.
156 | */
157 | loadTemplate(url: string): Promise;
158 |
159 | /**
160 | * Loads a text-based resource.
161 | * @param url The url of the text file to load.
162 | * @return A Promise for text content.
163 | */
164 | loadText(url: string): Promise;
165 |
166 | /**
167 | * Alters a module id so that it includes a plugin loader.
168 | * @param url The url of the module to load.
169 | * @param pluginName The plugin to apply to the module id.
170 | * @return The plugin-based module id.
171 | */
172 | applyPluginToUrl(url: string, pluginName: string): string;
173 |
174 | /**
175 | * Registers a plugin with the loader.
176 | * @param pluginName The name of the plugin.
177 | * @param implementation The plugin implementation.
178 | */
179 | addPlugin(pluginName: string, implementation: LoaderPlugin): void;
180 |
181 | /**
182 | * Gets or creates a TemplateRegistryEntry for the provided address.
183 | * @param address The address of the template.
184 | * @return The located or created TemplateRegistryEntry.
185 | */
186 | getOrCreateTemplateRegistryEntry(address: string): TemplateRegistryEntry;
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-loader/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/loader/master/typings.json",
5 | "raw": "github:aurelia/loader",
6 | "main": "dist/aurelia-loader.d.ts",
7 | "global": false,
8 | "name": "aurelia-loader",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-logging-console/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/logging-console/master/dist/aurelia-logging-console.d.ts
3 | declare module 'aurelia-logging-console' {
4 | import {
5 | Logger
6 | } from 'aurelia-logging';
7 |
8 | /*
9 | * An implementation of the Appender interface.
10 | */
11 | export class ConsoleAppender {
12 |
13 | /**
14 | * Appends a debug log.
15 | *
16 | * @param logger The source logger.
17 | * @param rest The data to log.
18 | */
19 | debug(logger: Logger, ...rest: any[]): void;
20 |
21 | /**
22 | * Appends an info log.
23 | *
24 | * @param logger The source logger.
25 | * @param rest The data to log.
26 | */
27 | info(logger: Logger, ...rest: any[]): void;
28 |
29 | /**
30 | * Appends a warning log.
31 | *
32 | * @param logger The source logger.
33 | * @param rest The data to log.
34 | */
35 | warn(logger: Logger, ...rest: any[]): void;
36 |
37 | /**
38 | * Appends an error log.
39 | *
40 | * @param logger The source logger.
41 | * @param rest The data to log.
42 | */
43 | error(logger: Logger, ...rest: any[]): void;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-logging-console/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/logging-console/master/typings.json",
5 | "raw": "github:aurelia/logging-console",
6 | "main": "dist/aurelia-logging-console.d.ts",
7 | "global": false,
8 | "name": "aurelia-logging-console",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-logging/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/logging/master/dist/aurelia-logging.d.ts
3 | declare module 'aurelia-logging' {
4 |
5 | /**
6 | * Specifies the available logging levels.
7 | */
8 | export interface LogLevel {
9 |
10 | /**
11 | * No logging.
12 | */
13 | none: number;
14 |
15 | /**
16 | * Log only error messages.
17 | */
18 | error: number;
19 |
20 | /**
21 | * Log warnings messages or above.
22 | */
23 | warn: number;
24 |
25 | /**
26 | * Log informational messages or above.
27 | */
28 | info: number;
29 |
30 | /**
31 | * Log all messages.
32 | */
33 | debug: number;
34 | }
35 |
36 | /**
37 | * Implemented by classes which wish to append log data to a target data store.
38 | */
39 | export interface Appender {
40 |
41 | /**
42 | * Appends a debug log.
43 | *
44 | * @param logger The source logger.
45 | * @param rest The data to log.
46 | */
47 | debug(logger: Logger, ...rest: any[]): void;
48 |
49 | /**
50 | * Appends an info log.
51 | *
52 | * @param logger The source logger.
53 | * @param rest The data to log.
54 | */
55 | info(logger: Logger, ...rest: any[]): void;
56 |
57 | /**
58 | * Appends a warning log.
59 | *
60 | * @param logger The source logger.
61 | * @param rest The data to log.
62 | */
63 | warn(logger: Logger, ...rest: any[]): void;
64 |
65 | /**
66 | * Appends an error log.
67 | *
68 | * @param logger The source logger.
69 | * @param rest The data to log.
70 | */
71 | error(logger: Logger, ...rest: any[]): void;
72 | }
73 |
74 | /**
75 | * Specifies the available logging levels.
76 | */
77 | /**
78 | * Specifies the available logging levels.
79 | */
80 | export const logLevel: LogLevel;
81 |
82 | /**
83 | * Gets the instance of a logger associated with a particular id (or creates one if it doesn't already exist).
84 | *
85 | * @param id The id of the logger you wish to get an instance of.
86 | * @return The instance of the logger, or creates a new logger if none exists for that id.
87 | */
88 | export function getLogger(id: string): Logger;
89 |
90 | /**
91 | * Adds an appender capable of processing logs and channeling them to an output.
92 | *
93 | * @param appender An appender instance to begin processing logs with.
94 | */
95 | /**
96 | * Adds an appender capable of processing logs and channeling them to an output.
97 | *
98 | * @param appender An appender instance to begin processing logs with.
99 | */
100 | export function addAppender(appender: Appender): void;
101 |
102 | /**
103 | * Sets the level of logging for the application loggers.
104 | *
105 | * @param level Matches a value of logLevel specifying the level of logging.
106 | */
107 | export function setLevel(level: number): void;
108 |
109 | /**
110 | * A logger logs messages to a set of appenders, depending on the log level that is set.
111 | */
112 | export class Logger {
113 |
114 | /**
115 | * The id that the logger was created with.
116 | */
117 | id: string;
118 |
119 | /**
120 | * You cannot instantiate the logger directly - you must use the getLogger method instead.
121 | */
122 | constructor(id: string, key: Object);
123 |
124 | /**
125 | * Logs a debug message.
126 | *
127 | * @param message The message to log.
128 | * @param rest The data to log.
129 | */
130 | debug(message: string, ...rest: any[]): void;
131 |
132 | /**
133 | * Logs info.
134 | *
135 | * @param message The message to log.
136 | * @param rest The data to log.
137 | */
138 | info(message: string, ...rest: any[]): void;
139 |
140 | /**
141 | * Logs a warning.
142 | *
143 | * @param message The message to log.
144 | * @param rest The data to log.
145 | */
146 | warn(message: string, ...rest: any[]): void;
147 |
148 | /**
149 | * Logs an error.
150 | *
151 | * @param message The message to log.
152 | * @param rest The data to log.
153 | */
154 | error(message: string, ...rest: any[]): void;
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-logging/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/logging/master/typings.json",
5 | "raw": "github:aurelia/logging",
6 | "main": "dist/aurelia-logging.d.ts",
7 | "global": false,
8 | "name": "aurelia-logging",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-metadata/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/metadata/master/typings.json",
5 | "raw": "github:aurelia/metadata",
6 | "main": "dist/aurelia-metadata.d.ts",
7 | "global": false,
8 | "dependencies": {
9 | "aurelia-pal": {
10 | "src": "https://raw.githubusercontent.com/aurelia/pal/master/typings.json",
11 | "raw": "github:aurelia/pal",
12 | "main": "dist/aurelia-pal.d.ts",
13 | "global": false,
14 | "name": "aurelia-pal",
15 | "type": "typings"
16 | }
17 | },
18 | "name": "aurelia-metadata",
19 | "type": "typings"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-pal-browser/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/pal-browser/master/typings.json",
5 | "raw": "github:aurelia/pal-browser",
6 | "main": "dist/aurelia-pal-browser.d.ts",
7 | "global": false,
8 | "dependencies": {
9 | "aurelia-pal": {
10 | "src": "https://raw.githubusercontent.com/aurelia/pal/master/typings.json",
11 | "raw": "github:aurelia/pal",
12 | "main": "dist/aurelia-pal.d.ts",
13 | "global": false,
14 | "name": "aurelia-pal",
15 | "type": "typings"
16 | }
17 | },
18 | "name": "aurelia-pal-browser",
19 | "type": "typings"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-pal/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/pal/master/typings.json",
5 | "raw": "github:aurelia/pal",
6 | "main": "dist/aurelia-pal.d.ts",
7 | "global": false,
8 | "name": "aurelia-pal",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-path/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/path/master/dist/aurelia-path.d.ts
3 | declare module 'aurelia-path' {
4 |
5 | /**
6 | * Calculates a path relative to a file.
7 | *
8 | * @param name The relative path.
9 | * @param file The file path.
10 | * @return The calculated path.
11 | */
12 | export function relativeToFile(name: string, file: string): string;
13 |
14 | /**
15 | * Joins two paths.
16 | *
17 | * @param path1 The first path.
18 | * @param path2 The second path.
19 | * @return The joined path.
20 | */
21 | export function join(path1: string, path2: string): string;
22 |
23 | /**
24 | * Generate a query string from an object.
25 | *
26 | * @param params Object containing the keys and values to be used.
27 | * @returns The generated query string, excluding leading '?'.
28 | */
29 | export function buildQueryString(params: Object): string;
30 |
31 | /**
32 | * Parse a query string.
33 | *
34 | * @param queryString The query string to parse.
35 | * @returns Object with keys and values mapped from the query string.
36 | */
37 | export function parseQueryString(queryString: string): Object;
38 | }
39 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-path/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/path/master/typings.json",
5 | "raw": "github:aurelia/path",
6 | "main": "dist/aurelia-path.d.ts",
7 | "global": false,
8 | "name": "aurelia-path",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-polyfills/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/polyfills/master/dist/aurelia-polyfills.d.ts
3 | declare module 'aurelia-polyfills' {
4 | import {
5 | PLATFORM
6 | } from 'aurelia-pal';
7 | }
8 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-polyfills/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/polyfills/master/typings.json",
5 | "raw": "github:aurelia/polyfills",
6 | "main": "dist/aurelia-polyfills.d.ts",
7 | "global": false,
8 | "name": "aurelia-polyfills",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-route-recognizer/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/route-recognizer/master/dist/aurelia-route-recognizer.d.ts
3 | declare module 'aurelia-route-recognizer' {
4 | import {
5 | buildQueryString,
6 | parseQueryString
7 | } from 'aurelia-path';
8 | export interface RouteHandler {
9 | name: string;
10 | }
11 | export interface ConfigurableRoute {
12 | path: string;
13 | handler: RouteHandler;
14 | caseSensitive: boolean;
15 | }
16 | export interface HandlerEntry {
17 | handler: RouteHandler;
18 | names: string[];
19 | }
20 | export interface RecognizedRoute {
21 | handler: RouteHandler;
22 | params: Object;
23 | isDynamic: boolean;
24 | }
25 | export interface CharSpec {
26 | invalidChars?: string;
27 | validChars?: string;
28 | repeat?: boolean;
29 | }
30 |
31 | // A State has a character specification and (`charSpec`) and a list of possible
32 | // subsequent states (`nextStates`).
33 | //
34 | // If a State is an accepting state, it will also have several additional
35 | // properties:
36 | //
37 | // * `regex`: A regular expression that is used to extract parameters from paths
38 | // that reached this accepting state.
39 | // * `handlers`: Information on how to convert the list of captures into calls
40 | // to registered handlers with the specified parameters.
41 | // * `types`: How many static, dynamic, or star segments in this route. Used to
42 | // decide which route to use if multiple registered routes match a path.
43 | //
44 | // Currently, State is implemented naively by looping over `nextStates` and
45 | // comparing a character specification against a character. A more efficient
46 | // implementation would use a hash of keys pointing at one or more next states.
47 | export class State {
48 | constructor(charSpec: CharSpec);
49 | get(charSpec: CharSpec): State;
50 | put(charSpec: CharSpec): State;
51 |
52 | // Find a list of child states matching the next character
53 | match(ch: string): State[];
54 | }
55 |
56 | // A Segment represents a segment in the original route description.
57 | // Each Segment type provides an `eachChar` and `regex` method.
58 | //
59 | // The `eachChar` method invokes the callback with one or more character
60 | // specifications. A character specification consumes one or more input
61 | // characters.
62 | //
63 | // The `regex` method returns a regex fragment for the segment. If the
64 | // segment is a dynamic or star segment, the regex fragment also includes
65 | // a capture.
66 | //
67 | // A character specification contains:
68 | //
69 | // * `validChars`: a String with a list of all valid characters, or
70 | // * `invalidChars`: a String with a list of all invalid characters
71 | // * `repeat`: true if the character specification can repeat
72 | export class StaticSegment {
73 | constructor(string: string, caseSensitive: boolean);
74 | eachChar(callback: ((spec: CharSpec) => void)): void;
75 | regex(): string;
76 | generate(): string;
77 | }
78 | export class DynamicSegment {
79 | constructor(name: string);
80 | eachChar(callback: ((spec: CharSpec) => void)): void;
81 | regex(): string;
82 | generate(params: Object, consumed: Object): string;
83 | }
84 | export class StarSegment {
85 | constructor(name: string);
86 | eachChar(callback: ((spec: CharSpec) => void)): void;
87 | regex(): string;
88 | generate(params: Object, consumed: Object): string;
89 | }
90 | export class EpsilonSegment {
91 | eachChar(): void;
92 | regex(): string;
93 | generate(): string;
94 | }
95 |
96 | /**
97 | * Class that parses route patterns and matches path strings.
98 | *
99 | * @class RouteRecognizer
100 | * @constructor
101 | */
102 | /**
103 | * Class that parses route patterns and matches path strings.
104 | *
105 | * @class RouteRecognizer
106 | * @constructor
107 | */
108 | export class RouteRecognizer {
109 | constructor();
110 |
111 | /**
112 | * Parse a route pattern and add it to the collection of recognized routes.
113 | *
114 | * @param route The route to add.
115 | */
116 | add(route: ConfigurableRoute | ConfigurableRoute[]): State;
117 |
118 | /**
119 | * Retrieve the handlers registered for the named route.
120 | *
121 | * @param name The name of the route.
122 | * @returns The handlers.
123 | */
124 | handlersFor(name: string): HandlerEntry[];
125 |
126 | /**
127 | * Check if this RouteRecognizer recognizes a named route.
128 | *
129 | * @param name The name of the route.
130 | * @returns True if the named route is recognized.
131 | */
132 | hasRoute(name: string): boolean;
133 |
134 | /**
135 | * Generate a path and query string from a route name and params object.
136 | *
137 | * @param name The name of the route.
138 | * @param params The route params to use when populating the pattern.
139 | * Properties not required by the pattern will be appended to the query string.
140 | * @returns The generated absolute path and query string.
141 | */
142 | generate(name: string, params: Object): string;
143 |
144 | /**
145 | * Match a path string against registered route patterns.
146 | *
147 | * @param path The path to attempt to match.
148 | * @returns Array of objects containing `handler`, `params`, and
149 | * `isDynanic` values for the matched route(s), or undefined if no match
150 | * was found.
151 | */
152 | recognize(path: string): RecognizedRoute[];
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-route-recognizer/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/route-recognizer/master/typings.json",
5 | "raw": "github:aurelia/route-recognizer",
6 | "main": "dist/aurelia-route-recognizer.d.ts",
7 | "global": false,
8 | "name": "aurelia-route-recognizer",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-router/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/router/master/typings.json",
5 | "raw": "github:aurelia/router",
6 | "main": "dist/aurelia-router.d.ts",
7 | "global": false,
8 | "name": "aurelia-router",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-task-queue/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/task-queue/master/dist/aurelia-task-queue.d.ts
3 | declare module 'aurelia-task-queue' {
4 | import {
5 | DOM,
6 | FEATURE
7 | } from 'aurelia-pal';
8 |
9 | /**
10 | * Either a Function or a class with a call method that will do work when dequeued.
11 | */
12 | export interface Task {
13 |
14 | /**
15 | * Call it.
16 | */
17 | call(): void;
18 | }
19 |
20 | /**
21 | * Implements an asynchronous task queue.
22 | */
23 | /**
24 | * Implements an asynchronous task queue.
25 | */
26 | export class TaskQueue {
27 |
28 | /**
29 | * Creates an instance of TaskQueue.
30 | */
31 | constructor();
32 |
33 | /**
34 | * Queues a task on the micro task queue for ASAP execution.
35 | * @param task The task to queue up for ASAP execution.
36 | */
37 | queueMicroTask(task: Task | Function): void;
38 |
39 | /**
40 | * Queues a task on the macro task queue for turn-based execution.
41 | * @param task The task to queue up for turn-based execution.
42 | */
43 | queueTask(task: Task | Function): void;
44 |
45 | /**
46 | * Immediately flushes the task queue.
47 | */
48 | flushTaskQueue(): void;
49 |
50 | /**
51 | * Immediately flushes the micro task queue.
52 | */
53 | flushMicroTaskQueue(): void;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-task-queue/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/task-queue/master/typings.json",
5 | "raw": "github:aurelia/task-queue",
6 | "main": "dist/aurelia-task-queue.d.ts",
7 | "global": false,
8 | "name": "aurelia-task-queue",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-templating-binding/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/templating-binding/master/dist/aurelia-templating-binding.d.ts
3 | declare module 'aurelia-templating-binding' {
4 | import * as LogManager from 'aurelia-logging';
5 | import {
6 | camelCase,
7 | SVGAnalyzer,
8 | bindingMode,
9 | connectable,
10 | enqueueBindingConnect,
11 | Parser,
12 | ObserverLocator,
13 | EventManager,
14 | ListenerExpression,
15 | BindingExpression,
16 | CallExpression,
17 | NameExpression
18 | } from 'aurelia-binding';
19 | import {
20 | BehaviorInstruction,
21 | BindingLanguage
22 | } from 'aurelia-templating';
23 | export class AttributeMap {
24 | static inject: any;
25 | elements: any;
26 | allElements: any;
27 | constructor(svg?: any);
28 |
29 | /**
30 | * Maps a specific HTML element attribute to a javascript property.
31 | */
32 | register(elementName?: any, attributeName?: any, propertyName?: any): any;
33 |
34 | /**
35 | * Maps an HTML attribute to a javascript property.
36 | */
37 | registerUniversal(attributeName?: any, propertyName?: any): any;
38 |
39 | /**
40 | * Returns the javascript property name for a particlar HTML attribute.
41 | */
42 | map(elementName?: any, attributeName?: any): any;
43 | }
44 | export class InterpolationBindingExpression {
45 | constructor(observerLocator?: any, targetProperty?: any, parts?: any, mode?: any, lookupFunctions?: any, attribute?: any);
46 | createBinding(target?: any): any;
47 | }
48 | export class InterpolationBinding {
49 | constructor(observerLocator?: any, parts?: any, target?: any, targetProperty?: any, mode?: any, lookupFunctions?: any);
50 | interpolate(): any;
51 | updateOneTimeBindings(): any;
52 | bind(source?: any): any;
53 | unbind(): any;
54 | }
55 | export class ChildInterpolationBinding {
56 | constructor(target?: any, observerLocator?: any, sourceExpression?: any, mode?: any, lookupFunctions?: any, targetProperty?: any, left?: any, right?: any);
57 | updateTarget(value?: any): any;
58 | call(): any;
59 | bind(source?: any): any;
60 | unbind(): any;
61 | connect(evaluate?: any): any;
62 | }
63 |
64 | /*eslint dot-notation:0*/
65 | export class SyntaxInterpreter {
66 | static inject: any;
67 | constructor(parser?: any, observerLocator?: any, eventManager?: any, attributeMap?: any);
68 | interpret(resources?: any, element?: any, info?: any, existingInstruction?: any, context?: any): any;
69 | handleUnknownCommand(resources?: any, element?: any, info?: any, existingInstruction?: any, context?: any): any;
70 | determineDefaultBindingMode(element?: any, attrName?: any, context?: any): any;
71 | bind(resources?: any, element?: any, info?: any, existingInstruction?: any, context?: any): any;
72 | trigger(resources?: any, element?: any, info?: any): any;
73 | delegate(resources?: any, element?: any, info?: any): any;
74 | call(resources?: any, element?: any, info?: any, existingInstruction?: any): any;
75 | options(resources?: any, element?: any, info?: any, existingInstruction?: any, context?: any): any;
76 | 'for'(resources?: any, element?: any, info?: any, existingInstruction?: any): any;
77 | 'two-way'(resources?: any, element?: any, info?: any, existingInstruction?: any): any;
78 | 'one-way'(resources?: any, element?: any, info?: any, existingInstruction?: any): any;
79 | 'one-time'(resources?: any, element?: any, info?: any, existingInstruction?: any): any;
80 | }
81 | export class TemplatingBindingLanguage extends BindingLanguage {
82 | static inject: any;
83 | constructor(parser?: any, observerLocator?: any, syntaxInterpreter?: any, attributeMap?: any);
84 | inspectAttribute(resources?: any, elementName?: any, attrName?: any, attrValue?: any): any;
85 | createAttributeInstruction(resources?: any, element?: any, theInfo?: any, existingInstruction?: any, context?: any): any;
86 | inspectTextContent(resources?: any, value?: any): any;
87 | parseInterpolation(resources?: any, value?: any): any;
88 | }
89 | export function configure(config?: any): any;
90 | }
91 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-templating-binding/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/templating-binding/master/typings.json",
5 | "raw": "github:aurelia/templating-binding",
6 | "main": "dist/aurelia-templating-binding.d.ts",
7 | "global": false,
8 | "name": "aurelia-templating-binding",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-templating-resources/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/templating-resources/master/typings.json",
5 | "raw": "github:aurelia/templating-resources",
6 | "main": "dist/aurelia-templating-resources.d.ts",
7 | "global": false,
8 | "name": "aurelia-templating-resources",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-templating-router/index.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by typings
2 | // Source: https://raw.githubusercontent.com/aurelia/templating-router/master/dist/aurelia-templating-router.d.ts
3 | declare module 'aurelia-templating-router' {
4 | import * as LogManager from 'aurelia-logging';
5 | import {
6 | customAttribute,
7 | bindable,
8 | ViewSlot,
9 | ViewLocator,
10 | customElement,
11 | noView,
12 | BehaviorInstruction,
13 | CompositionTransaction,
14 | CompositionEngine,
15 | ShadowDOM
16 | } from 'aurelia-templating';
17 | import {
18 | inject,
19 | Container
20 | } from 'aurelia-dependency-injection';
21 | import {
22 | Router,
23 | RouteLoader
24 | } from 'aurelia-router';
25 | import {
26 | DOM
27 | } from 'aurelia-pal';
28 | import {
29 | Origin
30 | } from 'aurelia-metadata';
31 | import {
32 | relativeToFile
33 | } from 'aurelia-path';
34 | export class RouteHref {
35 | constructor(router?: any, element?: any);
36 | bind(): any;
37 | unbind(): any;
38 | attributeChanged(value?: any, previous?: any): any;
39 | processChange(): any;
40 | }
41 | export class RouterView {
42 | swapOrder: any;
43 | layoutView: any;
44 | layoutViewModel: any;
45 | layoutModel: any;
46 | constructor(element?: any, container?: any, viewSlot?: any, router?: any, viewLocator?: any, compositionTransaction?: any, compositionEngine?: any);
47 | created(owningView?: any): any;
48 | bind(bindingContext?: any, overrideContext?: any): any;
49 | process(viewPortInstruction?: any, waitToSwap?: any): any;
50 | swap(viewPortInstruction?: any): any;
51 | }
52 | export class TemplatingRouteLoader extends RouteLoader {
53 | constructor(compositionEngine?: any);
54 | loadRoute(router?: any, config?: any): any;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-templating-router/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/templating-router/master/typings.json",
5 | "raw": "github:aurelia/templating-router",
6 | "main": "dist/aurelia-templating-router.d.ts",
7 | "global": false,
8 | "name": "aurelia-templating-router",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/typings/modules/aurelia-templating/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "resolution": "main",
3 | "tree": {
4 | "src": "https://raw.githubusercontent.com/aurelia/templating/master/typings.json",
5 | "raw": "github:aurelia/templating",
6 | "main": "dist/aurelia-templating.d.ts",
7 | "global": false,
8 | "name": "aurelia-templating",
9 | "type": "typings"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/exar-ui/wallaby.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = function (wallaby) {
3 |
4 | return {
5 | files: [
6 |
7 | {pattern: 'jspm_packages/system.js', instrument: false},
8 | {pattern: 'config.js', instrument: false},
9 |
10 | {pattern: 'src/**/*.ts', load: false}
11 |
12 | ],
13 |
14 | tests: [
15 | {pattern: 'test/unit/**/*.spec.ts', load: false}
16 | ],
17 |
18 |
19 | middleware: (app, express) => {
20 | app.use('/jspm_packages', express.static(require('path').join(__dirname, 'jspm_packages')));
21 | },
22 |
23 | bootstrap: function (wallaby) {
24 | wallaby.delayStart();
25 |
26 | System.config({
27 | paths: {
28 | "*": null,
29 | "src/*": "src/*",
30 | "typescript": "node_modules/typescript/lib/typescript.js",
31 | "systemjs": "node_modules/systemjs/dist/system.js",
32 | 'system-polyfills': 'node_modules/systemjs/dist/system-polyfills.js',
33 | 'es6-module-loader': 'node_modules/es6-module-loader/dist/es6-module-loader.js'
34 | },
35 | packages: {
36 | 'test/unit': {
37 | defaultExtension: 'ts'
38 | },
39 | 'src': {
40 | defaultExtension: 'ts'
41 | }
42 | },
43 | transpiler: 'typescript'
44 | });
45 |
46 | var promises = [];
47 | for (var i = 0, len = wallaby.tests.length; i < len; i++) {
48 | promises.push(System['import'](wallaby.tests[i].replace(/\.js$/, '')));
49 | }
50 |
51 | Promise.all(promises).then(function () {
52 | wallaby.start();
53 | });
54 | },
55 |
56 | debug: false
57 | };
58 | };
59 |
--------------------------------------------------------------------------------
/test-all:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd ./exar-core && cargo test && cargo test --features serde-serialization --no-default-features &&
4 | cd ../exar-net && cargo test &&
5 | cd ../exar-server && cargo test && cargo test --features serde-serialization --no-default-features &&
6 | cd ../exar-client && cargo test &&
7 | cd ../exar-testkit && cargo test &&
8 | cd ../exar-db && cargo test &&
9 | cd ..
10 |
--------------------------------------------------------------------------------