diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..d280a2850
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,9 @@
+[submodule "vendor/extensions/extensions-manager"]
+ path = vendor/extensions/extensions-manager
+ url = https://github.com/sn-extensions/extensions-manager.git
+[submodule "app/extensions/extensions-manager"]
+ path = app/extensions/extensions-manager
+ url = https://github.com/sn-extensions/extensions-manager.git
+[submodule "public/extensions/extensions-manager"]
+ path = public/extensions/extensions-manager
+ url = https://github.com/sn-extensions/extensions-manager.git
diff --git a/Capfile b/Capfile
index 08de6d646..532cfeef5 100644
--- a/Capfile
+++ b/Capfile
@@ -4,6 +4,12 @@ require "capistrano/setup"
# Include default deployment tasks
require "capistrano/deploy"
+require "capistrano/scm/git"
+install_plugin Capistrano::SCM::Git
+
+require "capistrano/scm/git-with-submodules"
+install_plugin Capistrano::SCM::Git::WithSubmodules
+
# Include tasks from other gems included in your Gemfile
#
# For documentation on these, see for example:
@@ -23,7 +29,6 @@ require 'capistrano/rails/assets'
# require 'capistrano/rails/migrations'
require 'capistrano/passenger'
# require 'capistrano/sidekiq'
-require 'capistrano/git-submodule-strategy'
# require "whenever/capistrano" # Update crontab on deploy
diff --git a/Gemfile b/Gemfile
index 753576444..906d29d4c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -44,5 +44,5 @@ group :development, :test do
gem 'capistrano-rails'
gem 'capistrano-rvm'
gem 'capistrano-sidekiq'
- gem 'capistrano-git-submodule-strategy', '~> 0.1.22'
+ gem 'capistrano-git-with-submodules', '~> 2.0'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 7c79bb6c2..d70ec701e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -38,74 +38,75 @@ GEM
i18n (~> 0.7)
minitest (~> 5.1)
tzinfo (~> 1.1)
- airbrussh (1.1.1)
+ airbrussh (1.3.0)
sshkit (>= 1.6.1, != 1.7.0)
arel (7.1.4)
- binding_of_caller (0.7.2)
+ binding_of_caller (0.8.0)
debug_inspector (>= 0.0.1)
bower-rails (0.10.0)
- builder (3.2.2)
- byebug (9.0.6)
- capistrano (3.6.1)
+ builder (3.2.3)
+ byebug (10.0.0)
+ capistrano (3.10.1)
airbrussh (>= 1.0.0)
- capistrano-harrow
i18n
rake (>= 10.0.0)
sshkit (>= 1.9.0)
- capistrano-bundler (1.2.0)
+ capistrano-bundler (1.3.0)
capistrano (~> 3.1)
sshkit (~> 1.2)
- capistrano-git-submodule-strategy (0.1.22)
- capistrano (~> 3.1)
- capistrano-harrow (0.5.3)
+ capistrano-git-with-submodules (2.0.3)
+ capistrano (~> 3.7)
capistrano-passenger (0.2.0)
capistrano (~> 3.0)
- capistrano-rails (1.2.0)
+ capistrano-rails (1.3.1)
capistrano (~> 3.1)
capistrano-bundler (~> 1.1)
capistrano-rvm (0.1.2)
capistrano (~> 3.0)
sshkit (~> 1.2)
- capistrano-sidekiq (0.10.0)
- capistrano
+ capistrano-sidekiq (1.0.0)
+ capistrano (>= 3.9.0)
sidekiq (>= 3.4)
- concurrent-ruby (1.0.2)
+ concurrent-ruby (1.0.5)
connection_pool (2.2.1)
- debug_inspector (0.0.2)
- dotenv (2.1.1)
- dotenv-rails (2.1.1)
- dotenv (= 2.1.1)
- railties (>= 4.0, < 5.1)
+ crass (1.0.3)
+ debug_inspector (0.0.3)
+ dotenv (2.1.2)
+ dotenv-rails (2.1.2)
+ dotenv (= 2.1.2)
+ railties (>= 3.2, < 5.1)
erubis (2.7.0)
execjs (2.7.0)
- globalid (0.3.7)
- activesupport (>= 4.1.0)
- haml (4.0.7)
+ ffi (1.9.18)
+ globalid (0.4.1)
+ activesupport (>= 4.2.0)
+ haml (5.0.4)
+ temple (>= 0.8.0)
tilt
- i18n (0.7.0)
- json (1.8.3)
- loofah (2.0.3)
+ i18n (0.9.3)
+ concurrent-ruby (~> 1.0)
+ json (1.8.6)
+ loofah (2.1.1)
+ crass (~> 1.0.2)
nokogiri (>= 1.5.9)
- mail (2.6.4)
- mime-types (>= 1.16, < 4)
- method_source (0.8.2)
- mime-types (3.1)
- mime-types-data (~> 3.2015)
- mime-types-data (3.2016.0521)
- mini_portile2 (2.1.0)
- minitest (5.9.1)
+ mail (2.7.0)
+ mini_mime (>= 0.1.1)
+ method_source (0.9.0)
+ mini_mime (1.0.0)
+ mini_portile2 (2.3.0)
+ minitest (5.11.3)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
- net-ssh (3.2.0)
+ net-ssh (4.2.0)
nio4r (1.2.1)
- nokogiri (1.6.8.1)
- mini_portile2 (~> 2.1.0)
+ nokogiri (1.8.2)
+ mini_portile2 (~> 2.3.0)
non-stupid-digest-assets (1.0.9)
sprockets (>= 2.0)
- puma (3.6.2)
- rack (2.0.1)
- rack-cors (1.0.0)
- rack-protection (1.5.3)
+ puma (3.11.2)
+ rack (2.0.3)
+ rack-cors (1.0.2)
+ rack-protection (2.0.0)
rack
rack-test (0.6.3)
rack (>= 1.0)
@@ -121,9 +122,9 @@ GEM
bundler (>= 1.3.0, < 2.0)
railties (= 5.0.0.1)
sprockets-rails (>= 2.0.0)
- rails-dom-testing (2.0.1)
- activesupport (>= 4.2.0, < 6.0)
- nokogiri (~> 1.6.0)
+ rails-dom-testing (2.0.3)
+ activesupport (>= 4.2.0)
+ nokogiri (>= 1.6)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
railties (5.0.0.1)
@@ -132,50 +133,59 @@ GEM
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
- rake (11.3.0)
+ rake (12.3.0)
+ rb-fsevent (0.10.2)
+ rb-inotify (0.9.10)
+ ffi (>= 0.5.0, < 2)
rdoc (4.3.0)
- redis (3.3.2)
- responders (2.3.0)
- railties (>= 4.2.0, < 5.1)
- sass (3.4.22)
+ redis (4.0.1)
+ responders (2.4.0)
+ actionpack (>= 4.2.0, < 5.3)
+ railties (>= 4.2.0, < 5.3)
+ sass (3.5.5)
+ sass-listen (~> 4.0.0)
+ sass-listen (4.0.0)
+ rb-fsevent (~> 0.9, >= 0.9.4)
+ rb-inotify (~> 0.9, >= 0.9.7)
sdoc (0.4.2)
json (~> 1.7, >= 1.7.7)
rdoc (~> 4.0)
- secure_headers (3.6.7)
- useragent
- sidekiq (4.2.7)
+ secure_headers (5.0.4)
+ useragent (>= 0.15.0)
+ sidekiq (5.0.5)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
rack-protection (>= 1.5.0)
- redis (~> 3.2, >= 3.2.1)
- spring (2.0.0)
+ redis (>= 3.3.4, < 5)
+ spring (2.0.2)
activesupport (>= 4.2)
- sprockets (3.7.0)
+ sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
- sprockets-rails (3.2.0)
+ sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
- sshkit (1.11.4)
+ sshkit (1.15.1)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
- thor (0.19.4)
- thread_safe (0.3.5)
- tilt (2.0.5)
- tzinfo (1.2.2)
+ temple (0.8.0)
+ thor (0.20.0)
+ thread_safe (0.3.6)
+ tilt (2.0.8)
+ tzinfo (1.2.4)
thread_safe (~> 0.1)
- uglifier (3.0.3)
+ uglifier (4.1.5)
execjs (>= 0.3.0, < 3)
- useragent (0.16.8)
+ useragent (0.16.9)
web-console (2.3.0)
activemodel (>= 4.0)
binding_of_caller (>= 0.7.2)
railties (>= 4.0)
sprockets-rails (>= 2.0, < 4.0)
- websocket-driver (0.6.4)
+ websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
- websocket-extensions (0.1.2)
+ websocket-extensions (0.1.3)
PLATFORMS
ruby
@@ -185,7 +195,7 @@ DEPENDENCIES
byebug
capistrano
capistrano-bundler
- capistrano-git-submodule-strategy (~> 0.1.22)
+ capistrano-git-with-submodules (~> 2.0)
capistrano-passenger (>= 0.2.0)
capistrano-rails
capistrano-rvm
@@ -205,4 +215,4 @@ DEPENDENCIES
web-console (~> 2.0)
BUNDLED WITH
- 1.15.1
+ 1.16.1
diff --git a/Gruntfile.js b/Gruntfile.js
index 7aecbdebc..6878b6524 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -34,7 +34,7 @@ module.exports = function(grunt) {
style: 'expanded'
},
files: {
- 'vendor/assets/stylesheets/app.css': 'app/assets/stylesheets/frontend.css.scss'
+ 'vendor/assets/stylesheets/app.css': 'app/assets/stylesheets/main.css.scss'
}
}
},
@@ -59,7 +59,7 @@ module.exports = function(grunt) {
src: ['**/*.html'],
dest: 'vendor/assets/javascripts/templates.js',
options: {
- module: 'app.frontend'
+ module: 'app'
}
}
},
@@ -70,12 +70,13 @@ module.exports = function(grunt) {
},
app: {
src: [
- 'app/assets/javascripts/app/services/encryption/*.js',
+ 'app/assets/javascripts/app/services/encryption/*.js', // this should come first
'app/assets/javascripts/app/*.js',
- 'app/assets/javascripts/app/frontend/*.js',
- 'app/assets/javascripts/app/frontend/controllers/*.js',
- 'app/assets/javascripts/app/frontend/models/**/*.js',
- 'app/assets/javascripts/app/services/**/*.js'
+ 'app/assets/javascripts/app/controllers/**/*.js',
+ 'app/assets/javascripts/app/models/**/*.js',
+ 'app/assets/javascripts/app/services/**/*.js',
+ 'app/assets/javascripts/app/filters/**/*.js',
+ 'app/assets/javascripts/app/directives/**/*.js',
],
dest: 'vendor/assets/javascripts/app.js',
},
@@ -95,8 +96,12 @@ module.exports = function(grunt) {
},
css: {
+ options: {
+ separator: '',
+ },
src: [
- 'vendor/assets/stylesheets/app.css'
+ 'vendor/assets/stylesheets/app.css',
+ 'node_modules/sn-stylekit/dist/stylekit.css'
],
dest: 'vendor/assets/stylesheets/app.css'
}
diff --git a/app/assets/images/.keep b/app/assets/images/.keep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/app/assets/images/archive.png b/app/assets/images/archive.png
deleted file mode 100644
index d6e8a2049..000000000
Binary files a/app/assets/images/archive.png and /dev/null differ
diff --git a/app/assets/images/encryption.png b/app/assets/images/encryption.png
deleted file mode 100644
index 7f80b67dd..000000000
Binary files a/app/assets/images/encryption.png and /dev/null differ
diff --git a/app/assets/images/filter.png b/app/assets/images/filter.png
deleted file mode 100644
index b707c70b5..000000000
Binary files a/app/assets/images/filter.png and /dev/null differ
diff --git a/app/assets/images/logo.png b/app/assets/images/logo.png
deleted file mode 100644
index 9b0c179d2..000000000
Binary files a/app/assets/images/logo.png and /dev/null differ
diff --git a/app/assets/javascripts/app/app.frontend.js b/app/assets/javascripts/app/app.js
similarity index 69%
rename from app/assets/javascripts/app/app.frontend.js
rename to app/assets/javascripts/app/app.js
index 80a607ee3..af4ac2d2e 100644
--- a/app/assets/javascripts/app/app.frontend.js
+++ b/app/assets/javascripts/app/app.js
@@ -13,7 +13,7 @@ if(!IEOrEdge && (window.crypto && window.crypto.subtle)) {
Neeto.crypto = new SNCryptoJS();
}
-angular.module('app.frontend', [])
+angular.module('app', [])
function getParameterByName(name, url) {
name = name.replace(/[\[\]]/g, "\\$&");
@@ -36,3 +36,17 @@ function parametersFromURL(url) {
function isDesktopApplication() {
return window && window.process && window.process.type && window.process.versions["electron"];
}
+
+function isMacApplication() {
+ return window && window.process && window.process.type && window.process.platform == "darwin";
+}
+
+/* Use with numbers and strings, not objects */
+Array.prototype.containsPrimitiveSubset = function(array) {
+ return !array.some(val => this.indexOf(val) === -1);
+}
+
+/* Use with numbers and strings, not objects */
+Array.prototype.containsObjectSubset = function(array) {
+ return !array.some(val => !_.find(this, val));
+}
diff --git a/app/assets/javascripts/app/frontend/controllers/editor.js b/app/assets/javascripts/app/controllers/editor.js
similarity index 58%
rename from app/assets/javascripts/app/frontend/controllers/editor.js
rename to app/assets/javascripts/app/controllers/editor.js
index b976d90fb..42f403470 100644
--- a/app/assets/javascripts/app/frontend/controllers/editor.js
+++ b/app/assets/javascripts/app/controllers/editor.js
@@ -1,4 +1,4 @@
-angular.module('app.frontend')
+angular.module('app')
.directive("editorSection", function($timeout, $sce){
return {
restrict: 'E',
@@ -8,7 +8,7 @@ angular.module('app.frontend')
note: "=",
updateTags: "&"
},
- templateUrl: 'frontend/editor.html',
+ templateUrl: 'editor.html',
replace: true,
controller: 'EditorCtrl',
controllerAs: 'ctrl',
@@ -23,10 +23,10 @@ angular.module('app.frontend')
}
}
})
- .controller('EditorCtrl', function ($sce, $timeout, authManager, $rootScope, extensionManager, syncManager, modelManager, themeManager, componentManager, storageManager) {
+ .controller('EditorCtrl', function ($sce, $timeout, authManager, $rootScope, actionsManager, syncManager, modelManager, themeManager, componentManager, storageManager) {
+ this.spellcheck = true;
this.componentManager = componentManager;
- this.componentStack = [];
$rootScope.$on("sync:taking-too-long", function(){
this.syncTakingTooLong = true;
@@ -50,31 +50,30 @@ angular.module('app.frontend')
this.showMenu = false;
this.loadTagsString();
+ let onReady = () => {
+ this.noteReady = true;
+ $timeout(() => {
+ this.loadPreferences();
+ })
+ }
+
let associatedEditor = this.editorForNote(note);
- if(associatedEditor) {
+ if(associatedEditor && associatedEditor != this.selectedEditor) {
// setting note to not ready will remove the editor from view in a flash,
// so we only want to do this if switching between external editors
this.noteReady = false;
- } else {
- this.noteReady = true;
- }
-
- if(this.editorComponent && this.editorComponent != associatedEditor) {
- // Deactivate old editor
- componentManager.deactivateComponent(this.editorComponent);
- this.editorComponent = null;
- }
-
- // Activate new editor if it's different from the one currently activated
- if(associatedEditor && associatedEditor != this.editorComponent) {
- // switch after timeout, so that note data isnt posted to current editor
+ // switch after timeout, so that note data isnt posted to current editor
$timeout(() => {
- this.enableComponent(associatedEditor);
- this.editorComponent = associatedEditor;
- this.noteReady = true;
+ this.selectedEditor = associatedEditor;
+ onReady();
})
+ } else if(associatedEditor) {
+ // Same editor as currently active
+ onReady();
} else {
- this.noteReady = true;
+ // No editor
+ this.selectedEditor = null;
+ onReady();
}
if(note.safeText().length == 0 && note.dummy) {
@@ -93,7 +92,7 @@ angular.module('app.frontend')
this.editorForNote = function(note) {
let editors = componentManager.componentsForArea("editor-editor");
for(var editor of editors) {
- if(editor.isActiveForItem(note)) {
+ if(editor.isExplicitlyEnabledForItem(note)) {
return editor;
}
}
@@ -104,33 +103,56 @@ angular.module('app.frontend')
}
}
- this.selectedEditor = function(editorComponent) {
+ this.onEditorMenuClick = function() {
+ // App bar menu item click
+ this.showEditorMenu = !this.showEditorMenu;
+ this.showMenu = false;
+ this.showExtensions = false;
+ }
+
+ this.closeAllMenus = function() {
this.showEditorMenu = false;
+ this.showMenu = false;
+ this.showExtensions = false;
+ }
- if(this.editorComponent && this.editorComponent !== editorComponent) {
- // This disassociates the editor from the note, but the component itself still needs to be deactivated
- this.disableComponentForCurrentItem(this.editorComponent);
- // Now deactivate the component
- componentManager.deactivateComponent(this.editorComponent);
+ this.editorMenuOnSelect = function(component) {
+ if(!component || component.area == "editor-editor") {
+ // if plain editor or other editor
+ this.showEditorMenu = false;
+ var editor = component;
+ if(this.selectedEditor && editor !== this.selectedEditor) {
+ this.disassociateComponentWithCurrentNote(this.selectedEditor);
+ }
+ if(editor) {
+ if(this.note.getAppDataItem("prefersPlainEditor") == true) {
+ this.note.setAppDataItem("prefersPlainEditor", false);
+ this.note.setDirty(true);
+ }
+ this.associateComponentWithCurrentNote(editor);
+ } else {
+ // Note prefers plain editor
+ if(!this.note.getAppDataItem("prefersPlainEditor")) {
+ this.note.setAppDataItem("prefersPlainEditor", true);
+ this.note.setDirty(true);
+ }
+ $timeout(() => {
+ this.reloadFont();
+ })
+ }
+
+ this.selectedEditor = editor;
+ } else if(component.area == "editor-stack") {
+ // If component stack item
+ this.toggleStackComponentForCurrentItem(component);
}
- if(editorComponent) {
- this.note.setAppDataItem("prefersPlainEditor", false);
- this.note.setDirty(true);
- this.enableComponent(editorComponent);
- this.associateComponentWithCurrentItem(editorComponent);
- } else {
- // Note prefers plain editor
- this.note.setAppDataItem("prefersPlainEditor", true);
- this.note.setDirty(true);
- syncManager.sync();
- }
-
- this.editorComponent = editorComponent;
+ // Lots of dirtying can happen above, so we'll sync
+ syncManager.sync("editorMenuOnSelect");
}.bind(this)
this.hasAvailableExtensions = function() {
- return extensionManager.extensionsInContextOfItem(this.note).length > 0;
+ return actionsManager.extensionsInContextOfItem(this.note).length > 0;
}
this.focusEditor = function(delay) {
@@ -183,16 +205,25 @@ angular.module('app.frontend')
}
var saveTimeout;
- this.changesMade = function() {
- this.note.hasChanges = true;
+ this.changesMade = function(bypassDebouncer = false) {
this.note.dummy = false;
+ /* In the case of keystrokes, saving should go through a debouncer to avoid frequent calls.
+ In the case of deleting or archiving a note, it should happen immediately before the note is switched out
+ */
+ let delay = bypassDebouncer ? 0 : 275;
+
+ // In the case of archiving a note, the note is saved immediately, then switched to another note.
+ // Usually note.hasChanges is set back to false after the saving delay, but in this case, because there is no delay,
+ // we set it to false immediately so that it is not saved twice: once now, and the other on setNote in oldNote.hasChanges.
+ this.note.hasChanges = bypassDebouncer ? false : true;
+
if(saveTimeout) $timeout.cancel(saveTimeout);
if(statusTimeout) $timeout.cancel(statusTimeout);
saveTimeout = $timeout(function(){
this.showSavingStatus();
this.saveNote();
- }.bind(this), 275)
+ }.bind(this), delay)
}
this.showSavingStatus = function() {
@@ -229,18 +260,13 @@ angular.module('app.frontend')
this.onNameBlur = function() {
this.editingName = false;
- this.updateTagsFromTagsString()
}
- this.toggleFullScreen = function() {
- this.fullscreen = !this.fullscreen;
- if(this.fullscreen) {
- this.focusEditor(0);
+ this.selectedMenuItem = function($event, hide) {
+ if(hide) {
+ this.showMenu = false;
}
- }
-
- this.selectedMenuItem = function($event) {
- this.showMenu = false;
+ $event.stopPropagation();
}
this.deleteNote = function() {
@@ -260,7 +286,7 @@ angular.module('app.frontend')
this.toggleArchiveNote = function() {
this.note.setAppDataItem("archived", !this.note.archived);
this.note.setDirty(true);
- this.changesMade();
+ this.changesMade(true);
$rootScope.$broadcast("noteArchived");
}
@@ -280,11 +306,7 @@ angular.module('app.frontend')
*/
this.loadTagsString = function() {
- var string = "";
- for(var tag of this.note.tags) {
- string += "#" + tag.title + " ";
- }
- this.tagsString = string;
+ this.tagsString = this.note.tagsString();
}
this.addTag = function(tag) {
@@ -309,20 +331,100 @@ angular.module('app.frontend')
}
this.updateTagsFromTagsString = function() {
- var tags = this.tagsString.split("#");
- tags = _.filter(tags, function(tag){
- return tag.length > 0;
- })
- tags = _.map(tags, function(tag){
- return tag.trim();
+ if(this.tagsString == this.note.tagsString()) {
+ return;
+ }
+
+ var strings = this.tagsString.split("#").filter((string) => {
+ return string.length > 0;
+ }).map((string) => {
+ return string.trim();
})
this.note.dummy = false;
- this.updateTags()(this.note, tags);
+ this.updateTags()(this.note, strings);
}
+ /* Resizability */
+ this.resizeControl = {};
+
+ this.onPanelResizeFinish = function(width, left, isMaxWidth) {
+ if(isMaxWidth) {
+ authManager.setUserPrefValue("editorWidth", null);
+ } else {
+ if(width !== undefined && width !== null) {
+ authManager.setUserPrefValue("editorWidth", width);
+ }
+ }
+
+ if(left !== undefined && left !== null) {
+ authManager.setUserPrefValue("editorLeft", left);
+ }
+ authManager.syncUserPreferences();
+ }
+
+ $rootScope.$on("user-preferences-changed", () => {
+ this.loadPreferences();
+ });
+
+ this.loadPreferences = function() {
+ this.monospaceFont = authManager.getUserPrefValue("monospaceFont", "monospace");
+ this.spellcheck = authManager.getUserPrefValue("spellcheck", true);
+
+ if(!document.getElementById("editor-content")) {
+ // Elements have not yet loaded due to ng-if around wrapper
+ return;
+ }
+
+ this.reloadFont();
+
+ let width = authManager.getUserPrefValue("editorWidth", null);
+ if(width !== null) {
+ this.resizeControl.setWidth(width);
+ }
+
+ let left = authManager.getUserPrefValue("editorLeft", null);
+ if(left !== null) {
+ this.resizeControl.setLeft(left);
+ }
+ }
+
+ this.reloadFont = function() {
+ var editable = document.getElementById("note-text-editor");
+
+ if(!editable) {
+ return;
+ }
+
+ if(this.monospaceFont) {
+ if(isMacApplication()) {
+ editable.style.fontFamily = "Menlo, Consolas, 'DejaVu Sans Mono', monospace";
+ } else {
+ editable.style.fontFamily = "monospace";
+ }
+ } else {
+ editable.style.fontFamily = "inherit";
+ }
+ }
+
+ this.toggleKey = function(key) {
+ this[key] = !this[key];
+ authManager.setUserPrefValue(key, this[key], true);
+ this.reloadFont();
+
+ if(key == "spellcheck") {
+ // Allows textarea to reload
+ this.noteReady = false;
+ $timeout(() => {
+ this.noteReady = true;
+ $timeout(() => {
+ this.reloadFont();
+ })
+ }, 0)
+ }
+ }
@@ -330,43 +432,27 @@ angular.module('app.frontend')
Components
*/
- componentManager.registerHandler({identifier: "editor", areas: ["note-tags", "editor-stack", "editor-editor"], activationHandler: function(component){
-
+ componentManager.registerHandler({identifier: "editor", areas: ["note-tags", "editor-stack", "editor-editor"], activationHandler: (component) => {
if(component.area === "note-tags") {
// Autocomplete Tags
this.tagsComponent = component.active ? component : null;
- } else if(component.area == "editor-stack") {
- // Stack
- if(component.active) {
- if(!_.find(this.componentStack, component)) {
- this.componentStack.push(component);
- }
- } else {
- _.pull(this.componentStack, component);
- }
- } else {
+ } else if(component.area == "editor-editor") {
// Editor
- if(component.active && this.note && component.isActiveForItem(this.note)) {
- this.editorComponent = component;
+ if(component.active && this.note && (component.isExplicitlyEnabledForItem(this.note) || component.isDefaultEditor())) {
+ this.selectedEditor = component;
} else {
- this.editorComponent = null;
+ this.selectedEditor = null;
}
+ } else if(component.area == "editor-stack") {
+ this.reloadComponentContext();
}
-
- if(component.active) {
- $timeout(function(){
- var iframe = componentManager.iframeForComponent(component);
- if(iframe) {
- iframe.onload = function() {
- componentManager.registerComponentWindow(component, iframe.contentWindow);
- }.bind(this);
- }
- }.bind(this));
- }
-
- }.bind(this), contextRequestHandler: function(component){
+ }, contextRequestHandler: (component) => {
return this.note;
- }.bind(this), actionHandler: function(component, action, data){
+ }, focusHandler: (component, focused) => {
+ if(component.isEditor() && focused) {
+ this.closeAllMenus();
+ }
+ }, actionHandler: (component, action, data) => {
if(action === "set-size") {
var setSize = function(element, size) {
var widthString = typeof size.width === 'string' ? size.width : `${data.width}px`;
@@ -374,21 +460,10 @@ angular.module('app.frontend')
element.setAttribute("style", `width:${widthString}; height:${heightString}; `);
}
- if(data.type === "content") {
- var iframe = componentManager.iframeForComponent(component);
- var width = data.width;
- var height = data.height;
- iframe.width = width;
- iframe.height = height;
-
- setSize(iframe, data);
- } else {
+ if(data.type == "container") {
if(component.area == "note-tags") {
var container = document.getElementById("note-tags-component-container");
setSize(container, data);
- } else {
- var container = document.getElementById("component-" + component.uuid);
- setSize(container, data);
}
}
}
@@ -423,11 +498,15 @@ angular.module('app.frontend')
}
}
}
- }.bind(this)});
+ }});
this.reloadComponentContext = function() {
+ // componentStack is used by the template to ng-repeat
+ this.componentStack = componentManager.componentsForArea("editor-stack");
for(var component of this.componentStack) {
- componentManager.setEventFlowForComponent(component, component.isActiveForItem(this.note));
+ if(component.active) {
+ component.hidden = !this.note || component.isExplicitlyDisabledForItem(this.note);
+ }
}
componentManager.contextItemDidChangeInArea("note-tags");
@@ -435,51 +514,41 @@ angular.module('app.frontend')
componentManager.contextItemDidChangeInArea("editor-editor");
}
- this.enableComponent = function(component) {
- componentManager.activateComponent(component);
- componentManager.setEventFlowForComponent(component, 1);
- }
-
- this.associateComponentWithCurrentItem = function(component) {
- componentManager.associateComponentWithItem(component, this.note);
- }
-
- let alertKey = "displayed-component-disable-alert";
- this.disableComponentForCurrentItem = function(component, showAlert) {
- componentManager.disassociateComponentWithItem(component, this.note);
- componentManager.setEventFlowForComponent(component, 0);
- if(showAlert && !storageManager.getItem(alertKey)) {
- alert("This component will be disabled for this note. You can re-enable this component in the 'Menu' of the editor pane.");
- storageManager.setItem(alertKey, true);
- }
- }
-
- this.hasDisabledStackComponents = function() {
- for(var component of this.componentStack) {
- if(component.ignoreEvents) {
- return true;
+ this.toggleStackComponentForCurrentItem = function(component) {
+ if(component.hidden) {
+ // Unhide, associate with current item
+ component.hidden = false;
+ if(!component.active) {
+ componentManager.activateComponent(component);
}
- }
-
- return false;
- }
-
- this.restoreDisabledStackComponents = function() {
- var relevantComponents = this.componentStack.filter(function(component){
- return component.ignoreEvents;
- })
-
- componentManager.enableComponentsForItem(relevantComponents, this.note);
-
- for(var component of relevantComponents) {
- componentManager.setEventFlowForComponent(component, true);
+ this.associateComponentWithCurrentNote(component);
componentManager.contextItemDidChangeInArea("editor-stack");
+ } else {
+ // not hidden, hide
+ component.hidden = true;
+ this.disassociateComponentWithCurrentNote(component);
}
}
+ this.disassociateComponentWithCurrentNote = function(component) {
+ component.associatedItemIds = component.associatedItemIds.filter((id) => {return id !== this.note.uuid});
+ if(!component.disassociatedItemIds.includes(this.note.uuid)) {
+ component.disassociatedItemIds.push(this.note.uuid);
+ }
+ component.setDirty(true);
+ }
+ this.associateComponentWithCurrentNote = function(component) {
+ component.disassociatedItemIds = component.disassociatedItemIds.filter((id) => {return id !== this.note.uuid});
+
+ if(!component.associatedItemIds.includes(this.note.uuid)) {
+ component.associatedItemIds.push(this.note.uuid);
+ }
+
+ component.setDirty(true);
+ }
diff --git a/app/assets/javascripts/app/frontend/controllers/footer.js b/app/assets/javascripts/app/controllers/footer.js
similarity index 50%
rename from app/assets/javascripts/app/frontend/controllers/footer.js
rename to app/assets/javascripts/app/controllers/footer.js
index e59321187..4da3b6ba1 100644
--- a/app/assets/javascripts/app/frontend/controllers/footer.js
+++ b/app/assets/javascripts/app/controllers/footer.js
@@ -1,9 +1,9 @@
-angular.module('app.frontend')
+angular.module('app')
.directive("footer", function(authManager){
return {
restrict: 'E',
scope: {},
- templateUrl: 'frontend/footer.html',
+ templateUrl: 'footer.html',
replace: true,
controller: 'FooterCtrl',
controllerAs: 'ctrl',
@@ -22,9 +22,12 @@ angular.module('app.frontend')
}
}
})
- .controller('FooterCtrl', function ($rootScope, authManager, modelManager, $timeout, dbManager, syncManager, storageManager, passcodeManager) {
+ .controller('FooterCtrl', function ($rootScope, authManager, modelManager, $timeout, dbManager,
+ syncManager, storageManager, passcodeManager, componentManager, singletonManager) {
- this.user = authManager.user;
+ this.getUser = function() {
+ return authManager.user;
+ }
this.updateOfflineStatus = function() {
this.offline = authManager.offline();
@@ -45,23 +48,11 @@ angular.module('app.frontend')
}.bind(this)
this.accountMenuPressed = function() {
- this.serverData = {};
this.showAccountMenu = !this.showAccountMenu;
- this.showFaq = false;
- this.showNewPasswordForm = false;
- this.showExtensionsMenu = false;
- this.showIOMenu = false;
+ this.closeAllRooms();
}
- this.toggleExtensions = function() {
- this.showAccountMenu = false;
- this.showIOMenu = false;
- this.showExtensionsMenu = !this.showExtensionsMenu;
- }
-
- this.toggleIO = function() {
- this.showIOMenu = !this.showIOMenu;
- this.showExtensionsMenu = false;
+ this.closeAccountMenu = () => {
this.showAccountMenu = false;
}
@@ -75,7 +66,7 @@ angular.module('app.frontend')
this.refreshData = function() {
this.isRefreshing = true;
- syncManager.sync(function(response){
+ syncManager.sync((response) => {
$timeout(function(){
this.isRefreshing = false;
}.bind(this), 200)
@@ -84,7 +75,7 @@ angular.module('app.frontend')
} else {
this.syncUpdated();
}
- }.bind(this));
+ }, null, "refreshData");
}
this.syncUpdated = function() {
@@ -104,6 +95,60 @@ angular.module('app.frontend')
this.clickedNewUpdateAnnouncement = function() {
this.newUpdateAvailable = false;
- alert("A new update is ready to install. Updates address performance and security issues, as well as bug fixes and feature enhancements. Simply quit Standard Notes and re-open it for the update to be applied.")
+ alert("A new update is ready to install. Simply quit Standard Notes and reopen it after a brief delay to apply the update.")
+ }
+
+
+ /* Rooms */
+
+ this.componentManager = componentManager;
+ this.rooms = [];
+
+ modelManager.addItemSyncObserver("room-bar", "SN|Component", (allItems, validItems, deletedItems, source) => {
+ var incomingRooms = allItems.filter((candidate) => {return candidate.area == "rooms"});
+ this.rooms = _.uniq(this.rooms.concat(incomingRooms)).filter((candidate) => {return !candidate.deleted});
+ });
+
+ componentManager.registerHandler({identifier: "roomBar", areas: ["rooms", "modal"], activationHandler: (component) => {
+ if(component.active) {
+ // Show room, if it was not activated manually (in the event of event from componentManager)
+ if(component.area == "rooms" && !component.showRoom) {
+ component.showRoom = true;
+ }
+ $timeout(() => {
+ var lastSize = component.getLastSize();
+ if(lastSize) {
+ componentManager.handleSetSizeEvent(component, lastSize);
+ }
+ });
+ }
+ }, actionHandler: (component, action, data) => {
+ if(action == "set-size") {
+ component.setLastSize(data);
+ }
+ }, focusHandler: (component, focused) => {
+ if(component.isEditor() && focused) {
+ this.closeAllRooms();
+ this.closeAccountMenu();
+ }
+ }});
+
+ $rootScope.$on("editorFocused", () => {
+ this.closeAllRooms();
+ this.closeAccountMenu();
+ })
+
+ this.onRoomDismiss = function(room) {
+ room.showRoom = false;
+ }
+
+ this.closeAllRooms = function() {
+ for(var room of this.rooms) {
+ room.showRoom = false;
+ }
+ }
+
+ this.selectRoom = function(room) {
+ room.showRoom = !room.showRoom;
}
});
diff --git a/app/assets/javascripts/app/frontend/controllers/home.js b/app/assets/javascripts/app/controllers/home.js
similarity index 91%
rename from app/assets/javascripts/app/frontend/controllers/home.js
rename to app/assets/javascripts/app/controllers/home.js
index 830479df3..d52c3c59d 100644
--- a/app/assets/javascripts/app/frontend/controllers/home.js
+++ b/app/assets/javascripts/app/controllers/home.js
@@ -1,4 +1,4 @@
-angular.module('app.frontend')
+angular.module('app')
.controller('HomeCtrl', function ($scope, $location, $rootScope, $timeout, modelManager,
dbManager, syncManager, authManager, themeManager, passcodeManager, storageManager, migrationManager) {
@@ -8,6 +8,11 @@ angular.module('app.frontend')
$rootScope.$broadcast('new-update-available', version);
}
+ /* Used to avoid circular dependencies where syncManager cannot be imported but rootScope can */
+ $rootScope.sync = function(source) {
+ syncManager.sync("$rootScope.sync - " + source);
+ }
+
$rootScope.lockApplication = function() {
// Reloading wipes current objects from memory
window.location.reload();
@@ -44,7 +49,7 @@ angular.module('app.frontend')
dbManager.openDatabase(null, function() {
// new database, delete syncToken so that items can be refetched entirely from server
syncManager.clearSyncToken();
- syncManager.sync();
+ syncManager.sync("openDatabase");
})
}
@@ -52,15 +57,14 @@ angular.module('app.frontend')
authManager.loadInitialData();
syncManager.loadLocalItems(function(items) {
$scope.allTag.didLoad = true;
- themeManager.activateInitialTheme();
$scope.$apply();
$rootScope.$broadcast("initial-data-loaded");
- syncManager.sync(null);
+ syncManager.sync("initiateSync");
// refresh every 30s
setInterval(function () {
- syncManager.sync(null);
+ syncManager.sync("timer");
}, 30000);
});
}
@@ -111,7 +115,7 @@ angular.module('app.frontend')
}
note.setDirty(true);
- syncManager.sync();
+ syncManager.sync("updateTagsForNote");
}
/*
@@ -141,7 +145,7 @@ angular.module('app.frontend')
return;
}
tag.setDirty(true);
- syncManager.sync(callback);
+ syncManager.sync(callback, null, "tagsSave");
$rootScope.$broadcast("tag-changed");
modelManager.resortTag(tag);
}
@@ -157,7 +161,7 @@ angular.module('app.frontend')
syncManager.sync(function(){
// force scope tags to update on sub directives
$scope.safeApply();
- });
+ }, null, "removeTag");
}
}
@@ -195,7 +199,7 @@ angular.module('app.frontend')
callback(true);
}
}
- })
+ }, null, "saveNote")
}
$scope.safeApply = function(fn) {
@@ -236,7 +240,7 @@ angular.module('app.frontend')
} else {
$scope.notifyDelete();
}
- });
+ }, null, "deleteNote");
}
@@ -259,12 +263,13 @@ angular.module('app.frontend')
return;
} else {
// sign out
+ authManager.signOut();
syncManager.destroyLocalData(function(){
window.location.reload();
})
}
} else {
- authManager.login(server, email, pw, false, function(response){
+ authManager.login(server, email, pw, false, {}, function(response){
window.location.reload();
})
}
diff --git a/app/assets/javascripts/app/frontend/controllers/lockScreen.js b/app/assets/javascripts/app/controllers/lockScreen.js
similarity index 78%
rename from app/assets/javascripts/app/frontend/controllers/lockScreen.js
rename to app/assets/javascripts/app/controllers/lockScreen.js
index 409344fb6..b04c77c21 100644
--- a/app/assets/javascripts/app/frontend/controllers/lockScreen.js
+++ b/app/assets/javascripts/app/controllers/lockScreen.js
@@ -2,7 +2,7 @@ class LockScreen {
constructor() {
this.restrict = "E";
- this.templateUrl = "frontend/lock-screen.html";
+ this.templateUrl = "lock-screen.html";
this.scope = {
onSuccess: "&",
};
@@ -27,4 +27,4 @@ class LockScreen {
}
-angular.module('app.frontend').directive('lockScreen', () => new LockScreen);
+angular.module('app').directive('lockScreen', () => new LockScreen);
diff --git a/app/assets/javascripts/app/frontend/controllers/notes.js b/app/assets/javascripts/app/controllers/notes.js
similarity index 56%
rename from app/assets/javascripts/app/frontend/controllers/notes.js
rename to app/assets/javascripts/app/controllers/notes.js
index 2f35f5d98..b04444c04 100644
--- a/app/assets/javascripts/app/frontend/controllers/notes.js
+++ b/app/assets/javascripts/app/controllers/notes.js
@@ -1,4 +1,4 @@
-angular.module('app.frontend')
+angular.module('app')
.directive("notesSection", function(){
return {
scope: {
@@ -7,7 +7,7 @@ angular.module('app.frontend')
tag: "="
},
- templateUrl: 'frontend/notes.html',
+ templateUrl: 'notes.html',
replace: true,
controller: 'NotesCtrl',
controllerAs: 'ctrl',
@@ -33,49 +33,109 @@ angular.module('app.frontend')
})
.controller('NotesCtrl', function (authManager, $timeout, $rootScope, modelManager, storageManager) {
- this.sortBy = storageManager.getItem("sortBy") || "created_at";
- this.showArchived = storageManager.getBooleanValue("showArchived") || false;
- this.sortDescending = this.sortBy != "title";
+ this.panelController = {};
+
+ $rootScope.$on("user-preferences-changed", () => {
+ this.loadPreferences();
+ });
+
+ this.loadPreferences = function() {
+ let prevSortValue = this.sortBy;
+ this.sortBy = authManager.getUserPrefValue("sortBy", "created_at");
+ if(prevSortValue && prevSortValue != this.sortBy) {
+ $timeout(() => {
+ this.selectFirstNote();
+ })
+ }
+ this.sortDescending = this.sortBy != "title";
+
+ this.showArchived = authManager.getUserPrefValue("showArchived", false);
+ this.hidePinned = authManager.getUserPrefValue("hidePinned", false);
+ this.hideNotePreview = authManager.getUserPrefValue("hideNotePreview", false);
+ this.hideDate = authManager.getUserPrefValue("hideDate", false);
+ this.hideTags = authManager.getUserPrefValue("hideTags", false);
+
+ let width = authManager.getUserPrefValue("notesPanelWidth");
+ if(width) {
+ this.panelController.setWidth(width);
+ }
+ }
+
+ this.loadPreferences();
+
+ this.onPanelResize = function(newWidth) {
+ authManager.setUserPrefValue("notesPanelWidth", newWidth);
+ authManager.syncUserPreferences();
+ }
+
+ angular.element(document).ready(() => {
+ this.loadPreferences();
+ });
$rootScope.$on("editorFocused", function(){
this.showMenu = false;
}.bind(this))
$rootScope.$on("noteDeleted", function() {
- this.selectFirstNote(false);
+ $timeout(this.onNoteRemoval.bind(this));
}.bind(this))
$rootScope.$on("noteArchived", function() {
- this.selectFirstNote(false);
- }.bind(this))
+ $timeout(this.onNoteRemoval.bind(this));
+ }.bind(this));
- this.DefaultNotesToDisplayValue = 20;
+
+ // When a note is removed from the list
+ this.onNoteRemoval = function() {
+ let visibleNotes = this.visibleNotes();
+ if(this.selectedIndex < visibleNotes.length) {
+ this.selectNote(visibleNotes[this.selectedIndex]);
+ } else {
+ this.selectNote(visibleNotes[visibleNotes.length - 1]);
+ }
+ }
+
+ let MinNoteHeight = 51.0; // This is the height of a note cell with nothing but the title, which *is* a display option
+ this.DefaultNotesToDisplayValue = (document.documentElement.clientHeight / MinNoteHeight) || 20;
this.notesToDisplay = this.DefaultNotesToDisplayValue;
this.paginate = function() {
this.notesToDisplay += this.DefaultNotesToDisplayValue
}
+ this.panelTitle = function() {
+ if(this.noteFilter.text.length) {
+ return `${this.tag.notes.filter((i) => {return i.visible;}).length} search results`;
+ } else if(this.tag) {
+ return `${this.tag.title} notes`;
+ }
+ }
+
this.optionsSubtitle = function() {
- var base = "Sorting by";
+ var base = "";
if(this.sortBy == "created_at") {
- base += " date added";
+ base += " Date Added";
} else if(this.sortBy == "updated_at") {
- base += " date modifed";
+ base += " Date Modifed";
} else if(this.sortBy == "title") {
- base += " title";
+ base += " Title";
}
if(this.showArchived && (!this.tag || !this.tag.archiveTag)) {
- base += " | Including archived"
+ base += " | + Archived"
+ }
+
+ if(this.hidePinned) {
+ base += " | – Pinned"
}
return base;
}
- this.toggleShowArchived = function() {
- this.showArchived = !this.showArchived;
- storageManager.setBooleanValue("showArchived", this.showArchived);
+ this.toggleKey = function(key) {
+ this[key] = !this[key];
+ authManager.setUserPrefValue(key, this[key]);
+ authManager.syncUserPreferences();
}
this.tagDidChange = function(tag, oldTag) {
@@ -108,10 +168,14 @@ angular.module('app.frontend')
this.selectFirstNote(createNew);
}
- this.selectFirstNote = function(createNew) {
- var visibleNotes = this.sortedNotes.filter(function(note){
+ this.visibleNotes = function() {
+ return this.sortedNotes.filter(function(note){
return note.visible;
});
+ }
+
+ this.selectFirstNote = function(createNew) {
+ var visibleNotes = this.visibleNotes();
if(visibleNotes.length > 0) {
this.selectNote(visibleNotes[0]);
@@ -121,9 +185,11 @@ angular.module('app.frontend')
}
this.selectNote = function(note) {
+ if(!note) { return; }
this.selectedNote = note;
note.conflict_of = null; // clear conflict
this.selectionMade()(note);
+ this.selectedIndex = this.visibleNotes().indexOf(note);
}
this.createNewNote = function() {
@@ -137,12 +203,7 @@ angular.module('app.frontend')
this.noteFilter = {text : ''};
this.filterNotes = function(note) {
- if(this.tag.archiveTag) {
- note.visible = note.archived;
- return note.visible;
- }
-
- if(note.archived && !this.showArchived) {
+ if((note.archived && !this.showArchived && !this.tag.archiveTag) || (note.pinned && this.hidePinned)) {
note.visible = false;
return note.visible;
}
@@ -156,6 +217,11 @@ angular.module('app.frontend')
var matchesBody = words.every(function(word) { return note.safeText().toLowerCase().indexOf(word) >= 0; });
note.visible = matchesTitle || matchesBody;
}
+
+ if(this.tag.archiveTag) {
+ note.visible = note.visible && note.archived;
+ }
+
return note.visible;
}.bind(this)
@@ -188,7 +254,21 @@ angular.module('app.frontend')
this.setSortBy = function(type) {
this.sortBy = type;
- storageManager.setItem("sortBy", type);
+ authManager.setUserPrefValue("sortBy", this.sortBy);
+ authManager.syncUserPreferences();
+ }
+
+ this.shouldShowTags = function(note) {
+ if(this.hideTags) {
+ return false;
+ }
+
+ if(this.tag.all) {
+ return true;
+ }
+
+ // Inside a tag, only show tags string if note contains tags other than this.tag
+ return note.tags && note.tags.length > 1;
}
});
diff --git a/app/assets/javascripts/app/frontend/controllers/tags.js b/app/assets/javascripts/app/controllers/tags.js
similarity index 84%
rename from app/assets/javascripts/app/frontend/controllers/tags.js
rename to app/assets/javascripts/app/controllers/tags.js
index abad7e59f..575011f58 100644
--- a/app/assets/javascripts/app/frontend/controllers/tags.js
+++ b/app/assets/javascripts/app/controllers/tags.js
@@ -1,4 +1,4 @@
-angular.module('app.frontend')
+angular.module('app')
.directive("tagsSection", function(){
return {
restrict: 'E',
@@ -13,7 +13,7 @@ angular.module('app.frontend')
updateNoteTag: "&",
removeTag: "&"
},
- templateUrl: 'frontend/tags.html',
+ templateUrl: 'tags.html',
replace: true,
controller: 'TagsCtrl',
controllerAs: 'ctrl',
@@ -34,26 +34,37 @@ angular.module('app.frontend')
}
}
})
- .controller('TagsCtrl', function ($rootScope, modelManager, $timeout, componentManager) {
+ .controller('TagsCtrl', function ($rootScope, modelManager, $timeout, componentManager, authManager) {
var initialLoad = true;
+ this.panelController = {};
+
+ $rootScope.$on("user-preferences-changed", () => {
+ this.loadPreferences();
+ });
+
+ this.loadPreferences = function() {
+ let width = authManager.getUserPrefValue("tagsPanelWidth");
+ if(width) {
+ this.panelController.setWidth(width);
+ }
+ }
+
+ this.loadPreferences();
+
+ this.onPanelResize = function(newWidth) {
+ authManager.setUserPrefValue("tagsPanelWidth", newWidth);
+ authManager.syncUserPreferences();
+ }
+
+ this.componentManager = componentManager;
+
componentManager.registerHandler({identifier: "tags", areas: ["tags-list"], activationHandler: function(component){
this.component = component;
-
- if(component.active) {
- $timeout(function(){
- var iframe = document.getElementById("tags-list-iframe");
- iframe.onload = function() {
- componentManager.registerComponentWindow(this.component, iframe.contentWindow);
- }.bind(this);
- }.bind(this));
- }
-
}.bind(this), contextRequestHandler: function(component){
return null;
}.bind(this), actionHandler: function(component, action, data){
-
if(action === "select-item") {
var tag = modelManager.findItem(data.item.uuid);
if(tag) {
@@ -64,7 +75,6 @@ angular.module('app.frontend')
else if(action === "clear-selection") {
this.selectTag(this.allTag);
}
-
}.bind(this)});
this.setAllTag = function(allTag) {
diff --git a/app/assets/javascripts/app/services/directives/functional/autofocus.js b/app/assets/javascripts/app/directives/functional/autofocus.js
similarity index 75%
rename from app/assets/javascripts/app/services/directives/functional/autofocus.js
rename to app/assets/javascripts/app/directives/functional/autofocus.js
index 49c733ecc..8bcf6c1d1 100644
--- a/app/assets/javascripts/app/services/directives/functional/autofocus.js
+++ b/app/assets/javascripts/app/directives/functional/autofocus.js
@@ -1,6 +1,6 @@
angular
- .module('app.frontend')
- .directive('mbAutofocus', ['$timeout', function($timeout) {
+ .module('app')
+ .directive('snAutofocus', ['$timeout', function($timeout) {
return {
restrict: 'A',
scope: {
diff --git a/app/assets/javascripts/app/services/directives/functional/click-outside.js b/app/assets/javascripts/app/directives/functional/click-outside.js
similarity index 95%
rename from app/assets/javascripts/app/services/directives/functional/click-outside.js
rename to app/assets/javascripts/app/directives/functional/click-outside.js
index 10e40e1da..dd8296470 100644
--- a/app/assets/javascripts/app/services/directives/functional/click-outside.js
+++ b/app/assets/javascripts/app/directives/functional/click-outside.js
@@ -1,5 +1,5 @@
angular
- .module('app.frontend')
+ .module('app')
.directive('clickOutside', ['$document', function($document) {
return {
restrict: 'A',
diff --git a/app/assets/javascripts/app/services/directives/functional/delay-hide.js b/app/assets/javascripts/app/directives/functional/delay-hide.js
similarity index 97%
rename from app/assets/javascripts/app/services/directives/functional/delay-hide.js
rename to app/assets/javascripts/app/directives/functional/delay-hide.js
index 6e381ed3f..fd52d70fb 100644
--- a/app/assets/javascripts/app/services/directives/functional/delay-hide.js
+++ b/app/assets/javascripts/app/directives/functional/delay-hide.js
@@ -1,5 +1,5 @@
angular
- .module('app.frontend')
+ .module('app')
.directive('delayHide', function($timeout) {
return {
restrict: 'A',
diff --git a/app/assets/javascripts/app/services/directives/functional/file-change.js b/app/assets/javascripts/app/directives/functional/file-change.js
similarity index 92%
rename from app/assets/javascripts/app/services/directives/functional/file-change.js
rename to app/assets/javascripts/app/directives/functional/file-change.js
index afec10954..c133c0852 100644
--- a/app/assets/javascripts/app/services/directives/functional/file-change.js
+++ b/app/assets/javascripts/app/directives/functional/file-change.js
@@ -1,5 +1,5 @@
angular
- .module('app.frontend')
+ .module('app')
.directive('fileChange', function() {
return {
restrict: 'A',
diff --git a/app/assets/javascripts/app/services/directives/functional/infiniteScroll.js b/app/assets/javascripts/app/directives/functional/infiniteScroll.js
similarity index 89%
rename from app/assets/javascripts/app/services/directives/functional/infiniteScroll.js
rename to app/assets/javascripts/app/directives/functional/infiniteScroll.js
index 372f0bf7b..3e1e633ef 100644
--- a/app/assets/javascripts/app/services/directives/functional/infiniteScroll.js
+++ b/app/assets/javascripts/app/directives/functional/infiniteScroll.js
@@ -1,4 +1,4 @@
-angular.module('app.frontend').directive('infiniteScroll', [
+angular.module('app').directive('infiniteScroll', [
'$rootScope', '$window', '$timeout', function($rootScope, $window, $timeout) {
return {
link: function(scope, elem, attrs) {
diff --git a/app/assets/javascripts/app/services/directives/functional/lowercase.js b/app/assets/javascripts/app/directives/functional/lowercase.js
similarity index 95%
rename from app/assets/javascripts/app/services/directives/functional/lowercase.js
rename to app/assets/javascripts/app/directives/functional/lowercase.js
index 1899a251b..40ce7421c 100644
--- a/app/assets/javascripts/app/services/directives/functional/lowercase.js
+++ b/app/assets/javascripts/app/directives/functional/lowercase.js
@@ -1,5 +1,5 @@
angular
- .module('app.frontend')
+ .module('app')
.directive('lowercase', function() {
return {
require: 'ngModel',
diff --git a/app/assets/javascripts/app/services/directives/functional/selectOnClick.js b/app/assets/javascripts/app/directives/functional/selectOnClick.js
similarity index 94%
rename from app/assets/javascripts/app/services/directives/functional/selectOnClick.js
rename to app/assets/javascripts/app/directives/functional/selectOnClick.js
index a8ad86cb1..598e45086 100644
--- a/app/assets/javascripts/app/services/directives/functional/selectOnClick.js
+++ b/app/assets/javascripts/app/directives/functional/selectOnClick.js
@@ -1,5 +1,5 @@
angular
- .module('app.frontend')
+ .module('app')
.directive('selectOnClick', ['$window', function ($window) {
return {
restrict: 'A',
diff --git a/app/assets/javascripts/app/services/directives/views/accountMenu.js b/app/assets/javascripts/app/directives/views/accountMenu.js
similarity index 88%
rename from app/assets/javascripts/app/services/directives/views/accountMenu.js
rename to app/assets/javascripts/app/directives/views/accountMenu.js
index 4c9d977ee..c561c0214 100644
--- a/app/assets/javascripts/app/services/directives/views/accountMenu.js
+++ b/app/assets/javascripts/app/directives/views/accountMenu.js
@@ -2,9 +2,10 @@ class AccountMenu {
constructor() {
this.restrict = "E";
- this.templateUrl = "frontend/directives/account-menu.html";
+ this.templateUrl = "directives/account-menu.html";
this.scope = {
- "onSuccessfulAuth" : "&"
+ "onSuccessfulAuth" : "&",
+ "closeFunction" : "&"
};
}
@@ -15,28 +16,17 @@ class AccountMenu {
$scope.user = authManager.user;
$scope.server = syncManager.serverURL;
+ $scope.close = function() {
+ $timeout(() => {
+ $scope.closeFunction()();
+ })
+ }
+
$scope.encryptedBackupsAvailable = function() {
return authManager.user || passcodeManager.hasPasscode();
}
$scope.syncStatus = syncManager.syncStatus;
-
- $scope.encryptionKey = function() {
- return authManager.keys().mk;
- }
-
- $scope.authKey = function() {
- return authManager.keys().ak;
- }
-
- $scope.serverPassword = function() {
- return syncManager.serverPassword;
- }
-
- $scope.dashboardURL = function() {
- return `${$scope.server}/dashboard/#server=${$scope.server}&id=${encodeURIComponent($scope.user.email)}&pw=${$scope.serverPassword()}`;
- }
-
$scope.newPasswordData = {};
$scope.showPasswordChangeForm = function() {
@@ -45,7 +35,13 @@ class AccountMenu {
$scope.submitPasswordChange = function() {
- if($scope.newPasswordData.newPassword != $scope.newPasswordData.newPasswordConfirmation) {
+ let newPass = $scope.newPasswordData.newPassword;
+
+ if(!newPass || newPass.length == 0) {
+ return;
+ }
+
+ if(newPass != $scope.newPasswordData.newPasswordConfirmation) {
alert("Your new password does not match its confirmation.");
$scope.newPasswordData.status = null;
return;
@@ -63,7 +59,7 @@ class AccountMenu {
// perform a sync beforehand to pull in any last minutes changes before we change the encryption key (and thus cant decrypt new changes)
syncManager.sync(function(response){
- authManager.changePassword(email, $scope.newPasswordData.newPassword, function(response){
+ authManager.changePassword(email, newPass, function(response){
if(response.error) {
alert("There was an error changing your password. Please try again.");
$scope.newPasswordData.status = null;
@@ -86,10 +82,19 @@ class AccountMenu {
}, 1000)
});
})
- })
+ }, null, "submitPasswordChange")
+ }
+
+ $scope.submitMfaForm = function() {
+ var params = {};
+ params[$scope.formData.mfa.payload.mfa_key] = $scope.formData.userMfaCode;
+ $scope.login(params);
}
$scope.submitAuthForm = function() {
+ if(!$scope.formData.email || !$scope.formData.user_password) {
+ return;
+ }
if($scope.formData.showLogin) {
$scope.login();
} else {
@@ -97,19 +102,37 @@ class AccountMenu {
}
}
- $scope.login = function() {
+ $scope.login = function(extraParams) {
$scope.formData.status = "Generating Login Keys...";
$timeout(function(){
- authManager.login($scope.formData.url, $scope.formData.email, $scope.formData.user_password, $scope.formData.ephemeral, function(response){
- if(!response || response.error) {
- $scope.formData.status = null;
- var error = response ? response.error : {message: "An unknown error occured."}
- if(!response || (response && !response.didDisplayAlert)) {
- alert(error.message);
+ authManager.login($scope.formData.url, $scope.formData.email, $scope.formData.user_password, $scope.formData.ephemeral, extraParams,
+ (response) => {
+ if(!response || response.error) {
+ $scope.formData.status = null;
+ var error = response ? response.error : {message: "An unknown error occured."}
+
+ // MFA Error
+ if(error.tag == "mfa-required" || error.tag == "mfa-invalid") {
+ $timeout(() => {
+ $scope.formData.showLogin = false;
+ $scope.formData.mfa = error;
+ })
+ }
+
+ // General Error
+ else {
+ $timeout(() => {
+ $scope.formData.showLogin = true;
+ $scope.formData.mfa = null;
+ })
+ alert(error.message);
+ }
+ }
+
+ // Success
+ else {
+ $scope.onAuthSuccess();
}
- } else {
- $scope.onAuthSuccess();
- }
});
})
}
@@ -150,7 +173,7 @@ class AccountMenu {
$timeout(function(){
$scope.onSuccessfulAuth()();
syncManager.refreshErroredItems();
- syncManager.sync();
+ syncManager.sync("onAuthSuccess");
})
}
@@ -159,7 +182,6 @@ class AccountMenu {
$rootScope.$broadcast("major-data-change");
$scope.clearDatabaseAndRewriteAllItems(true, block);
}
-
else {
modelManager.resetLocalMemory();
storageManager.clearAllModels(function(){
@@ -268,7 +290,7 @@ class AccountMenu {
syncManager.sync((response) => {
callback(response, errorCount);
- }, {additionalFields: ["created_at", "updated_at"]});
+ }, {additionalFields: ["created_at", "updated_at"]}, "importJSONData");
}.bind(this)
if(data.auth_params) {
@@ -431,7 +453,7 @@ class AccountMenu {
alert("Your items have been successfully re-encrypted and synced. You must sign out of all other signed in applications (mobile, desktop, web) and sign in again, or else you may corrupt your data.")
$scope.newPasswordData = {};
}, 1000)
- });
+ }, null, "reencryptPressed");
}
@@ -499,9 +521,9 @@ class AccountMenu {
$scope.encryptionStatusString = function() {
if(!authManager.offline()) {
- return "End-to-end encryption is enabled. Your data is encrypted before being synced to your private account.";
+ return "End-to-end encryption is enabled. Your data is encrypted before syncing to your private account.";
} else if(passcodeManager.hasPasscode()) {
- return "Encryption is enabled. Your data is encrypted using your passcode before being stored on disk.";
+ return "Encryption is enabled. Your data is encrypted using your passcode before saving to your device storage.";
} else {
return "Encryption is not enabled. Sign in, register, or add a passcode lock to enable encryption.";
}
@@ -511,11 +533,6 @@ class AccountMenu {
Passcode Lock
*/
- $scope.passcodeOptionAvailable = function() {
- // If you're signed in with an ephemeral session, passcode lock is unavailable
- return authManager.offline() || !authManager.isEphemeralSession();
- }
-
$scope.hasPasscode = function() {
return passcodeManager.hasPasscode();
}
@@ -531,18 +548,13 @@ class AccountMenu {
return;
}
- passcodeManager.setPasscode(passcode, () => {
+ let fn = $scope.formData.changingPasscode ? passcodeManager.changePasscode : passcodeManager.setPasscode;
+
+ fn(passcode, () => {
$timeout(function(){
$scope.formData.showPasscodeForm = false;
var offline = authManager.offline();
- // Allow UI to update before showing alert
- setTimeout(function () {
- var message = "You've succesfully set an app passcode.";
- if(offline) { message += " Your items will now be encrypted using this passcode."; }
- alert(message);
- }, 10);
-
if(offline) {
// Allows desktop to make backup file
$rootScope.$broadcast("major-data-change");
@@ -552,6 +564,12 @@ class AccountMenu {
})
}
+ $scope.changePasscodePressed = function() {
+ $scope.formData.changingPasscode = true;
+ $scope.addPasscodeClicked();
+ $scope.formData.changingPasscode = false;
+ }
+
$scope.removePasscodePressed = function() {
var signedIn = !authManager.offline();
var message = "Are you sure you want to remove your local passcode?";
@@ -577,4 +595,4 @@ class AccountMenu {
}
}
-angular.module('app.frontend').directive('accountMenu', () => new AccountMenu);
+angular.module('app').directive('accountMenu', () => new AccountMenu);
diff --git a/app/assets/javascripts/app/directives/views/actionsMenu.js b/app/assets/javascripts/app/directives/views/actionsMenu.js
new file mode 100644
index 000000000..1c7ace647
--- /dev/null
+++ b/app/assets/javascripts/app/directives/views/actionsMenu.js
@@ -0,0 +1,86 @@
+class ActionsMenu {
+
+ constructor() {
+ this.restrict = "E";
+ this.templateUrl = "directives/actions-menu.html";
+ this.scope = {
+ item: "="
+ };
+ }
+
+ controller($scope, modelManager, actionsManager) {
+ 'ngInject';
+
+ $scope.renderData = {};
+
+ $scope.extensions = actionsManager.extensions.sort((a, b) => {return a.name.toLowerCase() > b.name.toLowerCase()});
+
+ for(let ext of $scope.extensions) {
+ ext.loading = true;
+ actionsManager.loadExtensionInContextOfItem(ext, $scope.item, function(scopedExtension) {
+ ext.loading = false;
+ })
+ }
+
+ $scope.executeAction = function(action, extension, parentAction) {
+ if(action.verb == "nested") {
+ if(!action.subrows) {
+ action.subrows = $scope.subRowsForAction(action, extension);
+ } else {
+ action.subrows = null;
+ }
+ return;
+ }
+ action.running = true;
+ actionsManager.executeAction(action, extension, $scope.item, function(response){
+ action.running = false;
+ $scope.handleActionResponse(action, response);
+
+ // reload extension actions
+ actionsManager.loadExtensionInContextOfItem(extension, $scope.item, function(ext){
+ // keep nested state
+ if(parentAction) {
+ var matchingAction = _.find(ext.actions, {label: parentAction.label});
+ matchingAction.subrows = $scope.subRowsForAction(parentAction, extension);
+ }
+ });
+ })
+ }
+
+ $scope.handleActionResponse = function(action, response) {
+ switch (action.verb) {
+ case "render": {
+ var item = response.item;
+ if(item.content_type == "Note") {
+ $scope.renderData.title = item.title;
+ $scope.renderData.text = item.text;
+ $scope.renderData.showRenderModal = true;
+ }
+ }
+ }
+ }
+
+
+ $scope.subRowsForAction = function(parentAction, extension) {
+ if(!parentAction.subactions) {
+ return null;
+ }
+ return parentAction.subactions.map((subaction) => {
+ return {
+ onClick: ($event) => {
+ this.executeAction(subaction, extension, parentAction);
+ $event.stopPropagation();
+ },
+ title: subaction.label,
+ subtitle: subaction.desc,
+ spinnerClass: subaction.running ? 'info' : null
+ }
+ })
+ }
+
+
+ }
+
+}
+
+angular.module('app').directive('actionsMenu', () => new ActionsMenu);
diff --git a/app/assets/javascripts/app/directives/views/componentModal.js b/app/assets/javascripts/app/directives/views/componentModal.js
new file mode 100644
index 000000000..7cda3c897
--- /dev/null
+++ b/app/assets/javascripts/app/directives/views/componentModal.js
@@ -0,0 +1,31 @@
+class ComponentModal {
+
+ constructor() {
+ this.restrict = "E";
+ this.templateUrl = "directives/component-modal.html";
+ this.scope = {
+ show: "=",
+ component: "=",
+ callback: "=",
+ onDismiss: "&"
+ };
+ }
+
+ link($scope, el, attrs) {
+ $scope.el = el;
+ }
+
+ controller($scope, $timeout, componentManager) {
+ 'ngInject';
+
+ $scope.dismiss = function(callback) {
+ $scope.el.remove();
+ $scope.$destroy();
+ $scope.onDismiss && $scope.onDismiss() && $scope.onDismiss()($scope.component);
+ callback && callback();
+ }
+ }
+
+}
+
+angular.module('app').directive('componentModal', () => new ComponentModal);
diff --git a/app/assets/javascripts/app/directives/views/componentView.js b/app/assets/javascripts/app/directives/views/componentView.js
new file mode 100644
index 000000000..dd67eadee
--- /dev/null
+++ b/app/assets/javascripts/app/directives/views/componentView.js
@@ -0,0 +1,130 @@
+class ComponentView {
+
+ constructor(componentManager, desktopManager, $timeout) {
+ this.restrict = "E";
+ this.templateUrl = "directives/component-view.html";
+ this.scope = {
+ component: "=",
+ manualDealloc: "="
+ };
+
+ this.componentManager = componentManager;
+ this.desktopManager = desktopManager;
+ this.timeout = $timeout;
+ }
+
+ link($scope, el, attrs, ctrl) {
+ $scope.el = el;
+
+ $scope.identifier = "component-view-" + Math.random();
+
+ // console.log("Registering handler", $scope.identifier, $scope.component.name);
+
+ this.componentManager.registerHandler({identifier: $scope.identifier, areas: [$scope.component.area], activationHandler: (component) => {
+ if(component.active) {
+ this.timeout(() => {
+ var iframe = this.componentManager.iframeForComponent(component);
+ if(iframe) {
+ iframe.onload = function() {
+ this.componentManager.registerComponentWindow(component, iframe.contentWindow);
+ }.bind(this);
+ }
+ });
+ }
+ },
+ actionHandler: (component, action, data) => {
+ if(action == "set-size") {
+ this.componentManager.handleSetSizeEvent(component, data);
+ }
+ }});
+
+ $scope.updateObserver = this.desktopManager.registerUpdateObserver((component) => {
+ if(component == $scope.component && component.active) {
+ $scope.reloadComponent();
+ }
+ })
+
+ $scope.$watch('component', function(component, prevComponent){
+ ctrl.componentValueChanging(component, prevComponent);
+ });
+ }
+
+ controller($scope, $timeout, componentManager, desktopManager) {
+ 'ngInject';
+
+ this.componentValueChanging = (component, prevComponent) => {
+ if(prevComponent && component !== prevComponent) {
+ // Deactive old component
+ componentManager.deactivateComponent(prevComponent);
+ }
+
+ if(component) {
+ componentManager.activateComponent(component);
+ console.log("Loading", $scope.component.name, $scope.getUrl(), component.valid_until);
+
+ $scope.reloadStatus();
+ }
+ }
+
+ $scope.reloadComponent = function() {
+ console.log("Reloading component", $scope.component);
+ componentManager.deactivateComponent($scope.component);
+ $timeout(() => {
+ componentManager.activateComponent($scope.component);
+ })
+ }
+
+ $scope.reloadStatus = function() {
+ let component = $scope.component;
+ $scope.reloading = true;
+ let previouslyValid = $scope.componentValid;
+
+ var expired, offlineRestricted, urlError;
+
+ offlineRestricted = component.offlineOnly && !isDesktopApplication();
+
+ urlError =
+ (!isDesktopApplication() && (!component.url && !component.hosted_url))
+ ||
+ (isDesktopApplication() && (!component.local_url && !component.url && !component.hosted_url))
+
+ expired = component.valid_until && component.valid_until <= new Date();
+
+ $scope.componentValid = !offlineRestricted && !urlError && !expired;
+
+ if(offlineRestricted) $scope.error = 'offline-restricted';
+ else if(urlError) $scope.error = 'url-missing';
+ else if(expired) $scope.error = 'expired';
+ else $scope.error = null;
+
+ if($scope.componentValid !== previouslyValid) {
+ if($scope.componentValid) {
+ componentManager.activateComponent(component);
+ }
+ }
+
+ $timeout(() => {
+ $scope.reloading = false;
+ }, 500)
+ }
+
+ $scope.getUrl = function() {
+ var url = componentManager.urlForComponent($scope.component);
+ $scope.component.runningLocally = (url !== $scope.component.url) && url !== ($scope.component.hosted_url);
+ return url;
+ }
+
+ $scope.$on("$destroy", function() {
+ // console.log("Deregistering handler", $scope.identifier, $scope.component.name);
+ componentManager.deregisterHandler($scope.identifier);
+ if($scope.component && !$scope.manualDealloc) {
+ componentManager.deactivateComponent($scope.component);
+ }
+
+ desktopManager.deregisterUpdateObserver($scope.updateObserver);
+ });
+ }
+
+}
+
+angular.module('app').directive('componentView', (componentManager, desktopManager, $timeout) => new ComponentView(componentManager, desktopManager, $timeout));
diff --git a/app/assets/javascripts/app/directives/views/editorMenu.js b/app/assets/javascripts/app/directives/views/editorMenu.js
new file mode 100644
index 000000000..734a829cc
--- /dev/null
+++ b/app/assets/javascripts/app/directives/views/editorMenu.js
@@ -0,0 +1,91 @@
+class EditorMenu {
+
+ constructor() {
+ this.restrict = "E";
+ this.templateUrl = "directives/editor-menu.html";
+ this.scope = {
+ callback: "&",
+ selectedEditor: "=",
+ currentItem: "="
+ };
+ }
+
+ controller($scope, componentManager, syncManager, $timeout) {
+ 'ngInject';
+
+ $scope.formData = {};
+
+ $scope.editors = componentManager.componentsForArea("editor-editor").sort((a, b) => {return a.name.toLowerCase() > b.name.toLowerCase()});
+ $scope.stack = componentManager.componentsForArea("editor-stack").sort((a, b) => {return a.name.toLowerCase() > b.name.toLowerCase()});
+
+ $scope.isDesktop = isDesktopApplication();
+
+ $scope.defaultEditor = $scope.editors.filter((e) => {return e.isDefaultEditor()})[0];
+
+ $scope.selectComponent = function($event, component) {
+ $event.stopPropagation();
+ if(component) {
+ component.conflict_of = null; // clear conflict if applicable
+ }
+ $timeout(() => {
+ $scope.callback()(component);
+ })
+ }
+
+ $scope.toggleDefaultForEditor = function(editor) {
+ if($scope.defaultEditor == editor) {
+ $scope.removeEditorDefault(editor);
+ } else {
+ $scope.makeEditorDefault(editor);
+ }
+ }
+
+ $scope.offlineAvailableForComponent = function(component) {
+ return component.local_url && isDesktopApplication();
+ }
+
+ $scope.makeEditorDefault = function(component) {
+ var currentDefault = componentManager.componentsForArea("editor-editor").filter((e) => {return e.isDefaultEditor()})[0];
+ if(currentDefault) {
+ currentDefault.setAppDataItem("defaultEditor", false);
+ currentDefault.setDirty(true);
+ }
+
+ component.setAppDataItem("defaultEditor", true);
+ component.setDirty(true);
+ syncManager.sync("makeEditorDefault");
+
+ $scope.defaultEditor = component;
+ }
+
+ $scope.removeEditorDefault = function(component) {
+ component.setAppDataItem("defaultEditor", false);
+ component.setDirty(true);
+ syncManager.sync("removeEditorDefault");
+
+ $scope.defaultEditor = null;
+ }
+
+ $scope.shouldDisplayRunningLocallyLabel = function(component) {
+ if(!component.runningLocally) {
+ return false;
+ }
+
+ if(component == $scope.selectedEditor) {
+ return true;
+ } else if(component.area == "editor-stack") {
+ return $scope.stackComponentEnabled(component);
+ } else {
+ return false;
+ }
+ }
+
+ $scope.stackComponentEnabled = function(component) {
+ return component.active && !component.isExplicitlyDisabledForItem($scope.currentItem);
+ }
+
+ }
+
+}
+
+angular.module('app').directive('editorMenu', () => new EditorMenu);
diff --git a/app/assets/javascripts/app/directives/views/menuRow.js b/app/assets/javascripts/app/directives/views/menuRow.js
new file mode 100644
index 000000000..fe7a988f0
--- /dev/null
+++ b/app/assets/javascripts/app/directives/views/menuRow.js
@@ -0,0 +1,32 @@
+class MenuRow {
+
+ constructor() {
+ this.restrict = "E";
+ this.transclude = true;
+ this.templateUrl = "directives/menu-row.html";
+ this.scope = {
+ circle: "=",
+ title: "=",
+ subtite: "=",
+ hasButton: "=",
+ buttonText: "=",
+ buttonClass: "=",
+ buttonAction: "&",
+ spinnerClass: "=",
+ subRows: "=",
+ faded: "="
+ };
+ }
+
+ controller($scope, componentManager) {
+ 'ngInject';
+
+ $scope.clickButton = function($event) {
+ $event.stopPropagation();
+ $scope.buttonAction();
+ }
+
+ }
+}
+
+angular.module('app').directive('menuRow', () => new MenuRow);
diff --git a/app/assets/javascripts/app/directives/views/panelResizer.js b/app/assets/javascripts/app/directives/views/panelResizer.js
new file mode 100644
index 000000000..646bc1ab4
--- /dev/null
+++ b/app/assets/javascripts/app/directives/views/panelResizer.js
@@ -0,0 +1,246 @@
+class PanelResizer {
+
+ constructor() {
+ this.restrict = "E";
+ this.templateUrl = "directives/panel-resizer.html";
+ this.scope = {
+ index: "=",
+ panelId: "=",
+ onResize: "&",
+ onResizeFinish: "&",
+ control: "=",
+ alwaysVisible: "=",
+ minWidth: "=",
+ property: "=",
+ hoverable: "=",
+ collapsable: "="
+ };
+ }
+
+ link(scope, elem, attrs, ctrl) {
+ scope.elem = elem;
+
+ scope.control.setWidth = function(value) {
+ scope.setWidth(value, true);
+ }
+
+ scope.control.setLeft = function(value) {
+ scope.setLeft(value);
+ }
+ }
+
+ controller($scope, $element, modelManager, actionsManager, $timeout) {
+ 'ngInject';
+
+ let panel = document.getElementById($scope.panelId);
+ if(!panel) {
+ console.log("Panel not found for", $scope.panelId);
+ }
+
+ let resizerColumn = $element[0];
+ let resizerWidth = resizerColumn.offsetWidth;
+ let minWidth = $scope.minWidth || resizerWidth;
+ var pressed = false;
+ var startWidth = panel.scrollWidth, startX = 0, lastDownX = 0, collapsed, lastWidth = startWidth, startLeft, lastLeft;
+ var appFrame;
+
+ function getParentRect() {
+ return panel.parentNode.getBoundingClientRect();
+ }
+
+ if($scope.property == "right") {
+ let handleReize = debounce((event) => {
+ reloadDefaultValues();
+ handleWidthEvent();
+ $timeout(() => { $scope.finishSettingWidth(); })
+ }, 250);
+
+ window.addEventListener('resize', handleReize);
+
+ $scope.$on("$destroy", function() {
+ window.removeEventListener('resize', handleReize);
+ });
+ }
+
+ function reloadDefaultValues() {
+ startWidth = panel.scrollWidth;
+ appFrame = document.getElementById("app").getBoundingClientRect();
+ }
+ reloadDefaultValues();
+
+ if($scope.alwaysVisible) {
+ resizerColumn.classList.add("always-visible");
+ }
+
+ if($scope.hoverable) {
+ resizerColumn.classList.add("hoverable");
+ }
+
+ $scope.setWidth = function(width, finish) {
+ if(width < minWidth) {
+ width = minWidth;
+ }
+
+ let parentRect = getParentRect();
+
+ if(width > parentRect.width) {
+ width = parentRect.width;
+ }
+
+ let maxWidth = appFrame.width - panel.getBoundingClientRect().x;
+ if(width > maxWidth) {
+ width = maxWidth;
+ }
+
+ if(width == parentRect.width) {
+ panel.style.width = "100%";
+ panel.style.flexBasis = "100%";
+ } else {
+ panel.style.flexBasis = width + "px";
+ panel.style.width = width + "px";
+ }
+
+ lastWidth = width;
+
+ if(finish) {
+ $scope.finishSettingWidth();
+ }
+ }
+
+ $scope.setLeft = function(left) {
+ panel.style.left = left + "px";
+ lastLeft = left;
+ }
+
+ $scope.finishSettingWidth = function() {
+ if(!$scope.collapsable) {
+ return;
+ }
+
+ if(lastWidth <= minWidth) {
+ collapsed = true;
+ } else {
+ collapsed = false;
+ }
+ if(collapsed) {
+ resizerColumn.classList.add("collapsed");
+ } else {
+ resizerColumn.classList.remove("collapsed");
+ }
+ }
+
+ resizerColumn.addEventListener("mousedown", function(event){
+ pressed = true;
+ lastDownX = event.clientX;
+ startWidth = panel.scrollWidth;
+ startLeft = panel.offsetLeft;
+ panel.classList.add("no-selection");
+
+ if($scope.hoverable) {
+ resizerColumn.classList.add("dragging");
+ }
+ })
+
+ document.addEventListener("mousemove", function(event){
+ if(!pressed) {
+ return;
+ }
+
+ event.preventDefault();
+
+ if($scope.property && $scope.property == 'left') {
+ handleLeftEvent(event);
+ } else {
+ handleWidthEvent(event);
+ }
+ })
+
+ function handleWidthEvent(event) {
+ var rect = panel.getBoundingClientRect();
+ var panelMaxX = rect.left + (startWidth || panel.style.maxWidth);
+
+ var x;
+ if(event) {
+ x = event.clientX;
+ } else {
+ // coming from resize event
+ x = 0;
+ lastDownX = 0;
+ }
+
+ let deltaX = x - lastDownX;
+ var newWidth = startWidth + deltaX;
+
+ $scope.setWidth(newWidth, false);
+
+ if($scope.onResize()) {
+ $scope.onResize()(lastWidth, panel);
+ }
+ }
+
+ function handleLeftEvent(event) {
+ var panelRect = panel.getBoundingClientRect();
+ var x = event.clientX || panelRect.x;
+ let deltaX = x - lastDownX;
+ var newLeft = startLeft + deltaX;
+ if(newLeft < 0) {
+ newLeft = 0;
+ deltaX = -startLeft;
+ }
+
+ let parentRect = getParentRect();
+
+ var newWidth = startWidth - deltaX;
+ if(newWidth < minWidth) {
+ newWidth = minWidth;
+ }
+
+ if(newWidth > parentRect.width) {
+ newWidth = parentRect.width;
+ }
+
+
+ if(newLeft + newWidth > parentRect.width) {
+ newLeft = parentRect.width - newWidth;
+ }
+
+ $scope.setLeft(newLeft, false);
+ $scope.setWidth(newWidth, false);
+ }
+
+ document.addEventListener("mouseup", function(event){
+ if(pressed) {
+ pressed = false;
+ resizerColumn.classList.remove("dragging");
+ panel.classList.remove("no-selection");
+
+ let isMaxWidth = lastWidth == getParentRect().width;
+
+ if($scope.onResizeFinish) {
+ $scope.onResizeFinish()(lastWidth, lastLeft, isMaxWidth);
+ }
+
+ $scope.finishSettingWidth();
+ }
+ })
+ }
+
+}
+
+angular.module('app').directive('panelResizer', () => new PanelResizer);
+
+/* via https://davidwalsh.name/javascript-debounce-function */
+function debounce(func, wait, immediate) {
+ var timeout;
+ return function() {
+ var context = this, args = arguments;
+ var later = function() {
+ timeout = null;
+ if (!immediate) func.apply(context, args);
+ };
+ var callNow = immediate && !timeout;
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ if (callNow) func.apply(context, args);
+ };
+};
diff --git a/app/assets/javascripts/app/directives/views/permissionsModal.js b/app/assets/javascripts/app/directives/views/permissionsModal.js
new file mode 100644
index 000000000..a04ad0d8a
--- /dev/null
+++ b/app/assets/javascripts/app/directives/views/permissionsModal.js
@@ -0,0 +1,100 @@
+class PermissionsModal {
+
+ constructor() {
+ this.restrict = "E";
+ this.templateUrl = "directives/permissions-modal.html";
+ this.scope = {
+ show: "=",
+ component: "=",
+ permissions: "=",
+ callback: "="
+ };
+ }
+
+ link($scope, el, attrs) {
+
+ $scope.dismiss = function() {
+ el.remove();
+ }
+
+ $scope.accept = function() {
+ $scope.callback(true);
+ $scope.dismiss();
+ }
+
+ $scope.deny = function() {
+ $scope.callback(false);
+ $scope.dismiss();
+ }
+ }
+
+ controller($scope, modelManager) {
+ 'ngInject';
+
+ $scope.permissionsString = function() {
+ var finalString = "";
+ let permissionsCount = $scope.permissions.length;
+
+ let addSeparator = (index, length) => {
+ if(index > 0) {
+ if(index == length - 1) {
+ if(length == 2) {
+ return " and ";
+ } else {
+ return ", and "
+ }
+ } else {
+ return ", ";
+ }
+ }
+
+ return "";
+ }
+
+ $scope.permissions.forEach((permission, index) => {
+
+ if(permission.name === "stream-items") {
+ var types = permission.content_types.map(function(type){
+ var desc = modelManager.humanReadableDisplayForContentType(type);
+ if(desc) {
+ return desc + "s";
+ } else {
+ return "items of type " + type;
+ }
+ })
+ var typesString = "";
+
+ for(var i = 0;i < types.length;i++) {
+ var type = types[i];
+ typesString += addSeparator(i, types.length + permissionsCount - index - 1);
+ typesString += type;
+ }
+
+ finalString += addSeparator(index, permissionsCount);
+
+ finalString += typesString;
+
+ if(types.length >= 2 && index < permissionsCount - 1) {
+ // If you have a list of types, and still an additional root-level permission coming up, add a comma
+ finalString += ", ";
+ }
+ } else if(permission.name === "stream-context-item") {
+ var mapping = {
+ "editor-stack" : "working note",
+ "note-tags" : "working note",
+ "editor-editor": "working note"
+ }
+
+ finalString += addSeparator(index, permissionsCount, true);
+
+ finalString += mapping[$scope.component.area];
+ }
+ })
+
+ return finalString + ".";
+ }
+ }
+
+}
+
+angular.module('app').directive('permissionsModal', () => new PermissionsModal);
diff --git a/app/assets/javascripts/app/services/filters/appDate.js b/app/assets/javascripts/app/filters/appDate.js
similarity index 91%
rename from app/assets/javascripts/app/services/filters/appDate.js
rename to app/assets/javascripts/app/filters/appDate.js
index 381c3ed54..9a84a796e 100644
--- a/app/assets/javascripts/app/services/filters/appDate.js
+++ b/app/assets/javascripts/app/filters/appDate.js
@@ -1,4 +1,4 @@
-angular.module('app.frontend')
+angular.module('app')
.filter('appDate', function ($filter) {
return function (input) {
return input ? $filter('date')(new Date(input), 'MM/dd/yyyy', 'UTC') : '';
diff --git a/app/assets/javascripts/app/services/filters/sortBy.js b/app/assets/javascripts/app/filters/sortBy.js
similarity index 97%
rename from app/assets/javascripts/app/services/filters/sortBy.js
rename to app/assets/javascripts/app/filters/sortBy.js
index c3902604b..2f19d3769 100644
--- a/app/assets/javascripts/app/services/filters/sortBy.js
+++ b/app/assets/javascripts/app/filters/sortBy.js
@@ -1,4 +1,4 @@
-angular.module('app.frontend')
+angular.module('app')
.filter('sortBy', function ($filter) {
return function(items, sortBy) {
let sortValueFn = (a, b, pinCheck = false) => {
diff --git a/app/assets/javascripts/app/services/filters/startFrom.js b/app/assets/javascripts/app/filters/startFrom.js
similarity index 56%
rename from app/assets/javascripts/app/services/filters/startFrom.js
rename to app/assets/javascripts/app/filters/startFrom.js
index 3cf824c4c..7b64038f6 100644
--- a/app/assets/javascripts/app/services/filters/startFrom.js
+++ b/app/assets/javascripts/app/filters/startFrom.js
@@ -1,4 +1,4 @@
-angular.module('app.frontend').filter('startFrom', function() {
+angular.module('app').filter('startFrom', function() {
return function(input, start) {
return input.slice(start);
};
diff --git a/app/assets/javascripts/app/services/filters/trusted.js b/app/assets/javascripts/app/filters/trusted.js
similarity index 52%
rename from app/assets/javascripts/app/services/filters/trusted.js
rename to app/assets/javascripts/app/filters/trusted.js
index 7bb57b301..f2a41a3c0 100644
--- a/app/assets/javascripts/app/services/filters/trusted.js
+++ b/app/assets/javascripts/app/filters/trusted.js
@@ -1,4 +1,4 @@
-angular.module('app.frontend').filter('trusted', ['$sce', function ($sce) {
+angular.module('app').filter('trusted', ['$sce', function ($sce) {
return function(url) {
return $sce.trustAsResourceUrl(url);
};
diff --git a/app/assets/javascripts/app/frontend/models/app/extension.js b/app/assets/javascripts/app/frontend/models/app/extension.js
deleted file mode 100644
index 445c4dbb1..000000000
--- a/app/assets/javascripts/app/frontend/models/app/extension.js
+++ /dev/null
@@ -1,125 +0,0 @@
-class Action {
- constructor(json) {
- _.merge(this, json);
- this.running = false; // in case running=true was synced with server since model is uploaded nondiscriminatory
- this.error = false;
- if(this.lastExecuted) {
- // is string
- this.lastExecuted = new Date(this.lastExecuted);
- }
- }
-
- permissionsString() {
- if(!this.permissions) {
- return "";
- }
-
- var permission = this.permissions.charAt(0).toUpperCase() + this.permissions.slice(1); // capitalize first letter
- permission += ": ";
- for(var contentType of this.content_types) {
- if(contentType == "*") {
- permission += "All items";
- } else {
- permission += contentType;
- }
-
- permission += " ";
- }
-
- return permission;
- }
-
- encryptionModeString() {
- if(this.verb != "post") {
- return null;
- }
- var encryptionMode = "This action accepts data ";
- if(this.accepts_encrypted && this.accepts_decrypted) {
- encryptionMode += "encrypted or decrypted.";
- } else {
- if(this.accepts_encrypted) {
- encryptionMode += "encrypted.";
- } else {
- encryptionMode += "decrypted.";
- }
- }
- return encryptionMode;
- }
-
-}
-
-class Extension extends Item {
- constructor(json) {
- super(json);
-
- if(this.encrypted === null || this.encrypted === undefined) {
- // Default to encrypted on creation.
- this.encrypted = true;
- }
-
- if(json.actions) {
- this.actions = json.actions.map(function(action){
- return new Action(action);
- })
- }
-
- if(!this.actions) {
- this.actions = [];
- }
- }
-
- actionsInGlobalContext() {
- return this.actions.filter(function(action){
- return action.context == "global";
- })
- }
-
- actionsWithContextForItem(item) {
- return this.actions.filter(function(action){
- return action.context == item.content_type || action.context == "Item";
- })
- }
-
- mapContentToLocalProperties(content) {
- super.mapContentToLocalProperties(content)
- this.name = content.name;
- this.description = content.description;
- this.url = content.url;
-
- if(content.encrypted !== null && content.encrypted !== undefined) {
- this.encrypted = content.encrypted;
- } else {
- this.encrypted = true;
- }
-
- this.supported_types = content.supported_types;
- if(content.actions) {
- this.actions = content.actions.map(function(action){
- return new Action(action);
- })
- }
- }
-
- referenceParams() {
- return null;
- }
-
- get content_type() {
- return "Extension";
- }
-
- structureParams() {
- var params = {
- name: this.name,
- url: this.url,
- description: this.description,
- actions: this.actions,
- supported_types: this.supported_types,
- encrypted: this.encrypted
- };
-
- _.merge(params, super.structureParams());
- return params;
- }
-
-}
diff --git a/app/assets/javascripts/app/frontend/models/api/item.js b/app/assets/javascripts/app/models/api/item.js
similarity index 79%
rename from app/assets/javascripts/app/frontend/models/api/item.js
rename to app/assets/javascripts/app/models/api/item.js
index 1c3dcff1d..7671b061e 100644
--- a/app/assets/javascripts/app/frontend/models/api/item.js
+++ b/app/assets/javascripts/app/models/api/item.js
@@ -50,9 +50,17 @@ class Item {
if(json.content) {
this.mapContentToLocalProperties(this.contentObject);
+ } else if(json.deleted == true) {
+ this.handleDeletedContent();
}
}
+
+ /* Allows the item to handle the case where the item is deleted and the content is null */
+ handleDeletedContent() {
+ // Subclasses can override
+ }
+
setDirty(dirty) {
this.dirty = dirty;
@@ -84,10 +92,10 @@ class Item {
}
mapContentToLocalProperties(contentObj) {
- this.appData = contentObj.appData;
- if(!this.appData) {
- this.appData = {};
+ if(contentObj.appData) {
+ this.appData = contentObj.appData;
}
+ if(!this.appData) { this.appData = {}; }
}
createContentJSONFromProperties() {
@@ -185,7 +193,27 @@ class Item {
return this.getAppDataItem("archived");
}
+ /*
+ During sync conflicts, when determing whether to create a duplicate for an item, we can omit keys that have no
+ meaningful weight and can be ignored. For example, if one component has active = true and another component has active = false,
+ it would be silly to duplicate them, so instead we ignore this.
+ */
+ keysToIgnoreWhenCheckingContentEquality() {
+ return [];
+ }
+ isItemContentEqualWith(otherItem) {
+ let omit = (obj, keys) => {
+ for(var key of keys) {
+ delete obj[key];
+ }
+ return obj;
+ }
+ var left = omit(this.structureParams(), this.keysToIgnoreWhenCheckingContentEquality());
+ var right = omit(otherItem.structureParams(), otherItem.keysToIgnoreWhenCheckingContentEquality());
+
+ return JSON.stringify(left) === JSON.stringify(right)
+ }
/*
Dates
diff --git a/app/assets/javascripts/app/frontend/models/app/theme.js b/app/assets/javascripts/app/models/api/mfa.js
similarity index 50%
rename from app/assets/javascripts/app/frontend/models/app/theme.js
rename to app/assets/javascripts/app/models/api/mfa.js
index ec7486012..d3792654d 100644
--- a/app/assets/javascripts/app/frontend/models/app/theme.js
+++ b/app/assets/javascripts/app/models/api/mfa.js
@@ -1,4 +1,4 @@
-class Theme extends Item {
+class Mfa extends Item {
constructor(json_obj) {
super(json_obj);
@@ -6,18 +6,11 @@ class Theme extends Item {
mapContentToLocalProperties(content) {
super.mapContentToLocalProperties(content)
- this.url = content.url;
- this.name = content.name;
+ this.serverContent = content;
}
structureParams() {
- var params = {
- url: this.url,
- name: this.name,
- };
-
- _.merge(params, super.structureParams());
- return params;
+ return _.merge(this.serverContent, super.structureParams());
}
toJSON() {
@@ -25,6 +18,11 @@ class Theme extends Item {
}
get content_type() {
- return "SN|Theme";
+ return "SF|MFA";
}
+
+ doNotEncrypt() {
+ return true;
+ }
+
}
diff --git a/app/assets/javascripts/app/frontend/models/api/syncAdapter.js b/app/assets/javascripts/app/models/api/serverExtension.js
similarity index 96%
rename from app/assets/javascripts/app/frontend/models/api/syncAdapter.js
rename to app/assets/javascripts/app/models/api/serverExtension.js
index 12f87d20f..8149c5a95 100644
--- a/app/assets/javascripts/app/frontend/models/api/syncAdapter.js
+++ b/app/assets/javascripts/app/models/api/serverExtension.js
@@ -1,4 +1,4 @@
-class SyncAdapter extends Item {
+class ServerExtension extends Item {
constructor(json_obj) {
super(json_obj);
diff --git a/app/assets/javascripts/app/frontend/models/app/component.js b/app/assets/javascripts/app/models/app/component.js
similarity index 61%
rename from app/assets/javascripts/app/frontend/models/app/component.js
rename to app/assets/javascripts/app/models/app/component.js
index ac0c30d0e..92fae1ba6 100644
--- a/app/assets/javascripts/app/frontend/models/app/component.js
+++ b/app/assets/javascripts/app/models/app/component.js
@@ -18,13 +18,30 @@ class Component extends Item {
mapContentToLocalProperties(content) {
super.mapContentToLocalProperties(content)
- this.url = content.url;
+ /* Legacy */
+ this.url = content.url || content.hosted_url;
+ /* New */
+ this.local_url = content.local_url;
+ this.hosted_url = content.hosted_url || content.url;
+ this.offlineOnly = content.offlineOnly;
+
+ if(content.valid_until) {
+ this.valid_until = new Date(content.valid_until);
+ }
+
this.name = content.name;
+ this.autoupdateDisabled = content.autoupdateDisabled;
+
+ this.package_info = content.package_info;
// the location in the view this component is located in. Valid values are currently tags-list, note-tags, and editor-stack`
this.area = content.area;
this.permissions = content.permissions;
+ if(!this.permissions) {
+ this.permissions = [];
+ }
+
this.active = content.active;
// custom data that a component can store in itself
@@ -37,13 +54,25 @@ class Component extends Item {
this.associatedItemIds = content.associatedItemIds || [];
}
+ handleDeletedContent() {
+ super.handleDeletedContent();
+
+ this.active = false;
+ }
+
structureParams() {
var params = {
url: this.url,
+ hosted_url: this.hosted_url,
+ local_url: this.local_url,
+ valid_until: this.valid_until,
+ offlineOnly: this.offlineOnly,
name: this.name,
area: this.area,
+ package_info: this.package_info,
permissions: this.permissions,
active: this.active,
+ autoupdateDisabled: this.autoupdateDisabled,
componentData: this.componentData,
disassociatedItemIds: this.disassociatedItemIds,
associatedItemIds: this.associatedItemIds,
@@ -65,10 +94,26 @@ class Component extends Item {
return this.area == "editor-editor";
}
+ isTheme() {
+ return this.content_type == "SN|Theme" || this.area == "themes";
+ }
+
isDefaultEditor() {
return this.getAppDataItem("defaultEditor") == true;
}
+ setLastSize(size) {
+ this.setAppDataItem("lastSize", size);
+ }
+
+ getLastSize() {
+ return this.getAppDataItem("lastSize");
+ }
+
+ keysToIgnoreWhenCheckingContentEquality() {
+ return ["active"].concat(super.keysToIgnoreWhenCheckingContentEquality());
+ }
+
/*
An associative component depends on being explicitly activated for a given item, compared to a dissaciative component,
@@ -86,11 +131,11 @@ class Component extends Item {
this.associatedItemIds.push(item.uuid);
}
- isActiveForItem(item) {
- if(this.isAssociative()) {
- return this.associatedItemIds.indexOf(item.uuid) !== -1;
- } else {
- return this.disassociatedItemIds.indexOf(item.uuid) === -1;
- }
+ isExplicitlyEnabledForItem(item) {
+ return this.associatedItemIds.indexOf(item.uuid) !== -1;
+ }
+
+ isExplicitlyDisabledForItem(item) {
+ return this.disassociatedItemIds.indexOf(item.uuid) !== -1;
}
}
diff --git a/app/assets/javascripts/app/frontend/models/app/editor.js b/app/assets/javascripts/app/models/app/editor.js
similarity index 100%
rename from app/assets/javascripts/app/frontend/models/app/editor.js
rename to app/assets/javascripts/app/models/app/editor.js
diff --git a/app/assets/javascripts/app/models/app/extension.js b/app/assets/javascripts/app/models/app/extension.js
new file mode 100644
index 000000000..f990432a5
--- /dev/null
+++ b/app/assets/javascripts/app/models/app/extension.js
@@ -0,0 +1,61 @@
+class Action {
+ constructor(json) {
+ _.merge(this, json);
+ this.running = false; // in case running=true was synced with server since model is uploaded nondiscriminatory
+ this.error = false;
+ if(this.lastExecuted) {
+ // is string
+ this.lastExecuted = new Date(this.lastExecuted);
+ }
+ }
+}
+
+class Extension extends Component {
+ constructor(json) {
+ super(json);
+
+ if(json.actions) {
+ this.actions = json.actions.map(function(action){
+ return new Action(action);
+ })
+ }
+
+ if(!this.actions) {
+ this.actions = [];
+ }
+ }
+
+ actionsWithContextForItem(item) {
+ return this.actions.filter(function(action){
+ return action.context == item.content_type || action.context == "Item";
+ })
+ }
+
+ mapContentToLocalProperties(content) {
+ super.mapContentToLocalProperties(content)
+ this.description = content.description;
+
+ this.supported_types = content.supported_types;
+ if(content.actions) {
+ this.actions = content.actions.map(function(action){
+ return new Action(action);
+ })
+ }
+ }
+
+ get content_type() {
+ return "Extension";
+ }
+
+ structureParams() {
+ var params = {
+ description: this.description,
+ actions: this.actions.map((a) => {return _.omit(a, ["subrows", "subactions"])}),
+ supported_types: this.supported_types
+ };
+
+ _.merge(params, super.structureParams());
+ return params;
+ }
+
+}
diff --git a/app/assets/javascripts/app/frontend/models/app/note.js b/app/assets/javascripts/app/models/app/note.js
similarity index 100%
rename from app/assets/javascripts/app/frontend/models/app/note.js
rename to app/assets/javascripts/app/models/app/note.js
diff --git a/app/assets/javascripts/app/frontend/models/app/tag.js b/app/assets/javascripts/app/models/app/tag.js
similarity index 89%
rename from app/assets/javascripts/app/frontend/models/app/tag.js
rename to app/assets/javascripts/app/models/app/tag.js
index f94ee4151..b83585234 100644
--- a/app/assets/javascripts/app/frontend/models/app/tag.js
+++ b/app/assets/javascripts/app/models/app/tag.js
@@ -87,13 +87,9 @@ class Tag extends Item {
return this.notes;
}
- static arrayToDisplayString(tags, includeComma) {
- return tags.map(function(tag, i){
- var text = "#" + tag.title;
- if(i != tags.length - 1) {
- text += includeComma ? ", " : " ";
- }
- return text;
+ static arrayToDisplayString(tags) {
+ return tags.sort((a, b) => {return a.title > b.title}).map(function(tag, i){
+ return "#" + tag.title;
}).join(" ");
}
}
diff --git a/app/assets/javascripts/app/models/app/theme.js b/app/assets/javascripts/app/models/app/theme.js
new file mode 100644
index 000000000..7d03cb2c3
--- /dev/null
+++ b/app/assets/javascripts/app/models/app/theme.js
@@ -0,0 +1,12 @@
+class Theme extends Component {
+
+ constructor(json_obj) {
+ super(json_obj);
+
+ this.area = "themes";
+ }
+
+ get content_type() {
+ return "SN|Theme";
+ }
+}
diff --git a/app/assets/javascripts/app/frontend/models/local/encryptedStorage.js b/app/assets/javascripts/app/models/local/encryptedStorage.js
similarity index 100%
rename from app/assets/javascripts/app/frontend/models/local/encryptedStorage.js
rename to app/assets/javascripts/app/models/local/encryptedStorage.js
diff --git a/app/assets/javascripts/app/frontend/models/local/itemParams.js b/app/assets/javascripts/app/models/local/itemParams.js
similarity index 91%
rename from app/assets/javascripts/app/frontend/models/local/itemParams.js
rename to app/assets/javascripts/app/models/local/itemParams.js
index d5a488ae7..a1cb83e18 100644
--- a/app/assets/javascripts/app/frontend/models/local/itemParams.js
+++ b/app/assets/javascripts/app/models/local/itemParams.js
@@ -6,10 +6,14 @@ class ItemParams {
this.version = version || "002";
}
- paramsForExportFile() {
+ paramsForExportFile(includeDeleted) {
this.additionalFields = ["updated_at"];
this.forExportFile = true;
- return _.omit(this.__params(), ["deleted"]);
+ if(includeDeleted) {
+ return this.__params();
+ } else {
+ return _.omit(this.__params(), ["deleted"]);
+ }
}
paramsForExtension() {
diff --git a/app/assets/javascripts/app/frontend/routes.js b/app/assets/javascripts/app/routes.js
similarity index 90%
rename from app/assets/javascripts/app/frontend/routes.js
rename to app/assets/javascripts/app/routes.js
index 5409347db..fe6dac476 100644
--- a/app/assets/javascripts/app/frontend/routes.js
+++ b/app/assets/javascripts/app/routes.js
@@ -1,4 +1,4 @@
-angular.module('app.frontend')
+angular.module('app')
.config(function ($locationProvider) {
if(!isDesktopApplication()) {
@@ -11,5 +11,4 @@ angular.module('app.frontend')
} else {
$locationProvider.html5Mode(false);
}
-
});
diff --git a/app/assets/javascripts/app/services/actionsManager.js b/app/assets/javascripts/app/services/actionsManager.js
new file mode 100644
index 000000000..85a30253b
--- /dev/null
+++ b/app/assets/javascripts/app/services/actionsManager.js
@@ -0,0 +1,159 @@
+class ActionsManager {
+
+ constructor(httpManager, modelManager, authManager, syncManager) {
+ this.httpManager = httpManager;
+ this.modelManager = modelManager;
+ this.authManager = authManager;
+ this.syncManager = syncManager;
+ }
+
+ get extensions() {
+ return this.modelManager.extensions;
+ }
+
+ extensionsInContextOfItem(item) {
+ return this.extensions.filter(function(ext){
+ return _.includes(ext.supported_types, item.content_type) || ext.actionsWithContextForItem(item).length > 0;
+ })
+ }
+
+ /*
+ Loads an extension in the context of a certain item. The server then has the chance to respond with actions that are
+ relevant just to this item. The response extension is not saved, just displayed as a one-time thing.
+ */
+ loadExtensionInContextOfItem(extension, item, callback) {
+ this.httpManager.getAbsolute(extension.url, {content_type: item.content_type, item_uuid: item.uuid}, function(response){
+ this.updateExtensionFromRemoteResponse(extension, response);
+ callback && callback(extension);
+ }.bind(this), function(response){
+ console.log("Error loading extension", response);
+ if(callback) {
+ callback(null);
+ }
+ }.bind(this))
+ }
+
+ updateExtensionFromRemoteResponse(extension, response) {
+ if(response.description) { extension.description = response.description; }
+ if(response.supported_types) { extension.supported_types = response.supported_types; }
+
+ if(response.actions) {
+ extension.actions = response.actions.map(function(action){
+ return new Action(action);
+ })
+ } else {
+ extension.actions = [];
+ }
+ }
+
+ executeAction(action, extension, item, callback) {
+
+ var customCallback = function(response) {
+ action.running = false;
+ callback(response);
+ }
+
+ action.running = true;
+
+ let decrypted = action.access_type == "decrypted";
+
+ switch (action.verb) {
+ case "get": {
+
+ this.httpManager.getAbsolute(action.url, {}, function(response){
+ action.error = false;
+ var items = response.items || [response.item];
+ EncryptionHelper.decryptMultipleItems(items, this.authManager.keys());
+ items = this.modelManager.mapResponseItemsToLocalModels(items, ModelManager.MappingSourceRemoteActionRetrieved);
+ for(var item of items) {
+ item.setDirty(true);
+ }
+ this.syncManager.sync(null);
+ customCallback({items: items});
+ }.bind(this), function(response){
+ action.error = true;
+ customCallback(null);
+ })
+
+ break;
+ }
+
+ case "render": {
+
+ this.httpManager.getAbsolute(action.url, {}, function(response){
+ action.error = false;
+ EncryptionHelper.decryptItem(response.item, this.authManager.keys());
+ var item = this.modelManager.createItem(response.item, true /* Dont notify observers */);
+ customCallback({item: item});
+
+ }.bind(this), function(response){
+ action.error = true;
+ customCallback(null);
+ })
+
+ break;
+ }
+
+ case "show": {
+ var win = window.open(action.url, '_blank');
+ win.focus();
+ customCallback();
+ break;
+ }
+
+ case "post": {
+ var params = {};
+
+ if(action.all) {
+ var items = this.modelManager.allItemsMatchingTypes(action.content_types);
+ params.items = items.map(function(item){
+ var params = this.outgoingParamsForItem(item, extension, decrypted);
+ return params;
+ }.bind(this))
+
+ } else {
+ params.items = [this.outgoingParamsForItem(item, extension, decrypted)];
+ }
+
+ this.performPost(action, extension, params, function(response){
+ customCallback(response);
+ });
+
+ break;
+ }
+
+ default: {
+
+ }
+ }
+
+ action.lastExecuted = new Date();
+ }
+
+ outgoingParamsForItem(item, extension, decrypted = false) {
+ var keys = this.authManager.keys();
+ if(decrypted) {
+ keys = null;
+ }
+ var itemParams = new ItemParams(item, keys, this.authManager.protocolVersion());
+ return itemParams.paramsForExtension();
+ }
+
+ performPost(action, extension, params, callback) {
+ this.httpManager.postAbsolute(action.url, params, function(response){
+ action.error = false;
+ if(callback) {
+ callback(response);
+ }
+ }.bind(this), function(response){
+ action.error = true;
+ console.log("Action error response:", response);
+ if(callback) {
+ callback({error: "Request error"});
+ }
+ })
+ }
+
+}
+
+angular.module('app').service('actionsManager', ActionsManager);
diff --git a/app/assets/javascripts/app/services/authManager.js b/app/assets/javascripts/app/services/authManager.js
index 46011d36f..e90b92120 100644
--- a/app/assets/javascripts/app/services/authManager.js
+++ b/app/assets/javascripts/app/services/authManager.js
@@ -1,4 +1,4 @@
-angular.module('app.frontend')
+angular.module('app')
.provider('authManager', function () {
function domainName() {
@@ -7,11 +7,11 @@ angular.module('app.frontend')
return domain;
}
- this.$get = function($rootScope, $timeout, httpManager, modelManager, dbManager, storageManager) {
- return new AuthManager($rootScope, $timeout, httpManager, modelManager, dbManager, storageManager);
+ this.$get = function($rootScope, $timeout, httpManager, modelManager, dbManager, storageManager, singletonManager) {
+ return new AuthManager($rootScope, $timeout, httpManager, modelManager, dbManager, storageManager, singletonManager);
}
- function AuthManager($rootScope, $timeout, httpManager, modelManager, dbManager, storageManager) {
+ function AuthManager($rootScope, $timeout, httpManager, modelManager, dbManager, storageManager, singletonManager) {
this.loadInitialData = function() {
var userData = storageManager.getItem("user");
@@ -43,11 +43,10 @@ angular.module('app.frontend')
this.ephemeral = ephemeral;
if(ephemeral) {
storageManager.setModelStorageMode(StorageManager.Ephemeral);
- storageManager.setItemsMode(storageManager.hasPasscode() ? StorageManager.FixedEncrypted : StorageManager.Ephemeral);
+ storageManager.setItemsMode(StorageManager.Ephemeral);
} else {
storageManager.setModelStorageMode(StorageManager.Fixed);
storageManager.setItemsMode(storageManager.hasPasscode() ? StorageManager.FixedEncrypted : StorageManager.Fixed);
-
storageManager.setItem("ephemeral", JSON.stringify(false), StorageManager.Fixed);
}
}
@@ -95,9 +94,9 @@ angular.module('app.frontend')
return supportedVersions.includes(version);
}
- this.getAuthParamsForEmail = function(url, email, callback) {
+ this.getAuthParamsForEmail = function(url, email, extraParams, callback) {
var requestUrl = url + "/auth/params";
- httpManager.getAbsolute(requestUrl, {email: email}, function(response){
+ httpManager.getAbsolute(requestUrl, _.merge({email: email}, extraParams), function(response){
callback(response);
}, function(response){
console.error("Error getting auth params", response);
@@ -120,8 +119,8 @@ angular.module('app.frontend')
}
}
- this.login = function(url, email, password, ephemeral, callback) {
- this.getAuthParamsForEmail(url, email, function(authParams){
+ this.login = function(url, email, password, ephemeral, extraParams, callback) {
+ this.getAuthParamsForEmail(url, email, extraParams, function(authParams){
if(authParams.error) {
callback(authParams);
@@ -134,31 +133,30 @@ angular.module('app.frontend')
}
if(!this.isProtocolVersionSupported(authParams.version)) {
- alert("The protocol version associated with your account is outdated and no longer supported by this application. Please visit standardnotes.org/help/security-update for more information.");
- callback({didDisplayAlert: true});
+ let message = "The protocol version associated with your account is outdated and no longer supported by this application. Please visit standardnotes.org/help/security-update for more information.";
+ callback({error: {message: message}});
return;
}
if(!this.supportsPasswordDerivationCost(authParams.pw_cost)) {
- var string = "Your account was created on a platform with higher security capabilities than this browser supports. " +
+ let message = "Your account was created on a platform with higher security capabilities than this browser supports. " +
"If we attempted to generate your login keys here, it would take hours. " +
- "Please use a browser with more up to date security capabilities, like Google Chrome or Firefox, to login."
- alert(string)
- callback({didDisplayAlert: true});
+ "Please use a browser with more up to date security capabilities, like Google Chrome or Firefox, to log in."
+ callback({error: {message: message}});
return;
}
var minimum = this.costMinimumForVersion(authParams.version);
if(authParams.pw_cost < minimum) {
- alert("Unable to login due to insecure password parameters. Please visit standardnotes.org/help/password-upgrade for more information.");
- callback({didDisplayAlert: true});
+ let message = "Unable to login due to insecure password parameters. Please visit standardnotes.org/help/password-upgrade for more information.";
+ callback({error: {message: message}});
return;
}
Neeto.crypto.computeEncryptionKeysForUser(_.merge({password: password}, authParams), function(keys){
var requestUrl = url + "/auth/sign_in";
- var params = {password: keys.pw, email: email};
+ var params = _.merge({password: keys.pw, email: email}, extraParams);
httpManager.postAbsolute(requestUrl, params, function(response){
this.setEphemeral(ephemeral);
this.handleAuthResponse(response, email, url, authParams, keys);
@@ -291,5 +289,45 @@ angular.module('app.frontend')
this._authParams = null;
}
- }
+
+ /* User Preferences */
+
+ let prefsContentType = "SN|UserPreferences";
+
+ singletonManager.registerSingleton({content_type: prefsContentType}, (resolvedSingleton) => {
+ this.userPreferences = resolvedSingleton;
+ this.userPreferencesDidChange();
+ }, (valueCallback) => {
+ // Safe to create. Create and return object.
+ var prefs = new Item({content_type: prefsContentType});
+ modelManager.addItem(prefs);
+ prefs.setDirty(true);
+ $rootScope.sync("authManager singletonCreate");
+ valueCallback(prefs);
+ });
+
+ this.userPreferencesDidChange = function() {
+ $rootScope.$broadcast("user-preferences-changed");
+ }
+
+ this.syncUserPreferences = function() {
+ this.userPreferences.setDirty(true);
+ $rootScope.sync("syncUserPreferences");
+ }
+
+ this.getUserPrefValue = function(key, defaultValue) {
+ if(!this.userPreferences) { return defaultValue; }
+ var value = this.userPreferences.getAppDataItem(key);
+ return (value !== undefined && value != null) ? value : defaultValue;
+ }
+
+ this.setUserPrefValue = function(key, value, sync) {
+ if(!this.userPreferences) { console.log("Prefs are null, not setting value", key); return; }
+ this.userPreferences.setAppDataItem(key, value);
+ if(sync) {
+ this.syncUserPreferences();
+ }
+ }
+
+ }
});
diff --git a/app/assets/javascripts/app/services/componentManager.js b/app/assets/javascripts/app/services/componentManager.js
index c22cdbd85..52cde7942 100644
--- a/app/assets/javascripts/app/services/componentManager.js
+++ b/app/assets/javascripts/app/services/componentManager.js
@@ -3,27 +3,45 @@ let ClientDataDomain = "org.standardnotes.sn.components";
class ComponentManager {
- constructor($rootScope, modelManager, syncManager, themeManager, $timeout, $compile) {
+ constructor($rootScope, modelManager, syncManager, desktopManager, nativeExtManager, $timeout, $compile) {
this.$compile = $compile;
this.$rootScope = $rootScope;
this.modelManager = modelManager;
this.syncManager = syncManager;
- this.themeManager = themeManager;
+ this.desktopManager = desktopManager;
+ this.nativeExtManager = nativeExtManager;
this.timeout = $timeout;
this.streamObservers = [];
this.contextStreamObservers = [];
this.activeComponents = [];
+ const detectFocusChange = (event) => {
+ for(var component of this.activeComponents) {
+ if(document.activeElement == this.iframeForComponent(component)) {
+ this.timeout(() => {
+ this.focusChangedForComponent(component);
+ })
+ break;
+ }
+ }
+ }
+
+ window.addEventListener ? window.addEventListener('focus', detectFocusChange, true) : window.attachEvent('onfocusout', detectFocusChange);
+ window.addEventListener ? window.addEventListener('blur', detectFocusChange, true) : window.attachEvent('onblur', detectFocusChange);
+
+ desktopManager.registerUpdateObserver((component) => {
+ // Reload theme if active
+ if(component.active && component.isTheme()) {
+ this.postActiveThemeToAllComponents();
+ }
+ })
+
// this.loggingEnabled = true;
this.permissionDialogs = [];
this.handlers = [];
- $rootScope.$on("theme-changed", function(){
- this.postThemeToComponents();
- }.bind(this))
-
window.addEventListener("message", function(event){
if(this.loggingEnabled) {
console.log("Web app: received message", event);
@@ -31,7 +49,7 @@ class ComponentManager {
this.handleMessage(this.componentForSessionKey(event.data.sessionKey), event.data);
}.bind(this), false);
- this.modelManager.addItemSyncObserver("component-manager", "*", function(allItems, validItems, deletedItems, source) {
+ this.modelManager.addItemSyncObserver("component-manager", "*", (allItems, validItems, deletedItems, source) => {
/* If the source of these new or updated items is from a Component itself saving items, we don't need to notify
components again of the same item. Regarding notifying other components than the issuing component, other mapping sources
@@ -41,7 +59,18 @@ class ComponentManager {
return;
}
- var syncedComponents = allItems.filter(function(item){return item.content_type === "SN|Component" });
+ var syncedComponents = allItems.filter(function(item) {
+ return item.content_type === "SN|Component" || item.content_type == "SN|Theme"
+ });
+
+ /* We only want to sync if the item source is Retrieved, not MappingSourceRemoteSaved to avoid
+ recursion caused by the component being modified and saved after it is updated.
+ */
+ if(syncedComponents.length > 0 && source != ModelManager.MappingSourceRemoteSaved) {
+ // Ensure any component in our data is installed by the system
+ this.desktopManager.syncComponentsInstallation(syncedComponents);
+ }
+
for(var component of syncedComponents) {
var activeComponent = _.find(this.activeComponents, {uuid: component.uuid});
if(component.active && !component.deleted && !activeComponent) {
@@ -56,6 +85,10 @@ class ComponentManager {
return observer.contentTypes.indexOf(item.content_type) !== -1;
})
+ if(relevantItems.length == 0) {
+ continue;
+ }
+
var requiredPermissions = [
{
name: "stream-items",
@@ -63,9 +96,9 @@ class ComponentManager {
}
];
- this.runWithPermissions(observer.component, requiredPermissions, observer.originalMessage.permissions, function(){
+ this.runWithPermissions(observer.component, requiredPermissions, () => {
this.sendItemsInReply(observer.component, relevantItems, observer.originalMessage);
- }.bind(this))
+ })
}
var requiredContextPermissions = [
@@ -75,36 +108,45 @@ class ComponentManager {
];
for(let observer of this.contextStreamObservers) {
- this.runWithPermissions(observer.component, requiredContextPermissions, observer.originalMessage.permissions, function(){
- for(let handler of this.handlers) {
- if(!handler.areas.includes(observer.component.area)) {
- continue;
- }
+ for(let handler of this.handlers) {
+ if(!handler.areas.includes(observer.component.area) && !handler.areas.includes("*")) {
+ continue;
+ }
+ if(handler.contextRequestHandler) {
var itemInContext = handler.contextRequestHandler(observer.component);
if(itemInContext) {
var matchingItem = _.find(allItems, {uuid: itemInContext.uuid});
if(matchingItem) {
- this.sendContextItemInReply(observer.component, matchingItem, observer.originalMessage, source);
+ this.runWithPermissions(observer.component, requiredContextPermissions, () => {
+ this.sendContextItemInReply(observer.component, matchingItem, observer.originalMessage, source);
+ })
}
}
}
- }.bind(this))
+ }
}
- }.bind(this))
+ });
}
- postThemeToComponents() {
+ postActiveThemeToAllComponents() {
for(var component of this.components) {
- if(!component.active || !component.window) {
+ // Skip over components that are themes themselves,
+ // or components that are not active, or components that don't have a window
+ if(component.isTheme() || !component.active || !component.window) {
continue;
}
- this.postThemeToComponent(component);
+ this.postActiveThemeToComponent(component);
}
}
- postThemeToComponent(component) {
+ getActiveTheme() {
+ return this.componentsForArea("themes").find((theme) => {return theme.active});
+ }
+
+ postActiveThemeToComponent(component) {
+ var activeTheme = this.getActiveTheme();
var data = {
- themes: [this.themeManager.currentTheme ? this.themeManager.currentTheme.url : null]
+ themes: [activeTheme ? this.urlForComponent(activeTheme) : null]
}
this.sendMessageToComponent(component, {action: "themes", data: data})
@@ -112,7 +154,7 @@ class ComponentManager {
contextItemDidChangeInArea(area) {
for(let handler of this.handlers) {
- if(handler.areas.includes(area) === false) {
+ if(handler.areas.includes(area) === false && !handler.areas.includes("*")) {
continue;
}
var observers = this.contextStreamObservers.filter(function(observer){
@@ -120,8 +162,10 @@ class ComponentManager {
})
for(let observer of observers) {
- var itemInContext = handler.contextRequestHandler(observer.component);
- this.sendContextItemInReply(observer.component, itemInContext, observer.originalMessage);
+ if(handler.contextRequestHandler) {
+ var itemInContext = handler.contextRequestHandler(observer.component);
+ this.sendContextItemInReply(observer.component, itemInContext, observer.originalMessage);
+ }
}
}
}
@@ -129,7 +173,8 @@ class ComponentManager {
jsonForItem(item, component, source) {
var params = {uuid: item.uuid, content_type: item.content_type, created_at: item.created_at, updated_at: item.updated_at, deleted: item.deleted};
params.content = item.createContentJSONFromProperties();
- params.clientData = item.getDomainDataItem(component.url, ClientDataDomain) || {};
+ /* Legacy is using component.url key, so if it's present, use it, otherwise use uuid */
+ params.clientData = item.getDomainDataItem(component.url || component.uuid, ClientDataDomain) || {};
/* This means the this function is being triggered through a remote Saving response, which should not update
actual local content values. The reason is, Save responses may be delayed, and a user may have changed some values
@@ -139,7 +184,7 @@ class ComponentManager {
if(source && source == ModelManager.MappingSourceRemoteSaved) {
params.isMetadataUpdate = true;
}
- this.removePrivatePropertiesFromResponseItems([params]);
+ this.removePrivatePropertiesFromResponseItems([params], component);
return params;
}
@@ -160,8 +205,33 @@ class ComponentManager {
this.replyToMessage(component, originalMessage, response);
}
+ replyToMessage(component, originalMessage, replyData) {
+ var reply = {
+ action: "reply",
+ original: originalMessage,
+ data: replyData
+ }
+
+ this.sendMessageToComponent(component, reply);
+ }
+
+ sendMessageToComponent(component, message) {
+ let permissibleActionsWhileHidden = ["component-registered", "themes"];
+ if(component.hidden && !permissibleActionsWhileHidden.includes(message.action)) {
+ if(this.loggingEnabled) {
+ console.log("Component disabled for current item, not sending any messages.", component.name);
+ }
+ return;
+ }
+
+ if(this.loggingEnabled) {
+ console.log("Web|sendMessageToComponent", component, message);
+ }
+ component.window.postMessage(message, "*");
+ }
+
get components() {
- return this.modelManager.itemsForContentType("SN|Component");
+ return this.modelManager.allItemsMatchingTypes(["SN|Component", "SN|Theme"]);
}
componentsForArea(area) {
@@ -170,9 +240,17 @@ class ComponentManager {
})
}
+ urlForComponent(component) {
+ if(component.offlineOnly || (isDesktopApplication() && component.local_url)) {
+ return component.local_url && component.local_url.replace("sn://", this.desktopManager.getApplicationDataPath() + "/");
+ } else {
+ return component.hosted_url || component.url;
+ }
+ }
+
componentForUrl(url) {
return this.components.filter(function(component){
- return component.url === url;
+ return component.url === url || component.hosted_url === url;
})[0];
}
@@ -191,91 +269,46 @@ class ComponentManager {
/**
Possible Messages:
- set-size
- stream-items
- stream-context-item
- save-items
- select-item
- associate-item
- deassociate-item
- clear-selection
- create-item
- delete-items
- set-component-data
- save-context-client-data
- get-context-client-data
+ set-size
+ stream-items
+ stream-context-item
+ save-items
+ select-item
+ associate-item
+ deassociate-item
+ clear-selection
+ create-item
+ delete-items
+ set-component-data
+ install-local-component
+ toggle-activate-component
+ request-permissions
*/
if(message.action === "stream-items") {
this.handleStreamItemsMessage(component, message);
- }
-
- else if(message.action === "stream-context-item") {
+ } else if(message.action === "stream-context-item") {
this.handleStreamContextItemMessage(component, message);
+ } else if(message.action === "set-component-data") {
+ this.handleSetComponentDataMessage(component, message);
+ } else if(message.action === "delete-items") {
+ this.handleDeleteItemsMessage(component, message);
+ } else if(message.action === "create-item") {
+ this.handleCreateItemMessage(component, message);
+ } else if(message.action === "save-items") {
+ this.handleSaveItemsMessage(component, message);
+ } else if(message.action === "toggle-activate-component") {
+ let componentToToggle = this.modelManager.findItem(message.data.uuid);
+ this.handleToggleComponentMessage(component, componentToToggle, message);
+ } else if(message.action === "request-permissions") {
+ this.handleRequestPermissionsMessage(component, message);
+ } else if(message.action === "install-local-component") {
+ this.handleInstallLocalComponentMessage(component, message);
}
- else if(message.action === "set-component-data") {
- component.componentData = message.data.componentData;
- component.setDirty(true);
- this.syncManager.sync();
- }
-
- else if(message.action === "delete-items") {
- var items = message.data.items;
- var noun = items.length == 1 ? "item" : "items";
- if(confirm(`Are you sure you want to delete ${items.length} ${noun}?`)) {
- for(var item of items) {
- var model = this.modelManager.findItem(item.uuid);
- this.modelManager.setItemToBeDeleted(model);
- }
-
- this.syncManager.sync();
- }
- }
-
- else if(message.action === "create-item") {
- var responseItem = message.data.item;
- this.removePrivatePropertiesFromResponseItems([responseItem]);
- var item = this.modelManager.createItem(responseItem);
- if(responseItem.clientData) {
- item.setDomainDataItem(component.url, responseItem.clientData, ClientDataDomain);
- }
- this.modelManager.addItem(item);
- this.modelManager.resolveReferencesForItem(item);
- item.setDirty(true);
- this.syncManager.sync();
- this.replyToMessage(component, message, {item: this.jsonForItem(item, component)})
- }
-
- else if(message.action === "save-items") {
- var responseItems = message.data.items;
-
- this.removePrivatePropertiesFromResponseItems(responseItems);
-
- /*
- We map the items here because modelManager is what updates the UI. If you were to instead get the items directly,
- this would update them server side via sync, but would never make its way back to the UI.
- */
- var localItems = this.modelManager.mapResponseItemsToLocalModels(responseItems, ModelManager.MappingSourceComponentRetrieved);
-
- for(var item of localItems) {
- var responseItem = _.find(responseItems, {uuid: item.uuid});
- _.merge(item.content, responseItem.content);
- if(responseItem.clientData) {
- item.setDomainDataItem(component.url, responseItem.clientData, ClientDataDomain);
- }
- item.setDirty(true);
- }
- this.syncManager.sync((response) => {
- // Allow handlers to be notified when a save begins and ends, to update the UI
- var saveMessage = Object.assign({}, message);
- saveMessage.action = response && response.error ? "save-error" : "save-success";
- this.handleMessage(component, saveMessage);
- });
- }
-
+ // Notify observers
for(let handler of this.handlers) {
- if(handler.areas.includes(component.area)) {
+ if(handler.areas.includes(component.area) || handler.areas.includes("*")) {
this.timeout(function(){
handler.actionHandler(component, message.action, message.data);
})
@@ -283,9 +316,18 @@ class ComponentManager {
}
}
- removePrivatePropertiesFromResponseItems(responseItems) {
+ removePrivatePropertiesFromResponseItems(responseItems, component, options = {}) {
+ if(component) {
+ // System extensions can bypass this step
+ if(this.nativeExtManager.isSystemExtension(component)) {
+ return;
+ }
+ }
// Don't allow component to overwrite these properties.
- let privateProperties = ["appData"];
+ var privateProperties = ["appData", "autoupdateDisabled", "permissions", "active"];
+ if(options) {
+ if(options.includeUrls) { privateProperties = privateProperties.concat(["url", "hosted_url", "local_url"])}
+ }
for(var responseItem of responseItems) {
// Do not pass in actual items here, otherwise that would be destructive.
@@ -293,7 +335,7 @@ class ComponentManager {
console.assert(typeof responseItem.setDirty !== 'function');
for(var prop of privateProperties) {
- delete responseItem[prop];
+ delete responseItem.content[prop];
}
}
}
@@ -306,25 +348,24 @@ class ComponentManager {
}
];
- this.runWithPermissions(component, requiredPermissions, message.permissions, function(){
- if(!_.find(this.streamObservers, {identifier: component.url})) {
+ this.runWithPermissions(component, requiredPermissions, () => {
+ if(!_.find(this.streamObservers, {identifier: component.uuid})) {
// for pushing laster as changes come in
this.streamObservers.push({
- identifier: component.url,
+ identifier: component.uuid,
component: component,
originalMessage: message,
contentTypes: message.data.content_types
})
}
-
// push immediately now
var items = [];
for(var contentType of message.data.content_types) {
items = items.concat(this.modelManager.itemsForContentType(contentType));
}
this.sendItemsInReply(component, items, message);
- }.bind(this));
+ });
}
handleStreamContextItemMessage(component, message) {
@@ -335,55 +376,223 @@ class ComponentManager {
}
];
- this.runWithPermissions(component, requiredPermissions, message.permissions, function(){
- if(!_.find(this.contextStreamObservers, {identifier: component.url})) {
+ this.runWithPermissions(component, requiredPermissions, function(){
+ if(!_.find(this.contextStreamObservers, {identifier: component.uuid})) {
// for pushing laster as changes come in
this.contextStreamObservers.push({
- identifier: component.url,
+ identifier: component.uuid,
component: component,
originalMessage: message
})
}
// push immediately now
- for(let handler of this.handlers) {
- if(handler.areas.includes(component.area) === false) {
- continue;
+ for(let handler of this.handlersForArea(component.area)) {
+ if(handler.contextRequestHandler) {
+ var itemInContext = handler.contextRequestHandler(component);
+ this.sendContextItemInReply(component, itemInContext, message);
}
- var itemInContext = handler.contextRequestHandler(component);
- this.sendContextItemInReply(component, itemInContext, message);
}
}.bind(this))
}
- runWithPermissions(component, requiredPermissions, requestedPermissions, runFunction) {
-
- var acquiredPermissions = component.permissions;
-
- var requestedMatchesRequired = true;
-
- for(var required of requiredPermissions) {
- var matching = _.find(requestedPermissions, required);
- if(!matching) {
- requestedMatchesRequired = false;
- break;
+ isItemWithinComponentContextJurisdiction(item, component) {
+ for(let handler of this.handlersForArea(component.area)) {
+ if(handler.contextRequestHandler) {
+ var itemInContext = handler.contextRequestHandler(component);
+ if(itemInContext && itemInContext.uuid == item.uuid) {
+ return true;
+ }
}
}
+ return false;
+ }
- if(!requestedMatchesRequired) {
- // Error with Component permissions request
- console.error("You are requesting permissions", requestedPermissions, "when you need to be requesting", requiredPermissions, ". Component:", component);
+ handlersForArea(area) {
+ return this.handlers.filter((candidate) => {return candidate.areas.includes(area)});
+ }
+
+ handleSaveItemsMessage(component, message) {
+ var responseItems = message.data.items;
+ var requiredPermissions;
+
+ // Check if you're just trying to save the context item, which requires only stream-context-item permissions
+ if(responseItems.length == 1 && this.isItemWithinComponentContextJurisdiction(responseItems[0], component)) {
+ requiredPermissions = [
+ {
+ name: "stream-context-item"
+ }
+ ];
+ } else {
+ var requiredContentTypes = _.uniq(responseItems.map((i) => {return i.content_type})).sort();
+ requiredPermissions = [
+ {
+ name: "stream-items",
+ content_types: requiredContentTypes
+ }
+ ];
+ }
+
+ this.runWithPermissions(component, requiredPermissions, () => {
+
+ this.removePrivatePropertiesFromResponseItems(responseItems, component, {includeUrls: true});
+
+ /*
+ We map the items here because modelManager is what updates the UI. If you were to instead get the items directly,
+ this would update them server side via sync, but would never make its way back to the UI.
+ */
+ var localItems = this.modelManager.mapResponseItemsToLocalModels(responseItems, ModelManager.MappingSourceComponentRetrieved);
+
+ for(var item of localItems) {
+ var responseItem = _.find(responseItems, {uuid: item.uuid});
+ _.merge(item.content, responseItem.content);
+ if(responseItem.clientData) {
+ item.setDomainDataItem(component.url || component.uuid, responseItem.clientData, ClientDataDomain);
+ }
+ item.setDirty(true);
+ }
+
+ this.syncManager.sync((response) => {
+ // Allow handlers to be notified when a save begins and ends, to update the UI
+ var saveMessage = Object.assign({}, message);
+ saveMessage.action = response && response.error ? "save-error" : "save-success";
+ this.replyToMessage(component, message, {error: response.error})
+ this.handleMessage(component, saveMessage);
+ }, null, "handleSaveItemsMessage");
+ });
+ }
+
+ handleCreateItemMessage(component, message) {
+ var requiredPermissions = [
+ {
+ name: "stream-items",
+ content_types: [message.data.item.content_type]
+ }
+ ];
+
+ this.runWithPermissions(component, requiredPermissions, () => {
+ var responseItem = message.data.item;
+ this.removePrivatePropertiesFromResponseItems([responseItem], component);
+ var item = this.modelManager.createItem(responseItem);
+ if(responseItem.clientData) {
+ item.setDomainDataItem(component.url || component.uuid, responseItem.clientData, ClientDataDomain);
+ }
+ this.modelManager.addItem(item);
+ this.modelManager.resolveReferencesForItem(item);
+ item.setDirty(true);
+ this.syncManager.sync("handleCreateItemMessage");
+ this.replyToMessage(component, message, {item: this.jsonForItem(item, component)})
+ });
+ }
+
+ handleDeleteItemsMessage(component, message) {
+ var requiredContentTypes = _.uniq(message.data.items.map((i) => {return i.content_type})).sort();
+ var requiredPermissions = [
+ {
+ name: "stream-items",
+ content_types: requiredContentTypes
+ }
+ ];
+
+ this.runWithPermissions(component, requiredPermissions, () => {
+ var itemsData = message.data.items;
+ var noun = itemsData.length == 1 ? "item" : "items";
+ if(confirm(`Are you sure you want to delete ${itemsData.length} ${noun}?`)) {
+ // Filter for any components and deactivate before deleting
+ for(var itemData of itemsData) {
+ var model = this.modelManager.findItem(itemData.uuid);
+ if(["SN|Component", "SN|Theme"].includes(model.content_type)) {
+ this.deactivateComponent(model, true);
+ }
+ this.modelManager.setItemToBeDeleted(model);
+ }
+
+ this.syncManager.sync("handleDeleteItemsMessage");
+ }
+ });
+ }
+
+ handleRequestPermissionsMessage(component, message) {
+ this.runWithPermissions(component, message.data.permissions, () => {
+ this.replyToMessage(component, message, {approved: true});
+ });
+ }
+
+ handleSetComponentDataMessage(component, message) {
+ // A component setting its own data does not require special permissions
+ this.runWithPermissions(component, [], () => {
+ component.componentData = message.data.componentData;
+ component.setDirty(true);
+ this.syncManager.sync("handleSetComponentDataMessage");
+ });
+ }
+
+ handleToggleComponentMessage(sourceComponent, targetComponent, message) {
+ if(targetComponent.area == "modal") {
+ this.openModalComponent(targetComponent);
+ } else {
+ if(targetComponent.active) {
+ this.deactivateComponent(targetComponent);
+ } else {
+ if(targetComponent.content_type == "SN|Theme") {
+ // Deactive currently active theme
+ var activeTheme = this.getActiveTheme();
+ if(activeTheme) {
+ this.deactivateComponent(activeTheme);
+ }
+ }
+ this.activateComponent(targetComponent);
+ }
+ }
+ }
+
+ handleInstallLocalComponentMessage(sourceComponent, message) {
+ // Only extensions manager has this permission
+ if(!this.nativeExtManager.isSystemExtension(sourceComponent)) {
return;
}
+ let targetComponent = this.modelManager.findItem(message.data.uuid);
+ this.desktopManager.installComponent(targetComponent);
+ }
+
+ runWithPermissions(component, requiredPermissions, runFunction) {
+
if(!component.permissions) {
component.permissions = [];
}
- var acquiredMatchesRequested = angular.toJson(component.permissions.sort()) === angular.toJson(requestedPermissions.sort());
+ var acquiredPermissions = component.permissions;
+ var acquiredMatchesRequired = true;
- if(!acquiredMatchesRequested) {
- this.promptForPermissions(component, requestedPermissions, function(approved){
+ for(var required of requiredPermissions) {
+ var matching = acquiredPermissions.find((candidate) => {
+ var matchesContentTypes = true;
+ if(candidate.content_types && required.content_types) {
+ matchesContentTypes = JSON.stringify(candidate.content_types.sort()) == JSON.stringify(required.content_types.sort());
+ }
+ return candidate.name == required.name && matchesContentTypes;
+ });
+
+ if(!matching) {
+ /* Required permissions can be 1 content type, and requestedPermisisons may send an array of content types.
+ In the case of an array, we can just check to make sure that requiredPermissions content type is found in the array
+ */
+ matching = acquiredPermissions.find((candidate) => {
+ return Array.isArray(candidate.content_types)
+ && Array.isArray(required.content_types)
+ && candidate.content_types.containsPrimitiveSubset(required.content_types);
+ });
+
+ if(!matching) {
+ acquiredMatchesRequired = false;
+ break;
+ }
+ }
+ }
+
+ if(!acquiredMatchesRequired) {
+ this.promptForPermissions(component, requiredPermissions, function(approved){
if(approved) {
runFunction();
}
@@ -393,107 +602,86 @@ class ComponentManager {
}
}
- promptForPermissions(component, requestedPermissions, callback) {
- // since these calls are asyncronous, multiple dialogs may be requested at the same time. We only want to present one and trigger all callbacks based on one modal result
- var existingDialog = _.find(this.permissionDialogs, {component: component});
-
- component.trusted = component.url.startsWith("https://standardnotes.org") || component.url.startsWith("https://extensions.standardnotes.org");
+ promptForPermissions(component, permissions, callback) {
var scope = this.$rootScope.$new(true);
scope.component = component;
- scope.permissions = requestedPermissions;
+ scope.permissions = permissions;
scope.actionBlock = callback;
scope.callback = function(approved) {
if(approved) {
- component.permissions = requestedPermissions;
- component.setDirty(true);
- this.syncManager.sync();
- }
-
- for(var existing of this.permissionDialogs) {
- if(existing.component === component && existing.actionBlock) {
- existing.actionBlock(approved);
+ for(var permission of permissions) {
+ if(!component.permissions.includes(permission)) {
+ component.permissions.push(permission);
+ }
}
+ component.setDirty(true);
+ this.syncManager.sync("promptForPermissions");
}
- this.permissionDialogs = this.permissionDialogs.filter(function(dialog){
- return dialog.component !== component;
+ this.permissionDialogs = this.permissionDialogs.filter((pendingDialog) => {
+ // Remove self
+ if(pendingDialog == scope) {
+ pendingDialog.actionBlock && pendingDialog.actionBlock(approved);
+ return false;
+ }
+
+ if(pendingDialog.component == component) {
+ // remove pending dialogs that are encapsulated by already approved permissions, and run its function
+ if(pendingDialog.permissions == permissions || permissions.containsObjectSubset(pendingDialog.permissions)) {
+ // If approved, run the action block. Otherwise, if canceled, cancel any pending ones as well, since the user was
+ // explicit in their intentions
+ if(approved) {
+ pendingDialog.actionBlock && pendingDialog.actionBlock(approved);
+ }
+ return false;
+ }
+ }
+ return true;
})
+ if(this.permissionDialogs.length > 0) {
+ this.presentDialog(this.permissionDialogs[0]);
+ }
+
}.bind(this);
+ // since these calls are asyncronous, multiple dialogs may be requested at the same time. We only want to present one and trigger all callbacks based on one modal result
+ var existingDialog = _.find(this.permissionDialogs, {component: component});
+
this.permissionDialogs.push(scope);
if(!existingDialog) {
- var el = this.$compile( "" )(scope);
- angular.element(document.body).append(el);
+ this.presentDialog(scope);
} else {
console.log("Existing dialog, not presenting.");
}
}
- replyToMessage(component, originalMessage, replyData) {
- var reply = {
- action: "reply",
- original: originalMessage,
- data: replyData
- }
-
- this.sendMessageToComponent(component, reply);
+ presentDialog(dialog) {
+ var permissions = dialog.permissions;
+ var component = dialog.component;
+ var callback = dialog.callback;
+ var el = this.$compile( "" )(dialog);
+ angular.element(document.body).append(el);
}
- sendMessageToComponent(component, message) {
- if(component.ignoreEvents && message.action !== "component-registered") {
- if(this.loggingEnabled) {
- console.log("Component disabled for current item, not sending any messages.", component.name);
- }
- return;
- }
- if(this.loggingEnabled) {
- console.log("Web|sendMessageToComponent", component, message);
- }
- component.window.postMessage(message, "*");
- }
-
- installComponent(url) {
- var name = getParameterByName("name", url);
- var area = getParameterByName("area", url);
- var component = this.modelManager.createItem({
- content_type: "SN|Component",
- url: url,
- name: name,
- area: area
- })
-
- this.modelManager.addItem(component);
- component.setDirty(true);
- this.syncManager.sync();
- }
-
- activateComponent(component) {
- var didChange = component.active != true;
-
- component.active = true;
- for(var handler of this.handlers) {
- if(handler.areas.includes(component.area)) {
- handler.activationHandler(component);
- }
- }
-
- if(didChange) {
- component.setDirty(true);
- this.syncManager.sync();
- }
-
- if(!this.activeComponents.includes(component)) {
- this.activeComponents.push(component);
- }
+ openModalComponent(component) {
+ var scope = this.$rootScope.$new(true);
+ scope.component = component;
+ var el = this.$compile( "" )(scope);
+ angular.element(document.body).append(el);
}
registerHandler(handler) {
this.handlers.push(handler);
}
+ deregisterHandler(identifier) {
+ var handler = _.find(this.handlers, {identifier: identifier});
+ this.handlers.splice(this.handlers.indexOf(handler), 1);
+ }
+
// Called by other views when the iframe is ready
registerComponentWindow(component, componentWindow) {
if(component.window === componentWindow) {
@@ -507,24 +695,56 @@ class ComponentManager {
}
component.window = componentWindow;
component.sessionKey = Neeto.crypto.generateUUID();
- this.sendMessageToComponent(component, {action: "component-registered", sessionKey: component.sessionKey, componentData: component.componentData});
- this.postThemeToComponent(component);
+ this.sendMessageToComponent(component, {
+ action: "component-registered",
+ sessionKey: component.sessionKey,
+ componentData: component.componentData,
+ data: {
+ uuid: component.uuid,
+ environment: isDesktopApplication() ? "desktop" : "web"
+ }
+ });
+ this.postActiveThemeToComponent(component);
}
- deactivateComponent(component) {
+ activateComponent(component, dontSync = false) {
+ var didChange = component.active != true;
+
+ component.active = true;
+ for(var handler of this.handlers) {
+ if(handler.areas.includes(component.area) || handler.areas.includes("*")) {
+ handler.activationHandler(component);
+ }
+ }
+
+ if(didChange && !dontSync) {
+ component.setDirty(true);
+ this.syncManager.sync("activateComponent");
+ }
+
+ if(!this.activeComponents.includes(component)) {
+ this.activeComponents.push(component);
+ }
+
+ if(component.area == "themes") {
+ this.postActiveThemeToAllComponents();
+ }
+ }
+
+ deactivateComponent(component, dontSync = false) {
var didChange = component.active != false;
component.active = false;
component.sessionKey = null;
for(var handler of this.handlers) {
- if(handler.areas.includes(component.area)) {
+ if(handler.areas.includes(component.area) || handler.areas.includes("*")) {
handler.activationHandler(component);
}
}
- if(didChange) {
+ if(didChange && !dontSync) {
component.setDirty(true);
- this.syncManager.sync();
+ this.syncManager.sync("deactivateComponent");
}
_.pull(this.activeComponents, component);
@@ -536,57 +756,23 @@ class ComponentManager {
this.contextStreamObservers = this.contextStreamObservers.filter(function(o){
return o.component !== component;
})
+
+ if(component.area == "themes") {
+ this.postActiveThemeToAllComponents();
+ }
}
deleteComponent(component) {
this.modelManager.setItemToBeDeleted(component);
- this.syncManager.sync();
+ this.syncManager.sync("deleteComponent");
}
isComponentActive(component) {
return component.active;
}
- disassociateComponentWithItem(component, item) {
- _.pull(component.associatedItemIds, item.uuid);
-
- if(component.disassociatedItemIds.indexOf(item.uuid) !== -1) {
- return;
- }
-
- component.disassociatedItemIds.push(item.uuid);
-
- component.setDirty(true);
- this.syncManager.sync();
- }
-
- associateComponentWithItem(component, item) {
- _.pull(component.disassociatedItemIds, item.uuid);
-
- if(component.associatedItemIds.includes(item.uuid)) {
- return;
- }
-
- component.associatedItemIds.push(item.uuid);
-
- component.setDirty(true);
- this.syncManager.sync();
- }
-
- enableComponentsForItem(components, item) {
- for(var component of components) {
- _.pull(component.disassociatedItemIds, item.uuid);
- component.setDirty(true);
- }
- this.syncManager.sync();
- }
-
- setEventFlowForComponent(component, on) {
- component.ignoreEvents = !on;
- }
-
iframeForComponent(component) {
- for(var frame of document.getElementsByTagName("iframe")) {
+ for(var frame of Array.from(document.getElementsByTagName("iframe"))) {
var componentId = frame.dataset.componentId;
if(componentId === component.uuid) {
return frame;
@@ -594,7 +780,40 @@ class ComponentManager {
}
}
+ focusChangedForComponent(component) {
+ let focused = document.activeElement == this.iframeForComponent(component);
+ for(var handler of this.handlers) {
+ // Notify all handlers, and not just ones that match this component type
+ handler.focusHandler && handler.focusHandler(component, focused);
+ }
+ }
+
+ handleSetSizeEvent(component, data) {
+ var setSize = function(element, size) {
+ var widthString = typeof size.width === 'string' ? size.width : `${data.width}px`;
+ var heightString = typeof size.height === 'string' ? size.height : `${data.height}px`;
+ element.setAttribute("style", `width:${widthString}; height:${heightString}; `);
+ }
+
+ if(data.type === "content") {
+ var iframe = this.iframeForComponent(component);
+ var width = data.width;
+ var height = data.height;
+ iframe.width = width;
+ iframe.height = height;
+
+ setSize(iframe, data);
+ } else {
+ var container = document.getElementById("component-" + component.uuid);
+ if(container) {
+ // in the case of Modals, sometimes they may be "active" because they were so in another session,
+ // but no longer actually visible. So check to make sure the container exists
+ setSize(container, data);
+ }
+ }
+ }
+
}
-angular.module('app.frontend').service('componentManager', ComponentManager);
+angular.module('app').service('componentManager', ComponentManager);
diff --git a/app/assets/javascripts/app/services/dbManager.js b/app/assets/javascripts/app/services/dbManager.js
index 4c5d0341e..521fe2a1e 100644
--- a/app/assets/javascripts/app/services/dbManager.js
+++ b/app/assets/javascripts/app/services/dbManager.js
@@ -158,4 +158,4 @@ class DBManager {
}
}
-angular.module('app.frontend').service('dbManager', DBManager);
+angular.module('app').service('dbManager', DBManager);
diff --git a/app/assets/javascripts/app/services/desktopManager.js b/app/assets/javascripts/app/services/desktopManager.js
index 1cb28506c..3044e6da2 100644
--- a/app/assets/javascripts/app/services/desktopManager.js
+++ b/app/assets/javascripts/app/services/desktopManager.js
@@ -2,11 +2,16 @@
class DesktopManager {
- constructor($rootScope, modelManager, authManager, passcodeManager) {
+ constructor($rootScope, $timeout, modelManager, syncManager, authManager, passcodeManager) {
this.passcodeManager = passcodeManager;
this.modelManager = modelManager;
this.authManager = authManager;
+ this.syncManager = syncManager;
this.$rootScope = $rootScope;
+ this.timeout = $timeout;
+ this.updateObservers = [];
+
+ this.isDesktop = isDesktopApplication();
$rootScope.$on("initial-data-loaded", () => {
this.dataLoaded = true;
@@ -22,6 +27,84 @@ class DesktopManager {
})
}
+ getApplicationDataPath() {
+ console.assert(this.applicationDataPath, "applicationDataPath is null");
+ return this.applicationDataPath;
+ }
+
+ /* Sending a component in its raw state is really slow for the desktop app */
+ convertComponentForTransmission(component) {
+ return new ItemParams(component).paramsForExportFile(true);
+ }
+
+ // All `components` should be installed
+ syncComponentsInstallation(components) {
+ if(!this.isDesktop) return;
+
+ var data = components.map((component) => {
+ return this.convertComponentForTransmission(component);
+ })
+ this.installationSyncHandler(data);
+ }
+
+ installComponent(component) {
+ this.installComponentHandler(this.convertComponentForTransmission(component));
+ }
+
+ registerUpdateObserver(callback) {
+ var observer = {id: Math.random, callback: callback};
+ this.updateObservers.push(observer);
+ return observer;
+ }
+
+ deregisterUpdateObserver(observer) {
+ _.pull(this.updateObservers, observer);
+ }
+
+ desktop_onComponentInstallationComplete(componentData, error) {
+ console.log("Web|Component Installation/Update Complete", componentData, error);
+
+ // Desktop is only allowed to change these keys:
+ let permissableKeys = ["package_info", "local_url"];
+ var component = this.modelManager.findItem(componentData.uuid);
+
+ if(!component) {
+ console.error("desktop_onComponentInstallationComplete component is null for uuid", componentData.uuid);
+ return;
+ }
+
+ if(error) {
+ component.setAppDataItem("installError", error);
+ } else {
+ for(var key of permissableKeys) {
+ component[key] = componentData.content[key];
+ }
+ this.modelManager.notifySyncObserversOfModels([component], ModelManager.MappingSourceDesktopInstalled);
+ component.setAppDataItem("installError", null);
+ }
+ component.setDirty(true);
+ this.syncManager.sync("onComponentInstallationComplete");
+
+ this.timeout(() => {
+ for(var observer of this.updateObservers) {
+ observer.callback(component);
+ }
+ })
+ }
+
+ /* Used to resolve "sn://" */
+ desktop_setApplicationDataPath(path) {
+ this.applicationDataPath = path;
+ }
+
+ desktop_setComponentInstallationSyncHandler(handler) {
+ this.installationSyncHandler = handler;
+ }
+
+ desktop_setInstallComponentHandler(handler) {
+ this.installComponentHandler = handler;
+ }
+
desktop_setInitialDataLoadHandler(handler) {
this.dataLoadHandler = handler;
if(this.dataLoaded) {
@@ -56,4 +139,4 @@ class DesktopManager {
}
-angular.module('app.frontend').service('desktopManager', DesktopManager);
+angular.module('app').service('desktopManager', DesktopManager);
diff --git a/app/assets/javascripts/app/services/directives/views/contextualExtensionsMenu.js b/app/assets/javascripts/app/services/directives/views/contextualExtensionsMenu.js
deleted file mode 100644
index 3825aed6e..000000000
--- a/app/assets/javascripts/app/services/directives/views/contextualExtensionsMenu.js
+++ /dev/null
@@ -1,86 +0,0 @@
-class ContextualExtensionsMenu {
-
- constructor() {
- this.restrict = "E";
- this.templateUrl = "frontend/directives/contextual-menu.html";
- this.scope = {
- item: "="
- };
- }
-
- controller($scope, modelManager, extensionManager) {
- 'ngInject';
-
- $scope.renderData = {};
-
- $scope.extensions = _.map(extensionManager.extensionsInContextOfItem($scope.item), function(ext){
- // why are we cloning deep? commenting out because we want original reference so that extension.hide is saved between menu opens
- // return _.cloneDeep(ext);
- return ext;
- });
-
- for(let ext of $scope.extensions) {
- ext.loading = true;
- extensionManager.loadExtensionInContextOfItem(ext, $scope.item, function(scopedExtension) {
- ext.loading = false;
- })
- }
-
- $scope.executeAction = function(action, extension, parentAction) {
- if(!$scope.isActionEnabled(action, extension)) {
- alert("This action requires " + action.access_type + " access to this note. You can change this setting in the Extensions menu on the bottom of the app.");
- return;
- }
- if(action.verb == "nested") {
- action.showNestedActions = !action.showNestedActions;
- return;
- }
- action.running = true;
- extensionManager.executeAction(action, extension, $scope.item, function(response){
- action.running = false;
- $scope.handleActionResponse(action, response);
-
- // reload extension actions
- extensionManager.loadExtensionInContextOfItem(extension, $scope.item, function(ext){
- // keep nested state
- if(parentAction) {
- var matchingAction = _.find(ext.actions, {label: parentAction.label});
- matchingAction.showNestedActions = true;
- }
- });
- })
- }
-
- $scope.handleActionResponse = function(action, response) {
- switch (action.verb) {
- case "render": {
- var item = response.item;
- if(item.content_type == "Note") {
- $scope.renderData.title = item.title;
- $scope.renderData.text = item.text;
- $scope.renderData.showRenderModal = true;
- }
- }
- }
- }
-
- $scope.isActionEnabled = function(action, extension) {
- if(action.access_type) {
- var extEncryptedAccess = extension.encrypted;
- if(action.access_type == "decrypted" && extEncryptedAccess) {
- return false;
- } else if(action.access_type == "encrypted" && !extEncryptedAccess) {
- return false;
- }
- }
- return true;
- }
-
- $scope.accessTypeForExtension = function(extension) {
- return extension.encrypted ? "encrypted" : "decrypted";
- }
- }
-
-}
-
-angular.module('app.frontend').directive('contextualExtensionsMenu', () => new ContextualExtensionsMenu);
diff --git a/app/assets/javascripts/app/services/directives/views/editorMenu.js b/app/assets/javascripts/app/services/directives/views/editorMenu.js
deleted file mode 100644
index 008c5fadc..000000000
--- a/app/assets/javascripts/app/services/directives/views/editorMenu.js
+++ /dev/null
@@ -1,30 +0,0 @@
-class EditorMenu {
-
- constructor() {
- this.restrict = "E";
- this.templateUrl = "frontend/directives/editor-menu.html";
- this.scope = {
- callback: "&",
- selectedEditor: "="
- };
- }
-
- controller($scope, componentManager) {
- 'ngInject';
-
- $scope.formData = {};
-
- $scope.editors = componentManager.componentsForArea("editor-editor");
-
- $scope.selectEditor = function($event, editor) {
- if(editor) {
- editor.conflict_of = null; // clear conflict if applicable
- }
- $scope.callback()(editor);
- }
-
- }
-
-}
-
-angular.module('app.frontend').directive('editorMenu', () => new EditorMenu);
diff --git a/app/assets/javascripts/app/services/directives/views/globalExtensionsMenu.js b/app/assets/javascripts/app/services/directives/views/globalExtensionsMenu.js
deleted file mode 100644
index f046d48d5..000000000
--- a/app/assets/javascripts/app/services/directives/views/globalExtensionsMenu.js
+++ /dev/null
@@ -1,225 +0,0 @@
-class GlobalExtensionsMenu {
-
- constructor() {
- this.restrict = "E";
- this.templateUrl = "frontend/directives/global-extensions-menu.html";
- this.scope = {
- };
- }
-
- controller($scope, extensionManager, syncManager, modelManager, themeManager, componentManager) {
- 'ngInject';
-
- $scope.formData = {};
-
- $scope.extensionManager = extensionManager;
- $scope.themeManager = themeManager;
- $scope.componentManager = componentManager;
-
- $scope.serverExtensions = modelManager.itemsForContentType("SF|Extension");
-
- $scope.selectedAction = function(action, extension) {
- extensionManager.executeAction(action, extension, null, function(response){
- if(response && response.error) {
- action.error = true;
- alert("There was an error performing this action. Please try again.");
- } else {
- action.error = false;
- syncManager.sync(null);
- }
- })
- }
-
- $scope.changeExtensionEncryptionFormat = function(encrypted, extension) {
- extension.encrypted = encrypted;
- extension.setDirty(true);
- syncManager.sync();
- }
-
- $scope.deleteActionExtension = function(extension) {
- if(confirm("Are you sure you want to delete this extension?")) {
- extensionManager.deleteExtension(extension);
- }
- }
-
- $scope.reloadExtensionsPressed = function() {
- if(confirm("For your security, reloading extensions will disable any currently enabled repeat actions.")) {
- extensionManager.refreshExtensionsFromServer();
- }
- }
-
- $scope.deleteTheme = function(theme) {
- if(confirm("Are you sure you want to delete this theme?")) {
- themeManager.deactivateTheme(theme);
- modelManager.setItemToBeDeleted(theme);
- syncManager.sync();
- }
- }
-
- $scope.renameExtension = function(extension) {
- extension.tempName = extension.name;
- extension.rename = true;
- }
-
- $scope.submitExtensionRename = function(extension) {
- extension.name = extension.tempName;
- extension.tempName = null;
- extension.setDirty(true);
- extension.rename = false;
- syncManager.sync();
- }
-
- $scope.clickedExtension = function(extension) {
- if(extension.rename) {
- return;
- }
-
- if($scope.currentlyExpandedExtension && $scope.currentlyExpandedExtension !== extension) {
- $scope.currentlyExpandedExtension.showDetails = false;
- $scope.currentlyExpandedExtension.rename = false;
- }
-
- extension.showDetails = !extension.showDetails;
-
- if(extension.showDetails) {
- $scope.currentlyExpandedExtension = extension;
- }
- }
-
- // Server extensions
-
- $scope.deleteServerExt = function(ext) {
- if(confirm("Are you sure you want to delete and disable this extension?")) {
- _.remove($scope.serverExtensions, {uuid: ext.uuid});
- modelManager.setItemToBeDeleted(ext);
- syncManager.sync();
- }
- }
-
- $scope.nameForServerExtension = function(ext) {
- var url = ext.url;
- if(!url) {
- return "Invalid Extension";
- }
- if(url.includes("gdrive")) {
- return "Google Drive Sync";
- } else if(url.includes("file_attacher")) {
- return "File Attacher";
- } else if(url.includes("onedrive")) {
- return "OneDrive Sync";
- } else if(url.includes("backup.email_archive")) {
- return "Daily Email Backups";
- } else if(url.includes("dropbox")) {
- return "Dropbox Sync";
- } else if(url.includes("revisions")) {
- return "Revision History";
- } else {
- return null;
- }
- }
-
-
- // Components
-
- $scope.revokePermissions = function(component) {
- component.permissions = [];
- component.setDirty(true);
- syncManager.sync();
- }
-
- $scope.deleteComponent = function(component) {
- if(confirm("Are you sure you want to delete this component?")) {
- componentManager.deleteComponent(component);
- }
- }
-
- $scope.makeEditorDefault = function(component) {
- var currentDefault = componentManager.componentsForArea("editor-editor").filter((e) => {return e.isDefaultEditor()})[0];
- if(currentDefault) {
- currentDefault.setAppDataItem("defaultEditor", false);
- currentDefault.setDirty(true);
- }
- component.setAppDataItem("defaultEditor", true);
- component.setDirty(true);
- syncManager.sync();
- }
-
- $scope.removeEditorDefault = function(component) {
- component.setAppDataItem("defaultEditor", false);
- component.setDirty(true);
- syncManager.sync();
- }
-
- // Installation
-
- $scope.submitInstallLink = function() {
-
- var fullLink = $scope.formData.installLink;
- if(!fullLink) {
- return;
- }
-
- var completion = function() {
- $scope.formData.installLink = "";
- $scope.formData.successfullyInstalled = true;
- }
-
- var links = fullLink.split(",");
- for(var link of links) {
- var type = getParameterByName("type", link);
-
- if(type == "sf") {
- $scope.handleSyncAdapterLink(link, completion);
- } else if(type == "editor") {
- $scope.handleEditorLink(link, completion);
- } else if(link.indexOf(".css") != -1 || type == "theme") {
- $scope.handleThemeLink(link, completion);
- } else if(type == "component") {
- $scope.handleComponentLink(link, completion);
- }
-
- else {
- $scope.handleActionLink(link, completion);
- }
- }
- }
-
- $scope.handleSyncAdapterLink = function(link, completion) {
- var params = parametersFromURL(link);
- params["url"] = link;
- var ext = new SyncAdapter({content: params});
- ext.setDirty(true);
-
- modelManager.addItem(ext);
- syncManager.sync();
- $scope.serverExtensions.push(ext);
- completion();
- }
-
- $scope.handleThemeLink = function(link, completion) {
- themeManager.submitTheme(link);
- completion();
- }
-
- $scope.handleComponentLink = function(link, completion) {
- componentManager.installComponent(link);
- completion();
- }
-
- $scope.handleActionLink = function(link, completion) {
- if(link) {
- extensionManager.addExtension(link, function(response){
- if(!response) {
- alert("Unable to register this extension. Make sure the link is valid and try again.");
- } else {
- completion();
- }
- })
- }
- }
-
- }
-
-}
-
-angular.module('app.frontend').directive('globalExtensionsMenu', () => new GlobalExtensionsMenu);
diff --git a/app/assets/javascripts/app/services/directives/views/permissionsModal.js b/app/assets/javascripts/app/services/directives/views/permissionsModal.js
deleted file mode 100644
index e2a1f0a07..000000000
--- a/app/assets/javascripts/app/services/directives/views/permissionsModal.js
+++ /dev/null
@@ -1,70 +0,0 @@
-class PermissionsModal {
-
- constructor() {
- this.restrict = "E";
- this.templateUrl = "frontend/directives/permissions-modal.html";
- this.scope = {
- show: "=",
- component: "=",
- permissions: "=",
- callback: "="
- };
- }
-
- link($scope, el, attrs) {
-
- $scope.dismiss = function() {
- el.remove();
- }
-
- $scope.accept = function() {
- $scope.callback(true);
- $scope.dismiss();
- }
-
- $scope.deny = function() {
- $scope.callback(false);
- $scope.dismiss();
- }
-
- $scope.formattedPermissions = $scope.permissions.map(function(permission){
- if(permission.name === "stream-items") {
- var title = "Access to ";
- var types = permission.content_types.map(function(type){
- return (type + "s").toLowerCase();
- })
- var typesString = "";
- var separator = ", ";
-
- for(var i = 0;i < types.length;i++) {
- var type = types[i];
- if(i == 0) {
- // first element
- typesString = typesString + type;
- } else if(i == types.length - 1) {
- // last element
- if(types.length > 2) {
- typesString += separator + "and " + typesString;
- } else if(types.length == 2) {
- typesString = typesString + " and " + type;
- }
- } else {
- typesString += separator + type;
- }
- }
-
- return title + typesString;
- } else if(permission.name === "stream-context-item") {
- var mapping = {
- "editor-stack" : "working note",
- "note-tags" : "working note",
- "editor-editor": "working note"
- }
- return "Access to " + mapping[$scope.component.area];
- }
- })
- }
-
-}
-
-angular.module('app.frontend').directive('permissionsModal', () => new PermissionsModal);
diff --git a/app/assets/javascripts/app/services/extensionManager.js b/app/assets/javascripts/app/services/extensionManager.js
deleted file mode 100644
index ff7b66cd1..000000000
--- a/app/assets/javascripts/app/services/extensionManager.js
+++ /dev/null
@@ -1,337 +0,0 @@
-class ExtensionManager {
-
- constructor(httpManager, modelManager, authManager, syncManager, storageManager) {
- this.httpManager = httpManager;
- this.modelManager = modelManager;
- this.authManager = authManager;
- this.enabledRepeatActionUrls = JSON.parse(storageManager.getItem("enabledRepeatActionUrls")) || [];
- this.syncManager = syncManager;
- this.storageManager = storageManager;
-
- modelManager.addItemSyncObserver("extensionManager", "Extension", function(allItems, validItems, deletedItems){
- for (var ext of validItems) {
- for (var action of ext.actions) {
- if(_.includes(this.enabledRepeatActionUrls, action.url)) {
- this.enableRepeatAction(action, ext);
- }
- }
- }
- }.bind(this))
- }
-
- get extensions() {
- return this.modelManager.extensions;
- }
-
- extensionsInContextOfItem(item) {
- return this.extensions.filter(function(ext){
- return _.includes(ext.supported_types, item.content_type) || ext.actionsWithContextForItem(item).length > 0;
- })
- }
-
- actionWithURL(url) {
- for (var extension of this.extensions) {
- return _.find(extension.actions, {url: url})
- }
- }
-
- addExtension(url, callback) {
- this.retrieveExtensionFromServer(url, callback);
- }
-
- deleteExtension(extension) {
- for(var action of extension.actions) {
- if(action.repeat_mode) {
- if(this.isRepeatActionEnabled(action)) {
- this.disableRepeatAction(action);
- }
- }
- }
-
- this.modelManager.setItemToBeDeleted(extension);
- this.syncManager.sync(null);
- }
-
- /*
- Loads an extension in the context of a certain item. The server then has the chance to respond with actions that are
- relevant just to this item. The response extension is not saved, just displayed as a one-time thing.
- */
- loadExtensionInContextOfItem(extension, item, callback) {
-
- this.httpManager.getAbsolute(extension.url, {content_type: item.content_type, item_uuid: item.uuid}, function(response){
- this.updateExtensionFromRemoteResponse(extension, response);
- callback && callback(extension);
- }.bind(this), function(response){
- console.log("Error loading extension", response);
- if(callback) {
- callback(null);
- }
- }.bind(this))
- }
-
- /*
- Registers new extension and saves it to user's account
- */
- retrieveExtensionFromServer(url, callback) {
- this.httpManager.getAbsolute(url, {}, function(response){
- if(typeof response !== 'object') {
- callback(null);
- return;
- }
- var ext = this.handleExtensionLoadExternalResponseItem(url, response);
- if(callback) {
- callback(ext);
- }
- }.bind(this), function(response){
- console.error("Error registering extension", response);
- callback(null);
- })
- }
-
- handleExtensionLoadExternalResponseItem(url, externalResponseItem) {
- // Don't allow remote response to set these flags
- delete externalResponseItem.encrypted;
- delete externalResponseItem.uuid;
-
- var extension = _.find(this.extensions, {url: url});
- if(extension) {
- this.updateExtensionFromRemoteResponse(extension, externalResponseItem);
- } else {
- extension = new Extension(externalResponseItem);
- extension.url = url;
- extension.setDirty(true);
- this.modelManager.addItem(extension);
- this.syncManager.sync(null);
- }
-
- return extension;
- }
-
- updateExtensionFromRemoteResponse(extension, response) {
- if(response.description) {
- extension.description = response.description;
- }
- if(response.supported_types) {
- extension.supported_types = response.supported_types;
- }
-
- if(response.actions) {
- extension.actions = response.actions.map(function(action){
- return new Action(action);
- })
- } else {
- extension.actions = [];
- }
- }
-
- refreshExtensionsFromServer() {
- for (var url of this.enabledRepeatActionUrls) {
- var action = this.actionWithURL(url);
- if(action) {
- this.disableRepeatAction(action);
- }
- }
-
- for(var ext of this.extensions) {
- this.retrieveExtensionFromServer(ext.url, function(extension){
- extension.setDirty(true);
- });
- }
- }
-
- executeAction(action, extension, item, callback) {
-
- if(extension.encrypted && this.authManager.offline()) {
- alert("To send data encrypted, you must have an encryption key, and must therefore be signed in.");
- callback(null);
- return;
- }
-
- var customCallback = function(response) {
- action.running = false;
- callback(response);
- }
-
- action.running = true;
-
- switch (action.verb) {
- case "get": {
-
- this.httpManager.getAbsolute(action.url, {}, function(response){
- action.error = false;
- var items = response.items || [response.item];
- EncryptionHelper.decryptMultipleItems(items, this.authManager.keys());
- items = this.modelManager.mapResponseItemsToLocalModels(items, ModelManager.MappingSourceRemoteActionRetrieved);
- for(var item of items) {
- item.setDirty(true);
- }
- this.syncManager.sync(null);
- customCallback({items: items});
- }.bind(this), function(response){
- action.error = true;
- customCallback(null);
- })
-
- break;
- }
-
- case "render": {
-
- this.httpManager.getAbsolute(action.url, {}, function(response){
- action.error = false;
- EncryptionHelper.decryptItem(response.item, this.authManager.keys());
- var item = this.modelManager.createItem(response.item);
- customCallback({item: item});
-
- }.bind(this), function(response){
- action.error = true;
- customCallback(null);
- })
-
- break;
- }
-
- case "show": {
- var win = window.open(action.url, '_blank');
- win.focus();
- customCallback();
- break;
- }
-
- case "post": {
- var params = {};
-
- if(action.all) {
- var items = this.modelManager.allItemsMatchingTypes(action.content_types);
- params.items = items.map(function(item){
- var params = this.outgoingParamsForItem(item, extension);
- return params;
- }.bind(this))
-
- } else {
- params.items = [this.outgoingParamsForItem(item, extension)];
- }
-
- this.performPost(action, extension, params, function(response){
- customCallback(response);
- });
-
- break;
- }
-
- default: {
-
- }
- }
-
- action.lastExecuted = new Date();
- }
-
- isRepeatActionEnabled(action) {
- return _.includes(this.enabledRepeatActionUrls, action.url);
- }
-
- disableRepeatAction(action, extension) {
- _.pull(this.enabledRepeatActionUrls, action.url);
- this.storageManager.setItem("enabledRepeatActionUrls", JSON.stringify(this.enabledRepeatActionUrls));
- this.modelManager.removeItemChangeObserver(action.url);
-
- console.assert(this.isRepeatActionEnabled(action) == false);
- }
-
- enableRepeatAction(action, extension) {
- if(!_.find(this.enabledRepeatActionUrls, action.url)) {
- this.enabledRepeatActionUrls.push(action.url);
- this.storageManager.setItem("enabledRepeatActionUrls", JSON.stringify(this.enabledRepeatActionUrls));
- }
-
- if(action.repeat_mode) {
-
- if(action.repeat_mode == "watch") {
- this.modelManager.addItemChangeObserver(action.url, action.content_types, function(changedItems){
- this.triggerWatchAction(action, extension, changedItems);
- }.bind(this))
- }
-
- if(action.repeat_mode == "loop") {
- // todo
- }
-
- }
- }
-
- queueAction(action, extension, delay, changedItems) {
- this.actionQueue = this.actionQueue || [];
- if(_.find(this.actionQueue, {url: action.url})) {
- return;
- }
-
- this.actionQueue.push(action);
-
- setTimeout(function () {
- this.triggerWatchAction(action, extension, changedItems);
- _.pull(this.actionQueue, action);
- }.bind(this), delay * 1000);
- }
-
- triggerWatchAction(action, extension, changedItems) {
- if(action.repeat_timeout > 0) {
- var lastExecuted = action.lastExecuted;
- var diffInSeconds = (new Date() - lastExecuted)/1000;
- if(diffInSeconds < action.repeat_timeout) {
- var delay = action.repeat_timeout - diffInSeconds;
- this.queueAction(action, extension, delay, changedItems);
- return;
- }
- }
-
- action.lastExecuted = new Date();
-
- if(action.verb == "post") {
- var params = {};
- params.items = changedItems.map(function(item){
- var params = this.outgoingParamsForItem(item, extension);
- return params;
- }.bind(this))
-
- action.running = true;
- this.performPost(action, extension, params, function(){
- action.running = false;
- });
- } else {
- // todo
- }
- }
-
- outgoingParamsForItem(item, extension) {
- var keys = this.authManager.keys();
- if(!extension.encrypted) {
- keys = null;
- }
- var itemParams = new ItemParams(item, keys, this.authManager.protocolVersion());
- return itemParams.paramsForExtension();
- }
-
- performPost(action, extension, params, callback) {
-
- if(extension.encrypted) {
- params.auth_params = this.authManager.getAuthParams();
- }
-
- this.httpManager.postAbsolute(action.url, params, function(response){
- action.error = false;
- if(callback) {
- callback(response);
- }
- }.bind(this), function(response){
- action.error = true;
- console.log("Action error response:", response);
- if(callback) {
- callback({error: "Request error"});
- }
- })
- }
-
-}
-
-angular.module('app.frontend').service('extensionManager', ExtensionManager);
diff --git a/app/assets/javascripts/app/services/httpManager.js b/app/assets/javascripts/app/services/httpManager.js
index a5d157d57..71692f478 100644
--- a/app/assets/javascripts/app/services/httpManager.js
+++ b/app/assets/javascripts/app/services/httpManager.js
@@ -77,4 +77,4 @@ class HttpManager {
}
-angular.module('app.frontend').service('httpManager', HttpManager);
+angular.module('app').service('httpManager', HttpManager);
diff --git a/app/assets/javascripts/app/services/migrationManager.js b/app/assets/javascripts/app/services/migrationManager.js
index bb139860c..9fec09d65 100644
--- a/app/assets/javascripts/app/services/migrationManager.js
+++ b/app/assets/javascripts/app/services/migrationManager.js
@@ -50,7 +50,7 @@ class MigrationManager {
this.modelManager.setItemToBeDeleted(editor);
}
- this.syncManager.sync();
+ this.syncManager.sync("addEditorToComponentMigrator");
}
})
}
@@ -58,4 +58,4 @@ class MigrationManager {
}
-angular.module('app.frontend').service('migrationManager', MigrationManager);
+angular.module('app').service('migrationManager', MigrationManager);
diff --git a/app/assets/javascripts/app/services/modelManager.js b/app/assets/javascripts/app/services/modelManager.js
index 43cdbe11c..112d1da02 100644
--- a/app/assets/javascripts/app/services/modelManager.js
+++ b/app/assets/javascripts/app/services/modelManager.js
@@ -3,8 +3,10 @@ class ModelManager {
constructor(storageManager) {
ModelManager.MappingSourceRemoteRetrieved = "MappingSourceRemoteRetrieved";
ModelManager.MappingSourceRemoteSaved = "MappingSourceRemoteSaved";
+ ModelManager.MappingSourceLocalSaved = "MappingSourceLocalSaved";
ModelManager.MappingSourceLocalRetrieved = "MappingSourceLocalRetrieved";
ModelManager.MappingSourceComponentRetrieved = "MappingSourceComponentRetrieved";
+ ModelManager.MappingSourceDesktopInstalled = "MappingSourceDesktopInstalled"; // When a component is installed by the desktop and some of its values change
ModelManager.MappingSourceRemoteActionRetrieved = "MappingSourceRemoteActionRetrieved"; /* aciton-based Extensions like note history */
ModelManager.MappingSourceFileImport = "MappingSourceFileImport";
@@ -18,7 +20,7 @@ class ModelManager {
this._extensions = [];
this.acceptableContentTypes = [
"Note", "Tag", "Extension", "SN|Editor", "SN|Theme",
- "SN|Component", "SF|Extension", "SN|UserPreferences"
+ "SN|Component", "SF|Extension", "SN|UserPreferences", "SF|MFA"
];
}
@@ -52,6 +54,8 @@ class ModelManager {
this.informModelsOfUUIDChangeForItem(newItem, item.uuid, newItem.uuid);
+ console.log(item.uuid, "-->", newItem.uuid);
+
var block = () => {
this.addItem(newItem);
newItem.setDirty(true);
@@ -60,9 +64,10 @@ class ModelManager {
}
if(removeOriginal) {
- this.removeItemLocally(item, function(){
- block();
- });
+ // Set to deleted, then run through mapping function so that observers can be notified
+ item.deleted = true;
+ this.mapResponseItemsToLocalModels([item], ModelManager.MappingSourceLocalSaved);
+ block();
} else {
block();
}
@@ -79,13 +84,13 @@ class ModelManager {
}
allItemsMatchingTypes(contentTypes) {
- return this.items.filter(function(item){
+ return this.allItems.filter(function(item){
return (_.includes(contentTypes, item.content_type) || _.includes(contentTypes, "*")) && !item.dummy;
})
}
itemsForContentType(contentType) {
- return this.items.filter(function(item){
+ return this.allItems.filter(function(item){
return item.content_type == contentType;
});
}
@@ -103,6 +108,10 @@ class ModelManager {
return tag;
}
+ didSyncModelsOffline(items) {
+ this.notifySyncObserversOfModels(items, ModelManager.MappingSourceLocalSaved);
+ }
+
mapResponseItemsToLocalModels(items, source) {
return this.mapResponseItemsToLocalModelsOmittingFields(items, null, source);
}
@@ -139,7 +148,8 @@ class ModelManager {
continue;
}
- var unknownContentType = !_.includes(this.acceptableContentTypes, json_obj["content_type"]);
+ let contentType = json_obj["content_type"] || (item && item.content_type);
+ var unknownContentType = !_.includes(this.acceptableContentTypes, contentType);
if(json_obj.deleted == true || unknownContentType) {
if(item && !unknownContentType) {
modelsToNotifyObserversOf.push(item);
@@ -149,7 +159,7 @@ class ModelManager {
}
if(!item) {
- item = this.createItem(json_obj);
+ item = this.createItem(json_obj, true);
}
this.addItem(item);
@@ -172,6 +182,7 @@ class ModelManager {
return models;
}
+ /* Note that this function is public, and can also be called manually (desktopManager uses it) */
notifySyncObserversOfModels(models, source) {
for(var observer of this.itemSyncObservers) {
var allRelevantItems = models.filter(function(item){return item.content_type == observer.type || observer.type == "*"});
@@ -202,7 +213,7 @@ class ModelManager {
}
}
- createItem(json_obj) {
+ createItem(json_obj, dontNotifyObservers) {
var item;
if(json_obj.content_type == "Note") {
item = new Note(json_obj);
@@ -217,13 +228,24 @@ class ModelManager {
} else if(json_obj.content_type == "SN|Component") {
item = new Component(json_obj);
} else if(json_obj.content_type == "SF|Extension") {
- item = new SyncAdapter(json_obj);
+ item = new ServerExtension(json_obj);
+ } else if(json_obj.content_type == "SF|MFA") {
+ item = new Mfa(json_obj);
}
else {
item = new Item(json_obj);
}
+ // Some observers would be interested to know when an an item is locally created
+ // If we don't send this out, these observers would have to wait until MappingSourceRemoteSaved
+ // to hear about it, but sometimes, RemoveSaved is explicitly ignored by the observer to avoid
+ // recursive callbacks. See componentManager's syncObserver callback.
+ // dontNotifyObservers is currently only set true by modelManagers mapResponseItemsToLocalModels
+ if(!dontNotifyObservers) {
+ this.notifySyncObserversOfModels([item], ModelManager.MappingSourceLocalSaved);
+ }
+
item.addObserver(this, function(changedItem){
this.notifyItemChangeObserversOfModels([changedItem]);
}.bind(this));
@@ -232,7 +254,7 @@ class ModelManager {
}
createDuplicateItem(itemResponse, sourceItem) {
- var dup = this.createItem(itemResponse);
+ var dup = this.createItem(itemResponse, true);
this.resolveReferencesForItem(dup);
return dup;
}
@@ -405,6 +427,25 @@ class ModelManager {
return JSON.stringify(data, null, 2 /* pretty print */);
}
+
+
+ /*
+ Misc
+ */
+
+ humanReadableDisplayForContentType(contentType) {
+ return {
+ "Note" : "note",
+ "Tag" : "tag",
+ "Extension" : "action-based extension",
+ "SN|Component" : "component",
+ "SN|Editor" : "editor",
+ "SN|Theme" : "theme",
+ "SF|Extension" : "server extension",
+ "SF|MFA" : "two-factor authentication setting"
+ }[contentType];
+ }
+
}
-angular.module('app.frontend').service('modelManager', ModelManager);
+angular.module('app').service('modelManager', ModelManager);
diff --git a/app/assets/javascripts/app/services/nativeExtManager.js b/app/assets/javascripts/app/services/nativeExtManager.js
new file mode 100644
index 000000000..503e3f3b3
--- /dev/null
+++ b/app/assets/javascripts/app/services/nativeExtManager.js
@@ -0,0 +1,92 @@
+/* A class for handling installation of system extensions */
+
+class NativeExtManager {
+
+ constructor(modelManager, syncManager, singletonManager) {
+ this.modelManager = modelManager;
+ this.syncManager = syncManager;
+ this.singletonManager = singletonManager;
+
+ this.extensionsIdentifier = "org.standardnotes.extensions-manager";
+ this.systemExtensions = [];
+
+ this.resolveExtensionsManager();
+ }
+
+ isSystemExtension(extension) {
+ return this.systemExtensions.includes(extension.uuid);
+ }
+
+ resolveExtensionsManager() {
+
+ this.singletonManager.registerSingleton({content_type: "SN|Component", package_info: {identifier: this.extensionsIdentifier}}, (resolvedSingleton) => {
+ // Resolved Singleton
+ this.systemExtensions.push(resolvedSingleton.uuid);
+
+ var needsSync = false;
+ if(isDesktopApplication()) {
+ if(!resolvedSingleton.local_url) {
+ resolvedSingleton.local_url = window._extensions_manager_location;
+ needsSync = true;
+ }
+ } else {
+ if(!resolvedSingleton.hosted_url) {
+ resolvedSingleton.hosted_url = window._extensions_manager_location;
+ needsSync = true;
+ }
+ }
+
+ if(needsSync) {
+ resolvedSingleton.setDirty(true);
+ this.syncManager.sync("resolveExtensionsManager");
+ }
+ }, (valueCallback) => {
+ // Safe to create. Create and return object.
+ let url = window._extensions_manager_location;
+ console.log("Installing Extensions Manager from URL", url);
+ if(!url) {
+ console.error("window._extensions_manager_location must be set.");
+ return;
+ }
+
+ let packageInfo = {
+ name: "Extensions",
+ identifier: this.extensionsIdentifier
+ }
+
+ var item = {
+ content_type: "SN|Component",
+ content: {
+ name: packageInfo.name,
+ area: "rooms",
+ package_info: packageInfo,
+ permissions: [
+ {
+ name: "stream-items",
+ content_types: ["SN|Component", "SN|Theme", "SF|Extension", "Extension", "SF|MFA", "SN|Editor"]
+ }
+ ]
+ }
+ }
+
+ if(isDesktopApplication()) {
+ item.content.local_url = window._extensions_manager_location;
+ } else {
+ item.content.hosted_url = window._extensions_manager_location;
+ }
+
+ var component = this.modelManager.createItem(item);
+ this.modelManager.addItem(component);
+
+ component.setDirty(true);
+ this.syncManager.sync("resolveExtensionsManager createNew");
+
+ this.systemExtensions.push(component.uuid);
+
+ valueCallback(component);
+ });
+ }
+
+}
+
+angular.module('app').service('nativeExtManager', NativeExtManager);
diff --git a/app/assets/javascripts/app/services/passcodeManager.js b/app/assets/javascripts/app/services/passcodeManager.js
index e4862fbe6..a3a65ca86 100644
--- a/app/assets/javascripts/app/services/passcodeManager.js
+++ b/app/assets/javascripts/app/services/passcodeManager.js
@@ -1,4 +1,4 @@
-angular.module('app.frontend')
+angular.module('app')
.provider('passcodeManager', function () {
this.$get = function($rootScope, $timeout, modelManager, dbManager, authManager, storageManager) {
@@ -41,7 +41,7 @@ angular.module('app.frontend')
}.bind(this));
}
- this.setPasscode = function(passcode, callback) {
+ this.setPasscode = (passcode, callback) => {
var cost = Neeto.crypto.defaultPasswordGenerationCost();
var salt = Neeto.crypto.generateRandomKey(512);
var defaultParams = {pw_cost: cost, pw_salt: salt, version: "002"};
@@ -60,6 +60,10 @@ angular.module('app.frontend')
}.bind(this));
}
+ this.changePasscode = (newPasscode, callback) => {
+ this.setPasscode(newPasscode, callback);
+ }
+
this.clearPasscode = function() {
storageManager.setItemsMode(authManager.isEphemeralSession() ? StorageManager.Ephemeral : StorageManager.Fixed); // Transfer from Ephemeral
storageManager.removeItem("offlineParams", StorageManager.Fixed);
@@ -70,7 +74,8 @@ angular.module('app.frontend')
this.encryptLocalStorage = function(keys) {
storageManager.setKeys(keys);
// Switch to Ephemeral storage, wiping Fixed storage
- storageManager.setItemsMode(authManager.isEphemeralSession() ? StorageManager.Ephemeral : StorageManager.FixedEncrypted);
+ // Last argument is `force`, which we set to true because in the case of changing passcode
+ storageManager.setItemsMode(authManager.isEphemeralSession() ? StorageManager.Ephemeral : StorageManager.FixedEncrypted, true);
}
this.decryptLocalStorage = function(keys) {
diff --git a/app/assets/javascripts/app/services/singletonManager.js b/app/assets/javascripts/app/services/singletonManager.js
new file mode 100644
index 000000000..2e8774729
--- /dev/null
+++ b/app/assets/javascripts/app/services/singletonManager.js
@@ -0,0 +1,174 @@
+/*
+ The SingletonManager allows controllers to register an item as a singleton, which means only one instance of that model
+ should exist, both on the server and on the client. When the SingletonManager detects multiple items matching the singleton predicate,
+ the oldest ones will be deleted, leaving the newest ones.
+
+ We will treat the model most recently arrived from the server as the most recent one. The reason for this is, if you're offline,
+ a singleton can be created, as in the case of UserPreferneces. Then when you sign in, you'll retrieve your actual user preferences.
+ In that case, even though the offline singleton has a more recent updated_at, the server retreived value is the one we care more about.
+*/
+
+class SingletonManager {
+
+ constructor($rootScope, modelManager) {
+ this.$rootScope = $rootScope;
+ this.modelManager = modelManager;
+ this.singletonHandlers = [];
+
+ $rootScope.$on("initial-data-loaded", (event, data) => {
+ this.resolveSingletons(modelManager.allItems, null, true);
+ })
+
+ $rootScope.$on("sync:completed", (event, data) => {
+ // The reason we also need to consider savedItems in consolidating singletons is in case of sync conflicts,
+ // a new item can be created, but is never processed through "retrievedItems" since it is only created locally then saved.
+
+ // HOWEVER, by considering savedItems, we are now ruining everything, especially during sign in. A singleton can be created
+ // offline, and upon sign in, will sync all items to the server, and by combining retrievedItems & savedItems, and only choosing
+ // the latest, you are now resolving to the most recent one, which is in the savedItems list and not retrieved items, defeating
+ // the whole purpose of this thing.
+
+ // Updated solution: resolveSingletons will now evaluate both of these arrays separately.
+ this.resolveSingletons(data.retrievedItems, data.savedItems);
+ })
+ }
+
+ registerSingleton(predicate, resolveCallback, createBlock) {
+ /*
+ predicate: a key/value pair that specifies properties that should match in order for an item to be considered a predicate
+ resolveCallback: called when one or more items are deleted and a new item becomes the reigning singleton
+ createBlock: called when a sync is complete and no items are found. The createBlock should create the item and return it.
+ */
+ this.singletonHandlers.push({
+ predicate: predicate,
+ resolutionCallback: resolveCallback,
+ createBlock: createBlock
+ });
+ }
+
+ resolveSingletons(retrievedItems, savedItems, initialLoad) {
+ retrievedItems = retrievedItems || [];
+ savedItems = savedItems || [];
+
+ for(let singletonHandler of this.singletonHandlers) {
+ var predicate = singletonHandler.predicate;
+ let retrievedSingletonItems = this.filterItemsWithPredicate(retrievedItems, predicate);
+
+ // We only want to consider saved items count to see if it's more than 0, and do nothing else with it.
+ // This way we know there was some action and things need to be resolved. The saved items will come up
+ // in filterItemsWithPredicate(this.modelManager.allItems) and be deleted anyway
+ let savedSingletonItemsCount = this.filterItemsWithPredicate(savedItems, predicate).length;
+
+ if(retrievedSingletonItems.length > 0 || savedSingletonItemsCount > 0) {
+ /*
+ Check local inventory and make sure only 1 similar item exists. If more than 1, delete oldest
+ Note that this local inventory will also contain whatever is in retrievedItems.
+ However, as stated in the header comment, retrievedItems take precendence over existing items,
+ even if they have a lower updated_at value
+ */
+ var allExtantItemsMatchingPredicate = this.filterItemsWithPredicate(this.modelManager.allItems, predicate);
+
+ /*
+ If there are more than 1 matches, delete everything not in `retrievedSingletonItems`,
+ then delete all but the latest in `retrievedSingletonItems`
+ */
+ if(allExtantItemsMatchingPredicate.length >= 2) {
+
+ // Items that will be deleted
+ var toDelete = [];
+ // The item that will be chosen to be kept
+ var winningItem, sorted;
+
+ if(retrievedSingletonItems.length > 0) {
+ for(let extantItem of allExtantItemsMatchingPredicate) {
+ if(!retrievedSingletonItems.includes(extantItem)) {
+ // Delete it
+ toDelete.push(extantItem);
+ }
+ }
+
+ // Sort incoming singleton items by most recently updated first, then delete all the rest
+ sorted = retrievedSingletonItems.sort((a, b) => {
+ return a.updated_at < b.updated_at;
+ })
+
+ } else {
+ // We're in here because of savedItems
+ // This can be the case if retrievedSingletonItems/retrievedItems length is 0, but savedSingletonItemsCount is non zero.
+ // In this case, we want to sort by date and delete all but the most recent one
+ sorted = allExtantItemsMatchingPredicate.sort((a, b) => {
+ return a.updated_at < b.updated_at;
+ });
+ }
+
+ winningItem = sorted[0];
+
+ // Delete everything but the first one
+ toDelete = toDelete.concat(sorted.slice(1, sorted.length));
+
+ for(var d of toDelete) {
+ this.modelManager.setItemToBeDeleted(d);
+ }
+
+ this.$rootScope.sync("resolveSingletons");
+
+ // Send remaining item to callback
+ singletonHandler.singleton = winningItem;
+ singletonHandler.resolutionCallback(winningItem);
+
+ } else if(allExtantItemsMatchingPredicate.length == 1) {
+ if(!singletonHandler.singleton) {
+ // Not yet notified interested parties of object
+ var singleton = allExtantItemsMatchingPredicate[0];
+ singletonHandler.singleton = singleton;
+ singletonHandler.resolutionCallback(singleton);
+
+ }
+ }
+ } else {
+ // Retrieved items does not include any items of interest. If we don't have a singleton registered to this handler,
+ // we need to create one. Only do this on actual sync completetions and not on initial data load. Because we want
+ // to get the latest from the server before making the decision to create a new item
+ if(!singletonHandler.singleton && !initialLoad && !singletonHandler.pendingCreateBlockCallback) {
+ singletonHandler.pendingCreateBlockCallback = true;
+ singletonHandler.createBlock((created) => {
+ singletonHandler.singleton = created;
+ singletonHandler.pendingCreateBlockCallback = false;
+ singletonHandler.resolutionCallback(created);
+ });
+ }
+ }
+ }
+ }
+
+ filterItemsWithPredicate(items, predicate) {
+ return items.filter((candidate) => {
+ return this.itemSatisfiesPredicate(candidate, predicate);
+ })
+ }
+
+ itemSatisfiesPredicate(candidate, predicate) {
+ for(var key in predicate) {
+ var predicateValue = predicate[key];
+ var candidateValue = candidate[key];
+ if(typeof predicateValue == 'object') {
+ // Check nested properties
+ if(!candidateValue) {
+ // predicateValue is 'object' but candidateValue is null
+ return false;
+ }
+
+ if(!this.itemSatisfiesPredicate(candidateValue, predicateValue)) {
+ return false;
+ }
+ }
+ else if(candidateValue != predicateValue) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
+
+angular.module('app').service('singletonManager', SingletonManager);
diff --git a/app/assets/javascripts/app/services/storageManager.js b/app/assets/javascripts/app/services/storageManager.js
index cc8a3fa9b..e1aa26c4f 100644
--- a/app/assets/javascripts/app/services/storageManager.js
+++ b/app/assets/javascripts/app/services/storageManager.js
@@ -62,9 +62,9 @@ class StorageManager {
return this._memoryStorage;
}
- setItemsMode(mode) {
+ setItemsMode(mode, force) {
var newStorage = this.getVault(mode);
- if(newStorage !== this.storage) {
+ if(newStorage !== this.storage || mode !== this.itemsStorageMode || force) {
// transfer storages
var length = this.storage.length;
for(var i = 0; i < length; i++) {
@@ -161,7 +161,6 @@ class StorageManager {
for(var key of Object.keys(encryptedStorage.storage)) {
this.setItem(key, encryptedStorage.storage[key]);
}
-
}
hasPasscode() {
@@ -228,4 +227,4 @@ StorageManager.FixedEncrypted = "FixedEncrypted"; // encrypted memoryStorage + l
StorageManager.Ephemeral = "Ephemeral"; // memoryStorage
StorageManager.Fixed = "Fixed"; // localStorage
-angular.module('app.frontend').service('storageManager', StorageManager);
+angular.module('app').service('storageManager', StorageManager);
diff --git a/app/assets/javascripts/app/services/syncManager.js b/app/assets/javascripts/app/services/syncManager.js
index d11fe51c3..599aca41b 100644
--- a/app/assets/javascripts/app/services/syncManager.js
+++ b/app/assets/javascripts/app/services/syncManager.js
@@ -21,10 +21,6 @@ class SyncManager {
return this.storageManager.getItem("mk");
}
- get serverPassword() {
- return this.storageManager.getItem("pw");
- }
-
writeItemsToLocalStorage(items, offlineOnly, callback) {
if(items.length == 0) {
callback && callback();
@@ -62,6 +58,11 @@ class SyncManager {
}
}
+ this.$rootScope.$broadcast("sync:completed", {});
+
+ // Required in order for modelManager to notify sync observers
+ this.modelManager.didSyncModelsOffline(items);
+
if(callback) {
callback({success: true});
}
@@ -92,7 +93,7 @@ class SyncManager {
let alternateNextItem = () => {
if(index >= originalItems.length) {
- // We don't use originalItems as altnerating UUID will have deleted them.
+ // We don't use originalItems as alternating UUID will have deleted them.
block();
return;
}
@@ -188,7 +189,17 @@ class SyncManager {
this.$interval.cancel(this.syncStatus.checker);
}
- sync(callback, options = {}) {
+ sync(callback, options = {}, source) {
+
+ if(!options) options = {};
+
+ if(typeof callback == 'string') {
+ // is source string, used to avoid filling parameters on call
+ source = callback;
+ callback = null;
+ }
+
+ // console.log("Syncing from", source);
var allDirtyItems = this.modelManager.getDirtyItems();
@@ -241,6 +252,11 @@ class SyncManager {
this.allRetreivedItems = [];
}
+ // We also want to do this for savedItems
+ if(!this.allSavedItems) {
+ this.allSavedItems = [];
+ }
+
var version = this.authManager.protocolVersion();
var keys = this.authManager.keys();
@@ -265,7 +281,17 @@ class SyncManager {
this.$rootScope.$broadcast("sync:updated_token", this.syncToken);
+ // Filter retrieved_items to remove any items that may be in saved_items for this complete sync operation
+ // When signing in, and a user requires many round trips to complete entire retrieval of data, an item may be saved
+ // on the first trip, then on subsequent trips using cursor_token, this same item may be returned, since it's date is
+ // greater than cursor_token. We keep track of all saved items in whole sync operation with this.allSavedItems
+ // We need this because singletonManager looks at retrievedItems as higher precendence than savedItems, but if it comes in both
+ // then that's problematic.
+ let allSavedUUIDs = this.allSavedItems.map((item) => {return item.uuid});
+ response.retrieved_items = response.retrieved_items.filter((candidate) => {return !allSavedUUIDs.includes(candidate.uuid)});
+
// Map retrieved items to local data
+ // Note that deleted items will not be returned
var retrieved
= this.handleItemsResponse(response.retrieved_items, null, ModelManager.MappingSourceRemoteRetrieved);
@@ -281,6 +307,9 @@ class SyncManager {
var saved =
this.handleItemsResponse(response.saved_items, omitFields, ModelManager.MappingSourceRemoteSaved);
+ // Append items to master list of saved items for this ongoing sync operation
+ this.allSavedItems = this.allSavedItems.concat(saved);
+
// Create copies of items or alternate their uuids if neccessary
var unsaved = response.unsaved;
this.handleUnsavedItemsResponse(unsaved)
@@ -298,12 +327,12 @@ class SyncManager {
if(this.cursorToken || this.syncStatus.needsMoreSync) {
setTimeout(function () {
- this.sync(callback, options);
+ this.sync(callback, options, "onSyncSuccess cursorToken || needsMoreSync");
}.bind(this), 10); // wait 10ms to allow UI to update
} else if(this.repeatOnCompletion) {
this.repeatOnCompletion = false;
setTimeout(function () {
- this.sync(callback, options);
+ this.sync(callback, options, "onSyncSuccess repeatOnCompletion");
}.bind(this), 10); // wait 10ms to allow UI to update
} else {
this.writeItemsToLocalStorage(this.allRetreivedItems, false, null);
@@ -319,10 +348,11 @@ class SyncManager {
this.$rootScope.$broadcast("major-data-change");
}
- this.allRetreivedItems = [];
-
this.callQueuedCallbacksAndCurrent(callback, response);
- this.$rootScope.$broadcast("sync:completed");
+ this.$rootScope.$broadcast("sync:completed", {retrievedItems: this.allRetreivedItems, savedItems: this.allSavedItems});
+
+ this.allRetreivedItems = [];
+ this.allSavedItems = [];
}
}.bind(this);
@@ -391,14 +421,13 @@ class SyncManager {
console.log("Handle unsaved", unsaved);
var i = 0;
- var handleNext = function() {
+ var handleNext = () => {
if(i >= unsaved.length) {
// Handled all items
this.sync(null, {additionalFields: ["created_at", "updated_at"]});
return;
}
- var handled = false;
var mapping = unsaved[i];
var itemResponse = mapping.item;
EncryptionHelper.decryptMultipleItems([itemResponse], this.authManager.keys());
@@ -414,8 +443,10 @@ class SyncManager {
if(error.tag === "uuid_conflict") {
// UUID conflicts can occur if a user attempts to
// import an old data archive with uuids from the old account into a new account
- handled = true;
- this.modelManager.alternateUUIDForItem(item, handleNext, true);
+ this.modelManager.alternateUUIDForItem(item, () => {
+ i++;
+ handleNext();
+ }, true);
}
else if(error.tag === "sync_conflict") {
@@ -425,20 +456,16 @@ class SyncManager {
itemResponse.uuid = null;
var dup = this.modelManager.createDuplicateItem(itemResponse, item);
- if(!itemResponse.deleted && JSON.stringify(item.structureParams()) !== JSON.stringify(dup.structureParams())) {
+ if(!itemResponse.deleted && !item.isItemContentEqualWith(dup)) {
this.modelManager.addItem(dup);
dup.conflict_of = item.uuid;
dup.setDirty(true);
}
- }
- ++i;
-
- if(!handled) {
+ i++;
handleNext();
}
-
- }.bind(this);
+ }
handleNext();
}
@@ -459,4 +486,4 @@ class SyncManager {
}
}
-angular.module('app.frontend').service('syncManager', SyncManager);
+angular.module('app').service('syncManager', SyncManager);
diff --git a/app/assets/javascripts/app/services/themeManager.js b/app/assets/javascripts/app/services/themeManager.js
index 0e799ba08..deda2e089 100644
--- a/app/assets/javascripts/app/services/themeManager.js
+++ b/app/assets/javascripts/app/services/themeManager.js
@@ -1,99 +1,45 @@
class ThemeManager {
- constructor(modelManager, syncManager, $rootScope, storageManager) {
- this.syncManager = syncManager;
- this.modelManager = modelManager;
- this.$rootScope = $rootScope;
- this.storageManager = storageManager;
- }
+ constructor(componentManager, desktopManager) {
+ this.componentManager = componentManager;
- get themes() {
- return this.modelManager.itemsForContentType("SN|Theme");
- }
+ desktopManager.registerUpdateObserver((component) => {
+ // Reload theme if active
+ if(component.active && component.isTheme()) {
+ this.deactivateTheme(component);
+ setTimeout(() => {
+ this.activateTheme(component);
+ }, 10);
+ }
+ })
- /*
- activeTheme: computed property that returns saved theme
- currentTheme: stored variable that allows other classes to watch changes
- */
-
- get activeTheme() {
- var activeThemeId = this.storageManager.getItem("activeTheme");
- if(!activeThemeId) {
- return null;
- }
-
- var theme = _.find(this.themes, {uuid: activeThemeId});
- return theme;
- }
-
- activateInitialTheme() {
- var theme = this.activeTheme;
- if(theme) {
- this.activateTheme(theme);
- }
- }
-
- submitTheme(url) {
- var name = this.displayNameForThemeFile(this.fileNameFromPath(url));
- var theme = this.modelManager.createItem({content_type: "SN|Theme", url: url, name: name});
- this.modelManager.addItem(theme);
- theme.setDirty(true);
- this.syncManager.sync();
+ componentManager.registerHandler({identifier: "themeManager", areas: ["themes"], activationHandler: (component) => {
+ if(component.active) {
+ this.activateTheme(component);
+ } else {
+ this.deactivateTheme(component);
+ }
+ }});
}
activateTheme(theme) {
- var activeTheme = this.activeTheme;
- if(activeTheme) {
- this.deactivateTheme(activeTheme);
- }
-
+ var url = this.componentManager.urlForComponent(theme);
var link = document.createElement("link");
- link.href = theme.url;
+ link.href = url;
link.type = "text/css";
link.rel = "stylesheet";
link.media = "screen,print";
link.id = theme.uuid;
document.getElementsByTagName("head")[0].appendChild(link);
- this.storageManager.setItem("activeTheme", theme.uuid);
-
- this.currentTheme = theme;
- this.$rootScope.$broadcast("theme-changed");
}
deactivateTheme(theme) {
- this.storageManager.removeItem("activeTheme");
var element = document.getElementById(theme.uuid);
if(element) {
element.disabled = true;
element.parentNode.removeChild(element);
}
-
- this.currentTheme = null;
- this.$rootScope.$broadcast("theme-changed");
}
-
- isThemeActive(theme) {
- return this.storageManager.getItem("activeTheme") === theme.uuid;
- }
-
- fileNameFromPath(filePath) {
- return filePath.replace(/^.*[\\\/]/, '');
- }
-
- capitalizeString(string) {
- return string.replace(/(?:^|\s)\S/g, function(a) { return a.toUpperCase(); });
- }
-
- displayNameForThemeFile(fileName) {
- let fromParam = getParameterByName("name", fileName);
- if(fromParam) {
- return fromParam;
- }
- let name = fileName.split(".")[0];
- let cleaned = name.split("-").join(" ");
- return this.capitalizeString(cleaned);
- }
-
}
-angular.module('app.frontend').service('themeManager', ThemeManager);
+angular.module('app').service('themeManager', ThemeManager);
diff --git a/app/assets/javascripts/frontend.js b/app/assets/javascripts/frontend.js
deleted file mode 100644
index 7e4f399dd..000000000
--- a/app/assets/javascripts/frontend.js
+++ /dev/null
@@ -1,5 +0,0 @@
-//= require app/app.frontend.js
-//= require_tree ./app/services
-
-//= require app/app.frontend.js
-//= require_tree ./app/frontend
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
new file mode 100644
index 000000000..d7ba63e74
--- /dev/null
+++ b/app/assets/javascripts/main.js
@@ -0,0 +1 @@
+//= require_tree ./app
diff --git a/app/assets/stylesheets/_ionicons.scss b/app/assets/stylesheets/_ionicons.scss
deleted file mode 100644
index 47fd1b15c..000000000
--- a/app/assets/stylesheets/_ionicons.scss
+++ /dev/null
@@ -1,2966 +0,0 @@
-@charset "UTF-8";
-/*!
- Ionicons, v2.0.0
- Created by Ben Sperry for the Ionic Framework, http://ionicons.com/
- https://twitter.com/benjsperry https://twitter.com/ionicframework
- MIT License: https://github.com/driftyco/ionicons
-
- Android-style icons originally built by Google’s
- Material Design Icons: https://github.com/google/material-design-icons
- used under CC BY http://creativecommons.org/licenses/by/4.0/
- Modified icons to fit ionicon’s grid from original.
-*/
-@font-face {
- font-family: "Ionicons";
- src: url("../assets/ionicons.eot?v=2.0.0");
- src: url("../assets/ionicons.eot?v=2.0.0#iefix") format("embedded-opentype"), url("../assets/ionicons.ttf?v=2.0.0") format("truetype"), url("../assets/ionicons.woff?v=2.0.0") format("woff"), url("../assets/ionicons.svg?v=2.0.0#Ionicons") format("svg");
- font-weight: normal;
- font-style: normal;
-}
-.ion, .ionicons, .ion-alert:before, .ion-alert-circled:before, .ion-android-add:before, .ion-android-add-circle:before, .ion-android-alarm-clock:before, .ion-android-alert:before, .ion-android-apps:before, .ion-android-archive:before, .ion-android-arrow-back:before, .ion-android-arrow-down:before, .ion-android-arrow-dropdown:before, .ion-android-arrow-dropdown-circle:before, .ion-android-arrow-dropleft:before, .ion-android-arrow-dropleft-circle:before, .ion-android-arrow-dropright:before, .ion-android-arrow-dropright-circle:before, .ion-android-arrow-dropup:before, .ion-android-arrow-dropup-circle:before, .ion-android-arrow-forward:before, .ion-android-arrow-up:before, .ion-android-attach:before, .ion-android-bar:before, .ion-android-bicycle:before, .ion-android-boat:before, .ion-android-bookmark:before, .ion-android-bulb:before, .ion-android-bus:before, .ion-android-calendar:before, .ion-android-call:before, .ion-android-camera:before, .ion-android-cancel:before, .ion-android-car:before, .ion-android-cart:before, .ion-android-chat:before, .ion-android-checkbox:before, .ion-android-checkbox-blank:before, .ion-android-checkbox-outline:before, .ion-android-checkbox-outline-blank:before, .ion-android-checkmark-circle:before, .ion-android-clipboard:before, .ion-android-close:before, .ion-android-cloud:before, .ion-android-cloud-circle:before, .ion-android-cloud-done:before, .ion-android-cloud-outline:before, .ion-android-color-palette:before, .ion-android-compass:before, .ion-android-contact:before, .ion-android-contacts:before, .ion-android-contract:before, .ion-android-create:before, .ion-android-delete:before, .ion-android-desktop:before, .ion-android-document:before, .ion-android-done:before, .ion-android-done-all:before, .ion-android-download:before, .ion-android-drafts:before, .ion-android-exit:before, .ion-android-expand:before, .ion-android-favorite:before, .ion-android-favorite-outline:before, .ion-android-film:before, .ion-android-folder:before, .ion-android-folder-open:before, .ion-android-funnel:before, .ion-android-globe:before, .ion-android-hand:before, .ion-android-hangout:before, .ion-android-happy:before, .ion-android-home:before, .ion-android-image:before, .ion-android-laptop:before, .ion-android-list:before, .ion-android-locate:before, .ion-android-lock:before, .ion-android-mail:before, .ion-android-map:before, .ion-android-menu:before, .ion-android-microphone:before, .ion-android-microphone-off:before, .ion-android-more-horizontal:before, .ion-android-more-vertical:before, .ion-android-navigate:before, .ion-android-notifications:before, .ion-android-notifications-none:before, .ion-android-notifications-off:before, .ion-android-open:before, .ion-android-options:before, .ion-android-people:before, .ion-android-person:before, .ion-android-person-add:before, .ion-android-phone-landscape:before, .ion-android-phone-portrait:before, .ion-android-pin:before, .ion-android-plane:before, .ion-android-playstore:before, .ion-android-print:before, .ion-android-radio-button-off:before, .ion-android-radio-button-on:before, .ion-android-refresh:before, .ion-android-remove:before, .ion-android-remove-circle:before, .ion-android-restaurant:before, .ion-android-sad:before, .ion-android-search:before, .ion-android-send:before, .ion-android-settings:before, .ion-android-share:before, .ion-android-share-alt:before, .ion-android-star:before, .ion-android-star-half:before, .ion-android-star-outline:before, .ion-android-stopwatch:before, .ion-android-subway:before, .ion-android-sunny:before, .ion-android-sync:before, .ion-android-textsms:before, .ion-android-time:before, .ion-android-train:before, .ion-android-unlock:before, .ion-android-upload:before, .ion-android-volume-down:before, .ion-android-volume-mute:before, .ion-android-volume-off:before, .ion-android-volume-up:before, .ion-android-walk:before, .ion-android-warning:before, .ion-android-watch:before, .ion-android-wifi:before, .ion-aperture:before, .ion-archive:before, .ion-arrow-down-a:before, .ion-arrow-down-b:before, .ion-arrow-down-c:before, .ion-arrow-expand:before, .ion-arrow-graph-down-left:before, .ion-arrow-graph-down-right:before, .ion-arrow-graph-up-left:before, .ion-arrow-graph-up-right:before, .ion-arrow-left-a:before, .ion-arrow-left-b:before, .ion-arrow-left-c:before, .ion-arrow-move:before, .ion-arrow-resize:before, .ion-arrow-return-left:before, .ion-arrow-return-right:before, .ion-arrow-right-a:before, .ion-arrow-right-b:before, .ion-arrow-right-c:before, .ion-arrow-shrink:before, .ion-arrow-swap:before, .ion-arrow-up-a:before, .ion-arrow-up-b:before, .ion-arrow-up-c:before, .ion-asterisk:before, .ion-at:before, .ion-backspace:before, .ion-backspace-outline:before, .ion-bag:before, .ion-battery-charging:before, .ion-battery-empty:before, .ion-battery-full:before, .ion-battery-half:before, .ion-battery-low:before, .ion-beaker:before, .ion-beer:before, .ion-bluetooth:before, .ion-bonfire:before, .ion-bookmark:before, .ion-bowtie:before, .ion-briefcase:before, .ion-bug:before, .ion-calculator:before, .ion-calendar:before, .ion-camera:before, .ion-card:before, .ion-cash:before, .ion-chatbox:before, .ion-chatbox-working:before, .ion-chatboxes:before, .ion-chatbubble:before, .ion-chatbubble-working:before, .ion-chatbubbles:before, .ion-checkmark:before, .ion-checkmark-circled:before, .ion-checkmark-round:before, .ion-chevron-down:before, .ion-chevron-left:before, .ion-chevron-right:before, .ion-chevron-up:before, .ion-clipboard:before, .ion-clock:before, .ion-close:before, .ion-close-circled:before, .ion-close-round:before, .ion-closed-captioning:before, .ion-cloud:before, .ion-code:before, .ion-code-download:before, .ion-code-working:before, .ion-coffee:before, .ion-compass:before, .ion-compose:before, .ion-connection-bars:before, .ion-contrast:before, .ion-crop:before, .ion-cube:before, .ion-disc:before, .ion-document:before, .ion-document-text:before, .ion-drag:before, .ion-earth:before, .ion-easel:before, .ion-edit:before, .ion-egg:before, .ion-eject:before, .ion-email:before, .ion-email-unread:before, .ion-erlenmeyer-flask:before, .ion-erlenmeyer-flask-bubbles:before, .ion-eye:before, .ion-eye-disabled:before, .ion-female:before, .ion-filing:before, .ion-film-marker:before, .ion-fireball:before, .ion-flag:before, .ion-flame:before, .ion-flash:before, .ion-flash-off:before, .ion-folder:before, .ion-fork:before, .ion-fork-repo:before, .ion-forward:before, .ion-funnel:before, .ion-gear-a:before, .ion-gear-b:before, .ion-grid:before, .ion-hammer:before, .ion-happy:before, .ion-happy-outline:before, .ion-headphone:before, .ion-heart:before, .ion-heart-broken:before, .ion-help:before, .ion-help-buoy:before, .ion-help-circled:before, .ion-home:before, .ion-icecream:before, .ion-image:before, .ion-images:before, .ion-information:before, .ion-information-circled:before, .ion-ionic:before, .ion-ios-alarm:before, .ion-ios-alarm-outline:before, .ion-ios-albums:before, .ion-ios-albums-outline:before, .ion-ios-americanfootball:before, .ion-ios-americanfootball-outline:before, .ion-ios-analytics:before, .ion-ios-analytics-outline:before, .ion-ios-arrow-back:before, .ion-ios-arrow-down:before, .ion-ios-arrow-forward:before, .ion-ios-arrow-left:before, .ion-ios-arrow-right:before, .ion-ios-arrow-thin-down:before, .ion-ios-arrow-thin-left:before, .ion-ios-arrow-thin-right:before, .ion-ios-arrow-thin-up:before, .ion-ios-arrow-up:before, .ion-ios-at:before, .ion-ios-at-outline:before, .ion-ios-barcode:before, .ion-ios-barcode-outline:before, .ion-ios-baseball:before, .ion-ios-baseball-outline:before, .ion-ios-basketball:before, .ion-ios-basketball-outline:before, .ion-ios-bell:before, .ion-ios-bell-outline:before, .ion-ios-body:before, .ion-ios-body-outline:before, .ion-ios-bolt:before, .ion-ios-bolt-outline:before, .ion-ios-book:before, .ion-ios-book-outline:before, .ion-ios-bookmarks:before, .ion-ios-bookmarks-outline:before, .ion-ios-box:before, .ion-ios-box-outline:before, .ion-ios-briefcase:before, .ion-ios-briefcase-outline:before, .ion-ios-browsers:before, .ion-ios-browsers-outline:before, .ion-ios-calculator:before, .ion-ios-calculator-outline:before, .ion-ios-calendar:before, .ion-ios-calendar-outline:before, .ion-ios-camera:before, .ion-ios-camera-outline:before, .ion-ios-cart:before, .ion-ios-cart-outline:before, .ion-ios-chatboxes:before, .ion-ios-chatboxes-outline:before, .ion-ios-chatbubble:before, .ion-ios-chatbubble-outline:before, .ion-ios-checkmark:before, .ion-ios-checkmark-empty:before, .ion-ios-checkmark-outline:before, .ion-ios-circle-filled:before, .ion-ios-circle-outline:before, .ion-ios-clock:before, .ion-ios-clock-outline:before, .ion-ios-close:before, .ion-ios-close-empty:before, .ion-ios-close-outline:before, .ion-ios-cloud:before, .ion-ios-cloud-download:before, .ion-ios-cloud-download-outline:before, .ion-ios-cloud-outline:before, .ion-ios-cloud-upload:before, .ion-ios-cloud-upload-outline:before, .ion-ios-cloudy:before, .ion-ios-cloudy-night:before, .ion-ios-cloudy-night-outline:before, .ion-ios-cloudy-outline:before, .ion-ios-cog:before, .ion-ios-cog-outline:before, .ion-ios-color-filter:before, .ion-ios-color-filter-outline:before, .ion-ios-color-wand:before, .ion-ios-color-wand-outline:before, .ion-ios-compose:before, .ion-ios-compose-outline:before, .ion-ios-contact:before, .ion-ios-contact-outline:before, .ion-ios-copy:before, .ion-ios-copy-outline:before, .ion-ios-crop:before, .ion-ios-crop-strong:before, .ion-ios-download:before, .ion-ios-download-outline:before, .ion-ios-drag:before, .ion-ios-email:before, .ion-ios-email-outline:before, .ion-ios-eye:before, .ion-ios-eye-outline:before, .ion-ios-fastforward:before, .ion-ios-fastforward-outline:before, .ion-ios-filing:before, .ion-ios-filing-outline:before, .ion-ios-film:before, .ion-ios-film-outline:before, .ion-ios-flag:before, .ion-ios-flag-outline:before, .ion-ios-flame:before, .ion-ios-flame-outline:before, .ion-ios-flask:before, .ion-ios-flask-outline:before, .ion-ios-flower:before, .ion-ios-flower-outline:before, .ion-ios-folder:before, .ion-ios-folder-outline:before, .ion-ios-football:before, .ion-ios-football-outline:before, .ion-ios-game-controller-a:before, .ion-ios-game-controller-a-outline:before, .ion-ios-game-controller-b:before, .ion-ios-game-controller-b-outline:before, .ion-ios-gear:before, .ion-ios-gear-outline:before, .ion-ios-glasses:before, .ion-ios-glasses-outline:before, .ion-ios-grid-view:before, .ion-ios-grid-view-outline:before, .ion-ios-heart:before, .ion-ios-heart-outline:before, .ion-ios-help:before, .ion-ios-help-empty:before, .ion-ios-help-outline:before, .ion-ios-home:before, .ion-ios-home-outline:before, .ion-ios-infinite:before, .ion-ios-infinite-outline:before, .ion-ios-information:before, .ion-ios-information-empty:before, .ion-ios-information-outline:before, .ion-ios-ionic-outline:before, .ion-ios-keypad:before, .ion-ios-keypad-outline:before, .ion-ios-lightbulb:before, .ion-ios-lightbulb-outline:before, .ion-ios-list:before, .ion-ios-list-outline:before, .ion-ios-location:before, .ion-ios-location-outline:before, .ion-ios-locked:before, .ion-ios-locked-outline:before, .ion-ios-loop:before, .ion-ios-loop-strong:before, .ion-ios-medical:before, .ion-ios-medical-outline:before, .ion-ios-medkit:before, .ion-ios-medkit-outline:before, .ion-ios-mic:before, .ion-ios-mic-off:before, .ion-ios-mic-outline:before, .ion-ios-minus:before, .ion-ios-minus-empty:before, .ion-ios-minus-outline:before, .ion-ios-monitor:before, .ion-ios-monitor-outline:before, .ion-ios-moon:before, .ion-ios-moon-outline:before, .ion-ios-more:before, .ion-ios-more-outline:before, .ion-ios-musical-note:before, .ion-ios-musical-notes:before, .ion-ios-navigate:before, .ion-ios-navigate-outline:before, .ion-ios-nutrition:before, .ion-ios-nutrition-outline:before, .ion-ios-paper:before, .ion-ios-paper-outline:before, .ion-ios-paperplane:before, .ion-ios-paperplane-outline:before, .ion-ios-partlysunny:before, .ion-ios-partlysunny-outline:before, .ion-ios-pause:before, .ion-ios-pause-outline:before, .ion-ios-paw:before, .ion-ios-paw-outline:before, .ion-ios-people:before, .ion-ios-people-outline:before, .ion-ios-person:before, .ion-ios-person-outline:before, .ion-ios-personadd:before, .ion-ios-personadd-outline:before, .ion-ios-photos:before, .ion-ios-photos-outline:before, .ion-ios-pie:before, .ion-ios-pie-outline:before, .ion-ios-pint:before, .ion-ios-pint-outline:before, .ion-ios-play:before, .ion-ios-play-outline:before, .ion-ios-plus:before, .ion-ios-plus-empty:before, .ion-ios-plus-outline:before, .ion-ios-pricetag:before, .ion-ios-pricetag-outline:before, .ion-ios-pricetags:before, .ion-ios-pricetags-outline:before, .ion-ios-printer:before, .ion-ios-printer-outline:before, .ion-ios-pulse:before, .ion-ios-pulse-strong:before, .ion-ios-rainy:before, .ion-ios-rainy-outline:before, .ion-ios-recording:before, .ion-ios-recording-outline:before, .ion-ios-redo:before, .ion-ios-redo-outline:before, .ion-ios-refresh:before, .ion-ios-refresh-empty:before, .ion-ios-refresh-outline:before, .ion-ios-reload:before, .ion-ios-reverse-camera:before, .ion-ios-reverse-camera-outline:before, .ion-ios-rewind:before, .ion-ios-rewind-outline:before, .ion-ios-rose:before, .ion-ios-rose-outline:before, .ion-ios-search:before, .ion-ios-search-strong:before, .ion-ios-settings:before, .ion-ios-settings-strong:before, .ion-ios-shuffle:before, .ion-ios-shuffle-strong:before, .ion-ios-skipbackward:before, .ion-ios-skipbackward-outline:before, .ion-ios-skipforward:before, .ion-ios-skipforward-outline:before, .ion-ios-snowy:before, .ion-ios-speedometer:before, .ion-ios-speedometer-outline:before, .ion-ios-star:before, .ion-ios-star-half:before, .ion-ios-star-outline:before, .ion-ios-stopwatch:before, .ion-ios-stopwatch-outline:before, .ion-ios-sunny:before, .ion-ios-sunny-outline:before, .ion-ios-telephone:before, .ion-ios-telephone-outline:before, .ion-ios-tennisball:before, .ion-ios-tennisball-outline:before, .ion-ios-thunderstorm:before, .ion-ios-thunderstorm-outline:before, .ion-ios-time:before, .ion-ios-time-outline:before, .ion-ios-timer:before, .ion-ios-timer-outline:before, .ion-ios-toggle:before, .ion-ios-toggle-outline:before, .ion-ios-trash:before, .ion-ios-trash-outline:before, .ion-ios-undo:before, .ion-ios-undo-outline:before, .ion-ios-unlocked:before, .ion-ios-unlocked-outline:before, .ion-ios-upload:before, .ion-ios-upload-outline:before, .ion-ios-videocam:before, .ion-ios-videocam-outline:before, .ion-ios-volume-high:before, .ion-ios-volume-low:before, .ion-ios-wineglass:before, .ion-ios-wineglass-outline:before, .ion-ios-world:before, .ion-ios-world-outline:before, .ion-ipad:before, .ion-iphone:before, .ion-ipod:before, .ion-jet:before, .ion-key:before, .ion-knife:before, .ion-laptop:before, .ion-leaf:before, .ion-levels:before, .ion-lightbulb:before, .ion-link:before, .ion-load-a:before, .ion-load-b:before, .ion-load-c:before, .ion-load-d:before, .ion-location:before, .ion-lock-combination:before, .ion-locked:before, .ion-log-in:before, .ion-log-out:before, .ion-loop:before, .ion-magnet:before, .ion-male:before, .ion-man:before, .ion-map:before, .ion-medkit:before, .ion-merge:before, .ion-mic-a:before, .ion-mic-b:before, .ion-mic-c:before, .ion-minus:before, .ion-minus-circled:before, .ion-minus-round:before, .ion-model-s:before, .ion-monitor:before, .ion-more:before, .ion-mouse:before, .ion-music-note:before, .ion-navicon:before, .ion-navicon-round:before, .ion-navigate:before, .ion-network:before, .ion-no-smoking:before, .ion-nuclear:before, .ion-outlet:before, .ion-paintbrush:before, .ion-paintbucket:before, .ion-paper-airplane:before, .ion-paperclip:before, .ion-pause:before, .ion-person:before, .ion-person-add:before, .ion-person-stalker:before, .ion-pie-graph:before, .ion-pin:before, .ion-pinpoint:before, .ion-pizza:before, .ion-plane:before, .ion-planet:before, .ion-play:before, .ion-playstation:before, .ion-plus:before, .ion-plus-circled:before, .ion-plus-round:before, .ion-podium:before, .ion-pound:before, .ion-power:before, .ion-pricetag:before, .ion-pricetags:before, .ion-printer:before, .ion-pull-request:before, .ion-qr-scanner:before, .ion-quote:before, .ion-radio-waves:before, .ion-record:before, .ion-refresh:before, .ion-reply:before, .ion-reply-all:before, .ion-ribbon-a:before, .ion-ribbon-b:before, .ion-sad:before, .ion-sad-outline:before, .ion-scissors:before, .ion-search:before, .ion-settings:before, .ion-share:before, .ion-shuffle:before, .ion-skip-backward:before, .ion-skip-forward:before, .ion-social-android:before, .ion-social-android-outline:before, .ion-social-angular:before, .ion-social-angular-outline:before, .ion-social-apple:before, .ion-social-apple-outline:before, .ion-social-bitcoin:before, .ion-social-bitcoin-outline:before, .ion-social-buffer:before, .ion-social-buffer-outline:before, .ion-social-chrome:before, .ion-social-chrome-outline:before, .ion-social-codepen:before, .ion-social-codepen-outline:before, .ion-social-css3:before, .ion-social-css3-outline:before, .ion-social-designernews:before, .ion-social-designernews-outline:before, .ion-social-dribbble:before, .ion-social-dribbble-outline:before, .ion-social-dropbox:before, .ion-social-dropbox-outline:before, .ion-social-euro:before, .ion-social-euro-outline:before, .ion-social-facebook:before, .ion-social-facebook-outline:before, .ion-social-foursquare:before, .ion-social-foursquare-outline:before, .ion-social-freebsd-devil:before, .ion-social-github:before, .ion-social-github-outline:before, .ion-social-google:before, .ion-social-google-outline:before, .ion-social-googleplus:before, .ion-social-googleplus-outline:before, .ion-social-hackernews:before, .ion-social-hackernews-outline:before, .ion-social-html5:before, .ion-social-html5-outline:before, .ion-social-instagram:before, .ion-social-instagram-outline:before, .ion-social-javascript:before, .ion-social-javascript-outline:before, .ion-social-linkedin:before, .ion-social-linkedin-outline:before, .ion-social-markdown:before, .ion-social-nodejs:before, .ion-social-octocat:before, .ion-social-pinterest:before, .ion-social-pinterest-outline:before, .ion-social-python:before, .ion-social-reddit:before, .ion-social-reddit-outline:before, .ion-social-rss:before, .ion-social-rss-outline:before, .ion-social-sass:before, .ion-social-skype:before, .ion-social-skype-outline:before, .ion-social-snapchat:before, .ion-social-snapchat-outline:before, .ion-social-tumblr:before, .ion-social-tumblr-outline:before, .ion-social-tux:before, .ion-social-twitch:before, .ion-social-twitch-outline:before, .ion-social-twitter:before, .ion-social-twitter-outline:before, .ion-social-usd:before, .ion-social-usd-outline:before, .ion-social-vimeo:before, .ion-social-vimeo-outline:before, .ion-social-whatsapp:before, .ion-social-whatsapp-outline:before, .ion-social-windows:before, .ion-social-windows-outline:before, .ion-social-wordpress:before, .ion-social-wordpress-outline:before, .ion-social-yahoo:before, .ion-social-yahoo-outline:before, .ion-social-yen:before, .ion-social-yen-outline:before, .ion-social-youtube:before, .ion-social-youtube-outline:before, .ion-soup-can:before, .ion-soup-can-outline:before, .ion-speakerphone:before, .ion-speedometer:before, .ion-spoon:before, .ion-star:before, .ion-stats-bars:before, .ion-steam:before, .ion-stop:before, .ion-thermometer:before, .ion-thumbsdown:before, .ion-thumbsup:before, .ion-toggle:before, .ion-toggle-filled:before, .ion-transgender:before, .ion-trash-a:before, .ion-trash-b:before, .ion-trophy:before, .ion-tshirt:before, .ion-tshirt-outline:before, .ion-umbrella:before, .ion-university:before, .ion-unlocked:before, .ion-upload:before, .ion-usb:before, .ion-videocamera:before, .ion-volume-high:before, .ion-volume-low:before, .ion-volume-medium:before, .ion-volume-mute:before, .ion-wand:before, .ion-waterdrop:before, .ion-wifi:before, .ion-wineglass:before, .ion-woman:before, .ion-wrench:before, .ion-xbox:before {
- display: inline-block;
- font-family: "Ionicons";
- speak: none;
- font-style: normal;
- font-weight: normal;
- font-variant: normal;
- text-transform: none;
- text-rendering: auto;
- line-height: 1;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-.ion-alert:before {
- content: "\f101";
-}
-
-.ion-alert-circled:before {
- content: "\f100";
-}
-
-.ion-android-add:before {
- content: "\f2c7";
-}
-
-.ion-android-add-circle:before {
- content: "\f359";
-}
-
-.ion-android-alarm-clock:before {
- content: "\f35a";
-}
-
-.ion-android-alert:before {
- content: "\f35b";
-}
-
-.ion-android-apps:before {
- content: "\f35c";
-}
-
-.ion-android-archive:before {
- content: "\f2c9";
-}
-
-.ion-android-arrow-back:before {
- content: "\f2ca";
-}
-
-.ion-android-arrow-down:before {
- content: "\f35d";
-}
-
-.ion-android-arrow-dropdown:before {
- content: "\f35f";
-}
-
-.ion-android-arrow-dropdown-circle:before {
- content: "\f35e";
-}
-
-.ion-android-arrow-dropleft:before {
- content: "\f361";
-}
-
-.ion-android-arrow-dropleft-circle:before {
- content: "\f360";
-}
-
-.ion-android-arrow-dropright:before {
- content: "\f363";
-}
-
-.ion-android-arrow-dropright-circle:before {
- content: "\f362";
-}
-
-.ion-android-arrow-dropup:before {
- content: "\f365";
-}
-
-.ion-android-arrow-dropup-circle:before {
- content: "\f364";
-}
-
-.ion-android-arrow-forward:before {
- content: "\f30f";
-}
-
-.ion-android-arrow-up:before {
- content: "\f366";
-}
-
-.ion-android-attach:before {
- content: "\f367";
-}
-
-.ion-android-bar:before {
- content: "\f368";
-}
-
-.ion-android-bicycle:before {
- content: "\f369";
-}
-
-.ion-android-boat:before {
- content: "\f36a";
-}
-
-.ion-android-bookmark:before {
- content: "\f36b";
-}
-
-.ion-android-bulb:before {
- content: "\f36c";
-}
-
-.ion-android-bus:before {
- content: "\f36d";
-}
-
-.ion-android-calendar:before {
- content: "\f2d1";
-}
-
-.ion-android-call:before {
- content: "\f2d2";
-}
-
-.ion-android-camera:before {
- content: "\f2d3";
-}
-
-.ion-android-cancel:before {
- content: "\f36e";
-}
-
-.ion-android-car:before {
- content: "\f36f";
-}
-
-.ion-android-cart:before {
- content: "\f370";
-}
-
-.ion-android-chat:before {
- content: "\f2d4";
-}
-
-.ion-android-checkbox:before {
- content: "\f374";
-}
-
-.ion-android-checkbox-blank:before {
- content: "\f371";
-}
-
-.ion-android-checkbox-outline:before {
- content: "\f373";
-}
-
-.ion-android-checkbox-outline-blank:before {
- content: "\f372";
-}
-
-.ion-android-checkmark-circle:before {
- content: "\f375";
-}
-
-.ion-android-clipboard:before {
- content: "\f376";
-}
-
-.ion-android-close:before {
- content: "\f2d7";
-}
-
-.ion-android-cloud:before {
- content: "\f37a";
-}
-
-.ion-android-cloud-circle:before {
- content: "\f377";
-}
-
-.ion-android-cloud-done:before {
- content: "\f378";
-}
-
-.ion-android-cloud-outline:before {
- content: "\f379";
-}
-
-.ion-android-color-palette:before {
- content: "\f37b";
-}
-
-.ion-android-compass:before {
- content: "\f37c";
-}
-
-.ion-android-contact:before {
- content: "\f2d8";
-}
-
-.ion-android-contacts:before {
- content: "\f2d9";
-}
-
-.ion-android-contract:before {
- content: "\f37d";
-}
-
-.ion-android-create:before {
- content: "\f37e";
-}
-
-.ion-android-delete:before {
- content: "\f37f";
-}
-
-.ion-android-desktop:before {
- content: "\f380";
-}
-
-.ion-android-document:before {
- content: "\f381";
-}
-
-.ion-android-done:before {
- content: "\f383";
-}
-
-.ion-android-done-all:before {
- content: "\f382";
-}
-
-.ion-android-download:before {
- content: "\f2dd";
-}
-
-.ion-android-drafts:before {
- content: "\f384";
-}
-
-.ion-android-exit:before {
- content: "\f385";
-}
-
-.ion-android-expand:before {
- content: "\f386";
-}
-
-.ion-android-favorite:before {
- content: "\f388";
-}
-
-.ion-android-favorite-outline:before {
- content: "\f387";
-}
-
-.ion-android-film:before {
- content: "\f389";
-}
-
-.ion-android-folder:before {
- content: "\f2e0";
-}
-
-.ion-android-folder-open:before {
- content: "\f38a";
-}
-
-.ion-android-funnel:before {
- content: "\f38b";
-}
-
-.ion-android-globe:before {
- content: "\f38c";
-}
-
-.ion-android-hand:before {
- content: "\f2e3";
-}
-
-.ion-android-hangout:before {
- content: "\f38d";
-}
-
-.ion-android-happy:before {
- content: "\f38e";
-}
-
-.ion-android-home:before {
- content: "\f38f";
-}
-
-.ion-android-image:before {
- content: "\f2e4";
-}
-
-.ion-android-laptop:before {
- content: "\f390";
-}
-
-.ion-android-list:before {
- content: "\f391";
-}
-
-.ion-android-locate:before {
- content: "\f2e9";
-}
-
-.ion-android-lock:before {
- content: "\f392";
-}
-
-.ion-android-mail:before {
- content: "\f2eb";
-}
-
-.ion-android-map:before {
- content: "\f393";
-}
-
-.ion-android-menu:before {
- content: "\f394";
-}
-
-.ion-android-microphone:before {
- content: "\f2ec";
-}
-
-.ion-android-microphone-off:before {
- content: "\f395";
-}
-
-.ion-android-more-horizontal:before {
- content: "\f396";
-}
-
-.ion-android-more-vertical:before {
- content: "\f397";
-}
-
-.ion-android-navigate:before {
- content: "\f398";
-}
-
-.ion-android-notifications:before {
- content: "\f39b";
-}
-
-.ion-android-notifications-none:before {
- content: "\f399";
-}
-
-.ion-android-notifications-off:before {
- content: "\f39a";
-}
-
-.ion-android-open:before {
- content: "\f39c";
-}
-
-.ion-android-options:before {
- content: "\f39d";
-}
-
-.ion-android-people:before {
- content: "\f39e";
-}
-
-.ion-android-person:before {
- content: "\f3a0";
-}
-
-.ion-android-person-add:before {
- content: "\f39f";
-}
-
-.ion-android-phone-landscape:before {
- content: "\f3a1";
-}
-
-.ion-android-phone-portrait:before {
- content: "\f3a2";
-}
-
-.ion-android-pin:before {
- content: "\f3a3";
-}
-
-.ion-android-plane:before {
- content: "\f3a4";
-}
-
-.ion-android-playstore:before {
- content: "\f2f0";
-}
-
-.ion-android-print:before {
- content: "\f3a5";
-}
-
-.ion-android-radio-button-off:before {
- content: "\f3a6";
-}
-
-.ion-android-radio-button-on:before {
- content: "\f3a7";
-}
-
-.ion-android-refresh:before {
- content: "\f3a8";
-}
-
-.ion-android-remove:before {
- content: "\f2f4";
-}
-
-.ion-android-remove-circle:before {
- content: "\f3a9";
-}
-
-.ion-android-restaurant:before {
- content: "\f3aa";
-}
-
-.ion-android-sad:before {
- content: "\f3ab";
-}
-
-.ion-android-search:before {
- content: "\f2f5";
-}
-
-.ion-android-send:before {
- content: "\f2f6";
-}
-
-.ion-android-settings:before {
- content: "\f2f7";
-}
-
-.ion-android-share:before {
- content: "\f2f8";
-}
-
-.ion-android-share-alt:before {
- content: "\f3ac";
-}
-
-.ion-android-star:before {
- content: "\f2fc";
-}
-
-.ion-android-star-half:before {
- content: "\f3ad";
-}
-
-.ion-android-star-outline:before {
- content: "\f3ae";
-}
-
-.ion-android-stopwatch:before {
- content: "\f2fd";
-}
-
-.ion-android-subway:before {
- content: "\f3af";
-}
-
-.ion-android-sunny:before {
- content: "\f3b0";
-}
-
-.ion-android-sync:before {
- content: "\f3b1";
-}
-
-.ion-android-textsms:before {
- content: "\f3b2";
-}
-
-.ion-android-time:before {
- content: "\f3b3";
-}
-
-.ion-android-train:before {
- content: "\f3b4";
-}
-
-.ion-android-unlock:before {
- content: "\f3b5";
-}
-
-.ion-android-upload:before {
- content: "\f3b6";
-}
-
-.ion-android-volume-down:before {
- content: "\f3b7";
-}
-
-.ion-android-volume-mute:before {
- content: "\f3b8";
-}
-
-.ion-android-volume-off:before {
- content: "\f3b9";
-}
-
-.ion-android-volume-up:before {
- content: "\f3ba";
-}
-
-.ion-android-walk:before {
- content: "\f3bb";
-}
-
-.ion-android-warning:before {
- content: "\f3bc";
-}
-
-.ion-android-watch:before {
- content: "\f3bd";
-}
-
-.ion-android-wifi:before {
- content: "\f305";
-}
-
-.ion-aperture:before {
- content: "\f313";
-}
-
-.ion-archive:before {
- content: "\f102";
-}
-
-.ion-arrow-down-a:before {
- content: "\f103";
-}
-
-.ion-arrow-down-b:before {
- content: "\f104";
-}
-
-.ion-arrow-down-c:before {
- content: "\f105";
-}
-
-.ion-arrow-expand:before {
- content: "\f25e";
-}
-
-.ion-arrow-graph-down-left:before {
- content: "\f25f";
-}
-
-.ion-arrow-graph-down-right:before {
- content: "\f260";
-}
-
-.ion-arrow-graph-up-left:before {
- content: "\f261";
-}
-
-.ion-arrow-graph-up-right:before {
- content: "\f262";
-}
-
-.ion-arrow-left-a:before {
- content: "\f106";
-}
-
-.ion-arrow-left-b:before {
- content: "\f107";
-}
-
-.ion-arrow-left-c:before {
- content: "\f108";
-}
-
-.ion-arrow-move:before {
- content: "\f263";
-}
-
-.ion-arrow-resize:before {
- content: "\f264";
-}
-
-.ion-arrow-return-left:before {
- content: "\f265";
-}
-
-.ion-arrow-return-right:before {
- content: "\f266";
-}
-
-.ion-arrow-right-a:before {
- content: "\f109";
-}
-
-.ion-arrow-right-b:before {
- content: "\f10a";
-}
-
-.ion-arrow-right-c:before {
- content: "\f10b";
-}
-
-.ion-arrow-shrink:before {
- content: "\f267";
-}
-
-.ion-arrow-swap:before {
- content: "\f268";
-}
-
-.ion-arrow-up-a:before {
- content: "\f10c";
-}
-
-.ion-arrow-up-b:before {
- content: "\f10d";
-}
-
-.ion-arrow-up-c:before {
- content: "\f10e";
-}
-
-.ion-asterisk:before {
- content: "\f314";
-}
-
-.ion-at:before {
- content: "\f10f";
-}
-
-.ion-backspace:before {
- content: "\f3bf";
-}
-
-.ion-backspace-outline:before {
- content: "\f3be";
-}
-
-.ion-bag:before {
- content: "\f110";
-}
-
-.ion-battery-charging:before {
- content: "\f111";
-}
-
-.ion-battery-empty:before {
- content: "\f112";
-}
-
-.ion-battery-full:before {
- content: "\f113";
-}
-
-.ion-battery-half:before {
- content: "\f114";
-}
-
-.ion-battery-low:before {
- content: "\f115";
-}
-
-.ion-beaker:before {
- content: "\f269";
-}
-
-.ion-beer:before {
- content: "\f26a";
-}
-
-.ion-bluetooth:before {
- content: "\f116";
-}
-
-.ion-bonfire:before {
- content: "\f315";
-}
-
-.ion-bookmark:before {
- content: "\f26b";
-}
-
-.ion-bowtie:before {
- content: "\f3c0";
-}
-
-.ion-briefcase:before {
- content: "\f26c";
-}
-
-.ion-bug:before {
- content: "\f2be";
-}
-
-.ion-calculator:before {
- content: "\f26d";
-}
-
-.ion-calendar:before {
- content: "\f117";
-}
-
-.ion-camera:before {
- content: "\f118";
-}
-
-.ion-card:before {
- content: "\f119";
-}
-
-.ion-cash:before {
- content: "\f316";
-}
-
-.ion-chatbox:before {
- content: "\f11b";
-}
-
-.ion-chatbox-working:before {
- content: "\f11a";
-}
-
-.ion-chatboxes:before {
- content: "\f11c";
-}
-
-.ion-chatbubble:before {
- content: "\f11e";
-}
-
-.ion-chatbubble-working:before {
- content: "\f11d";
-}
-
-.ion-chatbubbles:before {
- content: "\f11f";
-}
-
-.ion-checkmark:before {
- content: "\f122";
-}
-
-.ion-checkmark-circled:before {
- content: "\f120";
-}
-
-.ion-checkmark-round:before {
- content: "\f121";
-}
-
-.ion-chevron-down:before {
- content: "\f123";
-}
-
-.ion-chevron-left:before {
- content: "\f124";
-}
-
-.ion-chevron-right:before {
- content: "\f125";
-}
-
-.ion-chevron-up:before {
- content: "\f126";
-}
-
-.ion-clipboard:before {
- content: "\f127";
-}
-
-.ion-clock:before {
- content: "\f26e";
-}
-
-.ion-close:before {
- content: "\f12a";
-}
-
-.ion-close-circled:before {
- content: "\f128";
-}
-
-.ion-close-round:before {
- content: "\f129";
-}
-
-.ion-closed-captioning:before {
- content: "\f317";
-}
-
-.ion-cloud:before {
- content: "\f12b";
-}
-
-.ion-code:before {
- content: "\f271";
-}
-
-.ion-code-download:before {
- content: "\f26f";
-}
-
-.ion-code-working:before {
- content: "\f270";
-}
-
-.ion-coffee:before {
- content: "\f272";
-}
-
-.ion-compass:before {
- content: "\f273";
-}
-
-.ion-compose:before {
- content: "\f12c";
-}
-
-.ion-connection-bars:before {
- content: "\f274";
-}
-
-.ion-contrast:before {
- content: "\f275";
-}
-
-.ion-crop:before {
- content: "\f3c1";
-}
-
-.ion-cube:before {
- content: "\f318";
-}
-
-.ion-disc:before {
- content: "\f12d";
-}
-
-.ion-document:before {
- content: "\f12f";
-}
-
-.ion-document-text:before {
- content: "\f12e";
-}
-
-.ion-drag:before {
- content: "\f130";
-}
-
-.ion-earth:before {
- content: "\f276";
-}
-
-.ion-easel:before {
- content: "\f3c2";
-}
-
-.ion-edit:before {
- content: "\f2bf";
-}
-
-.ion-egg:before {
- content: "\f277";
-}
-
-.ion-eject:before {
- content: "\f131";
-}
-
-.ion-email:before {
- content: "\f132";
-}
-
-.ion-email-unread:before {
- content: "\f3c3";
-}
-
-.ion-erlenmeyer-flask:before {
- content: "\f3c5";
-}
-
-.ion-erlenmeyer-flask-bubbles:before {
- content: "\f3c4";
-}
-
-.ion-eye:before {
- content: "\f133";
-}
-
-.ion-eye-disabled:before {
- content: "\f306";
-}
-
-.ion-female:before {
- content: "\f278";
-}
-
-.ion-filing:before {
- content: "\f134";
-}
-
-.ion-film-marker:before {
- content: "\f135";
-}
-
-.ion-fireball:before {
- content: "\f319";
-}
-
-.ion-flag:before {
- content: "\f279";
-}
-
-.ion-flame:before {
- content: "\f31a";
-}
-
-.ion-flash:before {
- content: "\f137";
-}
-
-.ion-flash-off:before {
- content: "\f136";
-}
-
-.ion-folder:before {
- content: "\f139";
-}
-
-.ion-fork:before {
- content: "\f27a";
-}
-
-.ion-fork-repo:before {
- content: "\f2c0";
-}
-
-.ion-forward:before {
- content: "\f13a";
-}
-
-.ion-funnel:before {
- content: "\f31b";
-}
-
-.ion-gear-a:before {
- content: "\f13d";
-}
-
-.ion-gear-b:before {
- content: "\f13e";
-}
-
-.ion-grid:before {
- content: "\f13f";
-}
-
-.ion-hammer:before {
- content: "\f27b";
-}
-
-.ion-happy:before {
- content: "\f31c";
-}
-
-.ion-happy-outline:before {
- content: "\f3c6";
-}
-
-.ion-headphone:before {
- content: "\f140";
-}
-
-.ion-heart:before {
- content: "\f141";
-}
-
-.ion-heart-broken:before {
- content: "\f31d";
-}
-
-.ion-help:before {
- content: "\f143";
-}
-
-.ion-help-buoy:before {
- content: "\f27c";
-}
-
-.ion-help-circled:before {
- content: "\f142";
-}
-
-.ion-home:before {
- content: "\f144";
-}
-
-.ion-icecream:before {
- content: "\f27d";
-}
-
-.ion-image:before {
- content: "\f147";
-}
-
-.ion-images:before {
- content: "\f148";
-}
-
-.ion-information:before {
- content: "\f14a";
-}
-
-.ion-information-circled:before {
- content: "\f149";
-}
-
-.ion-ionic:before {
- content: "\f14b";
-}
-
-.ion-ios-alarm:before {
- content: "\f3c8";
-}
-
-.ion-ios-alarm-outline:before {
- content: "\f3c7";
-}
-
-.ion-ios-albums:before {
- content: "\f3ca";
-}
-
-.ion-ios-albums-outline:before {
- content: "\f3c9";
-}
-
-.ion-ios-americanfootball:before {
- content: "\f3cc";
-}
-
-.ion-ios-americanfootball-outline:before {
- content: "\f3cb";
-}
-
-.ion-ios-analytics:before {
- content: "\f3ce";
-}
-
-.ion-ios-analytics-outline:before {
- content: "\f3cd";
-}
-
-.ion-ios-arrow-back:before {
- content: "\f3cf";
-}
-
-.ion-ios-arrow-down:before {
- content: "\f3d0";
-}
-
-.ion-ios-arrow-forward:before {
- content: "\f3d1";
-}
-
-.ion-ios-arrow-left:before {
- content: "\f3d2";
-}
-
-.ion-ios-arrow-right:before {
- content: "\f3d3";
-}
-
-.ion-ios-arrow-thin-down:before {
- content: "\f3d4";
-}
-
-.ion-ios-arrow-thin-left:before {
- content: "\f3d5";
-}
-
-.ion-ios-arrow-thin-right:before {
- content: "\f3d6";
-}
-
-.ion-ios-arrow-thin-up:before {
- content: "\f3d7";
-}
-
-.ion-ios-arrow-up:before {
- content: "\f3d8";
-}
-
-.ion-ios-at:before {
- content: "\f3da";
-}
-
-.ion-ios-at-outline:before {
- content: "\f3d9";
-}
-
-.ion-ios-barcode:before {
- content: "\f3dc";
-}
-
-.ion-ios-barcode-outline:before {
- content: "\f3db";
-}
-
-.ion-ios-baseball:before {
- content: "\f3de";
-}
-
-.ion-ios-baseball-outline:before {
- content: "\f3dd";
-}
-
-.ion-ios-basketball:before {
- content: "\f3e0";
-}
-
-.ion-ios-basketball-outline:before {
- content: "\f3df";
-}
-
-.ion-ios-bell:before {
- content: "\f3e2";
-}
-
-.ion-ios-bell-outline:before {
- content: "\f3e1";
-}
-
-.ion-ios-body:before {
- content: "\f3e4";
-}
-
-.ion-ios-body-outline:before {
- content: "\f3e3";
-}
-
-.ion-ios-bolt:before {
- content: "\f3e6";
-}
-
-.ion-ios-bolt-outline:before {
- content: "\f3e5";
-}
-
-.ion-ios-book:before {
- content: "\f3e8";
-}
-
-.ion-ios-book-outline:before {
- content: "\f3e7";
-}
-
-.ion-ios-bookmarks:before {
- content: "\f3ea";
-}
-
-.ion-ios-bookmarks-outline:before {
- content: "\f3e9";
-}
-
-.ion-ios-box:before {
- content: "\f3ec";
-}
-
-.ion-ios-box-outline:before {
- content: "\f3eb";
-}
-
-.ion-ios-briefcase:before {
- content: "\f3ee";
-}
-
-.ion-ios-briefcase-outline:before {
- content: "\f3ed";
-}
-
-.ion-ios-browsers:before {
- content: "\f3f0";
-}
-
-.ion-ios-browsers-outline:before {
- content: "\f3ef";
-}
-
-.ion-ios-calculator:before {
- content: "\f3f2";
-}
-
-.ion-ios-calculator-outline:before {
- content: "\f3f1";
-}
-
-.ion-ios-calendar:before {
- content: "\f3f4";
-}
-
-.ion-ios-calendar-outline:before {
- content: "\f3f3";
-}
-
-.ion-ios-camera:before {
- content: "\f3f6";
-}
-
-.ion-ios-camera-outline:before {
- content: "\f3f5";
-}
-
-.ion-ios-cart:before {
- content: "\f3f8";
-}
-
-.ion-ios-cart-outline:before {
- content: "\f3f7";
-}
-
-.ion-ios-chatboxes:before {
- content: "\f3fa";
-}
-
-.ion-ios-chatboxes-outline:before {
- content: "\f3f9";
-}
-
-.ion-ios-chatbubble:before {
- content: "\f3fc";
-}
-
-.ion-ios-chatbubble-outline:before {
- content: "\f3fb";
-}
-
-.ion-ios-checkmark:before {
- content: "\f3ff";
-}
-
-.ion-ios-checkmark-empty:before {
- content: "\f3fd";
-}
-
-.ion-ios-checkmark-outline:before {
- content: "\f3fe";
-}
-
-.ion-ios-circle-filled:before {
- content: "\f400";
-}
-
-.ion-ios-circle-outline:before {
- content: "\f401";
-}
-
-.ion-ios-clock:before {
- content: "\f403";
-}
-
-.ion-ios-clock-outline:before {
- content: "\f402";
-}
-
-.ion-ios-close:before {
- content: "\f406";
-}
-
-.ion-ios-close-empty:before {
- content: "\f404";
-}
-
-.ion-ios-close-outline:before {
- content: "\f405";
-}
-
-.ion-ios-cloud:before {
- content: "\f40c";
-}
-
-.ion-ios-cloud-download:before {
- content: "\f408";
-}
-
-.ion-ios-cloud-download-outline:before {
- content: "\f407";
-}
-
-.ion-ios-cloud-outline:before {
- content: "\f409";
-}
-
-.ion-ios-cloud-upload:before {
- content: "\f40b";
-}
-
-.ion-ios-cloud-upload-outline:before {
- content: "\f40a";
-}
-
-.ion-ios-cloudy:before {
- content: "\f410";
-}
-
-.ion-ios-cloudy-night:before {
- content: "\f40e";
-}
-
-.ion-ios-cloudy-night-outline:before {
- content: "\f40d";
-}
-
-.ion-ios-cloudy-outline:before {
- content: "\f40f";
-}
-
-.ion-ios-cog:before {
- content: "\f412";
-}
-
-.ion-ios-cog-outline:before {
- content: "\f411";
-}
-
-.ion-ios-color-filter:before {
- content: "\f414";
-}
-
-.ion-ios-color-filter-outline:before {
- content: "\f413";
-}
-
-.ion-ios-color-wand:before {
- content: "\f416";
-}
-
-.ion-ios-color-wand-outline:before {
- content: "\f415";
-}
-
-.ion-ios-compose:before {
- content: "\f418";
-}
-
-.ion-ios-compose-outline:before {
- content: "\f417";
-}
-
-.ion-ios-contact:before {
- content: "\f41a";
-}
-
-.ion-ios-contact-outline:before {
- content: "\f419";
-}
-
-.ion-ios-copy:before {
- content: "\f41c";
-}
-
-.ion-ios-copy-outline:before {
- content: "\f41b";
-}
-
-.ion-ios-crop:before {
- content: "\f41e";
-}
-
-.ion-ios-crop-strong:before {
- content: "\f41d";
-}
-
-.ion-ios-download:before {
- content: "\f420";
-}
-
-.ion-ios-download-outline:before {
- content: "\f41f";
-}
-
-.ion-ios-drag:before {
- content: "\f421";
-}
-
-.ion-ios-email:before {
- content: "\f423";
-}
-
-.ion-ios-email-outline:before {
- content: "\f422";
-}
-
-.ion-ios-eye:before {
- content: "\f425";
-}
-
-.ion-ios-eye-outline:before {
- content: "\f424";
-}
-
-.ion-ios-fastforward:before {
- content: "\f427";
-}
-
-.ion-ios-fastforward-outline:before {
- content: "\f426";
-}
-
-.ion-ios-filing:before {
- content: "\f429";
-}
-
-.ion-ios-filing-outline:before {
- content: "\f428";
-}
-
-.ion-ios-film:before {
- content: "\f42b";
-}
-
-.ion-ios-film-outline:before {
- content: "\f42a";
-}
-
-.ion-ios-flag:before {
- content: "\f42d";
-}
-
-.ion-ios-flag-outline:before {
- content: "\f42c";
-}
-
-.ion-ios-flame:before {
- content: "\f42f";
-}
-
-.ion-ios-flame-outline:before {
- content: "\f42e";
-}
-
-.ion-ios-flask:before {
- content: "\f431";
-}
-
-.ion-ios-flask-outline:before {
- content: "\f430";
-}
-
-.ion-ios-flower:before {
- content: "\f433";
-}
-
-.ion-ios-flower-outline:before {
- content: "\f432";
-}
-
-.ion-ios-folder:before {
- content: "\f435";
-}
-
-.ion-ios-folder-outline:before {
- content: "\f434";
-}
-
-.ion-ios-football:before {
- content: "\f437";
-}
-
-.ion-ios-football-outline:before {
- content: "\f436";
-}
-
-.ion-ios-game-controller-a:before {
- content: "\f439";
-}
-
-.ion-ios-game-controller-a-outline:before {
- content: "\f438";
-}
-
-.ion-ios-game-controller-b:before {
- content: "\f43b";
-}
-
-.ion-ios-game-controller-b-outline:before {
- content: "\f43a";
-}
-
-.ion-ios-gear:before {
- content: "\f43d";
-}
-
-.ion-ios-gear-outline:before {
- content: "\f43c";
-}
-
-.ion-ios-glasses:before {
- content: "\f43f";
-}
-
-.ion-ios-glasses-outline:before {
- content: "\f43e";
-}
-
-.ion-ios-grid-view:before {
- content: "\f441";
-}
-
-.ion-ios-grid-view-outline:before {
- content: "\f440";
-}
-
-.ion-ios-heart:before {
- content: "\f443";
-}
-
-.ion-ios-heart-outline:before {
- content: "\f442";
-}
-
-.ion-ios-help:before {
- content: "\f446";
-}
-
-.ion-ios-help-empty:before {
- content: "\f444";
-}
-
-.ion-ios-help-outline:before {
- content: "\f445";
-}
-
-.ion-ios-home:before {
- content: "\f448";
-}
-
-.ion-ios-home-outline:before {
- content: "\f447";
-}
-
-.ion-ios-infinite:before {
- content: "\f44a";
-}
-
-.ion-ios-infinite-outline:before {
- content: "\f449";
-}
-
-.ion-ios-information:before {
- content: "\f44d";
-}
-
-.ion-ios-information-empty:before {
- content: "\f44b";
-}
-
-.ion-ios-information-outline:before {
- content: "\f44c";
-}
-
-.ion-ios-ionic-outline:before {
- content: "\f44e";
-}
-
-.ion-ios-keypad:before {
- content: "\f450";
-}
-
-.ion-ios-keypad-outline:before {
- content: "\f44f";
-}
-
-.ion-ios-lightbulb:before {
- content: "\f452";
-}
-
-.ion-ios-lightbulb-outline:before {
- content: "\f451";
-}
-
-.ion-ios-list:before {
- content: "\f454";
-}
-
-.ion-ios-list-outline:before {
- content: "\f453";
-}
-
-.ion-ios-location:before {
- content: "\f456";
-}
-
-.ion-ios-location-outline:before {
- content: "\f455";
-}
-
-.ion-ios-locked:before {
- content: "\f458";
-}
-
-.ion-ios-locked-outline:before {
- content: "\f457";
-}
-
-.ion-ios-loop:before {
- content: "\f45a";
-}
-
-.ion-ios-loop-strong:before {
- content: "\f459";
-}
-
-.ion-ios-medical:before {
- content: "\f45c";
-}
-
-.ion-ios-medical-outline:before {
- content: "\f45b";
-}
-
-.ion-ios-medkit:before {
- content: "\f45e";
-}
-
-.ion-ios-medkit-outline:before {
- content: "\f45d";
-}
-
-.ion-ios-mic:before {
- content: "\f461";
-}
-
-.ion-ios-mic-off:before {
- content: "\f45f";
-}
-
-.ion-ios-mic-outline:before {
- content: "\f460";
-}
-
-.ion-ios-minus:before {
- content: "\f464";
-}
-
-.ion-ios-minus-empty:before {
- content: "\f462";
-}
-
-.ion-ios-minus-outline:before {
- content: "\f463";
-}
-
-.ion-ios-monitor:before {
- content: "\f466";
-}
-
-.ion-ios-monitor-outline:before {
- content: "\f465";
-}
-
-.ion-ios-moon:before {
- content: "\f468";
-}
-
-.ion-ios-moon-outline:before {
- content: "\f467";
-}
-
-.ion-ios-more:before {
- content: "\f46a";
-}
-
-.ion-ios-more-outline:before {
- content: "\f469";
-}
-
-.ion-ios-musical-note:before {
- content: "\f46b";
-}
-
-.ion-ios-musical-notes:before {
- content: "\f46c";
-}
-
-.ion-ios-navigate:before {
- content: "\f46e";
-}
-
-.ion-ios-navigate-outline:before {
- content: "\f46d";
-}
-
-.ion-ios-nutrition:before {
- content: "\f470";
-}
-
-.ion-ios-nutrition-outline:before {
- content: "\f46f";
-}
-
-.ion-ios-paper:before {
- content: "\f472";
-}
-
-.ion-ios-paper-outline:before {
- content: "\f471";
-}
-
-.ion-ios-paperplane:before {
- content: "\f474";
-}
-
-.ion-ios-paperplane-outline:before {
- content: "\f473";
-}
-
-.ion-ios-partlysunny:before {
- content: "\f476";
-}
-
-.ion-ios-partlysunny-outline:before {
- content: "\f475";
-}
-
-.ion-ios-pause:before {
- content: "\f478";
-}
-
-.ion-ios-pause-outline:before {
- content: "\f477";
-}
-
-.ion-ios-paw:before {
- content: "\f47a";
-}
-
-.ion-ios-paw-outline:before {
- content: "\f479";
-}
-
-.ion-ios-people:before {
- content: "\f47c";
-}
-
-.ion-ios-people-outline:before {
- content: "\f47b";
-}
-
-.ion-ios-person:before {
- content: "\f47e";
-}
-
-.ion-ios-person-outline:before {
- content: "\f47d";
-}
-
-.ion-ios-personadd:before {
- content: "\f480";
-}
-
-.ion-ios-personadd-outline:before {
- content: "\f47f";
-}
-
-.ion-ios-photos:before {
- content: "\f482";
-}
-
-.ion-ios-photos-outline:before {
- content: "\f481";
-}
-
-.ion-ios-pie:before {
- content: "\f484";
-}
-
-.ion-ios-pie-outline:before {
- content: "\f483";
-}
-
-.ion-ios-pint:before {
- content: "\f486";
-}
-
-.ion-ios-pint-outline:before {
- content: "\f485";
-}
-
-.ion-ios-play:before {
- content: "\f488";
-}
-
-.ion-ios-play-outline:before {
- content: "\f487";
-}
-
-.ion-ios-plus:before {
- content: "\f48b";
-}
-
-.ion-ios-plus-empty:before {
- content: "\f489";
-}
-
-.ion-ios-plus-outline:before {
- content: "\f48a";
-}
-
-.ion-ios-pricetag:before {
- content: "\f48d";
-}
-
-.ion-ios-pricetag-outline:before {
- content: "\f48c";
-}
-
-.ion-ios-pricetags:before {
- content: "\f48f";
-}
-
-.ion-ios-pricetags-outline:before {
- content: "\f48e";
-}
-
-.ion-ios-printer:before {
- content: "\f491";
-}
-
-.ion-ios-printer-outline:before {
- content: "\f490";
-}
-
-.ion-ios-pulse:before {
- content: "\f493";
-}
-
-.ion-ios-pulse-strong:before {
- content: "\f492";
-}
-
-.ion-ios-rainy:before {
- content: "\f495";
-}
-
-.ion-ios-rainy-outline:before {
- content: "\f494";
-}
-
-.ion-ios-recording:before {
- content: "\f497";
-}
-
-.ion-ios-recording-outline:before {
- content: "\f496";
-}
-
-.ion-ios-redo:before {
- content: "\f499";
-}
-
-.ion-ios-redo-outline:before {
- content: "\f498";
-}
-
-.ion-ios-refresh:before {
- content: "\f49c";
-}
-
-.ion-ios-refresh-empty:before {
- content: "\f49a";
-}
-
-.ion-ios-refresh-outline:before {
- content: "\f49b";
-}
-
-.ion-ios-reload:before {
- content: "\f49d";
-}
-
-.ion-ios-reverse-camera:before {
- content: "\f49f";
-}
-
-.ion-ios-reverse-camera-outline:before {
- content: "\f49e";
-}
-
-.ion-ios-rewind:before {
- content: "\f4a1";
-}
-
-.ion-ios-rewind-outline:before {
- content: "\f4a0";
-}
-
-.ion-ios-rose:before {
- content: "\f4a3";
-}
-
-.ion-ios-rose-outline:before {
- content: "\f4a2";
-}
-
-.ion-ios-search:before {
- content: "\f4a5";
-}
-
-.ion-ios-search-strong:before {
- content: "\f4a4";
-}
-
-.ion-ios-settings:before {
- content: "\f4a7";
-}
-
-.ion-ios-settings-strong:before {
- content: "\f4a6";
-}
-
-.ion-ios-shuffle:before {
- content: "\f4a9";
-}
-
-.ion-ios-shuffle-strong:before {
- content: "\f4a8";
-}
-
-.ion-ios-skipbackward:before {
- content: "\f4ab";
-}
-
-.ion-ios-skipbackward-outline:before {
- content: "\f4aa";
-}
-
-.ion-ios-skipforward:before {
- content: "\f4ad";
-}
-
-.ion-ios-skipforward-outline:before {
- content: "\f4ac";
-}
-
-.ion-ios-snowy:before {
- content: "\f4ae";
-}
-
-.ion-ios-speedometer:before {
- content: "\f4b0";
-}
-
-.ion-ios-speedometer-outline:before {
- content: "\f4af";
-}
-
-.ion-ios-star:before {
- content: "\f4b3";
-}
-
-.ion-ios-star-half:before {
- content: "\f4b1";
-}
-
-.ion-ios-star-outline:before {
- content: "\f4b2";
-}
-
-.ion-ios-stopwatch:before {
- content: "\f4b5";
-}
-
-.ion-ios-stopwatch-outline:before {
- content: "\f4b4";
-}
-
-.ion-ios-sunny:before {
- content: "\f4b7";
-}
-
-.ion-ios-sunny-outline:before {
- content: "\f4b6";
-}
-
-.ion-ios-telephone:before {
- content: "\f4b9";
-}
-
-.ion-ios-telephone-outline:before {
- content: "\f4b8";
-}
-
-.ion-ios-tennisball:before {
- content: "\f4bb";
-}
-
-.ion-ios-tennisball-outline:before {
- content: "\f4ba";
-}
-
-.ion-ios-thunderstorm:before {
- content: "\f4bd";
-}
-
-.ion-ios-thunderstorm-outline:before {
- content: "\f4bc";
-}
-
-.ion-ios-time:before {
- content: "\f4bf";
-}
-
-.ion-ios-time-outline:before {
- content: "\f4be";
-}
-
-.ion-ios-timer:before {
- content: "\f4c1";
-}
-
-.ion-ios-timer-outline:before {
- content: "\f4c0";
-}
-
-.ion-ios-toggle:before {
- content: "\f4c3";
-}
-
-.ion-ios-toggle-outline:before {
- content: "\f4c2";
-}
-
-.ion-ios-trash:before {
- content: "\f4c5";
-}
-
-.ion-ios-trash-outline:before {
- content: "\f4c4";
-}
-
-.ion-ios-undo:before {
- content: "\f4c7";
-}
-
-.ion-ios-undo-outline:before {
- content: "\f4c6";
-}
-
-.ion-ios-unlocked:before {
- content: "\f4c9";
-}
-
-.ion-ios-unlocked-outline:before {
- content: "\f4c8";
-}
-
-.ion-ios-upload:before {
- content: "\f4cb";
-}
-
-.ion-ios-upload-outline:before {
- content: "\f4ca";
-}
-
-.ion-ios-videocam:before {
- content: "\f4cd";
-}
-
-.ion-ios-videocam-outline:before {
- content: "\f4cc";
-}
-
-.ion-ios-volume-high:before {
- content: "\f4ce";
-}
-
-.ion-ios-volume-low:before {
- content: "\f4cf";
-}
-
-.ion-ios-wineglass:before {
- content: "\f4d1";
-}
-
-.ion-ios-wineglass-outline:before {
- content: "\f4d0";
-}
-
-.ion-ios-world:before {
- content: "\f4d3";
-}
-
-.ion-ios-world-outline:before {
- content: "\f4d2";
-}
-
-.ion-ipad:before {
- content: "\f1f9";
-}
-
-.ion-iphone:before {
- content: "\f1fa";
-}
-
-.ion-ipod:before {
- content: "\f1fb";
-}
-
-.ion-jet:before {
- content: "\f295";
-}
-
-.ion-key:before {
- content: "\f296";
-}
-
-.ion-knife:before {
- content: "\f297";
-}
-
-.ion-laptop:before {
- content: "\f1fc";
-}
-
-.ion-leaf:before {
- content: "\f1fd";
-}
-
-.ion-levels:before {
- content: "\f298";
-}
-
-.ion-lightbulb:before {
- content: "\f299";
-}
-
-.ion-link:before {
- content: "\f1fe";
-}
-
-.ion-load-a:before {
- content: "\f29a";
-}
-
-.ion-load-b:before {
- content: "\f29b";
-}
-
-.ion-load-c:before {
- content: "\f29c";
-}
-
-.ion-load-d:before {
- content: "\f29d";
-}
-
-.ion-location:before {
- content: "\f1ff";
-}
-
-.ion-lock-combination:before {
- content: "\f4d4";
-}
-
-.ion-locked:before {
- content: "\f200";
-}
-
-.ion-log-in:before {
- content: "\f29e";
-}
-
-.ion-log-out:before {
- content: "\f29f";
-}
-
-.ion-loop:before {
- content: "\f201";
-}
-
-.ion-magnet:before {
- content: "\f2a0";
-}
-
-.ion-male:before {
- content: "\f2a1";
-}
-
-.ion-man:before {
- content: "\f202";
-}
-
-.ion-map:before {
- content: "\f203";
-}
-
-.ion-medkit:before {
- content: "\f2a2";
-}
-
-.ion-merge:before {
- content: "\f33f";
-}
-
-.ion-mic-a:before {
- content: "\f204";
-}
-
-.ion-mic-b:before {
- content: "\f205";
-}
-
-.ion-mic-c:before {
- content: "\f206";
-}
-
-.ion-minus:before {
- content: "\f209";
-}
-
-.ion-minus-circled:before {
- content: "\f207";
-}
-
-.ion-minus-round:before {
- content: "\f208";
-}
-
-.ion-model-s:before {
- content: "\f2c1";
-}
-
-.ion-monitor:before {
- content: "\f20a";
-}
-
-.ion-more:before {
- content: "\f20b";
-}
-
-.ion-mouse:before {
- content: "\f340";
-}
-
-.ion-music-note:before {
- content: "\f20c";
-}
-
-.ion-navicon:before {
- content: "\f20e";
-}
-
-.ion-navicon-round:before {
- content: "\f20d";
-}
-
-.ion-navigate:before {
- content: "\f2a3";
-}
-
-.ion-network:before {
- content: "\f341";
-}
-
-.ion-no-smoking:before {
- content: "\f2c2";
-}
-
-.ion-nuclear:before {
- content: "\f2a4";
-}
-
-.ion-outlet:before {
- content: "\f342";
-}
-
-.ion-paintbrush:before {
- content: "\f4d5";
-}
-
-.ion-paintbucket:before {
- content: "\f4d6";
-}
-
-.ion-paper-airplane:before {
- content: "\f2c3";
-}
-
-.ion-paperclip:before {
- content: "\f20f";
-}
-
-.ion-pause:before {
- content: "\f210";
-}
-
-.ion-person:before {
- content: "\f213";
-}
-
-.ion-person-add:before {
- content: "\f211";
-}
-
-.ion-person-stalker:before {
- content: "\f212";
-}
-
-.ion-pie-graph:before {
- content: "\f2a5";
-}
-
-.ion-pin:before {
- content: "\f2a6";
-}
-
-.ion-pinpoint:before {
- content: "\f2a7";
-}
-
-.ion-pizza:before {
- content: "\f2a8";
-}
-
-.ion-plane:before {
- content: "\f214";
-}
-
-.ion-planet:before {
- content: "\f343";
-}
-
-.ion-play:before {
- content: "\f215";
-}
-
-.ion-playstation:before {
- content: "\f30a";
-}
-
-.ion-plus:before {
- content: "\f218";
-}
-
-.ion-plus-circled:before {
- content: "\f216";
-}
-
-.ion-plus-round:before {
- content: "\f217";
-}
-
-.ion-podium:before {
- content: "\f344";
-}
-
-.ion-pound:before {
- content: "\f219";
-}
-
-.ion-power:before {
- content: "\f2a9";
-}
-
-.ion-pricetag:before {
- content: "\f2aa";
-}
-
-.ion-pricetags:before {
- content: "\f2ab";
-}
-
-.ion-printer:before {
- content: "\f21a";
-}
-
-.ion-pull-request:before {
- content: "\f345";
-}
-
-.ion-qr-scanner:before {
- content: "\f346";
-}
-
-.ion-quote:before {
- content: "\f347";
-}
-
-.ion-radio-waves:before {
- content: "\f2ac";
-}
-
-.ion-record:before {
- content: "\f21b";
-}
-
-.ion-refresh:before {
- content: "\f21c";
-}
-
-.ion-reply:before {
- content: "\f21e";
-}
-
-.ion-reply-all:before {
- content: "\f21d";
-}
-
-.ion-ribbon-a:before {
- content: "\f348";
-}
-
-.ion-ribbon-b:before {
- content: "\f349";
-}
-
-.ion-sad:before {
- content: "\f34a";
-}
-
-.ion-sad-outline:before {
- content: "\f4d7";
-}
-
-.ion-scissors:before {
- content: "\f34b";
-}
-
-.ion-search:before {
- content: "\f21f";
-}
-
-.ion-settings:before {
- content: "\f2ad";
-}
-
-.ion-share:before {
- content: "\f220";
-}
-
-.ion-shuffle:before {
- content: "\f221";
-}
-
-.ion-skip-backward:before {
- content: "\f222";
-}
-
-.ion-skip-forward:before {
- content: "\f223";
-}
-
-.ion-social-android:before {
- content: "\f225";
-}
-
-.ion-social-android-outline:before {
- content: "\f224";
-}
-
-.ion-social-angular:before {
- content: "\f4d9";
-}
-
-.ion-social-angular-outline:before {
- content: "\f4d8";
-}
-
-.ion-social-apple:before {
- content: "\f227";
-}
-
-.ion-social-apple-outline:before {
- content: "\f226";
-}
-
-.ion-social-bitcoin:before {
- content: "\f2af";
-}
-
-.ion-social-bitcoin-outline:before {
- content: "\f2ae";
-}
-
-.ion-social-buffer:before {
- content: "\f229";
-}
-
-.ion-social-buffer-outline:before {
- content: "\f228";
-}
-
-.ion-social-chrome:before {
- content: "\f4db";
-}
-
-.ion-social-chrome-outline:before {
- content: "\f4da";
-}
-
-.ion-social-codepen:before {
- content: "\f4dd";
-}
-
-.ion-social-codepen-outline:before {
- content: "\f4dc";
-}
-
-.ion-social-css3:before {
- content: "\f4df";
-}
-
-.ion-social-css3-outline:before {
- content: "\f4de";
-}
-
-.ion-social-designernews:before {
- content: "\f22b";
-}
-
-.ion-social-designernews-outline:before {
- content: "\f22a";
-}
-
-.ion-social-dribbble:before {
- content: "\f22d";
-}
-
-.ion-social-dribbble-outline:before {
- content: "\f22c";
-}
-
-.ion-social-dropbox:before {
- content: "\f22f";
-}
-
-.ion-social-dropbox-outline:before {
- content: "\f22e";
-}
-
-.ion-social-euro:before {
- content: "\f4e1";
-}
-
-.ion-social-euro-outline:before {
- content: "\f4e0";
-}
-
-.ion-social-facebook:before {
- content: "\f231";
-}
-
-.ion-social-facebook-outline:before {
- content: "\f230";
-}
-
-.ion-social-foursquare:before {
- content: "\f34d";
-}
-
-.ion-social-foursquare-outline:before {
- content: "\f34c";
-}
-
-.ion-social-freebsd-devil:before {
- content: "\f2c4";
-}
-
-.ion-social-github:before {
- content: "\f233";
-}
-
-.ion-social-github-outline:before {
- content: "\f232";
-}
-
-.ion-social-google:before {
- content: "\f34f";
-}
-
-.ion-social-google-outline:before {
- content: "\f34e";
-}
-
-.ion-social-googleplus:before {
- content: "\f235";
-}
-
-.ion-social-googleplus-outline:before {
- content: "\f234";
-}
-
-.ion-social-hackernews:before {
- content: "\f237";
-}
-
-.ion-social-hackernews-outline:before {
- content: "\f236";
-}
-
-.ion-social-html5:before {
- content: "\f4e3";
-}
-
-.ion-social-html5-outline:before {
- content: "\f4e2";
-}
-
-.ion-social-instagram:before {
- content: "\f351";
-}
-
-.ion-social-instagram-outline:before {
- content: "\f350";
-}
-
-.ion-social-javascript:before {
- content: "\f4e5";
-}
-
-.ion-social-javascript-outline:before {
- content: "\f4e4";
-}
-
-.ion-social-linkedin:before {
- content: "\f239";
-}
-
-.ion-social-linkedin-outline:before {
- content: "\f238";
-}
-
-.ion-social-markdown:before {
- content: "\f4e6";
-}
-
-.ion-social-nodejs:before {
- content: "\f4e7";
-}
-
-.ion-social-octocat:before {
- content: "\f4e8";
-}
-
-.ion-social-pinterest:before {
- content: "\f2b1";
-}
-
-.ion-social-pinterest-outline:before {
- content: "\f2b0";
-}
-
-.ion-social-python:before {
- content: "\f4e9";
-}
-
-.ion-social-reddit:before {
- content: "\f23b";
-}
-
-.ion-social-reddit-outline:before {
- content: "\f23a";
-}
-
-.ion-social-rss:before {
- content: "\f23d";
-}
-
-.ion-social-rss-outline:before {
- content: "\f23c";
-}
-
-.ion-social-sass:before {
- content: "\f4ea";
-}
-
-.ion-social-skype:before {
- content: "\f23f";
-}
-
-.ion-social-skype-outline:before {
- content: "\f23e";
-}
-
-.ion-social-snapchat:before {
- content: "\f4ec";
-}
-
-.ion-social-snapchat-outline:before {
- content: "\f4eb";
-}
-
-.ion-social-tumblr:before {
- content: "\f241";
-}
-
-.ion-social-tumblr-outline:before {
- content: "\f240";
-}
-
-.ion-social-tux:before {
- content: "\f2c5";
-}
-
-.ion-social-twitch:before {
- content: "\f4ee";
-}
-
-.ion-social-twitch-outline:before {
- content: "\f4ed";
-}
-
-.ion-social-twitter:before {
- content: "\f243";
-}
-
-.ion-social-twitter-outline:before {
- content: "\f242";
-}
-
-.ion-social-usd:before {
- content: "\f353";
-}
-
-.ion-social-usd-outline:before {
- content: "\f352";
-}
-
-.ion-social-vimeo:before {
- content: "\f245";
-}
-
-.ion-social-vimeo-outline:before {
- content: "\f244";
-}
-
-.ion-social-whatsapp:before {
- content: "\f4f0";
-}
-
-.ion-social-whatsapp-outline:before {
- content: "\f4ef";
-}
-
-.ion-social-windows:before {
- content: "\f247";
-}
-
-.ion-social-windows-outline:before {
- content: "\f246";
-}
-
-.ion-social-wordpress:before {
- content: "\f249";
-}
-
-.ion-social-wordpress-outline:before {
- content: "\f248";
-}
-
-.ion-social-yahoo:before {
- content: "\f24b";
-}
-
-.ion-social-yahoo-outline:before {
- content: "\f24a";
-}
-
-.ion-social-yen:before {
- content: "\f4f2";
-}
-
-.ion-social-yen-outline:before {
- content: "\f4f1";
-}
-
-.ion-social-youtube:before {
- content: "\f24d";
-}
-
-.ion-social-youtube-outline:before {
- content: "\f24c";
-}
-
-.ion-soup-can:before {
- content: "\f4f4";
-}
-
-.ion-soup-can-outline:before {
- content: "\f4f3";
-}
-
-.ion-speakerphone:before {
- content: "\f2b2";
-}
-
-.ion-speedometer:before {
- content: "\f2b3";
-}
-
-.ion-spoon:before {
- content: "\f2b4";
-}
-
-.ion-star:before {
- content: "\f24e";
-}
-
-.ion-stats-bars:before {
- content: "\f2b5";
-}
-
-.ion-steam:before {
- content: "\f30b";
-}
-
-.ion-stop:before {
- content: "\f24f";
-}
-
-.ion-thermometer:before {
- content: "\f2b6";
-}
-
-.ion-thumbsdown:before {
- content: "\f250";
-}
-
-.ion-thumbsup:before {
- content: "\f251";
-}
-
-.ion-toggle:before {
- content: "\f355";
-}
-
-.ion-toggle-filled:before {
- content: "\f354";
-}
-
-.ion-transgender:before {
- content: "\f4f5";
-}
-
-.ion-trash-a:before {
- content: "\f252";
-}
-
-.ion-trash-b:before {
- content: "\f253";
-}
-
-.ion-trophy:before {
- content: "\f356";
-}
-
-.ion-tshirt:before {
- content: "\f4f7";
-}
-
-.ion-tshirt-outline:before {
- content: "\f4f6";
-}
-
-.ion-umbrella:before {
- content: "\f2b7";
-}
-
-.ion-university:before {
- content: "\f357";
-}
-
-.ion-unlocked:before {
- content: "\f254";
-}
-
-.ion-upload:before {
- content: "\f255";
-}
-
-.ion-usb:before {
- content: "\f2b8";
-}
-
-.ion-videocamera:before {
- content: "\f256";
-}
-
-.ion-volume-high:before {
- content: "\f257";
-}
-
-.ion-volume-low:before {
- content: "\f258";
-}
-
-.ion-volume-medium:before {
- content: "\f259";
-}
-
-.ion-volume-mute:before {
- content: "\f25a";
-}
-
-.ion-wand:before {
- content: "\f358";
-}
-
-.ion-waterdrop:before {
- content: "\f25b";
-}
-
-.ion-wifi:before {
- content: "\f25c";
-}
-
-.ion-wineglass:before {
- content: "\f2b9";
-}
-
-.ion-woman:before {
- content: "\f25d";
-}
-
-.ion-wrench:before {
- content: "\f2ba";
-}
-
-.ion-xbox:before {
- content: "\f30c";
-}
-
-/*# sourceMappingURL=ionicons.css.map */
diff --git a/app/assets/stylesheets/app/_editor.scss b/app/assets/stylesheets/app/_editor.scss
index 0860d57be..a1afdd7bb 100644
--- a/app/assets/stylesheets/app/_editor.scss
+++ b/app/assets/stylesheets/app/_editor.scss
@@ -1,25 +1,10 @@
$heading-height: 75px;
.editor {
flex: 1 50%;
- min-width: 300px;
display: flex;
flex-direction: column;
overflow-y: hidden;
background-color: white;
-
- &.fullscreen {
- width: 100%;
- position: absolute;
- left: 0px;
- top: 0px;
- z-index: 200;
- padding: 0;
- }
-
- .section-menu-bar {
- flex: 1 0 28px;
- max-height: 28px;
- }
}
#editor-title-bar {
@@ -37,10 +22,6 @@ $heading-height: 75px;
height: auto;
overflow: visible;
- &.fullscreen {
- position: relative;
- }
-
> .title {
font-size: 18px;
font-weight: bold;
@@ -87,7 +68,7 @@ $heading-height: 75px;
#note-tags-component-container {
height: 50px;
- #note-tags-iframe {
+ iframe {
height: 50px;
width: 100%;
position: absolute;
@@ -103,7 +84,7 @@ $heading-height: 75px;
}
}
-.editor-content {
+.editor-content, #editor-content {
flex: 1;
z-index: 10;
overflow-y: hidden;
@@ -111,9 +92,7 @@ $heading-height: 75px;
display: flex;
background-color: white;
- &.fullscreen {
- padding-top: 0px;
- }
+ position: relative;
#editor-iframe {
flex: 1;
@@ -122,7 +101,6 @@ $heading-height: 75px;
.editable {
font-family: monospace;
- flex: 1;
overflow-y: scroll;
width: 100%;
@@ -132,54 +110,16 @@ $heading-height: 75px;
padding-top: 11px;
font-size: 17px;
resize: none;
-
- &.fullscreen {
- padding: 85px 10%;
- max-width: 1200px;
- display: inline-block;
- margin-left: auto;
- margin-right: auto;
- }
}
}
#editor-pane-component-stack {
width: 100%;
- .component {
- height: 50px;
+ .component-stack-item {
width: 100%;
position: relative;
- &:not(:last-child) {
- border-bottom: 1px solid $bg-color;
- }
-
- &:first-child {
- border-top: 1px solid $bg-color;
- }
-
- .exit-button {
- width: 15px;
- height: 100%;
- position: absolute;
- right: 0;
- background-color: transparent;
- cursor: pointer;
- display: flex;
- align-items: center;
- color: rgba(black, 0.7);
- text-align: center;
- padding-left: 2px;
-
- .content {
-
- }
-
- &:hover {
- background-color: rgba(gray, 0.3);
- }
- }
-
+ border-top: 1px solid $bg-color;
iframe {
width: 100%;
}
diff --git a/app/assets/stylesheets/app/_extensions.scss b/app/assets/stylesheets/app/_extensions.scss
deleted file mode 100644
index 71edefcdb..000000000
--- a/app/assets/stylesheets/app/_extensions.scss
+++ /dev/null
@@ -1,97 +0,0 @@
-.extension-render-modal {
- position: fixed;
- margin-left: auto;
- margin-right: auto;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- z-index: 10000;
- width: 100vw;
- height: 100vh;
- background-color: rgba(gray, 0.3);
- color: black;
-
- .content {
- box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
- background-color: white;
- width: 700px;
- height: 500px;
- margin: auto;
- padding: 25px;
- position: absolute;
- top: 0; left: 0; bottom: 0; right: 0;
- overflow-y: scroll;
- }
-}
-
-#global-ext-menu {
- color: black;
- .panel-body {
- padding: 0;
- }
-
- .container {
- padding: 13px 18px;
-
- &.no-bottom {
- padding-bottom: 0;
- }
- }
-
- p {
- font-size: 14px;
-
- &.small {
- font-size: 12px;
- }
- }
-
- .link-group {
- a {
- margin-right: 2px;
- }
- }
-
- .dashboard-link {
- padding-top: 12px;
- font-weight: normal;
- }
-
- .section-margin {
- margin-top: 20px;
- }
-
- input {
- border: 1px solid $blue-color;
- border-radius: 2px;
- }
-
- .header {
- padding-bottom: 12px;
- }
-
- ul {
- border-top: 1px solid $light-bg-color;
- border-bottom: 1px solid $light-bg-color;
- margin: 0;
- padding: 0;
-
- li {
- cursor: pointer;
- background-color: rgba($light-bg-color, 0.2);
- &:hover {
- background-color: rgba($light-bg-color, 0.4);
- }
- &:not(:last-child) {
- border-bottom: 1px solid $light-bg-color;
- }
- }
- }
-
-}
-
-ul {
- margin: 0;
- padding: 0;
-}
diff --git a/app/assets/stylesheets/app/_footer.scss b/app/assets/stylesheets/app/_footer.scss
index ac85969c9..950331dea 100644
--- a/app/assets/stylesheets/app/_footer.scss
+++ b/app/assets/stylesheets/app/_footer.scss
@@ -1,221 +1,48 @@
-.fake-link {
- font-weight: bold;
- cursor: pointer;
-
- &:hover {
- text-decoration: underline;
- }
-}
-
-h2 {
- margin-bottom: 0px;
- margin-top: 0px;
-}
-
#footer-bar {
position: relative;
width: 100%;
- padding: 5px;
- background-color: #f1f1f1;
- border-top: 1px solid rgba(black, 0.04);
height: $footer-height;
max-height: $footer-height;
z-index: 100;
- font-size: 10px;
- color: $dark-gray;
-
- .medium-text {
- font-size: 14px;
- }
-
- a {
- font-weight: bold;
- cursor: pointer;
-
- &.gray {
- color: $dark-gray;
- }
-
- &.block {
- display: block;
- }
- }
-
- p {
- margin: 2px 0px;
- font-size: 12px;
- }
-
- label {
- font-weight: bold;
- margin-bottom: 4px;
- }
-
- h1 {
- font-size: 16px;
- }
-
- h3 {
- font-size: 14px;
- margin-top: 4px;
- margin-bottom: 3px;
- }
-
- h4 {
- margin-bottom: 4px;
- font-size: 13px;
- }
-
- section {
- padding: 5px;
- padding-bottom: 2px;
- margin-top: 5px;
-
- &.inline-h {
- padding-top: 5px;
- padding-left: 0;
- padding-right: 0;
- }
-
- }
-
- input {
- // margin-bottom: 10px;
- border-radius: 0px;
- }
}
-#footer-bar .footer-bar-link {
- font-size: 11px;
- font-weight: bold;
- margin-left: 8px;
- color: #515263;
-
+#footer-bar .item {
z-index: 1000;
- display: inline-block;
position: relative;
- cursor: pointer;
-
user-select: none;
- > a {
- color: #515263;
+ .panel {
+ max-height: 85vh;
+ position: absolute;
+ right: 0px;
+ left: 10px;
+ bottom: 40px;
+ min-width: 300px;
+ z-index: 1000;
+ margin-top: 15px;
+ background-color: white;
}
+
}
-.footer-bar-link .panel {
- font-weight: normal;
- font-size: 12px;
+#account-panel {
+ width: 400px;
+}
- max-height: 85vh;
- position: absolute;
- right: 0px;
- bottom: 20px;
- min-width: 300px;
- z-index: 1000;
- margin-top: 15px;
-
- box-shadow: 0px 0px 15px rgba(black, 0.2);
- border: none;
+.panel {
cursor: default;
- overflow: auto;
- background-color: white;
-}
-
-button.light {
- font-weight: bold;
- margin-bottom: 0px;
- font-size: 12px;
- height: 30px;
- padding-top: 3px;
- text-align: center;
- margin-bottom: 6px;
- background-color: white;
- display: block;
- width: 100%;
- border: 1px solid rgba(gray, 0.15);
- cursor: pointer;
-
- &:hover {
- background-color: rgba(gray, 0.10);
- }
-}
-
-.half-button {
- $spacing: 2px;
- width: calc(50% - #{$spacing});
- margin-left: $spacing/2.0;
- margin-right: $spacing/2.0;
- float: left;
-}
-
-.gray-bg {
- background-color: #f6f6f6;
- border: 1px solid #f2f2f2;
-}
-
-.white-bg {
- background-color: white;
- border: 1px solid rgba(gray, 0.2);
}
a.disabled {
pointer-events: none;
}
+#lock-item {
+ margin-left: 3px;
+}
.icon.ion-locked {
margin-left: 5px;
border-left: 1px solid gray;
padding-left: 8px;
}
-
-
-
-
-/* Global Ext Menu */
-
-.ext-section {
-
- min-height: 50px;
-
- h1 {
- margin: 0;
- padding: 0;
- padding-top: 5px;
- }
-
- &.opened {
- h1 {
- padding-top: 0px;
- // padding-bottom: 6px;
- }
- }
-
-}
-
-
-
-
-
-
-
-
-.spinner {
- height: 10px;
- width: 10px;
- animation: rotate 0.8s infinite linear;
- border: 1px solid #515263;
- border-right-color: transparent;
- border-radius: 50%;
-
- &.tinted {
- border: 1px solid $blue-color;
- border-right-color: transparent;
- }
-}
-
-@keyframes rotate {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
-}
diff --git a/app/assets/stylesheets/app/_ionicons.scss b/app/assets/stylesheets/app/_ionicons.scss
new file mode 100644
index 000000000..884e1f781
--- /dev/null
+++ b/app/assets/stylesheets/app/_ionicons.scss
@@ -0,0 +1,24 @@
+@charset "UTF-8";
+/*!
+ Ionicons, v2.0.1
+ Created by Ben Sperry for the Ionic Framework, http://ionicons.com/
+ https://twitter.com/benjsperry https://twitter.com/ionicframework
+ MIT License: https://github.com/driftyco/ionicons
+
+ Android-style icons originally built by Google’s
+ Material Design Icons: https://github.com/google/material-design-icons
+ used under CC BY http://creativecommons.org/licenses/by/4.0/
+ Modified icons to fit ionicon’s grid from original.
+*/
+@font-face { font-family: "Ionicons"; src: url("../assets/ionicons.eot?v=2.0.0"); src: url("../assets/ionicons.eot?v=2.0.1#iefix") format("embedded-opentype"), url("../assets/ionicons.ttf?v=2.0.1") format("truetype"), url("../assets/ionicons.woff?v=2.0.1") format("woff"), url("../assets/ionicons.svg?v=2.0.1#Ionicons") format("svg"); font-weight: normal; font-style: normal; }
+.ion, .ionicons, .ion-ios-box:before, .ion-bookmark:before, .ion-locked:before { display: inline-block; font-family: "Ionicons"; speak: none; font-style: normal; font-weight: normal; font-variant: normal; text-transform: none; text-rendering: auto; line-height: 1; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
+
+.ion-ios-box:before { content: "\f3ec"; }
+
+.ion-locked:before { content: "\f200"; }
+
+.ion-bookmark:before {
+ content: "\f26b";
+}
+
+/*# sourceMappingURL=ionicons.css.map */
diff --git a/app/assets/stylesheets/app/_lock-screen.scss b/app/assets/stylesheets/app/_lock-screen.scss
index 4fef13adb..5b0fe4ba9 100644
--- a/app/assets/stylesheets/app/_lock-screen.scss
+++ b/app/assets/stylesheets/app/_lock-screen.scss
@@ -14,6 +14,7 @@
font-size: 16px;
display: flex;
align-items: center;
+ justify-content: center;
.background {
position: absolute;
@@ -22,30 +23,12 @@
height: 100%;
}
- .content {
- // box-shadow: 0 3px 3px rgba(0, 0, 0, 0.175);
- border: 1px solid rgba(black, 0.1);
- background-color: white;
- width: 300px;
- // height: 500px;
- margin: auto;
- padding: 10px 30px;
- padding-bottom: 30px;
- // position: absolute;
- // top: 0; left: 0; bottom: 0; right: 0;
- overflow-y: scroll;
+ .panel {
+ width: 315px;
+ flex-grow: 0;
- p {
- margin-bottom: 8px;
- margin-top: 0;
- }
-
- h3 {
- margin-bottom: 0;
- }
-
- h4 {
- margin-bottom: 6px;
+ .header {
+ justify-content: center;
}
}
}
diff --git a/app/assets/stylesheets/app/_main.scss b/app/assets/stylesheets/app/_main.scss
index 83d9f0bad..45228e125 100644
--- a/app/assets/stylesheets/app/_main.scss
+++ b/app/assets/stylesheets/app/_main.scss
@@ -6,56 +6,6 @@ $selection-color: $bg-color;
$selected-text-color: black;
$blue-color: #086dd6;
-@mixin MQ-Small() {
- @media (max-width: $screen-xs-max) {
- @content;
- }
-
- @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
- @content;
- }
-}
-
-@mixin MQ-Medium() {
- @media (min-width: $screen-md-min) and (max-width: $screen-md-max) {
- @content;
- }
-}
-
-
-@mixin MQ-Large() {
- @media (min-width: $screen-lg-min) {
- @content;
- }
-}
-
-.tinted {
- color: $blue-color;
-}
-
-.tinted-selected {
- color: white;
-}
-
-.tinted-box {
- background-color: $blue-color;
- color: white;
- border-radius: 4px;
- padding: 16px 20px;
-
- button {
- background-color: white;
- color: $blue-color;
- border-radius: 3px;
- font-weight: bold;
- padding: 6px 20px;
- width: 100%;
- &:hover {
- text-decoration: underline;
- }
- }
-}
-
html,
body {
font-family: -apple-system, BlinkMacSystemFont,
@@ -66,34 +16,49 @@ body {
-webkit-font-smoothing: antialiased;
min-height: 100%;
height: 100%;
- font-size: 20px;
+ font-size: 14px;
margin: 0;
background-color: $bg-color;
}
-.dark-button {
- background-color: #2e2e2e;
- border: 0;
- padding: 6px 18px;
- font-size: 16px;
- cursor: pointer;
- color: #fff;
- border-radius: 2px;
- border: 1px solid transparent;
- -webkit-appearance: none;
- -webkit-font-smoothing: antialiased;
- -webkit-tap-highlight-color: transparent;
+* {
+ box-sizing: border-box;
+}
- &:hover {
- background-color: black;
- }
+.tinted {
+ color: $blue-color;
+}
+
+.tinted-selected {
+ color: white;
+}
+
+*:focus {outline:0;}
+
+button:focus {
+ outline:0;
+}
+
+input, button, select, textarea {
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
}
a {
color: $blue-color;
text-decoration: none;
+
+ &.no-decoration {
+ color: inherit;
+ }
+
&:hover {
- text-decoration: underline;;
+ text-decoration: underline;
+
+ &.no-decoration {
+ text-decoration: none;
+ }
}
}
@@ -108,12 +73,9 @@ p {
background-color: $bg-color;
}
-$footer-height: 25px;
-
-$section-header-height: 70px;
+$footer-height: 32px;
.app {
- // height: 100%;
height: calc(100% - #{$footer-height});
width: 100%;
display: flex;
@@ -121,18 +83,38 @@ $section-header-height: 70px;
overflow: hidden;
position: relative;
- .light-button {
- background-color: $bg-color;
- font-weight: bold;
- color: $main-text-color;
- font-size: 16px;
- text-align: center;
- height: 35px;
- border-radius: 4px;
- padding-top: 6px;
+ panel-resizer {
+ top: 0;
+ right: 0;
+ z-index: 1;
+ width: 8px;
+ height: 100%;
+ position: absolute;
+ cursor: col-resize;
+ background-color: rgb(224, 224, 224);
+ opacity: 0;
- &:hover {
- background-color: #cdcdcd;
+ &.left {
+ left: 0;
+ right: none;
+ }
+
+ &.always-visible {
+ opacity: 1;
+ }
+
+ &.collapsed {
+ opacity: 1;
+ }
+
+ &.dragging {
+ opacity: 1;
+ }
+
+ &.hoverable {
+ &:hover {
+ opacity: 1;
+ }
}
}
@@ -141,6 +123,8 @@ $section-header-height: 70px;
height: 100%;
max-height: calc(100vh - #{$footer-height});
font-size: 17px;
+ position: relative;
+ overflow: hidden;
.scrollable {
overflow-y: auto;
@@ -155,34 +139,42 @@ $section-header-height: 70px;
}
.section-title-bar {
- padding: 20px;
- height: $section-header-height;
font-weight: bold;
font-size: 14px;
- > .title {
- float: left;
- white-space: nowrap;
- text-overflow: ellipsis;
- width: 80%;
- overflow: hidden;
+ .padded {
+ padding: 0 14px;
}
- > .add-button {
- float: right;
- font-size: 18px;
- width: 45px;
- height: 24px;
- cursor: pointer;
- background-color: #e9e9e9;
- border-radius: 4px;
- font-weight: normal;
- text-align: center;
- position: absolute;
- right: 12px;
+ .section-title-bar-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ overflow: hidden;
- &:hover {
- background-color: rgba(#e9e9e9, 0.8);
+ > .title {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ width: 80%;
+ overflow: hidden;
+ }
+
+ > .add-button {
+ $button-bg: #e9e9e9;
+ color: lighten($main-text-color, 40%);
+ font-size: 18px;
+ width: 45px;
+ height: 24px;
+ cursor: pointer;
+ background-color: $button-bg;
+ border-radius: 4px;
+ font-weight: normal;
+ text-align: center;
+
+ &:hover {
+ background-color: darken($button-bg, 5%);
+ color: lighten($main-text-color, 40%);
+ }
}
}
}
diff --git a/app/assets/stylesheets/app/_menus.scss b/app/assets/stylesheets/app/_menus.scss
index e1bfbd4af..362eaf767 100644
--- a/app/assets/stylesheets/app/_menus.scss
+++ b/app/assets/stylesheets/app/_menus.scss
@@ -1,243 +1,20 @@
-ul.section-menu-bar {
- width: 100%;
- padding-top: 0px;
- padding-left: 6px;
- padding-right: 21px;
-
- user-select: none;
-
- background-color: #f1f1f1;
- color: $selected-text-color;
- height: 28px;
- cursor: default;
-
- margin-top: 0px;
- margin-bottom: 0;
- list-style: none;
- font-weight: bold;
- font-size: 0; /* trick to remove gaps between li inline-block elements */
-
- > li {
- padding: 6px 8px;
- text-align: left;
- display: inline-block;
+.app-bar {
+ .item {
position: relative;
-
- font-size: 13px;
- font-weight: bold;
- user-select: none;
-
- &.full-width {
- width: 100%;
- }
-
- &.item-with-subtitle {
- label {
- // float: left;
- margin-right: 8px;
- }
-
- .subtitle {
- margin-top: 1px;
- opacity: 0.5;
- font-weight: normal;
- font-size: 12px;
-
- overflow: hidden;
- text-overflow: ellipsis;
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 1; /* number of lines to show */
- $line-height: 18px;
- line-height: $line-height; /* fallback */
- max-height: calc(#{$line-height} * 1); /* fallback */
- }
- }
-
-
- &.selected {
- background-color: $blue-color;
- border-radius: 1px;
- color: white;
- }
}
}
.dropdown-menu {
- position: absolute;
- top: 100%;
- left: 0;
- float: left;
- min-width: 160px;
- z-index: 100;
+ position: absolute;
+ top: 100%;
+ left: 0;
+ float: left;
+ min-width: 160px;
+ z-index: 100;
- list-style: none;
- font-size: 14px;
- text-align: left;
-
- padding: 0 0;
- border: none;
- width: 280px;
-
- -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
- box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
- background-clip: padding-box;
-
- background-color: white;
- color: $selected-text-color;
-
- li:hover {
- background-color: $blue-color;
- color: white;
- }
-
- > li {
- width: 100%;
- height: 40px;
- padding-top: 3px;
- overflow: hidden;
- cursor: pointer;
-
- border-bottom: 1px solid rgba(black, 0.1);
-
- color: $selected-text-color;
- float: left;
-
- label {
- padding: 10px;
- padding-top: 8px;
- width: 100%;
- height: 100%;
- display: block;
- cursor: pointer;
- }
-
-
- .shortcut {
- float: right;
- font-size: 12px;
- font-weight: normal;
- opacity: 0.5;
- margin-top: 10px;
- padding-right: 10px;
- }
- }
-}
-
-
-
-
-
-
-
-
-
-.dropdown-menu.sectioned-menu {
- overflow-y: scroll;
+ margin-top: 5px;
+ width: 280px;
max-height: calc(85vh - 90px);
-
- ul {
- margin-top: 0px;
- margin-bottom: 0px;
- padding-left:0;
- position: relative;
-
- li {
- cursor: pointer;
- height: auto;
-
- padding: 10px;
- border-bottom: 1px solid rgba(black, 0.1);
- background-color: rgba(white, 0.9);
- height: auto;
-
- .left-side {
- left: 0;
- width: 60%;
- display: inline-block;
- vertical-align: top;
- user-select: text;
- }
-
- .right-side {
- right: 12px;
- width: 30%;
- display: inline-block;
- vertical-align: top;
- text-align: right;
- position: absolute;
- }
-
- &:hover {
- background-color: $blue-color;
-
-
- .tinted {
- color: white;
- }
-
- &.nested-hover {
- color: black;
- background-color: $light-bg-color;
- }
- }
-
- &.nested-hover {
- color: black;
- background-color: white;
- }
-
- .menu-item-title {
- font-weight: bold;
- font-size: 14px;
- margin-bottom: 3px;
- }
-
- .menu-item-subtitle {
- font-weight: normal;
- opacity: 0.5;
- margin-top: 1px;
- font-size: 12px;
- }
- }
- }
-
- .header {
- background-color: #ededed;
- border-bottom: 1px solid #d3d3d3;
- position: relative;
- padding-top: 12px;
- padding-left: 10px;
- padding-bottom: 10px;
- cursor: pointer;
- user-select: none;
-
-
- > .title {
- font-size: 14px;
- font-weight: bold;
- }
-
- > .subtitle {
- font-size: 12px;
- opacity: 0.5;
- font-weight: normal;
- margin-top: 2px;
- }
-
- > .loading {
- position: absolute;
- height: 15px;
- width: 15px;
- right: 10px;
- top: 20px;
- }
- }
-
- .footer {
- background-color: #ededed;
- border-top: 1px solid #d3d3d3;
- position: relative;
- padding: 10px;
- }
+ background-color: white;
+ color: $selected-text-color;
}
diff --git a/app/assets/stylesheets/app/_modals.scss b/app/assets/stylesheets/app/_modals.scss
new file mode 100644
index 000000000..69b9754e1
--- /dev/null
+++ b/app/assets/stylesheets/app/_modals.scss
@@ -0,0 +1,91 @@
+#permissions-modal {
+ width: 350px;
+ .panel {
+ border-radius: 0;
+ background-color: white;
+ }
+ .content {
+ padding-top: 1.1rem;
+ }
+ .footer {
+ padding-bottom: 1.4rem;
+ }
+}
+
+.panel {
+ background-color: white;
+}
+
+.header .subtitle {
+ font-size: 1.1rem;
+}
+
+.modal {
+ position: fixed;
+ margin-left: auto;
+ margin-right: auto;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ z-index: 10000;
+ width: 100vw;
+ height: 100vh;
+ background-color: rgba(gray, 0.3);
+ color: black;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ .sn-component {
+ height: 100%;
+ .panel {
+ height: 100%;
+ }
+ }
+
+ &.medium {
+ > .content {
+ width: 700px;
+ height: 500px;
+ }
+ }
+
+ .background {
+ position: absolute;
+ z-index: -1;
+ width: 100%;
+ height: 100%;
+ }
+
+ > .content {
+ overflow-y: auto;
+ width: auto;
+ padding: 0;
+ padding-bottom: 0;
+ min-width: 300px;
+ }
+}
+
+// Optionally use if .component-view container is not flex-based
+.component-view-container {
+ flex-grow: 1;
+ display: flex;
+ height: 100%;
+ width: 100%;
+}
+
+.component-view {
+ flex-grow: 1;
+ display: flex;
+ overflow: auto;
+
+ .sn-component {
+ min-width: 100%;
+ }
+
+ iframe {
+ flex: 1;
+ width: 100%;
+ }
+}
diff --git a/app/assets/stylesheets/app/_notes.scss b/app/assets/stylesheets/app/_notes.scss
index 7dd46dfd7..45e6cd0f0 100644
--- a/app/assets/stylesheets/app/_notes.scss
+++ b/app/assets/stylesheets/app/_notes.scss
@@ -1,45 +1,44 @@
-.notes {
+#notes-column, .notes {
border-left: 1px solid #dddddd;
border-right: 1px solid #dddddd;
- flex: 1 20%;
- max-width: 350px;
- min-width: 170px;
-
+ width: 350px;
+ flex-grow: 0;
user-select: none;
- $notes-title-bar-height: 148px;
+ -moz-user-select: none;
+ -khtml-user-select: none;
+ -webkit-user-select: none;
+
+ .content {
+ display: flex;
+ flex-direction: column;
+ }
#notes-title-bar {
- color: rgba(black, 0.40);
padding-top: 16px;
- padding-left: 14px;
- padding-right: 14px;
- height: $notes-title-bar-height;
font-weight: normal;
font-size: 18px;
- .title {
+ .section-title-bar-header .title {
+ color: rgba(black, 0.40);
width: calc(90% - 45px);
}
}
#notes-add-button {
- right: 14px;
+
}
#notes-menu-bar {
position: relative;
- margin: 0 -14px;
margin-top: 14px;
- height: 45px;
- width: auto;
}
.filter-section {
clear: left;
height: 32px;
- margin-top: 20px;
+ margin-top: 14px;
position: relative;
.filter-bar {
@@ -80,7 +79,7 @@
}
.scrollable {
- height: calc(100vh - (#{$notes-title-bar-height} + #{$footer-height}));
+ height: 100%;
}
.infinite-scroll {
diff --git a/app/assets/stylesheets/app/_permissions-modal.scss b/app/assets/stylesheets/app/_permissions-modal.scss
deleted file mode 100644
index c51800dd1..000000000
--- a/app/assets/stylesheets/app/_permissions-modal.scss
+++ /dev/null
@@ -1,86 +0,0 @@
-.permissions-modal {
- position: fixed;
- margin-left: auto;
- margin-right: auto;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- z-index: 10000;
- width: 100vw;
- height: 100vh;
- background-color: rgba(gray, 0.3);
- color: black;
- font-size: 16px;
- display: flex;
- align-items: center;
-
- .background {
- position: absolute;
- z-index: -1;
- width: 100%;
- height: 100%;
- }
-
- .content {
- box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
- background-color: white;
- width: 700px;
- // height: 500px;
- margin: auto;
- padding: 10px 30px;
- padding-bottom: 30px;
- // position: absolute;
- // top: 0; left: 0; bottom: 0; right: 0;
- overflow-y: scroll;
-
- p {
- margin-bottom: 8px;
- margin-top: 0;
- }
-
- h3 {
- margin-bottom: 0;
- }
-
- h4 {
- margin-bottom: 6px;
- }
- }
-
- .learn-more {
- margin-top: 20px;
- line-height: 1.3;
- }
-
- .status {
- color: orange;
- }
-
- .buttons {
- margin-top: 35px;
- }
-
- button.standard {
- border-radius: 1px;
- font-weight: bold;
- padding: 6px 20px;
- display: inline-block;
-
- &:hover {
- text-decoration: underline;
- }
-
- &.tinted {
- background-color: $blue-color;
- color: white;
- }
-
- &.white {
- color: black;
- background-color: white;
- border: 1px solid gray;
- }
- }
-
-}
diff --git a/app/assets/stylesheets/app/_standard.scss b/app/assets/stylesheets/app/_standard.scss
deleted file mode 100644
index c111f54d2..000000000
--- a/app/assets/stylesheets/app/_standard.scss
+++ /dev/null
@@ -1,298 +0,0 @@
-.selectable {
- user-select: text !important;
-}
-
-.clear {
- clear: both;
-}
-
-.pull-left {
- float: left !important;
-}
-
-.pull-right {
- float: right !important;
-}
-
-.mt-1 {
- margin-top: 1px !important;
-}
-
-.mt-2 {
- margin-top: 2px !important;
-}
-
-.mt-3 {
- margin-top: 3px !important;
-}
-
-.mt-5 {
- margin-top: 5px !important;
-}
-
-.mt-10 {
- margin-top: 10px !important;
-}
-
-.mt-15 {
- margin-top: 15px !important;
-}
-
-.mt-20 {
- margin-top: 20px !important;
-}
-
-.mt-25 {
- margin-top: 25px !important;
-}
-
-.mt-50 {
- margin-top: 50px !important;
-}
-
-.mt-100 {
- margin-top: 100px !important;
-}
-
-.mb-0 {
- margin-bottom: 0px !important;
-}
-
-.mb-5 {
- margin-bottom: 5px !important;
-}
-
-.mb-10 {
- margin-bottom: 10px !important;
-}
-
-.mr-5 {
- margin-right: 5px;
-}
-
-.mr-10 {
- margin-right: 10px;
-}
-
-.mr-15 {
- margin-right: 15px;
-}
-
-.mr-20 {
- margin-right: 20px;
-}
-
-.ml-2 {
- margin-left: 2px;
-}
-
-.pb-0 {
- padding-bottom: 0px !important;
-}
-
-.pt-5 {
- padding-top: 5px;
-}
-
-.faded {
- opacity: 0.5;
-}
-
-.center-align {
- text-align: center !important;
-}
-
-.center {
- margin-left: auto !important;
- margin-right: auto !important;
-}
-
-.block {
- display: block !important;
-}
-
-.wrap {
- word-wrap: break-word;
- word-break: break-all;
-}
-
-.one-line-overflow {
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
-}
-
-.small-v-space {
- height: 6px;
- display: block;
-}
-
-.medium-v-space {
- height: 12px;
- display: block;
-}
-
-.large-v-space {
- height: 24px;
- display: block;
-}
-
-.small-padding {
- padding: 5px !important;
-}
-
-.medium-padding {
- padding: 10px !important;
-}
-
-.pb-4 {
- padding-bottom: 4px !important;
-}
-
-.pb-6 {
- padding-bottom: 6px !important;
-}
-
-.pb-10 {
- padding-bottom: 10px !important;
-}
-
-.large-padding {
- padding: 22px !important;
-}
-
-.red {
- color: red !important;
-}
-
-.orange {
- color: orange !important;
-}
-
-.bold {
- font-weight: bold !important;
-}
-
-.normal {
- font-weight: normal !important;
-}
-
-.small {
- font-size: 10px;
-}
-
-.medium {
- font-size: 14px !important;
-}
-
-.inline {
- display: inline-block !important;
-
- &.top {
- vertical-align: top;
- }
-
- &.middle {
- vertical-align: middle;
- }
-}
-
-button {
- cursor: pointer;
-}
-
-input.form-control {
- margin-bottom: 10px;
- border-radius: 0px;
- min-height: 39px;
- font-size: 14px;
- padding-left: 6px;
-}
-
-button {
- border: none;
-
- @mixin wide-button() {
- font-weight: bold;
- text-align: center;
- padding: 10px;
- font-size: 16px;
- // min-width: 200px;
-
- &:hover {
- text-decoration: underline;
- }
- }
-
- &.black {
- @include wide-button();
- background-color: black;
- color: white;
- }
-
- &.white {
- @include wide-button();
- background-color: white;
- color: black;
- border: 1px solid rgba(gray, 0.2);
- }
-}
-
-
-.gray-bg {
- background-color: #f6f6f6;
- border: 1px solid #f2f2f2;
-}
-
-.white-bg {
- background-color: white;
- border: 1px solid rgba(gray, 0.2);
-}
-
-.col-container {
- // white-space: nowrap;
-}
-
-@mixin col() {
- display: inline-block;
- vertical-align: top;
- white-space: normal;
-}
-
-.col-10 {
- width: 10%;
- @include col();
-}
-
-.col-15 {
- width: 15%;
- @include col();
-}
-
-.col-20 {
- width: 20%;
- @include col();
-}
-
-.col-45 {
- width: 45%;
- @include col();
-}
-
-.col-50 {
- width: 50%;
- @include col();
-}
-
-.col-80 {
- width: 80%;
- @include col();
-}
-
-.relative {
- position: relative !important;
-}
-
-.absolute {
- position: absolute !important;
-}
diff --git a/app/assets/stylesheets/app/_stylekit-sub.scss b/app/assets/stylesheets/app/_stylekit-sub.scss
new file mode 100644
index 000000000..5fb32e5bc
--- /dev/null
+++ b/app/assets/stylesheets/app/_stylekit-sub.scss
@@ -0,0 +1,31 @@
+.sn-component {
+
+}
+
+.panel {
+ color: black;
+
+ .header {
+ .close-button {
+ &:hover {
+ text-decoration: none;
+ }
+ }
+ }
+
+ input {
+ min-height: 39px;
+ }
+
+
+ .button-group.stretch {
+ .button:not(.featured) {
+ // Default buttons that are not featured and stretched should have larger vertical padding
+ padding: 9px;
+ }
+ }
+
+ a {
+ color: $blue-color;
+ }
+}
diff --git a/app/assets/stylesheets/app/_tags.scss b/app/assets/stylesheets/app/_tags.scss
index d0e1e31db..5285e9c91 100644
--- a/app/assets/stylesheets/app/_tags.scss
+++ b/app/assets/stylesheets/app/_tags.scss
@@ -1,31 +1,28 @@
.tags {
- flex: 1 10%;
- max-width: 180px;
- min-width: 100px;
width: 180px;
- background-color: #f6f6f6;
+ flex-grow: 0;
+ -moz-user-select: none;
+ -khtml-user-select: none;
+ -webkit-user-select: none;
- user-select: none;
-
- $tags-title-bar-height: 55px;
+ &, #tags-content {
+ background-color: #f6f6f6;
+ display: flex;
+ flex-direction: column;
+ }
#tags-title-bar {
color: black;
- height: $tags-title-bar-height;
+ padding-top: 14px;
+ padding-bottom: 16px;
padding-left: 12px;
padding-right: 12px;
font-size: 12px;
color: rgba(black, 0.8);
}
- #tags-content {
- background-color: #f6f6f6;
- }
-
#tag-add-button {
- margin-top: -6px;
background-color: #d7d7d7;
- float: right;
&:hover {
background-color: rgba(#d7d7d7, 0.8);
@@ -33,7 +30,12 @@
}
.scrollable {
- height: calc(100vh - (#{$tags-title-bar-height} + #{$footer-height}));
+ height: 100%;
+ }
+
+ .infinite-scroll {
+ overflow-x: hidden;
+ height: inherit;
}
.tag {
diff --git a/app/assets/stylesheets/app/_ui.scss b/app/assets/stylesheets/app/_ui.scss
index fcbaa03eb..91b0be017 100644
--- a/app/assets/stylesheets/app/_ui.scss
+++ b/app/assets/stylesheets/app/_ui.scss
@@ -57,104 +57,56 @@ $screen-md-max: ($screen-lg-min - 1) !default;
}
}
-* {
- box-sizing: border-box;
+.selectable {
+ user-select: text !important;
+ cursor: text;
}
-*:focus {outline:0;}
-
-.float-group {
- height: 15px;
- &.h10 {
- height: 10px;
- }
-
- &.h20 {
- height: 20px;
- }
-
- &.h30 {
- height: 30px;
- }
- clear: both;
+.mt-5 {
+ margin-top: 5px !important;
}
-button:focus {outline:0;}
-
-
-.button-group {
- clear: both;
- height: 36px;
+.mt-10 {
+ margin-top: 10px !important;
}
-.ui-button {
- background-color: $blue-color;
- border: 0;
- color: white;
- font-weight: bold;
- min-height: 36px;
- font-size: 14px;
-
- &.block {
- width: 100%;
- }
+.faded {
+ opacity: 0.5;
}
-.panel {
- position: absolute;
- right: 0px;
- min-width: 300px;
- z-index: 1000;
- margin-top: 10px;
- box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.2);
- border: none;
- background-color: white;
+.center-align {
+ text-align: center !important;
}
-.panel-right {
- left: 0px;
+.block {
+ display: block !important;
}
-.panel-body {
- padding: 15px;
+.wrap {
+ word-wrap: break-word;
+ word-break: break-all;
}
-.form-control {
- display: block;
- width: 100%;
- height: 34px;
- padding: 6px 12px;
- font-size: 14px;
- line-height: 1.42857;
- color: #555555;
- background-color: #fff;
- background-image: none;
- border: 1px solid #ccc;
- border-radius: 4px;
- box-shadow: 0;
+.medium-padding {
+ padding: 10px !important;
}
-input, button, select, textarea {
- font-family: inherit;
- font-size: inherit;
- line-height: inherit;
+.red {
+ color: red !important;
}
-button {
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
- border-top-left-radius: 0;
- border-top-right-radius: 0;
+.bold {
+ font-weight: bold !important;
}
-.checkbox {
- font-size: 14px;
- font-weight: bold;
- margin-left: auto;
- margin-right: auto;
- margin-bottom: 10px;
-
- input {
- margin-left: 0px;
- }
+.normal {
+ font-weight: normal !important;
+}
+
+.small {
+ font-size: 10px;
+}
+
+.medium {
+ font-size: 14px !important;
}
diff --git a/app/assets/stylesheets/frontend.css.scss b/app/assets/stylesheets/main.css.scss
similarity index 57%
rename from app/assets/stylesheets/frontend.css.scss
rename to app/assets/stylesheets/main.css.scss
index 249d4f9ed..9e28dc002 100644
--- a/app/assets/stylesheets/frontend.css.scss
+++ b/app/assets/stylesheets/main.css.scss
@@ -1,15 +1,11 @@
-$dark-gray: #2e2e2e;
-
-@import "app/standard";
@import "app/main";
@import "app/ui";
@import "app/footer";
@import "app/tags";
@import "app/notes";
@import "app/editor";
-@import "app/extensions";
@import "app/menus";
-@import "app/permissions-modal";
+@import "app/modals";
@import "app/lock-screen";
-
-@import "ionicons";
+@import "app/stylekit-sub";
+@import "app/ionicons";
diff --git a/app/assets/templates/directives/account-menu.html.haml b/app/assets/templates/directives/account-menu.html.haml
new file mode 100644
index 000000000..9ddb39cfc
--- /dev/null
+++ b/app/assets/templates/directives/account-menu.html.haml
@@ -0,0 +1,189 @@
+.sn-component
+ .panel#account-panel
+ .header
+ %h1.title Account
+ %a.close-button{"ng-click" => "close()"} Close
+ .content
+
+ .panel-section.hero{"ng-if" => "!user && !formData.showLogin && !formData.showRegister && !formData.mfa"}
+ %h1.title Sign in or register to enable sync and end-to-end encryption.
+ .panel-row
+ .panel-row
+ .button-group.stretch
+ .button.info.featured{"ng-click" => "formData.showLogin = true"}
+ .label Sign In
+ .button.info.featured{"ng-click" => "formData.showRegister = true"}
+ .label Register
+ %p
+ Standard Notes is free on every platform, and comes standard with sync and encryption.
+
+ .panel-section{"ng-if" => "formData.showLogin || formData.showRegister"}
+ %h3.title.panel-row
+ {{formData.showLogin ? "Sign In" : "Register"}}
+
+ %form.panel-form{"ng-submit" => "submitAuthForm()"}
+ %input{:placeholder => 'Email', "sn-autofocus" => 'true', "should-focus" => "true", :name => 'email', :required => true, :type => 'email', 'ng-model' => 'formData.email'}
+ %input{:placeholder => 'Password', :name => 'password', :required => true, :type => 'password', 'ng-model' => 'formData.user_password'}
+ %input{:placeholder => 'Confirm Password', "ng-if" => "formData.showRegister", :name => 'password', :required => true, :type => 'password', 'ng-model' => 'formData.password_conf'}
+
+ %a.panel-row{"ng-click" => "formData.showAdvanced = !formData.showAdvanced"}
+ Advanced Options
+ .notification.info{"ng-if" => "formData.showRegister"}
+ %h2.title No Password Reset.
+ .text Because your notes are encrypted using your password, Standard Notes does not have a password reset option. You cannot forget your password.
+ .advanced-options.panel-row{"ng-if" => "formData.showAdvanced"}
+ .panel-column.stretch
+ %label Sync Server Domain
+ %input.form-control.mt-5{:name => 'server', :placeholder => 'Server URL', :required => true, :type => 'text', 'ng-model' => 'formData.url'}
+
+ .button-group.stretch.panel-row.form-submit
+ %button.button.info.featured{"type" => "submit"}
+ .label {{formData.showLogin ? "Sign In" : "Register"}}
+
+ %label
+ %input{"type" => "checkbox", "ng-model" => "formData.ephemeral", "ng-true-value" => "false", "ng-false-value" => "true"}
+ Stay signed in
+ %label{"ng-if" => "notesAndTagsCount() > 0"}
+ %input{"type" => "checkbox", "ng-model" => "formData.mergeLocal", "ng-bind" => "true", "ng-change" => "mergeLocalChanged()"}
+ Merge local data ({{notesAndTagsCount()}} notes and tags)
+
+ %em.block.center-align.mt-10{"ng-if" => "formData.status", "style" => "font-size: 14px;"}
+ {{formData.status}}
+
+ .panel-section{"ng-if" => "formData.mfa"}
+ %form{"ng-submit" => "submitMfaForm()"}
+ %p {{formData.mfa.message}}
+ %input.form-control.mt-10{:placeholder => "Enter Code", "sn-autofocus" => "true", "should-focus" => "true", :autofocus => "true", :name => 'mfa', :required => true, 'ng-model' => 'formData.userMfaCode'}
+ .button-group.stretch.panel-row.form-submit
+ %button.button.info.featured{"type" => "submit"}
+ .label Sign In
+
+ %div{"ng-if" => "!formData.showLogin && !formData.showRegister && !formData.mfa"}
+ .panel-section{"ng-if" => "user"}
+ .panel-row
+ %h2.title.wrap {{user.email}}
+ .horizontal-group{"delay-hide" => "true", "show" => "syncStatus.syncOpInProgress || syncStatus.needsMoreSync", "delay" => "1000"}
+ .spinner.small.info
+ .sublabel
+ {{"Syncing" + (syncStatus.total > 0 ? ":" : "")}}
+ %span{"ng-if" => "syncStatus.total > 0"} {{syncStatus.current}}/{{syncStatus.total}}
+
+ .subtitle.danger.panel-row{"ng-if" => "syncStatus.error"} Error syncing: {{syncStatus.error.message}}
+
+ .subtitle.subtle.normal {{server}}
+
+ .panel-row
+
+ %a.panel-row.condensed{"ng-click" => "newPasswordData.changePassword = !newPasswordData.changePassword"} Change Password
+ .notification.warning{"ng-if" => "newPasswordData.changePassword"}
+ %h1.title Change Password
+ .text
+ %p Since your encryption key is based on your password, changing your password requires all your notes and tags to be re-encrypted using your new key.
+ %p If you have thousands of items, this can take several minutes — you must keep the application window open during this process.
+ %p After changing your password, you must log out of all other applications currently signed in to your account.
+ %p.bold It is highly recommended you download a backup of your data before proceeding.
+ .panel-row{"ng-if" => "!newPasswordData.status"}
+ .horizontal-group{"ng-if" => "!newPasswordData.showForm"}
+ %a.red{"ng-click" => "showPasswordChangeForm()"} Continue
+ %a{"ng-click" => "newPasswordData.changePassword = false; newPasswordData.showForm = false"} Cancel
+ .panel-row{"ng-if" => "newPasswordData.showForm"}
+ %form.panel-form.stretch
+ %input{:type => 'password', "ng-model" => "newPasswordData.newPassword", "placeholder" => "Enter new password"}
+ %input{:type => 'password', "ng-model" => "newPasswordData.newPasswordConfirmation", "placeholder" => "Confirm new password"}
+ .button-group.stretch.panel-row.form-submit
+ .button.info{"type" => "submit", "ng-click" => "submitPasswordChange()"}
+ .label Submit
+ %a{"ng-click" => "newPasswordData.changePassword = false; newPasswordData.showForm = false"} Cancel
+
+ %p.italic.mt-10{"ng-if" => "newPasswordData.status"} {{newPasswordData.status}}
+
+
+
+ %a.panel-row.condensed{"ng-click" => "showAdvanced = !showAdvanced"} Advanced
+ %div{"ng-if" => "showAdvanced"}
+ %a.panel-row{"ng-click" => "reencryptPressed()"} Resync All Items
+
+
+ %a.panel-row.condensed{"ng-if" => "securityUpdateAvailable()", "ng-click" => "clickedSecurityUpdate()"} Security Update Available
+ .notification.default{"ng-if" => "securityUpdateData.showForm"}
+ %p
+ %a{"href" => "https://standardnotes.org/help/security-update", "target" => "_blank"} Learn more.
+ %form.panel-form.stretch{"ng-if" => "!securityUpdateData.processing", "ng-submit" => "submitSecurityUpdateForm()"}
+ %p Enter your password to update:
+ %input.panel-row{:type => 'password', "ng-model" => "securityUpdateData.password", "placeholder" => "Enter password"}
+ .button-group.stretch.panel-row.form-submit
+ %button.button.info{"ng-type" => "submit"}
+ .label Update
+ .panel-row{"ng-if" => "securityUpdateData.processing"}
+ %p.info Processing...
+
+
+ .panel-section
+ %h3.title.panel-row Encryption
+ %h5.subtitle.info.panel-row{"ng-if" => "encryptionEnabled()"}
+ {{encryptionStatusForNotes()}}
+ %p
+ {{encryptionStatusString()}}
+
+ .panel-section
+ %h3.title.panel-row Passcode Lock
+ %div{"ng-if" => "!hasPasscode()"}
+ .panel-row{"ng-if" => "!formData.showPasscodeForm"}
+ .button.info{"ng-click" => "addPasscodeClicked(); $event.stopPropagation();"}
+ .label Add Passcode
+
+ %p Add an app passcode to lock the app and encrypt on-device key storage.
+
+ %form{"ng-if" => "formData.showPasscodeForm", "ng-submit" => "submitPasscodeForm()"}
+ %input.form-control{:type => 'password', "ng-model" => "formData.passcode", "placeholder" => "Passcode", "sn-autofocus" => "true", "should-focus" => "true"}
+ %input.form-control{:type => 'password', "ng-model" => "formData.confirmPasscode", "placeholder" => "Confirm Passcode"}
+ .button-group.stretch.panel-row.form-submit
+ %button.button.info{"type" => "submit"}
+ .label Set Passcode
+ %a.panel-row{"ng-click" => "formData.showPasscodeForm = false"} Cancel
+
+ %div{"ng-if" => "hasPasscode() && !formData.showPasscodeForm"}
+ .panel-row
+ %p
+ Passcode lock is enabled.
+ %span{"ng-if" => "isDesktopApplication()"} Your passcode will be required on new sessions after app quit.
+ .panel-row.justify-left
+ .horizontal-group
+ %a.info{"ng-click" => "changePasscodePressed()"} Change Passcode
+ %a.danger{"ng-click" => "removePasscodePressed()"} Remove Passcode
+
+
+
+ .panel-section{"ng-if" => "!importData.loading"}
+ %h3.title Data Backups
+ %form.panel-form{"ng-if" => "encryptedBackupsAvailable()"}
+ .input-group
+ %label
+ %input{"type" => "radio", "ng-model" => "archiveFormData.encrypted", "ng-value" => "true", "ng-change" => "archiveFormData.encrypted = true"}
+ Encrypted
+ %label
+ %input{"type" => "radio", "ng-model" => "archiveFormData.encrypted", "ng-value" => "false", "ng-change" => "archiveFormData.encrypted = false"}
+ Decrypted
+
+ .button-group
+ .button.info{"ng-click" => "downloadDataArchive()", "ng-class" => "{'mt-5' : !user}"}
+ .label Download Backup
+
+ %label.button.info
+ %input{"type" => "file", "style" => "display: none;", "file-change" => "->", "handler" => "importFileSelected(files)"}
+ .label Import From Backup
+
+ %div{"ng-if" => "importData.requestPassword"}
+ %form.panel-form.stretch{"ng-submit" => "submitImportPassword()"}
+ %p Enter the account password associated with the import file.
+ %input.form-control.mt-5{:type => 'password', "placeholder" => "Enter File Account Password", "ng-model" => "importData.password", "autofocus" => "true"}
+ .button-group.stretch.panel-row.form-submit
+ %button.button.info{"type" => "submit"}
+ .label Decrypt & Import
+ .panel-row
+ .spinner.small.info{"ng-if" => "importData.loading"}
+ .footer
+ %a.right{"ng-if" => "formData.showLogin || formData.showRegister", "ng-click" => "formData.showLogin = false; formData.showRegister = false;"}
+ Cancel
+ %a.right{"ng-if" => "!formData.showLogin && !formData.showRegister", "ng-click" => "destroyLocalData()"}
+ {{ user ? "Sign out and clear local data" : "Clear all local data" }}
diff --git a/app/assets/templates/directives/actions-menu.html.haml b/app/assets/templates/directives/actions-menu.html.haml
new file mode 100644
index 000000000..52470f972
--- /dev/null
+++ b/app/assets/templates/directives/actions-menu.html.haml
@@ -0,0 +1,32 @@
+.sn-component
+ .menu-panel.dropdown-menu
+
+ %a.no-decoration{"ng-if" => "extensions.length == 0", "href" => "https://standardnotes.org/extensions", "target" => "blank"}
+ %menu-row{"title" => "'Download Actions'"}
+
+ %div{"ng-repeat" => "extension in extensions"}
+ .header{"ng-click" => "extension.hide = !extension.hide; $event.stopPropagation();"}
+ .column
+ %h4.title {{extension.name}}
+ .spinner.small.loading{"ng-if" => "extension.loading"}
+ %div{"ng-if" => "extension.hide"} …
+
+ %menu-row{"ng-if" => "!extension.hide", "ng-repeat" => "action in extension.actionsWithContextForItem(item)",
+ "ng-click" => "executeAction(action, extension); $event.stopPropagation();", "title" => "action.label", "subtitle" => "action.desc",
+ "spinner-class" => "action.running ? 'info' : null", "sub-rows" => "action.subrows"}
+ .sublabel{"ng-if" => "action.access_type"}
+ Uses
+ %strong {{action.access_type}}
+ access to this note.
+
+
+.modal.medium{"ng-if" => "renderData.showRenderModal", "ng-click" => "$event.stopPropagation();"}
+ .content
+ .sn-component
+ .panel
+ .header
+ %h1.title Preview
+ %a.close-button.info{"ng-click" => "renderData.showRenderModal = false; $event.stopPropagation();"} Close
+ .content.selectable
+ %h2 {{renderData.title}}
+ %p.normal{"style" => "white-space: pre-wrap; font-family: monospace; font-size: 16px;"} {{renderData.text}}
diff --git a/app/assets/templates/directives/component-modal.html.haml b/app/assets/templates/directives/component-modal.html.haml
new file mode 100644
index 000000000..1229327cc
--- /dev/null
+++ b/app/assets/templates/directives/component-modal.html.haml
@@ -0,0 +1,10 @@
+.background{"ng-click" => "dismiss()"}
+
+.content
+ .sn-component
+ .panel{"ng-attr-id" => "component-{{component.uuid}}"}
+ .header
+ %h1.title
+ {{component.name}}
+ %a.close-button.info{"ng-click" => "dismiss()"} Close
+ %component-view.component-view{"component" => "component"}
diff --git a/app/assets/templates/directives/component-view.html.haml b/app/assets/templates/directives/component-view.html.haml
new file mode 100644
index 000000000..e507ea060
--- /dev/null
+++ b/app/assets/templates/directives/component-view.html.haml
@@ -0,0 +1,70 @@
+.sn-component{"ng-if" => "error == 'expired'"}
+ .panel.static
+ .content
+ .panel-section.stretch
+ %h2.title Unable to load Standard Notes Extended
+ %p Your Extended subscription expired on {{component.dateToLocalizedString(component.valid_until)}}.
+ %p
+ Please visit
+ %a{"href" => "https://dashboard.standardnotes.org", "target" => "_blank"} dashboard.standardnotes.org
+ to renew your subscription, then open the "Extensions" menu via the bottom menu of the app to refresh your account data.
+ Afterwards, press the button below to attempt to reload this component.
+ .panel-row
+ .button.info{"ng-if" => "!reloading", "ng-click" => "reloadStatus()"}
+ .label Reload
+ .spinner.info.small{"ng-if" => "reloading"}
+
+ .panel-row
+ .panel-row
+ .panel-column
+ %p Otherwise, please follow the steps below to disable any external editors, so you can edit your note using the plain text editor instead.
+
+ %p
+ %ol
+ %li Click the "Editor" menu item above (under the note title).
+ %li Select "Plain Editor".
+ %li Repeat this for every note you'd like to access. You can also delete the editor completely to disable it for all notes. To do so, click "Extensions" in the lower left corner of the app, then, for every editor, click "Uninstall".
+
+ %p
+ Need help? Please email us at
+ %a{"href" => "mailto:hello@standardnotes.org", "target" => "_blank"} hello@standardnotes.org
+ or check out the
+ %a{"href" => "https://standardnotes.org/help", "target" => "_blank"} Help
+ page.
+
+.sn-component{"ng-if" => "error == 'offline-restricted'"}
+ .panel.static
+ .content
+ .panel-section.stretch
+ %h2.title You have restricted this extension to be used offline only.
+ %p Offline extensions are not available in the Web app.
+ .panel-row
+ .panel-column
+ %p You can either:
+ %p
+ %ul
+ %li Enable the Hosted option for this extension by opening the 'Extensions' menu and toggling 'Use hosted when local is unavailable' under this extension's options. Then press Reload below.
+ %li Use the Desktop application.
+ .panel-row
+ .button.info{"ng-if" => "!reloading", "ng-click" => "reloadStatus()"}
+ .label Reload
+ .spinner.info.small{"ng-if" => "reloading"}
+
+.sn-component{"ng-if" => "error == 'url-missing'"}
+ .panel.static
+ .content
+ .panel-section.stretch
+ %h2.title This extension is not installed correctly.
+ %p Please uninstall {{component.name}}, then re-install it.
+
+ %p
+ This issue can occur if you access Standard Notes using an older version of the app.
+ Ensure you are running at least version 2.1 on all platforms.
+
+
+%iframe{"ng-if" => "component && componentValid",
+ "ng-attr-id" => "component-{{component.uuid}}",
+ "ng-src" => "{{getUrl() | trusted}}", "frameBorder" => "0",
+ "sandbox" => "allow-scripts allow-top-navigation-by-user-activation allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-modals allow-forms",
+ "data-component-id" => "{{component.uuid}}"}
+ Loading
diff --git a/app/assets/templates/directives/editor-menu.html.haml b/app/assets/templates/directives/editor-menu.html.haml
new file mode 100644
index 000000000..6787ab986
--- /dev/null
+++ b/app/assets/templates/directives/editor-menu.html.haml
@@ -0,0 +1,26 @@
+.sn-component
+ .menu-panel.dropdown-menu
+ .section
+ .header
+ %h4.title Note Editor
+ %menu-row{"title" => "'Plain Editor'", "circle" => "selectedEditor == null && 'success'", "ng-click" => "selectComponent($event, null)"}
+
+ %menu-row{"ng-repeat" => "editor in editors", "ng-click" => "selectComponent($event, editor)", "title" => "editor.name",
+ "circle" => "selectedEditor === editor && 'success'",
+ "has-button" => "selectedEditor == editor || defaultEditor == editor", "button-text" => "defaultEditor == editor ? 'Undefault' : 'Set Default'",
+ "button-action" => "toggleDefaultForEditor(editor)", "button-class" => "defaultEditor == editor ? 'warning' : 'info'"}
+ .column{"ng-if" => "component.conflict_of || shouldDisplayRunningLocallyLabel(editor)"}
+ %strong.red.medium{"ng-if" => "editor.conflict_of"} Conflicted copy
+ .sublabel{"ng-if" => "shouldDisplayRunningLocallyLabel(editor)"} Running Locally
+
+ %a.no-decoration{"ng-if" => "editors.length == 0", "href" => "https://standardnotes.org/extensions", "target" => "blank"}
+ %menu-row{"title" => "'Download More Editors'"}
+
+ .section{"ng-if" => "stack.length > 0"}
+ .header
+ %h4.title Editor Stack
+ %menu-row{"ng-repeat" => "component in stack", "ng-click" => "selectComponent($event, component)", "title" => "component.name",
+ "circle" => "stackComponentEnabled(component) ? 'success' : 'danger'"}
+ .column{"ng-if" => "component.conflict_of || shouldDisplayRunningLocallyLabel(component)"}
+ %strong.red.medium{"ng-if" => "component.conflict_of"} Conflicted copy
+ .sublabel{"ng-if" => "shouldDisplayRunningLocallyLabel(component)"} Running Locally
diff --git a/app/assets/templates/directives/menu-row.html.haml b/app/assets/templates/directives/menu-row.html.haml
new file mode 100644
index 000000000..7bbff5528
--- /dev/null
+++ b/app/assets/templates/directives/menu-row.html.haml
@@ -0,0 +1,21 @@
+.row
+ .column
+ .left
+ .column{"ng-if" => "circle"}
+ .circle.small{"ng-class" => "circle"}
+ .column{"ng-class" => "{'faded' : faded}"}
+ .label
+ {{title}}
+ .sublabel{"ng-if" => "subtitle"}
+ {{subtitle}}
+ %ng-transclude
+ .subrows{"ng-if" => "subRows && subRows.length > 0"}
+ %menu-row{"ng-repeat" => "row in subRows", "ng-click" => "row.onClick($event); $event.stopPropagation();",
+ "title" => "row.title", "subtitle" => "row.subtitle", "spinner-class" => "row.spinnerClass"}
+
+ .column{"ng-if" => "hasButton"}
+ .button.info{"ng-click" => "clickButton($event)", "ng-class" => "buttonClass"}
+ {{buttonText}}
+
+ .column{"ng-if" => "spinnerClass"}
+ .spinner.small{"ng-class" => "spinnerClass"}
diff --git a/app/assets/templates/directives/panel-resizer.html.haml b/app/assets/templates/directives/panel-resizer.html.haml
new file mode 100644
index 000000000..b2822c8c3
--- /dev/null
+++ b/app/assets/templates/directives/panel-resizer.html.haml
@@ -0,0 +1 @@
+.panel-resizer-column
diff --git a/app/assets/templates/directives/permissions-modal.html.haml b/app/assets/templates/directives/permissions-modal.html.haml
new file mode 100644
index 000000000..63a5dc38f
--- /dev/null
+++ b/app/assets/templates/directives/permissions-modal.html.haml
@@ -0,0 +1,22 @@
+.background{"ng-click" => "deny()"}
+
+.content#permissions-modal
+ .sn-component
+ .panel
+ .header
+ %h1.title Activate Extension
+ %a.close-button.info{"ng-click" => "deny()"} Cancel
+ .content
+ .panel-section
+ .panel-row
+ %h3
+ %strong {{component.name}}
+ would like to interact with your
+ {{permissionsString()}}
+
+ .panel-row
+ %p
+ Extensions use an offline messaging system to communicate. Learn more at
+ %a{"href" => "https://standardnotes.org/permissions", "target" => "_blank"} https://standardnotes.org/permissions.
+ .footer
+ .button.info.big.block.bold{"ng-click" => "accept()"} Continue
diff --git a/app/assets/templates/editor.html.haml b/app/assets/templates/editor.html.haml
new file mode 100644
index 000000000..31c4a0a6c
--- /dev/null
+++ b/app/assets/templates/editor.html.haml
@@ -0,0 +1,59 @@
+.section.editor#editor-column
+ #editor-title-bar.section-title-bar{"ng-show" => "ctrl.note && !ctrl.note.errorDecrypting"}
+ .title
+ %input.input#note-title-editor{"ng-model" => "ctrl.note.title", "ng-keyup" => "$event.keyCode == 13 && ctrl.saveTitle($event)",
+ "ng-change" => "ctrl.nameChanged()", "ng-focus" => "ctrl.onNameFocus()", "ng-blur" => "ctrl.onNameBlur()",
+ "select-on-click" => "true"}
+
+ #save-status{"ng-class" => "{'red bold': ctrl.saveError, 'warning bold': ctrl.syncTakingTooLong}", "ng-bind-html" => "ctrl.noteStatus"}
+
+ .editor-tags
+ #note-tags-component-container{"ng-if" => "ctrl.tagsComponent"}
+ %component-view.component-view{ "component" => "ctrl.tagsComponent"}
+ %input.tags-input{"ng-if" => "!(ctrl.tagsComponent && ctrl.tagsComponent.active)", "type" => "text", "ng-keyup" => "$event.keyCode == 13 && $event.target.blur();",
+ "ng-model" => "ctrl.tagsString", "placeholder" => "#tags", "ng-blur" => "ctrl.updateTagsFromTagsString($event, ctrl.tagsString)",
+ "spellcheck" => "false"}
+
+ .sn-component{"ng-if" => "ctrl.note"}
+ .app-bar.no-edges
+ .left
+ .item{"ng-click" => "ctrl.showMenu = !ctrl.showMenu; ctrl.showExtensions = false; ctrl.showEditorMenu = false;", "ng-class" => "{'selected' : ctrl.showMenu}", "click-outside" => "ctrl.showMenu = false;", "is-open" => "ctrl.showMenu"}
+ .label Menu
+ .menu-panel.dropdown-menu{"ng-if" => "ctrl.showMenu"}
+ .section
+ .header
+ %h4.title Note Options
+ %menu-row{"title" => "ctrl.note.pinned ? 'Unpin' : 'Pin'", "ng-click" => "ctrl.selectedMenuItem($event, true); ctrl.togglePin()"}
+ %menu-row{"title" => "ctrl.note.archived ? 'Unarchive' : 'Archive'", "ng-click" => "ctrl.selectedMenuItem($event, true); ctrl.toggleArchiveNote()"}
+ %menu-row{"title" => "'Delete'", "ng-click" => "ctrl.selectedMenuItem($event); ctrl.deleteNote()"}
+
+ .section{"ng-if" => "!ctrl.selectedEditor"}
+ .header
+ %h4.title Global Display
+ %menu-row{"title" => "'Monospace Font'", "circle" => "ctrl.monospaceFont ? 'success' : 'default'", "ng-click" => "ctrl.selectedMenuItem($event, true); ctrl.toggleKey('monospaceFont')"}
+ %menu-row{"title" => "'Spellcheck'", "circle" => "ctrl.spellcheck ? 'success' : 'default'", "ng-click" => "ctrl.selectedMenuItem($event, true); ctrl.toggleKey('spellcheck')"}
+
+ .item{"ng-click" => "ctrl.onEditorMenuClick()", "ng-class" => "{'selected' : ctrl.showEditorMenu}", "click-outside" => "ctrl.showEditorMenu = false;", "is-open" => "ctrl.showEditorMenu"}
+ .label Editor
+ %editor-menu{"ng-if" => "ctrl.showEditorMenu", "callback" => "ctrl.editorMenuOnSelect", "selected-editor" => "ctrl.selectedEditor", "current-item" => "ctrl.note"}
+
+ .item{"ng-click" => "ctrl.showExtensions = !ctrl.showExtensions; ctrl.showMenu = false; ctrl.showEditorMenu = false;", "ng-class" => "{'selected' : ctrl.showExtensions}", "click-outside" => "ctrl.showExtensions = false;", "is-open" => "ctrl.showExtensions"}
+ .label Actions
+ %actions-menu{"ng-if" => "ctrl.showExtensions", "item" => "ctrl.note"}
+
+ .editor-content#editor-content{"ng-if" => "ctrl.noteReady && !ctrl.note.errorDecrypting"}
+ %panel-resizer.left{"panel-id" => "'editor-content'", "on-resize-finish" => "ctrl.onPanelResizeFinish","control" => "ctrl.resizeControl", "min-width" => 300, "property" => "'left'", "hoverable" => "true"}
+ %component-view.component-view{"ng-if" => "ctrl.selectedEditor", "component" => "ctrl.selectedEditor"}
+ %textarea.editable#note-text-editor{"ng-if" => "!ctrl.selectedEditor", "ng-model" => "ctrl.note.text",
+ "ng-change" => "ctrl.contentChanged()", "ng-trim" => "false", "ng-click" => "ctrl.clickedTextArea()",
+ "ng-focus" => "ctrl.onContentFocus()", "dir" => "auto", "ng-attr-spellcheck" => "{{ctrl.spellcheck}}"}
+ {{ctrl.onSystemEditorLoad()}}
+ %panel-resizer{"panel-id" => "'editor-content'", "on-resize-finish" => "ctrl.onPanelResizeFinish","control" => "ctrl.resizeControl", "min-width" => 300, "hoverable" => "true", "property" => "'right'"}
+
+ %section.section{"ng-if" => "ctrl.note.errorDecrypting"}
+ %p.medium-padding{"style" => "padding-top: 0 !important;"} There was an error decrypting this item. Ensure you are running the latest version of this app, then sign out and sign back in to try again.
+
+ #editor-pane-component-stack
+ .sn-component
+ %component-view.component-view.component-stack-item.border-color{"ng-repeat" => "component in ctrl.componentStack",
+ "ng-if" => "component.active", "ng-show" => "!component.hidden", "manual-dealloc" => "true", "component" => "component"}
diff --git a/app/assets/templates/footer.html.haml b/app/assets/templates/footer.html.haml
new file mode 100644
index 000000000..07c4de532
--- /dev/null
+++ b/app/assets/templates/footer.html.haml
@@ -0,0 +1,41 @@
+.sn-component
+ #footer-bar.app-bar.no-edges
+ .left
+ .item{"ng-click" => "ctrl.accountMenuPressed()", "click-outside" => "ctrl.showAccountMenu = false;", "is-open" => "ctrl.showAccountMenu"}
+ .column
+ .circle.small{"ng-class" => "ctrl.error ? 'danger' : (ctrl.getUser() ? 'info' : 'default')"}
+ .column
+ .label.title{"ng-class" => "{red: ctrl.error}"} Account
+ %account-menu{"ng-click" => "$event.stopPropagation()", "ng-if" => "ctrl.showAccountMenu", "on-successful-auth" => "ctrl.onAuthSuccess", "close-function" => "ctrl.closeAccountMenu"}
+
+ .item
+ %a.no-decoration.label.title{"href" => "https://standardnotes.org/help", "target" => "_blank"}
+ Help
+
+ .item.border
+
+ .item{"ng-repeat" => "room in ctrl.rooms track by room.uuid"}
+ .column{"ng-click" => "ctrl.selectRoom(room)"}
+ .label {{room.name}}
+ %component-modal{"ng-if" => "room.showRoom", "component" => "room", "on-dismiss" => "ctrl.onRoomDismiss"}
+
+
+ .right
+
+ .item{"ng-if" => "ctrl.newUpdateAvailable", "ng-click" => "ctrl.clickedNewUpdateAnnouncement()"}
+ %span.info.label New update downloaded. Installs on app restart.
+
+ .item.no-pointer{"ng-if" => "ctrl.lastSyncDate && !ctrl.isRefreshing"}
+ .label.subtle
+ Last refreshed {{ctrl.lastSyncDate | appDateTime}}
+ .item{"ng-if" => "ctrl.lastSyncDate && ctrl.isRefreshing"}
+ .spinner.small
+
+ .item{"ng-if" => "ctrl.offline"}
+ .label Offline
+ .item{"ng-if" => "!ctrl.offline", "ng-click" => "ctrl.refreshData()"}
+ .label Refresh
+
+ .item#lock-item{"ng-if" => "ctrl.hasPasscode()"}
+ .label
+ %i.icon.ion-locked{"ng-if" => "ctrl.hasPasscode()", "ng-click" => "ctrl.lockApp()"}
diff --git a/app/assets/templates/frontend/directives/contextual-menu.html.haml b/app/assets/templates/frontend/directives/contextual-menu.html.haml
deleted file mode 100644
index 416bd3c24..000000000
--- a/app/assets/templates/frontend/directives/contextual-menu.html.haml
+++ /dev/null
@@ -1,33 +0,0 @@
-%ul.dropdown-menu.sectioned-menu
- .extension{"ng-repeat" => "extension in extensions"}
- .header{"ng-click" => "extension.hide = !extension.hide"}
- .title {{extension.name}}
- .subtitle
- Will submit your note
- %strong {{accessTypeForExtension(extension)}}
- .spinner.loading{"ng-if" => "extension.loading"}
- %div{"ng-if" => "extension.hide"} …
- %ul{"ng-if" => "!extension.hide"}
- %li.menu-item{"ng-repeat" => "action in extension.actionsWithContextForItem(item)", "ng-click" => "executeAction(action, extension);",
- "ng-class" => "{'faded' : !isActionEnabled(action, extension)}"}
- %label.menu-item-title {{action.label}}
- .menu-item-subtitle {{action.desc}}
-
- .small.normal{"ng-if" => "!isActionEnabled(action, extension)"}
- Requires {{action.access_type}} access to this note.
-
- %div{"ng-if" => "action.showNestedActions"}
- %ul.mt-10
- %li.menu-item.white-bg.nested-hover{"ng-repeat" => "subaction in action.subactions", "ng-click" => "executeAction(subaction, extension, action); $event.stopPropagation();", "style" => "margin-top: -1px;"}
- %label.menu-item-title {{subaction.label}}
- .menu-item-subtitle {{subaction.desc}}
- %span{"ng-if" => "subaction.running"}
- .spinner{"style" => "margin-top: 3px;"}
-
- %span{"ng-if" => "action.running"}
- .spinner{"style" => "margin-top: 3px;"}
-
-.extension-render-modal{"ng-if" => "renderData.showRenderModal", "ng-click" => "renderData.showRenderModal = false"}
- .content
- %h2 {{renderData.title}}
- %p.normal{"style" => "white-space: pre-wrap; font-family: monospace; font-size: 16px;"} {{renderData.text}}
diff --git a/app/assets/templates/frontend/directives/editor-menu.html.haml b/app/assets/templates/frontend/directives/editor-menu.html.haml
deleted file mode 100644
index cad2f2d0b..000000000
--- a/app/assets/templates/frontend/directives/editor-menu.html.haml
+++ /dev/null
@@ -1,18 +0,0 @@
-%ul.dropdown-menu.sectioned-menu
- .header
- .title System Editor
- %ul
- %li.menu-item{"ng-click" => "selectEditor($event, null)"}
- %span.pull-left.mr-10{"ng-if" => "selectedEditor == null"} ✓
- %label.menu-item-title.pull-left Plain
-
- %div{"ng-if" => "editors.length > 0"}
- .header
- .title External Editors
- .subtitle Can access your current note decrypted.
- %ul
- %li.menu-item{"ng-repeat" => "editor in editors", "ng-click" => "selectEditor($event, editor)"}
- %strong.red.medium{"ng-if" => "editor.conflict_of"} Conflicted copy
- %label.menu-item-title
- %span.inline.tinted.mr-10{"ng-if" => "selectedEditor === editor"} ✓
- {{editor.name}}
diff --git a/app/assets/templates/frontend/directives/global-extensions-menu.html.haml b/app/assets/templates/frontend/directives/global-extensions-menu.html.haml
deleted file mode 100644
index fe8965304..000000000
--- a/app/assets/templates/frontend/directives/global-extensions-menu.html.haml
+++ /dev/null
@@ -1,138 +0,0 @@
-.panel.panel-default.account-panel.panel-right#global-ext-menu
- .panel-body
- .container
- .float-group.h20
- %h1.tinted.pull-left Extensions
- %a.block.pull-right.dashboard-link{"href" => "https://dashboard.standardnotes.org", "target" => "_blank"} Open Dashboard
- %div.clear{"ng-if" => "!extensionManager.extensions.length && !themeManager.themes.length && !componentManager.components.length"}
- %p Customize your experience with editors, themes, and actions.
- .tinted-box.mt-10
- %h3 Available as part of the Extended subscription.
- %p.mt-5 Note history
- %p.mt-5 Automated backups
- %p.mt-5 Editors, themes, and actions
- %a{"href" => "https://standardnotes.org/extensions", "target" => "_blank"}
- %button.mt-10
- %h3 Learn More
-
- %div{"ng-if" => "themeManager.themes.length > 0"}
- .header.container.section-margin
- %h2 Themes
- %ul
- %li{"ng-repeat" => "theme in themeManager.themes | orderBy: 'name'", "ng-click" => "clickedExtension(theme)"}
- .container
- %h3
- %input.bold{"ng-if" => "theme.rename", "ng-model" => "theme.tempName", "ng-keyup" => "$event.keyCode == 13 && submitExtensionRename(theme);", "mb-autofocus" => "true", "should-focus" => "true"}
- %span{"ng-if" => "!theme.rename"} {{theme.name}}
- %a{"ng-if" => "!themeManager.isThemeActive(theme)", "ng-click" => "themeManager.activateTheme(theme); $event.stopPropagation();"} Activate
- %a{"ng-if" => "themeManager.isThemeActive(theme)", "ng-click" => "themeManager.deactivateTheme(theme); $event.stopPropagation();"} Deactivate
- .mt-3{"ng-if" => "theme.showDetails"}
- .link-group
- %a{"ng-click" => "renameExtension(theme); $event.stopPropagation();"} Rename
- %a{"ng-click" => "theme.showLink = !theme.showLink; $event.stopPropagation();"} Show Link
- %a.red{"ng-click" => "deleteTheme(theme); $event.stopPropagation();"} Delete
- %p.small.selectable.wrap{"ng-if" => "theme.showLink"}
- {{theme.url}}
-
-
- %div{"ng-if" => "extensionManager.extensions.length"}
- .header.container.section-margin
- %h2 Actions
- %p{"style" => "margin-top: 3px;"} Choose "Actions" in the note editor to use installed actions.
-
- %ul
- %li{"ng-repeat" => "extension in extensionManager.extensions | orderBy: 'name'", "ng-init" => "extension.formData = {}", "ng-click" => "clickedExtension(extension)"}
- .container
- %h3
- %input.bold{"ng-if" => "extension.rename", "ng-model" => "extension.tempName", "ng-keyup" => "$event.keyCode == 13 && submitExtensionRename(extension);", "mb-autofocus" => "true", "should-focus" => "true"}
- %span{"ng-if" => "!extension.rename"} {{extension.name}}
- %p.small{"ng-if" => "extension.description"} {{extension.description}}
- %div{"ng-if" => "extension.showDetails"}
- .mt-10
- %label.block Access Type
- %label.normal.block{"ng-click" => " $event.stopPropagation();"}
- %input{"type" => "radio", "ng-model" => "extension.encrypted", "ng-value" => "true", "ng-change" => "changeExtensionEncryptionFormat(true, extension);"}
- Encrypted
- %label.normal.block{"ng-click" => " $event.stopPropagation();"}
- %input{"type" => "radio", "ng-model" => "extension.encrypted", "ng-value" => "false", "ng-change" => "changeExtensionEncryptionFormat(false, extension);"}
- Decrypted
-
- .small-v-space
-
- %ul{"ng-repeat" => "action in extension.actionsInGlobalContext()"}
- %li
- %label.block {{action.label}}
- %em{"style" => "font-style: italic;"} {{action.desc}}
- %em{"ng-if" => "action.repeat_mode == 'watch'"}
- Repeats when a change is made to your items.
- %em{"ng-if" => "action.repeat_mode == 'loop'"}
- Repeats at most once every {{action.repeat_timeout}} seconds
- %div
- %a{"ng-click" => "action.showPermissions = !action.showPermissions"} {{action.showPermissions ? "Hide permissions" : "Show permissions"}}
- %div{"ng-if" => "action.showPermissions"}
- {{action.permissionsString()}}
- %label.block.normal {{action.encryptionModeString()}}
-
- %div
- .mt-5{"ng-if" => "action.repeat_mode"}
- %button.light.tinted{"ng-if" => "extensionManager.isRepeatActionEnabled(action)", "ng-click" => "extensionManager.disableRepeatAction(action, extension); $event.stopPropagation();"} Disable
- %button.light.tinted{"ng-if" => "!extensionManager.isRepeatActionEnabled(action)", "ng-click" => "extensionManager.enableRepeatAction(action, extension); $event.stopPropagation();"} Enable
- %button.light.mt-10{"ng-if" => "!action.running && !action.repeat_mode", "ng-click" => "selectedAction(action, extension); $event.stopPropagation();"}
- Perform Action
- .spinner.mb-5.block{"ng-if" => "action.running"}
- %p.mb-5.mt-5.small{"ng-if" => "!action.error && action.lastExecuted && !action.running"}
- Last run {{action.lastExecuted | appDateTime}}
- %label.red{"ng-if" => "action.error"}
- Error performing action.
-
- %a.block.mt-5{"ng-click" => "renameExtension(extension); $event.stopPropagation();"} Rename
- %a.block.mt-5{"ng-click" => "extension.showURL = !extension.showURL; $event.stopPropagation();"} Show Link
- %p.wrap.selectable.small{"ng-if" => "extension.showURL"} {{extension.url}}
- %a.block.mt-5{"ng-click" => "deleteActionExtension(extension); $event.stopPropagation();"} Delete
-
- %div{"ng-if" => "componentManager.components.length > 0"}
- .header.container.section-margin
- %h2 Components
- %ul
- %li{"ng-repeat" => "component in componentManager.components | orderBy: 'name'", "ng-click" => "clickedExtension(component)"}
- .container
- %h3
- %input.bold{"ng-if" => "component.rename", "ng-model" => "component.tempName", "ng-keyup" => "$event.keyCode == 13 && submitExtensionRename(component);", "mb-autofocus" => "true", "should-focus" => "true"}
- %span{"ng-if" => "!component.rename"} {{component.name}}
-
- %div{"ng-if" => "component.isEditor()"}
- %a{"ng-if" => "!component.isDefaultEditor()", "ng-click" => "makeEditorDefault(component); $event.stopPropagation();"} Make Default
- %a{"ng-if" => "component.isDefaultEditor()", "ng-click" => "removeEditorDefault(component); $event.stopPropagation();"} Remove Default
- %div{"ng-if" => "!component.isEditor()"}
- %a{"ng-if" => "!componentManager.isComponentActive(component)", "ng-click" => "componentManager.activateComponent(component); $event.stopPropagation();"} Activate
- %a{"ng-if" => "componentManager.isComponentActive(component)", "ng-click" => "componentManager.deactivateComponent(component); $event.stopPropagation();"} Deactivate
- .mt-3{"ng-if" => "component.showDetails"}
- .link-group
- %a{"ng-click" => "renameExtension(component); $event.stopPropagation();"} Rename
- %a{"ng-click" => "component.showLink = !component.showLink; $event.stopPropagation();"} Show Link
- %a{"ng-if" => "component.permissions.length", "ng-click" => "revokePermissions(component); $event.stopPropagation();"} Revoke Permissions
- %a.red{"ng-click" => "deleteComponent(component); $event.stopPropagation();"} Delete
- %p.small.selectable.wrap{"ng-if" => "component.showLink"}
- {{component.url}}
-
- %div{"ng-if" => "serverExtensions.length > 0"}
- .header.container.section-margin
- %h2 Server Extensions
- %ul
- %li{"ng-repeat" => "ext in serverExtensions", "ng-click" => "ext.showDetails = !ext.showDetails"}
- .container
- %strong.red.medium{"ng-if" => "ext.conflict_of"} Conflicted copy
- %h3 {{nameForServerExtension(ext)}}
- %div.mt-3{"ng-if" => "ext.showDetails"}
- .link-group
- %a{"ng-click" => "ext.showUrl = !ext.showUrl; $event.stopPropagation();"} Show Link
- %a.red{ "ng-click" => "deleteServerExt(ext); $event.stopPropagation();"} Delete
- .wrap.mt-5.selectable{"ng-if" => "ext.showUrl"} {{ext.url}}
-
- .container.section-margin
- %h2.tinted Install
- %p.faded Enter an install link
- %form.mt-10.mb-10
- %input.form-control{:autofocus => 'autofocus', :name => 'url', :required => true, :autocomplete => "off",
- :type => 'url', 'ng-model' => 'formData.installLink', "ng-keyup" => "$event.keyCode == 13 && submitInstallLink();"}
- %p.tinted{"ng-if" => "formData.successfullyInstalled"} Successfully installed extension.
diff --git a/app/assets/templates/frontend/directives/permissions-modal.html.haml b/app/assets/templates/frontend/directives/permissions-modal.html.haml
deleted file mode 100644
index 0ca1c7f70..000000000
--- a/app/assets/templates/frontend/directives/permissions-modal.html.haml
+++ /dev/null
@@ -1,25 +0,0 @@
-.background{"ng-click" => "dismiss()"}
-
-.content
- %h3 The following extension has requested these permissions:
-
- %h4 Extension
- %p Name: {{component.name}}
- %p.wrap URL: {{component.url}}
-
- %h4 Permissions
- .permission{"ng-repeat" => "permission in formattedPermissions"}
- %p {{permission}}
-
- %h4 Status
- %p.status{"ng-class" => "{'trusted tinted' : component.trusted}"} {{component.trusted ? 'Trusted' : 'Untrusted'}}
-
- .learn-more
- %h4 Details
- %p
- Extensions use an offline messaging system to communicate. With Trusted extensions, data is never sent remotely without your consent. Learn more about extension permissions at
- %a{"href" => "https://standardnotes.org/permissions", "target" => "_blank"} https://standardnotes.org/permissions.
-
- .buttons
- %button.standard.white{"ng-click" => "deny()"} Deny
- %button.standard.tinted{"ng-click" => "accept()"} Accept
diff --git a/app/assets/templates/frontend/editor.html.haml b/app/assets/templates/frontend/editor.html.haml
deleted file mode 100644
index e6cb98055..000000000
--- a/app/assets/templates/frontend/editor.html.haml
+++ /dev/null
@@ -1,62 +0,0 @@
-.section.editor{"ng-class" => "{'fullscreen' : ctrl.fullscreen}"}
- #editor-title-bar.section-title-bar{"ng-show" => "ctrl.note && !ctrl.note.errorDecrypting", "ng-class" => "{'fullscreen' : ctrl.fullscreen }"}
- .title
- %input.input#note-title-editor{"ng-model" => "ctrl.note.title", "ng-keyup" => "$event.keyCode == 13 && ctrl.saveTitle($event)",
- "ng-change" => "ctrl.nameChanged()", "ng-focus" => "ctrl.onNameFocus()",
- "select-on-click" => "true"}
-
- #save-status{"ng-class" => "{'red bold': ctrl.saveError, 'orange bold': ctrl.syncTakingTooLong}", "ng-bind-html" => "ctrl.noteStatus"}
-
- .editor-tags
- #note-tags-component-container{"ng-if" => "ctrl.tagsComponent && ctrl.tagsComponent.active"}
- %iframe#note-tags-iframe{"ng-src" => "{{ctrl.tagsComponent.url | trusted}}", "frameBorder" => "0", "sandbox" => "allow-scripts", "data-component-id" => "{{ctrl.tagsComponent.uuid}}"}
- %input.tags-input{"ng-if" => "!(ctrl.tagsComponent && ctrl.tagsComponent.active)", "type" => "text", "ng-keyup" => "$event.keyCode == 13 && $event.target.blur();",
- "ng-model" => "ctrl.tagsString", "placeholder" => "#tags", "ng-blur" => "ctrl.updateTagsFromTagsString($event, ctrl.tagsString)"}
- %ul.section-menu-bar{"ng-if" => "ctrl.note"}
- %li{"ng-class" => "{'selected' : ctrl.showMenu}", "click-outside" => "ctrl.showMenu = false;", "is-open" => "ctrl.showMenu"}
- %label{"ng-click" => "ctrl.showMenu = !ctrl.showMenu; ctrl.showExtensions = false; ctrl.showEditorMenu = false;"} Menu
-
- %ul.dropdown-menu.sectioned-menu{"ng-if" => "ctrl.showMenu"}
- %li
- %label{"ng-click" => "ctrl.selectedMenuItem($event); ctrl.togglePin()"}
- %i.icon.ion-ios-flag
- {{ctrl.note.pinned ? "Unpin" : "Pin"}}
- %li
- %label{"ng-click" => "ctrl.selectedMenuItem($event); ctrl.toggleArchiveNote()"}
- %i.icon.ion-ios-box
- {{ctrl.note.archived ? "Unarchive" : "Archive"}}
- %li
- %label{"ng-click" => "ctrl.selectedMenuItem($event); ctrl.deleteNote()"}
- %i.icon.ion-trash-b
- Delete
- %li
- %label{"ng-click" => "ctrl.selectedMenuItem($event); ctrl.toggleFullScreen()"}
- %i.icon.ion-arrow-expand
- Toggle Fullscreen
-
- %li{"ng-if" => "ctrl.hasDisabledStackComponents()"}
- %label{"ng-click" => "ctrl.selectedMenuItem($event); ctrl.restoreDisabledStackComponents()"} Restore Disabled Components
-
- %li{"ng-class" => "{'selected' : ctrl.showEditorMenu}", "click-outside" => "ctrl.showEditorMenu = false;", "is-open" => "ctrl.showEditorMenu"}
- %label{"ng-click" => "ctrl.showEditorMenu = !ctrl.showEditorMenu; ctrl.showMenu = false; ctrl.showExtensions = false;"} Editor
- %editor-menu{"ng-if" => "ctrl.showEditorMenu", "callback" => "ctrl.selectedEditor", "selected-editor" => "ctrl.editorComponent"}
-
- %li{"ng-class" => "{'selected' : ctrl.showExtensions}", "ng-if" => "ctrl.hasAvailableExtensions()", "click-outside" => "ctrl.showExtensions = false;", "is-open" => "ctrl.showExtensions"}
- %label{"ng-click" => "ctrl.showExtensions = !ctrl.showExtensions; ctrl.showMenu = false; ctrl.showEditorMenu = false;"} Actions
- %contextual-extensions-menu{"ng-if" => "ctrl.showExtensions", "item" => "ctrl.note"}
-
- .editor-content{"ng-if" => "ctrl.noteReady && !ctrl.note.errorDecrypting", "ng-class" => "{'fullscreen' : ctrl.fullscreen }"}
- %iframe#editor-iframe{"ng-if" => "ctrl.editorComponent && ctrl.editorComponent.active", "ng-src" => "{{ctrl.editorComponent.url | trusted}}", "data-component-id" => "{{ctrl.editorComponent.uuid}}", "frameBorder" => "0", "style" => "width: 100%;"}
- Loading
- %textarea.editable#note-text-editor{"ng-if" => "!ctrl.editorComponent", "ng-class" => "{'fullscreen' : ctrl.fullscreen }", "ng-model" => "ctrl.note.text",
- "ng-change" => "ctrl.contentChanged()", "ng-click" => "ctrl.clickedTextArea()", "ng-focus" => "ctrl.onContentFocus()", "dir" => "auto"}
- {{ctrl.onSystemEditorLoad()}}
-
-
- %section.section{"ng-if" => "ctrl.note.errorDecrypting"}
- %p.medium-padding{"style" => "padding-top: 0 !important;"} There was an error decrypting this item. Ensure you are running the latest version of this app, then sign out and sign back in to try again.
-
- #editor-pane-component-stack
- .component.component-stack-border{"ng-repeat" => "component in ctrl.componentStack", "ng-if" => "component.active", "ng-show" => "!component.ignoreEvents", "id" => "{{'component-' + component.uuid}}", "ng-mouseover" => "component.showExit = true", "ng-mouseleave" => "component.showExit = false"}
- .exit-button.body-text-color{"ng-if" => "component.showExit", "ng-click" => "ctrl.disableComponentForCurrentItem(component, true)"} ×
- %iframe{"ng-src" => "{{component.url | trusted}}", "frameBorder" => "0", "sandbox" => "allow-scripts allow-top-navigation-by-user-activation allow-popups allow-popups-to-escape-sandbox allow-modals", "data-component-id" => "{{component.uuid}}"}
diff --git a/app/assets/templates/frontend/footer.html.haml b/app/assets/templates/frontend/footer.html.haml
deleted file mode 100644
index 1f7506f45..000000000
--- a/app/assets/templates/frontend/footer.html.haml
+++ /dev/null
@@ -1,31 +0,0 @@
-#footer-bar
- .pull-left
- .footer-bar-link{"click-outside" => "ctrl.showAccountMenu = false;", "is-open" => "ctrl.showAccountMenu"}
- %a{"ng-click" => "ctrl.accountMenuPressed()", "ng-class" => "{red: ctrl.error}"} Account
- %account-menu{"ng-if" => "ctrl.showAccountMenu", "on-successful-auth" => "ctrl.onAuthSuccess"}
-
- .footer-bar-link{"click-outside" => "ctrl.showExtensionsMenu = false;", "is-open" => "ctrl.showExtensionsMenu"}
- %a{"ng-click" => "ctrl.toggleExtensions()"} Extensions
- %global-extensions-menu{"ng-if" => "ctrl.showExtensionsMenu"}
-
- .footer-bar-link
- %a{"href" => "https://standardnotes.org/help", "target" => "_blank"}
- Help
-
- .pull-right
-
- .footer-bar-link{"ng-if" => "ctrl.newUpdateAvailable", "ng-click" => "ctrl.clickedNewUpdateAnnouncement()"}
- %span.tinted.normal New update downloaded. Installs on app restart.
-
- .footer-bar-link{"style" => "margin-right: 5px;"}
- %span{"ng-if" => "ctrl.lastSyncDate", "style" => "float: left; font-weight: normal; margin-right: 8px;"}
- %span{"ng-if" => "!ctrl.isRefreshing"}
- Last refreshed {{ctrl.lastSyncDate | appDateTime}}
- %span{"ng-if" => "ctrl.isRefreshing"}
- .spinner{"style" => "margin-top: 2px;"}
-
- %strong{"ng-if" => "ctrl.offline"} Offline
- %a{"ng-if" => "!ctrl.offline", "ng-click" => "ctrl.refreshData()"} Refresh
-
- %span{"ng-if" => "ctrl.hasPasscode()"}
- %i.icon.ion-locked{"ng-if" => "ctrl.hasPasscode()", "ng-click" => "ctrl.lockApp()"}
diff --git a/app/assets/templates/frontend/lock-screen.html.haml b/app/assets/templates/frontend/lock-screen.html.haml
deleted file mode 100644
index e79c7cbef..000000000
--- a/app/assets/templates/frontend/lock-screen.html.haml
+++ /dev/null
@@ -1,9 +0,0 @@
-#lock-screen
- .content
- %h3.center-align Passcode Required
-
- %form.mt-20{"ng-submit" => "submitPasscodeForm()"}
- %input.form-control.mt-10{:type => 'password',
- "ng-model" => "formData.passcode", "autofocus" => "true",
- "placeholder" => "Enter Passcode", "autocomplete" => "new-password"}
- %button.standard.ui-button.block.tinted.mt-5{"type" => "submit"} Unlock
diff --git a/app/assets/templates/frontend/notes.html.haml b/app/assets/templates/frontend/notes.html.haml
deleted file mode 100644
index 810763227..000000000
--- a/app/assets/templates/frontend/notes.html.haml
+++ /dev/null
@@ -1,64 +0,0 @@
-.section.notes
- .content
- .section-title-bar#notes-title-bar
- .title {{ctrl.tag.title}} notes
- .add-button#notes-add-button{"ng-click" => "ctrl.createNewNote()"} +
- %br
- .filter-section
- %input.filter-bar{"select-on-click" => "true", "ng-model" => "ctrl.noteFilter.text", "placeholder" => "Search", "ng-change" => "ctrl.filterTextChanged()", "lowercase" => "true"}
- #search-clear-button{"ng-if" => "ctrl.noteFilter.text", "ng-click" => "ctrl.noteFilter.text = ''; ctrl.filterTextChanged()"} ✕
- %ul.section-menu-bar#notes-menu-bar
- %li.item-with-subtitle{"ng-class" => "{'selected' : ctrl.showMenu}"}
- .wrapper{"ng-click" => "ctrl.showMenu = !ctrl.showMenu"}
- %label Options
- .subtitle {{ctrl.optionsSubtitle()}}
-
- .sectioned-menu.dropdown-menu{"ng-if" => "ctrl.showMenu"}
- %ul
- .header
- .title Sort by
- %li{"ng-click" => "ctrl.selectedMenuItem($event); ctrl.selectedSortByCreated()"}
- %label
- %span.top.mt-5.mr-5{"ng-if" => "ctrl.sortBy == 'created_at'"} ✓
- By date added
- %li{"ng-click" => "ctrl.selectedMenuItem($event); ctrl.selectedSortByUpdated()"}
- %label
- %span.top.mt-5.mr-5{"ng-if" => "ctrl.sortBy == 'updated_at'"} ✓
- By date modified
- %li{"ng-click" => "ctrl.selectedMenuItem($event); ctrl.selectedSortByTitle()"}
- %label
- %span.top.mt-5.mr-5{"ng-if" => "ctrl.sortBy == 'title'"} ✓
- By title
- %ul{"ng-if" => "!ctrl.tag.archiveTag"}
- .header
- .title Archives
- %li{"ng-click" => "ctrl.selectedMenuItem($event); ctrl.toggleShowArchived()"}
- %label
- %span.top.mt-5.mr-5{"ng-if" => "ctrl.showArchived == true"} ✓
- Show archived notes
-
- .scrollable
- .infinite-scroll#notes-scrollable{"infinite-scroll" => "ctrl.paginate()", "can-load" => "true", "threshold" => "200"}
- .note{"ng-repeat" => "note in (ctrl.sortedNotes = (ctrl.tag.notes | filter: ctrl.filterNotes | sortBy: ctrl.sortBy| limitTo:ctrl.notesToDisplay)) track by note.uuid",
- "ng-click" => "ctrl.selectNote(note)", "ng-class" => "{'selected' : ctrl.selectedNote == note}"}
- %strong.red.medium{"ng-if" => "note.conflict_of"} Conflicted copy
- %strong.red.medium{"ng-if" => "note.errorDecrypting"} Error decrypting
-
- .pinned.tinted{"ng-if" => "note.pinned", "ng-class" => "{'tinted-selected' : ctrl.selectedNote == note}"}
- %i.icon.ion-ios-flag
- %strong.medium Pinned
-
- .archived.tinted{"ng-if" => "note.archived && !ctrl.tag.archiveTag", "ng-class" => "{'tinted-selected' : ctrl.selectedNote == note}"}
- %i.icon.ion-ios-box
- %strong.medium Archived
-
- .tags-string{"ng-if" => "ctrl.tag.all"}
- .faded {{note.tagsString()}}
-
- .name{"ng-if" => "note.title"}
- {{note.title}}
- .note-preview
- {{note.text}}
- .date.faded
- %span{"ng-if" => "ctrl.sortBy == 'updated_at'"} Modified {{note.updatedAtString() || 'Now'}}
- %span{"ng-if" => "ctrl.sortBy != 'updated_at'"} {{note.createdAtString() || 'Now'}}
diff --git a/app/assets/templates/frontend/home.html.haml b/app/assets/templates/home.html.haml
similarity index 94%
rename from app/assets/templates/frontend/home.html.haml
rename to app/assets/templates/home.html.haml
index bf98088c2..eb2b1f7b4 100644
--- a/app/assets/templates/frontend/home.html.haml
+++ b/app/assets/templates/home.html.haml
@@ -1,6 +1,6 @@
.main-ui-view
%lock-screen{"ng-if" => "needsUnlock", "on-success" => "onSuccessfulUnlock"}
- .app{"ng-if" => "!needsUnlock"}
+ .app#app{"ng-if" => "!needsUnlock"}
%tags-section{"save" => "tagsSave", "add-new" => "tagsAddNew", "will-select" => "tagsWillMakeSelection", "selection-made" => "tagsSelectionMade",
"all-tag" => "allTag", "archive-tag" => "archiveTag", "tags" => "tags", "remove-tag" => "removeTag"}
diff --git a/app/assets/templates/lock-screen.html.haml b/app/assets/templates/lock-screen.html.haml
new file mode 100644
index 000000000..08c2b4472
--- /dev/null
+++ b/app/assets/templates/lock-screen.html.haml
@@ -0,0 +1,14 @@
+#lock-screen.sn-component
+ .panel
+ .header
+ %h1.title Passcode Required
+ .content
+ .panel-section
+ %form.panel-form.panel-row{"ng-submit" => "submitPasscodeForm()"}
+ .panel-column.stretch
+ %input.panel-row{:type => 'password',
+ "ng-model" => "formData.passcode", "autofocus" => "true", "sn-autofocus" => "true", "should-focus" => "true",
+ "placeholder" => "Enter Passcode", "autocomplete" => "new-password"}
+ .button-group.stretch.panel-row.form-submit
+ %button.button.info{"type" => "submit"}
+ .label Unlock
diff --git a/app/assets/templates/notes.html.haml b/app/assets/templates/notes.html.haml
new file mode 100644
index 000000000..5797b152a
--- /dev/null
+++ b/app/assets/templates/notes.html.haml
@@ -0,0 +1,68 @@
+.section.notes#notes-column
+ .content
+ .section-title-bar#notes-title-bar
+ .padded
+ .section-title-bar-header
+ .title {{ctrl.panelTitle()}}
+ .add-button#notes-add-button{"ng-click" => "ctrl.createNewNote()"} +
+ .filter-section
+ %input.filter-bar#search-bar.mousetrap{"select-on-click" => "true", "ng-model" => "ctrl.noteFilter.text", "placeholder" => "Search", "ng-change" => "ctrl.filterTextChanged()", "lowercase" => "true"}
+ #search-clear-button{"ng-if" => "ctrl.noteFilter.text", "ng-click" => "ctrl.noteFilter.text = ''; ctrl.filterTextChanged()"} ✕
+ .sn-component#notes-menu-bar
+ .app-bar.no-edges
+ .left
+ .item{"ng-click" => "ctrl.showMenu = !ctrl.showMenu", "ng-class" => "{'selected' : ctrl.showMenu}"}
+ .column
+ .label
+ Options
+ .column
+ .sublabel {{ctrl.optionsSubtitle()}}
+
+ .sn-component{"ng-if" => "ctrl.showMenu"}
+ .menu-panel.dropdown-menu
+ .section
+ .header
+ %h4.title Sort By
+
+ %menu-row{"title" => "'Date Added'", "circle" => "ctrl.sortBy == 'created_at' && 'success'", "ng-click" => "ctrl.selectedMenuItem($event); ctrl.selectedSortByCreated()"}
+ %menu-row{"title" => "'Date Modified'", "circle" => "ctrl.sortBy == 'updated_at' && 'success'", "ng-click" => "ctrl.selectedMenuItem($event); ctrl.selectedSortByUpdated()"}
+ %menu-row{"title" => "'Title'", "circle" => "ctrl.sortBy == 'title' && 'success'", "ng-click" => "ctrl.selectedMenuItem($event); ctrl.selectedSortByTitle()"}
+
+ .section{"ng-if" => "!ctrl.tag.archiveTag"}
+ .header
+ %h4.title Display
+
+ %menu-row{"title" => "'Archived Notes'", "circle" => "ctrl.showArchived ? 'success' : 'danger'", "faded" => "!ctrl.showArchived", "ng-click" => "ctrl.selectedMenuItem($event); ctrl.toggleKey('showArchived')"}
+ %menu-row{"title" => "'Pinned Notes'", "circle" => "ctrl.hidePinned ? 'danger' : 'success'", "faded" => "ctrl.hidePinned", "ng-click" => "ctrl.selectedMenuItem($event); ctrl.toggleKey('hidePinned')"}
+ %menu-row{"title" => "'Note Preview'", "circle" => "ctrl.hideNotePreview ? 'danger' : 'success'", "faded" => "ctrl.hideNotePreview", "ng-click" => "ctrl.selectedMenuItem($event); ctrl.toggleKey('hideNotePreview')"}
+ %menu-row{"title" => "'Date'", "circle" => "ctrl.hideDate ? 'danger' : 'success'","faded" => "ctrl.hideDate", "ng-click" => "ctrl.selectedMenuItem($event); ctrl.toggleKey('hideDate')"}
+ %menu-row{"title" => "'Tags'", "circle" => "ctrl.hideTags ? 'danger' : 'success'","faded" => "ctrl.hideTags", "ng-click" => "ctrl.selectedMenuItem($event); ctrl.toggleKey('hideTags')"}
+
+
+ .scrollable
+ .infinite-scroll#notes-scrollable{"infinite-scroll" => "ctrl.paginate()", "can-load" => "true", "threshold" => "200"}
+ .note{"ng-repeat" => "note in (ctrl.sortedNotes = (ctrl.tag.notes | filter: ctrl.filterNotes | sortBy: ctrl.sortBy | limitTo:ctrl.notesToDisplay)) track by note.uuid",
+ "ng-click" => "ctrl.selectNote(note)", "ng-class" => "{'selected' : ctrl.selectedNote == note}"}
+ %strong.red.medium{"ng-if" => "note.conflict_of"} Conflicted copy
+ %strong.red.medium{"ng-if" => "note.errorDecrypting"} Error decrypting
+
+ .pinned.tinted{"ng-if" => "note.pinned", "ng-class" => "{'tinted-selected' : ctrl.selectedNote == note}"}
+ %i.icon.ion-bookmark
+ %strong.medium Pinned
+
+ .archived.tinted{"ng-if" => "note.archived && !ctrl.tag.archiveTag", "ng-class" => "{'tinted-selected' : ctrl.selectedNote == note}"}
+ %i.icon.ion-ios-box
+ %strong.medium Archived
+
+ .tags-string{"ng-if" => "ctrl.shouldShowTags(note)"}
+ .faded {{note.tagsString()}}
+
+ .name{"ng-if" => "note.title"}
+ {{note.title}}
+ .note-preview{"ng-if" => "!ctrl.hideNotePreview"}
+ {{note.text}}
+ .date.faded{"ng-if" => "!ctrl.hideDate"}
+ %span{"ng-if" => "ctrl.sortBy == 'updated_at'"} Modified {{note.updatedAtString() || 'Now'}}
+ %span{"ng-if" => "ctrl.sortBy != 'updated_at'"} {{note.createdAtString() || 'Now'}}
+
+ %panel-resizer{"panel-id" => "'notes-column'", "on-resize-finish" => "ctrl.onPanelResize", "control" => "ctrl.panelController", "hoverable" => "true", "collapsable" => "true"}
diff --git a/app/assets/templates/frontend/tags.html.haml b/app/assets/templates/tags.html.haml
similarity index 77%
rename from app/assets/templates/frontend/tags.html.haml
rename to app/assets/templates/tags.html.haml
index 4b689860c..f99e9bfba 100644
--- a/app/assets/templates/frontend/tags.html.haml
+++ b/app/assets/templates/tags.html.haml
@@ -1,9 +1,13 @@
.section.tags#tags-column
- %iframe#tags-list-iframe{"ng-if" => "ctrl.component && ctrl.component.active", "ng-src" => "{{ctrl.component.url | trusted}}", "frameBorder" => "0", "style" => "width: 100%; height: 100%;", "sandbox" => "allow-scripts"}
+
+ .component-view-container{"ng-if" => "ctrl.component.active"}
+ %component-view.component-view{"component" => "ctrl.component"}
+
#tags-content.content{"ng-if" => "!(ctrl.component && ctrl.component.active)"}
#tags-title-bar.section-title-bar
- .title Tags
- .add-button#tag-add-button{"ng-click" => "ctrl.clickedAddNewTag()"} +
+ .section-title-bar-header
+ .title Tags
+ .add-button#tag-add-button{"ng-click" => "ctrl.clickedAddNewTag()"} +
.scrollable
.tag{"ng-if" => "ctrl.allTag", "ng-click" => "ctrl.selectTag(ctrl.allTag)", "ng-class" => "{'selected' : ctrl.selectedTag == ctrl.allTag}"}
@@ -13,7 +17,7 @@
.tag{"ng-repeat" => "tag in ctrl.tags track by tag.uuid", "ng-click" => "ctrl.selectTag(tag)", "ng-class" => "{'selected' : ctrl.selectedTag == tag}"}
.info
%input.title{"ng-attr-id" => "tag-{{tag.uuid}}", "ng-click" => "ctrl.selectTag(tag)", "ng-model" => "tag.title",
- "ng-keyup" => "$event.keyCode == 13 && ctrl.saveTag($event, tag)", "mb-autofocus" => "true", "should-focus" => "ctrl.newTag || ctrl.editingTag == tag",
+ "ng-keyup" => "$event.keyCode == 13 && ctrl.saveTag($event, tag)", "sn-autofocus" => "true", "should-focus" => "ctrl.newTag || ctrl.editingTag == tag",
"ng-change" => "ctrl.tagTitleDidChange(tag)", "ng-blur" => "ctrl.saveTag($event, tag)", "spellcheck" => "false"}
.count {{ctrl.noteCount(tag)}}
@@ -27,3 +31,5 @@
.tag.faded{"ng-if" => "ctrl.archiveTag", "ng-click" => "ctrl.selectTag(ctrl.archiveTag)", "ng-class" => "{'selected' : ctrl.selectedTag == ctrl.archiveTag}"}
.info
%input.title{"ng-disabled" => "true", "ng-model" => "ctrl.archiveTag.title"}
+
+ %panel-resizer{"panel-id" => "'tags-column'", "on-resize-finish" => "ctrl.onPanelResize", "control" => "ctrl.panelController", "hoverable" => "true", "collapsable" => "true"}
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 76def86a7..e3aa18d09 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -7,7 +7,7 @@ class ApplicationController < ActionController::Base
layout :false
- def frontend
+ def app
end
diff --git a/app/views/application/frontend.html.erb b/app/views/application/app.html.erb
similarity index 92%
rename from app/views/application/frontend.html.erb
rename to app/views/application/app.html.erb
index c1dea5432..d05065dc1 100644
--- a/app/views/application/frontend.html.erb
+++ b/app/views/application/app.html.erb
@@ -1,5 +1,5 @@
-
+
@@ -30,6 +30,7 @@
<% if Rails.env.development? %>
@@ -42,7 +43,7 @@
-
+
diff --git a/config/application.rb b/config/application.rb
index 16e4e7e40..ac93fc14b 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -53,7 +53,7 @@ module Neeto
font_src: %w(* 'self'),
form_action: %w('self'),
frame_ancestors: ["*"],
- img_src: %w('self' data:),
+ img_src: %w('self' * data:),
manifest_src: %w('self'),
media_src: %w('self'),
object_src: %w('self'),
diff --git a/config/cable.yml b/config/cable.yml
deleted file mode 100644
index 73739d638..000000000
--- a/config/cable.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-development:
- adapter: redis
- url: redis://localhost:6379
-
-test:
- adapter: async
-
-production:
- adapter: redis
- url: redis://localhost:6379/1
diff --git a/config/deploy.rb b/config/deploy.rb
index 0397e5190..572e17333 100644
--- a/config/deploy.rb
+++ b/config/deploy.rb
@@ -1,6 +1,4 @@
CAP_CONFIG = YAML.load_file("config/cap.yml")
-# config valid only for current version of Capistrano
-lock '3.6.1'
set :application, 'neeto'
set :repo_url, CAP_CONFIG["default"]["repo_url"]
@@ -11,10 +9,6 @@ set :repo_url, CAP_CONFIG["default"]["repo_url"]
# Default deploy_to directory is /var/www/my_app_name
# set :deploy_to, '/var/www/my_app_name'
-# Default value for :scm is :git
-set :scm, :git
-set :git_strategy, Capistrano::Git::SubmoduleStrategy
-
# Default value for :format is :airbrussh.
# set :format, :airbrussh
diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb
index bd097f99c..cb2eb3fc6 100644
--- a/config/initializers/assets.rb
+++ b/config/initializers/assets.rb
@@ -12,7 +12,6 @@ Rails.application.config.assets.precompile << /\.(?:svg|eot|woff|ttf)\z/
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
-# Rails.application.config.assets.precompile += %w( search.js )
Rails.application.config.assets.precompile += %w( app.css compiled.min.js compiled.js )
# zip library
diff --git a/config/routes.rb b/config/routes.rb
index 3bd46ba1b..1697cb1b1 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,3 +1,3 @@
Rails.application.routes.draw do
- root 'application#frontend'
+ root 'application#app'
end
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 000000000..8555f1a06
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,6544 @@
+{
+ "name": "standard-notes",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "JSONStream": {
+ "version": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz",
+ "integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=",
+ "dev": true,
+ "requires": {
+ "jsonparse": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "through": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
+ }
+ },
+ "abbrev": {
+ "version": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
+ "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=",
+ "dev": true
+ },
+ "accepts": {
+ "version": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz",
+ "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=",
+ "dev": true,
+ "requires": {
+ "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz",
+ "negotiator": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz"
+ }
+ },
+ "acorn": {
+ "version": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
+ "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=",
+ "dev": true
+ },
+ "after": {
+ "version": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
+ "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=",
+ "dev": true
+ },
+ "align-text": {
+ "version": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
+ "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
+ "dev": true,
+ "requires": {
+ "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "longest": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
+ "repeat-string": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz"
+ }
+ },
+ "alter": {
+ "version": "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz",
+ "integrity": "sha1-x1iICGF1cgNKrmJICvJrHU0cs80=",
+ "dev": true,
+ "requires": {
+ "stable": "https://registry.npmjs.org/stable/-/stable-0.1.6.tgz"
+ }
+ },
+ "amdefine": {
+ "version": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+ "dev": true
+ },
+ "angular": {
+ "version": "https://registry.npmjs.org/angular/-/angular-1.6.6.tgz",
+ "integrity": "sha1-/Vo8+0N844LYVO4BEgeXl4Uny2Q=",
+ "dev": true
+ },
+ "angular-mocks": {
+ "version": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.6.6.tgz",
+ "integrity": "sha1-yTAY54OMbcXOrxprz5vhPIMOpRU=",
+ "dev": true
+ },
+ "ansi-regex": {
+ "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "anymatch": {
+ "version": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+ "integrity": "sha1-VT3Lj5HjyImEXf26NMd3IbkLnXo=",
+ "dev": true,
+ "requires": {
+ "micromatch": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "normalize-path": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz"
+ }
+ },
+ "argparse": {
+ "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
+ "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
+ }
+ },
+ "arr-diff": {
+ "version": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz"
+ }
+ },
+ "arr-flatten": {
+ "version": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=",
+ "dev": true
+ },
+ "array-filter": {
+ "version": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
+ "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=",
+ "dev": true
+ },
+ "array-find-index": {
+ "version": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
+ "dev": true
+ },
+ "array-map": {
+ "version": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
+ "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=",
+ "dev": true
+ },
+ "array-reduce": {
+ "version": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
+ "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=",
+ "dev": true
+ },
+ "array-slice": {
+ "version": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
+ "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=",
+ "dev": true
+ },
+ "array-unique": {
+ "version": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+ "dev": true
+ },
+ "arraybuffer.slice": {
+ "version": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz",
+ "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=",
+ "dev": true
+ },
+ "asn1": {
+ "version": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
+ "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
+ "dev": true
+ },
+ "asn1.js": {
+ "version": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz",
+ "integrity": "sha1-SLokC0WpKA6UdImQull9IWYX/UA=",
+ "dev": true,
+ "requires": {
+ "bn.js": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "minimalistic-assert": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz"
+ }
+ },
+ "assert": {
+ "version": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
+ "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
+ "dev": true,
+ "requires": {
+ "util": "https://registry.npmjs.org/util/-/util-0.10.3.tgz"
+ }
+ },
+ "assert-plus": {
+ "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
+ "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=",
+ "dev": true
+ },
+ "astw": {
+ "version": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz",
+ "integrity": "sha1-e9QXhNMkk5h66yOba04cV6hzuRc=",
+ "dev": true,
+ "requires": {
+ "acorn": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz"
+ }
+ },
+ "async": {
+ "version": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+ "dev": true
+ },
+ "async-each": {
+ "version": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
+ "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=",
+ "dev": true
+ },
+ "asynckit": {
+ "version": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+ "dev": true
+ },
+ "aws-sign2": {
+ "version": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
+ "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=",
+ "dev": true
+ },
+ "aws4": {
+ "version": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
+ "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
+ "dev": true
+ },
+ "babel-cli": {
+ "version": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz",
+ "integrity": "sha1-UCq1SHTX24itALiHoGODzgPQAvE=",
+ "dev": true,
+ "requires": {
+ "babel-core": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz",
+ "babel-polyfill": "6.26.0",
+ "babel-register": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "chokidar": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
+ "commander": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
+ "convert-source-map": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz",
+ "fs-readdir-recursive": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz",
+ "glob": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "output-file-sync": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz",
+ "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "slash": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+ "v8flags": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz"
+ },
+ "dependencies": {
+ "babel-code-frame": {
+ "version": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+ "dev": true,
+ "requires": {
+ "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "js-tokens": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz"
+ }
+ },
+ "babel-core": {
+ "version": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz",
+ "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=",
+ "dev": true,
+ "requires": {
+ "babel-code-frame": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+ "babel-generator": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz",
+ "babel-helpers": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
+ "babel-messages": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "babel-register": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "babylon": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "convert-source-map": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "json5": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "private": "https://registry.npmjs.org/private/-/private-0.1.7.tgz",
+ "slash": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz"
+ }
+ },
+ "babel-generator": {
+ "version": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz",
+ "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=",
+ "dev": true,
+ "requires": {
+ "babel-messages": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "detect-indent": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
+ "jsesc": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+ "trim-right": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz"
+ }
+ },
+ "babel-register": {
+ "version": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
+ "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
+ "dev": true,
+ "requires": {
+ "babel-core": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "core-js": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz",
+ "home-or-tmp": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "source-map-support": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz",
+ "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=",
+ "dev": true
+ }
+ }
+ },
+ "babel-runtime": {
+ "version": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "dev": true,
+ "requires": {
+ "core-js": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
+ "regenerator-runtime": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz"
+ }
+ },
+ "babel-template": {
+ "version": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "babylon": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ }
+ },
+ "babel-traverse": {
+ "version": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+ "dev": true,
+ "requires": {
+ "babel-code-frame": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+ "babel-messages": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "babylon": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "globals": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+ "invariant": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ }
+ },
+ "babel-types": {
+ "version": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "to-fast-properties": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz"
+ }
+ },
+ "babylon": {
+ "version": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=",
+ "dev": true
+ },
+ "regenerator-runtime": {
+ "version": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
+ "integrity": "sha1-flT+W1zNXWYk6mJVw0c74JC4AuE=",
+ "dev": true
+ }
+ }
+ },
+ "babel-code-frame": {
+ "version": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz",
+ "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=",
+ "dev": true,
+ "requires": {
+ "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "js-tokens": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz"
+ }
+ },
+ "babel-core": {
+ "version": "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz",
+ "integrity": "sha1-fdQrBGPHQunVKW3rPsZ6kyLa1yk=",
+ "dev": true,
+ "requires": {
+ "babel-code-frame": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz",
+ "babel-generator": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz",
+ "babel-helpers": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
+ "babel-messages": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "babel-register": "https://registry.npmjs.org/babel-register/-/babel-register-6.24.1.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz",
+ "babylon": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz",
+ "convert-source-map": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "json5": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "private": "https://registry.npmjs.org/private/-/private-0.1.7.tgz",
+ "slash": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz"
+ }
+ },
+ "babel-generator": {
+ "version": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz",
+ "integrity": "sha1-M6GvcNXyiQrrRlpKd5PB32qeqfw=",
+ "dev": true,
+ "requires": {
+ "babel-messages": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz",
+ "detect-indent": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
+ "jsesc": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+ "trim-right": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz"
+ }
+ },
+ "babel-helper-builder-binary-assignment-operator-visitor": {
+ "version": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz",
+ "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=",
+ "dev": true,
+ "requires": {
+ "babel-helper-explode-assignable-expression": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-helper-call-delegate": {
+ "version": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
+ "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=",
+ "dev": true,
+ "requires": {
+ "babel-helper-hoist-variables": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-helper-define-map": {
+ "version": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
+ "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=",
+ "dev": true,
+ "requires": {
+ "babel-helper-function-name": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ },
+ "dependencies": {
+ "babel-runtime": {
+ "version": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "dev": true,
+ "requires": {
+ "core-js": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
+ "regenerator-runtime": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz"
+ }
+ },
+ "babel-types": {
+ "version": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "to-fast-properties": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz"
+ }
+ },
+ "regenerator-runtime": {
+ "version": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
+ "integrity": "sha1-flT+W1zNXWYk6mJVw0c74JC4AuE=",
+ "dev": true
+ }
+ }
+ },
+ "babel-helper-explode-assignable-expression": {
+ "version": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz",
+ "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-helper-function-name": {
+ "version": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
+ "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=",
+ "dev": true,
+ "requires": {
+ "babel-helper-get-function-arity": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-helper-get-function-arity": {
+ "version": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
+ "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-helper-hoist-variables": {
+ "version": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
+ "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-helper-optimise-call-expression": {
+ "version": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
+ "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-helper-regex": {
+ "version": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
+ "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ },
+ "dependencies": {
+ "babel-runtime": {
+ "version": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "dev": true,
+ "requires": {
+ "core-js": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
+ "regenerator-runtime": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz"
+ }
+ },
+ "babel-types": {
+ "version": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "to-fast-properties": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz"
+ }
+ },
+ "regenerator-runtime": {
+ "version": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
+ "integrity": "sha1-flT+W1zNXWYk6mJVw0c74JC4AuE=",
+ "dev": true
+ }
+ }
+ },
+ "babel-helper-remap-async-to-generator": {
+ "version": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz",
+ "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=",
+ "dev": true,
+ "requires": {
+ "babel-helper-function-name": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-helper-replace-supers": {
+ "version": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
+ "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=",
+ "dev": true,
+ "requires": {
+ "babel-helper-optimise-call-expression": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
+ "babel-messages": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-helpers": {
+ "version": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
+ "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz"
+ }
+ },
+ "babel-messages": {
+ "version": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+ }
+ },
+ "babel-plugin-check-es2015-constants": {
+ "version": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
+ "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+ }
+ },
+ "babel-plugin-syntax-async-functions": {
+ "version": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
+ "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=",
+ "dev": true
+ },
+ "babel-plugin-syntax-exponentiation-operator": {
+ "version": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
+ "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=",
+ "dev": true
+ },
+ "babel-plugin-syntax-trailing-function-commas": {
+ "version": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz",
+ "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=",
+ "dev": true
+ },
+ "babel-plugin-transform-async-to-generator": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz",
+ "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=",
+ "dev": true,
+ "requires": {
+ "babel-helper-remap-async-to-generator": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz",
+ "babel-plugin-syntax-async-functions": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-arrow-functions": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
+ "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-block-scoped-functions": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
+ "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-block-scoping": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
+ "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ },
+ "dependencies": {
+ "babel-code-frame": {
+ "version": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+ "dev": true,
+ "requires": {
+ "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "js-tokens": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz"
+ }
+ },
+ "babel-runtime": {
+ "version": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "dev": true,
+ "requires": {
+ "core-js": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
+ "regenerator-runtime": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz"
+ }
+ },
+ "babel-template": {
+ "version": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "babylon": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ }
+ },
+ "babel-traverse": {
+ "version": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+ "dev": true,
+ "requires": {
+ "babel-code-frame": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+ "babel-messages": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "babylon": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "globals": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+ "invariant": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ }
+ },
+ "babel-types": {
+ "version": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "to-fast-properties": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz"
+ }
+ },
+ "babylon": {
+ "version": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=",
+ "dev": true
+ },
+ "regenerator-runtime": {
+ "version": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
+ "integrity": "sha1-flT+W1zNXWYk6mJVw0c74JC4AuE=",
+ "dev": true
+ }
+ }
+ },
+ "babel-plugin-transform-es2015-classes": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
+ "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=",
+ "dev": true,
+ "requires": {
+ "babel-helper-define-map": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
+ "babel-helper-function-name": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
+ "babel-helper-optimise-call-expression": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
+ "babel-helper-replace-supers": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
+ "babel-messages": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-computed-properties": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
+ "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-destructuring": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
+ "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-duplicate-keys": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
+ "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-for-of": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
+ "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-function-name": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
+ "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=",
+ "dev": true,
+ "requires": {
+ "babel-helper-function-name": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-literals": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
+ "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-modules-amd": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
+ "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=",
+ "dev": true,
+ "requires": {
+ "babel-plugin-transform-es2015-modules-commonjs": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-modules-commonjs": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz",
+ "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=",
+ "dev": true,
+ "requires": {
+ "babel-plugin-transform-strict-mode": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz"
+ },
+ "dependencies": {
+ "babel-code-frame": {
+ "version": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+ "dev": true,
+ "requires": {
+ "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "js-tokens": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz"
+ }
+ },
+ "babel-runtime": {
+ "version": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "dev": true,
+ "requires": {
+ "core-js": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
+ "regenerator-runtime": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz"
+ }
+ },
+ "babel-template": {
+ "version": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "babylon": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ }
+ },
+ "babel-traverse": {
+ "version": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+ "dev": true,
+ "requires": {
+ "babel-code-frame": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+ "babel-messages": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "babylon": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "globals": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+ "invariant": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ }
+ },
+ "babel-types": {
+ "version": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "to-fast-properties": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz"
+ }
+ },
+ "babylon": {
+ "version": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=",
+ "dev": true
+ },
+ "regenerator-runtime": {
+ "version": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
+ "integrity": "sha1-flT+W1zNXWYk6mJVw0c74JC4AuE=",
+ "dev": true
+ }
+ }
+ },
+ "babel-plugin-transform-es2015-modules-systemjs": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz",
+ "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=",
+ "dev": true,
+ "requires": {
+ "babel-helper-hoist-variables": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-modules-umd": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz",
+ "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=",
+ "dev": true,
+ "requires": {
+ "babel-plugin-transform-es2015-modules-amd": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-object-super": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz",
+ "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=",
+ "dev": true,
+ "requires": {
+ "babel-helper-replace-supers": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-parameters": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz",
+ "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=",
+ "dev": true,
+ "requires": {
+ "babel-helper-call-delegate": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
+ "babel-helper-get-function-arity": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-template": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-shorthand-properties": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz",
+ "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-spread": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
+ "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-sticky-regex": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz",
+ "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=",
+ "dev": true,
+ "requires": {
+ "babel-helper-regex": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-template-literals": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
+ "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-typeof-symbol": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
+ "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+ }
+ },
+ "babel-plugin-transform-es2015-unicode-regex": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz",
+ "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=",
+ "dev": true,
+ "requires": {
+ "babel-helper-regex": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "regexpu-core": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz"
+ }
+ },
+ "babel-plugin-transform-exponentiation-operator": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz",
+ "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=",
+ "dev": true,
+ "requires": {
+ "babel-helper-builder-binary-assignment-operator-visitor": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz",
+ "babel-plugin-syntax-exponentiation-operator": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+ }
+ },
+ "babel-plugin-transform-regenerator": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
+ "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=",
+ "dev": true,
+ "requires": {
+ "regenerator-transform": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz"
+ }
+ },
+ "babel-plugin-transform-strict-mode": {
+ "version": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
+ "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz"
+ }
+ },
+ "babel-polyfill": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
+ "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "core-js": "2.5.3",
+ "regenerator-runtime": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz"
+ },
+ "dependencies": {
+ "babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "dev": true,
+ "requires": {
+ "core-js": "2.5.3",
+ "regenerator-runtime": "0.11.1"
+ },
+ "dependencies": {
+ "regenerator-runtime": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
+ "dev": true
+ }
+ }
+ },
+ "core-js": {
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz",
+ "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=",
+ "dev": true
+ }
+ }
+ },
+ "babel-preset-env": {
+ "version": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.0.tgz",
+ "integrity": "sha1-LeHHgqeAoKXWBdGZyVdZbaQ8ROQ=",
+ "dev": true,
+ "requires": {
+ "babel-plugin-check-es2015-constants": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
+ "babel-plugin-syntax-trailing-function-commas": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz",
+ "babel-plugin-transform-async-to-generator": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz",
+ "babel-plugin-transform-es2015-arrow-functions": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
+ "babel-plugin-transform-es2015-block-scoped-functions": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
+ "babel-plugin-transform-es2015-block-scoping": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
+ "babel-plugin-transform-es2015-classes": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
+ "babel-plugin-transform-es2015-computed-properties": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
+ "babel-plugin-transform-es2015-destructuring": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
+ "babel-plugin-transform-es2015-duplicate-keys": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
+ "babel-plugin-transform-es2015-for-of": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
+ "babel-plugin-transform-es2015-function-name": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
+ "babel-plugin-transform-es2015-literals": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
+ "babel-plugin-transform-es2015-modules-amd": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
+ "babel-plugin-transform-es2015-modules-commonjs": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz",
+ "babel-plugin-transform-es2015-modules-systemjs": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz",
+ "babel-plugin-transform-es2015-modules-umd": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz",
+ "babel-plugin-transform-es2015-object-super": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz",
+ "babel-plugin-transform-es2015-parameters": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz",
+ "babel-plugin-transform-es2015-shorthand-properties": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz",
+ "babel-plugin-transform-es2015-spread": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
+ "babel-plugin-transform-es2015-sticky-regex": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz",
+ "babel-plugin-transform-es2015-template-literals": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
+ "babel-plugin-transform-es2015-typeof-symbol": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
+ "babel-plugin-transform-es2015-unicode-regex": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz",
+ "babel-plugin-transform-exponentiation-operator": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz",
+ "babel-plugin-transform-regenerator": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
+ "browserslist": "https://registry.npmjs.org/browserslist/-/browserslist-2.4.0.tgz",
+ "invariant": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",
+ "semver": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz"
+ }
+ },
+ "babel-preset-es2016": {
+ "version": "https://registry.npmjs.org/babel-preset-es2016/-/babel-preset-es2016-6.24.1.tgz",
+ "integrity": "sha1-+QC/k+LrwNJ235uKtZck6/2Vn4s=",
+ "dev": true,
+ "requires": {
+ "babel-plugin-transform-exponentiation-operator": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz"
+ }
+ },
+ "babel-register": {
+ "version": "https://registry.npmjs.org/babel-register/-/babel-register-6.24.1.tgz",
+ "integrity": "sha1-fhDhOi9xBlvfrVoXh7pFvKbe118=",
+ "dev": true,
+ "requires": {
+ "babel-core": "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "core-js": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
+ "home-or-tmp": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "source-map-support": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz"
+ }
+ },
+ "babel-runtime": {
+ "version": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=",
+ "dev": true,
+ "requires": {
+ "core-js": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
+ "regenerator-runtime": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz"
+ }
+ },
+ "babel-template": {
+ "version": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz",
+ "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-traverse": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz",
+ "babylon": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ }
+ },
+ "babel-traverse": {
+ "version": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz",
+ "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=",
+ "dev": true,
+ "requires": {
+ "babel-code-frame": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz",
+ "babel-messages": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz",
+ "babylon": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "globals": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+ "invariant": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ }
+ },
+ "babel-types": {
+ "version": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz",
+ "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "to-fast-properties": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz"
+ }
+ },
+ "babylon": {
+ "version": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz",
+ "integrity": "sha1-Pot0AriNIsNCPhN6FXeIOxX/hpo=",
+ "dev": true
+ },
+ "backo2": {
+ "version": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
+ "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
+ "dev": true
+ },
+ "balanced-match": {
+ "version": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "base64-arraybuffer": {
+ "version": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
+ "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=",
+ "dev": true
+ },
+ "base64-js": {
+ "version": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
+ "integrity": "sha1-qRlH2h9KUW6jjltOwOw3c2deCIY=",
+ "dev": true
+ },
+ "base64id": {
+ "version": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
+ "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=",
+ "dev": true
+ },
+ "bcrypt-pbkdf": {
+ "version": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
+ "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "tweetnacl": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz"
+ }
+ },
+ "better-assert": {
+ "version": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
+ "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
+ "dev": true,
+ "requires": {
+ "callsite": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz"
+ }
+ },
+ "binary-extensions": {
+ "version": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz",
+ "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=",
+ "dev": true
+ },
+ "blob": {
+ "version": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz",
+ "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=",
+ "dev": true
+ },
+ "bluebird": {
+ "version": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz",
+ "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=",
+ "dev": true
+ },
+ "bn.js": {
+ "version": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "integrity": "sha1-LN4J617jQfSEdGuwMJsyU7GxRC8=",
+ "dev": true
+ },
+ "body-parser": {
+ "version": "https://registry.npmjs.org/body-parser/-/body-parser-1.14.2.tgz",
+ "integrity": "sha1-EBXLH+LEQ4WCWVgdtTMy+NDPUPk=",
+ "dev": true,
+ "requires": {
+ "bytes": "https://registry.npmjs.org/bytes/-/bytes-2.2.0.tgz",
+ "content-type": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "depd": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz",
+ "http-errors": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz",
+ "iconv-lite": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz",
+ "on-finished": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "qs": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz",
+ "raw-body": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz",
+ "type-is": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "dev": true,
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
+ }
+ },
+ "iconv-lite": {
+ "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz",
+ "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=",
+ "dev": true
+ },
+ "ms": {
+ "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=",
+ "dev": true
+ },
+ "qs": {
+ "version": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz",
+ "integrity": "sha1-qfMRQq9GjLcrJbMBNrokVoNJFr4=",
+ "dev": true
+ }
+ }
+ },
+ "boom": {
+ "version": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
+ "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
+ "dev": true,
+ "requires": {
+ "hoek": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
+ }
+ },
+ "bower": {
+ "version": "https://registry.npmjs.org/bower/-/bower-1.8.2.tgz",
+ "integrity": "sha1-rfU1KcjUrwLvJPuNU0HBQZ0z4vc=",
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
+ "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
+ "dev": true,
+ "requires": {
+ "balanced-match": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "concat-map": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+ }
+ },
+ "braces": {
+ "version": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "dev": true,
+ "requires": {
+ "expand-range": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+ "preserve": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+ "repeat-element": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz"
+ }
+ },
+ "brorand": {
+ "version": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
+ "dev": true
+ },
+ "browser-pack": {
+ "version": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.0.2.tgz",
+ "integrity": "sha1-+GzWzvT1MAyOY+B6TVEvZfv/RTE=",
+ "dev": true,
+ "requires": {
+ "JSONStream": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz",
+ "combine-source-map": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.7.2.tgz",
+ "defined": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+ "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+ "umd": "https://registry.npmjs.org/umd/-/umd-3.0.1.tgz"
+ }
+ },
+ "browser-resolve": {
+ "version": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz",
+ "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=",
+ "dev": true,
+ "requires": {
+ "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz"
+ }
+ },
+ "browserify": {
+ "version": "https://registry.npmjs.org/browserify/-/browserify-14.4.0.tgz",
+ "integrity": "sha1-CJo0Y69Y0OSNjNQHCz90ZU1avKk=",
+ "dev": true,
+ "requires": {
+ "JSONStream": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz",
+ "assert": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
+ "browser-pack": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.0.2.tgz",
+ "browser-resolve": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz",
+ "browserify-zlib": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
+ "buffer": "https://registry.npmjs.org/buffer/-/buffer-5.0.7.tgz",
+ "cached-path-relative": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz",
+ "concat-stream": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz",
+ "console-browserify": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+ "constants-browserify": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+ "crypto-browserify": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.1.tgz",
+ "defined": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+ "deps-sort": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz",
+ "domain-browser": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz",
+ "duplexer2": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+ "events": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
+ "glob": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "has": "https://registry.npmjs.org/has/-/has-1.0.1.tgz",
+ "htmlescape": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz",
+ "https-browserify": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "insert-module-globals": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.0.1.tgz",
+ "labeled-stream-splicer": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz",
+ "module-deps": "https://registry.npmjs.org/module-deps/-/module-deps-4.1.1.tgz",
+ "os-browserify": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.1.2.tgz",
+ "parents": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
+ "path-browserify": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
+ "process": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "punycode": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "querystring-es3": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+ "read-only-stream": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz",
+ "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
+ "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+ "shasum": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz",
+ "shell-quote": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
+ "stream-browserify": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
+ "stream-http": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz",
+ "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+ "subarg": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
+ "syntax-error": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.3.0.tgz",
+ "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+ "timers-browserify": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz",
+ "tty-browserify": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
+ "url": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+ "util": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+ "vm-browserify": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
+ "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
+ }
+ },
+ "browserify-aes": {
+ "version": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.8.tgz",
+ "integrity": "sha1-yPo7G3WFu3unfFVgtgmW3extUwk=",
+ "dev": true,
+ "requires": {
+ "buffer-xor": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+ "cipher-base": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "create-hash": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
+ "evp_bytestokey": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz"
+ }
+ },
+ "browserify-cache-api": {
+ "version": "https://registry.npmjs.org/browserify-cache-api/-/browserify-cache-api-3.0.1.tgz",
+ "integrity": "sha1-liR+hT8Gj9bg1FzHPwuyzZd47wI=",
+ "dev": true,
+ "requires": {
+ "async": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+ "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
+ }
+ },
+ "browserify-cipher": {
+ "version": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz",
+ "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=",
+ "dev": true,
+ "requires": {
+ "browserify-aes": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.8.tgz",
+ "browserify-des": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz",
+ "evp_bytestokey": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz"
+ }
+ },
+ "browserify-des": {
+ "version": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz",
+ "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=",
+ "dev": true,
+ "requires": {
+ "cipher-base": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "des.js": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
+ }
+ },
+ "browserify-incremental": {
+ "version": "https://registry.npmjs.org/browserify-incremental/-/browserify-incremental-3.1.1.tgz",
+ "integrity": "sha1-BxPLdYckemMqnwjPG9FpuHi2Koo=",
+ "dev": true,
+ "requires": {
+ "JSONStream": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.10.0.tgz",
+ "browserify-cache-api": "https://registry.npmjs.org/browserify-cache-api/-/browserify-cache-api-3.0.1.tgz",
+ "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+ "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
+ },
+ "dependencies": {
+ "JSONStream": {
+ "version": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.10.0.tgz",
+ "integrity": "sha1-dDSdDYlSK3HzDwoD/5vSDKbxKsA=",
+ "dev": true,
+ "requires": {
+ "jsonparse": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz",
+ "through": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
+ }
+ },
+ "jsonparse": {
+ "version": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz",
+ "integrity": "sha1-MwVCrT8KZUZlt3jz6y2an6UHrGQ=",
+ "dev": true
+ }
+ }
+ },
+ "browserify-rsa": {
+ "version": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+ "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
+ "dev": true,
+ "requires": {
+ "bn.js": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "randombytes": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz"
+ }
+ },
+ "browserify-sign": {
+ "version": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
+ "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
+ "dev": true,
+ "requires": {
+ "bn.js": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "browserify-rsa": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+ "create-hash": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
+ "create-hmac": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz",
+ "elliptic": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "parse-asn1": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz"
+ }
+ },
+ "browserify-zlib": {
+ "version": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
+ "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=",
+ "dev": true,
+ "requires": {
+ "pako": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz"
+ }
+ },
+ "browserslist": {
+ "version": "https://registry.npmjs.org/browserslist/-/browserslist-2.4.0.tgz",
+ "integrity": "sha1-aT7pPQHmZGimNI2lSY4BH1ePh/g=",
+ "dev": true,
+ "requires": {
+ "caniuse-lite": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000739.tgz",
+ "electron-to-chromium": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.23.tgz"
+ }
+ },
+ "buffer": {
+ "version": "https://registry.npmjs.org/buffer/-/buffer-5.0.7.tgz",
+ "integrity": "sha1-VwopC2Jc8mAykMEUkiPSfM8E25c=",
+ "dev": true,
+ "requires": {
+ "base64-js": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
+ "ieee754": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz"
+ }
+ },
+ "buffer-xor": {
+ "version": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
+ "dev": true
+ },
+ "builtin-modules": {
+ "version": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+ "dev": true
+ },
+ "builtin-status-codes": {
+ "version": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
+ "dev": true
+ },
+ "bytes": {
+ "version": "https://registry.npmjs.org/bytes/-/bytes-2.2.0.tgz",
+ "integrity": "sha1-/TVGSkA/b5EXwt42Cez/nK4ABYg=",
+ "dev": true
+ },
+ "cached-path-relative": {
+ "version": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz",
+ "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc=",
+ "dev": true
+ },
+ "callsite": {
+ "version": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
+ "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
+ "dev": true
+ },
+ "camel-case": {
+ "version": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
+ "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=",
+ "dev": true,
+ "requires": {
+ "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.1.tgz",
+ "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz"
+ }
+ },
+ "camelcase": {
+ "version": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
+ "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
+ "dev": true
+ },
+ "camelcase-keys": {
+ "version": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+ "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
+ "dev": true,
+ "requires": {
+ "camelcase": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
+ "map-obj": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz"
+ }
+ },
+ "caniuse-lite": {
+ "version": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000739.tgz",
+ "integrity": "sha1-nujHAW9cUi27DAhj1Vxh77RTrpU=",
+ "dev": true
+ },
+ "caseless": {
+ "version": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
+ "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=",
+ "dev": true
+ },
+ "center-align": {
+ "version": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
+ "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
+ "dev": true,
+ "requires": {
+ "align-text": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
+ "lazy-cache": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz"
+ }
+ },
+ "chalk": {
+ "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "has-ansi": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
+ }
+ },
+ "change-case": {
+ "version": "https://registry.npmjs.org/change-case/-/change-case-3.0.1.tgz",
+ "integrity": "sha1-7l9a0EFa0a2egHLPSc1M+nZgpVQ=",
+ "dev": true,
+ "requires": {
+ "camel-case": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
+ "constant-case": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz",
+ "dot-case": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz",
+ "header-case": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz",
+ "is-lower-case": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz",
+ "is-upper-case": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz",
+ "lower-case": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
+ "lower-case-first": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz",
+ "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.1.tgz",
+ "param-case": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
+ "pascal-case": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz",
+ "path-case": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz",
+ "sentence-case": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz",
+ "snake-case": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz",
+ "swap-case": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz",
+ "title-case": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz",
+ "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
+ "upper-case-first": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz"
+ }
+ },
+ "chokidar": {
+ "version": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
+ "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
+ "dev": true,
+ "requires": {
+ "anymatch": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+ "async-each": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
+ "fsevents": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz",
+ "glob-parent": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "is-binary-path": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+ "is-glob": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "readdirp": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz"
+ }
+ },
+ "cipher-base": {
+ "version": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=",
+ "dev": true,
+ "requires": {
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz"
+ }
+ },
+ "clean-css": {
+ "version": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.27.tgz",
+ "integrity": "sha1-re91sxwWD/pdcvTeZ5ZuJmDBolU=",
+ "dev": true,
+ "requires": {
+ "commander": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
+ "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
+ "dev": true,
+ "requires": {
+ "graceful-readlink": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
+ }
+ },
+ "source-map": {
+ "version": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+ "dev": true,
+ "requires": {
+ "amdefine": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz"
+ }
+ }
+ }
+ },
+ "cliui": {
+ "version": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
+ "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
+ "dev": true,
+ "requires": {
+ "center-align": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
+ "right-align": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
+ "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz"
+ }
+ },
+ "coffee-script": {
+ "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz",
+ "integrity": "sha1-EpOLz5vhlI+gBvkuDEyegXBRCMA=",
+ "dev": true
+ },
+ "colors": {
+ "version": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
+ "dev": true
+ },
+ "combine-lists": {
+ "version": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz",
+ "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=",
+ "dev": true,
+ "requires": {
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ }
+ },
+ "combine-source-map": {
+ "version": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.7.2.tgz",
+ "integrity": "sha1-CHAxKFazB6h8xKxIbzqaYq7MwJ4=",
+ "dev": true,
+ "requires": {
+ "convert-source-map": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
+ "inline-source-map": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz",
+ "lodash.memoize": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz"
+ },
+ "dependencies": {
+ "convert-source-map": {
+ "version": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
+ "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=",
+ "dev": true
+ }
+ }
+ },
+ "combined-stream": {
+ "version": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
+ "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
+ "dev": true,
+ "requires": {
+ "delayed-stream": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
+ }
+ },
+ "commander": {
+ "version": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
+ "integrity": "sha1-FXFS/R56bI2YpbcVzzdt+SgARWM=",
+ "dev": true
+ },
+ "component-bind": {
+ "version": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
+ "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=",
+ "dev": true
+ },
+ "component-emitter": {
+ "version": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz",
+ "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=",
+ "dev": true
+ },
+ "component-inherit": {
+ "version": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
+ "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "concat-stream": {
+ "version": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz",
+ "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=",
+ "dev": true,
+ "requires": {
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
+ "typedarray": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
+ "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
+ "dev": true,
+ "requires": {
+ "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+ "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
+ }
+ },
+ "string_decoder": {
+ "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
+ }
+ }
+ },
+ "connect": {
+ "version": "https://registry.npmjs.org/connect/-/connect-3.6.5.tgz",
+ "integrity": "sha1-+43ee6B2OHfQ7J352sC0tA5yx9o=",
+ "dev": true,
+ "requires": {
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "finalhandler": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz",
+ "parseurl": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+ "utils-merge": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
+ "dev": true,
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
+ }
+ },
+ "parseurl": {
+ "version": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+ "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=",
+ "dev": true
+ }
+ }
+ },
+ "console-browserify": {
+ "version": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+ "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
+ "dev": true,
+ "requires": {
+ "date-now": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz"
+ }
+ },
+ "constant-case": {
+ "version": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz",
+ "integrity": "sha1-QXV2TTidP6nI7NKRhu1gBSQ7akY=",
+ "dev": true,
+ "requires": {
+ "snake-case": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz",
+ "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz"
+ }
+ },
+ "constants-browserify": {
+ "version": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
+ "dev": true
+ },
+ "content-type": {
+ "version": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz",
+ "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=",
+ "dev": true
+ },
+ "convert-source-map": {
+ "version": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz",
+ "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=",
+ "dev": true
+ },
+ "cookie": {
+ "version": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=",
+ "dev": true
+ },
+ "core-js": {
+ "version": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
+ "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=",
+ "dev": true
+ },
+ "core-util-is": {
+ "version": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "create-ecdh": {
+ "version": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz",
+ "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=",
+ "dev": true,
+ "requires": {
+ "bn.js": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "elliptic": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz"
+ }
+ },
+ "create-hash": {
+ "version": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
+ "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=",
+ "dev": true,
+ "requires": {
+ "cipher-base": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "ripemd160": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
+ "sha.js": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz"
+ }
+ },
+ "create-hmac": {
+ "version": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz",
+ "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=",
+ "dev": true,
+ "requires": {
+ "cipher-base": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "create-hash": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "ripemd160": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
+ "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+ "sha.js": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz"
+ }
+ },
+ "cross-spawn": {
+ "version": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-0.2.9.tgz",
+ "integrity": "sha1-vWf5bAfvtjA7f+lMHpefiEeOCjk=",
+ "dev": true,
+ "requires": {
+ "lru-cache": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz"
+ }
+ },
+ "cryptiles": {
+ "version": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
+ "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
+ "dev": true,
+ "requires": {
+ "boom": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
+ }
+ },
+ "crypto-browserify": {
+ "version": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.1.tgz",
+ "integrity": "sha1-lIlF78Z1ekANbl5a9HGU0QBkJ58=",
+ "dev": true,
+ "requires": {
+ "browserify-cipher": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz",
+ "browserify-sign": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
+ "create-ecdh": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz",
+ "create-hash": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
+ "create-hmac": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz",
+ "diffie-hellman": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "pbkdf2": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz",
+ "public-encrypt": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz",
+ "randombytes": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz"
+ }
+ },
+ "currently-unhandled": {
+ "version": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+ "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
+ "dev": true,
+ "requires": {
+ "array-find-index": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz"
+ }
+ },
+ "custom-event": {
+ "version": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
+ "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=",
+ "dev": true
+ },
+ "dargs": {
+ "version": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz",
+ "integrity": "sha1-A6nbtLXC8Tm/FK5T8LiipqhvThc=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz"
+ }
+ },
+ "dashdash": {
+ "version": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true
+ }
+ }
+ },
+ "date-now": {
+ "version": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+ "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
+ "dev": true
+ },
+ "dateformat": {
+ "version": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz",
+ "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=",
+ "dev": true,
+ "requires": {
+ "get-stdin": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+ "meow": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz"
+ }
+ },
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
+ "dev": true,
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
+ }
+ },
+ "decamelize": {
+ "version": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true
+ },
+ "define-properties": {
+ "version": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
+ "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
+ "dev": true,
+ "requires": {
+ "foreach": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
+ "object-keys": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz"
+ }
+ },
+ "defined": {
+ "version": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+ "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
+ "dev": true
+ },
+ "delayed-stream": {
+ "version": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "dev": true
+ },
+ "depd": {
+ "version": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz",
+ "integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM=",
+ "dev": true
+ },
+ "deps-sort": {
+ "version": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz",
+ "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=",
+ "dev": true,
+ "requires": {
+ "JSONStream": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz",
+ "shasum": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz",
+ "subarg": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
+ "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz"
+ }
+ },
+ "des.js": {
+ "version": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz",
+ "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=",
+ "dev": true,
+ "requires": {
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "minimalistic-assert": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz"
+ }
+ },
+ "detect-indent": {
+ "version": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
+ "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
+ "dev": true,
+ "requires": {
+ "repeating": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz"
+ }
+ },
+ "detective": {
+ "version": "https://registry.npmjs.org/detective/-/detective-4.5.0.tgz",
+ "integrity": "sha1-blqMaybmx6JUsca210kNmOyR7dE=",
+ "dev": true,
+ "requires": {
+ "acorn": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
+ "defined": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz"
+ }
+ },
+ "di": {
+ "version": "https://registry.npmjs.org/di/-/di-0.0.1.tgz",
+ "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=",
+ "dev": true
+ },
+ "diffie-hellman": {
+ "version": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz",
+ "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=",
+ "dev": true,
+ "requires": {
+ "bn.js": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "miller-rabin": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+ "randombytes": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz"
+ }
+ },
+ "dom-serialize": {
+ "version": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
+ "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=",
+ "dev": true,
+ "requires": {
+ "custom-event": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
+ "ent": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz",
+ "extend": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
+ "void-elements": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz"
+ }
+ },
+ "domain-browser": {
+ "version": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz",
+ "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=",
+ "dev": true
+ },
+ "dot-case": {
+ "version": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz",
+ "integrity": "sha1-NNzzf1Co6TwrO8qLt/uRVcfaO+4=",
+ "dev": true,
+ "requires": {
+ "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.1.tgz"
+ }
+ },
+ "duplexer2": {
+ "version": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+ "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz"
+ }
+ },
+ "ecc-jsbn": {
+ "version": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
+ "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "jsbn": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz"
+ }
+ },
+ "ee-first": {
+ "version": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+ "dev": true
+ },
+ "electron-to-chromium": {
+ "version": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.23.tgz",
+ "integrity": "sha1-5maKsYy2mvuPV3yKn8I9ACeIvnQ=",
+ "dev": true
+ },
+ "elliptic": {
+ "version": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz",
+ "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=",
+ "dev": true,
+ "requires": {
+ "bn.js": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "brorand": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+ "hash.js": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
+ "hmac-drbg": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "minimalistic-assert": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
+ "minimalistic-crypto-utils": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz"
+ }
+ },
+ "encodeurl": {
+ "version": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
+ "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=",
+ "dev": true
+ },
+ "engine.io": {
+ "version": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.3.tgz",
+ "integrity": "sha1-jef5eJXSDTm4X4ju7nd7K9QrE9Q=",
+ "dev": true,
+ "requires": {
+ "accepts": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz",
+ "base64id": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
+ "cookie": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
+ "engine.io-parser": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz",
+ "ws": "https://registry.npmjs.org/ws/-/ws-1.1.2.tgz"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
+ "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
+ "dev": true,
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz"
+ }
+ },
+ "ms": {
+ "version": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+ "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
+ "dev": true
+ }
+ }
+ },
+ "engine.io-client": {
+ "version": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.3.tgz",
+ "integrity": "sha1-F5jtk0USRkU9TG9jXXogH+lA1as=",
+ "dev": true,
+ "requires": {
+ "component-emitter": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "component-inherit": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
+ "engine.io-parser": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz",
+ "has-cors": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
+ "indexof": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
+ "parsejson": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz",
+ "parseqs": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
+ "parseuri": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
+ "ws": "https://registry.npmjs.org/ws/-/ws-1.1.2.tgz",
+ "xmlhttprequest-ssl": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz",
+ "yeast": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz"
+ },
+ "dependencies": {
+ "component-emitter": {
+ "version": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+ "dev": true
+ },
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
+ "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
+ "dev": true,
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz"
+ }
+ },
+ "ms": {
+ "version": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+ "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
+ "dev": true
+ }
+ }
+ },
+ "engine.io-parser": {
+ "version": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz",
+ "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=",
+ "dev": true,
+ "requires": {
+ "after": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
+ "arraybuffer.slice": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz",
+ "base64-arraybuffer": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
+ "blob": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz",
+ "has-binary": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz",
+ "wtf-8": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz"
+ }
+ },
+ "ent": {
+ "version": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz",
+ "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=",
+ "dev": true
+ },
+ "error-ex": {
+ "version": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz",
+ "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=",
+ "dev": true,
+ "requires": {
+ "is-arrayish": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz"
+ }
+ },
+ "es6-promise": {
+ "version": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz",
+ "integrity": "sha1-eILzCt3lskDM+n99eMVIMwlRrkI=",
+ "dev": true
+ },
+ "escape-html": {
+ "version": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+ "dev": true
+ },
+ "escape-string-regexp": {
+ "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
+ },
+ "esprima": {
+ "version": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+ "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+ "dev": true
+ },
+ "esutils": {
+ "version": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+ "dev": true
+ },
+ "eventemitter2": {
+ "version": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
+ "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=",
+ "dev": true
+ },
+ "eventemitter3": {
+ "version": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz",
+ "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=",
+ "dev": true
+ },
+ "events": {
+ "version": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
+ "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
+ "dev": true
+ },
+ "evp_bytestokey": {
+ "version": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=",
+ "dev": true,
+ "requires": {
+ "md5.js": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz",
+ "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz"
+ }
+ },
+ "exit": {
+ "version": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
+ "dev": true
+ },
+ "expand-braces": {
+ "version": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz",
+ "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=",
+ "dev": true,
+ "requires": {
+ "array-slice": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
+ "array-unique": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "braces": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz"
+ },
+ "dependencies": {
+ "braces": {
+ "version": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz",
+ "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=",
+ "dev": true,
+ "requires": {
+ "expand-range": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz"
+ }
+ },
+ "expand-range": {
+ "version": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz",
+ "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=",
+ "dev": true,
+ "requires": {
+ "is-number": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz",
+ "repeat-string": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz"
+ }
+ },
+ "is-number": {
+ "version": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz",
+ "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=",
+ "dev": true
+ },
+ "repeat-string": {
+ "version": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz",
+ "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=",
+ "dev": true
+ }
+ }
+ },
+ "expand-brackets": {
+ "version": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "dev": true,
+ "requires": {
+ "is-posix-bracket": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz"
+ }
+ },
+ "expand-range": {
+ "version": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+ "dev": true,
+ "requires": {
+ "fill-range": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz"
+ }
+ },
+ "extend": {
+ "version": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
+ "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
+ "dev": true
+ },
+ "extglob": {
+ "version": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz"
+ }
+ },
+ "extract-zip": {
+ "version": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz",
+ "integrity": "sha1-ksz22B73Cp+kwXRxFMzvbYaIpsQ=",
+ "dev": true,
+ "requires": {
+ "concat-stream": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz",
+ "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz",
+ "yauzl": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz"
+ },
+ "dependencies": {
+ "concat-stream": {
+ "version": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz",
+ "integrity": "sha1-U/fUPFHF5D+ByP3QMyHGMb5o1hE=",
+ "dev": true,
+ "requires": {
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
+ "typedarray": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
+ }
+ },
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz",
+ "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=",
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz",
+ "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=",
+ "dev": true,
+ "requires": {
+ "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
+ }
+ },
+ "readable-stream": {
+ "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
+ "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
+ "dev": true,
+ "requires": {
+ "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+ "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
+ }
+ },
+ "string_decoder": {
+ "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
+ }
+ }
+ },
+ "extsprintf": {
+ "version": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz",
+ "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=",
+ "dev": true
+ },
+ "faye-websocket": {
+ "version": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
+ "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=",
+ "dev": true,
+ "requires": {
+ "websocket-driver": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz"
+ }
+ },
+ "fd-slicer": {
+ "version": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
+ "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
+ "dev": true,
+ "requires": {
+ "pend": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz"
+ }
+ },
+ "figures": {
+ "version": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
+ }
+ },
+ "file-sync-cmp": {
+ "version": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz",
+ "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=",
+ "dev": true
+ },
+ "filename-regex": {
+ "version": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+ "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+ "dev": true
+ },
+ "fill-range": {
+ "version": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
+ "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=",
+ "dev": true,
+ "requires": {
+ "is-number": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+ "isobject": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "randomatic": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
+ "repeat-element": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
+ "repeat-string": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz"
+ }
+ },
+ "finalhandler": {
+ "version": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz",
+ "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=",
+ "dev": true,
+ "requires": {
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "encodeurl": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
+ "escape-html": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "on-finished": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "parseurl": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+ "statuses": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
+ "unpipe": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
+ "dev": true,
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
+ }
+ },
+ "parseurl": {
+ "version": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+ "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=",
+ "dev": true
+ }
+ }
+ },
+ "find-up": {
+ "version": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+ "dev": true,
+ "requires": {
+ "path-exists": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+ "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz"
+ }
+ },
+ "findup-sync": {
+ "version": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz",
+ "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=",
+ "dev": true,
+ "requires": {
+ "glob": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+ "dev": true,
+ "requires": {
+ "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
+ }
+ }
+ }
+ },
+ "for-in": {
+ "version": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true
+ },
+ "for-own": {
+ "version": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+ "dev": true,
+ "requires": {
+ "for-in": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz"
+ }
+ },
+ "foreach": {
+ "version": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
+ "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=",
+ "dev": true
+ },
+ "forever-agent": {
+ "version": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "dev": true
+ },
+ "form-data": {
+ "version": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
+ "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
+ "dev": true,
+ "requires": {
+ "asynckit": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "combined-stream": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
+ "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz"
+ }
+ },
+ "fs-extra": {
+ "version": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz",
+ "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "jsonfile": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
+ "klaw": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz"
+ }
+ },
+ "fs-readdir-recursive": {
+ "version": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz",
+ "integrity": "sha1-jNF0XItPiinIyuw5JHaSG6GV9WA=",
+ "dev": true
+ },
+ "fs.realpath": {
+ "version": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "fsevents": {
+ "version": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz",
+ "integrity": "sha1-MoK3E/s62A7eDp/PRhG1qm/AM/Q=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "nan": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz",
+ "node-pre-gyp": "0.6.36"
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
+ "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=",
+ "dev": true,
+ "optional": true
+ },
+ "ajv": {
+ "version": "4.11.8",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
+ "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "co": "4.6.0",
+ "json-stable-stringify": "1.0.1"
+ }
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "aproba": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.1.tgz",
+ "integrity": "sha1-ldNgDwdxCqDpKYxyatXs8urLq6s=",
+ "dev": true,
+ "optional": true
+ },
+ "are-we-there-yet": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz",
+ "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "delegates": "1.0.0",
+ "readable-stream": "2.2.9"
+ }
+ },
+ "asn1": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
+ "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
+ "dev": true,
+ "optional": true
+ },
+ "assert-plus": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
+ "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=",
+ "dev": true,
+ "optional": true
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+ "dev": true,
+ "optional": true
+ },
+ "aws-sign2": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
+ "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=",
+ "dev": true,
+ "optional": true
+ },
+ "aws4": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
+ "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
+ "dev": true,
+ "optional": true
+ },
+ "balanced-match": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
+ "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=",
+ "dev": true
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
+ "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "tweetnacl": "0.14.5"
+ }
+ },
+ "block-stream": {
+ "version": "0.0.9",
+ "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
+ "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3"
+ }
+ },
+ "boom": {
+ "version": "2.10.1",
+ "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
+ "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
+ "dev": true,
+ "requires": {
+ "hoek": "2.16.3"
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz",
+ "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=",
+ "dev": true,
+ "requires": {
+ "balanced-match": "0.4.2",
+ "concat-map": "0.0.1"
+ }
+ },
+ "buffer-shims": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz",
+ "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=",
+ "dev": true
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+ "dev": true,
+ "optional": true
+ },
+ "co": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
+ "dev": true,
+ "optional": true
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+ "dev": true
+ },
+ "combined-stream": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
+ "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
+ "dev": true,
+ "requires": {
+ "delayed-stream": "1.0.0"
+ }
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
+ "dev": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "cryptiles": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
+ "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "boom": "2.10.1"
+ }
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assert-plus": "1.0.0"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "debug": {
+ "version": "2.6.8",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "deep-extend": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz",
+ "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=",
+ "dev": true,
+ "optional": true
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "dev": true
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+ "dev": true,
+ "optional": true
+ },
+ "ecc-jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
+ "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "jsbn": "0.1.1"
+ }
+ },
+ "extend": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
+ "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
+ "dev": true,
+ "optional": true
+ },
+ "extsprintf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz",
+ "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=",
+ "dev": true
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "dev": true,
+ "optional": true
+ },
+ "form-data": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
+ "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "asynckit": "0.4.0",
+ "combined-stream": "1.0.5",
+ "mime-types": "2.1.15"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "fstream": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz",
+ "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "inherits": "2.0.3",
+ "mkdirp": "0.5.1",
+ "rimraf": "2.6.1"
+ }
+ },
+ "fstream-ignore": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz",
+ "integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "fstream": "1.0.11",
+ "inherits": "2.0.3",
+ "minimatch": "3.0.4"
+ }
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "aproba": "1.1.1",
+ "console-control-strings": "1.1.0",
+ "has-unicode": "2.0.1",
+ "object-assign": "4.1.1",
+ "signal-exit": "3.0.2",
+ "string-width": "1.0.2",
+ "strip-ansi": "3.0.1",
+ "wide-align": "1.1.2"
+ }
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assert-plus": "1.0.0"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "glob": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "1.0.0",
+ "inflight": "1.0.6",
+ "inherits": "2.0.3",
+ "minimatch": "3.0.4",
+ "once": "1.4.0",
+ "path-is-absolute": "1.0.1"
+ }
+ },
+ "graceful-fs": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
+ "dev": true
+ },
+ "har-schema": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz",
+ "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=",
+ "dev": true,
+ "optional": true
+ },
+ "har-validator": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
+ "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "ajv": "4.11.8",
+ "har-schema": "1.0.5"
+ }
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+ "dev": true,
+ "optional": true
+ },
+ "hawk": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
+ "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "boom": "2.10.1",
+ "cryptiles": "2.0.5",
+ "hoek": "2.16.3",
+ "sntp": "1.0.9"
+ }
+ },
+ "hoek": {
+ "version": "2.16.3",
+ "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+ "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
+ "dev": true
+ },
+ "http-signature": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
+ "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assert-plus": "0.2.0",
+ "jsprim": "1.4.0",
+ "sshpk": "1.13.0"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "requires": {
+ "once": "1.4.0",
+ "wrappy": "1.0.2"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ },
+ "ini": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz",
+ "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=",
+ "dev": true,
+ "optional": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "1.0.1"
+ }
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true,
+ "optional": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+ "dev": true,
+ "optional": true
+ },
+ "jodid25519": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz",
+ "integrity": "sha1-BtSRIlUJNBlHfUJWM2BuDpB4KWc=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "jsbn": "0.1.1"
+ }
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "dev": true,
+ "optional": true
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+ "dev": true,
+ "optional": true
+ },
+ "json-stable-stringify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
+ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "jsonify": "0.0.0"
+ }
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true,
+ "optional": true
+ },
+ "jsonify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+ "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
+ "dev": true,
+ "optional": true
+ },
+ "jsprim": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz",
+ "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.0.2",
+ "json-schema": "0.2.3",
+ "verror": "1.3.6"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "mime-db": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz",
+ "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=",
+ "dev": true
+ },
+ "mime-types": {
+ "version": "2.1.15",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz",
+ "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=",
+ "dev": true,
+ "requires": {
+ "mime-db": "1.27.0"
+ }
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "dev": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true,
+ "optional": true
+ },
+ "node-pre-gyp": {
+ "version": "0.6.36",
+ "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz",
+ "integrity": "sha1-22BBEst04NR3VU6bUFsXq936t4Y=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "mkdirp": "0.5.1",
+ "nopt": "4.0.1",
+ "npmlog": "4.1.0",
+ "rc": "1.2.1",
+ "request": "2.81.0",
+ "rimraf": "2.6.1",
+ "semver": "5.3.0",
+ "tar": "2.2.1",
+ "tar-pack": "3.4.0"
+ }
+ },
+ "nopt": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
+ "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "abbrev": "1.1.0",
+ "osenv": "0.1.4"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.0.tgz",
+ "integrity": "sha512-ocolIkZYZt8UveuiDS0yAkkIjid1o7lPG8cYm05yNYzBn8ykQtaiPMEGp8fY9tKdDgm8okpdKzkvu1y9hUYugA==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "are-we-there-yet": "1.1.4",
+ "console-control-strings": "1.1.0",
+ "gauge": "2.7.4",
+ "set-blocking": "2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+ "dev": true
+ },
+ "oauth-sign": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
+ "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
+ "dev": true,
+ "optional": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true,
+ "optional": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "1.0.2"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "dev": true,
+ "optional": true
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+ "dev": true,
+ "optional": true
+ },
+ "osenv": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz",
+ "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "os-homedir": "1.0.2",
+ "os-tmpdir": "1.0.2"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "performance-now": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
+ "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=",
+ "dev": true,
+ "optional": true
+ },
+ "process-nextick-args": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+ "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
+ "dev": true
+ },
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true,
+ "optional": true
+ },
+ "qs": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
+ "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=",
+ "dev": true,
+ "optional": true
+ },
+ "rc": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz",
+ "integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "deep-extend": "0.4.2",
+ "ini": "1.3.4",
+ "minimist": "1.2.0",
+ "strip-json-comments": "2.0.1"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "2.2.9",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz",
+ "integrity": "sha1-z3jsb0ptHrQ9JkiMrJfwQudLf8g=",
+ "dev": true,
+ "requires": {
+ "buffer-shims": "1.0.0",
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "1.0.0",
+ "process-nextick-args": "1.0.7",
+ "string_decoder": "1.0.1",
+ "util-deprecate": "1.0.2"
+ }
+ },
+ "request": {
+ "version": "2.81.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
+ "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "aws-sign2": "0.6.0",
+ "aws4": "1.6.0",
+ "caseless": "0.12.0",
+ "combined-stream": "1.0.5",
+ "extend": "3.0.1",
+ "forever-agent": "0.6.1",
+ "form-data": "2.1.4",
+ "har-validator": "4.2.1",
+ "hawk": "3.1.3",
+ "http-signature": "1.1.1",
+ "is-typedarray": "1.0.0",
+ "isstream": "0.1.2",
+ "json-stringify-safe": "5.0.1",
+ "mime-types": "2.1.15",
+ "oauth-sign": "0.8.2",
+ "performance-now": "0.2.0",
+ "qs": "6.4.0",
+ "safe-buffer": "5.0.1",
+ "stringstream": "0.0.5",
+ "tough-cookie": "2.3.2",
+ "tunnel-agent": "0.6.0",
+ "uuid": "3.0.1"
+ }
+ },
+ "rimraf": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz",
+ "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=",
+ "dev": true,
+ "requires": {
+ "glob": "7.1.2"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+ "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=",
+ "dev": true
+ },
+ "semver": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+ "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
+ "dev": true,
+ "optional": true
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "dev": true,
+ "optional": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+ "dev": true,
+ "optional": true
+ },
+ "sntp": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
+ "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "hoek": "2.16.3"
+ }
+ },
+ "sshpk": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz",
+ "integrity": "sha1-/yo+T9BEl1Vf7Zezmg/YL6+zozw=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "asn1": "0.2.3",
+ "assert-plus": "1.0.0",
+ "bcrypt-pbkdf": "1.0.1",
+ "dashdash": "1.14.1",
+ "ecc-jsbn": "0.1.1",
+ "getpass": "0.1.7",
+ "jodid25519": "1.0.2",
+ "jsbn": "0.1.1",
+ "tweetnacl": "0.14.5"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "requires": {
+ "code-point-at": "1.1.0",
+ "is-fullwidth-code-point": "1.0.0",
+ "strip-ansi": "3.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.1.tgz",
+ "integrity": "sha1-YuIA8DmVWmgQ2N8KM//A8BNmLZg=",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.0.1"
+ }
+ },
+ "stringstream": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
+ "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
+ "dev": true,
+ "optional": true
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "2.1.1"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+ "dev": true,
+ "optional": true
+ },
+ "tar": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
+ "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
+ "dev": true,
+ "requires": {
+ "block-stream": "0.0.9",
+ "fstream": "1.0.11",
+ "inherits": "2.0.3"
+ }
+ },
+ "tar-pack": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.0.tgz",
+ "integrity": "sha1-I74tf2cagzk3bL2wuP4/3r8xeYQ=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "debug": "2.6.8",
+ "fstream": "1.0.11",
+ "fstream-ignore": "1.0.5",
+ "once": "1.4.0",
+ "readable-stream": "2.2.9",
+ "rimraf": "2.6.1",
+ "tar": "2.2.1",
+ "uid-number": "0.0.6"
+ }
+ },
+ "tough-cookie": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz",
+ "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "punycode": "1.4.1"
+ }
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "safe-buffer": "5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "dev": true,
+ "optional": true
+ },
+ "uid-number": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz",
+ "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=",
+ "dev": true,
+ "optional": true
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "uuid": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz",
+ "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=",
+ "dev": true,
+ "optional": true
+ },
+ "verror": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz",
+ "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "extsprintf": "1.0.2"
+ }
+ },
+ "wide-align": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz",
+ "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "string-width": "1.0.2"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ }
+ }
+ },
+ "function-bind": {
+ "version": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz",
+ "integrity": "sha1-FhdnFMgBeY5Ojyz391KUZ7tKV3E=",
+ "dev": true
+ },
+ "gaze": {
+ "version": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz",
+ "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=",
+ "dev": true,
+ "requires": {
+ "globule": "https://registry.npmjs.org/globule/-/globule-1.2.0.tgz"
+ }
+ },
+ "generate-function": {
+ "version": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
+ "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=",
+ "dev": true
+ },
+ "generate-object-property": {
+ "version": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
+ "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
+ "dev": true,
+ "requires": {
+ "is-property": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
+ }
+ },
+ "get-stdin": {
+ "version": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
+ "dev": true
+ },
+ "getobject": {
+ "version": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz",
+ "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=",
+ "dev": true
+ },
+ "getpass": {
+ "version": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true
+ }
+ }
+ },
+ "glob": {
+ "version": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
+ }
+ },
+ "glob-base": {
+ "version": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+ "dev": true,
+ "requires": {
+ "glob-parent": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+ "is-glob": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz"
+ }
+ },
+ "glob-parent": {
+ "version": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+ "dev": true,
+ "requires": {
+ "is-glob": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz"
+ }
+ },
+ "globals": {
+ "version": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+ "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=",
+ "dev": true
+ },
+ "globule": {
+ "version": "https://registry.npmjs.org/globule/-/globule-1.2.0.tgz",
+ "integrity": "sha1-HcScaCLdnoovoAuiopUAboZkvQk=",
+ "dev": true,
+ "requires": {
+ "glob": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz"
+ }
+ },
+ "graceful-fs": {
+ "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
+ "dev": true
+ },
+ "graceful-readlink": {
+ "version": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+ "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
+ "dev": true
+ },
+ "grunt": {
+ "version": "https://registry.npmjs.org/grunt/-/grunt-1.0.1.tgz",
+ "integrity": "sha1-6HeHZOlEsY8yuw8QuQeEdcnftWs=",
+ "dev": true,
+ "requires": {
+ "coffee-script": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz",
+ "dateformat": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz",
+ "eventemitter2": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
+ "exit": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "findup-sync": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz",
+ "glob": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
+ "grunt-cli": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz",
+ "grunt-known-options": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.0.tgz",
+ "grunt-legacy-log": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-1.0.0.tgz",
+ "grunt-legacy-util": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.0.0.tgz",
+ "iconv-lite": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz",
+ "js-yaml": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz",
+ "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "nopt": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+ "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "rimraf": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
+ "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
+ }
+ },
+ "grunt-cli": {
+ "version": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz",
+ "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=",
+ "dev": true,
+ "requires": {
+ "findup-sync": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz",
+ "grunt-known-options": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.0.tgz",
+ "nopt": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+ "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz"
+ }
+ }
+ }
+ },
+ "grunt-angular-templates": {
+ "version": "https://registry.npmjs.org/grunt-angular-templates/-/grunt-angular-templates-1.1.0.tgz",
+ "integrity": "sha1-EJYDorlf8BAZtxjHA0EmjwnYvhk=",
+ "dev": true,
+ "requires": {
+ "html-minifier": "https://registry.npmjs.org/html-minifier/-/html-minifier-2.1.7.tgz"
+ }
+ },
+ "grunt-babel": {
+ "version": "https://registry.npmjs.org/grunt-babel/-/grunt-babel-6.0.0.tgz",
+ "integrity": "sha1-N4GJtIfeEWjExKn8iN1gBbNd+WA=",
+ "dev": true,
+ "requires": {
+ "babel-core": "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz"
+ }
+ },
+ "grunt-browserify": {
+ "version": "https://registry.npmjs.org/grunt-browserify/-/grunt-browserify-5.2.0.tgz",
+ "integrity": "sha1-N65E+9x199gelyUmThGwXmJTfEY=",
+ "dev": true,
+ "requires": {
+ "async": "https://registry.npmjs.org/async/-/async-2.5.0.tgz",
+ "browserify": "https://registry.npmjs.org/browserify/-/browserify-14.4.0.tgz",
+ "browserify-incremental": "https://registry.npmjs.org/browserify-incremental/-/browserify-incremental-3.1.1.tgz",
+ "glob": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+ "watchify": "https://registry.npmjs.org/watchify/-/watchify-3.9.0.tgz"
+ },
+ "dependencies": {
+ "async": {
+ "version": "https://registry.npmjs.org/async/-/async-2.5.0.tgz",
+ "integrity": "sha1-hDGQ/WtzV6C54clW7d3V7IRitU0=",
+ "dev": true,
+ "requires": {
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ }
+ }
+ }
+ },
+ "grunt-contrib-concat": {
+ "version": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-1.0.1.tgz",
+ "integrity": "sha1-YVCYYwhOhx1+ht5IwBUlntl3Rb0=",
+ "dev": true,
+ "requires": {
+ "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz"
+ }
+ },
+ "grunt-contrib-copy": {
+ "version": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz",
+ "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=",
+ "dev": true,
+ "requires": {
+ "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "file-sync-cmp": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz"
+ }
+ },
+ "grunt-contrib-cssmin": {
+ "version": "https://registry.npmjs.org/grunt-contrib-cssmin/-/grunt-contrib-cssmin-1.0.2.tgz",
+ "integrity": "sha1-FzTL09hMpzZHWLflj/GOUqpgu3Y=",
+ "dev": true,
+ "requires": {
+ "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "clean-css": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.27.tgz",
+ "maxmin": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz"
+ }
+ },
+ "grunt-contrib-sass": {
+ "version": "https://registry.npmjs.org/grunt-contrib-sass/-/grunt-contrib-sass-1.0.0.tgz",
+ "integrity": "sha1-gGg4JRy8DhqU1k1RXN00z2dNcBs=",
+ "dev": true,
+ "requires": {
+ "async": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
+ "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "cross-spawn": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-0.2.9.tgz",
+ "dargs": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz",
+ "which": "https://registry.npmjs.org/which/-/which-1.2.14.tgz"
+ },
+ "dependencies": {
+ "async": {
+ "version": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
+ "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=",
+ "dev": true
+ }
+ }
+ },
+ "grunt-contrib-uglify": {
+ "version": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-2.3.0.tgz",
+ "integrity": "sha1-s9AmDr3WzvoS/y+Onh4ln33kIW8=",
+ "dev": true,
+ "requires": {
+ "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "maxmin": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz",
+ "object.assign": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz",
+ "uglify-js": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
+ "uri-path": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz"
+ },
+ "dependencies": {
+ "uglify-js": {
+ "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
+ "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
+ "dev": true,
+ "requires": {
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+ "uglify-to-browserify": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+ "yargs": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz"
+ }
+ }
+ }
+ },
+ "grunt-contrib-watch": {
+ "version": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.0.0.tgz",
+ "integrity": "sha1-hKGnodar0m7VaEE0lscxM+mQAY8=",
+ "dev": true,
+ "requires": {
+ "async": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "gaze": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+ "tiny-lr": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-0.2.1.tgz"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+ "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
+ "dev": true
+ }
+ }
+ },
+ "grunt-haml2html": {
+ "version": "https://registry.npmjs.org/grunt-haml2html/-/grunt-haml2html-0.3.1.tgz",
+ "integrity": "sha1-b7W9R+JQ3Q9VzS76kj7kMQFEFCM=",
+ "dev": true,
+ "requires": {
+ "dargs": "https://registry.npmjs.org/dargs/-/dargs-0.1.0.tgz"
+ },
+ "dependencies": {
+ "dargs": {
+ "version": "https://registry.npmjs.org/dargs/-/dargs-0.1.0.tgz",
+ "integrity": "sha1-I2Stn0Qfl23NX+mWHiFxVmWl48M=",
+ "dev": true
+ }
+ }
+ },
+ "grunt-known-options": {
+ "version": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.0.tgz",
+ "integrity": "sha1-pCdO6zL6dl2lp6OxcSYXzjsUQUk=",
+ "dev": true
+ },
+ "grunt-legacy-log": {
+ "version": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-1.0.0.tgz",
+ "integrity": "sha1-+4bxgJhHvAfcR4Q/ns1srLYt8tU=",
+ "dev": true,
+ "requires": {
+ "colors": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+ "grunt-legacy-log-utils": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-1.0.0.tgz",
+ "hooker": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+ "underscore.string": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+ "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
+ "dev": true
+ }
+ }
+ },
+ "grunt-legacy-log-utils": {
+ "version": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-1.0.0.tgz",
+ "integrity": "sha1-p7ji0Ps1taUPSvmG/BEnSevJbz0=",
+ "dev": true,
+ "requires": {
+ "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz",
+ "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=",
+ "dev": true
+ }
+ }
+ },
+ "grunt-legacy-util": {
+ "version": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.0.0.tgz",
+ "integrity": "sha1-OGqnjcbtUJhsKxiVcmWxtIq7m4Y=",
+ "dev": true,
+ "requires": {
+ "async": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "exit": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "getobject": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz",
+ "hooker": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz",
+ "underscore.string": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz",
+ "which": "https://registry.npmjs.org/which/-/which-1.2.14.tgz"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz",
+ "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=",
+ "dev": true
+ }
+ }
+ },
+ "grunt-newer": {
+ "version": "https://registry.npmjs.org/grunt-newer/-/grunt-newer-1.3.0.tgz",
+ "integrity": "sha1-g8y3od2ny9irI7BZAk6+YUrS80I=",
+ "dev": true,
+ "requires": {
+ "async": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "rimraf": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz",
+ "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=",
+ "dev": true,
+ "requires": {
+ "glob": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz"
+ }
+ }
+ }
+ },
+ "grunt-ng-annotate": {
+ "version": "https://registry.npmjs.org/grunt-ng-annotate/-/grunt-ng-annotate-3.0.0.tgz",
+ "integrity": "sha1-dqKiGha6Y+Vve+G3XuXErZMCeTk=",
+ "dev": true,
+ "requires": {
+ "lodash.clonedeep": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "ng-annotate": "https://registry.npmjs.org/ng-annotate/-/ng-annotate-1.2.2.tgz"
+ }
+ },
+ "gzip-size": {
+ "version": "https://registry.npmjs.org/gzip-size/-/gzip-size-1.0.0.tgz",
+ "integrity": "sha1-Zs+LEBBHInuVus5uodoMF37Vwi8=",
+ "dev": true,
+ "requires": {
+ "browserify-zlib": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
+ "concat-stream": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz"
+ }
+ },
+ "har-validator": {
+ "version": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
+ "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=",
+ "dev": true,
+ "requires": {
+ "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "commander": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
+ "is-my-json-valid": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz",
+ "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz"
+ }
+ },
+ "has": {
+ "version": "https://registry.npmjs.org/has/-/has-1.0.1.tgz",
+ "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=",
+ "dev": true,
+ "requires": {
+ "function-bind": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz"
+ }
+ },
+ "has-ansi": {
+ "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz"
+ }
+ },
+ "has-binary": {
+ "version": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz",
+ "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=",
+ "dev": true,
+ "requires": {
+ "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ }
+ }
+ },
+ "has-cors": {
+ "version": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
+ "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=",
+ "dev": true
+ },
+ "hash-base": {
+ "version": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz",
+ "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=",
+ "dev": true,
+ "requires": {
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
+ }
+ },
+ "hash.js": {
+ "version": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
+ "integrity": "sha1-NA3tvmKQGHFRweodd3o0SJNd+EY=",
+ "dev": true,
+ "requires": {
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "minimalistic-assert": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz"
+ }
+ },
+ "hasha": {
+ "version": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz",
+ "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=",
+ "dev": true,
+ "requires": {
+ "is-stream": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz"
+ }
+ },
+ "hawk": {
+ "version": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
+ "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
+ "dev": true,
+ "requires": {
+ "boom": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
+ "cryptiles": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
+ "hoek": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+ "sntp": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
+ }
+ },
+ "he": {
+ "version": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
+ "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
+ "dev": true
+ },
+ "header-case": {
+ "version": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz",
+ "integrity": "sha1-lTWXMZfBRLCWE81l0xfvGZY70C0=",
+ "dev": true,
+ "requires": {
+ "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.1.tgz",
+ "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz"
+ }
+ },
+ "hmac-drbg": {
+ "version": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+ "dev": true,
+ "requires": {
+ "hash.js": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
+ "minimalistic-assert": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
+ "minimalistic-crypto-utils": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz"
+ }
+ },
+ "hoek": {
+ "version": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+ "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
+ "dev": true
+ },
+ "home-or-tmp": {
+ "version": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
+ "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
+ "dev": true,
+ "requires": {
+ "os-homedir": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "os-tmpdir": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz"
+ }
+ },
+ "hooker": {
+ "version": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
+ "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=",
+ "dev": true
+ },
+ "hosted-git-info": {
+ "version": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",
+ "integrity": "sha1-bWDjSzq7yDEwYsO3mO+NkBoHrzw=",
+ "dev": true
+ },
+ "html-minifier": {
+ "version": "https://registry.npmjs.org/html-minifier/-/html-minifier-2.1.7.tgz",
+ "integrity": "sha1-kFHW/LvPIU7TB+GtdPQyu5rWVcw=",
+ "dev": true,
+ "requires": {
+ "change-case": "https://registry.npmjs.org/change-case/-/change-case-3.0.1.tgz",
+ "clean-css": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.27.tgz",
+ "commander": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+ "he": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
+ "ncname": "https://registry.npmjs.org/ncname/-/ncname-1.0.0.tgz",
+ "relateurl": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
+ "uglify-js": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+ "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
+ "dev": true,
+ "requires": {
+ "graceful-readlink": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
+ }
+ }
+ }
+ },
+ "htmlescape": {
+ "version": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz",
+ "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=",
+ "dev": true
+ },
+ "http-errors": {
+ "version": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz",
+ "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=",
+ "dev": true,
+ "requires": {
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "statuses": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz"
+ }
+ },
+ "http-proxy": {
+ "version": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz",
+ "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=",
+ "dev": true,
+ "requires": {
+ "eventemitter3": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz",
+ "requires-port": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz"
+ }
+ },
+ "http-signature": {
+ "version": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
+ "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
+ "jsprim": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz",
+ "sshpk": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz"
+ }
+ },
+ "https-browserify": {
+ "version": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
+ "dev": true
+ },
+ "iconv-lite": {
+ "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz",
+ "integrity": "sha1-I9hlaxaq5nQqwpcy6o8DNqR4nPI=",
+ "dev": true
+ },
+ "ieee754": {
+ "version": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
+ "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=",
+ "dev": true
+ },
+ "indent-string": {
+ "version": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+ "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
+ "dev": true,
+ "requires": {
+ "repeating": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz"
+ }
+ },
+ "indexof": {
+ "version": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
+ "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
+ "dev": true
+ },
+ "inflight": {
+ "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "requires": {
+ "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
+ }
+ },
+ "inherits": {
+ "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ },
+ "inline-source-map": {
+ "version": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz",
+ "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=",
+ "dev": true,
+ "requires": {
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz"
+ }
+ },
+ "insert-module-globals": {
+ "version": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.0.1.tgz",
+ "integrity": "sha1-wDv04BywhtW15azorQr+eInWOMM=",
+ "dev": true,
+ "requires": {
+ "JSONStream": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz",
+ "combine-source-map": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.7.2.tgz",
+ "concat-stream": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz",
+ "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz",
+ "lexical-scope": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz",
+ "process": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+ "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
+ }
+ },
+ "invariant": {
+ "version": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",
+ "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=",
+ "dev": true,
+ "requires": {
+ "loose-envify": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz"
+ }
+ },
+ "is-arrayish": {
+ "version": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+ "dev": true
+ },
+ "is-binary-path": {
+ "version": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz"
+ }
+ },
+ "is-buffer": {
+ "version": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz",
+ "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=",
+ "dev": true
+ },
+ "is-builtin-module": {
+ "version": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
+ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
+ "dev": true,
+ "requires": {
+ "builtin-modules": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz"
+ }
+ },
+ "is-dotfile": {
+ "version": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+ "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+ "dev": true
+ },
+ "is-equal-shallow": {
+ "version": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+ "dev": true,
+ "requires": {
+ "is-primitive": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz"
+ }
+ },
+ "is-extendable": {
+ "version": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true
+ },
+ "is-extglob": {
+ "version": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true
+ },
+ "is-finite": {
+ "version": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
+ "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz"
+ }
+ },
+ "is-glob": {
+ "version": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz"
+ }
+ },
+ "is-lower-case": {
+ "version": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz",
+ "integrity": "sha1-fhR75HaNxGbbO/shzGCzHmrWk5M=",
+ "dev": true,
+ "requires": {
+ "lower-case": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz"
+ }
+ },
+ "is-my-json-valid": {
+ "version": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz",
+ "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=",
+ "dev": true,
+ "requires": {
+ "generate-function": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
+ "generate-object-property": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
+ "jsonpointer": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
+ "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
+ }
+ },
+ "is-number": {
+ "version": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+ "dev": true,
+ "requires": {
+ "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz"
+ }
+ },
+ "is-posix-bracket": {
+ "version": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+ "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+ "dev": true
+ },
+ "is-primitive": {
+ "version": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+ "dev": true
+ },
+ "is-property": {
+ "version": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
+ "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=",
+ "dev": true
+ },
+ "is-stream": {
+ "version": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
+ "dev": true
+ },
+ "is-typedarray": {
+ "version": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true
+ },
+ "is-upper-case": {
+ "version": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz",
+ "integrity": "sha1-jQsfp+eTOh5YSDYA7H2WYcuvdW8=",
+ "dev": true,
+ "requires": {
+ "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz"
+ }
+ },
+ "is-utf8": {
+ "version": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+ "dev": true
+ },
+ "isarray": {
+ "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isbinaryfile": {
+ "version": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz",
+ "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=",
+ "dev": true
+ },
+ "isexe": {
+ "version": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "isobject": {
+ "version": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "requires": {
+ "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+ }
+ },
+ "isstream": {
+ "version": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+ "dev": true
+ },
+ "jasmine": {
+ "version": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz",
+ "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=",
+ "dev": true,
+ "requires": {
+ "exit": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "glob": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "jasmine-core": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz"
+ }
+ },
+ "jasmine-core": {
+ "version": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz",
+ "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=",
+ "dev": true
+ },
+ "js-tokens": {
+ "version": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz",
+ "integrity": "sha1-A3fDgBfKvHMisNH7zSWkkWQfL74=",
+ "dev": true,
+ "requires": {
+ "argparse": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
+ "esprima": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz"
+ }
+ },
+ "jsbn": {
+ "version": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "dev": true,
+ "optional": true
+ },
+ "jsesc": {
+ "version": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
+ "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
+ "dev": true
+ },
+ "json-schema": {
+ "version": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+ "dev": true
+ },
+ "json-stable-stringify": {
+ "version": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz",
+ "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=",
+ "dev": true,
+ "requires": {
+ "jsonify": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz"
+ }
+ },
+ "json-stringify-safe": {
+ "version": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true
+ },
+ "json3": {
+ "version": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz",
+ "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=",
+ "dev": true
+ },
+ "json5": {
+ "version": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
+ "dev": true
+ },
+ "jsonfile": {
+ "version": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
+ "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
+ }
+ },
+ "jsonify": {
+ "version": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+ "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
+ "dev": true
+ },
+ "jsonparse": {
+ "version": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
+ "dev": true
+ },
+ "jsonpointer": {
+ "version": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
+ "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
+ "dev": true
+ },
+ "jsprim": {
+ "version": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz",
+ "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "extsprintf": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz",
+ "json-schema": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "verror": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true
+ }
+ }
+ },
+ "karma": {
+ "version": "https://registry.npmjs.org/karma/-/karma-1.7.1.tgz",
+ "integrity": "sha1-hcwI6eCiLXzpzKN8ShvoJPaisa4=",
+ "dev": true,
+ "requires": {
+ "bluebird": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz",
+ "body-parser": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
+ "chokidar": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
+ "colors": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+ "combine-lists": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz",
+ "connect": "https://registry.npmjs.org/connect/-/connect-3.6.5.tgz",
+ "core-js": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
+ "di": "https://registry.npmjs.org/di/-/di-0.0.1.tgz",
+ "dom-serialize": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
+ "expand-braces": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz",
+ "glob": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "http-proxy": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz",
+ "isbinaryfile": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+ "log4js": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz",
+ "mime": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
+ "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "optimist": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+ "qjobs": "https://registry.npmjs.org/qjobs/-/qjobs-1.1.5.tgz",
+ "range-parser": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
+ "rimraf": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+ "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+ "socket.io": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.3.tgz",
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+ "tmp": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz",
+ "useragent": "https://registry.npmjs.org/useragent/-/useragent-2.2.1.tgz"
+ },
+ "dependencies": {
+ "body-parser": {
+ "version": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
+ "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
+ "dev": true,
+ "requires": {
+ "bytes": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+ "content-type": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "depd": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
+ "http-errors": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
+ "iconv-lite": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
+ "on-finished": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "qs": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
+ "raw-body": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
+ "type-is": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz"
+ }
+ },
+ "bytes": {
+ "version": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
+ "dev": true
+ },
+ "content-type": {
+ "version": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=",
+ "dev": true
+ },
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
+ "dev": true,
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
+ }
+ },
+ "depd": {
+ "version": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
+ "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=",
+ "dev": true
+ },
+ "http-errors": {
+ "version": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
+ "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
+ "dev": true,
+ "requires": {
+ "depd": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "setprototypeof": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
+ "statuses": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz"
+ }
+ },
+ "iconv-lite": {
+ "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
+ "integrity": "sha1-90aPYBNfXl2tM5nAqBvpoWA6CCs=",
+ "dev": true
+ },
+ "lodash": {
+ "version": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+ "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
+ "dev": true
+ },
+ "qs": {
+ "version": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
+ "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg=",
+ "dev": true
+ },
+ "raw-body": {
+ "version": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
+ "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
+ "dev": true,
+ "requires": {
+ "bytes": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+ "http-errors": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
+ "iconv-lite": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
+ "unpipe": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
+ }
+ },
+ "rimraf": {
+ "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+ "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=",
+ "dev": true,
+ "requires": {
+ "glob": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz"
+ }
+ }
+ }
+ },
+ "karma-cli": {
+ "version": "https://registry.npmjs.org/karma-cli/-/karma-cli-1.0.1.tgz",
+ "integrity": "sha1-rmw8WKMTodALRRZMRVubhs4X+WA=",
+ "dev": true,
+ "requires": {
+ "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz"
+ }
+ },
+ "karma-jasmine": {
+ "version": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.0.tgz",
+ "integrity": "sha1-IuTAa/mhguUpTR9wXjczgRuBCs8=",
+ "dev": true
+ },
+ "karma-phantomjs-launcher": {
+ "version": "https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.4.tgz",
+ "integrity": "sha1-0jyjSAG9qYY60xjju0vUBisTrNI=",
+ "dev": true,
+ "requires": {
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "phantomjs-prebuilt": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz"
+ }
+ },
+ "kew": {
+ "version": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz",
+ "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz"
+ }
+ },
+ "klaw": {
+ "version": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
+ "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
+ }
+ },
+ "labeled-stream-splicer": {
+ "version": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz",
+ "integrity": "sha1-pS4dE4AkwAuGscDJH2d5GLiuClk=",
+ "dev": true,
+ "requires": {
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "stream-splicer": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ }
+ }
+ },
+ "lazy-cache": {
+ "version": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
+ "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
+ "dev": true
+ },
+ "lexical-scope": {
+ "version": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz",
+ "integrity": "sha1-/Ope3HBKSzqHls3KQZw6CvryLfQ=",
+ "dev": true,
+ "requires": {
+ "astw": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz"
+ }
+ },
+ "livereload-js": {
+ "version": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz",
+ "integrity": "sha1-bIclfmSKtHW8JOoldFftzB+NC8I=",
+ "dev": true
+ },
+ "load-json-file": {
+ "version": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "parse-json": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "strip-bom": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz"
+ }
+ },
+ "lodash": {
+ "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
+ "dev": true
+ },
+ "lodash.clonedeep": {
+ "version": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
+ "dev": true
+ },
+ "lodash.memoize": {
+ "version": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
+ "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=",
+ "dev": true
+ },
+ "log4js": {
+ "version": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz",
+ "integrity": "sha1-LElBFmldb7JUgJQ9P8hy5mKlIv0=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+ "semver": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+ "dev": true,
+ "requires": {
+ "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+ }
+ },
+ "semver": {
+ "version": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
+ "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=",
+ "dev": true
+ },
+ "string_decoder": {
+ "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
+ }
+ }
+ },
+ "longest": {
+ "version": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
+ "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
+ "dev": true
+ },
+ "loose-envify": {
+ "version": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
+ "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
+ "dev": true,
+ "requires": {
+ "js-tokens": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz"
+ }
+ },
+ "loud-rejection": {
+ "version": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
+ "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
+ "dev": true,
+ "requires": {
+ "currently-unhandled": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+ "signal-exit": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz"
+ }
+ },
+ "lower-case": {
+ "version": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
+ "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=",
+ "dev": true
+ },
+ "lower-case-first": {
+ "version": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz",
+ "integrity": "sha1-5dp8JvKacHO+AtUrrJmA5ZIq36E=",
+ "dev": true,
+ "requires": {
+ "lower-case": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz"
+ }
+ },
+ "lru-cache": {
+ "version": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz",
+ "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=",
+ "dev": true
+ },
+ "map-obj": {
+ "version": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+ "dev": true
+ },
+ "maxmin": {
+ "version": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz",
+ "integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=",
+ "dev": true,
+ "requires": {
+ "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "figures": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+ "gzip-size": "https://registry.npmjs.org/gzip-size/-/gzip-size-1.0.0.tgz",
+ "pretty-bytes": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz"
+ }
+ },
+ "md5.js": {
+ "version": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz",
+ "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=",
+ "dev": true,
+ "requires": {
+ "hash-base": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
+ },
+ "dependencies": {
+ "hash-base": {
+ "version": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
+ "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
+ "dev": true,
+ "requires": {
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz"
+ }
+ }
+ }
+ },
+ "media-typer": {
+ "version": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+ "dev": true
+ },
+ "meow": {
+ "version": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+ "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
+ "dev": true,
+ "requires": {
+ "camelcase-keys": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+ "decamelize": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "loud-rejection": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
+ "map-obj": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "minimist": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "normalize-package-data": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+ "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "read-pkg-up": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+ "redent": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
+ "trim-newlines": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
+ }
+ }
+ },
+ "micromatch": {
+ "version": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "dev": true,
+ "requires": {
+ "arr-diff": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "array-unique": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "braces": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "expand-brackets": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "extglob": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "filename-regex": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+ "is-extglob": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "is-glob": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "normalize-path": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "object.omit": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+ "parse-glob": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+ "regex-cache": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz"
+ }
+ },
+ "miller-rabin": {
+ "version": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+ "integrity": "sha1-8IA1HIZbDcViqEYpZtqlNUPHik0=",
+ "dev": true,
+ "requires": {
+ "bn.js": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "brorand": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz"
+ }
+ },
+ "mime": {
+ "version": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
+ "integrity": "sha1-Eh+evEnjdm8xGnbh+hyAA8SwOqY=",
+ "dev": true
+ },
+ "mime-db": {
+ "version": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz",
+ "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=",
+ "dev": true
+ },
+ "mime-types": {
+ "version": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz",
+ "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=",
+ "dev": true,
+ "requires": {
+ "mime-db": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz"
+ }
+ },
+ "minimalistic-assert": {
+ "version": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
+ "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=",
+ "dev": true
+ },
+ "minimalistic-crypto-utils": {
+ "version": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz"
+ }
+ },
+ "minimist": {
+ "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "dev": true,
+ "requires": {
+ "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
+ }
+ },
+ "module-deps": {
+ "version": "https://registry.npmjs.org/module-deps/-/module-deps-4.1.1.tgz",
+ "integrity": "sha1-IyFYM/HaE/1gbMuAh7RIUty4If0=",
+ "dev": true,
+ "requires": {
+ "JSONStream": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz",
+ "browser-resolve": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz",
+ "cached-path-relative": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz",
+ "concat-stream": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz",
+ "defined": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+ "detective": "https://registry.npmjs.org/detective/-/detective-4.5.0.tgz",
+ "duplexer2": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "parents": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
+ "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
+ "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+ "stream-combiner2": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz",
+ "subarg": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
+ "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+ "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
+ }
+ },
+ "ms": {
+ "version": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "nan": {
+ "version": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz",
+ "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=",
+ "dev": true,
+ "optional": true
+ },
+ "ncname": {
+ "version": "https://registry.npmjs.org/ncname/-/ncname-1.0.0.tgz",
+ "integrity": "sha1-W1etGLHKCShk72Kwse2BlPODtxw=",
+ "dev": true,
+ "requires": {
+ "xml-char-classes": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz"
+ }
+ },
+ "negotiator": {
+ "version": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
+ "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=",
+ "dev": true
+ },
+ "ng-annotate": {
+ "version": "https://registry.npmjs.org/ng-annotate/-/ng-annotate-1.2.2.tgz",
+ "integrity": "sha1-3D/FG6Cy+LOF2+BH9NoG9YCh/WE=",
+ "dev": true,
+ "requires": {
+ "acorn": "https://registry.npmjs.org/acorn/-/acorn-2.6.4.tgz",
+ "alter": "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz",
+ "convert-source-map": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
+ "optimist": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+ "ordered-ast-traverse": "https://registry.npmjs.org/ordered-ast-traverse/-/ordered-ast-traverse-1.1.1.tgz",
+ "simple-fmt": "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz",
+ "simple-is": "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz",
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+ "stable": "https://registry.npmjs.org/stable/-/stable-0.1.6.tgz",
+ "stringmap": "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz",
+ "stringset": "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz",
+ "tryor": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "https://registry.npmjs.org/acorn/-/acorn-2.6.4.tgz",
+ "integrity": "sha1-6x9FtKQ/ox0DcBpexG87Umc+kO4=",
+ "dev": true
+ },
+ "convert-source-map": {
+ "version": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
+ "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=",
+ "dev": true
+ }
+ }
+ },
+ "no-case": {
+ "version": "https://registry.npmjs.org/no-case/-/no-case-2.3.1.tgz",
+ "integrity": "sha1-euuhxzpSGEJlVUt9wDuvcg34AIE=",
+ "dev": true,
+ "requires": {
+ "lower-case": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz"
+ }
+ },
+ "nopt": {
+ "version": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+ "dev": true,
+ "requires": {
+ "abbrev": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz"
+ }
+ },
+ "normalize-package-data": {
+ "version": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+ "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",
+ "is-builtin-module": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
+ "semver": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+ "validate-npm-package-license": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz"
+ }
+ },
+ "normalize-path": {
+ "version": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "requires": {
+ "remove-trailing-separator": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz"
+ }
+ },
+ "number-is-nan": {
+ "version": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+ "dev": true
+ },
+ "oauth-sign": {
+ "version": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
+ "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
+ "dev": true
+ },
+ "object-assign": {
+ "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true
+ },
+ "object-component": {
+ "version": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
+ "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=",
+ "dev": true
+ },
+ "object-keys": {
+ "version": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz",
+ "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=",
+ "dev": true
+ },
+ "object.assign": {
+ "version": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz",
+ "integrity": "sha1-scnMBE7xuf5jYG/BQau7MuFHMMw=",
+ "dev": true,
+ "requires": {
+ "define-properties": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
+ "function-bind": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz",
+ "object-keys": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz"
+ }
+ },
+ "object.omit": {
+ "version": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+ "dev": true,
+ "requires": {
+ "for-own": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+ "is-extendable": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz"
+ }
+ },
+ "on-finished": {
+ "version": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "dev": true,
+ "requires": {
+ "ee-first": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz"
+ }
+ },
+ "once": {
+ "version": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
+ }
+ },
+ "optimist": {
+ "version": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+ "dev": true,
+ "requires": {
+ "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz"
+ }
+ },
+ "options": {
+ "version": "https://registry.npmjs.org/options/-/options-0.0.6.tgz",
+ "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=",
+ "dev": true
+ },
+ "ordered-ast-traverse": {
+ "version": "https://registry.npmjs.org/ordered-ast-traverse/-/ordered-ast-traverse-1.1.1.tgz",
+ "integrity": "sha1-aEOhcLwO7otSDMjdwd3TqjD6BXw=",
+ "dev": true,
+ "requires": {
+ "ordered-esprima-props": "https://registry.npmjs.org/ordered-esprima-props/-/ordered-esprima-props-1.1.0.tgz"
+ }
+ },
+ "ordered-esprima-props": {
+ "version": "https://registry.npmjs.org/ordered-esprima-props/-/ordered-esprima-props-1.1.0.tgz",
+ "integrity": "sha1-qYJwht9fAQqmDpvQK24DNc6i/8s=",
+ "dev": true
+ },
+ "os-browserify": {
+ "version": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.1.2.tgz",
+ "integrity": "sha1-ScoCk+CxlZCl9d4Qx/JlphfY/lQ=",
+ "dev": true
+ },
+ "os-homedir": {
+ "version": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "dev": true
+ },
+ "os-tmpdir": {
+ "version": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+ "dev": true
+ },
+ "outpipe": {
+ "version": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz",
+ "integrity": "sha1-UM+GFjZeh+Ax4ppeyTOaPaRyX6I=",
+ "dev": true,
+ "requires": {
+ "shell-quote": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz"
+ }
+ },
+ "output-file-sync": {
+ "version": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz",
+ "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
+ }
+ },
+ "pako": {
+ "version": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
+ "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=",
+ "dev": true
+ },
+ "param-case": {
+ "version": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
+ "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=",
+ "dev": true,
+ "requires": {
+ "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.1.tgz"
+ }
+ },
+ "parents": {
+ "version": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
+ "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=",
+ "dev": true,
+ "requires": {
+ "path-platform": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz"
+ }
+ },
+ "parse-asn1": {
+ "version": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz",
+ "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=",
+ "dev": true,
+ "requires": {
+ "asn1.js": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz",
+ "browserify-aes": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.8.tgz",
+ "create-hash": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
+ "evp_bytestokey": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "pbkdf2": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz"
+ }
+ },
+ "parse-glob": {
+ "version": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+ "dev": true,
+ "requires": {
+ "glob-base": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+ "is-dotfile": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+ "is-extglob": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "is-glob": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz"
+ }
+ },
+ "parse-json": {
+ "version": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "dev": true,
+ "requires": {
+ "error-ex": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz"
+ }
+ },
+ "parsejson": {
+ "version": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz",
+ "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=",
+ "dev": true,
+ "requires": {
+ "better-assert": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz"
+ }
+ },
+ "parseqs": {
+ "version": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
+ "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
+ "dev": true,
+ "requires": {
+ "better-assert": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz"
+ }
+ },
+ "parseuri": {
+ "version": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
+ "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
+ "dev": true,
+ "requires": {
+ "better-assert": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz"
+ }
+ },
+ "parseurl": {
+ "version": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz",
+ "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=",
+ "dev": true
+ },
+ "pascal-case": {
+ "version": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz",
+ "integrity": "sha1-LVeNNFX2YNpl7KGO+VtODekSdh4=",
+ "dev": true,
+ "requires": {
+ "camel-case": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
+ "upper-case-first": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz"
+ }
+ },
+ "path-browserify": {
+ "version": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
+ "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=",
+ "dev": true
+ },
+ "path-case": {
+ "version": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz",
+ "integrity": "sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU=",
+ "dev": true,
+ "requires": {
+ "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.1.tgz"
+ }
+ },
+ "path-exists": {
+ "version": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+ "dev": true,
+ "requires": {
+ "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz"
+ }
+ },
+ "path-is-absolute": {
+ "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "path-platform": {
+ "version": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz",
+ "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=",
+ "dev": true
+ },
+ "path-type": {
+ "version": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz"
+ }
+ },
+ "pbkdf2": {
+ "version": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz",
+ "integrity": "sha1-o14TxkeZsGzhUyD0WcIw5o5zut4=",
+ "dev": true,
+ "requires": {
+ "create-hash": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
+ "create-hmac": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz",
+ "ripemd160": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
+ "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+ "sha.js": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz"
+ }
+ },
+ "pend": {
+ "version": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+ "dev": true
+ },
+ "phantomjs-prebuilt": {
+ "version": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz",
+ "integrity": "sha1-1T0xH8+30dCN2yQBRVjxGIxRbaA=",
+ "dev": true,
+ "requires": {
+ "es6-promise": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz",
+ "extract-zip": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz",
+ "fs-extra": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz",
+ "hasha": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz",
+ "kew": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz",
+ "progress": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz",
+ "request": "https://registry.npmjs.org/request/-/request-2.79.0.tgz",
+ "request-progress": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz",
+ "which": "https://registry.npmjs.org/which/-/which-1.2.14.tgz"
+ }
+ },
+ "pify": {
+ "version": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ },
+ "pinkie": {
+ "version": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+ "dev": true
+ },
+ "pinkie-promise": {
+ "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "dev": true,
+ "requires": {
+ "pinkie": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz"
+ }
+ },
+ "preserve": {
+ "version": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+ "dev": true
+ },
+ "pretty-bytes": {
+ "version": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz",
+ "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=",
+ "dev": true,
+ "requires": {
+ "get-stdin": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+ "meow": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz"
+ }
+ },
+ "private": {
+ "version": "https://registry.npmjs.org/private/-/private-0.1.7.tgz",
+ "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE=",
+ "dev": true
+ },
+ "process": {
+ "version": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
+ "dev": true
+ },
+ "process-nextick-args": {
+ "version": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+ "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
+ "dev": true
+ },
+ "progress": {
+ "version": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz",
+ "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=",
+ "dev": true
+ },
+ "public-encrypt": {
+ "version": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz",
+ "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=",
+ "dev": true,
+ "requires": {
+ "bn.js": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "browserify-rsa": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+ "create-hash": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
+ "parse-asn1": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz",
+ "randombytes": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz"
+ }
+ },
+ "punycode": {
+ "version": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true
+ },
+ "qjobs": {
+ "version": "https://registry.npmjs.org/qjobs/-/qjobs-1.1.5.tgz",
+ "integrity": "sha1-ZZ3p8s+NzCehSBJ28gU3cnI4LnM=",
+ "dev": true
+ },
+ "qs": {
+ "version": "https://registry.npmjs.org/qs/-/qs-5.1.0.tgz",
+ "integrity": "sha1-TZMuXH6kEcynajEtOaYGIA/VDNk=",
+ "dev": true
+ },
+ "querystring": {
+ "version": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
+ "dev": true
+ },
+ "querystring-es3": {
+ "version": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
+ "dev": true
+ },
+ "randomatic": {
+ "version": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
+ "integrity": "sha1-x6vpzIuHwLqodrGf3oP9RkeX44w=",
+ "dev": true,
+ "requires": {
+ "is-number": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz"
+ }
+ }
+ }
+ },
+ "kind-of": {
+ "version": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz"
+ }
+ }
+ }
+ },
+ "randombytes": {
+ "version": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz",
+ "integrity": "sha1-3ACaJGuNCaF3tLegrne8Vw9LG3k=",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz"
+ }
+ },
+ "range-parser": {
+ "version": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
+ "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=",
+ "dev": true
+ },
+ "raw-body": {
+ "version": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz",
+ "integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=",
+ "dev": true,
+ "requires": {
+ "bytes": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz",
+ "iconv-lite": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz",
+ "unpipe": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
+ },
+ "dependencies": {
+ "bytes": {
+ "version": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz",
+ "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=",
+ "dev": true
+ },
+ "iconv-lite": {
+ "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz",
+ "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=",
+ "dev": true
+ }
+ }
+ },
+ "read-only-stream": {
+ "version": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz",
+ "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz"
+ }
+ },
+ "read-pkg": {
+ "version": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+ "dev": true,
+ "requires": {
+ "load-json-file": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+ "normalize-package-data": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+ "path-type": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz"
+ }
+ },
+ "read-pkg-up": {
+ "version": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+ "dev": true,
+ "requires": {
+ "find-up": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+ "read-pkg": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz"
+ }
+ },
+ "readable-stream": {
+ "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
+ "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=",
+ "dev": true,
+ "requires": {
+ "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+ "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+ "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+ "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
+ }
+ },
+ "readdirp": {
+ "version": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
+ "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
+ "set-immediate-shim": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz"
+ }
+ },
+ "redent": {
+ "version": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
+ "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
+ "dev": true,
+ "requires": {
+ "indent-string": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+ "strip-indent": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz"
+ }
+ },
+ "regenerate": {
+ "version": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz",
+ "integrity": "sha1-DDNtOYBVPXVcObWGrjsgqknIK38=",
+ "dev": true
+ },
+ "regenerator-runtime": {
+ "version": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
+ "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
+ "dev": true
+ },
+ "regenerator-transform": {
+ "version": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
+ "integrity": "sha1-HkmWg3Ix2ot/PPQRTXG1aRoGgN0=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
+ "babel-types": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz",
+ "private": "https://registry.npmjs.org/private/-/private-0.1.7.tgz"
+ }
+ },
+ "regex-cache": {
+ "version": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+ "integrity": "sha1-db3FiioUls7EihKDW8VMjVYjNt0=",
+ "dev": true,
+ "requires": {
+ "is-equal-shallow": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz"
+ }
+ },
+ "regexpu-core": {
+ "version": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz",
+ "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=",
+ "dev": true,
+ "requires": {
+ "regenerate": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz",
+ "regjsgen": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
+ "regjsparser": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz"
+ }
+ },
+ "regjsgen": {
+ "version": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
+ "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
+ "dev": true
+ },
+ "regjsparser": {
+ "version": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
+ "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
+ "dev": true,
+ "requires": {
+ "jsesc": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz"
+ },
+ "dependencies": {
+ "jsesc": {
+ "version": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+ "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
+ "dev": true
+ }
+ }
+ },
+ "relateurl": {
+ "version": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
+ "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=",
+ "dev": true
+ },
+ "remove-trailing-separator": {
+ "version": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+ "dev": true
+ },
+ "repeat-element": {
+ "version": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
+ "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
+ "dev": true
+ },
+ "repeat-string": {
+ "version": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+ "dev": true
+ },
+ "repeating": {
+ "version": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+ "dev": true,
+ "requires": {
+ "is-finite": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz"
+ }
+ },
+ "request": {
+ "version": "https://registry.npmjs.org/request/-/request-2.79.0.tgz",
+ "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=",
+ "dev": true,
+ "requires": {
+ "aws-sign2": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
+ "aws4": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
+ "caseless": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
+ "combined-stream": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
+ "extend": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
+ "forever-agent": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "form-data": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
+ "har-validator": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
+ "hawk": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
+ "http-signature": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
+ "is-typedarray": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "isstream": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "json-stringify-safe": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz",
+ "oauth-sign": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
+ "qs": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz",
+ "stringstream": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
+ "tough-cookie": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz",
+ "tunnel-agent": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz",
+ "uuid": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz"
+ },
+ "dependencies": {
+ "qs": {
+ "version": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz",
+ "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=",
+ "dev": true
+ }
+ }
+ },
+ "request-progress": {
+ "version": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz",
+ "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=",
+ "dev": true,
+ "requires": {
+ "throttleit": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz"
+ }
+ },
+ "requires-port": {
+ "version": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+ "dev": true
+ },
+ "resolve": {
+ "version": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
+ "dev": true
+ },
+ "right-align": {
+ "version": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
+ "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
+ "dev": true,
+ "requires": {
+ "align-text": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz"
+ }
+ },
+ "rimraf": {
+ "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
+ "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=",
+ "dev": true
+ },
+ "ripemd160": {
+ "version": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
+ "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=",
+ "dev": true,
+ "requires": {
+ "hash-base": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
+ }
+ },
+ "safe-buffer": {
+ "version": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+ "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=",
+ "dev": true
+ },
+ "semver": {
+ "version": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+ "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
+ "dev": true
+ },
+ "sentence-case": {
+ "version": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz",
+ "integrity": "sha1-H24t2jnBaL+S0T+G1KkYkz9mftQ=",
+ "dev": true,
+ "requires": {
+ "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.1.tgz",
+ "upper-case-first": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz"
+ }
+ },
+ "set-immediate-shim": {
+ "version": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
+ "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
+ "dev": true
+ },
+ "setprototypeof": {
+ "version": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
+ "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=",
+ "dev": true
+ },
+ "sha.js": {
+ "version": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz",
+ "integrity": "sha1-mPZIgEdLdPSji42p08Dy0QRjPn0=",
+ "dev": true,
+ "requires": {
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz"
+ }
+ },
+ "shasum": {
+ "version": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz",
+ "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=",
+ "dev": true,
+ "requires": {
+ "json-stable-stringify": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz",
+ "sha.js": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz"
+ }
+ },
+ "shell-quote": {
+ "version": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
+ "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=",
+ "dev": true,
+ "requires": {
+ "array-filter": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
+ "array-map": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
+ "array-reduce": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
+ "jsonify": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz"
+ }
+ },
+ "signal-exit": {
+ "version": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+ "dev": true
+ },
+ "simple-fmt": {
+ "version": "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz",
+ "integrity": "sha1-GRv1ZqWeZTBILLJatTtKjchcOms=",
+ "dev": true
+ },
+ "simple-is": {
+ "version": "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz",
+ "integrity": "sha1-Krt1qt453rXMgVzhDmGRFkhQuvA=",
+ "dev": true
+ },
+ "slash": {
+ "version": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
+ "dev": true
+ },
+ "sn-stylekit": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/sn-stylekit/-/sn-stylekit-1.0.12.tgz",
+ "integrity": "sha512-CkCGj6pS2FB9tF5uVbqMlmKpQ1wJFCcXAri2B4nCq8aAv2D5frUhhPFJ1oCnFgBssB9LxnbW2+C2CQojVCL9ig==",
+ "dev": true
+ },
+ "snake-case": {
+ "version": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz",
+ "integrity": "sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8=",
+ "dev": true,
+ "requires": {
+ "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.1.tgz"
+ }
+ },
+ "sntp": {
+ "version": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
+ "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
+ "dev": true,
+ "requires": {
+ "hoek": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
+ }
+ },
+ "socket.io": {
+ "version": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.3.tgz",
+ "integrity": "sha1-uK+cq6AJSeVo42nxMn6pvp6iRhs=",
+ "dev": true,
+ "requires": {
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
+ "engine.io": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.3.tgz",
+ "has-binary": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz",
+ "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz",
+ "socket.io-adapter": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz",
+ "socket.io-client": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.3.tgz",
+ "socket.io-parser": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
+ "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
+ "dev": true,
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz"
+ }
+ },
+ "ms": {
+ "version": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+ "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
+ "dev": true
+ },
+ "object-assign": {
+ "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz",
+ "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=",
+ "dev": true
+ }
+ }
+ },
+ "socket.io-adapter": {
+ "version": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz",
+ "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=",
+ "dev": true,
+ "requires": {
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
+ "socket.io-parser": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
+ "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
+ "dev": true,
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz"
+ }
+ },
+ "ms": {
+ "version": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+ "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
+ "dev": true
+ }
+ }
+ },
+ "socket.io-client": {
+ "version": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.3.tgz",
+ "integrity": "sha1-sw6GqhDV7zVGYBwJzeR2Xjgdo3c=",
+ "dev": true,
+ "requires": {
+ "backo2": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
+ "component-bind": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
+ "component-emitter": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
+ "engine.io-client": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.3.tgz",
+ "has-binary": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz",
+ "indexof": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
+ "object-component": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
+ "parseuri": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
+ "socket.io-parser": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz",
+ "to-array": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz"
+ },
+ "dependencies": {
+ "component-emitter": {
+ "version": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+ "dev": true
+ },
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
+ "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
+ "dev": true,
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz"
+ }
+ },
+ "ms": {
+ "version": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+ "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
+ "dev": true
+ }
+ }
+ },
+ "socket.io-parser": {
+ "version": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz",
+ "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=",
+ "dev": true,
+ "requires": {
+ "component-emitter": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "json3": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "dev": true,
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
+ }
+ },
+ "isarray": {
+ "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ },
+ "ms": {
+ "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=",
+ "dev": true
+ }
+ }
+ },
+ "source-map": {
+ "version": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+ "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=",
+ "dev": true
+ },
+ "source-map-support": {
+ "version": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz",
+ "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=",
+ "dev": true,
+ "requires": {
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz"
+ }
+ },
+ "spdx-correct": {
+ "version": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz",
+ "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=",
+ "dev": true,
+ "requires": {
+ "spdx-license-ids": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz"
+ }
+ },
+ "spdx-expression-parse": {
+ "version": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz",
+ "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=",
+ "dev": true
+ },
+ "spdx-license-ids": {
+ "version": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz",
+ "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=",
+ "dev": true
+ },
+ "sprintf-js": {
+ "version": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "dev": true
+ },
+ "sshpk": {
+ "version": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
+ "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
+ "dev": true,
+ "requires": {
+ "asn1": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
+ "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "bcrypt-pbkdf": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
+ "dashdash": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "ecc-jsbn": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
+ "getpass": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "jsbn": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "tweetnacl": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true
+ }
+ }
+ },
+ "stable": {
+ "version": "https://registry.npmjs.org/stable/-/stable-0.1.6.tgz",
+ "integrity": "sha1-kQ9dKu17Ugxud3SZwfMuE5/eyxA=",
+ "dev": true
+ },
+ "statuses": {
+ "version": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
+ "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=",
+ "dev": true
+ },
+ "stream-browserify": {
+ "version": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
+ "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=",
+ "dev": true,
+ "requires": {
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz"
+ }
+ },
+ "stream-combiner2": {
+ "version": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz",
+ "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=",
+ "dev": true,
+ "requires": {
+ "duplexer2": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+ "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz"
+ }
+ },
+ "stream-http": {
+ "version": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz",
+ "integrity": "sha1-QKBQ7I3DtTsz2ZCUFcAsC/Gr+60=",
+ "dev": true,
+ "requires": {
+ "builtin-status-codes": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
+ "to-arraybuffer": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+ "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
+ }
+ },
+ "stream-splicer": {
+ "version": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz",
+ "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=",
+ "dev": true,
+ "requires": {
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz"
+ }
+ },
+ "string_decoder": {
+ "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+ "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz"
+ }
+ },
+ "stringmap": {
+ "version": "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz",
+ "integrity": "sha1-VWwTeyWPlCuHdvWy71gqoGnX0bE=",
+ "dev": true
+ },
+ "stringset": {
+ "version": "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz",
+ "integrity": "sha1-7yWcTjSTRDd/zRyRPdLoSMnAQrU=",
+ "dev": true
+ },
+ "stringstream": {
+ "version": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
+ "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz"
+ }
+ },
+ "strip-bom": {
+ "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+ "dev": true,
+ "requires": {
+ "is-utf8": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz"
+ }
+ },
+ "strip-indent": {
+ "version": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
+ "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
+ "dev": true,
+ "requires": {
+ "get-stdin": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
+ }
+ },
+ "subarg": {
+ "version": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
+ "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=",
+ "dev": true,
+ "requires": {
+ "minimist": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
+ }
+ }
+ },
+ "supports-color": {
+ "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ },
+ "swap-case": {
+ "version": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz",
+ "integrity": "sha1-w5IDpFhzhfrTyFCgvRvK+ggZdOM=",
+ "dev": true,
+ "requires": {
+ "lower-case": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
+ "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz"
+ }
+ },
+ "syntax-error": {
+ "version": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.3.0.tgz",
+ "integrity": "sha1-HtkmbE1AvnXcVb+bsct3Biu5bKE=",
+ "dev": true,
+ "requires": {
+ "acorn": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz"
+ }
+ },
+ "throttleit": {
+ "version": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz",
+ "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=",
+ "dev": true
+ },
+ "through": {
+ "version": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "through2": {
+ "version": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
+ "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
+ }
+ },
+ "timers-browserify": {
+ "version": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz",
+ "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=",
+ "dev": true,
+ "requires": {
+ "process": "https://registry.npmjs.org/process/-/process-0.11.10.tgz"
+ }
+ },
+ "tiny-lr": {
+ "version": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-0.2.1.tgz",
+ "integrity": "sha1-s/26gC5dVqM8L28QeUsy5Hescp0=",
+ "dev": true,
+ "requires": {
+ "body-parser": "https://registry.npmjs.org/body-parser/-/body-parser-1.14.2.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "faye-websocket": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
+ "livereload-js": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz",
+ "parseurl": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz",
+ "qs": "https://registry.npmjs.org/qs/-/qs-5.1.0.tgz"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "dev": true,
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
+ }
+ },
+ "ms": {
+ "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=",
+ "dev": true
+ }
+ }
+ },
+ "title-case": {
+ "version": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz",
+ "integrity": "sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o=",
+ "dev": true,
+ "requires": {
+ "no-case": "https://registry.npmjs.org/no-case/-/no-case-2.3.1.tgz",
+ "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz"
+ }
+ },
+ "tmp": {
+ "version": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz",
+ "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz"
+ }
+ },
+ "to-array": {
+ "version": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
+ "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=",
+ "dev": true
+ },
+ "to-arraybuffer": {
+ "version": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
+ "dev": true
+ },
+ "to-fast-properties": {
+ "version": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
+ "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
+ "dev": true
+ },
+ "tough-cookie": {
+ "version": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz",
+ "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=",
+ "dev": true,
+ "requires": {
+ "punycode": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz"
+ }
+ },
+ "trim-newlines": {
+ "version": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
+ "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
+ "dev": true
+ },
+ "trim-right": {
+ "version": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
+ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
+ "dev": true
+ },
+ "tryor": {
+ "version": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz",
+ "integrity": "sha1-gUXkynyv9ArN48z5Rui4u3W0Fys=",
+ "dev": true
+ },
+ "tty-browserify": {
+ "version": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
+ "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
+ "dev": true
+ },
+ "tunnel-agent": {
+ "version": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz",
+ "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=",
+ "dev": true
+ },
+ "tweetnacl": {
+ "version": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "dev": true,
+ "optional": true
+ },
+ "type-is": {
+ "version": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz",
+ "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=",
+ "dev": true,
+ "requires": {
+ "media-typer": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz"
+ }
+ },
+ "typedarray": {
+ "version": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+ "dev": true
+ },
+ "uglify-js": {
+ "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz",
+ "integrity": "sha1-ZeovswWck5RpLxX+2HwrNsFrmt8=",
+ "dev": true,
+ "requires": {
+ "async": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
+ "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+ "uglify-to-browserify": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+ "yargs": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz"
+ },
+ "dependencies": {
+ "async": {
+ "version": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
+ "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
+ "dev": true
+ }
+ }
+ },
+ "uglify-to-browserify": {
+ "version": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+ "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
+ "dev": true
+ },
+ "ultron": {
+ "version": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",
+ "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=",
+ "dev": true
+ },
+ "umd": {
+ "version": "https://registry.npmjs.org/umd/-/umd-3.0.1.tgz",
+ "integrity": "sha1-iuVW4RAR9jwllnCKiDclnwGz1g4=",
+ "dev": true
+ },
+ "underscore.string": {
+ "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz",
+ "integrity": "sha1-gGmSYzZl1eX8tNsfs6hi62jp5to=",
+ "dev": true
+ },
+ "unpipe": {
+ "version": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+ "dev": true
+ },
+ "upper-case": {
+ "version": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
+ "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=",
+ "dev": true
+ },
+ "upper-case-first": {
+ "version": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz",
+ "integrity": "sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU=",
+ "dev": true,
+ "requires": {
+ "upper-case": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz"
+ }
+ },
+ "uri-path": {
+ "version": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz",
+ "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=",
+ "dev": true
+ },
+ "url": {
+ "version": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+ "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+ "dev": true,
+ "requires": {
+ "punycode": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "querystring": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
+ "dev": true
+ }
+ }
+ },
+ "user-home": {
+ "version": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz",
+ "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=",
+ "dev": true
+ },
+ "useragent": {
+ "version": "https://registry.npmjs.org/useragent/-/useragent-2.2.1.tgz",
+ "integrity": "sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4=",
+ "dev": true,
+ "requires": {
+ "lru-cache": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz",
+ "tmp": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz"
+ },
+ "dependencies": {
+ "lru-cache": {
+ "version": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz",
+ "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=",
+ "dev": true
+ }
+ }
+ },
+ "util": {
+ "version": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+ "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+ "dev": true,
+ "requires": {
+ "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
+ "dev": true
+ }
+ }
+ },
+ "util-deprecate": {
+ "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "utils-merge": {
+ "version": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+ "dev": true
+ },
+ "uuid": {
+ "version": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
+ "integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ=",
+ "dev": true
+ },
+ "v8flags": {
+ "version": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz",
+ "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=",
+ "dev": true,
+ "requires": {
+ "user-home": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz"
+ }
+ },
+ "validate-npm-package-license": {
+ "version": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
+ "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=",
+ "dev": true,
+ "requires": {
+ "spdx-correct": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz",
+ "spdx-expression-parse": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz"
+ }
+ },
+ "verror": {
+ "version": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz",
+ "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=",
+ "dev": true,
+ "requires": {
+ "extsprintf": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz"
+ }
+ },
+ "vm-browserify": {
+ "version": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
+ "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=",
+ "dev": true,
+ "requires": {
+ "indexof": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz"
+ }
+ },
+ "void-elements": {
+ "version": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
+ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=",
+ "dev": true
+ },
+ "watchify": {
+ "version": "https://registry.npmjs.org/watchify/-/watchify-3.9.0.tgz",
+ "integrity": "sha1-8HX9LoqGrN6Eztum5cKgvt1SPZ4=",
+ "dev": true,
+ "requires": {
+ "anymatch": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+ "browserify": "https://registry.npmjs.org/browserify/-/browserify-14.4.0.tgz",
+ "chokidar": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
+ "defined": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+ "outpipe": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz",
+ "through2": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+ "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
+ }
+ },
+ "websocket-driver": {
+ "version": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
+ "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=",
+ "dev": true,
+ "requires": {
+ "websocket-extensions": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz"
+ }
+ },
+ "websocket-extensions": {
+ "version": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz",
+ "integrity": "sha1-domUmcGEtu91Q3fC27DNbLVdKec=",
+ "dev": true
+ },
+ "which": {
+ "version": "https://registry.npmjs.org/which/-/which-1.2.14.tgz",
+ "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=",
+ "dev": true,
+ "requires": {
+ "isexe": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
+ }
+ },
+ "window-size": {
+ "version": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
+ "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
+ "dev": true
+ },
+ "wordwrap": {
+ "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
+ "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
+ "dev": true
+ },
+ "wrappy": {
+ "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "ws": {
+ "version": "https://registry.npmjs.org/ws/-/ws-1.1.2.tgz",
+ "integrity": "sha1-iiRPoFJAHgjJiGz0SoUYnh/UBn8=",
+ "dev": true,
+ "requires": {
+ "options": "https://registry.npmjs.org/options/-/options-0.0.6.tgz",
+ "ultron": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz"
+ }
+ },
+ "wtf-8": {
+ "version": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz",
+ "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=",
+ "dev": true
+ },
+ "xml-char-classes": {
+ "version": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz",
+ "integrity": "sha1-ZGV4SKIP/F31g6Qq2KJ3tFErvE0=",
+ "dev": true
+ },
+ "xmlhttprequest-ssl": {
+ "version": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz",
+ "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=",
+ "dev": true
+ },
+ "xtend": {
+ "version": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
+ "dev": true
+ },
+ "yargs": {
+ "version": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+ "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
+ "dev": true,
+ "requires": {
+ "camelcase": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
+ "cliui": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
+ "decamelize": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "window-size": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
+ "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
+ "dev": true
+ }
+ }
+ },
+ "yauzl": {
+ "version": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
+ "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
+ "dev": true,
+ "requires": {
+ "fd-slicer": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz"
+ }
+ },
+ "yeast": {
+ "version": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
+ "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=",
+ "dev": true
+ }
+ }
+}
diff --git a/package.json b/package.json
index 6e3a91bc1..71547d01e 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "name": "neeto",
+ "name": "standard-notes",
"version": "1.0.0",
"repository": {
"type": "git",
@@ -32,7 +32,8 @@
"karma": "^1.4.0",
"karma-cli": "^1.0.1",
"karma-jasmine": "^1.1.0",
- "karma-phantomjs-launcher": "^1.0.2"
+ "karma-phantomjs-launcher": "^1.0.2",
+ "sn-stylekit": "1.0.12"
},
"license": "GPL-3.0"
}
diff --git a/public/extensions/extensions-manager b/public/extensions/extensions-manager
new file mode 160000
index 000000000..3bfd3c1b4
--- /dev/null
+++ b/public/extensions/extensions-manager
@@ -0,0 +1 @@
+Subproject commit 3bfd3c1b4fb1225fe6b063eacc51cc05697f47a8
diff --git a/test/javascripts/controllers/HomeCtrl_spec.js b/test/javascripts/controllers/HomeCtrl_spec.js
index 0ae1e1650..d93065c78 100644
--- a/test/javascripts/controllers/HomeCtrl_spec.js
+++ b/test/javascripts/controllers/HomeCtrl_spec.js
@@ -1,6 +1,6 @@
-describe("app.frontend", function() {
+describe("app", function() {
- beforeEach(module('app.frontend'));
+ beforeEach(module('app'));
describe('Home Controller', function() {
diff --git a/test/javascripts/filters/DateFilter_spec.js b/test/javascripts/filters/DateFilter_spec.js
index b79c1dce9..cdfa55a55 100644
--- a/test/javascripts/filters/DateFilter_spec.js
+++ b/test/javascripts/filters/DateFilter_spec.js
@@ -1,5 +1,5 @@
describe("date filter", function() {
- beforeEach(module('app.frontend'));
+ beforeEach(module('app'));
var $filter;
beforeEach(inject(function(_$filter_){
diff --git a/vendor/assets/fonts/ionicons.eot b/vendor/assets/fonts/ionicons.eot
index 92a3f20a3..9edec3907 100644
Binary files a/vendor/assets/fonts/ionicons.eot and b/vendor/assets/fonts/ionicons.eot differ
diff --git a/vendor/assets/fonts/ionicons.svg b/vendor/assets/fonts/ionicons.svg
index 49fc8f367..5188c5687 100644
--- a/vendor/assets/fonts/ionicons.svg
+++ b/vendor/assets/fonts/ionicons.svg
@@ -1,2230 +1,36 @@
-