9
.gitignore
vendored
|
@ -1,3 +1,10 @@
|
|||
node_modules
|
||||
|
||||
# Tests/examples
|
||||
test/logs
|
||||
Thumbs.db
|
||||
logs/
|
||||
logs*/
|
||||
|
||||
Thumbs.db
|
||||
|
||||
npm-debug.log
|
|
@ -10,5 +10,7 @@
|
|||
"unused": true,
|
||||
"boss": true,
|
||||
"eqnull": true,
|
||||
"node": true
|
||||
"node": true,
|
||||
"browser": true,
|
||||
"predef" : ["angular", "app"]
|
||||
}
|
||||
|
|
16
Gruntfile.js
|
@ -4,20 +4,15 @@ module.exports = function(grunt) {
|
|||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
nodeunit: {
|
||||
'files': ['test/**/*.js'],
|
||||
'usage': ['test/**/usage.js'],
|
||||
'express-usage': ['test/**/express-usage.js']
|
||||
},
|
||||
jshint: {
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
},
|
||||
gruntfile: {
|
||||
src: 'Gruntfile.js'
|
||||
src: ['scribe.js', 'Gruntfile.js']
|
||||
},
|
||||
lib: {
|
||||
src: ['lib/**/*.js']
|
||||
src: ['lib/**/*.js', 'examples/**/*.js', 'static/js/**/*.js']
|
||||
},
|
||||
test: {
|
||||
src: ['test/**/*.js']
|
||||
|
@ -30,21 +25,20 @@ module.exports = function(grunt) {
|
|||
},
|
||||
lib: {
|
||||
files: '<%= jshint.lib.src %>',
|
||||
tasks: ['jshint:lib', 'nodeunit']
|
||||
tasks: ['jshint:lib']
|
||||
},
|
||||
test: {
|
||||
files: '<%= jshint.test.src %>',
|
||||
tasks: ['jshint:test', 'nodeunit']
|
||||
tasks: ['jshint:test']
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// These plugins provide necessary tasks.
|
||||
grunt.loadNpmTasks('grunt-contrib-nodeunit');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
|
||||
// Default task.
|
||||
grunt.registerTask('default', ['jshint', 'nodeunit']);
|
||||
grunt.registerTask('default', ['jshint']);
|
||||
|
||||
};
|
||||
|
|
763
README.md
|
@ -1,129 +1,674 @@
|
|||

|
||||
=======
|
||||
|
||||
**Lightweight NodeJS Logging**
|
||||
Overview
|
||||
=======
|
||||
Unlike many of the libraries out there, Scribe.js allows logging on multiple files and is divided into folders by date. And it is possibly the easiest logging you can implement. And it does everything you need a basic logger to do.
|
||||
- Save messages into log files organized by user, date, and type
|
||||
|
||||
```javascript
|
||||
console.tag("Demo").time().file().log("%s is %s", "ScribeJS", "awesome")
|
||||
```
|
||||

|
||||
|
||||
# Overview
|
||||
|
||||
Unlike many of the libraries out there, Scribe.js allows logging on multiple files and is divided into folders by date.
|
||||
And it is possibly the easiest logging you can implement.
|
||||
And it does everything you need a basic logger to do :
|
||||
|
||||
- Keep using the `console` object
|
||||
- Save messages into json log files organized by user, date, and type or your custom rule
|
||||
- Print messages into console using colors indicating level of importance
|
||||
- Adding context to logs such as time, tags, filename and line number
|
||||
|
||||
Output Methods (Web | Console | File)
|
||||
=======
|
||||
Method#Web - Select Date
|
||||
---
|
||||

|
||||
Method#Web - Select Log Type
|
||||
---
|
||||

|
||||
Method#Web - View Logs
|
||||
---
|
||||

|
||||
Method#Console - Command Prompt
|
||||
---
|
||||

|
||||
Method#File - File
|
||||
---
|
||||

|
||||
Method#File - Directory Layout
|
||||
---
|
||||

|
||||
And :
|
||||
|
||||
- Logging express requests
|
||||
- Providing a rich HTML web panel to access logs from your browser and an API
|
||||
|
||||
|
||||
#Table of contents
|
||||
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
* [Overview](#overview)
|
||||
* [Table of contents](#table-of-contents)
|
||||
* [Installing](#installing)
|
||||
* [Examples](#examples)
|
||||
* [Documentation](#documentation)
|
||||
* [scribe(config)](#scribeconfig)
|
||||
* [scribe.console(config, logWriter)](#scribeconsoleconfig-logwriter)
|
||||
* [scribe.webPanel()](#scribewebpanel)
|
||||
* [scribe.express.logger(console, validate)](#scribeexpressloggerconsole-validate)
|
||||
* [scribe.LogWriter](#scribelogwriter)
|
||||
* [scribe.Console2](#scribeconsole2)
|
||||
* [Console2(opt)](#console2opt)
|
||||
* [Console2.time()](#console2time)
|
||||
* [Console2.date()](#console2date)
|
||||
* [Console2.tag(\*args), Console2.t(\*args)](#console2tagargs-console2targs)
|
||||
* [Console2.file(), Console2.f()](#console2file-console2f)
|
||||
* [Console2.addLogger(name, colors, opt)](#console2addloggername-colors-opt)
|
||||
* [Console2.buildArgs(log)](#console2buildargslog)
|
||||
* [Console2.buildContext(log, opt)](#console2buildcontextlog-opt)
|
||||
* [Console2.\[your logger\](*args)](#console2your-loggerargs)
|
||||
* [Console2 events](#console2-events)
|
||||
* [LogWriter(rootPath)](#logwriterrootpath)
|
||||
* [LogWriter.initHistory()](#logwriterinithistory)
|
||||
* [LogWriter.createDir(path, callback)](#logwritercreatedirpath-callback)
|
||||
* [LogWriter.appendFile(pathToFile, content, callback)](#logwriterappendfilepathtofile-content-callback)
|
||||
* [LogWriter.writeFile(pathToFile, content, callback)](#logwriterwritefilepathtofile-content-callback)
|
||||
* [LogWriter.newFileHistory(pathToFile)](#logwriternewfilehistorypathtofile)
|
||||
* [logWriter.getUser()](#logwritergetuser)
|
||||
* [LogWriter.getPath(opt)](#logwritergetpathopt)
|
||||
* [LogWriter.getFile(opt)](#logwritergetfileopt)
|
||||
* [LogWriter.path(opt)](#logwriterpathopt)
|
||||
* [LogWriter.save(log, opt)](#logwritersavelog-opt)
|
||||
* [LogWriter.saveOpt(logger)](#logwritersaveoptlogger)
|
||||
* [LogWriter.addLogger(logger)](#logwriteraddloggerlogger)
|
||||
* [*How logs are saved ?*](#how-logs-are-saved)
|
||||
* [Example](#example)
|
||||
* [WebPanel](#webpanel)
|
||||
* [Dev tips :](#dev-tips)
|
||||
* [ExpressLogger](#expresslogger)
|
||||
* [ExpressLogger.logger(console, filter)](#expressloggerloggerconsole-filter)
|
||||
* [Using Scribe through your modules](#using-scribe-through-your-modules)
|
||||
* [Come back to the old console](#come-back-to-the-old-console)
|
||||
* [Contributors](#contributors)
|
||||
|
||||
<!-- toc stop -->
|
||||
|
||||
|
||||
|
||||
|
||||
# Installing
|
||||
|
||||
Installation
|
||||
=======
|
||||
```
|
||||
npm install git+https://github.com/bluejamesbond/Scribe.js.git
|
||||
```
|
||||
Documentation
|
||||
=======
|
||||
```js
|
||||
var scribe = require('scribe');
|
||||
|
||||
// Configuration
|
||||
// --------------
|
||||
scribe.configure(function(){
|
||||
scribe.set('app', 'MY_APP_NAME'); // NOTE Best way learn about these settings is
|
||||
scribe.set('logPath', './logs'); // Doublecheck // them out for yourself.
|
||||
scribe.set('defaultTag', 'DEFAULT_TAG');
|
||||
scribe.set('divider', ':::');
|
||||
scribe.set('identation', 5); // Identation before console messages
|
||||
# Examples
|
||||
|
||||
A list of examples is provided in [`/examples`](/examples).
|
||||
|
||||
# Documentation
|
||||
|
||||
ScribeJS is divided is 4 main modules :
|
||||
|
||||
- [Console2](#console2opt) : an extended console object
|
||||
- [LogWriter](#logwriterrootpath) : an utility to save logs on disk
|
||||
- [WebPanel](#webpanel) : a rich HTML logs explorer
|
||||
- [ExpressLogger](#expresslogger) : an utility to logs all express request
|
||||
|
||||
It all starts by adding ScribeJS to your js file :
|
||||
|
||||
```javascript
|
||||
require('scribe')();
|
||||
|
||||
var console = process.console;
|
||||
```
|
||||
Use this import if you don't need do configure anything. It will attach a new Console2 instance on `process.console` and create [basic loggers](#basic-loggers).
|
||||
|
||||
Or :
|
||||
|
||||
```javascript
|
||||
var scribe = require('scribe')();
|
||||
```
|
||||
Use this import if you want to configure or custom something.
|
||||
|
||||
|
||||
##scribe(config)
|
||||
|
||||
**Params** :
|
||||
|
||||
- `config` : *Optional.*
|
||||
- `rootPath` : logs folder for LogWriter. Default `/logs`
|
||||
- `createDefaultConsole` : Boolean. If `true` : create a Console2 instance attached to `process.console`. Default `true`. See [Using Scribe through your modules](#using-scribe-through-your-modules)
|
||||
|
||||
|
||||
**Return** : an object with this properties
|
||||
|
||||
- `console`
|
||||
- `webPanel`
|
||||
- `express`
|
||||
- `LogWriter`
|
||||
- `Console2`
|
||||
|
||||
|
||||
###scribe.console(config, logWriter)
|
||||
|
||||
Create a new Console2 instance with LogWriter listening. This is the best way to create a console.
|
||||
|
||||
**Params** :
|
||||
|
||||
- `config`
|
||||
- `console` : *Optional.* [Console2 options](#console2opt)
|
||||
- `logWiter` : *Optional.* Boolean|Object. If `false`, don't save logs on disk.
|
||||
- `rootPath` : directory where to store logs
|
||||
- `createBasic` : *Optional*. Boolean. `true` to create [basic loggers](#basic-loggers). Default `true`.
|
||||
- `logWriter` : *Optional.* A custom LogWriter instance to use.
|
||||
|
||||
**Return** : A Console2 instance.
|
||||
|
||||
|
||||
**Example** :
|
||||
|
||||
```javascript
|
||||
var console = scribe.console();
|
||||
|
||||
var anotherConsole = scribe.console({
|
||||
console : myConsole2Config,
|
||||
createBasic : false
|
||||
});
|
||||
```
|
||||
|
||||
####Basic loggers
|
||||
When passing `true` as the `createBasic` config, you ask ScribeJS to create default loggers to the new console you're builting.
|
||||
|
||||
These loggers are :
|
||||
|
||||
- `log()`
|
||||
- `info()`
|
||||
- `error()`
|
||||
- `warning()`
|
||||
- `dir()`
|
||||
|
||||
See [`/examples/basic.js`](/examples/basic.js)
|
||||
|
||||
###scribe.webPanel()
|
||||
|
||||
**Return** : an express router
|
||||
|
||||
**Example** : (assuming you have an `app` express server)
|
||||
|
||||
```javascript
|
||||
app.use('/logs', scribe.webPanel());
|
||||
```
|
||||
|
||||
###scribe.express.logger(console, validate)
|
||||
|
||||
**Params**:
|
||||
|
||||
- `console` : *Optional.* An instance of Console2 with an `.info()` logger. If no console provided, Scribe will try to use `process.console` if it exists. If not, it will throw an error.
|
||||
- `validate` : a filter function that receive `req` and `res` as arguments and should return `true` in order to Scribe to log that request.
|
||||
|
||||
**Return** : a function that log every request
|
||||
|
||||
**Example** :
|
||||
|
||||
```javascript
|
||||
app.use(scribe.express.logger());
|
||||
```
|
||||
|
||||
See also : [`/examples/expressLogger_custom.js`](/examples/expressLogger_custom.js)
|
||||
|
||||
|
||||
###scribe.LogWriter
|
||||
|
||||
**LogWriter constructor**
|
||||
|
||||
Use the constructor to built your own instance of LogWriter. Usefull when you need, by example, to change to full path of a log file.
|
||||
Default is : `[YYYY]/[MM]/[DD_MM_YY].[logger].json`.
|
||||
|
||||
You can by example change it to `[user]/[logger]/[DD_MMM_YY].[logger].json`. See [`/examples/logWriter_config.js`](/examples/logWriter_config.js).
|
||||
|
||||
|
||||
###scribe.Console2
|
||||
|
||||
**Console2 constructor**
|
||||
|
||||
Don't use it directly but use `scribe.console()` instead in order to hook LogWriter logic (and others) on the new console.
|
||||
|
||||
|
||||
##Console2(opt)
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
require('../scribe')(); //loads Scribe (with basic loggers)
|
||||
|
||||
//create a local (for the module) console
|
||||
var console = process.console;
|
||||
|
||||
console.log("Hello");
|
||||
//you can use printf-like format
|
||||
console.log("A string %s and a number %d", "hello", "123");
|
||||
|
||||
//Time
|
||||
console.time().log("Print the full time");
|
||||
console.date().log("Just print the date");
|
||||
|
||||
//Tags
|
||||
console.tag("My Tag").log("Add a tag");
|
||||
console.tag("Tag1", 'Tag2', 123).log("Or multiple tag");
|
||||
console.tag({msg : 'my-tag', colors : ['red', 'inverse']}).log("Use colors.js colors");
|
||||
|
||||
//File and line number
|
||||
console.file().log("Print the file and the line of the call");
|
||||
|
||||
//Object
|
||||
console.log({just : 'an object'});
|
||||
|
||||
//Combos !
|
||||
console.log(
|
||||
"Print many things",
|
||||
{ key1 : "val 1", key2 : { a: "b", c : []}, key3 : [1234]},
|
||||
['an array'],
|
||||
"A String"
|
||||
);
|
||||
console.tag("Combo!").time().file().log("A combo");
|
||||
```
|
||||
|
||||
**Params** : (all optional)
|
||||
|
||||
- `opt.colors` : Array|String. Default colors output for all loggers. Default ['cyan'].
|
||||
- `opt.tagsColors` : Array|String. Default colors output for tags. Default undefined.
|
||||
- `opt.timeColors` : Array|String. Default colors output for time. Default undefined.
|
||||
- `opt.datecolors` : Array|String. Default colors output for date. Default undefined.
|
||||
- `opt.fileColors` : Array|String. Default colors output for filename. Default undefined.
|
||||
- `opt.lineColors` : Array|String. Default colors output for line number. Default undefined.
|
||||
- `opt.alwaysTags` : Boolean. Always print tags (even without tag() ). Default false.
|
||||
- `opt.alwaysLocation` : Boolean. Always print location (even without file() ). Default false.
|
||||
- `opt.alwaysTime` : Boolean. Always print time (even without time() ). Default false.
|
||||
- `opt.alwaysDate` : Boolean. Always print date (even without date() ). Default false.
|
||||
- `opt.logInConsole` : Boolean. Should all loggers print to console by default ? Default true.
|
||||
- `opt.contextMediumSize` : Int. Medium size of the context part of a log message. Used when calculating indent. Default to 45.
|
||||
- `opt.spaceSize` : Int. Space between context part and log part. Default to 4.
|
||||
|
||||
Colors must be [colors.js](https://github.com/Marak/colors.js) compatible.
|
||||
|
||||

|
||||
|
||||
**Example** :
|
||||
|
||||
```javascript
|
||||
var myConfigConsole = scribe.console({
|
||||
console : { //pass here Console2 options
|
||||
colors : ['rainbow', 'inverse'],
|
||||
tagsColors : ['yellow', 'underline']
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
See :
|
||||
|
||||
- [`/examples/run_with_config.js`](/examples/run_with_config.js)
|
||||
- [`/examples/console2.js`](/examples/console2.js)
|
||||
|
||||
###Console2.time()
|
||||
Tell the logger to log the time (ISO format).
|
||||
|
||||
###Console2.date()
|
||||
Tell the logger to log the date (using `toDateString()`).
|
||||
|
||||
###Console2.tag(\*args), Console2.t(\*args)
|
||||
|
||||
**Params**:
|
||||
|
||||
An infinite number of `tag` where `tag` is :
|
||||
|
||||
- a string
|
||||
- or an object :
|
||||
- `msg` : String. The tag
|
||||
- `colors` : Array|String. Colors.js colors
|
||||
|
||||
**Examples** :
|
||||
|
||||
```javascript
|
||||
console.tag('My tag').log('Something');
|
||||
console.tag("A tag", {msg : "A another tag", colors : ['red', 'inverse']}).log('Something else').
|
||||
```
|
||||
|
||||
###Console2.file(), Console2.f()
|
||||
Tell the logger to log the filename and the line of the log.
|
||||
|
||||
|
||||
|
||||
###Console2.addLogger(name, colors, opt)
|
||||
|
||||
**Params** :
|
||||
|
||||
- `name` : String. Name of the logger. Next you call the logger with `console.mylogger()`
|
||||
- `colors` : Array|String. *Optional*. Colors.js colors.
|
||||
- `opt` : *Optional*. Options for this logger only. See Console2 options.
|
||||
- `tagsColors` : Array|String. Default colors output for tags. Default undefined.
|
||||
- `timeColors` : Array|String. Default colors output for time. Default undefined.
|
||||
- `datecolors` : Array|String. Default colors output for date. Default undefined.
|
||||
- `fileColors` : Array|String. Default colors output for filename. Default undefined.
|
||||
- `lineColors` : Array|String. Default colors output for line number. Default undefined.
|
||||
- `alwaysTags` : Boolean. Always print tags (even without tag() ). Default false.
|
||||
- `alwaysLocation` : Boolean. Always print location (even without file() ). Default false.
|
||||
- `alwaysTime` : Boolean. Always print time (even without time() ). Default false.
|
||||
- `alwaysDate` : Boolean. Always print date (even without date() ). Default false.
|
||||
- `logInConsole` : Boolean. Should all loggers print to console by default ? Default true.
|
||||
|
||||
|
||||
**Example** :
|
||||
|
||||
```javascript
|
||||
console.addLogger('fun', ['rainbow', 'inverse'], {
|
||||
timeColors : ['gray', 'underline']
|
||||
})
|
||||
|
||||
console.fun('something');
|
||||
```
|
||||
See Console2.buildArgs() to know what you can pass to a logger
|
||||
|
||||
###Console2.buildArgs(log)
|
||||
|
||||
Do not use this unless you want to change how args you pass to a logger are printed. See code.
|
||||
|
||||
**Params** :
|
||||
|
||||
- `log` : A log object constructed by the logger. See code.
|
||||
- `args`. Logger's `arguments`
|
||||
- ...
|
||||
|
||||
**Return** : String. The args part of the message.
|
||||
|
||||
- If all args ar string of number, will use `util.format.apply()` as the original nodejs console does.
|
||||
- If object or array are present, will print the args line by line and object/arg on multilines.
|
||||
|
||||
See [`/examples/console2.js`](/examples/console2.js)
|
||||
|
||||
|
||||
###Console2.buildContext(log, opt)
|
||||
|
||||
Do not use this unless you want to change how context (tags/location/time/date/...) you pass to a logger are printed. See code.
|
||||
|
||||
**Params** :
|
||||
|
||||
- `log` : A log object constructed by the logger. See code.
|
||||
- `opt` : wether to print tags/location/time/date or not
|
||||
|
||||
**Return** :
|
||||
|
||||
- `result` : String. The context part of the log.
|
||||
- `lenght` : Int. The human-readable length of the result. Ie. without colors console caracters.
|
||||
|
||||
###Console2.\[your logger](*args)
|
||||
|
||||
Will print `*args` to the console, with context if there is.
|
||||
See `Console2.buildArgs()`.
|
||||
|
||||
**Example** :
|
||||
|
||||
```javascript
|
||||
console.addLogger('demo');
|
||||
|
||||
console.tag('Simple').demo('A ', 'message');
|
||||
console.tag('Printf format').demo("%s:%s", 10, "23");
|
||||
console.tag('Multiple args and big context').time().file().demo(
|
||||
"A message", //string
|
||||
123, //number
|
||||
[1, 2], //array
|
||||
{ foo : 'bar' } //object
|
||||
);
|
||||
```
|
||||
|
||||
See [`/examples/console2.js`](/examples/console2.js)
|
||||
|
||||
|
||||
###Console2 events
|
||||
|
||||
Each Console2 instance emits events :
|
||||
|
||||
- `newLogger` when a new logger is created
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* name : name of the logger
|
||||
* opt : Console2 options
|
||||
*/
|
||||
console.on('newLogger', function (name, opt) {
|
||||
//welcome, new logger !
|
||||
});
|
||||
```
|
||||
- `new` when a logger logs something
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* log : the log object.
|
||||
|
||||
var log = {
|
||||
type : 'loggerName',
|
||||
show : {
|
||||
tags : Boolean,
|
||||
location : Boolean,
|
||||
time : Boolean,
|
||||
date : Boolean
|
||||
},
|
||||
context : {
|
||||
tags : [ tags ],
|
||||
file : Boolean,
|
||||
time : Date.now(),
|
||||
location : { filename : 'main.js', line : 12 }
|
||||
},
|
||||
args : arguments, //loggers arguments
|
||||
opt : opt, //loggers options for addLogger()
|
||||
|
||||
contextString : '[..] ...' ,
|
||||
argsString : 'My message',
|
||||
message : '[..] ... My message'
|
||||
};
|
||||
|
||||
scribe.set('maxTagLength', 30); // Any tags that have a length greather than
|
||||
// 30 characters will be ignored
|
||||
*
|
||||
* loggerName : the logger name
|
||||
*/
|
||||
console.on('new', function (log, loggerName) {
|
||||
//Oh! `loggerName` has logged something
|
||||
});
|
||||
```
|
||||
- `[loggerName]` when [loggerName] logs something. Fired whith `new`
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* log : same as above
|
||||
*/
|
||||
console.on('log', function (log) {
|
||||
//someone has logged something with logger "log"
|
||||
});
|
||||
```
|
||||
If loggerName is `'error'`, Scribe replace error with `'errorEvent'` as NodeJS `eventEmitter` will raise an Error if there is no listeners.
|
||||
|
||||
scribe.set('mainUser', 'root'); // Username of the account which is running
|
||||
// the NodeJS server
|
||||
See [`/examples/events.js`](`/examples/events.js`)
|
||||
|
||||
## LogWriter(rootPath)
|
||||
|
||||

|
||||
|
||||
LogWriter constructor. Highly configurable as all functions are public. See code.
|
||||
|
||||
**Param** :
|
||||
|
||||
- `rootPath`: String. *Optional* Directory where to save logs. Default `logs`.
|
||||
|
||||
|
||||
###LogWriter.initHistory()
|
||||
Attach and init the history property.
|
||||
|
||||
###LogWriter.createDir(path, callback)
|
||||
Create a dir if doesn't exist yet.
|
||||
|
||||
###LogWriter.appendFile(pathToFile, content, callback)
|
||||
Append content to file.
|
||||
|
||||
###LogWriter.writeFile(pathToFile, content, callback)
|
||||
Write (erase) content to file.
|
||||
|
||||
###LogWriter.newFileHistory(pathToFile)
|
||||
Save the new file path in history according to date.
|
||||
|
||||
###logWriter.getUser()
|
||||
Util. Return active system user.
|
||||
|
||||
###LogWriter.getPath(opt)
|
||||
Build the path to current logs folder.
|
||||
Default return `[YYYY]/[MMM]`
|
||||
|
||||
###LogWriter.getFile(opt)
|
||||
Build the filename.
|
||||
Default `[DD_MM_YY].[loggerName].json`
|
||||
|
||||
###LogWriter.path(opt)
|
||||
Build the full path to file.
|
||||
Ie. RootPath + getPath() + getFile()
|
||||
|
||||
###LogWriter.save(log, opt)
|
||||
Save a log on disk
|
||||
|
||||
###LogWriter.saveOpt(logger)
|
||||
Save logger opt in root folder
|
||||
|
||||
###LogWriter.addLogger(logger)
|
||||
Call saveOpt().
|
||||
|
||||
###*How logs are saved ?*
|
||||
|
||||
LogWriter create an `history.json` file in root folder where it keeps tracks of all logs files created by date.
|
||||
|
||||
It also create `[logger name].json` in root folder for each logger where it saves the logger config.
|
||||
|
||||
Then LogWriter will save logs in directory according to the output of `LogWriter.path()`.
|
||||
|
||||
|
||||
### Example
|
||||
|
||||
See [`/examples/logWriter_config.js`](/examples/logWriter_config.js) to see how to build your custom log path and pass it to `scribe.console()` function.
|
||||
|
||||
|
||||
|
||||
## WebPanel
|
||||
|
||||
An express router that served an HTML logs explorer.
|
||||
|
||||

|
||||
|
||||
**Example** :
|
||||
|
||||
```javascript
|
||||
var scribe = require('scribe')(),
|
||||
app = express();
|
||||
|
||||
app.use('\logs', scribe.webPanel());
|
||||
|
||||
app.listen(8080);
|
||||
```
|
||||
|
||||
See :
|
||||
|
||||
- [`/examples/webPanel.js`](/examples/webPanel.js)
|
||||
- [`/examples/webPanel_auth.js`](/examples/webPanel_auth.js) where the webPanel is protected by a basic HTTP authentification.
|
||||
|
||||
###Dev tips :
|
||||
|
||||
WebPanel highly depends on LogWriter as it use `history.json` file to find logs.
|
||||
|
||||
WebPanel is RESTfull :
|
||||
|
||||
- on the server side, an express router serves an API and find files on disk
|
||||
- on client side, an AngularJS app manage the routing and the data
|
||||
|
||||
All the client code is under `/static`.
|
||||
|
||||
|
||||
|
||||
## ExpressLogger
|
||||
|
||||

|
||||
|
||||
###ExpressLogger.logger(console, filter)
|
||||
An utility to log each request made to an express server.
|
||||
See [`scribe.express.logger()`](#scribeexpressloggerconsole-validate)
|
||||
|
||||
#Using Scribe through your modules
|
||||
|
||||
When running `require('scribe')()` or `require('scribe')({createDefaultConsole : true})` you ask Scribe to attach a fresh console on the NodeJS `process` variable.
|
||||
|
||||
As `process` is shared accross all modules you required (the whole process), you can use the Console2 instance in sub-modules.
|
||||
|
||||
**Example** :
|
||||
|
||||
```javascript
|
||||
//main.js
|
||||
require('scribe')();
|
||||
var sub = require('./sub.js'); //a sub-module
|
||||
var console = process.console;
|
||||
|
||||
console.tag('Hello world').log("We're in the main file")
|
||||
|
||||
sub.something(); //Will use process.console
|
||||
```
|
||||
|
||||
```javascript
|
||||
//sub.js
|
||||
//don't require scribe, simply link `process.console`
|
||||
var console = process.console;
|
||||
|
||||
module.exports = {
|
||||
something : function () {
|
||||
console.tag("Hello World", "Sub").log("We're in a submodule");
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Tip : even if you don't tell scribe to create a default console, you can manually attach a Console2 instance on `process`.
|
||||
|
||||
```javascript
|
||||
//main.js
|
||||
var scribe = require('scribe')({
|
||||
createDefaultConsole : false
|
||||
});
|
||||
var sub = require('./sub.js'); //a sub-module
|
||||
|
||||
var customConsole = scribe.console({ //a new console
|
||||
//custom
|
||||
});
|
||||
|
||||
// Create Loggers
|
||||
// --------------
|
||||
scribe.addLogger("log", true , true, 'green'); // (name, save to file, print to console,
|
||||
scribe.addLogger('realtime', true, true, 'underline'); // tag color)
|
||||
scribe.addLogger('high', true, true, 'magenta');
|
||||
scribe.addLogger('normal', true, true, 'white');
|
||||
scribe.addLogger('low', true, true, 'grey');
|
||||
scribe.addLogger('info', true, true, 'cyan');
|
||||
process.customConsole = customConsole; //attach it to process
|
||||
|
||||
// Express.js
|
||||
// WARNING: ExpressJS must be installed for this to work
|
||||
// You also need to start an ExpressJS server in order for
|
||||
// this to work.
|
||||
// --------------
|
||||
app.use(scribe.express.logger(function(req, res){ // Express.js access log
|
||||
return true; // Filter out any Express messages
|
||||
}));
|
||||
|
||||
// Control Panel
|
||||
// WARNING: ExpressJS must be installed for this to work
|
||||
// You also need to start an ExpressJS server in order for
|
||||
// this to work.
|
||||
// --------------
|
||||
app.get('/log', scribe.express.controlPanel()); // Enable web control panel
|
||||
|
||||
// Basic logging
|
||||
// --------------
|
||||
console.log("[Tagname] Your message"); // [Tagname] Your message
|
||||
console.realtime("[Tagname] Your message"); // [Tagname] Your message
|
||||
console.high("[Tagname] Your message "); // [Tagname] Your message
|
||||
console.normal("[Tagname][]Your message"); // [Tagname] []Your message
|
||||
console.low("[Tagname]Your message"); // [Tagname] Your message
|
||||
|
||||
// Tagging function
|
||||
// ----------------
|
||||
console.t("Tagname").log("Your message"); // [Tagname] Your message
|
||||
console.t("Tagname").log("Your message"); // [Tagname] Your message
|
||||
console.t("Tagname").log("Your message"); // [Tagname] Your message
|
||||
|
||||
// Force use default tag
|
||||
// ---------------------
|
||||
console.t().log("Your message"); // [MY_APP_NAME] Your message
|
||||
|
||||
// Pass in file name
|
||||
// -----------------
|
||||
console.f(__filename).log("Your message"); // [file.js] Your message
|
||||
|
||||
// Auto tagging
|
||||
// ------------
|
||||
console.log("Your message"); // [invokedFrom.js:25] Your message
|
||||
|
||||
// Tag Scoping
|
||||
// -----------
|
||||
(function(console){
|
||||
|
||||
console.info("yeeha"); // [scoped-tag] yeeha
|
||||
console.log("yeeha"); // [scoped-tag] yeeha
|
||||
|
||||
})(console.t('scoped-tag'));
|
||||
customConsole('Hello world').log("We're in the main file")
|
||||
|
||||
sub.something(); //Will use process.console
|
||||
```
|
||||
Experimental
|
||||
=======
|
||||
```js
|
||||
// Simple Testing
|
||||
// --------------
|
||||
console.test("Test name").should(5).be(5); // Pretty printed test results
|
||||
|
||||
```javascript
|
||||
//sub.js
|
||||
//don't require scribe
|
||||
var console = process.customConsole;
|
||||
|
||||
module.exports = {
|
||||
something : function () {
|
||||
console.tag("Hello World", "Sub").log("We're in a submodule");
|
||||
}
|
||||
};
|
||||
```
|
||||
Contributors
|
||||
=======
|
||||
|
||||
See :
|
||||
|
||||
- [`/examples/run.js`](/examples/run.js)
|
||||
- [NodeJS process doc](http://nodejs.org/api/process.html)
|
||||
|
||||
|
||||
#Come back to the old console
|
||||
|
||||
Scribe overides nothing and doesn't break logging in dependencies. The old NodeJS console is never too far away.
|
||||
|
||||
```javascript
|
||||
require('scribe')();
|
||||
|
||||
var console = process.console;
|
||||
|
||||
console.time().log("Logging with Scribe")
|
||||
global.console.log("Logging the old way")
|
||||
```
|
||||
bluejamesbond
|
||||
|
||||
```javascript
|
||||
//in a dependency
|
||||
console.log("Something") //the old console
|
||||
```
|
||||
|
||||
See : [NodeJS global doc](http://nodejs.org/api/globals.html)
|
||||
|
||||
#Contributors
|
||||
|
||||
- [bluejamesbond](https://github.com/bluejamesbond)
|
||||
- [guillaumewuip](https://github.com/guillaumewuip)
|
BIN
__misc/colorsDemo.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
__misc/console2Demo.png
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
__misc/expressLoggerDemo.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
__misc/introDemo.png
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
__misc/logWriterDemo.png
Normal file
After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 40 KiB |
BIN
__misc/webPanelDemo.gif
Normal file
After Width: | Height: | Size: 2.8 MiB |
13
examples/basic.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*jshint -W079 */
|
||||
|
||||
require('../scribe')(); //loads Scribe
|
||||
|
||||
var console = process.console;
|
||||
|
||||
console.log("Console log");
|
||||
console.info("Console info");
|
||||
console.error("Console error");
|
||||
console.warning("Console warning");
|
||||
console.dir({
|
||||
foo : 'bar'
|
||||
});
|
37
examples/console2.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*jshint -W079 */
|
||||
|
||||
/**
|
||||
* Console2 functions
|
||||
*/
|
||||
|
||||
require('../scribe')(); //loads Scribe (with basic loggers)
|
||||
|
||||
var console = process.console; //create a local (for the module) console
|
||||
|
||||
console.log("Hello");
|
||||
console.log("A string %s and a number %d", "hello", "123"); //you can use printf-like format
|
||||
|
||||
//Time
|
||||
console.time().log("Print the full time");
|
||||
console.date().log("Just print the date");
|
||||
|
||||
//Tags
|
||||
console.tag("My Tag").log("Add a tag");
|
||||
console.tag("Tag1", 'Tag2', 123).log("Or multiple tag");
|
||||
console.tag({msg : 'my-tag', colors : ['red', 'inverse']}).log("Use colors.js colors");
|
||||
|
||||
//File and line number
|
||||
console.file().log("Print the file and the line of the call");
|
||||
|
||||
//Object
|
||||
console.log({just : 'an object'});
|
||||
|
||||
//Combos !
|
||||
console.log(
|
||||
"Print many things",
|
||||
{ key1 : "val 1", key2 : { a: "b", c : []}, key3 : [1234]},
|
||||
['an array'],
|
||||
"A String"
|
||||
);
|
||||
console.tag("Combo!").time().file().log("A combo");
|
||||
|
20
examples/events.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*jshint -W079, -W117 */
|
||||
(function () {
|
||||
|
||||
require('./scribe')();
|
||||
|
||||
var console = process.console;
|
||||
|
||||
console.addLogger('fire');
|
||||
|
||||
console.on('fire', function (log) {
|
||||
//call 911
|
||||
phone.call911(log.argsString);
|
||||
});
|
||||
|
||||
/* .... */
|
||||
|
||||
//Somewhere in your code
|
||||
console.tag("Argggg").fire("Need help !");
|
||||
|
||||
}());
|
13
examples/expressLogger.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* jshint -W098 */
|
||||
(function () {
|
||||
var scribe = require('../scribe')(),
|
||||
express = require('express'),
|
||||
app = express(),
|
||||
console = process.console;
|
||||
|
||||
app.use(scribe.express.logger()); //Log each request
|
||||
|
||||
app.listen(8080, function () {
|
||||
console.time().log('Server listening at port 8080');
|
||||
});
|
||||
}());
|
40
examples/expressLogger_custom.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* jshint -W098 */
|
||||
(function () {
|
||||
var scribe = require('../scribe')(),
|
||||
express = require('express'),
|
||||
app = express(),
|
||||
console = process.console;
|
||||
|
||||
//Create a Console2 for express
|
||||
//with logs saved in /expressLogger
|
||||
var expressConsole = scribe.console({
|
||||
console : {
|
||||
colors : 'white',
|
||||
timeColors : ['grey', 'underline'],
|
||||
},
|
||||
createBasic : false,
|
||||
logWriter : {
|
||||
rootPath : 'expressLogger'
|
||||
}
|
||||
});
|
||||
|
||||
expressConsole.addLogger('info'); //create a 'info' logger
|
||||
|
||||
//A filter function
|
||||
var validate = function (req, res) {
|
||||
|
||||
//if (something) {
|
||||
// return false //ie. don't log this request
|
||||
//else
|
||||
//{
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
//Pass the console and the filter
|
||||
app.use(scribe.express.logger(expressConsole, validate));
|
||||
|
||||
app.listen(8080, function () {
|
||||
console.time().log('Server listening at port 8080');
|
||||
});
|
||||
}());
|
87
examples/logWriter_config.js
Normal file
|
@ -0,0 +1,87 @@
|
|||
/* jshint -W079 */
|
||||
|
||||
var moment = require('moment'),
|
||||
path = require('path');
|
||||
|
||||
var scribe = require('../scribe.js')({
|
||||
createDefaultConsole : false
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Create a custom LogWriter
|
||||
*
|
||||
* It'll save logs under logsConsoleTwo/[user]/[logger]/[DD_MMM_YY].[logger].json
|
||||
*
|
||||
* @see lib/logWriter.js for details
|
||||
*/
|
||||
|
||||
var myLogWriter = new scribe.LogWriter('logsConsoleTwo');
|
||||
|
||||
//Create own getPath and getFilename methods to erase to default ones
|
||||
|
||||
myLogWriter.getPath = function (opt) {
|
||||
|
||||
return path.join(
|
||||
this.getUser(),
|
||||
opt.logger.name
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
myLogWriter.getFilename = function (opt) {
|
||||
|
||||
var now = moment();
|
||||
|
||||
return (now.format('DD_MMM_YY')).toLowerCase() +
|
||||
'.' +
|
||||
opt.logger.name +
|
||||
'.json';
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create 3 console2 instances
|
||||
*/
|
||||
|
||||
var consoleOne = scribe.console({
|
||||
console : {
|
||||
colors : 'white'
|
||||
},
|
||||
logWriter : {
|
||||
rootPath : 'logsConsoleOne' //all logs in ./logsConsoleOne
|
||||
}
|
||||
});
|
||||
|
||||
var consoleTwo = scribe.console(
|
||||
{
|
||||
console : {
|
||||
colors : 'inverse'
|
||||
}
|
||||
},
|
||||
myLogWriter //don't pass a logWriter config, but a custom LogWriter instead
|
||||
);
|
||||
|
||||
var consoleThree = scribe.console({
|
||||
console : {
|
||||
colors : 'magenta'
|
||||
},
|
||||
logWriter : false //don't save logs on disk
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Use the consoles
|
||||
*
|
||||
* Then check logsConsoleOne and logsConsoleTwo folders
|
||||
*/
|
||||
|
||||
//consoleOne.addLogger('log');
|
||||
//consoleTwo.addLogger('log');
|
||||
//consoleThree.addLogger('log');
|
||||
|
||||
consoleOne.time().log('Hello World from consoleOne');
|
||||
consoleTwo.time().log('Hello World from consoleTwo');
|
||||
consoleThree.time().log('Hello World from consoleThree');
|
||||
|
26
examples/run.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*jshint -W079 */
|
||||
/**
|
||||
* The main file
|
||||
*/
|
||||
|
||||
require('../scribe')(); //loads Scribe
|
||||
|
||||
var console = process.console; //create a local (for the module) console
|
||||
|
||||
|
||||
//Don't worry, you can still access the original console
|
||||
global.console.log("I'm using the original console.log()");
|
||||
|
||||
//Let's create a new logger `myLoger` ...
|
||||
console.addLogger('myLogger');
|
||||
//... and use it !
|
||||
console.tag('MyTag').time().file().myLogger('Scribe.js is awesome');
|
||||
|
||||
|
||||
//Let's see how to use the new console in a sub-module :
|
||||
//(just open submodules to see what's going on there)
|
||||
|
||||
//By default, submodules still use original console
|
||||
require('./sub-without_new_console').saySomething("Hello world !");
|
||||
//But, you can use the new one !
|
||||
require('./sub-with_new_console').saySomething("Hello world !");
|
37
examples/run_with_config.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* jshint -W079 */
|
||||
/**
|
||||
* With config
|
||||
*/
|
||||
|
||||
var scribe = require('../scribe')({
|
||||
createDefaultConsole : false //Scribe won't attach a fresh console2 to process.console
|
||||
});
|
||||
|
||||
console.log(process.console); //undefined
|
||||
|
||||
var myConfigConsole = scribe.console({
|
||||
|
||||
console : { //Default options for all myConfigConsole loggers
|
||||
colors : 'white',
|
||||
tagsColors : 'red',
|
||||
timeColors : ['grey', 'underline'],
|
||||
dateColors : ['gray', 'bgMagenta'],
|
||||
fileColors : 'white',
|
||||
lineColors : ['yellow', 'inverse']
|
||||
},
|
||||
|
||||
createBasic : false //Don't create basic loggers
|
||||
|
||||
});
|
||||
|
||||
|
||||
myConfigConsole.addLogger('fun', ['rainbow', 'inverse', 'black']);
|
||||
|
||||
myConfigConsole.fun('Some rainbow in background !');
|
||||
|
||||
myConfigConsole.addLogger('log');
|
||||
|
||||
myConfigConsole.tag('A tag', 123).log('custom tags');
|
||||
myConfigConsole.time().log('custom time');
|
||||
myConfigConsole.date().log('custom date');
|
||||
myConfigConsole.file().log('custom file');
|
18
examples/sub-with_new_console.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
(function () {
|
||||
|
||||
|
||||
//You can use the new console and all its loggers
|
||||
//it's not too far away
|
||||
var console = process.console;
|
||||
|
||||
module.exports = {
|
||||
|
||||
saySomething : function (msg) {
|
||||
msg = "With new console - " + msg;
|
||||
console.myLogger(msg); //I'm using my custom logger `myLogger`
|
||||
//you can still use global.console object if you need to
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}());
|
15
examples/sub-without_new_console.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
(function () {
|
||||
|
||||
//By default, the module access global.console
|
||||
//so it doesn't break dependencies logging
|
||||
|
||||
module.exports = {
|
||||
|
||||
saySomething : function (msg) {
|
||||
msg = "Without new console - " + msg;
|
||||
console.log(msg);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}());
|
1
examples/users.htpasswd
Normal file
|
@ -0,0 +1 @@
|
|||
test:test
|
30
examples/webPanel.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* jshint -W079 */
|
||||
(function () {
|
||||
var scribe = require('../scribe')(),
|
||||
console = process.console,
|
||||
express = require('express'),
|
||||
app = express();
|
||||
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
res.send('Hello world, see you at /logs');
|
||||
});
|
||||
|
||||
app.use('/logs', scribe.webPanel());
|
||||
|
||||
|
||||
//Make some logs
|
||||
console.addLogger('debug', 'inverse');
|
||||
console.addLogger('fun', 'rainbow');
|
||||
|
||||
console.time().fun('hello world');
|
||||
console.tag('This is a test').debug('A test');
|
||||
console.tag('An object').log({
|
||||
a: 'b',
|
||||
c : [1, 2, 3]
|
||||
});
|
||||
|
||||
app.listen(8080, function () {
|
||||
console.time().log('Server listening at port 8080');
|
||||
});
|
||||
}());
|
37
examples/webPanel_auth.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* jshint -W079 */
|
||||
var auth = require('http-auth'), // @see https://github.com/gevorg/http-auth
|
||||
express = require('express'),
|
||||
app = express(),
|
||||
scribe = require('../scribe')(),
|
||||
console = process.console;
|
||||
|
||||
/**
|
||||
* User : test
|
||||
* Pwd : tes
|
||||
*/
|
||||
var basicAuth = auth.basic({ //basic auth config
|
||||
realm : "ScribeJS WebPanel",
|
||||
file : __dirname + "/users.htpasswd" // test:test
|
||||
});
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
res.send('Hello world, see you at /logs');
|
||||
});
|
||||
|
||||
app.use('/logs', auth.connect(basicAuth), scribe.webPanel());
|
||||
|
||||
//Make some logs
|
||||
console.addLogger('log');
|
||||
console.addLogger('debug', 'inverse');
|
||||
console.addLogger('fun', 'rainbow');
|
||||
|
||||
console.time().fun('hello world');
|
||||
console.tag('This is a test').debug('A test');
|
||||
console.tag('An object').log({
|
||||
a: 'b',
|
||||
c : [1, 2, 3]
|
||||
});
|
||||
|
||||
app.listen(8080, function () {
|
||||
console.time().log('Server listening at port 8080');
|
||||
});
|
460
index.js
|
@ -1,460 +0,0 @@
|
|||
// Scribe.js (NodeJS)
|
||||
// Mathew Kurian
|
||||
|
||||
// Module dependences
|
||||
// ---------------------------------
|
||||
|
||||
var util = require('util');
|
||||
var mkdirp = require('mkdirp');
|
||||
var path = require('path');
|
||||
var moment = require('moment');
|
||||
var fs = require('fs');
|
||||
var stack = require('callsite');
|
||||
var colors = require('colors');
|
||||
|
||||
var self = module.exports;
|
||||
self.express = {};
|
||||
|
||||
// Configuration
|
||||
// ---------------------------------
|
||||
|
||||
var $ = {
|
||||
app: "scribe.js",
|
||||
logPath: "./../logs",
|
||||
mainUser: "root",
|
||||
maxTagLength: 50,
|
||||
indentation: 2,
|
||||
divider: ':::',
|
||||
defaultUserDir: '_user',
|
||||
testOutput: function(result, pipes, actual, expected, opts) {
|
||||
|
||||
var pipe = result ? 'log' : 'error';
|
||||
var ne = expected.indexOf("\n") > -1;
|
||||
var na = actual.indexOf("\n") > -1;
|
||||
|
||||
pipes[pipe]((" " + opts + " ").bold.inverse + (result ? " PASSED ".green : " FAILED ".red).bold.inverse);
|
||||
pipes[pipe](" EXPECTED " [result ? "green" : "red"].bold.inverse + " " + (!ne ? expected : ""));
|
||||
if (ne) {
|
||||
pipes[pipe](expected);
|
||||
}
|
||||
pipes[pipe](" ACTUAL " [result ? "green" : "red"].bold.inverse + " " + (!na ? actual : ""));
|
||||
if (na) {
|
||||
pipes[pipe](actual);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Active settings
|
||||
// ---------------------------------
|
||||
|
||||
var activeDefaultTag;
|
||||
var activeUserDir;
|
||||
var activeDateDir;
|
||||
var activeDayIso;
|
||||
var activeDir;
|
||||
|
||||
var loggers = {};
|
||||
var theme = {};
|
||||
var fsOptions = {
|
||||
encoding: 'utf8'
|
||||
};
|
||||
var __reserved = ["f", "t", "tag", "file", "should", "be", "test", "assert"];
|
||||
|
||||
// Cache pipe out
|
||||
// ---------------------------------
|
||||
|
||||
var __stdpipe = (function() {
|
||||
return console.log;
|
||||
})();
|
||||
|
||||
// Utility functions
|
||||
// ---------------------------------
|
||||
|
||||
var pretty = function(a) {
|
||||
if (!a) {
|
||||
return a + "";
|
||||
}
|
||||
if (typeof a === 'object') {
|
||||
return JSON.stringify(a, null, 4);
|
||||
}
|
||||
return a.toString();
|
||||
};
|
||||
|
||||
var compress = function(a) {
|
||||
if (!a) {
|
||||
return a + "";
|
||||
}
|
||||
if (typeof a === 'object') {
|
||||
return JSON.stringify(a);
|
||||
}
|
||||
return a.toString();
|
||||
};
|
||||
|
||||
var tag = function(a) {
|
||||
return "[" + a + "]";
|
||||
};
|
||||
|
||||
var createDir = function() {
|
||||
mkdirp.sync(path.normalize($.logPath), 0777 & (~process.umask()));
|
||||
mkdirp.sync(path.normalize(path.join($.logPath, activeDateDir)), 0777 & (~process.umask()));
|
||||
mkdirp.sync(activeDir = path.normalize(path.join($.logPath, activeDateDir, activeUserDir)), 0777 & (~process.umask()));
|
||||
};
|
||||
|
||||
var getUser = function() {
|
||||
try {
|
||||
activeUserDir = process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'].toLowerCase();
|
||||
activeUserDir = activeUserDir.slice(activeUserDir.lastIndexOf((process.platform === 'win32') ? '\\' : '/') + 1);
|
||||
} catch (e) {
|
||||
activeUserDir = $.defaultUserDir;
|
||||
} finally {
|
||||
return activeUserDir;
|
||||
}
|
||||
};
|
||||
|
||||
var validate = function() {
|
||||
var _activeDayIso = moment().day();
|
||||
if (activeDayIso !== _activeDayIso) {
|
||||
activeDayIso = _activeDayIso;
|
||||
activeDateDir = moment().format('MMM_D_YY').toLowerCase();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
function Extender(tag, opts, mode) {
|
||||
|
||||
var self = this;
|
||||
|
||||
self.tag = tag;
|
||||
self.opts = opts;
|
||||
self.mode = mode;
|
||||
|
||||
self.do = self.invoke = self.should = function(actual) {
|
||||
|
||||
var _actual = compress(actual);
|
||||
|
||||
self.expect = self.be = function(expected) {
|
||||
|
||||
var _expected = compress(expected);
|
||||
|
||||
$.testOutput(_actual === _expected, self, pretty(actual), pretty(expected), self.opts);
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
var spaces = function(sp) {
|
||||
var s = '';
|
||||
for (var z = 0; z < sp; z++) {
|
||||
s += ' ';
|
||||
}
|
||||
return s;
|
||||
};
|
||||
|
||||
var stackTag = function(_stack) {
|
||||
try {
|
||||
return tag(path.basename(_stack.getFileName()) + ":" + _stack.getLineNumber());
|
||||
} catch (e) {
|
||||
return tag(activeDefaultTag);
|
||||
}
|
||||
};
|
||||
|
||||
// Exports
|
||||
// ---------------------------------
|
||||
|
||||
self.addLogger = function(name, file, console, color) {
|
||||
if (arguments.length < 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (__reserved.indexOf(name) > -1) {
|
||||
throw Error("Reserved pipe - " + name);
|
||||
}
|
||||
|
||||
theme[name] = color;
|
||||
loggers[name] = {
|
||||
"file": file,
|
||||
"console": console
|
||||
};
|
||||
|
||||
colors.setTheme(theme);
|
||||
|
||||
addPipe(name);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
exports.removeLogger = function(name) {
|
||||
if (loggers[name]) {
|
||||
delete loggers[name];
|
||||
delete console[name];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
self.set = function(a, b) {
|
||||
$[a] = b;
|
||||
};
|
||||
|
||||
self.configure = function(callback) {
|
||||
|
||||
var _logPath = $.logPath;
|
||||
var _activeUserDir = activeUserDir;
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
activeDefaultTag = tag($.app.toLowerCase());
|
||||
activeUserDir = getUser();
|
||||
|
||||
if ($.logPath !== _logPath) {
|
||||
if (_logPath) {
|
||||
fs.unlink(_logPath, function() {});
|
||||
}
|
||||
} else if (_activeUserDir !== activeUserDir) {
|
||||
if (_activeUserDir) {
|
||||
fs.unlink(_activeUserDir, function() {});
|
||||
}
|
||||
}
|
||||
|
||||
validate();
|
||||
createDir();
|
||||
};
|
||||
|
||||
self.express.logger = function(validate) {
|
||||
|
||||
return function(req, res, next) {
|
||||
|
||||
if (!validate || validate(req, res)) {
|
||||
console.info('[%s]%s %s %s %s', "express.js", req.ip.red, req.method.green, req.url.grey, (/mobile/i.test(req.headers['user-agent']) ? 'MOBILE' : 'DESKTOP').yellow);
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
self.express.webpipe = function() {
|
||||
|
||||
self.addLogger('user', true, true, 'magenta');
|
||||
|
||||
return function(req, res) {
|
||||
console.t('scribe.js').user(req.ip.red + " " + req.body.data);
|
||||
res.send('received');
|
||||
};
|
||||
};
|
||||
|
||||
// Web Control Panel
|
||||
// ---------------------------------
|
||||
|
||||
var datetemplate = fs.readFileSync(path.join(__dirname, "/log.html"), {
|
||||
encoding: "utf8"
|
||||
});
|
||||
var flatColors = ["#16a085", "#27ae60", "#2980b9", "#8e44ad", "#f39c12", "#d35400", "#c0392b", "#7f8c8d"];
|
||||
|
||||
self.express.controlPanel = function() {
|
||||
|
||||
return function(req, res) {
|
||||
var date = req.param('date');
|
||||
|
||||
if (!date) {
|
||||
|
||||
var datePath = path.normalize(path.join($.logPath));
|
||||
|
||||
fs.readdir(datePath, function(err, files) {
|
||||
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return res.send(err);
|
||||
}
|
||||
|
||||
var loggerDates = "";
|
||||
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
try {
|
||||
var file = files[i];
|
||||
var fileSplit = file.split("_");
|
||||
loggerDates += '<div style="background:' +
|
||||
flatColors[Math.floor(Math.random() * flatColors.length)] + '"data-types="' +
|
||||
fs.readdirSync(path.join(datePath, file, $.mainUser)).join(',').replace(/app./g, '') + '", data-raw="' +
|
||||
file + '" class="date"><div class="date-month">' + fileSplit[0] + '</div><div class="date-day">' +
|
||||
fileSplit[1] + '</div><div class="date-year">' + ("20" + fileSplit[2]) + '</div></div>';
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return res.send(datetemplate.replace("__title", $.app + " - Scribe.js Control Panel")
|
||||
.replace('__content', files.join(","))
|
||||
.replace('__logdates', loggerDates)
|
||||
.replace('__logpath', activeDir)
|
||||
.replace('__username', $.mainUser)
|
||||
.replace('__divider', $.divider));
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var type = req.param('type');
|
||||
type = type ? type : "log";
|
||||
|
||||
var filepath = path.join(activeDir, "app." + type);
|
||||
|
||||
if (fs.existsSync(filepath)) {
|
||||
var stream = fs.createReadStream(filepath);
|
||||
|
||||
res.writeHead(200, {
|
||||
'Content-Length': fs.statSync(filepath).size,
|
||||
'Content-Type': 'text/plain',
|
||||
});
|
||||
|
||||
stream.pipe(res);
|
||||
} else {
|
||||
res.statusCode = 404;
|
||||
res.send();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Additional Features
|
||||
// ---------------------------------
|
||||
|
||||
console.t = function(n, _) {
|
||||
n = _ ? _ + ":" + n : n;
|
||||
var _tag = n;
|
||||
var ext = new Extender(n ? tag(n) : activeDefaultTag);
|
||||
ext.t = function() {
|
||||
return console.t.call(console, arguments[0], _tag);
|
||||
};
|
||||
|
||||
ext.t = function() {
|
||||
return console.t.call(console, arguments[0], _tag);
|
||||
};
|
||||
|
||||
return ext;
|
||||
};
|
||||
|
||||
console.f = function(n, _) {
|
||||
|
||||
if (!n) {
|
||||
var st = stack()[1];
|
||||
n = path.basename(st.getFileName());
|
||||
} else {
|
||||
n = path.basename(n);
|
||||
}
|
||||
|
||||
(n = _ ? _ + ":" + n : n);
|
||||
|
||||
var _tag = n;
|
||||
var ext = new Extender(n ? n : activeDefaultTag, undefined, "f");
|
||||
|
||||
ext.f = function() {
|
||||
return console.f.call(console, arguments[0], _tag);
|
||||
};
|
||||
|
||||
ext.t = function() {
|
||||
return console.t.call(console, arguments[0], _tag);
|
||||
};
|
||||
|
||||
return ext;
|
||||
};
|
||||
|
||||
Extender.prototype.test =
|
||||
Extender.prototype.asset =
|
||||
console.assert =
|
||||
console.test = function(name, tag) {
|
||||
tag = tag ? tag : stackTag(stack()[1]);
|
||||
return new Extender(tag, name, stack()[1]);
|
||||
};
|
||||
|
||||
function addPipe(n) {
|
||||
|
||||
Extender.prototype[n] = function() {
|
||||
var args = Array.prototype.splice.call(arguments, 0);
|
||||
if (this.mode === "f") {
|
||||
var st = stack()[1];
|
||||
args.unshift(tag(this.tag + ":" + st.getLineNumber()) + args.shift());
|
||||
} else {
|
||||
args.unshift(this.tag + args.shift());
|
||||
}
|
||||
console[n].apply(this, args);
|
||||
};
|
||||
|
||||
console[n] = (function(i) {
|
||||
|
||||
if (validate()) {
|
||||
createDir();
|
||||
}
|
||||
|
||||
return function() {
|
||||
|
||||
var utfs = (arguments.length === 1 ? pretty(arguments[0]) : util.format.apply(util, arguments)).trim();
|
||||
var time = moment().format('h:mm:ss A');
|
||||
var file = path.join(activeDir, 'app.' + i);
|
||||
var indent = spaces($.indentation);
|
||||
var tag = utfs.match(/^\[(.*?)\]\s{0,}/m);
|
||||
var cleanTag;
|
||||
|
||||
if (loggers[i].file && utfs) {
|
||||
|
||||
var outfs = utfs.stripColors;
|
||||
cleanTag = "";
|
||||
|
||||
if (tag) {
|
||||
outfs = outfs.replace(tag[0], "");
|
||||
cleanTag = tag[0].trim();
|
||||
}
|
||||
|
||||
outfs = time + $.divider + cleanTag + outfs.replace(/\n/g, '\n' + time + $.divider + cleanTag) + '\n';
|
||||
|
||||
fs.appendFileSync(file, outfs, fsOptions, function() {});
|
||||
}
|
||||
|
||||
if (loggers[i].console) {
|
||||
|
||||
if (!tag) {
|
||||
tag = [stackTag(stack()[1])];
|
||||
}
|
||||
|
||||
var tabIn;
|
||||
cleanTag = tag[0].trim();
|
||||
|
||||
if (cleanTag.length <= $.maxTagLength) {
|
||||
utfs = utfs.replace(tag[0], "");
|
||||
tabIn = spaces($.maxTagLength - cleanTag.length);
|
||||
cleanTag = cleanTag[i].bold;
|
||||
utfs = indent + cleanTag + tabIn + utfs.replace(/\n/g, '\n' + indent + cleanTag + tabIn);
|
||||
} else {
|
||||
tabIn = indent + spaces($.maxTagLength);
|
||||
utfs = tabIn + utfs.replace(/\n/g, '\n' + tabIn);
|
||||
}
|
||||
|
||||
__stdpipe(utfs);
|
||||
}
|
||||
};
|
||||
|
||||
})(n);
|
||||
|
||||
// console.t()[n]('Created pipe console.%s', n.toUpperCase());
|
||||
}
|
||||
|
||||
// Startup
|
||||
$.mainUser = activeUserDir = getUser();
|
||||
self.configure();
|
||||
|
||||
// Express missing notification
|
||||
try {
|
||||
var express = require("express");
|
||||
if (!express) {
|
||||
throw new Error();
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("SCRIBE WARNING: Express not installed - visual web logger is disabled.");
|
||||
}
|
610
lib/console2.js
Normal file
|
@ -0,0 +1,610 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
var stack = require('callsite'),
|
||||
util = require('util'),
|
||||
EventEmitter = require('events').EventEmitter,
|
||||
path = require('path'),
|
||||
colorsjs = require('colors/safe');
|
||||
|
||||
/**
|
||||
* consoleOriginal
|
||||
*
|
||||
* NodeJS console object
|
||||
* @type {Object}
|
||||
*/
|
||||
var consoleOriginal = console;
|
||||
|
||||
/**
|
||||
* getLocation
|
||||
*
|
||||
* Get location of log.
|
||||
* ie. filename and line number
|
||||
*
|
||||
* @return {Obsject}
|
||||
* @return {String} filename
|
||||
* @return {Number} line
|
||||
*/
|
||||
var getLocation = function () {
|
||||
|
||||
var st = stack()[2],
|
||||
result = {};
|
||||
|
||||
result.filename = path.basename(st.getFileName());
|
||||
result.line = st.getLineNumber();
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* buildTime
|
||||
*
|
||||
* @param {timestamp} timestamp
|
||||
*
|
||||
* @return {Object}
|
||||
* @return {String} msg ISO time
|
||||
* @return {int} msgLength
|
||||
*/
|
||||
var buildTime = function (timestamp) {
|
||||
var time = (new Date(timestamp)).toISOString();
|
||||
return {
|
||||
msg : time,
|
||||
msgLength : time.length
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* buildDate
|
||||
*
|
||||
* @param {timestamp} timestamp
|
||||
*
|
||||
* @return {Object}
|
||||
* @return {String} msg Date to string
|
||||
* @return {int} msgLength
|
||||
*/
|
||||
var buildDate = function (timestamp) {
|
||||
var date = (new Date(timestamp)).toDateString();
|
||||
return {
|
||||
msg : date,
|
||||
msgLength : date.length
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* buildTags
|
||||
*
|
||||
* @param {Array} tags Tags are string or object {msg :'', colors : []}
|
||||
*
|
||||
* @return {Object}
|
||||
* @return {String} msg Tags string with colors if given. Ex : "[tag1][tag2]"
|
||||
* @return {int} msgLength Tags string length (without colors elements)
|
||||
*/
|
||||
var buildTags = function (tags) {
|
||||
|
||||
var result = "",
|
||||
length = 0;
|
||||
|
||||
tags.forEach(function (tag) {
|
||||
if (tag !== null && typeof tag === 'object') {
|
||||
result += applyColors('[' + tag.msg + ']', tag.colors);
|
||||
length += ("" + tag.msg).length + 2;
|
||||
} else {
|
||||
result += '[' + tag + ']';
|
||||
length += ("" + tag).length + 2;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
msg : result,
|
||||
msgLength : length
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* buildFileInfos
|
||||
*
|
||||
* @param {Object} infos
|
||||
* @param {String} infos.filename
|
||||
* @param {String} infos.line
|
||||
*
|
||||
* @param {String|Array} fileColors Optional colors.
|
||||
* @param {String|Array} lineColors Optional colors.
|
||||
*
|
||||
* @return {Object}
|
||||
* @return {String} msg File infos with colors if given
|
||||
* @return {int} msgLength
|
||||
*/
|
||||
var buildFileInfos = function (infos, fileColors, lineColors) {
|
||||
var result = '[' +
|
||||
applyColors(infos.filename, fileColors) +
|
||||
':' +
|
||||
applyColors(infos.line, lineColors) +
|
||||
']';
|
||||
var length = ('[' + infos.filename + ':' + infos.line + ']').length;
|
||||
|
||||
return {
|
||||
msg : result,
|
||||
msgLength : length
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* areAllStringOrNumber
|
||||
*
|
||||
* Check in an array contains only string and number
|
||||
*
|
||||
* @param {Array} arr
|
||||
* @retrun {Boolean}
|
||||
*/
|
||||
var areAllStringOrNumber = function (arr) {
|
||||
var result = true;
|
||||
arr.forEach(function (elem) {
|
||||
if (!(typeof elem === 'string' || typeof elem === 'number')) {
|
||||
result = false;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* applyColors
|
||||
*
|
||||
* Apply style with colors.js on the console output
|
||||
* @param {String} msg The msg to stylize
|
||||
* @param {Array|String} colors The colors
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
var applyColors = function (msg, colors) {
|
||||
|
||||
if (!colors) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (typeof colors === 'string') {
|
||||
colors = [colors];
|
||||
}
|
||||
|
||||
colors.forEach(function (color) {
|
||||
if (typeof colorsjs[color] === 'function') {
|
||||
msg = colorsjs[color](msg);
|
||||
}
|
||||
});
|
||||
|
||||
return msg;
|
||||
};
|
||||
|
||||
/*
|
||||
* Console2
|
||||
*
|
||||
* @constructor
|
||||
*
|
||||
* @param {Object} opt Optional default options for all loggers.
|
||||
* @param {Boolean} opt.logInConsole Should all loggers print to console by default ? Default true.
|
||||
*
|
||||
* @param {int} opt.contextMediumSize Medium size of the context part of a log message.
|
||||
* Used when calculating indent. Default to 45.
|
||||
* @param {int} opt.spaceSize Space between context part and log part. Default to 4.
|
||||
*
|
||||
* @param {Array|String} opt.colors Default colors output for all loggers. Default ['cyan'].
|
||||
* @param {Array|String} opt.tagsColors Default colors output for tags. Default undefined.
|
||||
* @param {Array|String} opt.timeColors Default colors output for time. Default undefined.
|
||||
* @param {Array|String} opt.dateColors Default colors output for date. Default undefined.
|
||||
* @param {Array|String} opt.fileColors Default colors output for filename. Default undefined.
|
||||
* @param {Array|String} opt.lineColors Default colors output for line number. Default undefined.
|
||||
*
|
||||
* @param {Boolean} opt.alwaysTags Always print tags (even without tag() ). Default false.
|
||||
* @param {Boolean} opt.alwaysLocation Always print location (even without file() ). Default false.
|
||||
* @param {Boolean} opt.alwaysTime Always print time (even without time() ). Default false.
|
||||
* @param {Boolean} opt.alwaysDate Always print date (even without date() ). Default false.
|
||||
*/
|
||||
var Console2 = function (opt) {
|
||||
|
||||
if (!opt) {
|
||||
opt = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* opt
|
||||
*
|
||||
* Constructor opt.
|
||||
* Setting default.
|
||||
*/
|
||||
this.opt = {
|
||||
logInConsole : opt.logInConsole !== false,
|
||||
|
||||
contextMediumSize : opt.contextMediumSize || 45,
|
||||
spaceSize : opt.spaceSize || 4,
|
||||
|
||||
colors : opt.colors || "cyan",
|
||||
tagsColors : opt.tagsColors,
|
||||
timeColors : opt.timeColors,
|
||||
dateColors : opt.dateColors,
|
||||
lineColors : opt.lineColors,
|
||||
fileColors : opt.fileColors,
|
||||
|
||||
alwaysTags : opt.alwaysTags === true,
|
||||
alwaysLocation : opt.alwaysLocation === true,
|
||||
alwaysTime : opt.alwaysTime === true,
|
||||
alwaysDate : opt.alwaysDate === true
|
||||
};
|
||||
|
||||
/**
|
||||
* _tags
|
||||
*
|
||||
* Store all tags for current log
|
||||
*
|
||||
* @type {Array}
|
||||
*/
|
||||
this._tags = [];
|
||||
|
||||
/**
|
||||
*._time
|
||||
*
|
||||
* Log time (full date) ?
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this._time = false;
|
||||
|
||||
/**
|
||||
* _date
|
||||
*
|
||||
* Log date ?
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this._date = false;
|
||||
|
||||
/**
|
||||
* _location
|
||||
*
|
||||
* Should we log filename and line number ?
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this._location = false;
|
||||
|
||||
/**
|
||||
* _reset
|
||||
*
|
||||
* Reset properties after log
|
||||
*/
|
||||
this._reset = function () {
|
||||
this._tags = [];
|
||||
this._time = false;
|
||||
this._date = false;
|
||||
this._location = false;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* loggers
|
||||
*
|
||||
* Stores loggers infos
|
||||
* @type {Object}
|
||||
*/
|
||||
this.loggers = {};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
//inherits form EventEmitter.prototype
|
||||
util.inherits(Console2, EventEmitter);
|
||||
|
||||
|
||||
/**
|
||||
* Console2.prototype.time
|
||||
*
|
||||
* Log the time
|
||||
*/
|
||||
Console2.prototype.time = function () {
|
||||
this._time = true;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Console2.prototype.date
|
||||
*
|
||||
* Log the date
|
||||
*/
|
||||
Console2.prototype.date = function () {
|
||||
this._date = true;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Console2.prototype.tag
|
||||
*
|
||||
* Add tags
|
||||
* @param {String|Object} tag
|
||||
* @param {String} tag.msg The tag
|
||||
* @paral {String|Array} tag.colors colors.js colors
|
||||
*/
|
||||
Console2.prototype.tag = Console2.prototype.t = function () {
|
||||
var tags = Array.prototype.slice.call(arguments, 0);
|
||||
this._tags = this._tags.concat(tags);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Console2.prototype.file
|
||||
*
|
||||
* Log the file name + line
|
||||
*/
|
||||
Console2.prototype.file = Console2.prototype.f = function () {
|
||||
this._location = true;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Console2.prototype.buildArgs
|
||||
*
|
||||
* Build the args string
|
||||
* ie. the string composed with the arguments send to the logger
|
||||
*
|
||||
* @param {Object} log
|
||||
* @return {String} the string
|
||||
*/
|
||||
Console2.prototype.buildArgs = function (log) {
|
||||
|
||||
var args = Array.prototype.slice.call(log.args, 0), //transform args in an array
|
||||
msg = ""; //the log message
|
||||
|
||||
//if all args are string or number, format args as usual
|
||||
if (areAllStringOrNumber(args)) {
|
||||
msg = util.format.apply(this, args);
|
||||
|
||||
//if objects or array present
|
||||
} else {
|
||||
|
||||
var delimiter = '\n',
|
||||
multiLines = false; //if the log need multiples lines (ie. object, array)
|
||||
|
||||
//Process arg one by one
|
||||
args.forEach(function (arg) {
|
||||
|
||||
//if arg is an object / array
|
||||
//use multiples lines
|
||||
if (arg !== null && typeof arg === 'object') {
|
||||
|
||||
msg += delimiter;
|
||||
|
||||
msg += JSON.stringify(arg, null, 2);
|
||||
|
||||
multiLines = true;
|
||||
|
||||
//for "normal" args
|
||||
} else {
|
||||
if (multiLines) {
|
||||
msg += delimiter;
|
||||
}
|
||||
msg += arg + "";
|
||||
}
|
||||
});
|
||||
|
||||
if (multiLines) {
|
||||
msg += '\n';
|
||||
msg = msg.replace(/\n/gm, '\n' + new Array(this.opt.spaceSize).join(' '));
|
||||
}
|
||||
}
|
||||
|
||||
return msg;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Console2.prototype.buildContext
|
||||
*
|
||||
* Build the context string
|
||||
* ie. the string composed with arguments passed to Console2 context functions
|
||||
*
|
||||
* @param {Object} log The log object
|
||||
*
|
||||
* @param {Object} opt Optional options telling what to include in the message
|
||||
* @param {Boolean} opt.tags Print Tags ? Default false.
|
||||
* @param {Boolean} opt.location Print location ? Default false.
|
||||
* @param {Boolean} opt.time Print time ? Default false.
|
||||
* @param {Boolean} opt.date Print date ? Default false.
|
||||
*
|
||||
* @return {Object}
|
||||
* @return {String} result
|
||||
* @return {Int} length the "human readable" length of the result
|
||||
*/
|
||||
Console2.prototype.buildContext = function (log, opt) {
|
||||
|
||||
if (!opt) {
|
||||
opt = {};
|
||||
}
|
||||
|
||||
opt.tags = opt.tags === true;
|
||||
opt.location = opt.location === true;
|
||||
opt.time = opt.time === true;
|
||||
opt.date = opt.date === true;
|
||||
|
||||
var result = "", //final output
|
||||
space = " ", //space between context parts
|
||||
length = 0; //length of the context part (human readable string)
|
||||
//ie. without escapted or colors caracters
|
||||
|
||||
if (opt.tags && log.context.tags) {
|
||||
var tags = buildTags(log.context.tags);
|
||||
result += applyColors(tags.msg, log.opt.tagsColors) + space;
|
||||
length += tags.msgLength + space.length;
|
||||
}
|
||||
|
||||
if (opt.location && log.context.location.filename && log.context.location.line) {
|
||||
var infos = buildFileInfos(log.context.location, log.opt.fileColors, log.opt.lineColors);
|
||||
result += infos.msg + space;
|
||||
length += infos.msgLength + space.length;
|
||||
}
|
||||
|
||||
if (opt.time && log.context.time) {
|
||||
var time = buildTime(log.context.time);
|
||||
result += applyColors(time.msg, log.opt.timeColors) + space;
|
||||
length += time.msgLength + space.length;
|
||||
}
|
||||
|
||||
if (opt.date && log.context.time) {
|
||||
var date = buildDate(log.context.time);
|
||||
result += applyColors(date.msg, log.opt.dateColors) + space;
|
||||
length += date.msgLength + space.length;
|
||||
}
|
||||
|
||||
return {
|
||||
result : result,
|
||||
length : length
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Console2.prototype.addLogger
|
||||
*
|
||||
* Create a new logger
|
||||
* You can then use it with console.myNewLogger
|
||||
*
|
||||
* @param {String} name The name of the logger.
|
||||
* @param {Array|String} colors Optional colorsjs colors of the console output.
|
||||
* Override constructor default.
|
||||
* See text colors from https://github.com/Marak/colors.js
|
||||
*
|
||||
* @param {Object} opt Optional options object. @see Console2 opt for default values.
|
||||
*
|
||||
* @param {Array|String} opt.tagsColors Default colors output for tags. Default undefined.
|
||||
* @param {Array|String} opt.timeColors Default colors output for time. Default undefined.
|
||||
* @param {Array|String} opt.dateColors Default colors output for date. Default undefined.
|
||||
* @param {Array|String} opt.fileColors Default colors output for filename. Default undefined.
|
||||
* @param {Array|String} opt.lineColors Default colors output for line number. Default undefined.
|
||||
*
|
||||
* @param {Boolean} opt.logInConsole Should the logger print to the console ?
|
||||
* @param {Boolean} opt.alwaysTags Always print tags (even without tag() )
|
||||
* @param {Boolean} opt.alwaysLocation Always print location (even without file() )
|
||||
* @param {Boolean} opt.alwaysTime Always print time (even without time() )
|
||||
* @param {Boolean} opt.alwaysDate Always print date (even without date() )
|
||||
*/
|
||||
Console2.prototype.addLogger = function (name, colors, opt) {
|
||||
|
||||
if (!opt) {
|
||||
opt = {};
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
throw new Error("No name given at addLogger");
|
||||
}
|
||||
|
||||
opt.name = name;
|
||||
opt.type = opt.type || opt.name;
|
||||
|
||||
opt.colors = colors || this.opt.colors;
|
||||
opt.tagsColors = opt.tagsColors || this.opt.tagsColors;
|
||||
opt.timeColors = opt.timeColors || this.opt.timeColors;
|
||||
opt.dateColors = opt.dateColors || this.opt.dateColors;
|
||||
opt.fileColors = opt.fileColors || this.opt.fileColors;
|
||||
opt.lineColors = opt.lineColors || this.opt.lineColors;
|
||||
|
||||
opt.logInConsole = opt.logInConsole || this.opt.logInConsole;
|
||||
opt.alwaysTags = opt.alwaysTags || this.opt.alwaysTags;
|
||||
opt.alwaysLocation = opt.alwaysLocation || this.opt.alwaysLocation;
|
||||
opt.alwaysTime = opt.alwaysTime || this.opt.alwaysTime;
|
||||
opt.alwaysDate = opt.alwaysDate || this.opt.alwaysDate;
|
||||
|
||||
this[name] = function () {
|
||||
|
||||
var location = getLocation();
|
||||
var time = Date.now();
|
||||
|
||||
//Let's build the log object
|
||||
|
||||
var log = {
|
||||
type : opt.type || name,
|
||||
show : {
|
||||
tags : this._tags.length > 0 || this.opt.alwaysTags,
|
||||
location : this._location || this.opt.alwaysLocation,
|
||||
time : this._time || this.opt.alwaysTime,
|
||||
date : this._date || this.opt.alwaysDate
|
||||
},
|
||||
context : {
|
||||
tags : this._tags,
|
||||
file : this._location,
|
||||
time : time,
|
||||
location : location
|
||||
},
|
||||
args : arguments,
|
||||
opt : opt
|
||||
};
|
||||
|
||||
//It's time to build the result string
|
||||
|
||||
var offsetSpace = "";
|
||||
|
||||
//Build the context string
|
||||
var context = this.buildContext(log, log.show);
|
||||
|
||||
log.contextString = context.result;
|
||||
|
||||
//Build the args string
|
||||
log.argsString = this.buildArgs(log);
|
||||
|
||||
//Generate the according number of space between context and args strings
|
||||
if (context.length > 0) { //if there is context string
|
||||
//add space according to the contextMediumSize
|
||||
var offset = this.opt.contextMediumSize - context.length;
|
||||
|
||||
if (offset < 0) { //context string could be longer than medium size
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
offsetSpace = new Array(offset + this.opt.spaceSize).join(' ');
|
||||
}
|
||||
|
||||
//Finally, the message
|
||||
log.message = log.contextString + offsetSpace + log.argsString;
|
||||
|
||||
//Emit events
|
||||
this.emit('new', log, log.type); //'new' event
|
||||
|
||||
var msg = log.type;
|
||||
|
||||
/*
|
||||
* EventEmitter.emit() will raise an Error
|
||||
* if we emit the event 'error' and there is no listeners
|
||||
* For now, transform 'error' in 'errorEvent'
|
||||
*/
|
||||
if (msg === 'error') {
|
||||
msg += 'Event';
|
||||
}
|
||||
this.emit(msg, log); //`log.type` event
|
||||
|
||||
//If the logger should print the message
|
||||
//Print it
|
||||
if (opt.logInConsole) {
|
||||
global.console.log(applyColors(log.message, opt.colors));
|
||||
}
|
||||
|
||||
this._reset();
|
||||
};
|
||||
|
||||
this.loggers[name] = opt;
|
||||
|
||||
this.emit('newLogger', name, opt);
|
||||
|
||||
};
|
||||
|
||||
//Keep the old console
|
||||
//use also `global.console`
|
||||
Console2.prototype.Original = consoleOriginal;
|
||||
|
||||
module.exports = Console2;
|
||||
|
||||
}());
|
56
lib/expressLogger.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* jshint -W098 */
|
||||
(function () {
|
||||
|
||||
var colorsjs = require('colors/safe'),
|
||||
Console2 = require('./console2');
|
||||
|
||||
/**
|
||||
* logger
|
||||
*
|
||||
* @param {Console2|undefined} console
|
||||
* @param {Function|undefined} validate
|
||||
*/
|
||||
var logger = function (console, validate) {
|
||||
|
||||
if (!(console instanceof Console2)) {
|
||||
|
||||
if (!(process.console instanceof Console2)) {
|
||||
throw new Error("No process.console");
|
||||
} else {
|
||||
console = process.console;
|
||||
}
|
||||
}
|
||||
|
||||
if (console.info === undefined) {
|
||||
throw new Error("No 'info' logger attach to console");
|
||||
}
|
||||
|
||||
return function (req, res, next) {
|
||||
|
||||
if (!validate || validate(req, res)) {
|
||||
|
||||
console
|
||||
.time()
|
||||
.tag(
|
||||
{msg : 'Express', colors : 'cyan'},
|
||||
{msg : req.ip, colors : 'red'},
|
||||
{msg : req.method, colors : 'green'},
|
||||
{
|
||||
msg : (/mobile/i.test(req.headers['user-agent']) ? 'MOBILE' : 'DESKTOP'),
|
||||
colors : 'grey'
|
||||
}
|
||||
)
|
||||
.info(req.url);
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
||||
logger : logger
|
||||
|
||||
};
|
||||
}());
|
340
lib/logWriter.js
Normal file
|
@ -0,0 +1,340 @@
|
|||
/* jshint -W098 */
|
||||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
var moment = require('moment'),
|
||||
fs = require('fs'),
|
||||
mkdirp = require('mkdirp'),
|
||||
path = require('path');
|
||||
|
||||
|
||||
/**
|
||||
* rootPaths
|
||||
*
|
||||
* Store all rootPaths
|
||||
* @type {Array}
|
||||
*/
|
||||
var rootPaths = [];
|
||||
|
||||
|
||||
/**
|
||||
* LogWriter
|
||||
*
|
||||
* Save console logs on disk
|
||||
*
|
||||
* @constructor
|
||||
*
|
||||
* @param {String} rootPath root logs folder
|
||||
*/
|
||||
var LogWriter = function (rootPath) {
|
||||
|
||||
this.rootPath = rootPath || 'logs';
|
||||
|
||||
//Check if the folder is already in use
|
||||
if (rootPaths.indexOf(this.rootPath) > -1) {
|
||||
throw new Error('Folder ' + this.rootPath + ' already in use');
|
||||
} else {
|
||||
rootPaths.push(this.rootPath);
|
||||
}
|
||||
|
||||
//Init history
|
||||
this.initHistory();
|
||||
};
|
||||
|
||||
/**
|
||||
* LogWriter.prototype.initHistory
|
||||
*
|
||||
* Attach and init the history property
|
||||
*/
|
||||
LogWriter.prototype.initHistory = function () {
|
||||
|
||||
this.history = {
|
||||
dates : {}
|
||||
};
|
||||
|
||||
var historyPath = path.join(this.rootPath, 'history.json');
|
||||
|
||||
if (!fs.existsSync(historyPath)) { //create file if doesn't exist yet
|
||||
|
||||
this.writeFile(
|
||||
historyPath,
|
||||
this.history,
|
||||
function (err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
} else { //get history if file exists
|
||||
|
||||
var self = this;
|
||||
|
||||
fs.readFile(historyPath, function (err, data) {
|
||||
if (err) {
|
||||
throw err;
|
||||
} else {
|
||||
try {
|
||||
|
||||
self.history = JSON.parse(data);
|
||||
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* LogWriter.prototype.createDir
|
||||
*
|
||||
* Create a dir if it doesn't exist yet
|
||||
*
|
||||
* @param {String} path The dir
|
||||
* @param {Function} callback
|
||||
*/
|
||||
LogWriter.prototype.createDir = function (path, callback) {
|
||||
mkdirp(path, function (err) {
|
||||
callback(err);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* LogWriter.prototype.appendFile
|
||||
*
|
||||
* Append content to a file
|
||||
*
|
||||
* @param {String} pathToFile The file
|
||||
* @param {String} content
|
||||
* @param {Function} callback
|
||||
*/
|
||||
LogWriter.prototype.appendFile = function (pathToFile, content, callback) {
|
||||
|
||||
var self = this;
|
||||
|
||||
self.createDir(path.dirname(pathToFile), function (err) {
|
||||
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
|
||||
var newFile = !fs.existsSync(pathToFile);
|
||||
|
||||
fs.appendFile(pathToFile, content, function (err) {
|
||||
|
||||
if (err) {
|
||||
throw err;
|
||||
} else if (newFile) {
|
||||
self.newFileHistory(pathToFile);
|
||||
callback();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* LogWriter.prototype.writeFile
|
||||
*
|
||||
* Write content into a file (erase old one)
|
||||
*
|
||||
* @param {String} pathToFile The file
|
||||
* @param {String} content
|
||||
* @param {Function} callback
|
||||
*/
|
||||
LogWriter.prototype.writeFile = function (pathToFile, content, callback) {
|
||||
|
||||
if (typeof content !== 'string') {
|
||||
content = JSON.stringify(content);
|
||||
}
|
||||
|
||||
this.createDir(path.dirname(pathToFile), function (err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
fs.writeFile(pathToFile, content, callback);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* LogWriter.prototype.newFileHistory
|
||||
*
|
||||
* Save the new file path in history according to the date
|
||||
*
|
||||
* @param {String} pathToFile
|
||||
*/
|
||||
LogWriter.prototype.newFileHistory = function (pathToFile) {
|
||||
|
||||
var historyPath = path.join(this.rootPath, 'history.json'),
|
||||
self = this;
|
||||
|
||||
var today = moment().startOf('day').valueOf().toString();
|
||||
|
||||
//Save the path under today key
|
||||
|
||||
if (!self.history.dates[today]) {
|
||||
self.history.dates[today] = [];
|
||||
}
|
||||
|
||||
if (self.history.dates[today].indexOf(pathToFile) === -1) {
|
||||
|
||||
self.history.dates[today].push(pathToFile);
|
||||
|
||||
self.writeFile(historyPath, self.history, function (err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* LogWriter.prototype.getUser
|
||||
*
|
||||
* Tool, return active user
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
LogWriter.prototype.getUser = function () {
|
||||
|
||||
var user = '';
|
||||
|
||||
try {
|
||||
|
||||
var platformKey = process.platform === 'win32' ? 'USERPROFILE' : 'HOME',
|
||||
platformDivider = process.platform === 'win32' ? '\\' : '/';
|
||||
|
||||
|
||||
var userDir = process.env[platformKey].toLowerCase();
|
||||
user = userDir.slice(userDir.lastIndexOf(platformDivider) + 1);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
user = 'user'; //default
|
||||
|
||||
} finally {
|
||||
|
||||
return user;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* LogWriter.prototype.getPath
|
||||
*
|
||||
* @param {Object} opt params
|
||||
* @param {String} opt.logger logger options
|
||||
*
|
||||
* @return {String} The path to current folder (without rootPath)
|
||||
*/
|
||||
LogWriter.prototype.getPath = function (opt) {
|
||||
|
||||
var now = moment();
|
||||
|
||||
return path.join(
|
||||
now.format('YYYY'),
|
||||
now.format('MMM')
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* LogWriter.prototype.getFile
|
||||
*
|
||||
* @param {Object} opt params
|
||||
* @param {String} opt.logger logger options
|
||||
*
|
||||
* @return {String} the filname (with extension)
|
||||
*/
|
||||
LogWriter.prototype.getFile = function (opt) {
|
||||
|
||||
var now = moment();
|
||||
|
||||
return (now.format('DD_MMM_YY')).toLowerCase() +
|
||||
'.' +
|
||||
opt.logger.name +
|
||||
'.json';
|
||||
};
|
||||
|
||||
/**
|
||||
* LogWriter.prototype.path
|
||||
*
|
||||
* @param {Object} opt params
|
||||
* @param {String} opt.logger logger options
|
||||
*
|
||||
* @return {String} the full path to file
|
||||
*/
|
||||
LogWriter.prototype.path = function (opt) {
|
||||
return path.join(
|
||||
this.rootPath,
|
||||
this.getPath(opt),
|
||||
this.getFile(opt)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* LogWriter.prototype.save
|
||||
*
|
||||
* Save a log on disk
|
||||
*
|
||||
* @param {Object} log The log to save
|
||||
*
|
||||
* @param {Object} opt Options
|
||||
* @param {String} opt.logger logger options
|
||||
*/
|
||||
LogWriter.prototype.save = function (log, opt) {
|
||||
|
||||
delete log.opt; //we save logger options in rootPath/[logger].json
|
||||
|
||||
var json = JSON.stringify(log);
|
||||
|
||||
this.appendFile(this.path(opt), json + '\n', function (err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* LogWriter.prototype.saveOpt
|
||||
*
|
||||
* Save logger opt in root folder
|
||||
*
|
||||
* @param {Object} logger Logger options.
|
||||
*/
|
||||
LogWriter.prototype.saveOpt = function (logger) {
|
||||
|
||||
var filePath = path.join(this.rootPath, logger.name + '.json');
|
||||
|
||||
this.writeFile(filePath, JSON.stringify(logger), function (err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* LogWriter.prototype.addLogger
|
||||
*
|
||||
* Simply call this.saveOpt() from now
|
||||
* but could be use for more
|
||||
*
|
||||
* @param {Object} logger Console2 logger options
|
||||
*/
|
||||
LogWriter.prototype.addLogger = function (logger) {
|
||||
|
||||
this.saveOpt(logger);
|
||||
};
|
||||
|
||||
|
||||
module.exports = {
|
||||
LogWriter : LogWriter,
|
||||
folders : rootPaths
|
||||
};
|
||||
|
||||
}());
|
249
lib/webPanel.js
Normal file
|
@ -0,0 +1,249 @@
|
|||
/* jshint -W098 */
|
||||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
var express = require('express'),
|
||||
serveStatic = require('serve-static'),
|
||||
path = require('path'),
|
||||
fs = require('fs');
|
||||
|
||||
|
||||
/**
|
||||
* map
|
||||
*
|
||||
* Custom map function
|
||||
* That filter undefined and null values
|
||||
*
|
||||
* @param {Array} arr
|
||||
* @param {Function} callback
|
||||
* @return {Array}
|
||||
*/
|
||||
var map = function (arr, callback) {
|
||||
|
||||
var result = arr.map(callback);
|
||||
return result.filter(function (item) {
|
||||
return item !== undefined && item !== null;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* initWebPanel
|
||||
*
|
||||
* @param {Array} consoles Array of Console2 instances with their logWriter
|
||||
[{
|
||||
console : Console2 instance,
|
||||
logWriter : null | LogWriter instance
|
||||
}]
|
||||
*
|
||||
* @return {Express Router}
|
||||
*/
|
||||
var initWebPanel = function (consoles) {
|
||||
|
||||
var webPanel = express.Router();
|
||||
|
||||
//Static files
|
||||
|
||||
webPanel.use('/', serveStatic('./static'));
|
||||
|
||||
//API
|
||||
|
||||
/**
|
||||
* readDir
|
||||
*
|
||||
* Return dir content
|
||||
*
|
||||
* @param {String} dirPath A path
|
||||
* @param {Function} callback Function to chain with result array
|
||||
*/
|
||||
var readDir = function (dirPath, callback) {
|
||||
|
||||
if (!dirPath || typeof dirPath !== 'string') {
|
||||
callback("dirPath must be a string");
|
||||
} else {
|
||||
fs.readdir(dirPath, function (err, list) {
|
||||
var dir = [];
|
||||
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
} else {
|
||||
list.forEach(function (item) {
|
||||
dir.push(readNode(path.join(dirPath, item)));
|
||||
});
|
||||
|
||||
callback(null, dir);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* readNode
|
||||
*
|
||||
* Return some infos on the file or folder given
|
||||
*
|
||||
* @param {String} itemPath A path
|
||||
* @return {Object}
|
||||
* @return {String} type 'folder' or 'file'
|
||||
* @return {String} name
|
||||
* @return {String} path @see params
|
||||
*/
|
||||
var readNode = function (itemPath) {
|
||||
|
||||
var info = fs.statSync(itemPath),
|
||||
item = {};
|
||||
|
||||
item.type = info.isDirectory() ? 'folder' : 'file';
|
||||
item.name = path.basename(itemPath);
|
||||
item.path = itemPath;
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
/**
|
||||
* getLogFolders
|
||||
*
|
||||
* @return {Array} logs folder in use
|
||||
*/
|
||||
var getLogFolders = function () {
|
||||
return map(consoles, function (elem) {
|
||||
return elem.logWriter.rootPath || undefined;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* getLogWriter
|
||||
*
|
||||
* @param {String} logFolder root folder of the logWriter to find
|
||||
*
|
||||
* @return {LogWriter|false} If false, no logWriter with rootPath set to logFolder
|
||||
*/
|
||||
var getLogWriter = function (logFolder) {
|
||||
var logWriter;
|
||||
|
||||
return consoles.some(function (item) {
|
||||
if (item.logWriter && item.logWriter.rootPath === logFolder) {
|
||||
logWriter = item.logWriter;
|
||||
return true;
|
||||
}
|
||||
}) ? logWriter : false;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* /api
|
||||
*
|
||||
* Send logWriters
|
||||
*/
|
||||
webPanel.get('/api', function (req, res) {
|
||||
|
||||
var path = req.query.path;
|
||||
|
||||
res.status(200).json(getLogFolders());
|
||||
});
|
||||
|
||||
/**
|
||||
* /api/folderExplorer
|
||||
*
|
||||
* Send path content info
|
||||
*/
|
||||
webPanel.get('/api/folderExplorer', function (req, res) {
|
||||
|
||||
var path = req.query.path;
|
||||
|
||||
readDir(path, function (err, dir) {
|
||||
if (err) {
|
||||
res.status(400).end();
|
||||
} else {
|
||||
res.status(200).json(dir);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* /api/dateExplorer
|
||||
*
|
||||
* Send files according to history dates
|
||||
* With pagination
|
||||
*/
|
||||
webPanel.get('/api/dateExplorer', function (req, res) {
|
||||
|
||||
var from = req.query.from || Date.now(),
|
||||
length = req.query.length || 10,
|
||||
logFolder = req.query.logFolder;
|
||||
|
||||
var logWriter = getLogWriter(logFolder);
|
||||
|
||||
if (!logWriter) {
|
||||
res.status(400).send('No logWriter attached to ' + logFolder);
|
||||
} else {
|
||||
|
||||
//Find the good dates
|
||||
|
||||
var nb = 0,
|
||||
result = [],
|
||||
dates = Object.keys(logWriter.history.dates).filter(function (date) {
|
||||
|
||||
if (date < from && nb <= length) {
|
||||
nb++;
|
||||
return date;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
dates.forEach(function (date) {
|
||||
result.push({
|
||||
date : date,
|
||||
files : map(logWriter.history.dates[date], function (item) {
|
||||
return {
|
||||
name : path.basename(item),
|
||||
path : item
|
||||
};
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
res.status(200).json(result);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* /api/log
|
||||
*
|
||||
* Send stream of file content
|
||||
*/
|
||||
webPanel.get('/api/log', function (req, res) {
|
||||
|
||||
var path = req.query.path;
|
||||
|
||||
if (fs.existsSync(path)) {
|
||||
var stream = fs.createReadStream(path);
|
||||
|
||||
res.writeHead(200, {
|
||||
'Content-Length': fs.statSync(path).size,
|
||||
'Content-Type' : 'text/plain'
|
||||
});
|
||||
|
||||
res.status(200);
|
||||
stream.pipe(res);
|
||||
|
||||
} else {
|
||||
res.status(400).send("Can't read path");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return webPanel;
|
||||
|
||||
};
|
||||
|
||||
|
||||
module.exports = initWebPanel;
|
||||
|
||||
|
||||
}());
|
517
log.html
|
@ -1,517 +0,0 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<title>__title</title>
|
||||
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,300,600,700' rel='stylesheet' type='text/css'>
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="http://anthonyterrien.com/js/jquery.knob.js"></script>
|
||||
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.6.0/moment.js"></script>
|
||||
<script type="text/javascript">
|
||||
function Transform3d(a) {
|
||||
this.desc = "";
|
||||
this.obj = a;
|
||||
this.translate = function (b, d, c) {
|
||||
this.desc += " translate3d(" + b + "," + d + "," + c + ")";
|
||||
return this
|
||||
};
|
||||
this.scale = function (b, d, c) {
|
||||
this.desc += " scale3d(" + b + "," + d + "," + c + ")";
|
||||
return this
|
||||
};
|
||||
this.rotate = function (b, d, c) {
|
||||
this.desc += " rotate3d(" + b + "," + d + "," + c + ")";
|
||||
return this
|
||||
};
|
||||
this.apply = function () {
|
||||
var b = this.obj;
|
||||
var c = this.desc;
|
||||
(b = $(b)).css({
|
||||
"-webkit-transform": c,
|
||||
"-ms-transform": c,
|
||||
"-moz-transform": c,
|
||||
transform: c,
|
||||
});
|
||||
return b
|
||||
}
|
||||
}
|
||||
$.fn.transform3d = function () {
|
||||
return new Transform3d(this)
|
||||
};
|
||||
$.fn.center = function () {
|
||||
this.css("position", "absolute");
|
||||
this.css("top", Math.max(0, (($(window).height() - this.outerHeight()) / 2) + $(window).scrollTop()) + "px");
|
||||
this.css("left", Math.max(0, (($(window).width() - this.outerWidth()) / 2) + $(window).scrollLeft()) + "px");
|
||||
return this
|
||||
};
|
||||
$.fn.centerInParent = function () {
|
||||
this.css("position", "absolute");
|
||||
this.css("top", Math.max(0, ((this.parent().height() - this.outerHeight()) / 2) + this.parent().scrollTop()) + "px");
|
||||
this.css("left", Math.max(0, ((this.parent().width() - this.outerWidth()) / 2) + this.parent().scrollLeft()) + "px");
|
||||
return this
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
div,
|
||||
span,
|
||||
applet,
|
||||
object,
|
||||
iframe,
|
||||
p,
|
||||
blockquote,
|
||||
pre,
|
||||
a,
|
||||
abbr,
|
||||
acronym,
|
||||
address,
|
||||
big,
|
||||
cite,
|
||||
code,
|
||||
del,
|
||||
dfn,
|
||||
em,
|
||||
img,
|
||||
ins,
|
||||
kbd,
|
||||
q,
|
||||
s,
|
||||
samp,
|
||||
small,
|
||||
strike,
|
||||
strong,
|
||||
sub,
|
||||
sup,
|
||||
tt,
|
||||
var,
|
||||
u,
|
||||
i,
|
||||
center,
|
||||
dl,
|
||||
dt,
|
||||
dd,
|
||||
ol,
|
||||
ul,
|
||||
li,
|
||||
textarea,
|
||||
fieldset,
|
||||
form,
|
||||
label,
|
||||
legend,
|
||||
table,
|
||||
caption,
|
||||
tbody,
|
||||
tfoot,
|
||||
thead,
|
||||
tr,
|
||||
th,
|
||||
td,
|
||||
article,
|
||||
aside,
|
||||
canvas,
|
||||
details,
|
||||
embed,
|
||||
figure,
|
||||
figcaption,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
menu,
|
||||
nav,
|
||||
output,
|
||||
ruby,
|
||||
section,
|
||||
summary,
|
||||
time,
|
||||
mark,
|
||||
audio,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font: inherit;
|
||||
vertical-align: top;
|
||||
text-indent: 0;
|
||||
font-family: 'Open Sans'
|
||||
}
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
menu,
|
||||
nav,
|
||||
section {
|
||||
display: block
|
||||
}
|
||||
span {
|
||||
vertical-align: baseline
|
||||
}
|
||||
body {
|
||||
display: block
|
||||
}
|
||||
ol,
|
||||
ul {
|
||||
list-style: none
|
||||
}
|
||||
blockquote,
|
||||
q {
|
||||
quotes: none
|
||||
}
|
||||
blockquote:before,
|
||||
blockquote:after,
|
||||
q:before,
|
||||
q:after {
|
||||
content: '';
|
||||
content: none
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: inherit
|
||||
}
|
||||
html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: 'Open Sans'
|
||||
}
|
||||
html,
|
||||
div,
|
||||
span,
|
||||
a {
|
||||
user-select: none;
|
||||
-o-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
font-family: 'Open Sans'
|
||||
}
|
||||
div::selection,
|
||||
html::selection,
|
||||
span::selection,
|
||||
a::selection {
|
||||
background: transparent;
|
||||
font-family: 'Open Sans'
|
||||
}
|
||||
div::-moz-selection,
|
||||
html::-moz-selection,
|
||||
span::-moz-selection,
|
||||
a::-moz-selection {
|
||||
background: transparent;
|
||||
font-family: 'Open Sans'
|
||||
}
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
float: none;
|
||||
display: block;
|
||||
padding: 0;
|
||||
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
|
||||
background: #161d25;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%
|
||||
}
|
||||
div {
|
||||
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
|
||||
font-size: 11px
|
||||
}
|
||||
html {
|
||||
background: #161d25;
|
||||
padding: 0
|
||||
}
|
||||
body {
|
||||
border-left: 1px solid rgba(255, 255, 255, 0.12)
|
||||
}
|
||||
.animator {
|
||||
-webkit-transition: all 500ms ease-out;
|
||||
transition: all 500ms ease-out;
|
||||
-ms-transition: all 500ms ease-out;
|
||||
-moz-transition: all 500ms ease-out;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
-ms-transform: translate3d(0, 0, 0);
|
||||
-moz-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
-webkit-backface-visibility: hidden
|
||||
}
|
||||
.log-time {
|
||||
background: 0;
|
||||
color: rgba(255, 255, 255, 0.24);
|
||||
padding: 2px 5px;
|
||||
margin-right: 2px;
|
||||
margin-left: -1px;
|
||||
font-size: 11px;
|
||||
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif
|
||||
}
|
||||
.log-type {
|
||||
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
|
||||
background: #04c25f;
|
||||
color: #000;
|
||||
padding: 2px 4px;
|
||||
margin-right: 2px;
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
font-size: 9px;
|
||||
letter-spacing: 1px;
|
||||
font-weight: 700;
|
||||
border-radius: 3px
|
||||
}
|
||||
.log-line {
|
||||
height: auto;
|
||||
line-height: 15px;
|
||||
color: #bebebe;
|
||||
font-size: 11px;
|
||||
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif
|
||||
}
|
||||
.button,
|
||||
.selected {
|
||||
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
|
||||
background: #2c3338;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
line-height: 35px;
|
||||
height: 35px;
|
||||
margin-bottom: 5px;
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.11)
|
||||
}
|
||||
.selected {
|
||||
background: #4d5961
|
||||
}
|
||||
a {
|
||||
background: 0;
|
||||
text-decoration: none;
|
||||
font-size: 11px;
|
||||
color: #c2c2c2;
|
||||
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif
|
||||
}
|
||||
.menu {
|
||||
border-radius: 3px;
|
||||
background: url(http://i.imgur.com/LnFUuFm.png) center center no-repeat;
|
||||
background-size: 67%;
|
||||
cursor: pointer;
|
||||
background-color: #2980b9;
|
||||
border: 1px solid rgba(255, 255, 255, 0.05)
|
||||
}
|
||||
.menu-item {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
|
||||
color: #DDD;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-indent: 14px;
|
||||
font-family: "Open Sans";
|
||||
font-size: 9px;
|
||||
cursor: pointer;
|
||||
font-weight: 900
|
||||
}
|
||||
.menu-item-selected {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-bottom-color: transparent
|
||||
}
|
||||
.back {
|
||||
background-image: url(http://i.imgur.com/hkF73Yp.png?1);
|
||||
background-size: 30% auto;
|
||||
background-color:#34495e;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center
|
||||
}
|
||||
.date {
|
||||
height: 200px;
|
||||
line-height: 49px;
|
||||
width: 200px;
|
||||
margin: 10px;
|
||||
background: #393e41;
|
||||
color: rgba(255, 255, 255, 0.39);
|
||||
text-align: center;
|
||||
font-family: "Open Sans";
|
||||
text-transform: uppercase;
|
||||
font-weight: 300;
|
||||
letter-spacing: 1px;
|
||||
font-size: 53px;
|
||||
text-align: left;
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
margin-right: 0
|
||||
}
|
||||
.date-month {
|
||||
font-family: "Open Sans";
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
letter-spacing: 2px;
|
||||
padding-top: 6px;
|
||||
font-size: 21px
|
||||
}
|
||||
.date-year {
|
||||
font-family: "Open Sans";
|
||||
text-align: center;
|
||||
font-weight: 300;
|
||||
letter-spacing: 2px;
|
||||
margin-top: 21px
|
||||
}
|
||||
.date-day {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
font-size: 92px;
|
||||
font-family: "Open Sans";
|
||||
margin-top: 25px;
|
||||
color: #FFF;
|
||||
font-weight: 300
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="position:relative;left:0;top:0;bottom:0">
|
||||
<div class="back" style="position:absolute;left:0;top:50px;bottom:0;width:30px;cursor:pointer;z-index:900">
|
||||
</div>
|
||||
<div style="position:absolute;left:0;top:0;right:0;height:50px;background:#34495e">
|
||||
<div id="menu-container" style="position:absolute;left:0;top:0;right:0;height:50px">
|
||||
<div id="menu" class="menu" style="position:absolute;left:10px;top:9px;height:30px;width:40px"></div>
|
||||
<a id="path" style="position:absolute;left:70px;top:9px;height:30px;width:500px;color:#DDD;line-height:33px;font-weight:bold;color:#FFF;text-transform:uppercase;font-weight:300;letter-spacing:1px;font-size:9px" target="_blank" href="#"></a>
|
||||
</div>
|
||||
<div style="position:absolute;right:0;top:5px;bottom:5px;width:168px;right:5px;background:url(http://i.imgur.com/0Jg6k6g.png) center right no-repeat;background-size:66%"></div>
|
||||
</div>
|
||||
<div id="sidebar" class="shift" style="position:absolute;left:30px;top:50px;right:0;width:250px;background:#000;border-right:1px solid rgba(255,255,255,0.15);bottom:0;z-index:800;box-shadow:50px 0 50px -50px #000">LOGGERS
|
||||
</div>
|
||||
<div class="shift" style="position:absolute;left:30px;top:50px;bottom:0;right:0">
|
||||
<div style="width:100%;height:100%;overflow:auto">
|
||||
<div id="dates" style="width:100%;height:auto">__logdates</div>
|
||||
<div id="content" style="width:100%;height:auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="dial-holder" class="animator shift" style="position:absolute;left:30px;right:0;top:50px;bottom:0;display:none;background:rgba(0,0,0,0.7);z-index:10">
|
||||
<input type="text" value="0" data-width="65" class="dial" id="progress-knob" data-height="65" '+ ' data-fgColor="#0788a5" data-readOnly="1" data-bgColor="#3e4043" />
|
||||
</div>
|
||||
<script>
|
||||
/*<![CDATA[*/
|
||||
var activeDate = undefined;
|
||||
var activeMenuItem = undefined;
|
||||
var activeType = undefined;
|
||||
var logPath = "__logpath";
|
||||
var username = "__username";
|
||||
var divider = "__divider";
|
||||
var activeXhr;
|
||||
var divRegex = divider.replace(/([\||\$|\^|\?|\[|\]|\)|\(|\{|\}])/g, "\\$1");
|
||||
var regA = new RegExp("^(.*)(" + divRegex + ")", "gm");
|
||||
var regB = new RegExp("^(.*)" + divRegex + "\\s{0,}\\[(.*?)\\](.*)$", "gm");
|
||||
var regC = new RegExp("^(.*)" + divRegex, "gm");
|
||||
var processData = function (b) {
|
||||
b = b.replace(/ /g, " ");
|
||||
b = b.replace(regA, '<span class = "log-time">$1</span>$2');
|
||||
b = b.replace(regB, '$1<span class = "log-type">$2</span>$3');
|
||||
b = b.replace(regC, "$1");
|
||||
b = b.replace(/^(.*?)$/mg, '<div class = "log-line">$1</div>');
|
||||
return b
|
||||
};
|
||||
$("#sidebar").on("click", ".menu-item", function () {
|
||||
$(".menu-item").removeClass("menu-item-selected");
|
||||
$(this).addClass("menu-item-selected");
|
||||
var e = activeType = $(this).html();
|
||||
activeMenuItem = e;
|
||||
var b = activeDate;
|
||||
try {
|
||||
activeXhr.abort()
|
||||
} catch (a) {}
|
||||
activeXhr = $.ajax("log?type=" + e + "&date=" + b + "&token=" + location.search.split('token=')[1], {
|
||||
settings: {
|
||||
dataType: "text"
|
||||
},
|
||||
xhrFields: {
|
||||
onprogress: function (c) {
|
||||
$("#progress-knob").val(Math.floor(c.loaded / (c.totalSize | c.total) * 100)).change();
|
||||
}
|
||||
}
|
||||
}).done(function (f, g, d) {
|
||||
if (f.replace) {
|
||||
$("#content").html(processData(f))
|
||||
} else {
|
||||
if (d.responseText) {
|
||||
$("#content").html(processData(d.responseText))
|
||||
}
|
||||
}
|
||||
$("#content").parent().scrollTop(9999999);
|
||||
$("#dial-holder").fadeOut()
|
||||
}).fail(function (c) {
|
||||
$("#content").html(processData(moment().format("h:mm:ss A") + " " + divider + "[StreamError]Detected error retrieving the content to your browser."));
|
||||
$("#dial-holder").fadeOut()
|
||||
});
|
||||
$("#path").html(logPath + "/log/" + activeDate + "/" + username + "/app." + e);
|
||||
$("#path").attr("href", "log?type=" + e + "&date=" + b + "&raw=true");
|
||||
$("#path").attr("target", "_blank");
|
||||
toggleSidebar();
|
||||
$("#progress-knob").val(0).change();
|
||||
$("#dial-holder").fadeIn()
|
||||
});
|
||||
$(".date").click(function () {
|
||||
activeDate = $(this).attr("data-raw");
|
||||
$("#dates").css("display", "none");
|
||||
var b = $(this).attr("data-types").split(",");
|
||||
if (b) {
|
||||
var a = "";
|
||||
for (var c = 0; c < b.length; c++) {
|
||||
a += '<div class = "menu-item" id="menu-' + b[c] + '">' + b[c] + "</div>"
|
||||
}
|
||||
$("#sidebar").html(a);
|
||||
($("#menu-" + activeMenuItem).length > 0 ? $("#menu-" + activeMenuItem) : $("#sidebar").children().eq(0)).trigger("click")
|
||||
}
|
||||
toggleSidebar(false);
|
||||
$(".shift").css("left", "30px");
|
||||
$(".back").css("width", "30px");
|
||||
$("#menu-container").transform3d().translate(0, 0, 0).apply()
|
||||
});
|
||||
$(".back").click(function () {
|
||||
$(".shift").css("left", "0");
|
||||
$(".back").css("width", "0");
|
||||
$("#menu-container").transform3d().translate("-52px", 0, 0).apply();
|
||||
$("#dates").css("display", "block");
|
||||
$("#content").html("");
|
||||
$("#path").html("Select a date to begin");
|
||||
$("#path").attr("href", "#");
|
||||
$("#path").attr("target", "");
|
||||
try {
|
||||
activeXhr.abort()
|
||||
} catch (b) {}
|
||||
toggleSidebar(false);
|
||||
activeDate = undefined
|
||||
});
|
||||
var sidebarVisible = false;
|
||||
|
||||
function toggleSidebar(a) {
|
||||
sidebarVisible = typeof a === "boolean" ? a : !sidebarVisible;
|
||||
if (!sidebarVisible) {
|
||||
$("#sidebar").transform3d().translate("-300px", 0, 0).apply()
|
||||
} else {
|
||||
$("#sidebar").transform3d().translate(0, 0, 0).apply()
|
||||
}
|
||||
}
|
||||
$("#menu").click(function () {
|
||||
toggleSidebar()
|
||||
});
|
||||
$(window).resize(function () {
|
||||
$(".dial").parent().centerInParent()
|
||||
});
|
||||
$(document).ready(function () {
|
||||
$(".dial").knob();
|
||||
$(".dial").parent().centerInParent();
|
||||
$(".shift").css("left", "0").addClass("animator");
|
||||
$(".back").css("width", "0").addClass("animator");
|
||||
$("#menu-container").transform3d().translate("-52px", 0, 0).apply().addClass("animator");
|
||||
$("#sidebar").transform3d().translate("-300px", 0, 0).apply().addClass("animator");
|
||||
$("#path").html("Select a date to begin")
|
||||
}); /*]]>*/
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
24
package.json
239
scribe.js
Normal file
|
@ -0,0 +1,239 @@
|
|||
/*jshint -W020 */
|
||||
|
||||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
var Console2 = require('./lib/console2.js'),
|
||||
LogWriter = require('./lib/logWriter.js').LogWriter,
|
||||
ExpressLogger = require('./lib/expressLogger.js'),
|
||||
webPanel = require('./lib/webPanel.js');
|
||||
|
||||
|
||||
/**
|
||||
* scribe
|
||||
*
|
||||
* Scribe.js module
|
||||
*
|
||||
* @param {Object} scribeOpt Optional options
|
||||
* @param {String} scribe.rootPath Logs folder. Default 'logs'
|
||||
* @param {Boolean} scribeOpt.createDefaultConsole Should scribe attach a fresh Console2
|
||||
* to process.console ? Default true.
|
||||
*
|
||||
* @return {Object}
|
||||
* @return {Function} console Get a console
|
||||
* @return {Function} webPanel Get an express Router
|
||||
* @return {Constructor} Console2 Console2 constructor
|
||||
* @return {Constructor} LogWriter LogWriter constructor
|
||||
* @return {Object} express Express utils
|
||||
*/
|
||||
var scribe = function (scribeOpt) {
|
||||
|
||||
//Scribe options
|
||||
|
||||
if (!scribeOpt) {
|
||||
scribeOpt = {};
|
||||
}
|
||||
|
||||
scribeOpt.rootPath = scribeOpt.rootPath || 'logs';
|
||||
scribeOpt.createDefaultConsole = scribeOpt.createDefaultConsole !== false;
|
||||
|
||||
|
||||
/**
|
||||
* consoles
|
||||
*
|
||||
* Stores consoles and their logWriters
|
||||
*
|
||||
* @type {Array}
|
||||
*/
|
||||
var consoles = [];
|
||||
|
||||
|
||||
/**
|
||||
* listenOnConsole
|
||||
*
|
||||
* Listen on console2 events 'new' and 'newLogger'
|
||||
* Save logs and options.
|
||||
*
|
||||
* @param {Console2} console2 A Console2 instance
|
||||
* @param {LogWriter} logWriter A LogWriter instance
|
||||
*/
|
||||
var listenOnConsole = function (console2, logWriter) {
|
||||
|
||||
//On new log, save it
|
||||
console2.on('new', function (log) {
|
||||
|
||||
logWriter.save(log, {
|
||||
logger : log.opt
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
//On new logger, save its options
|
||||
console2.on('newLogger', function (logger, loggerOpt) {
|
||||
|
||||
logWriter.addLogger(loggerOpt);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* createBasic
|
||||
*
|
||||
* Create basic log function of nodejs for `console`
|
||||
*
|
||||
* @param {Console2} console
|
||||
*/
|
||||
var createBasic = function (console) {
|
||||
|
||||
var loggers = [
|
||||
{
|
||||
name : 'log',
|
||||
color : 'white'
|
||||
},
|
||||
{
|
||||
name : 'info',
|
||||
color : 'cyan'
|
||||
},
|
||||
{
|
||||
name : 'error',
|
||||
color : 'red'
|
||||
},
|
||||
{
|
||||
name : 'warning',
|
||||
color : 'yellow'
|
||||
},
|
||||
{
|
||||
name : 'dir',
|
||||
color : 'white'
|
||||
}
|
||||
];
|
||||
|
||||
loggers.forEach(function (logger) {
|
||||
console.addLogger(logger.name, logger.color);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* addConsole
|
||||
*
|
||||
* Create a new console
|
||||
*
|
||||
* @param {Object} config Config options
|
||||
* @param {?Object} config.console Console2 options
|
||||
* @param {?Object} config.logWriter LogWriter options.
|
||||
* If false, Scribe won't save logs on disk.
|
||||
* @param {Boolean} config.createBasic Should scribe create basic logging functions ?
|
||||
* Default true
|
||||
*
|
||||
* @param {LogWriter} logWriter Optional. A custom logWriter instance
|
||||
*
|
||||
* @return {Console2} A new Console2 instance
|
||||
*/
|
||||
var addConsole = function (config, logWriter) {
|
||||
|
||||
if (!config) {
|
||||
config = {};
|
||||
}
|
||||
|
||||
config.createBasic = config.createBasic !== false;
|
||||
|
||||
var console = new Console2(config.console || {});
|
||||
|
||||
if (config.logWriter !== false) { //if config.logWriter is false, don't save logs
|
||||
|
||||
if (!logWriter) {
|
||||
|
||||
var rootPath = config.logWriter ?
|
||||
config.logWriter.rootPath || scribeOpt.rootPath :
|
||||
scribeOpt.rootPath
|
||||
;
|
||||
|
||||
logWriter = new LogWriter(rootPath);
|
||||
}
|
||||
|
||||
listenOnConsole(
|
||||
console,
|
||||
logWriter
|
||||
);
|
||||
}
|
||||
|
||||
consoles.push({
|
||||
console : console,
|
||||
logWriter : config.logWriter !== false ? logWriter : null
|
||||
});
|
||||
|
||||
//Create basic logging functions
|
||||
if (config.createBasic) {
|
||||
createBasic(console);
|
||||
}
|
||||
|
||||
return console;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* initWebPanel
|
||||
*
|
||||
* @return an express Router
|
||||
*/
|
||||
var initWebPanel = function () {
|
||||
|
||||
return webPanel(consoles);
|
||||
|
||||
};
|
||||
|
||||
|
||||
//Create a default console2 and attach it to process
|
||||
if (scribeOpt.createDefaultConsole) {
|
||||
process.console = addConsole();
|
||||
}
|
||||
|
||||
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* console
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
console : addConsole,
|
||||
|
||||
/**
|
||||
* webPanel
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
webPanel : initWebPanel,
|
||||
|
||||
/**
|
||||
* express
|
||||
*
|
||||
* Utilities for express
|
||||
* @type {Object}
|
||||
*/
|
||||
express : ExpressLogger,
|
||||
|
||||
/**
|
||||
* Console2
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
Console2 : Console2,
|
||||
|
||||
/**
|
||||
* LogWriter
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
LogWriter : LogWriter
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = scribe;
|
||||
|
||||
}());
|
BIN
static/img/logo.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
static/img/menu.png
Normal file
After Width: | Height: | Size: 15 KiB |
62
static/index.html
Normal file
|
@ -0,0 +1,62 @@
|
|||
<!DOCTYPE html>
|
||||
<html ng-app="scribe">
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title>{{title}} - ScribeJS</title>
|
||||
|
||||
<link
|
||||
href='http://fonts.googleapis.com/css?family=Open+Sans:400,300,600,700'
|
||||
rel='stylesheet'
|
||||
type='text/css'>
|
||||
<link rel="stylesheet" href="lib/ng-toggle.css" type="text/css">
|
||||
<link rel="stylesheet" href="lib/autocomplete.css" type="text/css">
|
||||
<link href="style.css" rel="stylesheet" type="text/css">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header class="header">
|
||||
|
||||
<div class="header__menu-button" ng-click="sidebar = !sidebar"></div>
|
||||
<p class="header__title a" ng-click="back()">{{title}}</p>
|
||||
<div class="header__mode">
|
||||
Mode : {{mode}}
|
||||
<ng-toggle ng-true-val="'dates'" ng-false-val="'folder'" ng-model="mode"></ng-toggle>
|
||||
</div>
|
||||
<a class="header__logo" href="/logs"></a>
|
||||
|
||||
</header>
|
||||
|
||||
<ng-view></ng-view>
|
||||
|
||||
<div class="mask" ng-show="sidebar" ng-click="sidebar = false"></div>
|
||||
|
||||
<script type="text/javascript" src="lib/angular.min.js"></script>
|
||||
<script type="text/javascript" src="lib/angular-route.min.js"></script>
|
||||
<script type="text/javascript" src="lib/angular-resource.min.js"></script>
|
||||
<script type="text/javascript" src="lib/ng-toggle.js"></script>
|
||||
<script type="text/javascript" src="lib/autocomplete.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/app.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/directives/block.js"></script>
|
||||
<script type="text/javascript" src="js/directives/sidebarLoggers.js"></script>
|
||||
<script type="text/javascript" src="js/directives/sidebarLogs.js"></script>
|
||||
<script type="text/javascript" src="js/directives/log.js"></script>
|
||||
<script type="text/javascript" src="js/directives/menu.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/services/scribeAPI.js"></script>
|
||||
<script type="text/javascript" src="js/services/logs.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/controllers/homeController.js"></script>
|
||||
<script type="text/javascript" src="js/controllers/dateController.js"></script>
|
||||
<script type="text/javascript" src="js/controllers/folderController.js"></script>
|
||||
<script type="text/javascript" src="js/controllers/logsController.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
238
static/js/app.js
Normal file
|
@ -0,0 +1,238 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* ScribeJS - WebPanel
|
||||
*/
|
||||
|
||||
window.app = angular.module('scribe', ['ngRoute', 'ngResource', 'ngToggle', 'autocomplete']);
|
||||
|
||||
//Configure routes
|
||||
app.config(['$routeProvider', function ($routeProvider) {
|
||||
|
||||
/**
|
||||
* Routes :
|
||||
*
|
||||
* - /
|
||||
* Home page. Choose the good logger
|
||||
* - /dates/?path
|
||||
* Choose the dates.
|
||||
* - /folder/?path
|
||||
* Explore directories.
|
||||
* - /logs
|
||||
* The logs viewer
|
||||
*/
|
||||
|
||||
$routeProvider
|
||||
|
||||
.when('/', {
|
||||
templateUrl : 'partials/folder.html',
|
||||
controller : 'homeController'
|
||||
})
|
||||
|
||||
.when('/dates/', {
|
||||
templateUrl : 'partials/dates.html',
|
||||
controller : 'dateController',
|
||||
|
||||
// resolve dates
|
||||
resolve : {
|
||||
dates : [
|
||||
'ScribeAPI',
|
||||
'$rootScope',
|
||||
'$location',
|
||||
function (ScribeAPI, $rootScope, $location) {
|
||||
|
||||
//query params
|
||||
var from = $location.search().from || Date.now(), //timestamp
|
||||
length = $location.search().length || 10, //number of dates to show
|
||||
logWriter = $location.search().path; //which log writer to use ?
|
||||
|
||||
$rootScope.title = logWriter + ' dates';
|
||||
|
||||
//Get dates
|
||||
return ScribeAPI.dateExplorer({
|
||||
logFolder : logWriter,
|
||||
from : from,
|
||||
length : length
|
||||
}).$promise;
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
.when('/folder/', {
|
||||
templateUrl : 'partials/folder.html',
|
||||
controller : 'folderController',
|
||||
|
||||
//resolve folder content
|
||||
resolve : {
|
||||
folder : [
|
||||
'ScribeAPI',
|
||||
'$rootScope',
|
||||
'$location',
|
||||
function (ScribeAPI, $rootScope, $location) {
|
||||
|
||||
//folder path
|
||||
var path = $location.search().path;
|
||||
|
||||
$rootScope.title = path;
|
||||
|
||||
//Get folder content
|
||||
return ScribeAPI.folderExplorer({
|
||||
path : path
|
||||
}).$promise;
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
.when('/logs/', {
|
||||
templateUrl : 'partials/logs.html',
|
||||
controller : 'logsController'
|
||||
});
|
||||
}]);
|
||||
|
||||
app.run([
|
||||
'$rootScope',
|
||||
'$location',
|
||||
'$q',
|
||||
'$window',
|
||||
'$document',
|
||||
'ScribeAPI',
|
||||
function ($rootScope, $location, $q, $window, $document, ScribeAPI) {
|
||||
|
||||
/**
|
||||
* getAllLogsFiles
|
||||
*
|
||||
* Retrieve all logs files of all loggers
|
||||
* All files path are stored in the history file of each logger
|
||||
*
|
||||
* @param {Array} loggers
|
||||
* @return {promise}
|
||||
*/
|
||||
var getAllLogsFiles = function (loggers) {
|
||||
|
||||
var deferred = $q.defer(),
|
||||
loggersHistory = [];
|
||||
|
||||
//First, get all history files
|
||||
loggers.forEach(function (logger) {
|
||||
loggersHistory.push(ScribeAPI.log({
|
||||
path: logger + '/history.json'
|
||||
}).$promise);
|
||||
});
|
||||
|
||||
//Then, extract all files path (they're saved by date)
|
||||
$q.all(loggersHistory).then(function (data) {
|
||||
|
||||
var files = [];
|
||||
|
||||
//extract the paths and push them in the `files` array
|
||||
data.forEach(function (history) {
|
||||
Object.keys(history[0].dates).forEach(function (date) {
|
||||
files = files.concat(history[0].dates[date]);
|
||||
});
|
||||
});
|
||||
|
||||
//send the array
|
||||
deferred.resolve(files);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* $rootScope.mode
|
||||
*
|
||||
* Webpanel mode. Wether use folder or dates mode by default
|
||||
*
|
||||
* @type {String} 'folder' | 'dates'
|
||||
*/
|
||||
$rootScope.mode = 'dates';
|
||||
|
||||
/**
|
||||
* $rootScope.title
|
||||
*
|
||||
* Page title
|
||||
*
|
||||
* @type {String}
|
||||
*/
|
||||
$rootScope.title = "ScribeJS";
|
||||
|
||||
/**
|
||||
* $rootScope.sidebar
|
||||
*
|
||||
* Open/close sidebar
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
$rootScope.sidebar = false;
|
||||
|
||||
/**
|
||||
* $rootScope.logWriters
|
||||
*
|
||||
* Stores all logsWriters of the app
|
||||
*
|
||||
* @type {Array}
|
||||
*/
|
||||
$rootScope.logWriters = [];
|
||||
|
||||
/**
|
||||
* $rootScope.allLogsFiles
|
||||
*
|
||||
* Stores all files of all logWriters
|
||||
*
|
||||
* @type {Array}
|
||||
*/
|
||||
$rootScope.allLogsFiles = [];
|
||||
|
||||
//Get all logWriters
|
||||
//Get all log files of atll logWriters
|
||||
ScribeAPI.logWriters(function (logWriters) {
|
||||
$rootScope.logWriters = logWriters;
|
||||
getAllLogsFiles(logWriters).then(function (files) {
|
||||
$rootScope.allLogsFiles = files;
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* $rootScope.back
|
||||
*
|
||||
* History back
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
$rootScope.back = function () {
|
||||
$window.history.back();
|
||||
};
|
||||
|
||||
/**
|
||||
* $rootScope.go
|
||||
*
|
||||
* Wrapper for $location path and search
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
$rootScope.go = function (path, search) {
|
||||
$location.path(path);
|
||||
if (search) {
|
||||
$location.search(search);
|
||||
} else {
|
||||
$location.search({});
|
||||
}
|
||||
};
|
||||
|
||||
$document.bind('keydown', function ($event) {
|
||||
if ($event.keyCode === 27) {
|
||||
$rootScope.sidebar = false;
|
||||
$rootScope.$digest();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
|
||||
}());
|
70
static/js/controllers/dateController.js
Normal file
|
@ -0,0 +1,70 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Dates controller
|
||||
*/
|
||||
|
||||
window.app.controller('dateController', [
|
||||
'$scope',
|
||||
'$rootScope',
|
||||
'$location',
|
||||
'$filter',
|
||||
'logs',
|
||||
'dates',
|
||||
function ($scope, $rootScope, $location, $filter, logs, dates) {
|
||||
|
||||
//reset
|
||||
$rootScope.sidebar = false;
|
||||
|
||||
/**
|
||||
* $scope.nextPage
|
||||
*
|
||||
* Go to to a next page
|
||||
*
|
||||
* @param {int} next if < 0, goes to older dates, if > 0 goes to newer dates
|
||||
*/
|
||||
$scope.nextPage = function (next) {
|
||||
|
||||
var currentDate = $location.search().from || Date.now(),
|
||||
day = 24 * 60 * 60 * 1000;
|
||||
|
||||
$rootScope.go(
|
||||
'dates',
|
||||
{
|
||||
path : $location.search().path,
|
||||
from : next * day + parseInt(currentDate, 10),
|
||||
length : 10
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
//build blocks
|
||||
$scope.blocks = dates.map(function (item) {
|
||||
|
||||
return {
|
||||
type : 'date',
|
||||
messageTop : $filter('date')(item.date, 'MMM'),
|
||||
message : $filter('date')(item.date, 'd'),
|
||||
messageBottom : $filter('date')(item.date, 'yyyy'),
|
||||
click : function () {
|
||||
//save files
|
||||
logs.setLogs(item.files.map(function (el, index) {
|
||||
return {
|
||||
selected : index === 0, //select the first by default
|
||||
name : el.name,
|
||||
path : el.path
|
||||
};
|
||||
}));
|
||||
|
||||
//redirect
|
||||
$rootScope.go('logs');
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
}
|
||||
]);
|
||||
|
||||
}());
|
61
static/js/controllers/folderController.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Folder controller
|
||||
*/
|
||||
|
||||
window.app.controller('folderController', [
|
||||
'$scope',
|
||||
'$rootScope',
|
||||
'logs',
|
||||
'folder',
|
||||
function ($scope, $rootScope, logs, folder) {
|
||||
|
||||
//reset
|
||||
$rootScope.sidebar = false;
|
||||
$scope.onlyFiles = true;
|
||||
|
||||
//build each block
|
||||
$scope.blocks = folder.map(function (item) {
|
||||
|
||||
if (item.type !== 'file') {
|
||||
$scope.onlyFiles = false;
|
||||
}
|
||||
|
||||
return {
|
||||
message : item.name,
|
||||
click : function () {
|
||||
if (item.type === 'file') {
|
||||
|
||||
//Save all current files of the folder
|
||||
//But select only the clicked one
|
||||
var newFiles = folder.map(function (file) {
|
||||
if (file.type === 'file') {
|
||||
return {
|
||||
selected : file.path === item.path,
|
||||
name : file.name,
|
||||
path : file.path
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
//save files and redirect
|
||||
logs.setLogs(newFiles);
|
||||
$rootScope.go('logs');
|
||||
|
||||
} else {
|
||||
$rootScope.go('folder', {
|
||||
path : item.path
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
]);
|
||||
|
||||
}());
|
37
static/js/controllers/homeController.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Home controller
|
||||
*/
|
||||
|
||||
window.app.controller('homeController', [
|
||||
'$scope',
|
||||
'$rootScope',
|
||||
function ($scope, $rootScope) {
|
||||
|
||||
//reset
|
||||
$rootScope.title = "Loggers";
|
||||
$rootScope.sidebar = false;
|
||||
|
||||
//build block for each logWriter
|
||||
$scope.blocks = $rootScope.logWriters.map(function (item) {
|
||||
|
||||
return {
|
||||
message : item,
|
||||
click : function () {
|
||||
$rootScope.go(
|
||||
$rootScope.mode, //routes according to mode
|
||||
{
|
||||
path : item
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
}
|
||||
]);
|
||||
|
||||
}());
|
147
static/js/controllers/logsController.js
Normal file
|
@ -0,0 +1,147 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Logs controller
|
||||
*/
|
||||
|
||||
window.app.controller('logsController', [
|
||||
'$scope',
|
||||
'$rootScope',
|
||||
'ScribeAPI',
|
||||
'logs',
|
||||
function ($scope, $rootScope, ScribeAPI, logs) {
|
||||
|
||||
//reset
|
||||
$rootScope.sidebar = false;
|
||||
|
||||
/**
|
||||
* attachCurrentFiles
|
||||
*
|
||||
* Attach current files to $scope
|
||||
* If no current files, redirect to home
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
var attachCurrentFiles = function (currentFiles) {
|
||||
//if no files, redirect to home
|
||||
if (currentFiles.length === 0) {
|
||||
$rootScope.go('/');
|
||||
}
|
||||
$scope.currentFiles = currentFiles;
|
||||
};
|
||||
|
||||
/**
|
||||
* getCurrentLogs
|
||||
*
|
||||
* Get content of each current files
|
||||
* And push all the lines in `$scope.lines`
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
var getCurrentLogs = function () {
|
||||
|
||||
$scope.currentFiles.forEach(function (file) {
|
||||
|
||||
$scope.lines = [];
|
||||
|
||||
if (file.selected) {
|
||||
ScribeAPI.log({
|
||||
path : file.path
|
||||
}, function (data) {
|
||||
$scope.lines = $scope.lines.concat(data);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* selectAll
|
||||
*
|
||||
* Select all current files
|
||||
*
|
||||
* @params {Boolean} select True: select / False: unselect
|
||||
* @type {Function}
|
||||
*/
|
||||
var selectAll = function (select) {
|
||||
$scope.currentFiles = $scope.currentFiles.map(function (file) {
|
||||
file.selected = select;
|
||||
return file;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Init $sope values
|
||||
*/
|
||||
|
||||
//ng-toggle values
|
||||
//3 states : 1 / null / 0
|
||||
$scope.showFile = null;
|
||||
$scope.showTime = 1;
|
||||
$scope.showDate = 0;
|
||||
$scope.showTags = null;
|
||||
|
||||
//Stores all lines (a line = a log)
|
||||
$scope.lines = [];
|
||||
|
||||
//default order by time
|
||||
$scope.order = "context.time";
|
||||
//order reverse
|
||||
$scope.reverse = false;
|
||||
|
||||
/**
|
||||
* $scope.addFile
|
||||
*
|
||||
* Add a file to current files
|
||||
*
|
||||
* @param {String} path Its path (with logWriter dir)
|
||||
* @type {Function}
|
||||
*/
|
||||
$scope.addFile = function (path) {
|
||||
if (path !== "") {
|
||||
attachCurrentFiles(logs.addLog(path, true));
|
||||
}
|
||||
$scope.fileToAdd = "";
|
||||
};
|
||||
|
||||
/**
|
||||
* $scope.reload
|
||||
*
|
||||
* Reload all selected files
|
||||
* @type {Function}
|
||||
*/
|
||||
$scope.reload = function () {
|
||||
attachCurrentFiles(logs.getLogs());
|
||||
getCurrentLogs();
|
||||
};
|
||||
|
||||
$scope.reload();
|
||||
|
||||
|
||||
/**
|
||||
* Watchers
|
||||
*/
|
||||
|
||||
//watch current files for changes
|
||||
//as user can select / unselect files in sidebar
|
||||
$scope.$watch('currentFiles', function (value, old) {
|
||||
if (value !== old) {
|
||||
getCurrentLogs();
|
||||
}
|
||||
}, true);
|
||||
|
||||
//watch selectAll checkbox
|
||||
//to select all current files
|
||||
$scope.$watch('selectAll', function (value, old) {
|
||||
if (value !== old) {
|
||||
selectAll(value);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
]);
|
||||
|
||||
}());
|
89
static/js/directives/block.js
Normal file
|
@ -0,0 +1,89 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Block directives
|
||||
*
|
||||
* Blocks ar used in home, folder and dates view
|
||||
* to display folder name, dates and file name
|
||||
*/
|
||||
|
||||
var colors = [
|
||||
"#16a085",
|
||||
"#27ae60",
|
||||
"#2980b9",
|
||||
"#8e44ad",
|
||||
"#f39c12",
|
||||
"#d35400",
|
||||
"#c0392b",
|
||||
"#7f8c8d"
|
||||
];
|
||||
|
||||
window.app.directive('block', [function () {
|
||||
|
||||
return {
|
||||
scope : {
|
||||
|
||||
/**
|
||||
* type
|
||||
*
|
||||
* @type {String} 'dates' or anything else
|
||||
*/
|
||||
type : "=",
|
||||
|
||||
/**
|
||||
* message
|
||||
*
|
||||
* Main message. If top and bottom messages,
|
||||
* main message goes in middle
|
||||
*
|
||||
* @type {String}
|
||||
*/
|
||||
message : "=",
|
||||
|
||||
/**
|
||||
* messageTop
|
||||
*
|
||||
* @type {String}
|
||||
*/
|
||||
messageTop : "=",
|
||||
|
||||
/**
|
||||
* messageBottom
|
||||
*
|
||||
* @type {String}
|
||||
*/
|
||||
messageBottom : "=",
|
||||
|
||||
/**
|
||||
* forceFile
|
||||
*
|
||||
* If true, the block won't be a square
|
||||
* but with be full-wifth in order to contain a file name
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
forceFile : "="
|
||||
|
||||
},
|
||||
restrict : "E",
|
||||
templateUrl : 'partials/elements/blocks.html',
|
||||
replace : true,
|
||||
|
||||
controller : ['$scope', function ($scope) {
|
||||
|
||||
/**
|
||||
* $scope.color
|
||||
*
|
||||
* @return {String} A radom haxa color from `colors`
|
||||
*/
|
||||
$scope.color = function () {
|
||||
return colors[Math.floor(Math.random() * colors.length)];
|
||||
};
|
||||
}]
|
||||
};
|
||||
|
||||
}]);
|
||||
|
||||
}());
|
92
static/js/directives/log.js
Normal file
|
@ -0,0 +1,92 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Log directive
|
||||
*
|
||||
* Represents a single log
|
||||
*/
|
||||
|
||||
window.app.directive('log', [function () {
|
||||
|
||||
return {
|
||||
scope : {
|
||||
|
||||
/**
|
||||
* log
|
||||
*
|
||||
* The log object
|
||||
* @type {Object}
|
||||
*/
|
||||
log : "=",
|
||||
|
||||
/**
|
||||
* showFile
|
||||
*
|
||||
* Force to show file ?
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
showFile : "=",
|
||||
|
||||
/**
|
||||
* showTime
|
||||
*
|
||||
* Force to show time ?
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
showTime : "=",
|
||||
|
||||
/**
|
||||
* showDate
|
||||
*
|
||||
* Force to show date ?
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
showDate : "=",
|
||||
|
||||
/**
|
||||
* showTags
|
||||
*
|
||||
* Force to show tags ?
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
showTags : "="
|
||||
},
|
||||
restrict : 'E',
|
||||
templateUrl : 'partials/elements/log.html',
|
||||
replace : true,
|
||||
|
||||
controller : ['$scope', function ($scope) {
|
||||
|
||||
/**
|
||||
* $scope.handleTags
|
||||
*
|
||||
* As tags could be string or object,
|
||||
* extracts the tag message
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
$scope.handleTags = function (tag) {
|
||||
|
||||
if (typeof tag === 'string') {
|
||||
return tag;
|
||||
} else if (typeof tag === 'object') {
|
||||
return tag.msg || '';
|
||||
} else {
|
||||
return tag;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}]
|
||||
};
|
||||
|
||||
}]);
|
||||
|
||||
|
||||
}());
|
22
static/js/directives/menu.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Menu directive
|
||||
*
|
||||
* Log viewer top control bar
|
||||
*/
|
||||
|
||||
window.app.directive('menu', [function () {
|
||||
|
||||
return {
|
||||
scope : false,
|
||||
restrict : 'E',
|
||||
templateUrl : 'partials/elements/menu.html',
|
||||
replace : true
|
||||
};
|
||||
|
||||
}]);
|
||||
|
||||
}());
|
20
static/js/directives/sidebarLoggers.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Home, folders and dates sidebar directives
|
||||
*/
|
||||
|
||||
window.app.directive('sidebarLoggers', [function () {
|
||||
|
||||
return {
|
||||
scop : false,
|
||||
restrict : 'E',
|
||||
templateUrl : 'partials/elements/sidebarLoggers.html',
|
||||
replace : true
|
||||
};
|
||||
|
||||
}]);
|
||||
|
||||
}());
|
20
static/js/directives/sidebarLogs.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Log viewer sidebar directives
|
||||
*/
|
||||
|
||||
window.app.directive('sidebarLogs', [function () {
|
||||
|
||||
return {
|
||||
scope : false,
|
||||
restrict : 'E',
|
||||
templateUrl : 'partials/elements/sidebarLogs.html',
|
||||
replace : true
|
||||
};
|
||||
|
||||
}]);
|
||||
|
||||
}());
|
121
static/js/services/logs.js
Normal file
|
@ -0,0 +1,121 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Logs service
|
||||
*
|
||||
* A bridge between dates or folder controller and logs controller
|
||||
*
|
||||
* Stores files to show in logs viewer
|
||||
*/
|
||||
|
||||
window.app.factory('logs', [function () {
|
||||
|
||||
/**
|
||||
* files
|
||||
*
|
||||
* @type {Array} Array of object
|
||||
*
|
||||
{
|
||||
name : 'file name',
|
||||
path : 'file full path (with logWriter dir)',
|
||||
selected : True //if false, file belongs to currentFiles
|
||||
//but won't be show by default in the log viewer
|
||||
}
|
||||
*
|
||||
*/
|
||||
var files = [];
|
||||
|
||||
/**
|
||||
* basename
|
||||
*
|
||||
* @see http://stackoverflow.com/questions/3820381/need-a-basename-function-in-javascript#comment29942319_15270931
|
||||
*
|
||||
* @param {String} path
|
||||
*/
|
||||
var basename = function (path) {
|
||||
return path.split(/[\\/]/).pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* pathInFiles
|
||||
*
|
||||
* Is the path `search` in `files` ?
|
||||
*
|
||||
* @param {String} search
|
||||
*/
|
||||
var pathInFiles = function (search) {
|
||||
var result = false;
|
||||
|
||||
files.forEach(function (elem) {
|
||||
if (elem.path === search) {
|
||||
result = true;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* getLogs
|
||||
*
|
||||
* @return all files
|
||||
*/
|
||||
getLogs : function () {
|
||||
return files;
|
||||
},
|
||||
|
||||
/**
|
||||
* addLog
|
||||
*
|
||||
* Add a log file
|
||||
*
|
||||
* @param {String} path The path's file
|
||||
* @param {Boolean} selected Whether the file is selected. Default false.
|
||||
*
|
||||
* @return all files
|
||||
*/
|
||||
addLog : function (path, selected) {
|
||||
|
||||
if (!pathInFiles(path)) {
|
||||
var file;
|
||||
|
||||
//if path is string, we constructthe good object
|
||||
if (typeof path === 'string') {
|
||||
file = {
|
||||
name : basename(path),
|
||||
path : path,
|
||||
selected : selected || false
|
||||
};
|
||||
} else {
|
||||
//TODO : check something ?
|
||||
file = path;
|
||||
}
|
||||
|
||||
files.push(file);
|
||||
}
|
||||
return files;
|
||||
},
|
||||
|
||||
/**
|
||||
* setLogs
|
||||
*
|
||||
* Override `files`
|
||||
*
|
||||
* @param {Array} newFiles
|
||||
*/
|
||||
setLogs : function (newFiles) {
|
||||
//simply delete null and undefined values that can comes from map()
|
||||
files = newFiles.filter(function (item) {
|
||||
return !!item;
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}]);
|
||||
|
||||
}());
|
55
static/js/services/scribeAPI.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* ScribeAPI
|
||||
*
|
||||
* A $resource API wrapper
|
||||
*/
|
||||
|
||||
window.app.factory('ScribeAPI', ['$resource', function ($resource) {
|
||||
|
||||
return $resource(
|
||||
'api',
|
||||
null,
|
||||
{
|
||||
logWriters : {
|
||||
method : 'GET',
|
||||
isArray : true
|
||||
},
|
||||
dateExplorer : {
|
||||
method : 'GET',
|
||||
url : 'api/dateExplorer',
|
||||
isArray : true
|
||||
},
|
||||
folderExplorer : {
|
||||
method : 'GET',
|
||||
url : 'api/folderExplorer',
|
||||
isArray : true
|
||||
},
|
||||
log : {
|
||||
method : 'GET',
|
||||
url : 'api/log',
|
||||
isArray : true,
|
||||
|
||||
//As logs are lines of JSON, we want to parse each lines one by one
|
||||
transformResponse : function (data) {
|
||||
|
||||
var lines = data.match(/[^\r\n]+/g); //cut lines
|
||||
|
||||
return lines.map(function (line) {
|
||||
try {
|
||||
return JSON.parse(line);
|
||||
} catch (e) {
|
||||
return line;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}]);
|
||||
|
||||
}());
|
13
static/lib/angular-resource.min.js
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
AngularJS v1.2.26
|
||||
(c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
License: MIT
|
||||
*/
|
||||
(function(H,a,A){'use strict';function D(p,g){g=g||{};a.forEach(g,function(a,c){delete g[c]});for(var c in p)!p.hasOwnProperty(c)||"$"===c.charAt(0)&&"$"===c.charAt(1)||(g[c]=p[c]);return g}var v=a.$$minErr("$resource"),C=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;a.module("ngResource",["ng"]).factory("$resource",["$http","$q",function(p,g){function c(a,c){this.template=a;this.defaults=c||{};this.urlParams={}}function t(n,w,l){function r(h,d){var e={};d=x({},w,d);s(d,function(b,d){u(b)&&(b=b());var k;if(b&&
|
||||
b.charAt&&"@"==b.charAt(0)){k=h;var a=b.substr(1);if(null==a||""===a||"hasOwnProperty"===a||!C.test("."+a))throw v("badmember",a);for(var a=a.split("."),f=0,c=a.length;f<c&&k!==A;f++){var g=a[f];k=null!==k?k[g]:A}}else k=b;e[d]=k});return e}function e(a){return a.resource}function f(a){D(a||{},this)}var F=new c(n);l=x({},B,l);s(l,function(h,d){var c=/^(POST|PUT|PATCH)$/i.test(h.method);f[d]=function(b,d,k,w){var q={},n,l,y;switch(arguments.length){case 4:y=w,l=k;case 3:case 2:if(u(d)){if(u(b)){l=
|
||||
b;y=d;break}l=d;y=k}else{q=b;n=d;l=k;break}case 1:u(b)?l=b:c?n=b:q=b;break;case 0:break;default:throw v("badargs",arguments.length);}var t=this instanceof f,m=t?n:h.isArray?[]:new f(n),z={},B=h.interceptor&&h.interceptor.response||e,C=h.interceptor&&h.interceptor.responseError||A;s(h,function(a,b){"params"!=b&&("isArray"!=b&&"interceptor"!=b)&&(z[b]=G(a))});c&&(z.data=n);F.setUrlParams(z,x({},r(n,h.params||{}),q),h.url);q=p(z).then(function(b){var d=b.data,k=m.$promise;if(d){if(a.isArray(d)!==!!h.isArray)throw v("badcfg",
|
||||
h.isArray?"array":"object",a.isArray(d)?"array":"object");h.isArray?(m.length=0,s(d,function(b){"object"===typeof b?m.push(new f(b)):m.push(b)})):(D(d,m),m.$promise=k)}m.$resolved=!0;b.resource=m;return b},function(b){m.$resolved=!0;(y||E)(b);return g.reject(b)});q=q.then(function(b){var a=B(b);(l||E)(a,b.headers);return a},C);return t?q:(m.$promise=q,m.$resolved=!1,m)};f.prototype["$"+d]=function(b,a,k){u(b)&&(k=a,a=b,b={});b=f[d].call(this,b,this,a,k);return b.$promise||b}});f.bind=function(a){return t(n,
|
||||
x({},w,a),l)};return f}var B={get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}},E=a.noop,s=a.forEach,x=a.extend,G=a.copy,u=a.isFunction;c.prototype={setUrlParams:function(c,g,l){var r=this,e=l||r.template,f,p,h=r.urlParams={};s(e.split(/\W/),function(a){if("hasOwnProperty"===a)throw v("badname");!/^\d+$/.test(a)&&(a&&RegExp("(^|[^\\\\]):"+a+"(\\W|$)").test(e))&&(h[a]=!0)});e=e.replace(/\\:/g,":");g=g||{};s(r.urlParams,function(d,
|
||||
c){f=g.hasOwnProperty(c)?g[c]:r.defaults[c];a.isDefined(f)&&null!==f?(p=encodeURIComponent(f).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"%20").replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+"),e=e.replace(RegExp(":"+c+"(\\W|$)","g"),function(a,c){return p+c})):e=e.replace(RegExp("(/?):"+c+"(\\W|$)","g"),function(a,c,d){return"/"==d.charAt(0)?d:c+d})});e=e.replace(/\/+$/,"")||"/";e=e.replace(/\/\.(?=\w+($|\?))/,".");c.url=e.replace(/\/\\\./,
|
||||
"/.");s(g,function(a,e){r.urlParams[e]||(c.params=c.params||{},c.params[e]=a)})}};return t}])})(window,window.angular);
|
||||
//# sourceMappingURL=angular-resource.min.js.map
|
8
static/lib/angular-resource.min.js.map
Normal file
14
static/lib/angular-route.min.js
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
AngularJS v1.2.26
|
||||
(c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
License: MIT
|
||||
*/
|
||||
(function(n,e,A){'use strict';function x(s,g,h){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,w){function y(){p&&(p.remove(),p=null);k&&(k.$destroy(),k=null);l&&(h.leave(l,function(){p=null}),p=l,l=null)}function v(){var b=s.current&&s.current.locals;if(e.isDefined(b&&b.$template)){var b=a.$new(),d=s.current;l=w(b,function(d){h.enter(d,null,l||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||g()});y()});k=d.scope=b;k.$emit("$viewContentLoaded");k.$eval(u)}else y()}
|
||||
var k,l,p,t=b.autoscroll,u=b.onload||"";a.$on("$routeChangeSuccess",v);v()}}}function z(e,g,h){return{restrict:"ECA",priority:-400,link:function(a,c){var b=h.current,f=b.locals;c.html(f.$template);var w=e(c.contents());b.controller&&(f.$scope=a,f=g(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));w(a)}}}n=e.module("ngRoute",["ng"]).provider("$route",function(){function s(a,c){return e.extend(new (e.extend(function(){},
|
||||
{prototype:a})),c)}function g(a,e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},h=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;h.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var h={};this.when=function(a,c){h[a]=e.extend({reloadOnSearch:!0},c,a&&g(a,c));if(a){var b=
|
||||
"/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";h[b]=e.extend({redirectTo:a},g(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,g,n,v,k){function l(){var d=p(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!u)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)u=!1,a.$broadcast("$routeChangeStart",
|
||||
d,m),(r.current=d)&&d.redirectTo&&(e.isString(d.redirectTo)?c.path(t(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?g.get(d):g.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=k.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl=
|
||||
b,c=n.get(b,{cache:v}).then(function(a){return a.data})));e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function p(){var a,b;e.forEach(h,function(f,h){var q;if(q=!b){var g=c.path();q=f.keys;var l={};if(f.regexp)if(g=f.regexp.exec(g)){for(var k=1,p=g.length;k<p;++k){var n=q[k-1],r=g[k];n&&r&&(l[n.name]=r)}q=l}else q=null;
|
||||
else q=null;q=a=q}q&&(b=s(f,{params:e.extend({},c.search(),a),pathParams:a}),b.$$route=f)});return b||h[null]&&s(h[null],{params:{},pathParams:{}})}function t(a,c){var b=[];e.forEach((a||"").split(":"),function(a,d){if(0===d)b.push(a);else{var e=a.match(/(\w+)(.*)/),f=e[1];b.push(c[f]);b.push(e[2]||"");delete c[f]}});return b.join("")}var u=!1,r={routes:h,reload:function(){u=!0;a.$evalAsync(l)}};a.$on("$locationChangeSuccess",l);return r}]});n.provider("$routeParams",function(){this.$get=function(){return{}}});
|
||||
n.directive("ngView",x);n.directive("ngView",z);x.$inject=["$route","$anchorScroll","$animate"];z.$inject=["$compile","$controller","$route"]})(window,window.angular);
|
||||
//# sourceMappingURL=angular-route.min.js.map
|
8
static/lib/angular-route.min.js.map
Normal file
216
static/lib/angular.min.js
vendored
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
AngularJS v1.2.26
|
||||
(c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
License: MIT
|
||||
*/
|
||||
(function(W,X,t){'use strict';function C(b){return function(){var a=arguments[0],c,a="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.2.26/"+(b?b+"/":"")+a;for(c=1;c<arguments.length;c++)a=a+(1==c?"?":"&")+"p"+(c-1)+"="+encodeURIComponent("function"==typeof arguments[c]?arguments[c].toString().replace(/ \{[\s\S]*$/,""):"undefined"==typeof arguments[c]?"undefined":"string"!=typeof arguments[c]?JSON.stringify(arguments[c]):arguments[c]);return Error(a)}}function Pa(b){if(null==b||Ga(b))return!1;
|
||||
var a=b.length;return 1===b.nodeType&&a?!0:v(b)||J(b)||0===a||"number"===typeof a&&0<a&&a-1 in b}function r(b,a,c){var d;if(b)if(P(b))for(d in b)"prototype"==d||("length"==d||"name"==d||b.hasOwnProperty&&!b.hasOwnProperty(d))||a.call(c,b[d],d);else if(J(b)||Pa(b))for(d=0;d<b.length;d++)a.call(c,b[d],d);else if(b.forEach&&b.forEach!==r)b.forEach(a,c);else for(d in b)b.hasOwnProperty(d)&&a.call(c,b[d],d);return b}function Zb(b){var a=[],c;for(c in b)b.hasOwnProperty(c)&&a.push(c);return a.sort()}function Tc(b,
|
||||
a,c){for(var d=Zb(b),e=0;e<d.length;e++)a.call(c,b[d[e]],d[e]);return d}function $b(b){return function(a,c){b(c,a)}}function hb(){for(var b=ma.length,a;b;){b--;a=ma[b].charCodeAt(0);if(57==a)return ma[b]="A",ma.join("");if(90==a)ma[b]="0";else return ma[b]=String.fromCharCode(a+1),ma.join("")}ma.unshift("0");return ma.join("")}function ac(b,a){a?b.$$hashKey=a:delete b.$$hashKey}function D(b){var a=b.$$hashKey;r(arguments,function(a){a!==b&&r(a,function(a,c){b[c]=a})});ac(b,a);return b}function U(b){return parseInt(b,
|
||||
10)}function bc(b,a){return D(new (D(function(){},{prototype:b})),a)}function E(){}function Qa(b){return b}function ba(b){return function(){return b}}function x(b){return"undefined"===typeof b}function y(b){return"undefined"!==typeof b}function T(b){return null!=b&&"object"===typeof b}function v(b){return"string"===typeof b}function ib(b){return"number"===typeof b}function ta(b){return"[object Date]"===za.call(b)}function P(b){return"function"===typeof b}function jb(b){return"[object RegExp]"===za.call(b)}
|
||||
function Ga(b){return b&&b.document&&b.location&&b.alert&&b.setInterval}function Uc(b){return!(!b||!(b.nodeName||b.prop&&b.attr&&b.find))}function Vc(b,a,c){var d=[];r(b,function(b,f,g){d.push(a.call(c,b,f,g))});return d}function Ra(b,a){if(b.indexOf)return b.indexOf(a);for(var c=0;c<b.length;c++)if(a===b[c])return c;return-1}function Sa(b,a){var c=Ra(b,a);0<=c&&b.splice(c,1);return a}function Ha(b,a,c,d){if(Ga(b)||b&&b.$evalAsync&&b.$watch)throw Ta("cpws");if(a){if(b===a)throw Ta("cpi");c=c||[];
|
||||
d=d||[];if(T(b)){var e=Ra(c,b);if(-1!==e)return d[e];c.push(b);d.push(a)}if(J(b))for(var f=a.length=0;f<b.length;f++)e=Ha(b[f],null,c,d),T(b[f])&&(c.push(b[f]),d.push(e)),a.push(e);else{var g=a.$$hashKey;J(a)?a.length=0:r(a,function(b,c){delete a[c]});for(f in b)e=Ha(b[f],null,c,d),T(b[f])&&(c.push(b[f]),d.push(e)),a[f]=e;ac(a,g)}}else if(a=b)J(b)?a=Ha(b,[],c,d):ta(b)?a=new Date(b.getTime()):jb(b)?(a=RegExp(b.source,b.toString().match(/[^\/]*$/)[0]),a.lastIndex=b.lastIndex):T(b)&&(a=Ha(b,{},c,d));
|
||||
return a}function ha(b,a){if(J(b)){a=a||[];for(var c=0;c<b.length;c++)a[c]=b[c]}else if(T(b))for(c in a=a||{},b)!kb.call(b,c)||"$"===c.charAt(0)&&"$"===c.charAt(1)||(a[c]=b[c]);return a||b}function Aa(b,a){if(b===a)return!0;if(null===b||null===a)return!1;if(b!==b&&a!==a)return!0;var c=typeof b,d;if(c==typeof a&&"object"==c)if(J(b)){if(!J(a))return!1;if((c=b.length)==a.length){for(d=0;d<c;d++)if(!Aa(b[d],a[d]))return!1;return!0}}else{if(ta(b))return ta(a)?isNaN(b.getTime())&&isNaN(a.getTime())||b.getTime()===
|
||||
a.getTime():!1;if(jb(b)&&jb(a))return b.toString()==a.toString();if(b&&b.$evalAsync&&b.$watch||a&&a.$evalAsync&&a.$watch||Ga(b)||Ga(a)||J(a))return!1;c={};for(d in b)if("$"!==d.charAt(0)&&!P(b[d])){if(!Aa(b[d],a[d]))return!1;c[d]=!0}for(d in a)if(!c.hasOwnProperty(d)&&"$"!==d.charAt(0)&&a[d]!==t&&!P(a[d]))return!1;return!0}return!1}function Bb(b,a){var c=2<arguments.length?Ba.call(arguments,2):[];return!P(a)||a instanceof RegExp?a:c.length?function(){return arguments.length?a.apply(b,c.concat(Ba.call(arguments,
|
||||
0))):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}}function Wc(b,a){var c=a;"string"===typeof b&&"$"===b.charAt(0)?c=t:Ga(a)?c="$WINDOW":a&&X===a?c="$DOCUMENT":a&&(a.$evalAsync&&a.$watch)&&(c="$SCOPE");return c}function na(b,a){return"undefined"===typeof b?t:JSON.stringify(b,Wc,a?" ":null)}function cc(b){return v(b)?JSON.parse(b):b}function Ua(b){"function"===typeof b?b=!0:b&&0!==b.length?(b=K(""+b),b=!("f"==b||"0"==b||"false"==b||"no"==b||"n"==b||"[]"==b)):b=!1;
|
||||
return b}function ia(b){b=w(b).clone();try{b.empty()}catch(a){}var c=w("<div>").append(b).html();try{return 3===b[0].nodeType?K(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+K(b)})}catch(d){return K(c)}}function dc(b){try{return decodeURIComponent(b)}catch(a){}}function ec(b){var a={},c,d;r((b||"").split("&"),function(b){b&&(c=b.replace(/\+/g,"%20").split("="),d=dc(c[0]),y(d)&&(b=y(c[1])?dc(c[1]):!0,kb.call(a,d)?J(a[d])?a[d].push(b):a[d]=[a[d],b]:a[d]=b))});return a}function Cb(b){var a=
|
||||
[];r(b,function(b,d){J(b)?r(b,function(b){a.push(Ca(d,!0)+(!0===b?"":"="+Ca(b,!0)))}):a.push(Ca(d,!0)+(!0===b?"":"="+Ca(b,!0)))});return a.length?a.join("&"):""}function lb(b){return Ca(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function Ca(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,a?"%20":"+")}function Xc(b,a){function c(a){a&&d.push(a)}var d=[b],e,f,g=["ng:app","ng-app","x-ng-app",
|
||||
"data-ng-app"],k=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;r(g,function(a){g[a]=!0;c(X.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(r(b.querySelectorAll("."+a),c),r(b.querySelectorAll("."+a+"\\:"),c),r(b.querySelectorAll("["+a+"]"),c))});r(d,function(a){if(!e){var b=k.exec(" "+a.className+" ");b?(e=a,f=(b[2]||"").replace(/\s+/g,",")):r(a.attributes,function(b){!e&&g[b.name]&&(e=a,f=b.value)})}});e&&a(e,f?[f]:[])}function fc(b,a){var c=function(){b=w(b);if(b.injector()){var c=b[0]===X?
|
||||
"document":ia(b);throw Ta("btstrpd",c.replace(/</,"<").replace(/>/,">"));}a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng");c=gc(a);c.invoke(["$rootScope","$rootElement","$compile","$injector","$animate",function(a,b,c,d,e){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},d=/^NG_DEFER_BOOTSTRAP!/;if(W&&!d.test(W.name))return c();W.name=W.name.replace(d,"");Va.resumeBootstrap=function(b){r(b,function(b){a.push(b)});c()}}function mb(b,a){a=
|
||||
a||"_";return b.replace(Yc,function(b,d){return(d?a:"")+b.toLowerCase()})}function Db(b,a,c){if(!b)throw Ta("areq",a||"?",c||"required");return b}function Wa(b,a,c){c&&J(b)&&(b=b[b.length-1]);Db(P(b),a,"not a function, got "+(b&&"object"===typeof b?b.constructor.name||"Object":typeof b));return b}function Da(b,a){if("hasOwnProperty"===b)throw Ta("badname",a);}function hc(b,a,c){if(!a)return b;a=a.split(".");for(var d,e=b,f=a.length,g=0;g<f;g++)d=a[g],b&&(b=(e=b)[d]);return!c&&P(b)?Bb(e,b):b}function Eb(b){var a=
|
||||
b[0];b=b[b.length-1];if(a===b)return w(a);var c=[a];do{a=a.nextSibling;if(!a)break;c.push(a)}while(a!==b);return w(c)}function Zc(b){var a=C("$injector"),c=C("ng");b=b.angular||(b.angular={});b.$$minErr=b.$$minErr||C;return b.module||(b.module=function(){var b={};return function(e,f,g){if("hasOwnProperty"===e)throw c("badname","module");f&&b.hasOwnProperty(e)&&(b[e]=null);return b[e]||(b[e]=function(){function b(a,d,e){return function(){c[e||"push"]([a,d,arguments]);return n}}if(!f)throw a("nomod",
|
||||
e);var c=[],d=[],l=b("$injector","invoke"),n={_invokeQueue:c,_runBlocks:d,requires:f,name:e,provider:b("$provide","provider"),factory:b("$provide","factory"),service:b("$provide","service"),value:b("$provide","value"),constant:b("$provide","constant","unshift"),animation:b("$animateProvider","register"),filter:b("$filterProvider","register"),controller:b("$controllerProvider","register"),directive:b("$compileProvider","directive"),config:l,run:function(a){d.push(a);return this}};g&&l(g);return n}())}}())}
|
||||
function $c(b){D(b,{bootstrap:fc,copy:Ha,extend:D,equals:Aa,element:w,forEach:r,injector:gc,noop:E,bind:Bb,toJson:na,fromJson:cc,identity:Qa,isUndefined:x,isDefined:y,isString:v,isFunction:P,isObject:T,isNumber:ib,isElement:Uc,isArray:J,version:ad,isDate:ta,lowercase:K,uppercase:Ia,callbacks:{counter:0},$$minErr:C,$$csp:Xa});Ya=Zc(W);try{Ya("ngLocale")}catch(a){Ya("ngLocale",[]).provider("$locale",bd)}Ya("ng",["ngLocale"],["$provide",function(a){a.provider({$$sanitizeUri:cd});a.provider("$compile",
|
||||
ic).directive({a:dd,input:jc,textarea:jc,form:ed,script:fd,select:gd,style:hd,option:id,ngBind:jd,ngBindHtml:kd,ngBindTemplate:ld,ngClass:md,ngClassEven:nd,ngClassOdd:od,ngCloak:pd,ngController:qd,ngForm:rd,ngHide:sd,ngIf:td,ngInclude:ud,ngInit:vd,ngNonBindable:wd,ngPluralize:xd,ngRepeat:yd,ngShow:zd,ngStyle:Ad,ngSwitch:Bd,ngSwitchWhen:Cd,ngSwitchDefault:Dd,ngOptions:Ed,ngTransclude:Fd,ngModel:Gd,ngList:Hd,ngChange:Id,required:kc,ngRequired:kc,ngValue:Jd}).directive({ngInclude:Kd}).directive(Fb).directive(lc);
|
||||
a.provider({$anchorScroll:Ld,$animate:Md,$browser:Nd,$cacheFactory:Od,$controller:Pd,$document:Qd,$exceptionHandler:Rd,$filter:mc,$interpolate:Sd,$interval:Td,$http:Ud,$httpBackend:Vd,$location:Wd,$log:Xd,$parse:Yd,$rootScope:Zd,$q:$d,$sce:ae,$sceDelegate:be,$sniffer:ce,$templateCache:de,$timeout:ee,$window:fe,$$rAF:ge,$$asyncCallback:he})}])}function Za(b){return b.replace(ie,function(a,b,d,e){return e?d.toUpperCase():d}).replace(je,"Moz$1")}function Gb(b,a,c,d){function e(b){var e=c&&b?[this.filter(b)]:
|
||||
[this],m=a,h,l,n,p,q,s;if(!d||null!=b)for(;e.length;)for(h=e.shift(),l=0,n=h.length;l<n;l++)for(p=w(h[l]),m?p.triggerHandler("$destroy"):m=!m,q=0,p=(s=p.children()).length;q<p;q++)e.push(Ea(s[q]));return f.apply(this,arguments)}var f=Ea.fn[b],f=f.$original||f;e.$original=f;Ea.fn[b]=e}function S(b){if(b instanceof S)return b;v(b)&&(b=aa(b));if(!(this instanceof S)){if(v(b)&&"<"!=b.charAt(0))throw Hb("nosel");return new S(b)}if(v(b)){var a=b;b=X;var c;if(c=ke.exec(a))b=[b.createElement(c[1])];else{var d=
|
||||
b,e;b=d.createDocumentFragment();c=[];if(Ib.test(a)){d=b.appendChild(d.createElement("div"));e=(le.exec(a)||["",""])[1].toLowerCase();e=ea[e]||ea._default;d.innerHTML="<div> </div>"+e[1]+a.replace(me,"<$1></$2>")+e[2];d.removeChild(d.firstChild);for(a=e[0];a--;)d=d.lastChild;a=0;for(e=d.childNodes.length;a<e;++a)c.push(d.childNodes[a]);d=b.firstChild;d.textContent=""}else c.push(d.createTextNode(a));b.textContent="";b.innerHTML="";b=c}Jb(this,b);w(X.createDocumentFragment()).append(this)}else Jb(this,
|
||||
b)}function Kb(b){return b.cloneNode(!0)}function Ja(b){Lb(b);var a=0;for(b=b.childNodes||[];a<b.length;a++)Ja(b[a])}function nc(b,a,c,d){if(y(d))throw Hb("offargs");var e=oa(b,"events");oa(b,"handle")&&(x(a)?r(e,function(a,c){$a(b,c,a);delete e[c]}):r(a.split(" "),function(a){x(c)?($a(b,a,e[a]),delete e[a]):Sa(e[a]||[],c)}))}function Lb(b,a){var c=b.ng339,d=ab[c];d&&(a?delete ab[c].data[a]:(d.handle&&(d.events.$destroy&&d.handle({},"$destroy"),nc(b)),delete ab[c],b.ng339=t))}function oa(b,a,c){var d=
|
||||
b.ng339,d=ab[d||-1];if(y(c))d||(b.ng339=d=++ne,d=ab[d]={}),d[a]=c;else return d&&d[a]}function Mb(b,a,c){var d=oa(b,"data"),e=y(c),f=!e&&y(a),g=f&&!T(a);d||g||oa(b,"data",d={});if(e)d[a]=c;else if(f){if(g)return d&&d[a];D(d,a)}else return d}function Nb(b,a){return b.getAttribute?-1<(" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").indexOf(" "+a+" "):!1}function nb(b,a){a&&b.setAttribute&&r(a.split(" "),function(a){b.setAttribute("class",aa((" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g,
|
||||
" ").replace(" "+aa(a)+" "," ")))})}function ob(b,a){if(a&&b.setAttribute){var c=(" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ");r(a.split(" "),function(a){a=aa(a);-1===c.indexOf(" "+a+" ")&&(c+=a+" ")});b.setAttribute("class",aa(c))}}function Jb(b,a){if(a){a=a.nodeName||!y(a.length)||Ga(a)?[a]:a;for(var c=0;c<a.length;c++)b.push(a[c])}}function oc(b,a){return pb(b,"$"+(a||"ngController")+"Controller")}function pb(b,a,c){9==b.nodeType&&(b=b.documentElement);for(a=J(a)?a:[a];b;){for(var d=
|
||||
0,e=a.length;d<e;d++)if((c=w.data(b,a[d]))!==t)return c;b=b.parentNode||11===b.nodeType&&b.host}}function pc(b){for(var a=0,c=b.childNodes;a<c.length;a++)Ja(c[a]);for(;b.firstChild;)b.removeChild(b.firstChild)}function qc(b,a){var c=qb[a.toLowerCase()];return c&&rc[b.nodeName]&&c}function oe(b,a){var c=function(c,e){c.preventDefault||(c.preventDefault=function(){c.returnValue=!1});c.stopPropagation||(c.stopPropagation=function(){c.cancelBubble=!0});c.target||(c.target=c.srcElement||X);if(x(c.defaultPrevented)){var f=
|
||||
c.preventDefault;c.preventDefault=function(){c.defaultPrevented=!0;f.call(c)};c.defaultPrevented=!1}c.isDefaultPrevented=function(){return c.defaultPrevented||!1===c.returnValue};var g=ha(a[e||c.type]||[]);r(g,function(a){a.call(b,c)});8>=Q?(c.preventDefault=null,c.stopPropagation=null,c.isDefaultPrevented=null):(delete c.preventDefault,delete c.stopPropagation,delete c.isDefaultPrevented)};c.elem=b;return c}function Ka(b,a){var c=typeof b,d;"function"==c||"object"==c&&null!==b?"function"==typeof(d=
|
||||
b.$$hashKey)?d=b.$$hashKey():d===t&&(d=b.$$hashKey=(a||hb)()):d=b;return c+":"+d}function bb(b,a){if(a){var c=0;this.nextUid=function(){return++c}}r(b,this.put,this)}function sc(b){var a,c;"function"===typeof b?(a=b.$inject)||(a=[],b.length&&(c=b.toString().replace(pe,""),c=c.match(qe),r(c[1].split(re),function(b){b.replace(se,function(b,c,d){a.push(d)})})),b.$inject=a):J(b)?(c=b.length-1,Wa(b[c],"fn"),a=b.slice(0,c)):Wa(b,"fn",!0);return a}function gc(b){function a(a){return function(b,c){if(T(b))r(b,
|
||||
$b(a));else return a(b,c)}}function c(a,b){Da(a,"service");if(P(b)||J(b))b=n.instantiate(b);if(!b.$get)throw cb("pget",a);return l[a+k]=b}function d(a,b){return c(a,{$get:b})}function e(a){var b=[],c,d,f,k;r(a,function(a){if(!h.get(a)){h.put(a,!0);try{if(v(a))for(c=Ya(a),b=b.concat(e(c.requires)).concat(c._runBlocks),d=c._invokeQueue,f=0,k=d.length;f<k;f++){var g=d[f],m=n.get(g[0]);m[g[1]].apply(m,g[2])}else P(a)?b.push(n.invoke(a)):J(a)?b.push(n.invoke(a)):Wa(a,"module")}catch(l){throw J(a)&&(a=
|
||||
a[a.length-1]),l.message&&(l.stack&&-1==l.stack.indexOf(l.message))&&(l=l.message+"\n"+l.stack),cb("modulerr",a,l.stack||l.message||l);}}});return b}function f(a,b){function c(d){if(a.hasOwnProperty(d)){if(a[d]===g)throw cb("cdep",d+" <- "+m.join(" <- "));return a[d]}try{return m.unshift(d),a[d]=g,a[d]=b(d)}catch(e){throw a[d]===g&&delete a[d],e;}finally{m.shift()}}function d(a,b,e){var f=[],k=sc(a),g,m,h;m=0;for(g=k.length;m<g;m++){h=k[m];if("string"!==typeof h)throw cb("itkn",h);f.push(e&&e.hasOwnProperty(h)?
|
||||
e[h]:c(h))}J(a)&&(a=a[g]);return a.apply(b,f)}return{invoke:d,instantiate:function(a,b){var c=function(){},e;c.prototype=(J(a)?a[a.length-1]:a).prototype;c=new c;e=d(a,c,b);return T(e)||P(e)?e:c},get:c,annotate:sc,has:function(b){return l.hasOwnProperty(b+k)||a.hasOwnProperty(b)}}}var g={},k="Provider",m=[],h=new bb([],!0),l={$provide:{provider:a(c),factory:a(d),service:a(function(a,b){return d(a,["$injector",function(a){return a.instantiate(b)}])}),value:a(function(a,b){return d(a,ba(b))}),constant:a(function(a,
|
||||
b){Da(a,"constant");l[a]=b;p[a]=b}),decorator:function(a,b){var c=n.get(a+k),d=c.$get;c.$get=function(){var a=q.invoke(d,c);return q.invoke(b,null,{$delegate:a})}}}},n=l.$injector=f(l,function(){throw cb("unpr",m.join(" <- "));}),p={},q=p.$injector=f(p,function(a){a=n.get(a+k);return q.invoke(a.$get,a)});r(e(b),function(a){q.invoke(a||E)});return q}function Ld(){var b=!0;this.disableAutoScrolling=function(){b=!1};this.$get=["$window","$location","$rootScope",function(a,c,d){function e(a){var b=null;
|
||||
r(a,function(a){b||"a"!==K(a.nodeName)||(b=a)});return b}function f(){var b=c.hash(),d;b?(d=g.getElementById(b))?d.scrollIntoView():(d=e(g.getElementsByName(b)))?d.scrollIntoView():"top"===b&&a.scrollTo(0,0):a.scrollTo(0,0)}var g=a.document;b&&d.$watch(function(){return c.hash()},function(){d.$evalAsync(f)});return f}]}function he(){this.$get=["$$rAF","$timeout",function(b,a){return b.supported?function(a){return b(a)}:function(b){return a(b,0,!1)}}]}function te(b,a,c,d){function e(a){try{a.apply(null,
|
||||
Ba.call(arguments,1))}finally{if(s--,0===s)for(;F.length;)try{F.pop()()}catch(b){c.error(b)}}}function f(a,b){(function fa(){r(u,function(a){a()});A=b(fa,a)})()}function g(){z=null;N!=k.url()&&(N=k.url(),r(ca,function(a){a(k.url())}))}var k=this,m=a[0],h=b.location,l=b.history,n=b.setTimeout,p=b.clearTimeout,q={};k.isMock=!1;var s=0,F=[];k.$$completeOutstandingRequest=e;k.$$incOutstandingRequestCount=function(){s++};k.notifyWhenNoOutstandingRequests=function(a){r(u,function(a){a()});0===s?a():F.push(a)};
|
||||
var u=[],A;k.addPollFn=function(a){x(A)&&f(100,n);u.push(a);return a};var N=h.href,R=a.find("base"),z=null;k.url=function(a,c){h!==b.location&&(h=b.location);l!==b.history&&(l=b.history);if(a){if(N!=a)return N=a,d.history?c?l.replaceState(null,"",a):(l.pushState(null,"",a),R.attr("href",R.attr("href"))):(z=a,c?h.replace(a):h.href=a),k}else return z||h.href.replace(/%27/g,"'")};var ca=[],L=!1;k.onUrlChange=function(a){if(!L){if(d.history)w(b).on("popstate",g);if(d.hashchange)w(b).on("hashchange",g);
|
||||
else k.addPollFn(g);L=!0}ca.push(a);return a};k.$$checkUrlChange=g;k.baseHref=function(){var a=R.attr("href");return a?a.replace(/^(https?\:)?\/\/[^\/]*/,""):""};var O={},da="",B=k.baseHref();k.cookies=function(a,b){var d,e,f,k;if(a)b===t?m.cookie=escape(a)+"=;path="+B+";expires=Thu, 01 Jan 1970 00:00:00 GMT":v(b)&&(d=(m.cookie=escape(a)+"="+escape(b)+";path="+B).length+1,4096<d&&c.warn("Cookie '"+a+"' possibly not set or overflowed because it was too large ("+d+" > 4096 bytes)!"));else{if(m.cookie!==
|
||||
da)for(da=m.cookie,d=da.split("; "),O={},f=0;f<d.length;f++)e=d[f],k=e.indexOf("="),0<k&&(a=unescape(e.substring(0,k)),O[a]===t&&(O[a]=unescape(e.substring(k+1))));return O}};k.defer=function(a,b){var c;s++;c=n(function(){delete q[c];e(a)},b||0);q[c]=!0;return c};k.defer.cancel=function(a){return q[a]?(delete q[a],p(a),e(E),!0):!1}}function Nd(){this.$get=["$window","$log","$sniffer","$document",function(b,a,c,d){return new te(b,d,a,c)}]}function Od(){this.$get=function(){function b(b,d){function e(a){a!=
|
||||
n&&(p?p==a&&(p=a.n):p=a,f(a.n,a.p),f(a,n),n=a,n.n=null)}function f(a,b){a!=b&&(a&&(a.p=b),b&&(b.n=a))}if(b in a)throw C("$cacheFactory")("iid",b);var g=0,k=D({},d,{id:b}),m={},h=d&&d.capacity||Number.MAX_VALUE,l={},n=null,p=null;return a[b]={put:function(a,b){if(h<Number.MAX_VALUE){var c=l[a]||(l[a]={key:a});e(c)}if(!x(b))return a in m||g++,m[a]=b,g>h&&this.remove(p.key),b},get:function(a){if(h<Number.MAX_VALUE){var b=l[a];if(!b)return;e(b)}return m[a]},remove:function(a){if(h<Number.MAX_VALUE){var b=
|
||||
l[a];if(!b)return;b==n&&(n=b.p);b==p&&(p=b.n);f(b.n,b.p);delete l[a]}delete m[a];g--},removeAll:function(){m={};g=0;l={};n=p=null},destroy:function(){l=k=m=null;delete a[b]},info:function(){return D({},k,{size:g})}}}var a={};b.info=function(){var b={};r(a,function(a,e){b[e]=a.info()});return b};b.get=function(b){return a[b]};return b}}function de(){this.$get=["$cacheFactory",function(b){return b("templates")}]}function ic(b,a){var c={},d="Directive",e=/^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,f=/(([\d\w_\-]+)(?:\:([^;]+))?;?)/,
|
||||
g=/^(on[a-z]+|formaction)$/;this.directive=function m(a,e){Da(a,"directive");v(a)?(Db(e,"directiveFactory"),c.hasOwnProperty(a)||(c[a]=[],b.factory(a+d,["$injector","$exceptionHandler",function(b,d){var e=[];r(c[a],function(c,f){try{var g=b.invoke(c);P(g)?g={compile:ba(g)}:!g.compile&&g.link&&(g.compile=ba(g.link));g.priority=g.priority||0;g.index=f;g.name=g.name||a;g.require=g.require||g.controller&&g.name;g.restrict=g.restrict||"A";e.push(g)}catch(m){d(m)}});return e}])),c[a].push(e)):r(a,$b(m));
|
||||
return this};this.aHrefSanitizationWhitelist=function(b){return y(b)?(a.aHrefSanitizationWhitelist(b),this):a.aHrefSanitizationWhitelist()};this.imgSrcSanitizationWhitelist=function(b){return y(b)?(a.imgSrcSanitizationWhitelist(b),this):a.imgSrcSanitizationWhitelist()};this.$get=["$injector","$interpolate","$exceptionHandler","$http","$templateCache","$parse","$controller","$rootScope","$document","$sce","$animate","$$sanitizeUri",function(a,b,l,n,p,q,s,F,u,A,N,R){function z(a,b,c,d,e){a instanceof
|
||||
w||(a=w(a));r(a,function(b,c){3==b.nodeType&&b.nodeValue.match(/\S+/)&&(a[c]=w(b).wrap("<span></span>").parent()[0])});var f=L(a,b,a,c,d,e);ca(a,"ng-scope");return function(b,c,d,e){Db(b,"scope");var g=c?La.clone.call(a):a;r(d,function(a,b){g.data("$"+b+"Controller",a)});d=0;for(var m=g.length;d<m;d++){var h=g[d].nodeType;1!==h&&9!==h||g.eq(d).data("$scope",b)}c&&c(g,b);f&&f(b,g,g,e);return g}}function ca(a,b){try{a.addClass(b)}catch(c){}}function L(a,b,c,d,e,f){function g(a,c,d,e){var f,h,l,q,n,
|
||||
p,s;f=c.length;var M=Array(f);for(q=0;q<f;q++)M[q]=c[q];p=q=0;for(n=m.length;q<n;p++)h=M[p],c=m[q++],f=m[q++],c?(c.scope?(l=a.$new(),w.data(h,"$scope",l)):l=a,s=c.transcludeOnThisElement?O(a,c.transclude,e):!c.templateOnThisElement&&e?e:!e&&b?O(a,b):null,c(f,l,h,d,s)):f&&f(a,h.childNodes,t,e)}for(var m=[],h,l,q,n,p=0;p<a.length;p++)h=new Ob,l=da(a[p],[],h,0===p?d:t,e),(f=l.length?H(l,a[p],h,b,c,null,[],[],f):null)&&f.scope&&ca(h.$$element,"ng-scope"),h=f&&f.terminal||!(q=a[p].childNodes)||!q.length?
|
||||
null:L(q,f?(f.transcludeOnThisElement||!f.templateOnThisElement)&&f.transclude:b),m.push(f,h),n=n||f||h,f=null;return n?g:null}function O(a,b,c){return function(d,e,f){var g=!1;d||(d=a.$new(),g=d.$$transcluded=!0);e=b(d,e,f,c);if(g)e.on("$destroy",function(){d.$destroy()});return e}}function da(a,b,c,d,g){var m=c.$attr,h;switch(a.nodeType){case 1:fa(b,pa(Ma(a).toLowerCase()),"E",d,g);for(var l,q,n,p=a.attributes,s=0,F=p&&p.length;s<F;s++){var A=!1,N=!1;l=p[s];if(!Q||8<=Q||l.specified){h=l.name;q=
|
||||
aa(l.value);l=pa(h);if(n=U.test(l))h=mb(l.substr(6),"-");var u=l.replace(/(Start|End)$/,"");l===u+"Start"&&(A=h,N=h.substr(0,h.length-5)+"end",h=h.substr(0,h.length-6));l=pa(h.toLowerCase());m[l]=h;if(n||!c.hasOwnProperty(l))c[l]=q,qc(a,l)&&(c[l]=!0);S(a,b,q,l);fa(b,l,"A",d,g,A,N)}}a=a.className;if(v(a)&&""!==a)for(;h=f.exec(a);)l=pa(h[2]),fa(b,l,"C",d,g)&&(c[l]=aa(h[3])),a=a.substr(h.index+h[0].length);break;case 3:K(b,a.nodeValue);break;case 8:try{if(h=e.exec(a.nodeValue))l=pa(h[1]),fa(b,l,"M",
|
||||
d,g)&&(c[l]=aa(h[2]))}catch(z){}}b.sort(x);return b}function B(a,b,c){var d=[],e=0;if(b&&a.hasAttribute&&a.hasAttribute(b)){do{if(!a)throw ja("uterdir",b,c);1==a.nodeType&&(a.hasAttribute(b)&&e++,a.hasAttribute(c)&&e--);d.push(a);a=a.nextSibling}while(0<e)}else d.push(a);return w(d)}function I(a,b,c){return function(d,e,f,g,h){e=B(e[0],b,c);return a(d,e,f,g,h)}}function H(a,c,d,e,f,g,m,n,p){function F(a,b,c,d){if(a){c&&(a=I(a,c,d));a.require=G.require;a.directiveName=C;if(L===G||G.$$isolateScope)a=
|
||||
tc(a,{isolateScope:!0});m.push(a)}if(b){c&&(b=I(b,c,d));b.require=G.require;b.directiveName=C;if(L===G||G.$$isolateScope)b=tc(b,{isolateScope:!0});n.push(b)}}function A(a,b,c,d){var e,f="data",g=!1;if(v(b)){for(;"^"==(e=b.charAt(0))||"?"==e;)b=b.substr(1),"^"==e&&(f="inheritedData"),g=g||"?"==e;e=null;d&&"data"===f&&(e=d[b]);e=e||c[f]("$"+b+"Controller");if(!e&&!g)throw ja("ctreq",b,a);}else J(b)&&(e=[],r(b,function(b){e.push(A(a,b,c,d))}));return e}function N(a,e,f,g,p){function F(a,b){var c;2>arguments.length&&
|
||||
(b=a,a=t);K&&(c=da);return p(a,b,c)}var u,M,z,O,I,B,da={},rb;u=c===f?d:ha(d,new Ob(w(f),d.$attr));M=u.$$element;if(L){var Na=/^\s*([@=&])(\??)\s*(\w*)\s*$/;B=e.$new(!0);!H||H!==L&&H!==L.$$originalDirective?M.data("$isolateScopeNoTemplate",B):M.data("$isolateScope",B);ca(M,"ng-isolate-scope");r(L.scope,function(a,c){var d=a.match(Na)||[],f=d[3]||c,g="?"==d[2],d=d[1],m,l,n,p;B.$$isolateBindings[c]=d+f;switch(d){case "@":u.$observe(f,function(a){B[c]=a});u.$$observers[f].$$scope=e;u[f]&&(B[c]=b(u[f])(e));
|
||||
break;case "=":if(g&&!u[f])break;l=q(u[f]);p=l.literal?Aa:function(a,b){return a===b||a!==a&&b!==b};n=l.assign||function(){m=B[c]=l(e);throw ja("nonassign",u[f],L.name);};m=B[c]=l(e);B.$watch(function(){var a=l(e);p(a,B[c])||(p(a,m)?n(e,a=B[c]):B[c]=a);return m=a},null,l.literal);break;case "&":l=q(u[f]);B[c]=function(a){return l(e,a)};break;default:throw ja("iscp",L.name,c,a);}})}rb=p&&F;R&&r(R,function(a){var b={$scope:a===L||a.$$isolateScope?B:e,$element:M,$attrs:u,$transclude:rb},c;I=a.controller;
|
||||
"@"==I&&(I=u[a.name]);c=s(I,b);da[a.name]=c;K||M.data("$"+a.name+"Controller",c);a.controllerAs&&(b.$scope[a.controllerAs]=c)});g=0;for(z=m.length;g<z;g++)try{O=m[g],O(O.isolateScope?B:e,M,u,O.require&&A(O.directiveName,O.require,M,da),rb)}catch(G){l(G,ia(M))}g=e;L&&(L.template||null===L.templateUrl)&&(g=B);a&&a(g,f.childNodes,t,p);for(g=n.length-1;0<=g;g--)try{O=n[g],O(O.isolateScope?B:e,M,u,O.require&&A(O.directiveName,O.require,M,da),rb)}catch(y){l(y,ia(M))}}p=p||{};for(var u=-Number.MAX_VALUE,
|
||||
O,R=p.controllerDirectives,L=p.newIsolateScopeDirective,H=p.templateDirective,fa=p.nonTlbTranscludeDirective,x=!1,D=!1,K=p.hasElementTranscludeDirective,Z=d.$$element=w(c),G,C,V,S=e,Q,Fa=0,qa=a.length;Fa<qa;Fa++){G=a[Fa];var U=G.$$start,Y=G.$$end;U&&(Z=B(c,U,Y));V=t;if(u>G.priority)break;if(V=G.scope)O=O||G,G.templateUrl||(db("new/isolated scope",L,G,Z),T(V)&&(L=G));C=G.name;!G.templateUrl&&G.controller&&(V=G.controller,R=R||{},db("'"+C+"' controller",R[C],G,Z),R[C]=G);if(V=G.transclude)x=!0,G.$$tlb||
|
||||
(db("transclusion",fa,G,Z),fa=G),"element"==V?(K=!0,u=G.priority,V=Z,Z=d.$$element=w(X.createComment(" "+C+": "+d[C]+" ")),c=Z[0],Na(f,Ba.call(V,0),c),S=z(V,e,u,g&&g.name,{nonTlbTranscludeDirective:fa})):(V=w(Kb(c)).contents(),Z.empty(),S=z(V,e));if(G.template)if(D=!0,db("template",H,G,Z),H=G,V=P(G.template)?G.template(Z,d):G.template,V=W(V),G.replace){g=G;V=Ib.test(V)?w(aa(V)):[];c=V[0];if(1!=V.length||1!==c.nodeType)throw ja("tplrt",C,"");Na(f,Z,c);qa={$attr:{}};V=da(c,[],qa);var $=a.splice(Fa+
|
||||
1,a.length-(Fa+1));L&&y(V);a=a.concat(V).concat($);E(d,qa);qa=a.length}else Z.html(V);if(G.templateUrl)D=!0,db("template",H,G,Z),H=G,G.replace&&(g=G),N=ue(a.splice(Fa,a.length-Fa),Z,d,f,x&&S,m,n,{controllerDirectives:R,newIsolateScopeDirective:L,templateDirective:H,nonTlbTranscludeDirective:fa}),qa=a.length;else if(G.compile)try{Q=G.compile(Z,d,S),P(Q)?F(null,Q,U,Y):Q&&F(Q.pre,Q.post,U,Y)}catch(ve){l(ve,ia(Z))}G.terminal&&(N.terminal=!0,u=Math.max(u,G.priority))}N.scope=O&&!0===O.scope;N.transcludeOnThisElement=
|
||||
x;N.templateOnThisElement=D;N.transclude=S;p.hasElementTranscludeDirective=K;return N}function y(a){for(var b=0,c=a.length;b<c;b++)a[b]=bc(a[b],{$$isolateScope:!0})}function fa(b,e,f,g,h,q,n){if(e===h)return null;h=null;if(c.hasOwnProperty(e)){var p;e=a.get(e+d);for(var s=0,u=e.length;s<u;s++)try{p=e[s],(g===t||g>p.priority)&&-1!=p.restrict.indexOf(f)&&(q&&(p=bc(p,{$$start:q,$$end:n})),b.push(p),h=p)}catch(F){l(F)}}return h}function E(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;r(a,function(d,e){"$"!=
|
||||
e.charAt(0)&&(b[e]&&b[e]!==d&&(d+=("style"===e?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});r(b,function(b,f){"class"==f?(ca(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):"style"==f?(e.attr("style",e.attr("style")+";"+b),a.style=(a.style?a.style+";":"")+b):"$"==f.charAt(0)||a.hasOwnProperty(f)||(a[f]=b,d[f]=c[f])})}function ue(a,b,c,d,e,f,g,h){var m=[],l,q,s=b[0],u=a.shift(),F=D({},u,{templateUrl:null,transclude:null,replace:null,$$originalDirective:u}),N=P(u.templateUrl)?u.templateUrl(b,c):u.templateUrl;
|
||||
b.empty();n.get(A.getTrustedResourceUrl(N),{cache:p}).success(function(n){var p,A;n=W(n);if(u.replace){n=Ib.test(n)?w(aa(n)):[];p=n[0];if(1!=n.length||1!==p.nodeType)throw ja("tplrt",u.name,N);n={$attr:{}};Na(d,b,p);var z=da(p,[],n);T(u.scope)&&y(z);a=z.concat(a);E(c,n)}else p=s,b.html(n);a.unshift(F);l=H(a,p,c,e,b,u,f,g,h);r(d,function(a,c){a==p&&(d[c]=b[0])});for(q=L(b[0].childNodes,e);m.length;){n=m.shift();A=m.shift();var R=m.shift(),I=m.shift(),z=b[0];if(A!==s){var B=A.className;h.hasElementTranscludeDirective&&
|
||||
u.replace||(z=Kb(p));Na(R,w(A),z);ca(w(z),B)}A=l.transcludeOnThisElement?O(n,l.transclude,I):I;l(q,n,z,d,A)}m=null}).error(function(a,b,c,d){throw ja("tpload",d.url);});return function(a,b,c,d,e){a=e;m?(m.push(b),m.push(c),m.push(d),m.push(a)):(l.transcludeOnThisElement&&(a=O(b,l.transclude,e)),l(q,b,c,d,a))}}function x(a,b){var c=b.priority-a.priority;return 0!==c?c:a.name!==b.name?a.name<b.name?-1:1:a.index-b.index}function db(a,b,c,d){if(b)throw ja("multidir",b.name,c.name,a,ia(d));}function K(a,
|
||||
c){var d=b(c,!0);d&&a.push({priority:0,compile:function(a){var b=a.parent().length;b&&ca(a.parent(),"ng-binding");return function(a,c){var e=c.parent(),f=e.data("$binding")||[];f.push(d);e.data("$binding",f);b||ca(e,"ng-binding");a.$watch(d,function(a){c[0].nodeValue=a})}}})}function C(a,b){if("srcdoc"==b)return A.HTML;var c=Ma(a);if("xlinkHref"==b||"FORM"==c&&"action"==b||"IMG"!=c&&("src"==b||"ngSrc"==b))return A.RESOURCE_URL}function S(a,c,d,e){var f=b(d,!0);if(f){if("multiple"===e&&"SELECT"===
|
||||
Ma(a))throw ja("selmulti",ia(a));c.push({priority:100,compile:function(){return{pre:function(c,d,m){d=m.$$observers||(m.$$observers={});if(g.test(e))throw ja("nodomevents");if(f=b(m[e],!0,C(a,e)))m[e]=f(c),(d[e]||(d[e]=[])).$$inter=!0,(m.$$observers&&m.$$observers[e].$$scope||c).$watch(f,function(a,b){"class"===e&&a!=b?m.$updateClass(a,b):m.$set(e,a)})}}}})}}function Na(a,b,c){var d=b[0],e=b.length,f=d.parentNode,g,m;if(a)for(g=0,m=a.length;g<m;g++)if(a[g]==d){a[g++]=c;m=g+e-1;for(var h=a.length;g<
|
||||
h;g++,m++)m<h?a[g]=a[m]:delete a[g];a.length-=e-1;break}f&&f.replaceChild(c,d);a=X.createDocumentFragment();a.appendChild(d);c[w.expando]=d[w.expando];d=1;for(e=b.length;d<e;d++)f=b[d],w(f).remove(),a.appendChild(f),delete b[d];b[0]=c;b.length=1}function tc(a,b){return D(function(){return a.apply(null,arguments)},a,b)}var Ob=function(a,b){this.$$element=a;this.$attr=b||{}};Ob.prototype={$normalize:pa,$addClass:function(a){a&&0<a.length&&N.addClass(this.$$element,a)},$removeClass:function(a){a&&0<
|
||||
a.length&&N.removeClass(this.$$element,a)},$updateClass:function(a,b){var c=uc(a,b),d=uc(b,a);0===c.length?N.removeClass(this.$$element,d):0===d.length?N.addClass(this.$$element,c):N.setClass(this.$$element,c,d)},$set:function(a,b,c,d){var e=qc(this.$$element[0],a);e&&(this.$$element.prop(a,b),d=e);this[a]=b;d?this.$attr[a]=d:(d=this.$attr[a])||(this.$attr[a]=d=mb(a,"-"));e=Ma(this.$$element);if("A"===e&&"href"===a||"IMG"===e&&"src"===a)this[a]=b=R(b,"src"===a);!1!==c&&(null===b||b===t?this.$$element.removeAttr(d):
|
||||
this.$$element.attr(d,b));(c=this.$$observers)&&r(c[a],function(a){try{a(b)}catch(c){l(c)}})},$observe:function(a,b){var c=this,d=c.$$observers||(c.$$observers={}),e=d[a]||(d[a]=[]);e.push(b);F.$evalAsync(function(){e.$$inter||b(c[a])});return b}};var qa=b.startSymbol(),Z=b.endSymbol(),W="{{"==qa||"}}"==Z?Qa:function(a){return a.replace(/\{\{/g,qa).replace(/}}/g,Z)},U=/^ngAttr[A-Z]/;return z}]}function pa(b){return Za(b.replace(we,""))}function uc(b,a){var c="",d=b.split(/\s+/),e=a.split(/\s+/),f=
|
||||
0;a:for(;f<d.length;f++){for(var g=d[f],k=0;k<e.length;k++)if(g==e[k])continue a;c+=(0<c.length?" ":"")+g}return c}function Pd(){var b={},a=/^(\S+)(\s+as\s+(\w+))?$/;this.register=function(a,d){Da(a,"controller");T(a)?D(b,a):b[a]=d};this.$get=["$injector","$window",function(c,d){return function(e,f){var g,k,m;v(e)&&(g=e.match(a),k=g[1],m=g[3],e=b.hasOwnProperty(k)?b[k]:hc(f.$scope,k,!0)||hc(d,k,!0),Wa(e,k,!0));g=c.instantiate(e,f);if(m){if(!f||"object"!==typeof f.$scope)throw C("$controller")("noscp",
|
||||
k||e.name,m);f.$scope[m]=g}return g}}]}function Qd(){this.$get=["$window",function(b){return w(b.document)}]}function Rd(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b,arguments)}}]}function vc(b){var a={},c,d,e;if(!b)return a;r(b.split("\n"),function(b){e=b.indexOf(":");c=K(aa(b.substr(0,e)));d=aa(b.substr(e+1));c&&(a[c]=a[c]?a[c]+", "+d:d)});return a}function wc(b){var a=T(b)?b:t;return function(c){a||(a=vc(b));return c?a[K(c)]||null:a}}function xc(b,a,c){if(P(c))return c(b,
|
||||
a);r(c,function(c){b=c(b,a)});return b}function Ud(){var b=/^\s*(\[|\{[^\{])/,a=/[\}\]]\s*$/,c=/^\)\]\}',?\n/,d={"Content-Type":"application/json;charset=utf-8"},e=this.defaults={transformResponse:[function(d){v(d)&&(d=d.replace(c,""),b.test(d)&&a.test(d)&&(d=cc(d)));return d}],transformRequest:[function(a){return T(a)&&"[object File]"!==za.call(a)&&"[object Blob]"!==za.call(a)?na(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:ha(d),put:ha(d),patch:ha(d)},xsrfCookieName:"XSRF-TOKEN",
|
||||
xsrfHeaderName:"X-XSRF-TOKEN"},f=this.interceptors=[],g=this.responseInterceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(a,b,c,d,n,p){function q(a){function b(a){var d=D({},a,{data:xc(a.data,a.headers,c.transformResponse)});return 200<=a.status&&300>a.status?d:n.reject(d)}var c={method:"get",transformRequest:e.transformRequest,transformResponse:e.transformResponse},d=function(a){var b=e.headers,c=D({},a.headers),d,f,b=D({},b.common,b[K(a.method)]);
|
||||
a:for(d in b){a=K(d);for(f in c)if(K(f)===a)continue a;c[d]=b[d]}(function(a){var b;r(a,function(c,d){P(c)&&(b=c(),null!=b?a[d]=b:delete a[d])})})(c);return c}(a);D(c,a);c.headers=d;c.method=Ia(c.method);var f=[function(a){d=a.headers;var c=xc(a.data,wc(d),a.transformRequest);x(c)&&r(d,function(a,b){"content-type"===K(b)&&delete d[b]});x(a.withCredentials)&&!x(e.withCredentials)&&(a.withCredentials=e.withCredentials);return s(a,c,d).then(b,b)},t],g=n.when(c);for(r(A,function(a){(a.request||a.requestError)&&
|
||||
f.unshift(a.request,a.requestError);(a.response||a.responseError)&&f.push(a.response,a.responseError)});f.length;){a=f.shift();var m=f.shift(),g=g.then(a,m)}g.success=function(a){g.then(function(b){a(b.data,b.status,b.headers,c)});return g};g.error=function(a){g.then(null,function(b){a(b.data,b.status,b.headers,c)});return g};return g}function s(c,f,g){function h(a,b,c,e){I&&(200<=a&&300>a?I.put(w,[a,b,vc(c),e]):I.remove(w));p(b,a,c,e);d.$$phase||d.$apply()}function p(a,b,d,e){b=Math.max(b,0);(200<=
|
||||
b&&300>b?A.resolve:A.reject)({data:a,status:b,headers:wc(d),config:c,statusText:e})}function s(){var a=Ra(q.pendingRequests,c);-1!==a&&q.pendingRequests.splice(a,1)}var A=n.defer(),r=A.promise,I,H,w=F(c.url,c.params);q.pendingRequests.push(c);r.then(s,s);!c.cache&&!e.cache||(!1===c.cache||"GET"!==c.method&&"JSONP"!==c.method)||(I=T(c.cache)?c.cache:T(e.cache)?e.cache:u);if(I)if(H=I.get(w),y(H)){if(H&&P(H.then))return H.then(s,s),H;J(H)?p(H[1],H[0],ha(H[2]),H[3]):p(H,200,{},"OK")}else I.put(w,r);x(H)&&
|
||||
((H=Pb(c.url)?b.cookies()[c.xsrfCookieName||e.xsrfCookieName]:t)&&(g[c.xsrfHeaderName||e.xsrfHeaderName]=H),a(c.method,w,f,h,g,c.timeout,c.withCredentials,c.responseType));return r}function F(a,b){if(!b)return a;var c=[];Tc(b,function(a,b){null===a||x(a)||(J(a)||(a=[a]),r(a,function(a){T(a)&&(a=ta(a)?a.toISOString():na(a));c.push(Ca(b)+"="+Ca(a))}))});0<c.length&&(a+=(-1==a.indexOf("?")?"?":"&")+c.join("&"));return a}var u=c("$http"),A=[];r(f,function(a){A.unshift(v(a)?p.get(a):p.invoke(a))});r(g,
|
||||
function(a,b){var c=v(a)?p.get(a):p.invoke(a);A.splice(b,0,{response:function(a){return c(n.when(a))},responseError:function(a){return c(n.reject(a))}})});q.pendingRequests=[];(function(a){r(arguments,function(a){q[a]=function(b,c){return q(D(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){r(arguments,function(a){q[a]=function(b,c,d){return q(D(d||{},{method:a,url:b,data:c}))}})})("post","put");q.defaults=e;return q}]}function xe(b){if(8>=Q&&(!b.match(/^(get|post|head|put|delete|options)$/i)||
|
||||
!W.XMLHttpRequest))return new W.ActiveXObject("Microsoft.XMLHTTP");if(W.XMLHttpRequest)return new W.XMLHttpRequest;throw C("$httpBackend")("noxhr");}function Vd(){this.$get=["$browser","$window","$document",function(b,a,c){return ye(b,xe,b.defer,a.angular.callbacks,c[0])}]}function ye(b,a,c,d,e){function f(a,b,c){var f=e.createElement("script"),g=null;f.type="text/javascript";f.src=a;f.async=!0;g=function(a){$a(f,"load",g);$a(f,"error",g);e.body.removeChild(f);f=null;var k=-1,s="unknown";a&&("load"!==
|
||||
a.type||d[b].called||(a={type:"error"}),s=a.type,k="error"===a.type?404:200);c&&c(k,s)};sb(f,"load",g);sb(f,"error",g);8>=Q&&(f.onreadystatechange=function(){v(f.readyState)&&/loaded|complete/.test(f.readyState)&&(f.onreadystatechange=null,g({type:"load"}))});e.body.appendChild(f);return g}var g=-1;return function(e,m,h,l,n,p,q,s){function F(){A=g;R&&R();z&&z.abort()}function u(a,d,e,f,g){L&&c.cancel(L);R=z=null;0===d&&(d=e?200:"file"==ua(m).protocol?404:0);a(1223===d?204:d,e,f,g||"");b.$$completeOutstandingRequest(E)}
|
||||
var A;b.$$incOutstandingRequestCount();m=m||b.url();if("jsonp"==K(e)){var N="_"+(d.counter++).toString(36);d[N]=function(a){d[N].data=a;d[N].called=!0};var R=f(m.replace("JSON_CALLBACK","angular.callbacks."+N),N,function(a,b){u(l,a,d[N].data,"",b);d[N]=E})}else{var z=a(e);z.open(e,m,!0);r(n,function(a,b){y(a)&&z.setRequestHeader(b,a)});z.onreadystatechange=function(){if(z&&4==z.readyState){var a=null,b=null,c="";A!==g&&(a=z.getAllResponseHeaders(),b="response"in z?z.response:z.responseText);A===g&&
|
||||
10>Q||(c=z.statusText);u(l,A||z.status,b,a,c)}};q&&(z.withCredentials=!0);if(s)try{z.responseType=s}catch(ca){if("json"!==s)throw ca;}z.send(h||null)}if(0<p)var L=c(F,p);else p&&P(p.then)&&p.then(F)}}function Sd(){var b="{{",a="}}";this.startSymbol=function(a){return a?(b=a,this):b};this.endSymbol=function(b){return b?(a=b,this):a};this.$get=["$parse","$exceptionHandler","$sce",function(c,d,e){function f(f,h,l){for(var n,p,q=0,s=[],F=f.length,u=!1,A=[];q<F;)-1!=(n=f.indexOf(b,q))&&-1!=(p=f.indexOf(a,
|
||||
n+g))?(q!=n&&s.push(f.substring(q,n)),s.push(q=c(u=f.substring(n+g,p))),q.exp=u,q=p+k,u=!0):(q!=F&&s.push(f.substring(q)),q=F);(F=s.length)||(s.push(""),F=1);if(l&&1<s.length)throw yc("noconcat",f);if(!h||u)return A.length=F,q=function(a){try{for(var b=0,c=F,g;b<c;b++){if("function"==typeof(g=s[b]))if(g=g(a),g=l?e.getTrusted(l,g):e.valueOf(g),null==g)g="";else switch(typeof g){case "string":break;case "number":g=""+g;break;default:g=na(g)}A[b]=g}return A.join("")}catch(k){a=yc("interr",f,k.toString()),
|
||||
d(a)}},q.exp=f,q.parts=s,q}var g=b.length,k=a.length;f.startSymbol=function(){return b};f.endSymbol=function(){return a};return f}]}function Td(){this.$get=["$rootScope","$window","$q",function(b,a,c){function d(d,g,k,m){var h=a.setInterval,l=a.clearInterval,n=c.defer(),p=n.promise,q=0,s=y(m)&&!m;k=y(k)?k:0;p.then(null,null,d);p.$$intervalId=h(function(){n.notify(q++);0<k&&q>=k&&(n.resolve(q),l(p.$$intervalId),delete e[p.$$intervalId]);s||b.$apply()},g);e[p.$$intervalId]=n;return p}var e={};d.cancel=
|
||||
function(b){return b&&b.$$intervalId in e?(e[b.$$intervalId].reject("canceled"),a.clearInterval(b.$$intervalId),delete e[b.$$intervalId],!0):!1};return d}]}function bd(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January February March April May June July August September October November December".split(" "),
|
||||
SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return 1===b?"one":"other"}}}}function Qb(b){b=b.split("/");for(var a=b.length;a--;)b[a]=
|
||||
lb(b[a]);return b.join("/")}function zc(b,a,c){b=ua(b,c);a.$$protocol=b.protocol;a.$$host=b.hostname;a.$$port=U(b.port)||ze[b.protocol]||null}function Ac(b,a,c){var d="/"!==b.charAt(0);d&&(b="/"+b);b=ua(b,c);a.$$path=decodeURIComponent(d&&"/"===b.pathname.charAt(0)?b.pathname.substring(1):b.pathname);a.$$search=ec(b.search);a.$$hash=decodeURIComponent(b.hash);a.$$path&&"/"!=a.$$path.charAt(0)&&(a.$$path="/"+a.$$path)}function ra(b,a){if(0===a.indexOf(b))return a.substr(b.length)}function eb(b){var a=
|
||||
b.indexOf("#");return-1==a?b:b.substr(0,a)}function Rb(b){return b.substr(0,eb(b).lastIndexOf("/")+1)}function Bc(b,a){this.$$html5=!0;a=a||"";var c=Rb(b);zc(b,this,b);this.$$parse=function(a){var e=ra(c,a);if(!v(e))throw Sb("ipthprfx",a,c);Ac(e,this,b);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=Cb(this.$$search),b=this.$$hash?"#"+lb(this.$$hash):"";this.$$url=Qb(this.$$path)+(a?"?"+a:"")+b;this.$$absUrl=c+this.$$url.substr(1)};this.$$rewrite=function(d){var e;
|
||||
if((e=ra(b,d))!==t)return d=e,(e=ra(a,e))!==t?c+(ra("/",e)||e):b+d;if((e=ra(c,d))!==t)return c+e;if(c==d+"/")return c}}function Tb(b,a){var c=Rb(b);zc(b,this,b);this.$$parse=function(d){var e=ra(b,d)||ra(c,d),e="#"==e.charAt(0)?ra(a,e):this.$$html5?e:"";if(!v(e))throw Sb("ihshprfx",d,a);Ac(e,this,b);d=this.$$path;var f=/^\/[A-Z]:(\/.*)/;0===e.indexOf(b)&&(e=e.replace(b,""));f.exec(e)||(d=(e=f.exec(d))?e[1]:d);this.$$path=d;this.$$compose()};this.$$compose=function(){var c=Cb(this.$$search),e=this.$$hash?
|
||||
"#"+lb(this.$$hash):"";this.$$url=Qb(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+(this.$$url?a+this.$$url:"")};this.$$rewrite=function(a){if(eb(b)==eb(a))return a}}function Ub(b,a){this.$$html5=!0;Tb.apply(this,arguments);var c=Rb(b);this.$$rewrite=function(d){var e;if(b==eb(d))return d;if(e=ra(c,d))return b+a+e;if(c===d+"/")return c};this.$$compose=function(){var c=Cb(this.$$search),e=this.$$hash?"#"+lb(this.$$hash):"";this.$$url=Qb(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+a+this.$$url}}function tb(b){return function(){return this[b]}}
|
||||
function Cc(b,a){return function(c){if(x(c))return this[b];this[b]=a(c);this.$$compose();return this}}function Wd(){var b="",a=!1;this.hashPrefix=function(a){return y(a)?(b=a,this):b};this.html5Mode=function(b){return y(b)?(a=b,this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(c,d,e,f){function g(a){c.$broadcast("$locationChangeSuccess",k.absUrl(),a)}var k,m,h=d.baseHref(),l=d.url(),n;a?(n=l.substring(0,l.indexOf("/",l.indexOf("//")+2))+(h||"/"),m=e.history?Bc:Ub):(n=
|
||||
eb(l),m=Tb);k=new m(n,"#"+b);k.$$parse(k.$$rewrite(l));var p=/^\s*(javascript|mailto):/i;f.on("click",function(a){if(!a.ctrlKey&&!a.metaKey&&2!=a.which){for(var e=w(a.target);"a"!==K(e[0].nodeName);)if(e[0]===f[0]||!(e=e.parent())[0])return;var g=e.prop("href");T(g)&&"[object SVGAnimatedString]"===g.toString()&&(g=ua(g.animVal).href);if(!p.test(g)){if(m===Ub){var h=e.attr("href")||e.attr("xlink:href");if(h&&0>h.indexOf("://"))if(g="#"+b,"/"==h[0])g=n+g+h;else if("#"==h[0])g=n+g+(k.path()||"/")+h;
|
||||
else{var l=k.path().split("/"),h=h.split("/");2!==l.length||l[1]||(l.length=1);for(var q=0;q<h.length;q++)"."!=h[q]&&(".."==h[q]?l.pop():h[q].length&&l.push(h[q]));g=n+g+l.join("/")}}l=k.$$rewrite(g);g&&(!e.attr("target")&&l&&!a.isDefaultPrevented())&&(a.preventDefault(),l!=d.url()&&(k.$$parse(l),c.$apply(),W.angular["ff-684208-preventDefault"]=!0))}}});k.absUrl()!=l&&d.url(k.absUrl(),!0);d.onUrlChange(function(a){k.absUrl()!=a&&(c.$evalAsync(function(){var b=k.absUrl();k.$$parse(a);c.$broadcast("$locationChangeStart",
|
||||
a,b).defaultPrevented?(k.$$parse(b),d.url(b)):g(b)}),c.$$phase||c.$digest())});var q=0;c.$watch(function(){var a=d.url(),b=k.$$replace;q&&a==k.absUrl()||(q++,c.$evalAsync(function(){c.$broadcast("$locationChangeStart",k.absUrl(),a).defaultPrevented?k.$$parse(a):(d.url(k.absUrl(),b),g(a))}));k.$$replace=!1;return q});return k}]}function Xd(){var b=!0,a=this;this.debugEnabled=function(a){return y(a)?(b=a,this):b};this.$get=["$window",function(c){function d(a){a instanceof Error&&(a.stack?a=a.message&&
|
||||
-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=c.console||{},e=b[a]||b.log||E;a=!1;try{a=!!e.apply}catch(m){}return a?function(){var a=[];r(arguments,function(b){a.push(d(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){b&&c.apply(a,arguments)}}()}}]}function ka(b,
|
||||
a){if("__defineGetter__"===b||"__defineSetter__"===b||"__lookupGetter__"===b||"__lookupSetter__"===b||"__proto__"===b)throw la("isecfld",a);return b}function va(b,a){if(b){if(b.constructor===b)throw la("isecfn",a);if(b.document&&b.location&&b.alert&&b.setInterval)throw la("isecwindow",a);if(b.children&&(b.nodeName||b.prop&&b.attr&&b.find))throw la("isecdom",a);if(b===Object)throw la("isecobj",a);}return b}function ub(b,a,c,d,e){va(b,d);e=e||{};a=a.split(".");for(var f,g=0;1<a.length;g++){f=ka(a.shift(),
|
||||
d);var k=va(b[f],d);k||(k={},b[f]=k);b=k;b.then&&e.unwrapPromises&&(wa(d),"$$v"in b||function(a){a.then(function(b){a.$$v=b})}(b),b.$$v===t&&(b.$$v={}),b=b.$$v)}f=ka(a.shift(),d);va(b[f],d);return b[f]=c}function Dc(b,a,c,d,e,f,g){ka(b,f);ka(a,f);ka(c,f);ka(d,f);ka(e,f);return g.unwrapPromises?function(g,m){var h=m&&m.hasOwnProperty(b)?m:g,l;if(null==h)return h;(h=h[b])&&h.then&&(wa(f),"$$v"in h||(l=h,l.$$v=t,l.then(function(a){l.$$v=a})),h=h.$$v);if(!a)return h;if(null==h)return t;(h=h[a])&&h.then&&
|
||||
(wa(f),"$$v"in h||(l=h,l.$$v=t,l.then(function(a){l.$$v=a})),h=h.$$v);if(!c)return h;if(null==h)return t;(h=h[c])&&h.then&&(wa(f),"$$v"in h||(l=h,l.$$v=t,l.then(function(a){l.$$v=a})),h=h.$$v);if(!d)return h;if(null==h)return t;(h=h[d])&&h.then&&(wa(f),"$$v"in h||(l=h,l.$$v=t,l.then(function(a){l.$$v=a})),h=h.$$v);if(!e)return h;if(null==h)return t;(h=h[e])&&h.then&&(wa(f),"$$v"in h||(l=h,l.$$v=t,l.then(function(a){l.$$v=a})),h=h.$$v);return h}:function(f,g){var h=g&&g.hasOwnProperty(b)?g:f;if(null==
|
||||
h)return h;h=h[b];if(!a)return h;if(null==h)return t;h=h[a];if(!c)return h;if(null==h)return t;h=h[c];if(!d)return h;if(null==h)return t;h=h[d];return e?null==h?t:h=h[e]:h}}function Ec(b,a,c){if(Vb.hasOwnProperty(b))return Vb[b];var d=b.split("."),e=d.length,f;if(a.csp)f=6>e?Dc(d[0],d[1],d[2],d[3],d[4],c,a):function(b,f){var g=0,k;do k=Dc(d[g++],d[g++],d[g++],d[g++],d[g++],c,a)(b,f),f=t,b=k;while(g<e);return k};else{var g="var p;\n";r(d,function(b,d){ka(b,c);g+="if(s == null) return undefined;\ns="+
|
||||
(d?"s":'((k&&k.hasOwnProperty("'+b+'"))?k:s)')+'["'+b+'"];\n'+(a.unwrapPromises?'if (s && s.then) {\n pw("'+c.replace(/(["\r\n])/g,"\\$1")+'");\n if (!("$$v" in s)) {\n p=s;\n p.$$v = undefined;\n p.then(function(v) {p.$$v=v;});\n}\n s=s.$$v\n}\n':"")});var g=g+"return s;",k=new Function("s","k","pw",g);k.toString=ba(g);f=a.unwrapPromises?function(a,b){return k(a,b,wa)}:k}"hasOwnProperty"!==b&&(Vb[b]=f);return f}function Yd(){var b={},a={csp:!1,unwrapPromises:!1,logPromiseWarnings:!0};this.unwrapPromises=
|
||||
function(b){return y(b)?(a.unwrapPromises=!!b,this):a.unwrapPromises};this.logPromiseWarnings=function(b){return y(b)?(a.logPromiseWarnings=b,this):a.logPromiseWarnings};this.$get=["$filter","$sniffer","$log",function(c,d,e){a.csp=d.csp;wa=function(b){a.logPromiseWarnings&&!Fc.hasOwnProperty(b)&&(Fc[b]=!0,e.warn("[$parse] Promise found in the expression `"+b+"`. Automatic unwrapping of promises in Angular expressions is deprecated."))};return function(d){var e;switch(typeof d){case "string":if(b.hasOwnProperty(d))return b[d];
|
||||
e=new Wb(a);e=(new fb(e,c,a)).parse(d);"hasOwnProperty"!==d&&(b[d]=e);return e;case "function":return d;default:return E}}}]}function $d(){this.$get=["$rootScope","$exceptionHandler",function(b,a){return Ae(function(a){b.$evalAsync(a)},a)}]}function Ae(b,a){function c(a){return a}function d(a){return g(a)}var e=function(){var g=[],h,l;return l={resolve:function(a){if(g){var c=g;g=t;h=f(a);c.length&&b(function(){for(var a,b=0,d=c.length;b<d;b++)a=c[b],h.then(a[0],a[1],a[2])})}},reject:function(a){l.resolve(k(a))},
|
||||
notify:function(a){if(g){var c=g;g.length&&b(function(){for(var b,d=0,e=c.length;d<e;d++)b=c[d],b[2](a)})}},promise:{then:function(b,f,k){var l=e(),F=function(d){try{l.resolve((P(b)?b:c)(d))}catch(e){l.reject(e),a(e)}},u=function(b){try{l.resolve((P(f)?f:d)(b))}catch(c){l.reject(c),a(c)}},A=function(b){try{l.notify((P(k)?k:c)(b))}catch(d){a(d)}};g?g.push([F,u,A]):h.then(F,u,A);return l.promise},"catch":function(a){return this.then(null,a)},"finally":function(a){function b(a,c){var d=e();c?d.resolve(a):
|
||||
d.reject(a);return d.promise}function d(e,f){var g=null;try{g=(a||c)()}catch(k){return b(k,!1)}return g&&P(g.then)?g.then(function(){return b(e,f)},function(a){return b(a,!1)}):b(e,f)}return this.then(function(a){return d(a,!0)},function(a){return d(a,!1)})}}}},f=function(a){return a&&P(a.then)?a:{then:function(c){var d=e();b(function(){d.resolve(c(a))});return d.promise}}},g=function(a){var b=e();b.reject(a);return b.promise},k=function(c){return{then:function(f,g){var k=e();b(function(){try{k.resolve((P(g)?
|
||||
g:d)(c))}catch(b){k.reject(b),a(b)}});return k.promise}}};return{defer:e,reject:g,when:function(k,h,l,n){var p=e(),q,s=function(b){try{return(P(h)?h:c)(b)}catch(d){return a(d),g(d)}},F=function(b){try{return(P(l)?l:d)(b)}catch(c){return a(c),g(c)}},u=function(b){try{return(P(n)?n:c)(b)}catch(d){a(d)}};b(function(){f(k).then(function(a){q||(q=!0,p.resolve(f(a).then(s,F,u)))},function(a){q||(q=!0,p.resolve(F(a)))},function(a){q||p.notify(u(a))})});return p.promise},all:function(a){var b=e(),c=0,d=J(a)?
|
||||
[]:{};r(a,function(a,e){c++;f(a).then(function(a){d.hasOwnProperty(e)||(d[e]=a,--c||b.resolve(d))},function(a){d.hasOwnProperty(e)||b.reject(a)})});0===c&&b.resolve(d);return b.promise}}}function ge(){this.$get=["$window","$timeout",function(b,a){var c=b.requestAnimationFrame||b.webkitRequestAnimationFrame||b.mozRequestAnimationFrame,d=b.cancelAnimationFrame||b.webkitCancelAnimationFrame||b.mozCancelAnimationFrame||b.webkitCancelRequestAnimationFrame,e=!!c,f=e?function(a){var b=c(a);return function(){d(b)}}:
|
||||
function(b){var c=a(b,16.66,!1);return function(){a.cancel(c)}};f.supported=e;return f}]}function Zd(){var b=10,a=C("$rootScope"),c=null;this.digestTtl=function(a){arguments.length&&(b=a);return b};this.$get=["$injector","$exceptionHandler","$parse","$browser",function(d,e,f,g){function k(){this.$id=hb();this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;this["this"]=this.$root=this;this.$$destroyed=!1;this.$$asyncQueue=[];this.$$postDigestQueue=
|
||||
[];this.$$listeners={};this.$$listenerCount={};this.$$isolateBindings={}}function m(b){if(p.$$phase)throw a("inprog",p.$$phase);p.$$phase=b}function h(a,b){var c=f(a);Wa(c,b);return c}function l(a,b,c){do a.$$listenerCount[c]-=b,0===a.$$listenerCount[c]&&delete a.$$listenerCount[c];while(a=a.$parent)}function n(){}k.prototype={constructor:k,$new:function(a){a?(a=new k,a.$root=this.$root,a.$$asyncQueue=this.$$asyncQueue,a.$$postDigestQueue=this.$$postDigestQueue):(this.$$childScopeClass||(this.$$childScopeClass=
|
||||
function(){this.$$watchers=this.$$nextSibling=this.$$childHead=this.$$childTail=null;this.$$listeners={};this.$$listenerCount={};this.$id=hb();this.$$childScopeClass=null},this.$$childScopeClass.prototype=this),a=new this.$$childScopeClass);a["this"]=a;a.$parent=this;a.$$prevSibling=this.$$childTail;this.$$childHead?this.$$childTail=this.$$childTail.$$nextSibling=a:this.$$childHead=this.$$childTail=a;return a},$watch:function(a,b,d){var e=h(a,"watch"),f=this.$$watchers,g={fn:b,last:n,get:e,exp:a,
|
||||
eq:!!d};c=null;if(!P(b)){var k=h(b||E,"listener");g.fn=function(a,b,c){k(c)}}if("string"==typeof a&&e.constant){var l=g.fn;g.fn=function(a,b,c){l.call(this,a,b,c);Sa(f,g)}}f||(f=this.$$watchers=[]);f.unshift(g);return function(){Sa(f,g);c=null}},$watchCollection:function(a,b){var c=this,d,e,g,k=1<b.length,h=0,l=f(a),m=[],p={},n=!0,r=0;return this.$watch(function(){d=l(c);var a,b,f;if(T(d))if(Pa(d))for(e!==m&&(e=m,r=e.length=0,h++),a=d.length,r!==a&&(h++,e.length=r=a),b=0;b<a;b++)f=e[b]!==e[b]&&d[b]!==
|
||||
d[b],f||e[b]===d[b]||(h++,e[b]=d[b]);else{e!==p&&(e=p={},r=0,h++);a=0;for(b in d)d.hasOwnProperty(b)&&(a++,e.hasOwnProperty(b)?(f=e[b]!==e[b]&&d[b]!==d[b],f||e[b]===d[b]||(h++,e[b]=d[b])):(r++,e[b]=d[b],h++));if(r>a)for(b in h++,e)e.hasOwnProperty(b)&&!d.hasOwnProperty(b)&&(r--,delete e[b])}else e!==d&&(e=d,h++);return h},function(){n?(n=!1,b(d,d,c)):b(d,g,c);if(k)if(T(d))if(Pa(d)){g=Array(d.length);for(var a=0;a<d.length;a++)g[a]=d[a]}else for(a in g={},d)kb.call(d,a)&&(g[a]=d[a]);else g=d})},$digest:function(){var d,
|
||||
f,k,h,l=this.$$asyncQueue,r=this.$$postDigestQueue,R,z,t=b,L,O=[],w,B,I;m("$digest");g.$$checkUrlChange();c=null;do{z=!1;for(L=this;l.length;){try{I=l.shift(),I.scope.$eval(I.expression)}catch(H){p.$$phase=null,e(H)}c=null}a:do{if(h=L.$$watchers)for(R=h.length;R--;)try{if(d=h[R])if((f=d.get(L))!==(k=d.last)&&!(d.eq?Aa(f,k):"number"===typeof f&&"number"===typeof k&&isNaN(f)&&isNaN(k)))z=!0,c=d,d.last=d.eq?Ha(f,null):f,d.fn(f,k===n?f:k,L),5>t&&(w=4-t,O[w]||(O[w]=[]),B=P(d.exp)?"fn: "+(d.exp.name||d.exp.toString()):
|
||||
d.exp,B+="; newVal: "+na(f)+"; oldVal: "+na(k),O[w].push(B));else if(d===c){z=!1;break a}}catch(y){p.$$phase=null,e(y)}if(!(h=L.$$childHead||L!==this&&L.$$nextSibling))for(;L!==this&&!(h=L.$$nextSibling);)L=L.$parent}while(L=h);if((z||l.length)&&!t--)throw p.$$phase=null,a("infdig",b,na(O));}while(z||l.length);for(p.$$phase=null;r.length;)try{r.shift()()}catch(v){e(v)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;this!==p&&(r(this.$$listenerCount,
|
||||
Bb(null,l,this)),a.$$childHead==this&&(a.$$childHead=this.$$nextSibling),a.$$childTail==this&&(a.$$childTail=this.$$prevSibling),this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling),this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling),this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=this.$root=null,this.$$listeners={},this.$$watchers=this.$$asyncQueue=this.$$postDigestQueue=[],this.$destroy=this.$digest=this.$apply=E,this.$on=
|
||||
this.$watch=function(){return E})}},$eval:function(a,b){return f(a)(this,b)},$evalAsync:function(a){p.$$phase||p.$$asyncQueue.length||g.defer(function(){p.$$asyncQueue.length&&p.$digest()});this.$$asyncQueue.push({scope:this,expression:a})},$$postDigest:function(a){this.$$postDigestQueue.push(a)},$apply:function(a){try{return m("$apply"),this.$eval(a)}catch(b){e(b)}finally{p.$$phase=null;try{p.$digest()}catch(c){throw e(c),c;}}},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=
|
||||
c=[]);c.push(b);var d=this;do d.$$listenerCount[a]||(d.$$listenerCount[a]=0),d.$$listenerCount[a]++;while(d=d.$parent);var e=this;return function(){c[Ra(c,b)]=null;l(e,1,a)}},$emit:function(a,b){var c=[],d,f=this,g=!1,k={name:a,targetScope:f,stopPropagation:function(){g=!0},preventDefault:function(){k.defaultPrevented=!0},defaultPrevented:!1},h=[k].concat(Ba.call(arguments,1)),l,m;do{d=f.$$listeners[a]||c;k.currentScope=f;l=0;for(m=d.length;l<m;l++)if(d[l])try{d[l].apply(null,h)}catch(p){e(p)}else d.splice(l,
|
||||
1),l--,m--;if(g)break;f=f.$parent}while(f);return k},$broadcast:function(a,b){for(var c=this,d=this,f={name:a,targetScope:this,preventDefault:function(){f.defaultPrevented=!0},defaultPrevented:!1},g=[f].concat(Ba.call(arguments,1)),k,h;c=d;){f.currentScope=c;d=c.$$listeners[a]||[];k=0;for(h=d.length;k<h;k++)if(d[k])try{d[k].apply(null,g)}catch(l){e(l)}else d.splice(k,1),k--,h--;if(!(d=c.$$listenerCount[a]&&c.$$childHead||c!==this&&c.$$nextSibling))for(;c!==this&&!(d=c.$$nextSibling);)c=c.$parent}return f}};
|
||||
var p=new k;return p}]}function cd(){var b=/^\s*(https?|ftp|mailto|tel|file):/,a=/^\s*((https?|ftp|file):|data:image\/)/;this.aHrefSanitizationWhitelist=function(a){return y(a)?(b=a,this):b};this.imgSrcSanitizationWhitelist=function(b){return y(b)?(a=b,this):a};this.$get=function(){return function(c,d){var e=d?a:b,f;if(!Q||8<=Q)if(f=ua(c).href,""!==f&&!f.match(e))return"unsafe:"+f;return c}}}function Be(b){if("self"===b)return b;if(v(b)){if(-1<b.indexOf("***"))throw xa("iwcard",b);b=b.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g,
|
||||
"\\$1").replace(/\x08/g,"\\x08").replace("\\*\\*",".*").replace("\\*","[^:/.?&;]*");return RegExp("^"+b+"$")}if(jb(b))return RegExp("^"+b.source+"$");throw xa("imatcher");}function Gc(b){var a=[];y(b)&&r(b,function(b){a.push(Be(b))});return a}function be(){this.SCE_CONTEXTS=ga;var b=["self"],a=[];this.resourceUrlWhitelist=function(a){arguments.length&&(b=Gc(a));return b};this.resourceUrlBlacklist=function(b){arguments.length&&(a=Gc(b));return a};this.$get=["$injector",function(c){function d(a){var b=
|
||||
function(a){this.$$unwrapTrustedValue=function(){return a}};a&&(b.prototype=new a);b.prototype.valueOf=function(){return this.$$unwrapTrustedValue()};b.prototype.toString=function(){return this.$$unwrapTrustedValue().toString()};return b}var e=function(a){throw xa("unsafe");};c.has("$sanitize")&&(e=c.get("$sanitize"));var f=d(),g={};g[ga.HTML]=d(f);g[ga.CSS]=d(f);g[ga.URL]=d(f);g[ga.JS]=d(f);g[ga.RESOURCE_URL]=d(g[ga.URL]);return{trustAs:function(a,b){var c=g.hasOwnProperty(a)?g[a]:null;if(!c)throw xa("icontext",
|
||||
a,b);if(null===b||b===t||""===b)return b;if("string"!==typeof b)throw xa("itype",a);return new c(b)},getTrusted:function(c,d){if(null===d||d===t||""===d)return d;var f=g.hasOwnProperty(c)?g[c]:null;if(f&&d instanceof f)return d.$$unwrapTrustedValue();if(c===ga.RESOURCE_URL){var f=ua(d.toString()),l,n,p=!1;l=0;for(n=b.length;l<n;l++)if("self"===b[l]?Pb(f):b[l].exec(f.href)){p=!0;break}if(p)for(l=0,n=a.length;l<n;l++)if("self"===a[l]?Pb(f):a[l].exec(f.href)){p=!1;break}if(p)return d;throw xa("insecurl",
|
||||
d.toString());}if(c===ga.HTML)return e(d);throw xa("unsafe");},valueOf:function(a){return a instanceof f?a.$$unwrapTrustedValue():a}}}]}function ae(){var b=!0;this.enabled=function(a){arguments.length&&(b=!!a);return b};this.$get=["$parse","$sniffer","$sceDelegate",function(a,c,d){if(b&&c.msie&&8>c.msieDocumentMode)throw xa("iequirks");var e=ha(ga);e.isEnabled=function(){return b};e.trustAs=d.trustAs;e.getTrusted=d.getTrusted;e.valueOf=d.valueOf;b||(e.trustAs=e.getTrusted=function(a,b){return b},
|
||||
e.valueOf=Qa);e.parseAs=function(b,c){var d=a(c);return d.literal&&d.constant?d:function(a,c){return e.getTrusted(b,d(a,c))}};var f=e.parseAs,g=e.getTrusted,k=e.trustAs;r(ga,function(a,b){var c=K(b);e[Za("parse_as_"+c)]=function(b){return f(a,b)};e[Za("get_trusted_"+c)]=function(b){return g(a,b)};e[Za("trust_as_"+c)]=function(b){return k(a,b)}});return e}]}function ce(){this.$get=["$window","$document",function(b,a){var c={},d=U((/android (\d+)/.exec(K((b.navigator||{}).userAgent))||[])[1]),e=/Boxee/i.test((b.navigator||
|
||||
{}).userAgent),f=a[0]||{},g=f.documentMode,k,m=/^(Moz|webkit|O|ms)(?=[A-Z])/,h=f.body&&f.body.style,l=!1,n=!1;if(h){for(var p in h)if(l=m.exec(p)){k=l[0];k=k.substr(0,1).toUpperCase()+k.substr(1);break}k||(k="WebkitOpacity"in h&&"webkit");l=!!("transition"in h||k+"Transition"in h);n=!!("animation"in h||k+"Animation"in h);!d||l&&n||(l=v(f.body.style.webkitTransition),n=v(f.body.style.webkitAnimation))}return{history:!(!b.history||!b.history.pushState||4>d||e),hashchange:"onhashchange"in b&&(!g||7<
|
||||
g),hasEvent:function(a){if("input"==a&&9==Q)return!1;if(x(c[a])){var b=f.createElement("div");c[a]="on"+a in b}return c[a]},csp:Xa(),vendorPrefix:k,transitions:l,animations:n,android:d,msie:Q,msieDocumentMode:g}}]}function ee(){this.$get=["$rootScope","$browser","$q","$exceptionHandler",function(b,a,c,d){function e(e,k,m){var h=c.defer(),l=h.promise,n=y(m)&&!m;k=a.defer(function(){try{h.resolve(e())}catch(a){h.reject(a),d(a)}finally{delete f[l.$$timeoutId]}n||b.$apply()},k);l.$$timeoutId=k;f[k]=h;
|
||||
return l}var f={};e.cancel=function(b){return b&&b.$$timeoutId in f?(f[b.$$timeoutId].reject("canceled"),delete f[b.$$timeoutId],a.defer.cancel(b.$$timeoutId)):!1};return e}]}function ua(b,a){var c=b;Q&&(Y.setAttribute("href",c),c=Y.href);Y.setAttribute("href",c);return{href:Y.href,protocol:Y.protocol?Y.protocol.replace(/:$/,""):"",host:Y.host,search:Y.search?Y.search.replace(/^\?/,""):"",hash:Y.hash?Y.hash.replace(/^#/,""):"",hostname:Y.hostname,port:Y.port,pathname:"/"===Y.pathname.charAt(0)?Y.pathname:
|
||||
"/"+Y.pathname}}function Pb(b){b=v(b)?ua(b):b;return b.protocol===Hc.protocol&&b.host===Hc.host}function fe(){this.$get=ba(W)}function mc(b){function a(d,e){if(T(d)){var f={};r(d,function(b,c){f[c]=a(c,b)});return f}return b.factory(d+c,e)}var c="Filter";this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+c)}}];a("currency",Ic);a("date",Jc);a("filter",Ce);a("json",De);a("limitTo",Ee);a("lowercase",Fe);a("number",Kc);a("orderBy",Lc);a("uppercase",Ge)}function Ce(){return function(b,
|
||||
a,c){if(!J(b))return b;var d=typeof c,e=[];e.check=function(a){for(var b=0;b<e.length;b++)if(!e[b](a))return!1;return!0};"function"!==d&&(c="boolean"===d&&c?function(a,b){return Va.equals(a,b)}:function(a,b){if(a&&b&&"object"===typeof a&&"object"===typeof b){for(var d in a)if("$"!==d.charAt(0)&&kb.call(a,d)&&c(a[d],b[d]))return!0;return!1}b=(""+b).toLowerCase();return-1<(""+a).toLowerCase().indexOf(b)});var f=function(a,b){if("string"==typeof b&&"!"===b.charAt(0))return!f(a,b.substr(1));switch(typeof a){case "boolean":case "number":case "string":return c(a,
|
||||
b);case "object":switch(typeof b){case "object":return c(a,b);default:for(var d in a)if("$"!==d.charAt(0)&&f(a[d],b))return!0}return!1;case "array":for(d=0;d<a.length;d++)if(f(a[d],b))return!0;return!1;default:return!1}};switch(typeof a){case "boolean":case "number":case "string":a={$:a};case "object":for(var g in a)(function(b){"undefined"!==typeof a[b]&&e.push(function(c){return f("$"==b?c:c&&c[b],a[b])})})(g);break;case "function":e.push(a);break;default:return b}d=[];for(g=0;g<b.length;g++){var k=
|
||||
b[g];e.check(k)&&d.push(k)}return d}}function Ic(b){var a=b.NUMBER_FORMATS;return function(b,d){x(d)&&(d=a.CURRENCY_SYM);return Mc(b,a.PATTERNS[1],a.GROUP_SEP,a.DECIMAL_SEP,2).replace(/\u00A4/g,d)}}function Kc(b){var a=b.NUMBER_FORMATS;return function(b,d){return Mc(b,a.PATTERNS[0],a.GROUP_SEP,a.DECIMAL_SEP,d)}}function Mc(b,a,c,d,e){if(null==b||!isFinite(b)||T(b))return"";var f=0>b;b=Math.abs(b);var g=b+"",k="",m=[],h=!1;if(-1!==g.indexOf("e")){var l=g.match(/([\d\.]+)e(-?)(\d+)/);l&&"-"==l[2]&&
|
||||
l[3]>e+1?(g="0",b=0):(k=g,h=!0)}if(h)0<e&&(-1<b&&1>b)&&(k=b.toFixed(e));else{g=(g.split(Nc)[1]||"").length;x(e)&&(e=Math.min(Math.max(a.minFrac,g),a.maxFrac));b=+(Math.round(+(b.toString()+"e"+e)).toString()+"e"+-e);0===b&&(f=!1);b=(""+b).split(Nc);g=b[0];b=b[1]||"";var l=0,n=a.lgSize,p=a.gSize;if(g.length>=n+p)for(l=g.length-n,h=0;h<l;h++)0===(l-h)%p&&0!==h&&(k+=c),k+=g.charAt(h);for(h=l;h<g.length;h++)0===(g.length-h)%n&&0!==h&&(k+=c),k+=g.charAt(h);for(;b.length<e;)b+="0";e&&"0"!==e&&(k+=d+b.substr(0,
|
||||
e))}m.push(f?a.negPre:a.posPre);m.push(k);m.push(f?a.negSuf:a.posSuf);return m.join("")}function Xb(b,a,c){var d="";0>b&&(d="-",b=-b);for(b=""+b;b.length<a;)b="0"+b;c&&(b=b.substr(b.length-a));return d+b}function $(b,a,c,d){c=c||0;return function(e){e=e["get"+b]();if(0<c||e>-c)e+=c;0===e&&-12==c&&(e=12);return Xb(e,a,d)}}function vb(b,a){return function(c,d){var e=c["get"+b](),f=Ia(a?"SHORT"+b:b);return d[f][e]}}function Jc(b){function a(a){var b;if(b=a.match(c)){a=new Date(0);var f=0,g=0,k=b[8]?
|
||||
a.setUTCFullYear:a.setFullYear,m=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=U(b[9]+b[10]),g=U(b[9]+b[11]));k.call(a,U(b[1]),U(b[2])-1,U(b[3]));f=U(b[4]||0)-f;g=U(b[5]||0)-g;k=U(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));m.call(a,f,g,k,b)}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e){var f="",g=[],k,m;e=e||"mediumDate";e=b.DATETIME_FORMATS[e]||e;v(c)&&(c=He.test(c)?U(c):a(c));ib(c)&&(c=new Date(c));
|
||||
if(!ta(c))return c;for(;e;)(m=Ie.exec(e))?(g=g.concat(Ba.call(m,1)),e=g.pop()):(g.push(e),e=null);r(g,function(a){k=Je[a];f+=k?k(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return f}}function De(){return function(b){return na(b,!0)}}function Ee(){return function(b,a){if(!J(b)&&!v(b))return b;a=Infinity===Math.abs(Number(a))?Number(a):U(a);if(v(b))return a?0<=a?b.slice(0,a):b.slice(a,b.length):"";var c=[],d,e;a>b.length?a=b.length:a<-b.length&&(a=-b.length);0<a?(d=0,e=a):(d=
|
||||
b.length+a,e=b.length);for(;d<e;d++)c.push(b[d]);return c}}function Lc(b){return function(a,c,d){function e(a,b){return Ua(b)?function(b,c){return a(c,b)}:a}function f(a,b){var c=typeof a,d=typeof b;return c==d?(ta(a)&&ta(b)&&(a=a.valueOf(),b=b.valueOf()),"string"==c&&(a=a.toLowerCase(),b=b.toLowerCase()),a===b?0:a<b?-1:1):c<d?-1:1}if(!Pa(a)||!c)return a;c=J(c)?c:[c];c=Vc(c,function(a){var c=!1,d=a||Qa;if(v(a)){if("+"==a.charAt(0)||"-"==a.charAt(0))c="-"==a.charAt(0),a=a.substring(1);d=b(a);if(d.constant){var g=
|
||||
d();return e(function(a,b){return f(a[g],b[g])},c)}}return e(function(a,b){return f(d(a),d(b))},c)});for(var g=[],k=0;k<a.length;k++)g.push(a[k]);return g.sort(e(function(a,b){for(var d=0;d<c.length;d++){var e=c[d](a,b);if(0!==e)return e}return 0},d))}}function ya(b){P(b)&&(b={link:b});b.restrict=b.restrict||"AC";return ba(b)}function Oc(b,a,c,d){function e(a,c){c=c?"-"+mb(c,"-"):"";d.setClass(b,(a?wb:xb)+c,(a?xb:wb)+c)}var f=this,g=b.parent().controller("form")||yb,k=0,m=f.$error={},h=[];f.$name=
|
||||
a.name||a.ngForm;f.$dirty=!1;f.$pristine=!0;f.$valid=!0;f.$invalid=!1;g.$addControl(f);b.addClass(Oa);e(!0);f.$addControl=function(a){Da(a.$name,"input");h.push(a);a.$name&&(f[a.$name]=a)};f.$removeControl=function(a){a.$name&&f[a.$name]===a&&delete f[a.$name];r(m,function(b,c){f.$setValidity(c,!0,a)});Sa(h,a)};f.$setValidity=function(a,b,c){var d=m[a];if(b)d&&(Sa(d,c),d.length||(k--,k||(e(b),f.$valid=!0,f.$invalid=!1),m[a]=!1,e(!0,a),g.$setValidity(a,!0,f)));else{k||e(b);if(d){if(-1!=Ra(d,c))return}else m[a]=
|
||||
d=[],k++,e(!1,a),g.$setValidity(a,!1,f);d.push(c);f.$valid=!1;f.$invalid=!0}};f.$setDirty=function(){d.removeClass(b,Oa);d.addClass(b,zb);f.$dirty=!0;f.$pristine=!1;g.$setDirty()};f.$setPristine=function(){d.removeClass(b,zb);d.addClass(b,Oa);f.$dirty=!1;f.$pristine=!0;r(h,function(a){a.$setPristine()})}}function sa(b,a,c,d){b.$setValidity(a,c);return c?d:t}function Pc(b,a){var c,d;if(a)for(c=0;c<a.length;++c)if(d=a[c],b[d])return!0;return!1}function Ke(b,a,c,d,e){T(e)&&(b.$$hasNativeValidators=!0,
|
||||
b.$parsers.push(function(f){if(b.$error[a]||Pc(e,d)||!Pc(e,c))return f;b.$setValidity(a,!1)}))}function Ab(b,a,c,d,e,f){var g=a.prop(Le),k=a[0].placeholder,m={},h=K(a[0].type);d.$$validityState=g;if(!e.android){var l=!1;a.on("compositionstart",function(a){l=!0});a.on("compositionend",function(){l=!1;n()})}var n=function(e){if(!l){var f=a.val();if(Q&&"input"===(e||m).type&&a[0].placeholder!==k)k=a[0].placeholder;else if("password"!==h&&Ua(c.ngTrim||"T")&&(f=aa(f)),e=g&&d.$$hasNativeValidators,d.$viewValue!==
|
||||
f||""===f&&e)b.$root.$$phase?d.$setViewValue(f):b.$apply(function(){d.$setViewValue(f)})}};if(e.hasEvent("input"))a.on("input",n);else{var p,q=function(){p||(p=f.defer(function(){n();p=null}))};a.on("keydown",function(a){a=a.keyCode;91===a||(15<a&&19>a||37<=a&&40>=a)||q()});if(e.hasEvent("paste"))a.on("paste cut",q)}a.on("change",n);d.$render=function(){a.val(d.$isEmpty(d.$viewValue)?"":d.$viewValue)};var s=c.ngPattern;s&&((e=s.match(/^\/(.*)\/([gim]*)$/))?(s=RegExp(e[1],e[2]),e=function(a){return sa(d,
|
||||
"pattern",d.$isEmpty(a)||s.test(a),a)}):e=function(c){var e=b.$eval(s);if(!e||!e.test)throw C("ngPattern")("noregexp",s,e,ia(a));return sa(d,"pattern",d.$isEmpty(c)||e.test(c),c)},d.$formatters.push(e),d.$parsers.push(e));if(c.ngMinlength){var r=U(c.ngMinlength);e=function(a){return sa(d,"minlength",d.$isEmpty(a)||a.length>=r,a)};d.$parsers.push(e);d.$formatters.push(e)}if(c.ngMaxlength){var u=U(c.ngMaxlength);e=function(a){return sa(d,"maxlength",d.$isEmpty(a)||a.length<=u,a)};d.$parsers.push(e);
|
||||
d.$formatters.push(e)}}function Yb(b,a){b="ngClass"+b;return["$animate",function(c){function d(a,b){var c=[],d=0;a:for(;d<a.length;d++){for(var e=a[d],l=0;l<b.length;l++)if(e==b[l])continue a;c.push(e)}return c}function e(a){if(!J(a)){if(v(a))return a.split(" ");if(T(a)){var b=[];r(a,function(a,c){a&&(b=b.concat(c.split(" ")))});return b}}return a}return{restrict:"AC",link:function(f,g,k){function m(a,b){var c=g.data("$classCounts")||{},d=[];r(a,function(a){if(0<b||c[a])c[a]=(c[a]||0)+b,c[a]===+(0<
|
||||
b)&&d.push(a)});g.data("$classCounts",c);return d.join(" ")}function h(b){if(!0===a||f.$index%2===a){var h=e(b||[]);if(!l){var q=m(h,1);k.$addClass(q)}else if(!Aa(b,l)){var s=e(l),q=d(h,s),h=d(s,h),h=m(h,-1),q=m(q,1);0===q.length?c.removeClass(g,h):0===h.length?c.addClass(g,q):c.setClass(g,q,h)}}l=ha(b)}var l;f.$watch(k[b],h,!0);k.$observe("class",function(a){h(f.$eval(k[b]))});"ngClass"!==b&&f.$watch("$index",function(c,d){var g=c&1;if(g!==(d&1)){var h=e(f.$eval(k[b]));g===a?(g=m(h,1),k.$addClass(g)):
|
||||
(g=m(h,-1),k.$removeClass(g))}})}}}]}var Le="validity",K=function(b){return v(b)?b.toLowerCase():b},kb=Object.prototype.hasOwnProperty,Ia=function(b){return v(b)?b.toUpperCase():b},Q,w,Ea,Ba=[].slice,Me=[].push,za=Object.prototype.toString,Ta=C("ng"),Va=W.angular||(W.angular={}),Ya,Ma,ma=["0","0","0"];Q=U((/msie (\d+)/.exec(K(navigator.userAgent))||[])[1]);isNaN(Q)&&(Q=U((/trident\/.*; rv:(\d+)/.exec(K(navigator.userAgent))||[])[1]));E.$inject=[];Qa.$inject=[];var J=function(){return P(Array.isArray)?
|
||||
Array.isArray:function(b){return"[object Array]"===za.call(b)}}(),aa=function(){return String.prototype.trim?function(b){return v(b)?b.trim():b}:function(b){return v(b)?b.replace(/^\s\s*/,"").replace(/\s\s*$/,""):b}}();Ma=9>Q?function(b){b=b.nodeName?b:b[0];return b.scopeName&&"HTML"!=b.scopeName?Ia(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?b.nodeName:b[0].nodeName};var Xa=function(){if(y(Xa.isActive_))return Xa.isActive_;var b=!(!X.querySelector("[ng-csp]")&&!X.querySelector("[data-ng-csp]"));
|
||||
if(!b)try{new Function("")}catch(a){b=!0}return Xa.isActive_=b},Yc=/[A-Z]/g,ad={full:"1.2.26",major:1,minor:2,dot:26,codeName:"captivating-disinterest"};S.expando="ng339";var ab=S.cache={},ne=1,sb=W.document.addEventListener?function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},$a=W.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)};S._data=function(b){return this.cache[b[this.expando]]||{}};var ie=/([\:\-\_]+(.))/g,
|
||||
je=/^moz([A-Z])/,Hb=C("jqLite"),ke=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,Ib=/<|&#?\w+;/,le=/<([\w:]+)/,me=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ea={option:[1,'<select multiple="multiple">',"</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ea.optgroup=ea.option;ea.tbody=ea.tfoot=ea.colgroup=ea.caption=ea.thead;ea.th=
|
||||
ea.td;var La=S.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;"complete"===X.readyState?setTimeout(a):(this.on("DOMContentLoaded",a),S(W).on("load",a))},toString:function(){var b=[];r(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return 0<=b?w(this[b]):w(this[this.length+b])},length:0,push:Me,sort:[].sort,splice:[].splice},qb={};r("multiple selected checked disabled readOnly required open".split(" "),function(b){qb[K(b)]=b});var rc={};r("input select option textarea button form details".split(" "),
|
||||
function(b){rc[Ia(b)]=!0});r({data:Mb,removeData:Lb},function(b,a){S[a]=b});r({data:Mb,inheritedData:pb,scope:function(b){return w.data(b,"$scope")||pb(b.parentNode||b,["$isolateScope","$scope"])},isolateScope:function(b){return w.data(b,"$isolateScope")||w.data(b,"$isolateScopeNoTemplate")},controller:oc,injector:function(b){return pb(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Nb,css:function(b,a,c){a=Za(a);if(y(c))b.style[a]=c;else{var d;8>=Q&&(d=b.currentStyle&&b.currentStyle[a],
|
||||
""===d&&(d="auto"));d=d||b.style[a];8>=Q&&(d=""===d?t:d);return d}},attr:function(b,a,c){var d=K(a);if(qb[d])if(y(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||E).specified?d:t;else if(y(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),null===b?t:b},prop:function(b,a,c){if(y(c))b[a]=c;else return b[a]},text:function(){function b(b,d){var e=a[b.nodeType];if(x(d))return e?b[e]:"";b[e]=d}var a=[];9>Q?(a[1]=
|
||||
"innerText",a[3]="nodeValue"):a[1]=a[3]="textContent";b.$dv="";return b}(),val:function(b,a){if(x(a)){if("SELECT"===Ma(b)&&b.multiple){var c=[];r(b.options,function(a){a.selected&&c.push(a.value||a.text)});return 0===c.length?null:c}return b.value}b.value=a},html:function(b,a){if(x(a))return b.innerHTML;for(var c=0,d=b.childNodes;c<d.length;c++)Ja(d[c]);b.innerHTML=a},empty:pc},function(b,a){S.prototype[a]=function(a,d){var e,f,g=this.length;if(b!==pc&&(2==b.length&&b!==Nb&&b!==oc?a:d)===t){if(T(a)){for(e=
|
||||
0;e<g;e++)if(b===Mb)b(this[e],a);else for(f in a)b(this[e],f,a[f]);return this}e=b.$dv;g=e===t?Math.min(g,1):g;for(f=0;f<g;f++){var k=b(this[f],a,d);e=e?e+k:k}return e}for(e=0;e<g;e++)b(this[e],a,d);return this}});r({removeData:Lb,dealoc:Ja,on:function a(c,d,e,f){if(y(f))throw Hb("onargs");var g=oa(c,"events"),k=oa(c,"handle");g||oa(c,"events",g={});k||oa(c,"handle",k=oe(c,g));r(d.split(" "),function(d){var f=g[d];if(!f){if("mouseenter"==d||"mouseleave"==d){var l=X.body.contains||X.body.compareDocumentPosition?
|
||||
function(a,c){var d=9===a.nodeType?a.documentElement:a,e=c&&c.parentNode;return a===e||!!(e&&1===e.nodeType&&(d.contains?d.contains(e):a.compareDocumentPosition&&a.compareDocumentPosition(e)&16))}:function(a,c){if(c)for(;c=c.parentNode;)if(c===a)return!0;return!1};g[d]=[];a(c,{mouseleave:"mouseout",mouseenter:"mouseover"}[d],function(a){var c=a.relatedTarget;c&&(c===this||l(this,c))||k(a,d)})}else sb(c,d,k),g[d]=[];f=g[d]}f.push(e)})},off:nc,one:function(a,c,d){a=w(a);a.on(c,function f(){a.off(c,
|
||||
d);a.off(c,f)});a.on(c,d)},replaceWith:function(a,c){var d,e=a.parentNode;Ja(a);r(new S(c),function(c){d?e.insertBefore(c,d.nextSibling):e.replaceChild(c,a);d=c})},children:function(a){var c=[];r(a.childNodes,function(a){1===a.nodeType&&c.push(a)});return c},contents:function(a){return a.contentDocument||a.childNodes||[]},append:function(a,c){r(new S(c),function(c){1!==a.nodeType&&11!==a.nodeType||a.appendChild(c)})},prepend:function(a,c){if(1===a.nodeType){var d=a.firstChild;r(new S(c),function(c){a.insertBefore(c,
|
||||
d)})}},wrap:function(a,c){c=w(c)[0];var d=a.parentNode;d&&d.replaceChild(c,a);c.appendChild(a)},remove:function(a){Ja(a);var c=a.parentNode;c&&c.removeChild(a)},after:function(a,c){var d=a,e=a.parentNode;r(new S(c),function(a){e.insertBefore(a,d.nextSibling);d=a})},addClass:ob,removeClass:nb,toggleClass:function(a,c,d){c&&r(c.split(" "),function(c){var f=d;x(f)&&(f=!Nb(a,c));(f?ob:nb)(a,c)})},parent:function(a){return(a=a.parentNode)&&11!==a.nodeType?a:null},next:function(a){if(a.nextElementSibling)return a.nextElementSibling;
|
||||
for(a=a.nextSibling;null!=a&&1!==a.nodeType;)a=a.nextSibling;return a},find:function(a,c){return a.getElementsByTagName?a.getElementsByTagName(c):[]},clone:Kb,triggerHandler:function(a,c,d){var e,f;e=c.type||c;var g=(oa(a,"events")||{})[e];g&&(e={preventDefault:function(){this.defaultPrevented=!0},isDefaultPrevented:function(){return!0===this.defaultPrevented},stopPropagation:E,type:e,target:a},c.type&&(e=D(e,c)),c=ha(g),f=d?[e].concat(d):[e],r(c,function(c){c.apply(a,f)}))}},function(a,c){S.prototype[c]=
|
||||
function(c,e,f){for(var g,k=0;k<this.length;k++)x(g)?(g=a(this[k],c,e,f),y(g)&&(g=w(g))):Jb(g,a(this[k],c,e,f));return y(g)?g:this};S.prototype.bind=S.prototype.on;S.prototype.unbind=S.prototype.off});bb.prototype={put:function(a,c){this[Ka(a,this.nextUid)]=c},get:function(a){return this[Ka(a,this.nextUid)]},remove:function(a){var c=this[a=Ka(a,this.nextUid)];delete this[a];return c}};var qe=/^function\s*[^\(]*\(\s*([^\)]*)\)/m,re=/,/,se=/^\s*(_?)(\S+?)\1\s*$/,pe=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,
|
||||
cb=C("$injector"),Ne=C("$animate"),Md=["$provide",function(a){this.$$selectors={};this.register=function(c,d){var e=c+"-animation";if(c&&"."!=c.charAt(0))throw Ne("notcsel",c);this.$$selectors[c.substr(1)]=e;a.factory(e,d)};this.classNameFilter=function(a){1===arguments.length&&(this.$$classNameFilter=a instanceof RegExp?a:null);return this.$$classNameFilter};this.$get=["$timeout","$$asyncCallback",function(a,d){return{enter:function(a,c,g,k){g?g.after(a):(c&&c[0]||(c=g.parent()),c.append(a));k&&
|
||||
d(k)},leave:function(a,c){a.remove();c&&d(c)},move:function(a,c,d,k){this.enter(a,c,d,k)},addClass:function(a,c,g){c=v(c)?c:J(c)?c.join(" "):"";r(a,function(a){ob(a,c)});g&&d(g)},removeClass:function(a,c,g){c=v(c)?c:J(c)?c.join(" "):"";r(a,function(a){nb(a,c)});g&&d(g)},setClass:function(a,c,g,k){r(a,function(a){ob(a,c);nb(a,g)});k&&d(k)},enabled:E}}]}],ja=C("$compile");ic.$inject=["$provide","$$sanitizeUriProvider"];var we=/^(x[\:\-_]|data[\:\-_])/i,yc=C("$interpolate"),Oe=/^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
|
||||
ze={http:80,https:443,ftp:21},Sb=C("$location");Ub.prototype=Tb.prototype=Bc.prototype={$$html5:!1,$$replace:!1,absUrl:tb("$$absUrl"),url:function(a){if(x(a))return this.$$url;a=Oe.exec(a);a[1]&&this.path(decodeURIComponent(a[1]));(a[2]||a[1])&&this.search(a[3]||"");this.hash(a[5]||"");return this},protocol:tb("$$protocol"),host:tb("$$host"),port:tb("$$port"),path:Cc("$$path",function(a){a=a?a.toString():"";return"/"==a.charAt(0)?a:"/"+a}),search:function(a,c){switch(arguments.length){case 0:return this.$$search;
|
||||
case 1:if(v(a)||ib(a))a=a.toString(),this.$$search=ec(a);else if(T(a))r(a,function(c,e){null==c&&delete a[e]}),this.$$search=a;else throw Sb("isrcharg");break;default:x(c)||null===c?delete this.$$search[a]:this.$$search[a]=c}this.$$compose();return this},hash:Cc("$$hash",function(a){return a?a.toString():""}),replace:function(){this.$$replace=!0;return this}};var la=C("$parse"),Fc={},wa,Pe=Function.prototype.call,Qe=Function.prototype.apply,Qc=Function.prototype.bind,gb={"null":function(){return null},
|
||||
"true":function(){return!0},"false":function(){return!1},undefined:E,"+":function(a,c,d,e){d=d(a,c);e=e(a,c);return y(d)?y(e)?d+e:d:y(e)?e:t},"-":function(a,c,d,e){d=d(a,c);e=e(a,c);return(y(d)?d:0)-(y(e)?e:0)},"*":function(a,c,d,e){return d(a,c)*e(a,c)},"/":function(a,c,d,e){return d(a,c)/e(a,c)},"%":function(a,c,d,e){return d(a,c)%e(a,c)},"^":function(a,c,d,e){return d(a,c)^e(a,c)},"=":E,"===":function(a,c,d,e){return d(a,c)===e(a,c)},"!==":function(a,c,d,e){return d(a,c)!==e(a,c)},"==":function(a,
|
||||
c,d,e){return d(a,c)==e(a,c)},"!=":function(a,c,d,e){return d(a,c)!=e(a,c)},"<":function(a,c,d,e){return d(a,c)<e(a,c)},">":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Re={n:"\n",f:"\f",r:"\r",
|
||||
t:"\t",v:"\v","'":"'",'"':'"'},Wb=function(a){this.options=a};Wb.prototype={constructor:Wb,lex:function(a){this.text=a;this.index=0;this.ch=t;this.lastCh=":";for(this.tokens=[];this.index<this.text.length;){this.ch=this.text.charAt(this.index);if(this.is("\"'"))this.readString(this.ch);else if(this.isNumber(this.ch)||this.is(".")&&this.isNumber(this.peek()))this.readNumber();else if(this.isIdent(this.ch))this.readIdent();else if(this.is("(){}[].,;:?"))this.tokens.push({index:this.index,text:this.ch}),
|
||||
this.index++;else if(this.isWhitespace(this.ch)){this.index++;continue}else{a=this.ch+this.peek();var c=a+this.peek(2),d=gb[this.ch],e=gb[a],f=gb[c];f?(this.tokens.push({index:this.index,text:c,fn:f}),this.index+=3):e?(this.tokens.push({index:this.index,text:a,fn:e}),this.index+=2):d?(this.tokens.push({index:this.index,text:this.ch,fn:d}),this.index+=1):this.throwError("Unexpected next character ",this.index,this.index+1)}this.lastCh=this.ch}return this.tokens},is:function(a){return-1!==a.indexOf(this.ch)},
|
||||
was:function(a){return-1!==a.indexOf(this.lastCh)},peek:function(a){a=a||1;return this.index+a<this.text.length?this.text.charAt(this.index+a):!1},isNumber:function(a){return"0"<=a&&"9">=a},isWhitespace:function(a){return" "===a||"\r"===a||"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdent:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},throwError:function(a,c,d){d=d||this.index;c=y(c)?"s "+c+"-"+this.index+" ["+
|
||||
this.text.substring(c,d)+"]":" "+d;throw la("lexerr",a,c,this.text);},readNumber:function(){for(var a="",c=this.index;this.index<this.text.length;){var d=K(this.text.charAt(this.index));if("."==d||this.isNumber(d))a+=d;else{var e=this.peek();if("e"==d&&this.isExpOperator(e))a+=d;else if(this.isExpOperator(d)&&e&&this.isNumber(e)&&"e"==a.charAt(a.length-1))a+=d;else if(!this.isExpOperator(d)||e&&this.isNumber(e)||"e"!=a.charAt(a.length-1))break;else this.throwError("Invalid exponent")}this.index++}a*=
|
||||
1;this.tokens.push({index:c,text:a,literal:!0,constant:!0,fn:function(){return a}})},readIdent:function(){for(var a=this,c="",d=this.index,e,f,g,k;this.index<this.text.length;){k=this.text.charAt(this.index);if("."===k||this.isIdent(k)||this.isNumber(k))"."===k&&(e=this.index),c+=k;else break;this.index++}if(e)for(f=this.index;f<this.text.length;){k=this.text.charAt(f);if("("===k){g=c.substr(e-d+1);c=c.substr(0,e-d);this.index=f;break}if(this.isWhitespace(k))f++;else break}d={index:d,text:c};if(gb.hasOwnProperty(c))d.fn=
|
||||
gb[c],d.literal=!0,d.constant=!0;else{var m=Ec(c,this.options,this.text);d.fn=D(function(a,c){return m(a,c)},{assign:function(d,e){return ub(d,c,e,a.text,a.options)}})}this.tokens.push(d);g&&(this.tokens.push({index:e,text:"."}),this.tokens.push({index:e+1,text:g}))},readString:function(a){var c=this.index;this.index++;for(var d="",e=a,f=!1;this.index<this.text.length;){var g=this.text.charAt(this.index),e=e+g;if(f)"u"===g?(f=this.text.substring(this.index+1,this.index+5),f.match(/[\da-f]{4}/i)||
|
||||
this.throwError("Invalid unicode escape [\\u"+f+"]"),this.index+=4,d+=String.fromCharCode(parseInt(f,16))):d+=Re[g]||g,f=!1;else if("\\"===g)f=!0;else{if(g===a){this.index++;this.tokens.push({index:c,text:e,string:d,literal:!0,constant:!0,fn:function(){return d}});return}d+=g}this.index++}this.throwError("Unterminated quote",c)}};var fb=function(a,c,d){this.lexer=a;this.$filter=c;this.options=d};fb.ZERO=D(function(){return 0},{constant:!0});fb.prototype={constructor:fb,parse:function(a){this.text=
|
||||
a;this.tokens=this.lexer.lex(a);a=this.statements();0!==this.tokens.length&&this.throwError("is an unexpected token",this.tokens[0]);a.literal=!!a.literal;a.constant=!!a.constant;return a},primary:function(){var a;if(this.expect("("))a=this.filterChain(),this.consume(")");else if(this.expect("["))a=this.arrayDeclaration();else if(this.expect("{"))a=this.object();else{var c=this.expect();(a=c.fn)||this.throwError("not a primary expression",c);a.literal=!!c.literal;a.constant=!!c.constant}for(var d;c=
|
||||
this.expect("(","[",".");)"("===c.text?(a=this.functionCall(a,d),d=null):"["===c.text?(d=a,a=this.objectIndex(a)):"."===c.text?(d=a,a=this.fieldAccess(a)):this.throwError("IMPOSSIBLE");return a},throwError:function(a,c){throw la("syntax",c.text,a,c.index+1,this.text,this.text.substring(c.index));},peekToken:function(){if(0===this.tokens.length)throw la("ueoe",this.text);return this.tokens[0]},peek:function(a,c,d,e){if(0<this.tokens.length){var f=this.tokens[0],g=f.text;if(g===a||g===c||g===d||g===
|
||||
e||!(a||c||d||e))return f}return!1},expect:function(a,c,d,e){return(a=this.peek(a,c,d,e))?(this.tokens.shift(),a):!1},consume:function(a){this.expect(a)||this.throwError("is unexpected, expecting ["+a+"]",this.peek())},unaryFn:function(a,c){return D(function(d,e){return a(d,e,c)},{constant:c.constant})},ternaryFn:function(a,c,d){return D(function(e,f){return a(e,f)?c(e,f):d(e,f)},{constant:a.constant&&c.constant&&d.constant})},binaryFn:function(a,c,d){return D(function(e,f){return c(e,f,a,d)},{constant:a.constant&&
|
||||
d.constant})},statements:function(){for(var a=[];;)if(0<this.tokens.length&&!this.peek("}",")",";","]")&&a.push(this.filterChain()),!this.expect(";"))return 1===a.length?a[0]:function(c,d){for(var e,f=0;f<a.length;f++){var g=a[f];g&&(e=g(c,d))}return e}},filterChain:function(){for(var a=this.expression(),c;;)if(c=this.expect("|"))a=this.binaryFn(a,c.fn,this.filter());else return a},filter:function(){for(var a=this.expect(),c=this.$filter(a.text),d=[];;)if(a=this.expect(":"))d.push(this.expression());
|
||||
else{var e=function(a,e,k){k=[k];for(var m=0;m<d.length;m++)k.push(d[m](a,e));return c.apply(a,k)};return function(){return e}}},expression:function(){return this.assignment()},assignment:function(){var a=this.ternary(),c,d;return(d=this.expect("="))?(a.assign||this.throwError("implies assignment but ["+this.text.substring(0,d.index)+"] can not be assigned to",d),c=this.ternary(),function(d,f){return a.assign(d,c(d,f),f)}):a},ternary:function(){var a=this.logicalOR(),c,d;if(this.expect("?")){c=this.assignment();
|
||||
if(d=this.expect(":"))return this.ternaryFn(a,c,this.assignment());this.throwError("expected :",d)}else return a},logicalOR:function(){for(var a=this.logicalAND(),c;;)if(c=this.expect("||"))a=this.binaryFn(a,c.fn,this.logicalAND());else return a},logicalAND:function(){var a=this.equality(),c;if(c=this.expect("&&"))a=this.binaryFn(a,c.fn,this.logicalAND());return a},equality:function(){var a=this.relational(),c;if(c=this.expect("==","!=","===","!=="))a=this.binaryFn(a,c.fn,this.equality());return a},
|
||||
relational:function(){var a=this.additive(),c;if(c=this.expect("<",">","<=",">="))a=this.binaryFn(a,c.fn,this.relational());return a},additive:function(){for(var a=this.multiplicative(),c;c=this.expect("+","-");)a=this.binaryFn(a,c.fn,this.multiplicative());return a},multiplicative:function(){for(var a=this.unary(),c;c=this.expect("*","/","%");)a=this.binaryFn(a,c.fn,this.unary());return a},unary:function(){var a;return this.expect("+")?this.primary():(a=this.expect("-"))?this.binaryFn(fb.ZERO,a.fn,
|
||||
this.unary()):(a=this.expect("!"))?this.unaryFn(a.fn,this.unary()):this.primary()},fieldAccess:function(a){var c=this,d=this.expect().text,e=Ec(d,this.options,this.text);return D(function(c,d,k){return e(k||a(c,d))},{assign:function(e,g,k){(k=a(e,k))||a.assign(e,k={});return ub(k,d,g,c.text,c.options)}})},objectIndex:function(a){var c=this,d=this.expression();this.consume("]");return D(function(e,f){var g=a(e,f),k=d(e,f),m;ka(k,c.text);if(!g)return t;(g=va(g[k],c.text))&&(g.then&&c.options.unwrapPromises)&&
|
||||
(m=g,"$$v"in g||(m.$$v=t,m.then(function(a){m.$$v=a})),g=g.$$v);return g},{assign:function(e,f,g){var k=ka(d(e,g),c.text);(g=va(a(e,g),c.text))||a.assign(e,g={});return g[k]=f}})},functionCall:function(a,c){var d=[];if(")"!==this.peekToken().text){do d.push(this.expression());while(this.expect(","))}this.consume(")");var e=this;return function(f,g){for(var k=[],m=c?c(f,g):f,h=0;h<d.length;h++)k.push(va(d[h](f,g),e.text));h=a(f,g,m)||E;va(m,e.text);var l=e.text;if(h){if(h.constructor===h)throw la("isecfn",
|
||||
l);if(h===Pe||h===Qe||Qc&&h===Qc)throw la("isecff",l);}k=h.apply?h.apply(m,k):h(k[0],k[1],k[2],k[3],k[4]);return va(k,e.text)}},arrayDeclaration:function(){var a=[],c=!0;if("]"!==this.peekToken().text){do{if(this.peek("]"))break;var d=this.expression();a.push(d);d.constant||(c=!1)}while(this.expect(","))}this.consume("]");return D(function(c,d){for(var g=[],k=0;k<a.length;k++)g.push(a[k](c,d));return g},{literal:!0,constant:c})},object:function(){var a=[],c=!0;if("}"!==this.peekToken().text){do{if(this.peek("}"))break;
|
||||
var d=this.expect(),d=d.string||d.text;this.consume(":");var e=this.expression();a.push({key:d,value:e});e.constant||(c=!1)}while(this.expect(","))}this.consume("}");return D(function(c,d){for(var e={},m=0;m<a.length;m++){var h=a[m];e[h.key]=h.value(c,d)}return e},{literal:!0,constant:c})}};var Vb={},xa=C("$sce"),ga={HTML:"html",CSS:"css",URL:"url",RESOURCE_URL:"resourceUrl",JS:"js"},Y=X.createElement("a"),Hc=ua(W.location.href,!0);mc.$inject=["$provide"];Ic.$inject=["$locale"];Kc.$inject=["$locale"];
|
||||
var Nc=".",Je={yyyy:$("FullYear",4),yy:$("FullYear",2,0,!0),y:$("FullYear",1),MMMM:vb("Month"),MMM:vb("Month",!0),MM:$("Month",2,1),M:$("Month",1,1),dd:$("Date",2),d:$("Date",1),HH:$("Hours",2),H:$("Hours",1),hh:$("Hours",2,-12),h:$("Hours",1,-12),mm:$("Minutes",2),m:$("Minutes",1),ss:$("Seconds",2),s:$("Seconds",1),sss:$("Milliseconds",3),EEEE:vb("Day"),EEE:vb("Day",!0),a:function(a,c){return 12>a.getHours()?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){a=-1*a.getTimezoneOffset();return a=(0<=a?"+":"")+(Xb(Math[0<
|
||||
a?"floor":"ceil"](a/60),2)+Xb(Math.abs(a%60),2))}},Ie=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,He=/^\-?\d+$/;Jc.$inject=["$locale"];var Fe=ba(K),Ge=ba(Ia);Lc.$inject=["$parse"];var dd=ba({restrict:"E",compile:function(a,c){8>=Q&&(c.href||c.name||c.$set("href",""),a.append(X.createComment("IE fix")));if(!c.href&&!c.xlinkHref&&!c.name)return function(a,c){var f="[object SVGAnimatedString]"===za.call(c.prop("href"))?"xlink:href":"href";c.on("click",function(a){c.attr(f)||
|
||||
a.preventDefault()})}}}),Fb={};r(qb,function(a,c){if("multiple"!=a){var d=pa("ng-"+c);Fb[d]=function(){return{priority:100,link:function(a,f,g){a.$watch(g[d],function(a){g.$set(c,!!a)})}}}}});r(["src","srcset","href"],function(a){var c=pa("ng-"+a);Fb[c]=function(){return{priority:99,link:function(d,e,f){var g=a,k=a;"href"===a&&"[object SVGAnimatedString]"===za.call(e.prop("href"))&&(k="xlinkHref",f.$attr[k]="xlink:href",g=null);f.$observe(c,function(c){c?(f.$set(k,c),Q&&g&&e.prop(g,f[k])):"href"===
|
||||
a&&f.$set(k,null)})}}}});var yb={$addControl:E,$removeControl:E,$setValidity:E,$setDirty:E,$setPristine:E};Oc.$inject=["$element","$attrs","$scope","$animate"];var Rc=function(a){return["$timeout",function(c){return{name:"form",restrict:a?"EAC":"E",controller:Oc,compile:function(){return{pre:function(a,e,f,g){if(!f.action){var k=function(a){a.preventDefault?a.preventDefault():a.returnValue=!1};sb(e[0],"submit",k);e.on("$destroy",function(){c(function(){$a(e[0],"submit",k)},0,!1)})}var m=e.parent().controller("form"),
|
||||
h=f.name||f.ngForm;h&&ub(a,h,g,h);if(m)e.on("$destroy",function(){m.$removeControl(g);h&&ub(a,h,t,h);D(g,yb)})}}}}}]},ed=Rc(),rd=Rc(!0),Se=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,Te=/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,Ue=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,Sc={text:Ab,number:function(a,c,d,e,f,g){Ab(a,c,d,e,f,g);e.$parsers.push(function(a){var c=e.$isEmpty(a);if(c||Ue.test(a))return e.$setValidity("number",
|
||||
!0),""===a?null:c?a:parseFloat(a);e.$setValidity("number",!1);return t});Ke(e,"number",Ve,null,e.$$validityState);e.$formatters.push(function(a){return e.$isEmpty(a)?"":""+a});d.min&&(a=function(a){var c=parseFloat(d.min);return sa(e,"min",e.$isEmpty(a)||a>=c,a)},e.$parsers.push(a),e.$formatters.push(a));d.max&&(a=function(a){var c=parseFloat(d.max);return sa(e,"max",e.$isEmpty(a)||a<=c,a)},e.$parsers.push(a),e.$formatters.push(a));e.$formatters.push(function(a){return sa(e,"number",e.$isEmpty(a)||
|
||||
ib(a),a)})},url:function(a,c,d,e,f,g){Ab(a,c,d,e,f,g);a=function(a){return sa(e,"url",e.$isEmpty(a)||Se.test(a),a)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,c,d,e,f,g){Ab(a,c,d,e,f,g);a=function(a){return sa(e,"email",e.$isEmpty(a)||Te.test(a),a)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){x(d.name)&&c.attr("name",hb());c.on("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};
|
||||
d.$observe("value",e.$render)},checkbox:function(a,c,d,e){var f=d.ngTrueValue,g=d.ngFalseValue;v(f)||(f=!0);v(g)||(g=!1);c.on("click",function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});e.$render=function(){c[0].checked=e.$viewValue};e.$isEmpty=function(a){return a!==f};e.$formatters.push(function(a){return a===f});e.$parsers.push(function(a){return a?f:g})},hidden:E,button:E,submit:E,reset:E,file:E},Ve=["badInput"],jc=["$browser","$sniffer",function(a,c){return{restrict:"E",require:"?ngModel",
|
||||
link:function(d,e,f,g){g&&(Sc[K(f.type)]||Sc.text)(d,e,f,g,c,a)}}}],wb="ng-valid",xb="ng-invalid",Oa="ng-pristine",zb="ng-dirty",We=["$scope","$exceptionHandler","$attrs","$element","$parse","$animate",function(a,c,d,e,f,g){function k(a,c){c=c?"-"+mb(c,"-"):"";g.removeClass(e,(a?xb:wb)+c);g.addClass(e,(a?wb:xb)+c)}this.$modelValue=this.$viewValue=Number.NaN;this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=
|
||||
d.name;var m=f(d.ngModel),h=m.assign;if(!h)throw C("ngModel")("nonassign",d.ngModel,ia(e));this.$render=E;this.$isEmpty=function(a){return x(a)||""===a||null===a||a!==a};var l=e.inheritedData("$formController")||yb,n=0,p=this.$error={};e.addClass(Oa);k(!0);this.$setValidity=function(a,c){p[a]!==!c&&(c?(p[a]&&n--,n||(k(!0),this.$valid=!0,this.$invalid=!1)):(k(!1),this.$invalid=!0,this.$valid=!1,n++),p[a]=!c,k(c,a),l.$setValidity(a,c,this))};this.$setPristine=function(){this.$dirty=!1;this.$pristine=
|
||||
!0;g.removeClass(e,zb);g.addClass(e,Oa)};this.$setViewValue=function(d){this.$viewValue=d;this.$pristine&&(this.$dirty=!0,this.$pristine=!1,g.removeClass(e,Oa),g.addClass(e,zb),l.$setDirty());r(this.$parsers,function(a){d=a(d)});this.$modelValue!==d&&(this.$modelValue=d,h(a,d),r(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}}))};var q=this;a.$watch(function(){var c=m(a);if(q.$modelValue!==c){var d=q.$formatters,e=d.length;for(q.$modelValue=c;e--;)c=d[e](c);q.$viewValue!==c&&(q.$viewValue=
|
||||
c,q.$render())}return c})}],Gd=function(){return{require:["ngModel","^?form"],controller:We,link:function(a,c,d,e){var f=e[0],g=e[1]||yb;g.$addControl(f);a.$on("$destroy",function(){g.$removeControl(f)})}}},Id=ba({require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),kc=function(){return{require:"?ngModel",link:function(a,c,d,e){if(e){d.required=!0;var f=function(a){if(d.required&&e.$isEmpty(a))e.$setValidity("required",!1);else return e.$setValidity("required",
|
||||
!0),a};e.$formatters.push(f);e.$parsers.unshift(f);d.$observe("required",function(){f(e.$viewValue)})}}}},Hd=function(){return{require:"ngModel",link:function(a,c,d,e){var f=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||d.ngList||",";e.$parsers.push(function(a){if(!x(a)){var c=[];a&&r(a.split(f),function(a){a&&c.push(aa(a))});return c}});e.$formatters.push(function(a){return J(a)?a.join(", "):t});e.$isEmpty=function(a){return!a||!a.length}}}},Xe=/^(true|false|\d+)$/,Jd=function(){return{priority:100,
|
||||
compile:function(a,c){return Xe.test(c.ngValue)?function(a,c,f){f.$set("value",a.$eval(f.ngValue))}:function(a,c,f){a.$watch(f.ngValue,function(a){f.$set("value",a)})}}}},jd=ya({compile:function(a){a.addClass("ng-binding");return function(a,d,e){d.data("$binding",e.ngBind);a.$watch(e.ngBind,function(a){d.text(a==t?"":a)})}}}),ld=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding",c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}],
|
||||
kd=["$sce","$parse",function(a,c){return{compile:function(d){d.addClass("ng-binding");return function(d,f,g){f.data("$binding",g.ngBindHtml);var k=c(g.ngBindHtml);d.$watch(function(){return(k(d)||"").toString()},function(c){f.html(a.getTrustedHtml(k(d))||"")})}}}}],md=Yb("",!0),od=Yb("Odd",0),nd=Yb("Even",1),pd=ya({compile:function(a,c){c.$set("ngCloak",t);a.removeClass("ng-cloak")}}),qd=[function(){return{scope:!0,controller:"@",priority:500}}],lc={},Ye={blur:!0,focus:!0};r("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),
|
||||
function(a){var c=pa("ng-"+a);lc[c]=["$parse","$rootScope",function(d,e){return{compile:function(f,g){var k=d(g[c]);return function(c,d){d.on(a,function(d){var f=function(){k(c,{$event:d})};Ye[a]&&e.$$phase?c.$evalAsync(f):c.$apply(f)})}}}}]});var td=["$animate",function(a){return{transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(c,d,e,f,g){var k,m,h;c.$watch(e.ngIf,function(f){Ua(f)?m||(m=c.$new(),g(m,function(c){c[c.length++]=X.createComment(" end ngIf: "+e.ngIf+
|
||||
" ");k={clone:c};a.enter(c,d.parent(),d)})):(h&&(h.remove(),h=null),m&&(m.$destroy(),m=null),k&&(h=Eb(k.clone),a.leave(h,function(){h=null}),k=null))})}}}],ud=["$http","$templateCache","$anchorScroll","$animate","$sce",function(a,c,d,e,f){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:Va.noop,compile:function(g,k){var m=k.ngInclude||k.src,h=k.onload||"",l=k.autoscroll;return function(g,k,q,r,F){var u=0,t,w,R,z=function(){w&&(w.remove(),w=null);t&&(t.$destroy(),t=null);
|
||||
R&&(e.leave(R,function(){w=null}),w=R,R=null)};g.$watch(f.parseAsResourceUrl(m),function(f){var m=function(){!y(l)||l&&!g.$eval(l)||d()},q=++u;f?(a.get(f,{cache:c}).success(function(a){if(q===u){var c=g.$new();r.template=a;a=F(c,function(a){z();e.enter(a,null,k,m)});t=c;R=a;t.$emit("$includeContentLoaded");g.$eval(h)}}).error(function(){q===u&&z()}),g.$emit("$includeContentRequested")):(z(),r.template=null)})}}}}],Kd=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",
|
||||
link:function(c,d,e,f){d.html(f.template);a(d.contents())(c)}}}],vd=ya({priority:450,compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),wd=ya({terminal:!0,priority:1E3}),xd=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",link:function(e,f,g){var k=g.count,m=g.$attr.when&&f.attr(g.$attr.when),h=g.offset||0,l=e.$eval(m)||{},n={},p=c.startSymbol(),q=c.endSymbol(),s=/^when(Minus)?(.+)$/;r(g,function(a,c){s.test(c)&&(l[K(c.replace("when","").replace("Minus","-"))]=
|
||||
f.attr(g.$attr[c]))});r(l,function(a,e){n[e]=c(a.replace(d,p+k+"-"+h+q))});e.$watch(function(){var c=parseFloat(e.$eval(k));if(isNaN(c))return"";c in l||(c=a.pluralCat(c-h));return n[c](e,f,!0)},function(a){f.text(a)})}}}],yd=["$parse","$animate",function(a,c){var d=C("ngRepeat");return{transclude:"element",priority:1E3,terminal:!0,$$tlb:!0,link:function(e,f,g,k,m){var h=g.ngRepeat,l=h.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),n,p,q,s,t,u,A={$id:Ka};if(!l)throw d("iexp",
|
||||
h);g=l[1];k=l[2];(l=l[3])?(n=a(l),p=function(a,c,d){u&&(A[u]=a);A[t]=c;A.$index=d;return n(e,A)}):(q=function(a,c){return Ka(c)},s=function(a){return a});l=g.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!l)throw d("iidexp",g);t=l[3]||l[1];u=l[2];var y={};e.$watchCollection(k,function(a){var g,k,l=f[0],n,A={},B,I,H,v,E,C,x,J=[];if(Pa(a))C=a,E=p||q;else{E=p||s;C=[];for(H in a)a.hasOwnProperty(H)&&"$"!=H.charAt(0)&&C.push(H);C.sort()}B=C.length;k=J.length=C.length;for(g=0;g<k;g++)if(H=a===
|
||||
C?g:C[g],v=a[H],n=E(H,v,g),Da(n,"`track by` id"),y.hasOwnProperty(n))x=y[n],delete y[n],A[n]=x,J[g]=x;else{if(A.hasOwnProperty(n))throw r(J,function(a){a&&a.scope&&(y[a.id]=a)}),d("dupes",h,n,na(v));J[g]={id:n};A[n]=!1}for(H in y)y.hasOwnProperty(H)&&(x=y[H],g=Eb(x.clone),c.leave(g),r(g,function(a){a.$$NG_REMOVED=!0}),x.scope.$destroy());g=0;for(k=C.length;g<k;g++){H=a===C?g:C[g];v=a[H];x=J[g];J[g-1]&&(l=J[g-1].clone[J[g-1].clone.length-1]);if(x.scope){I=x.scope;n=l;do n=n.nextSibling;while(n&&n.$$NG_REMOVED);
|
||||
x.clone[0]!=n&&c.move(Eb(x.clone),null,w(l));l=x.clone[x.clone.length-1]}else I=e.$new();I[t]=v;u&&(I[u]=H);I.$index=g;I.$first=0===g;I.$last=g===B-1;I.$middle=!(I.$first||I.$last);I.$odd=!(I.$even=0===(g&1));x.scope||m(I,function(a){a[a.length++]=X.createComment(" end ngRepeat: "+h+" ");c.enter(a,null,w(l));l=a;x.scope=I;x.clone=a;A[x.id]=x})}y=A})}}}],zd=["$animate",function(a){return function(c,d,e){c.$watch(e.ngShow,function(c){a[Ua(c)?"removeClass":"addClass"](d,"ng-hide")})}}],sd=["$animate",
|
||||
function(a){return function(c,d,e){c.$watch(e.ngHide,function(c){a[Ua(c)?"addClass":"removeClass"](d,"ng-hide")})}}],Ad=ya(function(a,c,d){a.$watch(d.ngStyle,function(a,d){d&&a!==d&&r(d,function(a,d){c.css(d,"")});a&&c.css(a)},!0)}),Bd=["$animate",function(a){return{restrict:"EA",require:"ngSwitch",controller:["$scope",function(){this.cases={}}],link:function(c,d,e,f){var g=[],k=[],m=[],h=[];c.$watch(e.ngSwitch||e.on,function(d){var n,p;n=0;for(p=m.length;n<p;++n)m[n].remove();n=m.length=0;for(p=
|
||||
h.length;n<p;++n){var q=k[n];h[n].$destroy();m[n]=q;a.leave(q,function(){m.splice(n,1)})}k.length=0;h.length=0;if(g=f.cases["!"+d]||f.cases["?"])c.$eval(e.change),r(g,function(d){var e=c.$new();h.push(e);d.transclude(e,function(c){var e=d.element;k.push(c);a.enter(c,e.parent(),e)})})})}}}],Cd=ya({transclude:"element",priority:800,require:"^ngSwitch",link:function(a,c,d,e,f){e.cases["!"+d.ngSwitchWhen]=e.cases["!"+d.ngSwitchWhen]||[];e.cases["!"+d.ngSwitchWhen].push({transclude:f,element:c})}}),Dd=
|
||||
ya({transclude:"element",priority:800,require:"^ngSwitch",link:function(a,c,d,e,f){e.cases["?"]=e.cases["?"]||[];e.cases["?"].push({transclude:f,element:c})}}),Fd=ya({link:function(a,c,d,e,f){if(!f)throw C("ngTransclude")("orphan",ia(c));f(function(a){c.empty();c.append(a)})}}),fd=["$templateCache",function(a){return{restrict:"E",terminal:!0,compile:function(c,d){"text/ng-template"==d.type&&a.put(d.id,c[0].text)}}}],Ze=C("ngOptions"),Ed=ba({terminal:!0}),gd=["$compile","$parse",function(a,c){var d=
|
||||
/^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,e={$setViewValue:E};return{restrict:"E",require:["select","?ngModel"],controller:["$element","$scope","$attrs",function(a,c,d){var m=this,h={},l=e,n;m.databound=d.ngModel;m.init=function(a,c,d){l=a;n=d};m.addOption=function(c){Da(c,'"option value"');h[c]=!0;l.$viewValue==c&&(a.val(c),n.parent()&&n.remove())};
|
||||
m.removeOption=function(a){this.hasOption(a)&&(delete h[a],l.$viewValue==a&&this.renderUnknownOption(a))};m.renderUnknownOption=function(c){c="? "+Ka(c)+" ?";n.val(c);a.prepend(n);a.val(c);n.prop("selected",!0)};m.hasOption=function(a){return h.hasOwnProperty(a)};c.$on("$destroy",function(){m.renderUnknownOption=E})}],link:function(e,g,k,m){function h(a,c,d,e){d.$render=function(){var a=d.$viewValue;e.hasOption(a)?(v.parent()&&v.remove(),c.val(a),""===a&&u.prop("selected",!0)):x(a)&&u?c.val(""):e.renderUnknownOption(a)};
|
||||
c.on("change",function(){a.$apply(function(){v.parent()&&v.remove();d.$setViewValue(c.val())})})}function l(a,c,d){var e;d.$render=function(){var a=new bb(d.$viewValue);r(c.find("option"),function(c){c.selected=y(a.get(c.value))})};a.$watch(function(){Aa(e,d.$viewValue)||(e=ha(d.$viewValue),d.$render())});c.on("change",function(){a.$apply(function(){var a=[];r(c.find("option"),function(c){c.selected&&a.push(c.value)});d.$setViewValue(a)})})}function n(e,f,g){function k(){var a={"":[]},c=[""],d,h,
|
||||
s,t,v;s=g.$modelValue;t=w(e)||[];var E=n?Zb(t):t,I,M,B;M={};B=!1;if(q)if(h=g.$modelValue,x&&J(h))for(B=new bb([]),d={},v=0;v<h.length;v++)d[m]=h[v],B.put(x(e,d),h[v]);else B=new bb(h);v=B;var D,K;for(B=0;I=E.length,B<I;B++){h=B;if(n){h=E[B];if("$"===h.charAt(0))continue;M[n]=h}M[m]=t[h];d=r(e,M)||"";(h=a[d])||(h=a[d]=[],c.push(d));q?d=y(v.remove(x?x(e,M):u(e,M))):(x?(d={},d[m]=s,d=x(e,d)===x(e,M)):d=s===u(e,M),v=v||d);D=l(e,M);D=y(D)?D:"";h.push({id:x?x(e,M):n?E[B]:B,label:D,selected:d})}q||(F||null===
|
||||
s?a[""].unshift({id:"",label:"",selected:!v}):v||a[""].unshift({id:"?",label:"",selected:!0}));M=0;for(E=c.length;M<E;M++){d=c[M];h=a[d];z.length<=M?(s={element:C.clone().attr("label",d),label:h.label},t=[s],z.push(t),f.append(s.element)):(t=z[M],s=t[0],s.label!=d&&s.element.attr("label",s.label=d));D=null;B=0;for(I=h.length;B<I;B++)d=h[B],(v=t[B+1])?(D=v.element,v.label!==d.label&&D.text(v.label=d.label),v.id!==d.id&&D.val(v.id=d.id),D[0].selected!==d.selected&&(D.prop("selected",v.selected=d.selected),
|
||||
Q&&D.prop("selected",v.selected))):(""===d.id&&F?K=F:(K=A.clone()).val(d.id).prop("selected",d.selected).attr("selected",d.selected).text(d.label),t.push({element:K,label:d.label,id:d.id,selected:d.selected}),p.addOption(d.label,K),D?D.after(K):s.element.append(K),D=K);for(B++;t.length>B;)d=t.pop(),p.removeOption(d.label),d.element.remove()}for(;z.length>M;)z.pop()[0].element.remove()}var h;if(!(h=s.match(d)))throw Ze("iexp",s,ia(f));var l=c(h[2]||h[1]),m=h[4]||h[6],n=h[5],r=c(h[3]||""),u=c(h[2]?
|
||||
h[1]:m),w=c(h[7]),x=h[8]?c(h[8]):null,z=[[{element:f,label:""}]];F&&(a(F)(e),F.removeClass("ng-scope"),F.remove());f.empty();f.on("change",function(){e.$apply(function(){var a,c=w(e)||[],d={},h,l,p,r,s,v,y;if(q)for(l=[],r=0,v=z.length;r<v;r++)for(a=z[r],p=1,s=a.length;p<s;p++){if((h=a[p].element)[0].selected){h=h.val();n&&(d[n]=h);if(x)for(y=0;y<c.length&&(d[m]=c[y],x(e,d)!=h);y++);else d[m]=c[h];l.push(u(e,d))}}else if(h=f.val(),"?"==h)l=t;else if(""===h)l=null;else if(x)for(y=0;y<c.length;y++){if(d[m]=
|
||||
c[y],x(e,d)==h){l=u(e,d);break}}else d[m]=c[h],n&&(d[n]=h),l=u(e,d);g.$setViewValue(l);k()})});g.$render=k;e.$watchCollection(w,k);e.$watchCollection(function(){var a={},c=w(e);if(c){for(var d=Array(c.length),f=0,g=c.length;f<g;f++)a[m]=c[f],d[f]=l(e,a);return d}},k);q&&e.$watchCollection(function(){return g.$modelValue},k)}if(m[1]){var p=m[0];m=m[1];var q=k.multiple,s=k.ngOptions,F=!1,u,A=w(X.createElement("option")),C=w(X.createElement("optgroup")),v=A.clone();k=0;for(var z=g.children(),E=z.length;k<
|
||||
E;k++)if(""===z[k].value){u=F=z.eq(k);break}p.init(m,F,v);q&&(m.$isEmpty=function(a){return!a||0===a.length});s?n(e,g,m):q?l(e,g,m):h(e,g,m,p)}}}}],id=["$interpolate",function(a){var c={addOption:E,removeOption:E};return{restrict:"E",priority:100,compile:function(d,e){if(x(e.value)){var f=a(d.text(),!0);f||e.$set("value",d.text())}return function(a,d,e){var h=d.parent(),l=h.data("$selectController")||h.parent().data("$selectController");l&&l.databound?d.prop("selected",!1):l=c;f?a.$watch(f,function(a,
|
||||
c){e.$set("value",a);a!==c&&l.removeOption(c);l.addOption(a)}):l.addOption(e.value);d.on("$destroy",function(){l.removeOption(e.value)})}}}}],hd=ba({restrict:"E",terminal:!0});W.angular.bootstrap?console.log("WARNING: Tried to load angular more than once."):((Ea=W.jQuery)&&Ea.fn.on?(w=Ea,D(Ea.fn,{scope:La.scope,isolateScope:La.isolateScope,controller:La.controller,injector:La.injector,inheritedData:La.inheritedData}),Gb("remove",!0,!0,!1),Gb("empty",!1,!1,!1),Gb("html",!1,!1,!0)):w=S,Va.element=w,
|
||||
$c(Va),w(X).ready(function(){Xc(X,fc)}))})(window,document);!window.angular.$$csp()&&window.angular.element(document).find("head").prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}.ng-hide-add-active,.ng-hide-remove{display:block!important;}</style>');
|
||||
//# sourceMappingURL=angular.min.js.map
|
8
static/lib/angular.min.js.map
Normal file
44
static/lib/autocomplete.css
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* AUTOCOMPLETE */
|
||||
|
||||
.autocomplete{
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.autocomplete input{
|
||||
font-size: 1.2em;
|
||||
width: 100%;
|
||||
padding:0.4em;
|
||||
}
|
||||
|
||||
.autocomplete ul{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
border-left: 1px solid #888;
|
||||
border-right: 1px solid #888;
|
||||
border-bottom: 1px solid #888;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.autocomplete li{
|
||||
text-align: left;
|
||||
list-style:none;
|
||||
width: 100%;
|
||||
padding:0.4em;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.autocomplete li.active{
|
||||
width: 100%;
|
||||
background-color: #4bf;
|
||||
}
|
||||
|
||||
.autocomplete .highlight {
|
||||
background-color: #E2E2E2;
|
||||
}
|
||||
|
||||
.autocomplete li.active .highlight {
|
||||
background: #666;
|
||||
color: #fff;
|
||||
}
|
284
static/lib/autocomplete.js
Normal file
|
@ -0,0 +1,284 @@
|
|||
/* --- Made by justgoscha and licensed under MIT license --- */
|
||||
|
||||
var app = angular.module('autocomplete', []);
|
||||
|
||||
app.directive('autocomplete', function() {
|
||||
var index = -1;
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
searchParam: '=ngModel',
|
||||
suggestions: '=data',
|
||||
onType: '=onType',
|
||||
onSelect: '=onSelect'
|
||||
},
|
||||
controller: ['$scope', function($scope){
|
||||
// the index of the suggestions that's currently selected
|
||||
$scope.selectedIndex = -1;
|
||||
|
||||
// set new index
|
||||
$scope.setIndex = function(i){
|
||||
$scope.selectedIndex = parseInt(i);
|
||||
};
|
||||
|
||||
this.setIndex = function(i){
|
||||
$scope.setIndex(i);
|
||||
$scope.$apply();
|
||||
};
|
||||
|
||||
$scope.getIndex = function(i){
|
||||
return $scope.selectedIndex;
|
||||
};
|
||||
|
||||
// watches if the parameter filter should be changed
|
||||
var watching = true;
|
||||
|
||||
// autocompleting drop down on/off
|
||||
$scope.completing = false;
|
||||
|
||||
// starts autocompleting on typing in something
|
||||
$scope.$watch('searchParam', function(newValue, oldValue){
|
||||
|
||||
if (oldValue === newValue || !oldValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(watching && typeof $scope.searchParam !== 'undefined' && $scope.searchParam !== null) {
|
||||
$scope.completing = true;
|
||||
$scope.searchFilter = $scope.searchParam;
|
||||
$scope.selectedIndex = -1;
|
||||
}
|
||||
|
||||
// function thats passed to on-type attribute gets executed
|
||||
if($scope.onType)
|
||||
$scope.onType($scope.searchParam);
|
||||
});
|
||||
|
||||
// for hovering over suggestions
|
||||
this.preSelect = function(suggestion){
|
||||
|
||||
watching = false;
|
||||
|
||||
// this line determines if it is shown
|
||||
// in the input field before it's selected:
|
||||
//$scope.searchParam = suggestion;
|
||||
|
||||
$scope.$apply();
|
||||
watching = true;
|
||||
|
||||
};
|
||||
|
||||
$scope.preSelect = this.preSelect;
|
||||
|
||||
this.preSelectOff = function(){
|
||||
watching = true;
|
||||
};
|
||||
|
||||
$scope.preSelectOff = this.preSelectOff;
|
||||
|
||||
// selecting a suggestion with RIGHT ARROW or ENTER
|
||||
$scope.select = function(suggestion){
|
||||
if(suggestion){
|
||||
$scope.searchParam = suggestion;
|
||||
$scope.searchFilter = suggestion;
|
||||
if($scope.onSelect)
|
||||
$scope.onSelect(suggestion);
|
||||
}
|
||||
watching = false;
|
||||
$scope.completing = false;
|
||||
setTimeout(function(){watching = true;},1000);
|
||||
$scope.setIndex(-1);
|
||||
};
|
||||
|
||||
|
||||
}],
|
||||
link: function(scope, element, attrs){
|
||||
|
||||
var attr = '';
|
||||
|
||||
// Default atts
|
||||
scope.attrs = {
|
||||
"placeholder": "start typing...",
|
||||
"class": "",
|
||||
"id": "",
|
||||
"inputclass": "",
|
||||
"inputid": ""
|
||||
};
|
||||
|
||||
for (var a in attrs) {
|
||||
attr = a.replace('attr', '').toLowerCase();
|
||||
// add attribute overriding defaults
|
||||
// and preventing duplication
|
||||
if (a.indexOf('attr') === 0) {
|
||||
scope.attrs[attr] = attrs[a];
|
||||
}
|
||||
}
|
||||
|
||||
if (attrs.clickActivation) {
|
||||
element[0].onclick = function(e){
|
||||
if(!scope.searchParam){
|
||||
scope.completing = true;
|
||||
scope.$apply();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var key = {left: 37, up: 38, right: 39, down: 40 , enter: 13, esc: 27, tab: 9};
|
||||
|
||||
document.addEventListener("keydown", function(e){
|
||||
var keycode = e.keyCode || e.which;
|
||||
|
||||
switch (keycode){
|
||||
case key.esc:
|
||||
// disable suggestions on escape
|
||||
scope.select();
|
||||
scope.setIndex(-1);
|
||||
scope.$apply();
|
||||
e.preventDefault();
|
||||
}
|
||||
}, true);
|
||||
|
||||
document.addEventListener("blur", function(e){
|
||||
// disable suggestions on blur
|
||||
// we do a timeout to prevent hiding it before a click event is registered
|
||||
setTimeout(function() {
|
||||
scope.select();
|
||||
scope.setIndex(-1);
|
||||
scope.$apply();
|
||||
}, 200);
|
||||
}, true);
|
||||
|
||||
element[0].addEventListener("keydown",function (e){
|
||||
var keycode = e.keyCode || e.which;
|
||||
|
||||
var l = angular.element(this).find('li').length;
|
||||
|
||||
// implementation of the up and down movement in the list of suggestions
|
||||
switch (keycode){
|
||||
case key.up:
|
||||
|
||||
index = scope.getIndex()-1;
|
||||
if(index<-1){
|
||||
index = l-1;
|
||||
} else if (index >= l ){
|
||||
index = -1;
|
||||
scope.setIndex(index);
|
||||
scope.preSelectOff();
|
||||
break;
|
||||
}
|
||||
scope.setIndex(index);
|
||||
|
||||
if(index!==-1)
|
||||
scope.preSelect(angular.element(angular.element(this).find('li')[index]).text());
|
||||
|
||||
scope.$apply();
|
||||
|
||||
break;
|
||||
case key.down:
|
||||
index = scope.getIndex()+1;
|
||||
if(index<-1){
|
||||
index = l-1;
|
||||
} else if (index >= l ){
|
||||
index = -1;
|
||||
scope.setIndex(index);
|
||||
scope.preSelectOff();
|
||||
scope.$apply();
|
||||
break;
|
||||
}
|
||||
scope.setIndex(index);
|
||||
|
||||
if(index!==-1)
|
||||
scope.preSelect(angular.element(angular.element(this).find('li')[index]).text());
|
||||
|
||||
break;
|
||||
case key.left:
|
||||
break;
|
||||
case key.right:
|
||||
case key.enter:
|
||||
case key.tab:
|
||||
|
||||
index = scope.getIndex();
|
||||
// scope.preSelectOff();
|
||||
if(index !== -1) {
|
||||
scope.select(angular.element(angular.element(this).find('li')[index]).text());
|
||||
if(keycode == key.enter) {
|
||||
e.preventDefault();
|
||||
}
|
||||
} else {
|
||||
if(keycode == key.enter) {
|
||||
scope.select();
|
||||
}
|
||||
}
|
||||
scope.setIndex(-1);
|
||||
scope.$apply();
|
||||
|
||||
break;
|
||||
case key.esc:
|
||||
// disable suggestions on escape
|
||||
scope.select();
|
||||
scope.setIndex(-1);
|
||||
scope.$apply();
|
||||
e.preventDefault();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
template: '\
|
||||
<div class="autocomplete {{ attrs.class }}" id="{{ attrs.id }}">\
|
||||
<input\
|
||||
type="text"\
|
||||
ng-model="searchParam"\
|
||||
placeholder="{{ attrs.placeholder }}"\
|
||||
class="{{ attrs.inputclass }}"\
|
||||
id="{{ attrs.inputid }}"/>\
|
||||
<ul ng-show="completing && suggestions.length>0">\
|
||||
<li\
|
||||
suggestion\
|
||||
ng-repeat="suggestion in suggestions | filter:searchFilter | orderBy:\'toString()\' track by $index"\
|
||||
index="{{ $index }}"\
|
||||
val="{{ suggestion }}"\
|
||||
ng-class="{ active: ($index === selectedIndex) }"\
|
||||
ng-click="select(suggestion)"\
|
||||
ng-bind-html="suggestion | highlight:searchParam"></li>\
|
||||
</ul>\
|
||||
</div>'
|
||||
};
|
||||
});
|
||||
|
||||
app.filter('highlight', ['$sce', function ($sce) {
|
||||
return function (input, searchParam) {
|
||||
if (typeof input === 'function') return '';
|
||||
if (searchParam) {
|
||||
var words = '(' +
|
||||
searchParam.split(/\ /).join(' |') + '|' +
|
||||
searchParam.split(/\ /).join('|') +
|
||||
')',
|
||||
exp = new RegExp(words, 'gi');
|
||||
if (words.length) {
|
||||
input = input.replace(exp, "<span class=\"highlight\">$1</span>");
|
||||
}
|
||||
}
|
||||
return $sce.trustAsHtml(input);
|
||||
};
|
||||
}]);
|
||||
|
||||
app.directive('suggestion', function(){
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: '^autocomplete', // ^look for controller on parents element
|
||||
link: function(scope, element, attrs, autoCtrl){
|
||||
element.bind('mouseenter', function() {
|
||||
autoCtrl.preSelect(attrs.val);
|
||||
autoCtrl.setIndex(attrs.index);
|
||||
});
|
||||
|
||||
element.bind('mouseleave', function() {
|
||||
autoCtrl.preSelectOff();
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
117
static/lib/ng-toggle.css
Normal file
|
@ -0,0 +1,117 @@
|
|||
.ng-toggle-wrap {
|
||||
display: inline-block;
|
||||
margin: 3px;
|
||||
position: relative;
|
||||
width: 62px;
|
||||
height: 36px;
|
||||
-webkit-backface-visibility: hidden;
|
||||
-webkit-transform: translateZ(0) scale(1.0, 1.0);
|
||||
z-index: 0;
|
||||
}
|
||||
.ng-toggle-wrap:hover {
|
||||
z-index: 1;
|
||||
}
|
||||
.ng-toggle-wrap.vertical {
|
||||
height: 62px;
|
||||
}
|
||||
.ng-toggle-wrap .ng-toggle-switch {
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.ng-toggle-wrap.vertical .ng-toggle-switch {
|
||||
-webkit-transform: translate(-50%, -50%) rotate(-90deg);
|
||||
transform: translate(-50%, -50%) rotate(-90deg);
|
||||
}
|
||||
.ng-toggle-switch {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 56px;
|
||||
height: 30px;
|
||||
display: inline-block;
|
||||
background-color: #ddd;
|
||||
border-radius: 25px;
|
||||
-webkit-transition: background-color .25s ease;
|
||||
transition: background-color .25s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ng-toggle-switch.true {
|
||||
background-color: #68C527;
|
||||
}
|
||||
.ng-toggle-switch.false {
|
||||
background-color: #ff4d35;
|
||||
}
|
||||
.ng-toggle-false {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
}
|
||||
.ng-toggle-true {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
}
|
||||
.ng-toggle-handle {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 100%;
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 16px;
|
||||
-webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.15);
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.15);
|
||||
-webkit-transition: all .2s ease-out;
|
||||
transition: all .2s ease-out;
|
||||
}
|
||||
.ng-toggle-switch.true .ng-toggle-handle {
|
||||
left: 29px;
|
||||
}
|
||||
.ng-toggle-switch.false .ng-toggle-handle {
|
||||
left: 3px;
|
||||
}
|
||||
.ng-toggle-tooltip {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 100%;
|
||||
top: 50%;
|
||||
-webkittransition: opacity .3s ease;
|
||||
transition: opacity .3s ease;
|
||||
transform: translate(-5px, -50%) translateZ(0) scale(1.0, 1.0);
|
||||
-webkit-transform: translate(-5px, -50%) translateZ(0) scale(1.0, 1.0);
|
||||
-webkit-backface-visibility: hidden;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: #CCC;
|
||||
padding: 3px 11px;
|
||||
font-size: 12px;
|
||||
border-radius: 12px;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ng-toggle-wrap:hover .ng-toggle-tooltip {
|
||||
opacity: 1;
|
||||
}
|
||||
.ng-toggle-tooltip:before {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-style: solid;
|
||||
border-width: 4px 0px 4px 5px;
|
||||
border-color: rgba(0, 0, 0, 0) rgba(0, 0, 0, 0) rgba(0, 0, 0, 0) rgba(0, 0, 0, 0.8);
|
||||
position: absolute;
|
||||
right: -6px;
|
||||
top: 50%;
|
||||
-webkit-transform: translate(0, -50%);
|
||||
transform: translate(0, -50%);
|
||||
content: '';
|
||||
pointer-events: none;
|
||||
}
|
||||
.ng-toggle-tooltip .active {
|
||||
color: white;
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, .4);
|
||||
-webkit-transition: all .2s ease;
|
||||
transition: all .2s ease;
|
||||
}
|
337
static/lib/ng-toggle.js
Normal file
|
@ -0,0 +1,337 @@
|
|||
var ngToggle = angular.module('ngToggle', []);
|
||||
ngToggle
|
||||
.directive('ngToggle', function($timeout) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
scope: {
|
||||
config: '=?',
|
||||
ngToggleChange: '&?',
|
||||
ngToggleClick: '&?',
|
||||
val: '=ngModel',
|
||||
ngDefault: '=?',
|
||||
ngTrueVal: '=?',
|
||||
ngFalseVal: '=?',
|
||||
ngNullVal: '=?',
|
||||
ngWidth: '=?',
|
||||
ngHeight: '=?',
|
||||
ngTrueTip: '=?',
|
||||
ngFalseTip: '=?',
|
||||
ngNullTip: '=?',
|
||||
},
|
||||
template: '<div class="ng-toggle-wrap" ng-style="styleWrap" ng-class="{\'vertical\': vertical}"><div class="ng-toggle-switch" ng-style="styleSwitch" ng-class="{\'true\': val==ngTrueVal, \'false\': val==ngFalseVal}" ng-click="toggle()"><div class="ng-toggle-false"></div><div class="ng-toggle-true"></div><div class="ng-toggle-handle" ng-style="styleHandle"></div></div><div class="ng-toggle-tooltip" ng-show="tooltip"><span ng-class="{\'active\': showTooltip1}"><span ng-show="tooltip1"></span>{{tooltip1}} •</span><br ng-show="triToggle"><span ng-class="{\'active\': showTooltip2}" ng-show="triToggle"><span ng-show="tooltip2"></span>{{tooltip2}} •</span><br><span ng-class="{\'active\': showTooltip3}"><span ng-show="tooltip3"></span>{{tooltip3}} •</span></div></div>',
|
||||
link: function(scope, element, attrs) {
|
||||
|
||||
/* Catch Config, allow attr overrides */
|
||||
|
||||
if (angular.isDefined(scope.config)) {
|
||||
|
||||
/* Tri-toggle Setting */
|
||||
|
||||
if (angular.isDefined(scope.config.triToggle) && !angular.isDefined(attrs.triToggle)) {
|
||||
if (scope.config.triToggle) {
|
||||
attrs.triToggle = scope.config.triToggle;
|
||||
}
|
||||
}
|
||||
|
||||
/* ngToggleChange Function */
|
||||
if (angular.isDefined(scope.config.change) && !angular.isDefined(attrs.ngToggleChange)) {
|
||||
scope.ngToggleChange = scope.config.change;
|
||||
}
|
||||
|
||||
/* ngToggleClick Function */
|
||||
|
||||
if (angular.isDefined(scope.config.click) && !angular.isDefined(attrs.ngToggleClick)) {
|
||||
scope.ngToggleClick = scope.config.click;
|
||||
}
|
||||
|
||||
/* Model Binding */
|
||||
|
||||
if (angular.isDefined(scope.config.val) && !angular.isDefined(attrs.val)) {
|
||||
scope.val = scope.config.val;
|
||||
}
|
||||
|
||||
/* Default Value */
|
||||
|
||||
if (angular.isDefined(scope.config.default) && !angular.isDefined(attrs.ngDefault)) {
|
||||
scope.ngDefault = scope.config.default;
|
||||
}
|
||||
|
||||
/* Values */
|
||||
|
||||
if (angular.isDefined(scope.config.trueVal) && !angular.isDefined(attrs.ngTrueVal)) {
|
||||
scope.ngTrueVal = scope.config.trueVal;
|
||||
}
|
||||
if (angular.isDefined(scope.config.falseVal) && !angular.isDefined(attrs.ngFalseVal)) {
|
||||
scope.ngFalseVal = scope.config.falseVal;
|
||||
}
|
||||
if (angular.isDefined(scope.config.nullVal) && !angular.isDefined(attrs.ngNullVal)) {
|
||||
scope.ngNullVal = scope.config.nullVal;
|
||||
}
|
||||
|
||||
/* Width & Height */
|
||||
|
||||
if (angular.isDefined(scope.config.width) && !angular.isDefined(attrs.ngWidth)) {
|
||||
scope.ngWidth = scope.config.width;
|
||||
}
|
||||
if (angular.isDefined(scope.config.height) && !angular.isDefined(attrs.ngHeight)) {
|
||||
scope.ngHeight = scope.config.height;
|
||||
}
|
||||
|
||||
/* Custom Colors */
|
||||
|
||||
if (angular.isDefined(scope.config.falseColor) && !angular.isDefined(attrs.ngFalseColor)) {
|
||||
attrs.ngFalseColor = scope.config.falseColor;
|
||||
}
|
||||
if (angular.isDefined(scope.config.nullColor) && !angular.isDefined(attrs.ngNullColor)) {
|
||||
attrs.ngNullColor = scope.config.nullColor;
|
||||
}
|
||||
if (angular.isDefined(scope.config.trueColor) && !angular.isDefined(attrs.ngTrueColor)) {
|
||||
attrs.ngTrueColor = scope.config.trueColor;
|
||||
}
|
||||
|
||||
/* Vertical Setting */
|
||||
|
||||
if (angular.isDefined(scope.config.vertical) && !angular.isDefined(attrs.vertical)) {
|
||||
attrs.vertical = scope.config.vertical;
|
||||
}
|
||||
|
||||
/* ToolTips */
|
||||
|
||||
if (angular.isDefined(scope.config.trueTip) && !angular.isDefined(attrs.ngTrueTip)) {
|
||||
scope.ngTrueTip = scope.config.trueTip;
|
||||
}
|
||||
if (angular.isDefined(scope.config.falseTip) && !angular.isDefined(attrs.ngFalseTip)) {
|
||||
scope.ngFalseTip = scope.config.falseTip;
|
||||
}
|
||||
if (angular.isDefined(scope.config.nullTip) && !angular.isDefined(attrs.ngNullTip)) {
|
||||
scope.ngNullTip = scope.config.nullTip;
|
||||
}
|
||||
if (!angular.isDefined(scope.ngTrueTip) && !angular.isDefined(attrs.ngFalseTip) && !angular.isDefined(attrs.ngNullTip)) {
|
||||
scope.tooltip = false;
|
||||
} else {
|
||||
scope.tooltip = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Default Styling */
|
||||
|
||||
scope.triToggle = false;
|
||||
scope.vertical = false;
|
||||
scope.styleWrap = {};
|
||||
scope.styleSwitch = {};
|
||||
scope.styleHandle = {};
|
||||
|
||||
/* Is TriToggle? */
|
||||
|
||||
if (angular.isDefined(attrs.triToggle)) {
|
||||
scope.triToggle = true;
|
||||
}
|
||||
|
||||
/* Custom Container Size */
|
||||
|
||||
if (angular.isDefined(scope.ngWidth)) {
|
||||
scope.styleWrap.width = scope.ngWidth + 6 + 'px';
|
||||
}
|
||||
if (angular.isDefined(scope.ngHeight)) {
|
||||
scope.styleWrap.height = scope.ngHeight + 6 + 'px';
|
||||
}
|
||||
|
||||
/* Custom Switch and Handle Size */
|
||||
|
||||
if (angular.isDefined(attrs.vertical) && attrs.vertical) {
|
||||
|
||||
scope.vertical = true;
|
||||
|
||||
scope.tooltip1 = scope.ngTrueTip;
|
||||
scope.tooltip2 = scope.ngNullTip;
|
||||
scope.tooltip3 = scope.ngFalseTip;
|
||||
|
||||
if (angular.isDefined(scope.ngWidth)) {
|
||||
scope.styleSwitch.height = scope.ngWidth + 'px';
|
||||
scope.styleHandle.height = scope.ngWidth - 6 + 'px';
|
||||
}
|
||||
if (angular.isDefined(scope.ngHeight)) {
|
||||
scope.styleSwitch.width = scope.ngHeight + 'px';
|
||||
scope.styleHandle.width = scope.ngHeight * 0.428 + 'px';
|
||||
}
|
||||
} else {
|
||||
|
||||
scope.tooltip1 = scope.ngFalseTip;
|
||||
scope.tooltip2 = scope.ngNullTip;
|
||||
scope.tooltip3 = scope.ngTrueTip;
|
||||
|
||||
if (angular.isDefined(scope.ngWidth)) {
|
||||
scope.styleSwitch.width = scope.ngWidth + 'px';
|
||||
scope.styleHandle.width = scope.ngWidth * 0.428 + 'px';
|
||||
}
|
||||
if (angular.isDefined(scope.ngHeight)) {
|
||||
scope.styleSwitch.height = scope.ngHeight + 'px';
|
||||
scope.styleHandle.height = scope.ngHeight - 6 + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom Border Radii */
|
||||
|
||||
if (angular.isDefined(scope.ngWidth) && angular.isDefined(scope.ngHeight)) {
|
||||
if (scope.ngWidth <= scope.ngHeight) {
|
||||
scope.styleSwitch['border-radius'] = (scope.ngHeight + 6) / 2 + 'px';
|
||||
scope.styleHandle['border-radius'] = scope.ngHeight / 2 + 'px';
|
||||
} else {
|
||||
scope.styleSwitch['border-radius'] = (scope.ngWidth + 6) / 2 + 'px';
|
||||
scope.styleHandle['border-radius'] = scope.ngWidth / 2 + 'px';
|
||||
}
|
||||
} else if (angular.isDefined(scope.ngWidth)) {
|
||||
if (scope.ngWidth <= 30) {
|
||||
scope.styleSwitch['border-radius'] = 18 + 'px';
|
||||
scope.styleHandle['border-radius'] = 15 + 'px';
|
||||
} else {
|
||||
scope.styleSwitch['border-radius'] = (scope.ngWidth + 6) / 2 + 'px';
|
||||
scope.styleHandle['border-radius'] = scope.ngWidth / 2 + 'px';
|
||||
}
|
||||
} else if (angular.isDefined(scope.ngHeight)) {
|
||||
if (scope.ngHeight >= 56) {
|
||||
scope.styleSwitch['border-radius'] = 31 + 'px';
|
||||
scope.styleHandle['border-radius'] = 28 + 'px';
|
||||
} else {
|
||||
scope.styleSwitch['border-radius'] = (scope.ngHeight + 6) / 2 + 'px';
|
||||
scope.styleHandle['border-radius'] = scope.ngHeight / 2 + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom CSS Color Overrides */
|
||||
|
||||
function updateCustomColor() {
|
||||
switch (scope.val) {
|
||||
case scope.ngTrueVal:
|
||||
if (angular.isDefined(attrs.ngTrueColor)) {
|
||||
scope.styleSwitch['background-color'] = attrs.ngTrueColor;
|
||||
}
|
||||
break;
|
||||
case scope.ngFalseVal:
|
||||
if (angular.isDefined(attrs.ngFalseColor)) {
|
||||
scope.styleSwitch['background-color'] = attrs.ngFalseColor;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (scope.triToggle) {
|
||||
if (angular.isDefined(attrs.ngNullColor)) {
|
||||
scope.styleSwitch['background-color'] = attrs.ngNullColor;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom Position Maintenance */
|
||||
|
||||
function equals(val, valtwo) {
|
||||
if (typeof val == 'object' && typeof valtwo == 'object') {
|
||||
if (JSON.stringify(val) === JSON.stringify(valtwo)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return val === valtwo;
|
||||
}
|
||||
|
||||
function updatePosition() {
|
||||
if (equals(scope.val, scope.ngFalseVal)) {
|
||||
if (angular.isDefined(scope.ngWidth)) {
|
||||
scope.styleHandle.left = 3 + 'px';
|
||||
}
|
||||
} else if (equals(scope.val, scope.ngNullVal)) {
|
||||
if (scope.triToggle) {
|
||||
if (angular.isDefined(attrs.vertical) && attrs.vertical) {
|
||||
if (angular.isDefined(scope.ngHeight)) {
|
||||
scope.styleHandle.left = scope.ngHeight * 0.22 + 3 + 'px';
|
||||
}
|
||||
} else if (angular.isDefined(scope.ngWidth)) {
|
||||
scope.styleHandle.left = scope.ngWidth * 0.22 + 3 + 'px';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (angular.isDefined(attrs.vertical) && attrs.vertical) {
|
||||
if (angular.isDefined(scope.ngHeight)) {
|
||||
scope.styleHandle.left = (scope.ngHeight) * 0.517 + 'px';
|
||||
}
|
||||
} else if (angular.isDefined(scope.ngWidth)) {
|
||||
scope.styleHandle.left = (scope.ngWidth) * 0.517 + 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom Tooltip */
|
||||
|
||||
function updateTooltip() {
|
||||
scope.showTooltip1 = false;
|
||||
scope.showTooltip2 = false;
|
||||
scope.showTooltip3 = false;
|
||||
if (scope.val === scope.ngTrueVal) {
|
||||
if (scope.vertical) {
|
||||
scope.showTooltip1 = true;
|
||||
} else {
|
||||
scope.showTooltip3 = true;
|
||||
}
|
||||
} else if (scope.val === scope.ngFalseVal) {
|
||||
if (scope.vertical) {
|
||||
scope.showTooltip3 = true;
|
||||
} else {
|
||||
scope.showTooltip1 = true;
|
||||
}
|
||||
} else {
|
||||
if (scope.triToggle) {
|
||||
scope.showTooltip2 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Logic */
|
||||
|
||||
scope.toggle = function() {
|
||||
if (scope.val === scope.ngTrueVal) {
|
||||
scope.val = scope.ngFalseVal;
|
||||
} else if (scope.val === scope.ngFalseVal && scope.triToggle) {
|
||||
scope.val = scope.ngNullVal;
|
||||
} else {
|
||||
scope.val = scope.ngTrueVal;
|
||||
}
|
||||
if (typeof scope.ngToggleClick != 'undefined') {
|
||||
$timeout(function() {
|
||||
scope.ngToggleClick(scope.val);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
scope.$watch('val', function() {
|
||||
updateCustomColor();
|
||||
updatePosition();
|
||||
updateTooltip();
|
||||
if (typeof scope.ngToggleChange != 'undefined') {
|
||||
$timeout(function() {
|
||||
scope.ngToggleChange(scope.val);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/* Value Configuration */
|
||||
|
||||
if (!angular.isDefined(scope.ngTrueVal)) {
|
||||
scope.ngTrueVal = 1;
|
||||
}
|
||||
if (!angular.isDefined(scope.ngFalseVal)) {
|
||||
scope.ngFalseVal = 0;
|
||||
}
|
||||
if (!angular.isDefined(scope.ngNullVal)) {
|
||||
scope.ngNullVal = null;
|
||||
}
|
||||
if (!angular.isDefined(scope.val)) {
|
||||
if (angular.isDefined(scope.ngDefault)) {
|
||||
scope.val = scope.ngDefault;
|
||||
} else {
|
||||
scope.val = scope.ngNullVal;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
21
static/partials/dates.html
Normal file
|
@ -0,0 +1,21 @@
|
|||
<div class="page">
|
||||
|
||||
<sidebar-loggers open="sidebar" loggers="logWriters" ></sidebar-loggers>
|
||||
|
||||
<block
|
||||
ng-repeat="block in blocks"
|
||||
type="block.type"
|
||||
message-top="block.messageTop"
|
||||
message="block.message"
|
||||
message-bottom="block.messageBottom"
|
||||
force-file="onlyFiles"
|
||||
ng-click="block.click()"
|
||||
></block>
|
||||
|
||||
<div class="nav">
|
||||
<div class="btn previous" ng-click="nextPage(-10)"><</div>
|
||||
<div class="btn pull-right next" ng-click="nextPage(10)">></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
9
static/partials/elements/blocks.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
<div
|
||||
class="block"
|
||||
ng-class="{'block--date' : type == 'date', 'block--file': forceFile}"
|
||||
style="background: {{ color() }}"
|
||||
>
|
||||
<p class="block__message block__message--top" ng-if="messageTop">{{messageTop}}</p>
|
||||
<p class="block__message block__message--middle" ng-if="message">{{message}}</p>
|
||||
<p class="block__message block__message--bottom" ng-if="messageBottom">{{messageBottom}}</p>
|
||||
</div>
|
28
static/partials/elements/log.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
<p class="log">
|
||||
|
||||
<span class="log__item log__time">
|
||||
<span ng-if="showDate != 0 && (showDate == 1 || log.show.date)">
|
||||
{{log.context.time | date: 'EEE MMM dd yyyy'}}
|
||||
</span>
|
||||
<span ng-if="showTime != 0 && (showTime == 1 || log.show.time)">
|
||||
{{log.context.time | date: 'yyyy-MM-ddTHH:mm:ss:Z'}}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="log__item log__tags">
|
||||
<span ng-if="showTags != 0 && (showTags == 1 || log.show.tags)">
|
||||
<span ng-repeat="tag in log.context.tags" class="log__tag bck-tag">{{handleTags(tag)}}</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="log__item log__location">
|
||||
<span ng-if="showFile != 0 && (showFile == 1 || log.show.location)" class="bck-tag">
|
||||
{{log.context.location.filename}}:{{log.context.location.line}}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="log__item log__message" ng-if="log.hasOwnProperty('argsString')" >{{log.argsString}}</span>
|
||||
|
||||
<span class="log__item log__json" ng-if="!log.hasOwnProperty('argsString')">{{log}}</span>
|
||||
|
||||
</p>
|
54
static/partials/elements/menu.html
Normal file
|
@ -0,0 +1,54 @@
|
|||
<div class="menu">
|
||||
|
||||
<ul class="actions">
|
||||
|
||||
<li class="action action--reload a" ng-click="reload()">⟳</li>
|
||||
|
||||
<li class="action">
|
||||
<h4 class="title">Date :</h4>
|
||||
<ng-toggle tri-toggle ng-model="showDate"></ng-toggle>
|
||||
</li>
|
||||
|
||||
<li class="action">
|
||||
<h4 class="title">Time :</h4>
|
||||
<ng-toggle tri-toggle ng-model="showTime"></ng-toggle>
|
||||
</li>
|
||||
|
||||
<li class="action">
|
||||
<h4 class="title">Tags :</h4>
|
||||
<ng-toggle tri-toggle ng-model="showTags"></ng-toggle>
|
||||
</li>
|
||||
|
||||
<li class="action">
|
||||
<h4 class="title">File :</h4>
|
||||
<ng-toggle tri-toggle ng-model="showFile"></ng-toggle>
|
||||
</li>
|
||||
|
||||
<li class="action">
|
||||
|
||||
<h4 class="title">Order by :</h4>
|
||||
|
||||
<select ng-model="order">
|
||||
<option value="context.time">Time</option>
|
||||
<option value="context.tags">Tags</option>
|
||||
<option value="context.location">File</option>
|
||||
<option value="argsString">Message</option>
|
||||
</select>
|
||||
|
||||
<form action="">
|
||||
<input type="checkbox" id="reverseOrder" ng-model="reverse">
|
||||
<label class="title tiny" for="reverseOrder">Reverse</label>
|
||||
</form>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="action action--search pull-right">
|
||||
<h4 class="title">Filter :</h4>
|
||||
<form action="">
|
||||
<input type="text" class="input" ng-model="search">
|
||||
</form>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
15
static/partials/elements/sidebarLoggers.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
<div class="sidebar" ng-class="{'sidebar--open' : sidebar}">
|
||||
|
||||
<h3 class="sidebar__title">
|
||||
Loggers
|
||||
</h3>
|
||||
|
||||
<ul class="content">
|
||||
|
||||
<li ng-repeat="logger in logWriters" class="sidebar__item">
|
||||
<a href="" ng-click="go(mode, {path : logger});">{{logger}}</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
35
static/partials/elements/sidebarLogs.html
Normal file
|
@ -0,0 +1,35 @@
|
|||
<div class="sidebar" ng-class="{'sidebar--open' : sidebar}">
|
||||
|
||||
<h3 class="sidebar__title">
|
||||
Files
|
||||
<span class="tiny pull-right">
|
||||
<form action="">
|
||||
<input type="checkbox" id="selectAll" ng-model="selectAll">
|
||||
<label for="selectAll">Select all</label>
|
||||
</form>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<ul class="content">
|
||||
|
||||
<li ng-repeat="file in currentFiles" class="sidebar__item">
|
||||
<form action="">
|
||||
<input type="checkbox" id="check{{$id}}" ng-model="file.selected">
|
||||
<label for="check{{$id}}">{{file.name}}</label>
|
||||
</form>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<h3 class="sidebar__title">Add a file</h3>
|
||||
<autocomplete
|
||||
ng-model="fileToAdd"
|
||||
data="allLogsFiles"
|
||||
on-select="addFile"
|
||||
ng-keyup="$event.keyCode == 13 && addFile(fileToAdd)"
|
||||
click-activation="true"
|
||||
attr-placeholder="A path"
|
||||
attr-input-class="input"
|
||||
class="sidebar__block"></autocomplete>
|
||||
|
||||
</div>
|
15
static/partials/folder.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
<div class="page">
|
||||
|
||||
<sidebar-loggers open="sidebar" loggers="logWriters" ></sidebar-loggers>
|
||||
|
||||
<block
|
||||
ng-repeat="block in blocks"
|
||||
type="block.type"
|
||||
message-top="block.messageTop"
|
||||
message="block.message"
|
||||
message-bottom="block.messageBottom"
|
||||
force-file="onlyFiles"
|
||||
ng-click="block.click()"
|
||||
></block>
|
||||
</div>
|
||||
|
23
static/partials/logs.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
<div class="page">
|
||||
|
||||
<sidebar-logs files="currentFiles" open="sidebar"></sidebar-logs>
|
||||
|
||||
<menu></menu>
|
||||
|
||||
<div class="logs__wrapper">
|
||||
<log
|
||||
ng-repeat="line in lines | orderBy : order : reverse | filter : search track by $index"
|
||||
log="line"
|
||||
show-file="showFile"
|
||||
show-time="showTime"
|
||||
show-date="showDate"
|
||||
show-tags="showTags"
|
||||
></log>
|
||||
</div>
|
||||
|
||||
<div class="logs__empty" ng-if="lines.length == 0">
|
||||
<h1>No file selected</h1>
|
||||
<h2>← Open menu</h2>
|
||||
</div>
|
||||
|
||||
</div>
|
398
static/style.css
Normal file
|
@ -0,0 +1,398 @@
|
|||
|
||||
/*
|
||||
* Scribe.js style
|
||||
*/
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
font-family: Consolas, Menlo, Monaco, Lucida Console,
|
||||
Liberation Mono, DejaVu Sans Mono,
|
||||
Bitstream Vera Sans Mono, Courier New, monospace, serif;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border: 0;
|
||||
background: #161d25;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.a:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pull-left {
|
||||
float: left;
|
||||
}
|
||||
.pull-right {
|
||||
float: right;
|
||||
}
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.tiny {
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.input {
|
||||
border-radius: 2px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.bck-tag {
|
||||
background: #04c25f;
|
||||
border-radius: 3px;
|
||||
color: #000;
|
||||
margin-right: 2px;
|
||||
padding: 2px 4px;
|
||||
text-transform: uppercase;
|
||||
font-size: 9px;
|
||||
letter-spacing: 1px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.page {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-top: 50px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(10, 10, 10, 0.2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Header
|
||||
*/
|
||||
.header {
|
||||
position : absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 4;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background: #34495e;
|
||||
box-shadow: #101 0px 0px 6px;
|
||||
}
|
||||
.header__menu-button {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 9px;
|
||||
height: 30px;
|
||||
width: 40px;
|
||||
|
||||
border-radius: 3px;
|
||||
background: url("img/menu.png") center center no-repeat;
|
||||
background-size: 67%;
|
||||
cursor: pointer;
|
||||
background-color: #2980b9;
|
||||
border: 1px solid rgba(255, 255, 255, 0.05)
|
||||
}
|
||||
.header__title {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 70px;
|
||||
height: 30px;
|
||||
width: 500px;
|
||||
font-size: 9px;
|
||||
line-height: 33px;
|
||||
font-weight: 300;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
color: #fff;
|
||||
}
|
||||
.header__mode {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 180px;
|
||||
color: #e2e2e2;
|
||||
}
|
||||
.header__mode > * {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.header__logo {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
width: 168px;
|
||||
background: url("img/logo.png") center right no-repeat;
|
||||
background-size: 65%;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sidebar
|
||||
*/
|
||||
.sidebar {
|
||||
position : absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 3;
|
||||
overflow-y: auto;
|
||||
width: 300px;
|
||||
padding-top: 50px;
|
||||
background: #111;
|
||||
color: #fff;
|
||||
transform: translate3d(-360px, 0, 0);
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
.sidebar--open {
|
||||
box-shadow: #111 0 0 20px 0;
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
.sidebar__title {
|
||||
font-size: 18px;
|
||||
padding: 0 22px;
|
||||
margin: 22px 0;
|
||||
}
|
||||
.sidebar__block {
|
||||
list-style: none;
|
||||
width: 100%;
|
||||
}
|
||||
.sidebar__item {
|
||||
list-style: none;
|
||||
width: 100%;
|
||||
padding-left: 22px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.sidebar__item a {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks
|
||||
*/
|
||||
.block {
|
||||
display: inline-block;
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
margin: 10px;
|
||||
margin-right: 0;
|
||||
|
||||
color: rgba(255, 255, 255, 0.39);
|
||||
font-family: "Open Sans";
|
||||
font-size: 53px;
|
||||
text-align: center;
|
||||
line-height: 49px;
|
||||
font-weight: 300;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
|
||||
background: #393e41;
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
cursor: pointer;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
.block:hover {
|
||||
background: #595e50;
|
||||
}
|
||||
.block__message {
|
||||
margin: 0;
|
||||
font-family: "Open Sans";
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
}
|
||||
.block__message--top {
|
||||
padding-top: 6px;
|
||||
}
|
||||
.block__message--middle {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
line-height: 200px;
|
||||
}
|
||||
.block__message--top + .block__message--middle {
|
||||
height: auto;
|
||||
line-height: 32px;
|
||||
}
|
||||
.block--file {
|
||||
height: 48px;
|
||||
width: 98%;
|
||||
margin: 4px 1%;
|
||||
padding: 8px;
|
||||
}
|
||||
.block--file:nth-child(2) {
|
||||
margin-top: 12px;
|
||||
}
|
||||
.block--file .block__message {
|
||||
text-align: left;
|
||||
line-height: 30px;
|
||||
width: auto
|
||||
}
|
||||
.block--date {}
|
||||
.block--date .block__message--top {
|
||||
letter-spacing: 2px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.block--date .block__message--middle {
|
||||
font-size: 92px;
|
||||
color: #fff;
|
||||
font-weight: 300;
|
||||
line-height: 93px;
|
||||
}
|
||||
.block--date .block__message--bottom {
|
||||
letter-spacing: 2px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nav
|
||||
*/
|
||||
.nav {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.nav > .btn {
|
||||
display: inline-block;
|
||||
padding: 4px 14px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
box-shadow: #101 0px 0px 6px;
|
||||
border-radius : 4px;
|
||||
font-size: 38px;
|
||||
color: #e2e2e2;
|
||||
}
|
||||
.nav > .btn:hover {
|
||||
cursor: pointer;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu
|
||||
*/
|
||||
.menu {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.actions {
|
||||
margin: 0;
|
||||
padding: 0 6px;
|
||||
}
|
||||
.action {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
list-style: none;
|
||||
}
|
||||
.action > * {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.action .title {
|
||||
color: #e2e2e2;
|
||||
font-weight: 400;
|
||||
}
|
||||
.action--search > * {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.action--search input {
|
||||
height: 24px;
|
||||
min-width: 190px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.action--reload {
|
||||
color: #e2e2e2;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log
|
||||
*/
|
||||
.logs__wrapper {
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
max-width: 100%;
|
||||
}
|
||||
.log {
|
||||
display: table-row;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
font-size: 11px;
|
||||
line-height: 20px;
|
||||
color: #bebebe;
|
||||
}
|
||||
.log__item {
|
||||
display: table-cell;
|
||||
padding: 0 6px;
|
||||
}
|
||||
.log__tags {}
|
||||
.log__tag {}
|
||||
.log__time {}
|
||||
.log__location {}
|
||||
.log__location > span {
|
||||
background: #2980b9;
|
||||
}
|
||||
.log__message {
|
||||
white-space: pre;
|
||||
}
|
||||
.log__json {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.logs__empty {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
color: #e2e2e2
|
||||
}
|
||||
.logs__empty > * {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/**
|
||||
* ngToggle
|
||||
*/
|
||||
.ng-toggle-wrap {
|
||||
margin: 2px;
|
||||
}
|
||||
.ng-toggle-switch {
|
||||
width: 42px;
|
||||
height: 22px;
|
||||
}
|
||||
.ng-toggle-handle {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
left: 12px;
|
||||
}
|
||||
.ng-toggle-switch.true .ng-toggle-handle {
|
||||
left: 22px;
|
||||
}
|
||||
|
||||
/**
|
||||
* autocomplete
|
||||
*/
|
||||
.autocomplete {
|
||||
color: black;
|
||||
}
|
||||
.autocomplete > ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.sidebar__block > .autocomplete {
|
||||
padding: 0 22px;
|
||||
}
|
||||
.sidebar__block > .autocomplete > ul {
|
||||
left: 22px;
|
||||
right: 22px;
|
||||
width: auto;
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
/*
|
||||
======== A Handy Little Nodeunit Reference ========
|
||||
https://github.com/caolan/nodeunit
|
||||
|
||||
Test methods:
|
||||
test.expect(numAssertions)
|
||||
test.done()
|
||||
Test assertions:
|
||||
test.ok(value, [message])
|
||||
test.equal(actual, expected, [message])
|
||||
test.notEqual(actual, expected, [message])
|
||||
test.deepEqual(actual, expected, [message])
|
||||
test.notDeepEqual(actual, expected, [message])
|
||||
test.strictEqual(actual, expected, [message])
|
||||
test.notStrictEqual(actual, expected, [message])
|
||||
test.throws(block, [error], [message])
|
||||
test.doesNotThrow(block, [error], [message])
|
||||
test.ifError(value)
|
||||
*/
|
||||
|
||||
var scribe = require('../');
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
|
||||
exports['read'] = {
|
||||
"to-obj": function(test) {
|
||||
test.expect(1);
|
||||
|
||||
// Configuration
|
||||
// --------------
|
||||
scribe.configure(function() {
|
||||
scribe.set('app', 'MY_APP_NAME'); // NOTE Best way learn about these settings is
|
||||
scribe.set('logPath', './test/logs'); // Doublecheck // them out for yourself.
|
||||
scribe.set('defaultTag', 'DEFAULT_TAG');
|
||||
scribe.set('divider', ':::');
|
||||
scribe.set('identation', 5); // Identation before console messages
|
||||
|
||||
scribe.set('maxTagLength', 30); // Any tags that have a length greather than
|
||||
// 30 characters will be ignored
|
||||
|
||||
// scribe.set('mainUser', 'root'); // Username of the account which is running
|
||||
// the NodeJS server
|
||||
});
|
||||
|
||||
// Create Loggers
|
||||
// --------------
|
||||
scribe.addLogger("log", true, true, 'green'); // (name, save to file, print to console,
|
||||
scribe.addLogger('realtime', true, true, 'underline'); // tag color)
|
||||
scribe.addLogger('high', true, true, 'magenta');
|
||||
scribe.addLogger('normal', true, true, 'white');
|
||||
scribe.addLogger('low', true, true, 'grey');
|
||||
scribe.addLogger('info', true, true, 'cyan');
|
||||
|
||||
// Express.js
|
||||
// WARNING: ExpressJS must be installed for this to work
|
||||
// You also need to start an ExpressJS server in order for
|
||||
// this to work.
|
||||
// --------------
|
||||
app.use(scribe.express.logger(function(req, res) { // Express.js access log
|
||||
return true; // Filter out any Express messages
|
||||
}));
|
||||
|
||||
// Control Panel
|
||||
// WARNING: ExpressJS must be installed for this to work
|
||||
// You also need to start an ExpressJS server in order for
|
||||
// this to work.
|
||||
// --------------
|
||||
app.get('/log', scribe.express.controlPanel()); // Enable web control panel
|
||||
|
||||
var server = app.listen(2000, function() {
|
||||
console.log('Listening on port %d', server.address().port);
|
||||
});
|
||||
|
||||
// Basic logging
|
||||
// --------------
|
||||
console.log("[Tagname] Your message"); // [Tagname] Your message
|
||||
console.realtime("[Tagname] Your message"); // [Tagname] Your message
|
||||
console.high("[Tagname] Your message "); // [Tagname] Your message
|
||||
console.normal("[Tagname][]Your message"); // [Tagname] []Your message
|
||||
console.low("[Tagname]Your message"); // [Tagname] Your message
|
||||
|
||||
// Tagging function
|
||||
// ----------------
|
||||
console.t("Tagname").log("Your message"); // [Tagname] Your message
|
||||
console.t("Tagname").log("Your message"); // [Tagname] Your message
|
||||
console.t("Tagname").log("Your message"); // [Tagname] Your message
|
||||
|
||||
// Force use default tag
|
||||
// ---------------------
|
||||
console.t().log("Your message"); // [MY_APP_NAME] Your message
|
||||
|
||||
// Pass in file name
|
||||
// -----------------
|
||||
console.f(__filename).log("Your message"); // [file.js] Your message
|
||||
|
||||
// Auto tagging
|
||||
// ------------
|
||||
console.log("Your message"); // [invokedFrom.js:25] Your message
|
||||
|
||||
// Tag Scoping
|
||||
// -----------
|
||||
(function(console) {
|
||||
|
||||
console.info("yeeha"); // [scoped-tag] yeeha
|
||||
console.log("yeeha"); // [scoped-tag] yeeha
|
||||
|
||||
})(console.t('scoped-tag'));
|
||||
|
||||
console.warn("For the web view...");
|
||||
console.warn("Please visit http://localhost:2000/log");
|
||||
|
||||
// test.equal(true, true);
|
||||
// test.done();
|
||||
}
|
||||
};
|
146
test/usage.js
|
@ -1,146 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
/*
|
||||
======== A Handy Little Nodeunit Reference ========
|
||||
https://github.com/caolan/nodeunit
|
||||
|
||||
Test methods:
|
||||
test.expect(numAssertions)
|
||||
test.done()
|
||||
Test assertions:
|
||||
test.ok(value, [message])
|
||||
test.equal(actual, expected, [message])
|
||||
test.notEqual(actual, expected, [message])
|
||||
test.deepEqual(actual, expected, [message])
|
||||
test.notDeepEqual(actual, expected, [message])
|
||||
test.strictEqual(actual, expected, [message])
|
||||
test.notStrictEqual(actual, expected, [message])
|
||||
test.throws(block, [error], [message])
|
||||
test.doesNotThrow(block, [error], [message])
|
||||
test.ifError(value)
|
||||
*/
|
||||
|
||||
var scribe = require('../');
|
||||
|
||||
exports['read'] = {
|
||||
"to-obj": function(test) {
|
||||
test.expect(1);
|
||||
|
||||
// Configuration
|
||||
// --------------
|
||||
scribe.configure(function() {
|
||||
scribe.set('app', 'MY_APP_NAME'); // NOTE Best way learn about these settings is
|
||||
scribe.set('logPath', './test/logs'); // Doublecheck // them out for yourself.
|
||||
scribe.set('defaultTag', 'DEFAULT_TAG');
|
||||
scribe.set('divider', ':::');
|
||||
scribe.set('identation', 5); // Identation before console messages
|
||||
|
||||
scribe.set('maxTagLength', 50); // Any tags that have a length greather than
|
||||
// 30 characters will be ignored
|
||||
|
||||
// scribe.set('mainUser', 'root'); // Username of the account which is running
|
||||
// the NodeJS server
|
||||
});
|
||||
|
||||
// Create Loggers
|
||||
// --------------
|
||||
scribe.addLogger("log", true, true, 'green'); // (name, save to file, print to console,
|
||||
scribe.addLogger('realtime', true, true, 'underline'); // tag color)
|
||||
scribe.addLogger('high', true, true, 'magenta');
|
||||
scribe.addLogger('normal', true, true, 'white');
|
||||
scribe.addLogger('low', true, true, 'grey');
|
||||
scribe.addLogger('info', true, true, 'cyan');
|
||||
|
||||
|
||||
// Basic logging
|
||||
// --------------
|
||||
console.log("[Tagname] Your message"); // [Tagname] Your message
|
||||
console.realtime("[Tagname] Your message"); // [Tagname] Your message
|
||||
console.high("[Tagname] Your message "); // [Tagname] Your message
|
||||
console.normal("[Tagname][]Your message"); // [Tagname] []Your message
|
||||
console.low("[Tagname]Your message"); // [Tagname] Your message
|
||||
|
||||
// Tagging function
|
||||
// ----------------
|
||||
console.t("Tagname").log("Your message"); // [Tagname] Your message
|
||||
console.t("Tagname").log("Your message"); // [Tagname] Your message
|
||||
console.t("Tagname").log("Your message"); // [Tagname] Your message
|
||||
|
||||
// Force use default tag
|
||||
// ---------------------
|
||||
console.t().log("Your message"); // [MY_APP_NAME] Your message
|
||||
|
||||
// Pass in file name
|
||||
// -----------------
|
||||
console.f(__filename).log("Your message"); // [file.js] Your message
|
||||
|
||||
// Auto tagging
|
||||
// ------------
|
||||
console.log("Your message"); // [invokedFrom.js:25] Your message
|
||||
|
||||
// Tag Scoping
|
||||
// -----------
|
||||
(function(console) {
|
||||
|
||||
console.info("yeeha");
|
||||
console.log("yeeha");
|
||||
|
||||
// Tag Scoping
|
||||
// -----------
|
||||
(function(console) {
|
||||
|
||||
// Tag Scoping
|
||||
// -----------
|
||||
(function(console) {
|
||||
|
||||
console.info("yeeha");
|
||||
console.log("yeeha");
|
||||
|
||||
})(console.t('l3'));
|
||||
|
||||
console.info("yeeha");
|
||||
console.log("yeeha");
|
||||
|
||||
})(console.t('l2'));
|
||||
|
||||
})(console.t('l1'));
|
||||
|
||||
|
||||
// File Scoping
|
||||
// -----------
|
||||
(function(console) {
|
||||
|
||||
console.info("yeeha");
|
||||
console.log("yeeha");
|
||||
|
||||
// File Scoping
|
||||
// -----------
|
||||
(function(console) {
|
||||
|
||||
// File Scoping
|
||||
// -----------
|
||||
(function(console) {
|
||||
|
||||
// Note: a use of console.t(...) resets the
|
||||
console.t("LOL").info("yeeha");
|
||||
|
||||
console.info("yeeha");
|
||||
console.log("yeeha");
|
||||
|
||||
})(console.f());
|
||||
|
||||
console.info("yeeha");
|
||||
console.log("yeeha");
|
||||
|
||||
})(console.f());
|
||||
|
||||
})(console.f());
|
||||
|
||||
// Simple Testing
|
||||
// --------------
|
||||
console.test("Test name").should(5).be(5); // Pretty printed test results
|
||||
|
||||
test.equal(true, true);
|
||||
test.done();
|
||||
}
|
||||
};
|