diff --git a/Makefile b/Makefile index dc71fb01e3..3d8ffc7e2c 100644 --- a/Makefile +++ b/Makefile @@ -364,7 +364,6 @@ server_noattach: tmux new-window 'exec make receiver' tmux select-window -t tower:1 tmux rename-window 'Extra Services' - tmux split-window -v 'exec make socketservice' tmux split-window -h 'exec make factcacher' server: server_noattach diff --git a/Procfile b/Procfile index b8dd37a983..b63680a2e2 100644 --- a/Procfile +++ b/Procfile @@ -1,6 +1,5 @@ runserver: make runserver celeryd: make celeryd receiver: make receiver -socketservice: make socketservice factcacher: make factcacher flower: make flower diff --git a/awx/api/views.py b/awx/api/views.py index b6423776a2..1343b34d3b 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -68,7 +68,7 @@ from awx.api.permissions import * # noqa from awx.api.renderers import * # noqa from awx.api.serializers import * # noqa from awx.api.metadata import RoleMetadata -from awx.main.utils import emit_websocket_notification +from awx.main.consumers import emit_channel_notification logger = logging.getLogger('awx.api.views') @@ -532,11 +532,9 @@ class AuthTokenView(APIView): # Mark them as invalid and inform the user invalid_tokens = AuthToken.get_tokens_over_limit(serializer.validated_data['user']) for t in invalid_tokens: - # TODO: send socket notification - emit_websocket_notification('/socket.io/control', - 'limit_reached', - dict(reason=force_text(AuthToken.reason_long('limit_reached'))), - token_key=t.key) + emit_channel_notification('control-limit_reached', dict(group_name='control', + reason=force_text(AuthToken.reason_long('limit_reached')), + token_key=t.key)) t.invalidate(reason='limit_reached') # Note: This header is normally added in the middleware whenever an @@ -2654,7 +2652,7 @@ class WorkflowJobTemplateNodeChildrenBaseList(EnforceParentRelationshipMixin, Su relationship = '' enforce_parent_relationship = 'workflow_job_template' new_in_310 = True - + ''' Limit the set of WorkflowJobTemplateNodes to the related nodes of specified by 'relationship' @@ -2663,7 +2661,7 @@ class WorkflowJobTemplateNodeChildrenBaseList(EnforceParentRelationshipMixin, Su parent = self.get_parent_object() self.check_parent_access(parent) return getattr(parent, self.relationship).all() - + class WorkflowJobTemplateNodeSuccessNodesList(WorkflowJobTemplateNodeChildrenBaseList): relationship = 'success_nodes' @@ -2684,7 +2682,7 @@ class WorkflowJobNodeChildrenBaseList(SubListAPIView): enforce_parent_relationship = 'workflow_job_template' new_in_310 = True ''' - + # #Limit the set of WorkflowJobeNodes to the related nodes of specified by #'relationship' @@ -2693,7 +2691,7 @@ class WorkflowJobNodeChildrenBaseList(SubListAPIView): parent = self.get_parent_object() self.check_parent_access(parent) return getattr(parent, self.relationship).all() - + class WorkflowJobNodeSuccessNodesList(WorkflowJobNodeChildrenBaseList): relationship = 'success_nodes' @@ -2768,6 +2766,7 @@ class WorkflowJobTemplateJobsList(SubListAPIView): relationship = 'jobs' parent_key = 'workflow_job_template' +# TODO: class WorkflowJobList(ListCreateAPIView): model = WorkflowJob @@ -3174,21 +3173,8 @@ class JobJobTasksList(BaseJobEventsList): return ({'detail': 'Parent event not found.'}, -1, status.HTTP_404_NOT_FOUND) parent_task = parent_task[0] - # Some events correspond to a playbook or task starting up, - # and these are what we're interested in here. STARTING_EVENTS = ('playbook_on_task_start', 'playbook_on_setup') - - # We need to pull information about each start event. - # - # This is super tricky, because this table has a one-to-many - # relationship with itself (parent-child), and we're getting - # information for an arbitrary number of children. This means we - # need stats on grandchildren, sorted by child. - queryset = (JobEvent.objects.filter(parent__parent=parent_task, - parent__event__in=STARTING_EVENTS) - .values('parent__id', 'event', 'changed') - .annotate(num=Count('event')) - .order_by('parent__id')) + queryset = JobEvent.get_startevent_queryset(parent_task, STARTING_EVENTS) # The data above will come back in a list, but we are going to # want to access it based on the parent id, so map it into a @@ -3766,7 +3752,7 @@ class RoleList(ListAPIView): def get_queryset(self): result = Role.visible_roles(self.request.user) - # Sanity check: is the requesting user an orphaned non-admin/auditor? + # Sanity check: is the requesting user an orphaned non-admin/auditor? # if yes, make system admin/auditor mandatorily visible. if not self.request.user.organizations.exists() and\ not self.request.user.is_superuser and\ diff --git a/awx/asgi.py b/awx/asgi.py new file mode 100644 index 0000000000..42d800d939 --- /dev/null +++ b/awx/asgi.py @@ -0,0 +1,37 @@ +# Copyright (c) 2015 Ansible, Inc. +# All Rights Reserved. +import os +import logging +from awx import __version__ as tower_version + +# Prepare the AWX environment. +from awx import prepare_env, MODE +prepare_env() + +from django.core.wsgi import get_wsgi_application # NOQA + +""" +ASGI config for AWX project. + +It exposes the ASGI callable as a module-level variable named ``channel_layer``. + +For more information on this file, see +https://channels.readthedocs.io/en/latest/deploying.html +""" + +if MODE == 'production': + logger = logging.getLogger('awx.main.models.jobs') + try: + fd = open("/var/lib/awx/.tower_version", "r") + if fd.read().strip() != tower_version: + raise Exception() + except Exception: + logger.error("Missing or incorrect metadata for Tower version. Ensure Tower was installed using the setup playbook.") + raise Exception("Missing or incorrect metadata for Tower version. Ensure Tower was installed using the setup playbook.") + +from channels.asgi import get_channel_layer + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "awx.settings") + + +channel_layer = get_channel_layer() diff --git a/awx/main/consumers.py b/awx/main/consumers.py new file mode 100644 index 0000000000..fb4bf55fd3 --- /dev/null +++ b/awx/main/consumers.py @@ -0,0 +1,39 @@ +import json + +from channels import Group +from channels.sessions import channel_session + + +def discard_groups(message): + if 'groups' in message.channel_session: + for group in message.channel_session['groups']: + Group(group).discard(message.reply_channel) + +@channel_session +def ws_disconnect(message): + discard_groups(message) + +@channel_session +def ws_receive(message): + raw_data = message.content['text'] + data = json.loads(raw_data) + + if 'groups' in data: + discard_groups(message) + groups = data['groups'] + current_groups = message.channel_session.pop('groups') if 'groups' in message.channel_session else [] + for group_name,v in groups.items(): + if type(v) is list: + for oid in v: + name = '{}-{}'.format(group_name, oid) + current_groups.append(name) + Group(name).add(message.reply_channel) + else: + current_groups.append(group_name) + Group(group_name).add(message.reply_channel) + message.channel_session['groups'] = current_groups + + +def emit_channel_notification(group, payload): + payload = json.dumps(payload) + Group(group).send({"text": json.dumps(payload)}) diff --git a/awx/main/migrations/0039_v310_channelgroup.py b/awx/main/migrations/0039_v310_channelgroup.py new file mode 100644 index 0000000000..a150f4cf29 --- /dev/null +++ b/awx/main/migrations/0039_v310_channelgroup.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0038_v310_workflow_rbac_prompts'), + ] + + operations = [ + migrations.CreateModel( + name='ChannelGroup', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('group', models.CharField(unique=True, max_length=200)), + ('channels', models.TextField()), + ], + ), + ] diff --git a/awx/main/models/__init__.py b/awx/main/models/__init__.py index 161a59e65c..f70229cf72 100644 --- a/awx/main/models/__init__.py +++ b/awx/main/models/__init__.py @@ -22,6 +22,7 @@ from awx.main.models.notifications import * # noqa from awx.main.models.fact import * # noqa from awx.main.models.label import * # noqa from awx.main.models.workflow import * # noqa +from awx.main.models.channels import * # noqa # Monkeypatch Django serializer to ignore django-taggit fields (which break # the dumpdata command; see https://github.com/alex/django-taggit/issues/155). diff --git a/awx/main/models/channels.py b/awx/main/models/channels.py new file mode 100644 index 0000000000..cd34678638 --- /dev/null +++ b/awx/main/models/channels.py @@ -0,0 +1,5 @@ +from django.db import models + +class ChannelGroup(models.Model): + group = models.CharField(max_length=200, unique=True) + channels = models.TextField() diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 5089c4a868..7dc7eae7b5 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -1222,7 +1222,7 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin): from awx.main.tasks import RunInventoryUpdate return RunInventoryUpdate - def socketio_emit_data(self): + def websocket_emit_data(self): if self.inventory_source.group is not None: return dict(group_id=self.inventory_source.group.id) return {} diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index d08a5fba40..e146a266be 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -29,12 +29,13 @@ from awx.main.models.notifications import ( JobNotificationMixin, ) from awx.main.utils import decrypt_field, ignore_inventory_computed_fields -from awx.main.utils import emit_websocket_notification from awx.main.redact import PlainTextCleaner from awx.main.fields import ImplicitRoleField from awx.main.models.mixins import ResourceMixin from awx.main.models.base import PERM_INVENTORY_SCAN +from awx.main.consumers import emit_channel_notification + logger = logging.getLogger('awx.main.models.jobs') @@ -1270,11 +1271,10 @@ class JobEvent(CreatedModifiedModel): if update_fields: host_summary.save(update_fields=update_fields) job.inventory.update_computed_fields() - emit_websocket_notification('/socket.io/jobs', 'summary_complete', dict(unified_job_id=job.id)) - + emit_channel_notification('jobs-summary', dict(group_name='jobs', unified_job_id=job.id)) @classmethod - def start_event_queryset(cls, parent_task, starting_events, ordering=None): + def get_startevent_queryset(cls, parent_task, starting_events, ordering=None): ''' We need to pull information about each start event. @@ -1380,7 +1380,7 @@ class SystemJob(UnifiedJob, SystemJobOptions, JobNotificationMixin): from awx.main.tasks import RunSystemJob return RunSystemJob - def socketio_emit_data(self): + def websocket_emit_data(self): return {} def get_absolute_url(self): @@ -1421,4 +1421,3 @@ class SystemJob(UnifiedJob, SystemJobOptions, JobNotificationMixin): def get_notification_friendly_name(self): return "System Job" - diff --git a/awx/main/models/projects.py b/awx/main/models/projects.py index c9b23adc7b..59263fff6a 100644 --- a/awx/main/models/projects.py +++ b/awx/main/models/projects.py @@ -407,7 +407,7 @@ class ProjectUpdate(UnifiedJob, ProjectOptions, JobNotificationMixin): return True return False - def socketio_emit_data(self): + def websocket_emit_data(self): return dict(project_id=self.project.id) @property diff --git a/awx/main/models/schedules.py b/awx/main/models/schedules.py index d9de8b394e..8fe83d832b 100644 --- a/awx/main/models/schedules.py +++ b/awx/main/models/schedules.py @@ -16,7 +16,8 @@ from jsonfield import JSONField # AWX from awx.main.models.base import * # noqa -from awx.main.utils import ignore_inventory_computed_fields, emit_websocket_notification +from awx.main.utils import ignore_inventory_computed_fields +from awx.main.consumers import emit_channel_notification from django.core.urlresolvers import reverse logger = logging.getLogger('awx.main.models.schedule') @@ -112,7 +113,7 @@ class Schedule(CommonModel): self.dtend = make_aware(datetime.datetime.strptime(until_date, "%Y%m%dT%H%M%SZ"), get_default_timezone()) if 'count' in self.rrule.lower(): self.dtend = future_rs[-1] - emit_websocket_notification('/socket.io/schedules', 'schedule_changed', dict(id=self.id)) + emit_channel_notification('schedules-changed', dict(id=self.id, group_name='schedules')) with ignore_inventory_computed_fields(): self.unified_job_template.update_computed_fields() diff --git a/awx/main/models/unified_jobs.py b/awx/main/models/unified_jobs.py index d304f24d79..3a30906e02 100644 --- a/awx/main/models/unified_jobs.py +++ b/awx/main/models/unified_jobs.py @@ -32,8 +32,9 @@ from djcelery.models import TaskMeta # AWX from awx.main.models.base import * # noqa from awx.main.models.schedules import Schedule -from awx.main.utils import decrypt_field, emit_websocket_notification, _inventory_updates -from awx.main.redact import UriCleaner, REPLACE_STR +from awx.main.utils import decrypt_field, _inventory_updates +from awx.main.redact import UriCleaner +from awx.main.consumers import emit_channel_notification __all__ = ['UnifiedJobTemplate', 'UnifiedJob'] @@ -774,14 +775,15 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique ''' Given another task object determine if this task would be blocked by it ''' raise NotImplementedError # Implement in subclass. - def socketio_emit_data(self): + def websocket_emit_data(self): ''' Return extra data that should be included when submitting data to the browser over the websocket connection ''' return {} - def socketio_emit_status(self, status): + def websocket_emit_status(self, status): status_data = dict(unified_job_id=self.id, status=status) - status_data.update(self.socketio_emit_data()) - emit_websocket_notification('/socket.io/jobs', 'status_changed', status_data) + status_data.update(self.websocket_emit_data()) + status_data['group_name'] = 'jobs' + emit_channel_notification('jobs-status_changed', status_data) def generate_dependencies(self, active_tasks): ''' Generate any tasks that the current task might be dependent on given a list of active @@ -859,7 +861,7 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique # Save the pending status, and inform the SocketIO listener. self.update_fields(start_args=json.dumps(kwargs), status='pending') - self.socketio_emit_status("pending") + self.websocket_emit_status("pending") from awx.main.scheduler.tasks import run_job_launch run_job_launch.delay(self.id) @@ -912,7 +914,7 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique instance.job_explanation = 'Forced cancel' update_fields.append('job_explanation') instance.save(update_fields=update_fields) - self.socketio_emit_status("canceled") + self.websocket_emit_status("canceled") except: # FIXME: Log this exception! if settings.DEBUG: raise @@ -926,8 +928,7 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique self.status = 'canceled' cancel_fields.append('status') self.save(update_fields=cancel_fields) - self.socketio_emit_status("canceled") + self.websocket_emit_status("canceled") if settings.BROKER_URL.startswith('amqp://'): self._force_cancel() return self.cancel_flag - diff --git a/awx/main/routing.py b/awx/main/routing.py new file mode 100644 index 0000000000..67a08ff1bd --- /dev/null +++ b/awx/main/routing.py @@ -0,0 +1,7 @@ +from channels.routing import route + + +channel_routing = [ + route("websocket.disconnect", "awx.main.consumers.ws_disconnect", path=r'^/websocket/$'), + route("websocket.receive", "awx.main.consumers.ws_receive", path=r'^/websocket/$'), +] diff --git a/awx/main/scheduler/__init__.py b/awx/main/scheduler/__init__.py index 6c15488251..b93ce6956e 100644 --- a/awx/main/scheduler/__init__.py +++ b/awx/main/scheduler/__init__.py @@ -62,7 +62,7 @@ def spawn_workflow_graph_jobs(workflow_jobs): job.status = 'failed' job.job_explanation = "Workflow job could not start because it was not in the right state or required manual credentials" job.save(update_fields=['status', 'job_explanation']) - job.socketio_emit_status("failed") + job.websocket_emit_status("failed") # TODO: should we emit a status on the socket here similar to tasks.py tower_periodic_scheduler() ? #emit_websocket_notification('/socket.io/jobs', '', dict(id=)) @@ -76,7 +76,7 @@ def process_finished_workflow_jobs(workflow_jobs): # TODO: detect if wfj failed workflow_job.status = 'completed' workflow_job.save() - workflow_job.socketio_emit_status('completed') + workflow_job.websocket_emit_status('completed') def rebuild_graph(): """Regenerate the task graph by refreshing known tasks from Tower, purging @@ -120,7 +120,7 @@ def rebuild_graph(): logger.debug("Active celery tasks: " + str(active_tasks)) for task in list(running_celery_tasks): if (task.celery_task_id not in active_tasks and not hasattr(settings, 'IGNORE_CELERY_INSPECTOR')): - # NOTE: Pull status again and make sure it didn't finish in + # NOTE: Pull status again and make sure it didn't finish in # the meantime? task.status = 'failed' task.job_explanation += ' '.join(( @@ -128,8 +128,8 @@ def rebuild_graph(): 'Celery, so it has been marked as failed.', )) task.save() - task.socketio_emit_status("failed") - running_tasks.pop(task) + task.websocket_emit_status("failed") + running_tasks.pop(running_tasks.index(task)) logger.error("Task %s appears orphaned... marking as failed" % task) # Create and process dependencies for new tasks @@ -142,7 +142,7 @@ def rebuild_graph(): task.status = 'failed' task.job_explanation += 'Task failed to generate dependencies: {}'.format(e) task.save() - task.socketio_emit_status("failed") + task.websocket_emit_status("failed") continue logger.debug("New dependencies: %s" % str(task_dependencies)) for dep in task_dependencies: @@ -202,7 +202,7 @@ def process_graph(graph, task_capacity): node_type = graph.get_node_type(node_obj) if node_type == 'job': - # clear dependencies because a job can block (not necessarily + # clear dependencies because a job can block (not necessarily # depend) on other jobs that share the same job template node_dependencies = [] @@ -215,7 +215,7 @@ def process_graph(graph, task_capacity): node_obj.start() spawn_workflow_graph_jobs([node_obj]) return process_graph(graph, task_capacity) - + dependent_nodes = [{'type': graph.get_node_type(node_obj), 'id': node_obj.id}] + \ [{'type': graph.get_node_type(n['node_object']), 'id': n['node_object'].id} for n in node_dependencies] diff --git a/awx/main/signals.py b/awx/main/signals.py index 324f3fe825..7a06934d27 100644 --- a/awx/main/signals.py +++ b/awx/main/signals.py @@ -19,10 +19,12 @@ from crum.signals import current_user_getter # AWX from awx.main.models import * # noqa from awx.api.serializers import * # noqa -from awx.main.utils import model_instance_diff, model_to_dict, camelcase_to_underscore, emit_websocket_notification +from awx.main.utils import model_instance_diff, model_to_dict, camelcase_to_underscore from awx.main.utils import ignore_inventory_computed_fields, ignore_inventory_group_removal, _inventory_updates from awx.main.tasks import update_inventory_computed_fields +from awx.main.consumers import emit_channel_notification + __all__ = [] logger = logging.getLogger('awx.main.signals') @@ -33,13 +35,15 @@ logger = logging.getLogger('awx.main.signals') def emit_job_event_detail(sender, **kwargs): instance = kwargs['instance'] created = kwargs['created'] + print("before created job_event_detail") if created: event_serialized = JobEventSerializer(instance).data event_serialized['id'] = instance.id event_serialized["created"] = event_serialized["created"].isoformat() event_serialized["modified"] = event_serialized["modified"].isoformat() event_serialized["event_name"] = instance.event - emit_websocket_notification('/socket.io/job_events', 'job_events-' + str(instance.job.id), event_serialized) + event_serialized["group_name"] = "job_events" + emit_channel_notification('job_events-' + str(instance.job.id), event_serialized) def emit_ad_hoc_command_event_detail(sender, **kwargs): instance = kwargs['instance'] @@ -50,7 +54,8 @@ def emit_ad_hoc_command_event_detail(sender, **kwargs): event_serialized["created"] = event_serialized["created"].isoformat() event_serialized["modified"] = event_serialized["modified"].isoformat() event_serialized["event_name"] = instance.event - emit_websocket_notification('/socket.io/ad_hoc_command_events', 'ad_hoc_command_events-' + str(instance.ad_hoc_command_id), event_serialized) + event_serialized["group_name"] = "ad_hoc_command_events" + emit_channel_notification('ad_hoc_command_events-' + str(instance.ad_hoc_command_id), event_serialized) def emit_update_inventory_computed_fields(sender, **kwargs): logger.debug("In update inventory computed fields") diff --git a/awx/main/tasks.py b/awx/main/tasks.py index 932ba3262c..05a172b6da 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -49,13 +49,13 @@ from awx.main.models import * # noqa from awx.main.models import UnifiedJob from awx.main.task_engine import TaskEnhancer from awx.main.utils import (get_ansible_version, get_ssh_version, decrypt_field, update_scm_url, - emit_websocket_notification, check_proot_installed, build_proot_temp_dir, wrap_args_with_proot) +from awx.main.consumers import emit_channel_notification __all__ = ['RunJob', 'RunSystemJob', 'RunProjectUpdate', 'RunInventoryUpdate', - 'RunAdHocCommand', 'RunWorkflowJob', 'handle_work_error', - 'handle_work_success', 'update_inventory_computed_fields', - 'send_notifications', 'run_administrative_checks', + 'RunAdHocCommand', 'RunWorkflowJob', 'handle_work_error', + 'handle_work_success', 'update_inventory_computed_fields', + 'send_notifications', 'run_administrative_checks', 'RunJobLaunch'] HIDDEN_PASSWORD = '**********' @@ -183,8 +183,8 @@ def tower_periodic_scheduler(self): new_unified_job.status = 'failed' new_unified_job.job_explanation = "Scheduled job could not start because it was not in the right state or required manual credentials" new_unified_job.save(update_fields=['status', 'job_explanation']) - new_unified_job.socketio_emit_status("failed") - emit_websocket_notification('/socket.io/schedules', 'schedule_changed', dict(id=schedule.id)) + new_unified_job.websocket_emit_status("failed") + emit_channel_notification('schedules-changed', dict(id=schedule.id, group_name="schedules")) def _send_notification_templates(instance, status_str): if status_str not in ['succeeded', 'failed']: @@ -237,11 +237,11 @@ def handle_work_error(self, task_id, subtasks=None): instance.job_explanation = 'Previous Task Failed: {"job_type": "%s", "job_name": "%s", "job_id": "%s"}' % \ (first_instance_type, first_instance.name, first_instance.id) instance.save() - instance.socketio_emit_status("failed") + instance.websocket_emit_status("failed") if first_instance: _send_notification_templates(first_instance, 'failed') - + # We only send 1 job complete message since all the job completion message # handling does is trigger the scheduler. If we extend the functionality of # what the job complete message handler does then we may want to send a @@ -590,7 +590,7 @@ class BaseTask(Task): ''' instance = self.update_model(pk, status='running', celery_task_id=self.request.id) - instance.socketio_emit_status("running") + instance.websocket_emit_status("running") status, rc, tb = 'error', None, '' output_replacements = [] try: @@ -659,7 +659,7 @@ class BaseTask(Task): instance = self.update_model(pk, status=status, result_traceback=tb, output_replacements=output_replacements) self.post_run_hook(instance, **kwargs) - instance.socketio_emit_status(status) + instance.websocket_emit_status(status) if status != 'successful' and not hasattr(settings, 'CELERY_UNIT_TEST'): # Raising an exception will mark the job as 'failed' in celery # and will stop a task chain from continuing to execute @@ -1678,7 +1678,7 @@ class RunSystemJob(BaseTask): ''' class RunWorkflowJob(BaseTask): - + name = 'awx.main.tasks.run_workflow_job' model = WorkflowJob @@ -1691,14 +1691,14 @@ class RunWorkflowJob(BaseTask): # complete. Instead, the workflow job should return or never even run, # because all of the "launch logic" can be done schedule(). - # However, other aspects of our system depend on a 1-1 relationship + # However, other aspects of our system depend on a 1-1 relationship # between a Job and a Celery Task. - # + # # * If we let the workflow job task (RunWorkflowJob.run()) complete - # then how do we trigger the handle_work_error and + # then how do we trigger the handle_work_error and # handle_work_success subtasks? # - # * How do we handle the recovery process? (i.e. there is an entry in + # * How do we handle the recovery process? (i.e. there is an entry in # the database but not in celery). while True: dag = WorkflowDAG(instance) diff --git a/awx/main/utils.py b/awx/main/utils.py index 0bb8ccc149..c06d0fac2d 100644 --- a/awx/main/utils.py +++ b/awx/main/utils.py @@ -491,19 +491,6 @@ def get_system_task_capacity(): return 50 + ((int(total_mem_value) / 1024) - 2) * 75 -def emit_websocket_notification(endpoint, event, payload, token_key=None): - from awx.main.socket_queue import Socket - - try: - with Socket('websocket', 'w', nowait=True, logger=logger) as websocket: - if token_key: - payload['token_key'] = token_key - payload['event'] = event - payload['endpoint'] = endpoint - websocket.publish(payload) - except Exception: - pass - _inventory_updates = threading.local() diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index 71467e3bab..ecc27fcbf0 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -192,6 +192,7 @@ INSTALLED_APPS = ( 'django_extensions', 'djcelery', 'kombu.transport.django', + 'channels', 'polymorphic', 'taggit', 'social.apps.django_app.default', @@ -375,7 +376,7 @@ CELERY_ROUTES = {'awx.main.tasks.run_job': {'queue': 'jobs', 'awx.main.tasks.cluster_node_heartbeat': {'queue': 'default', 'routing_key': 'cluster.heartbeat'}, } - + CELERYBEAT_SCHEDULE = { 'tower_scheduler': { 'task': 'awx.main.tasks.tower_periodic_scheduler', @@ -976,4 +977,3 @@ LOGGING = { }, } } - diff --git a/awx/settings/local_settings.py.docker_compose b/awx/settings/local_settings.py.docker_compose index c87a209501..088f651e77 100644 --- a/awx/settings/local_settings.py.docker_compose +++ b/awx/settings/local_settings.py.docker_compose @@ -75,7 +75,7 @@ if is_testing(sys.argv): }, } } - + MONGO_DB = 'system_tracking_test' # Celery AMQP configuration. @@ -84,6 +84,12 @@ BROKER_URL = "amqp://{}:{}@{}/{}".format(os.environ.get("RABBITMQ_USER"), os.environ.get("RABBITMQ_HOST"), os.environ.get("RABBITMQ_VHOST")) +CHANNEL_LAYERS = { + 'default': {'BACKEND': 'asgi_amqp.AMQPChannelLayer', + 'ROUTING': 'awx.main.routing.channel_routing', + 'CONFIG': {'url': BROKER_URL}} +} + # Mongo host configuration MONGO_HOST = NotImplemented diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index 0f925812f6..6df9567b34 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -29,7 +29,6 @@ import './helpers'; import './forms'; import './lists'; import './widgets'; -import './help'; import './filters'; import { Home } from './controllers/Home'; import { SocketsController } from './controllers/Sockets'; @@ -75,7 +74,6 @@ import './shared/Modal'; import './shared/prompt-dialog'; import './shared/directives'; import './shared/filters'; -import './shared/Socket'; import './shared/features/main'; import config from './shared/config/main'; import './login/authenticationServices/pendo/ng-pendo'; @@ -183,7 +181,6 @@ var tower = angular.module('Tower', [ 'HostGroupsFormDefinition', 'StreamWidget', 'JobsHelper', - 'InventoryGroupsHelpDefinition', 'CredentialsHelper', 'StreamListDefinition', 'ActivityDetailDefinition', @@ -197,10 +194,8 @@ var tower = angular.module('Tower', [ 'StandardOutHelper', 'LogViewerOptionsDefinition', 'JobDetailHelper', - 'SocketIO', 'lrInfiniteScroll', 'LoadConfigHelper', - 'SocketHelper', 'PortalJobsListDefinition', 'features', 'longDateFilter', @@ -243,88 +238,6 @@ var tower = angular.module('Tower', [ }); $stateProvider. - state('dashboard', { - url: '/home', - templateUrl: urlPrefix + 'partials/home.html', - controller: Home, - params: { licenseMissing: null }, - data: { - activityStream: true, - refreshButton: true - }, - ncyBreadcrumb: { - label: "DASHBOARD" - }, - resolve: { - graphData: ['$q', 'jobStatusGraphData', '$rootScope', - function($q, jobStatusGraphData, $rootScope) { - return $rootScope.featuresConfigured.promise.then(function() { - return $q.all({ - jobStatus: jobStatusGraphData.get("month", "all"), - }); - }); - } - ] - } - }). - - state('jobs', { - url: '/jobs', - templateUrl: urlPrefix + 'partials/jobs.html', - controller: JobsListController, - ncyBreadcrumb: { - label: "JOBS" - } - }). - - state('projects', { - url: '/projects?{status}', - templateUrl: urlPrefix + 'partials/projects.html', - controller: ProjectsList, - data: { - activityStream: true, - activityStreamTarget: 'project' - }, - ncyBreadcrumb: { - label: "PROJECTS" - } - }). - - state('projects.add', { - url: '/add', - templateUrl: urlPrefix + 'partials/projects.html', - controller: ProjectsAdd, - ncyBreadcrumb: { - parent: "projects", - label: "CREATE PROJECT" - } - }). - - state('projects.edit', { - url: '/:id', - templateUrl: urlPrefix + 'partials/projects.html', - controller: ProjectsEdit, - data: { - activityStreamId: 'id' - }, - ncyBreadcrumb: { - parent: 'projects', - label: '{{name}}' - } - }). - - state('projectOrganizations', { - url: '/projects/:project_id/organizations', - templateUrl: urlPrefix + 'partials/projects.html', - controller: OrganizationsList - }). - - state('projectOrganizationAdd', { - url: '/projects/:project_id/organizations/add', - templateUrl: urlPrefix + 'partials/projects.html', - controller: OrganizationsAdd - }). - state('teams', { url: '/teams', templateUrl: urlPrefix + 'partials/teams.html', @@ -526,18 +439,137 @@ var tower = angular.module('Tower', [ }]); }]) -.run(['$q', '$compile', '$cookieStore', '$rootScope', '$log', +.run(['$stateExtender', '$q', '$compile', '$cookieStore', '$rootScope', '$log', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer', - 'ClearScope', 'Socket', 'LoadConfig', 'Store', - 'ShowSocketHelp', 'pendoService', 'Prompt', 'Rest', 'Wait', - 'ProcessErrors', '$state', 'GetBasePath', 'ConfigService', - 'FeaturesService', '$filter', - function($q, $compile, $cookieStore, $rootScope, $log, CheckLicense, - $location, Authorization, LoadBasePaths, Timer, ClearScope, Socket, - LoadConfig, Store, ShowSocketHelp, pendoService, Prompt, Rest, Wait, + 'ClearScope', 'LoadConfig', 'Store', 'pendoService', 'Prompt', 'Rest', + 'Wait', 'ProcessErrors', '$state', 'GetBasePath', 'ConfigService', + 'FeaturesService', '$filter', 'SocketService', + function($stateExtender, $q, $compile, $cookieStore, $rootScope, $log, + CheckLicense, $location, Authorization, LoadBasePaths, Timer, + ClearScope, LoadConfig, Store, pendoService, Prompt, Rest, Wait, ProcessErrors, $state, GetBasePath, ConfigService, FeaturesService, - $filter) { - var sock; + $filter, SocketService) { + + $stateExtender.addState({ + name: 'dashboard', + url: '/home', + templateUrl: urlPrefix + 'partials/home.html', + controller: Home, + params: { licenseMissing: null }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } + }, + data: { + activityStream: true, + refreshButton: true + }, + ncyBreadcrumb: { + label: "DASHBOARD" + }, + resolve: { + graphData: ['$q', 'jobStatusGraphData', '$rootScope', + function($q, jobStatusGraphData, $rootScope) { + return $rootScope.featuresConfigured.promise.then(function() { + return $q.all({ + jobStatus: jobStatusGraphData.get("month", "all"), + }); + }); + } + ] + } + }); + + $stateExtender.addState({ + name: 'jobs', + url: '/jobs', + templateUrl: urlPrefix + 'partials/jobs.html', + controller: JobsListController, + ncyBreadcrumb: { + label: "JOBS" + }, + params: { + search: { + value: {order_by:'-finished'} + } + }, + socket: { + "groups":{ + "jobs": ["status_changed"], + "schedules": ["changed"] + } + } + }); + + $stateExtender.addState({ + name: 'projects', + url: '/projects?{status}', + templateUrl: urlPrefix + 'partials/projects.html', + controller: ProjectsList, + data: { + activityStream: true, + activityStreamTarget: 'project' + }, + ncyBreadcrumb: { + label: "PROJECTS" + }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } + } + }); + + $stateExtender.addState({ + name: 'projects.add', + url: '/add', + templateUrl: urlPrefix + 'partials/projects.html', + controller: ProjectsAdd, + ncyBreadcrumb: { + parent: "projects", + label: "CREATE PROJECT" + }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } + } + }); + + $stateExtender.addState({ + name: 'projects.edit', + url: '/:id', + templateUrl: urlPrefix + 'partials/projects.html', + controller: ProjectsEdit, + data: { + activityStreamId: 'id' + }, + ncyBreadcrumb: { + parent: 'projects', + label: '{{name}}' + }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } + } + }); + + $stateExtender.addState({ + name: 'projectOrganizations', + url: '/projects/:project_id/organizations', + templateUrl: urlPrefix + 'partials/projects.html', + controller: OrganizationsList + }); + + $stateExtender.addState({ + name: 'projectOrganizationAdd', + url: '/projects/:project_id/organizations/add', + templateUrl: urlPrefix + 'partials/projects.html', + controller: OrganizationsAdd + }); + $rootScope.addPermission = function(scope) { $compile("")(scope); }; @@ -709,84 +741,9 @@ var tower = angular.module('Tower', [ $rootScope.crumbCache = []; - if ($rootScope.removeOpenSocket) { - $rootScope.removeOpenSocket(); - } - $rootScope.removeOpenSocket = $rootScope.$on('OpenSocket', function() { - // Listen for job changes and issue callbacks to initiate - // DOM updates - function openSocket() { - var schedule_socket, control_socket; - - sock = Socket({ scope: $rootScope, endpoint: "jobs" }); - sock.init(); - sock.on("status_changed", function(data) { - $log.debug('Job ' + data.unified_job_id + - ' status changed to ' + data.status + - ' send to ' + $location.$$url); - - // this acts as a router...it emits the proper - // value based on what URL the user is currently - // accessing. - if ($state.is('jobs')) { - $rootScope.$emit('JobStatusChange-jobs', data); - } else if ($state.includes('jobDetail') || - $state.is('adHocJobStdout') || - $state.is('inventorySyncStdout') || - $state.is('managementJobStdout') || - $state.is('scmUpdateStdout')) { - - $log.debug("sending status to standard out"); - $rootScope.$emit('JobStatusChange-jobStdout', data); - } - if ($state.includes('jobDetail')) { - $rootScope.$emit('JobStatusChange-jobDetails', data); - } else if ($state.is('dashboard')) { - $rootScope.$emit('JobStatusChange-home', data); - } else if ($state.is('portalMode')) { - $rootScope.$emit('JobStatusChange-portal', data); - } else if ($state.is('projects')) { - $rootScope.$emit('JobStatusChange-projects', data); - } else if ($state.is('inventoryManage')) { - $rootScope.$emit('JobStatusChange-inventory', data); - } - }); - sock.on("summary_complete", function(data) { - $log.debug('Job summary_complete ' + data.unified_job_id); - $rootScope.$emit('JobSummaryComplete', data); - }); - - schedule_socket = Socket({ - scope: $rootScope, - endpoint: "schedules" - }); - schedule_socket.init(); - schedule_socket.on("schedule_changed", function(data) { - $log.debug('Schedule ' + data.unified_job_id + ' status changed to ' + data.status); - $rootScope.$emit('ScheduleStatusChange', data); - }); - - control_socket = Socket({ - scope: $rootScope, - endpoint: "control" - }); - control_socket.init(); - control_socket.on("limit_reached", function(data) { - $log.debug(data.reason); - $rootScope.sessionTimer.expireSession('session_limit'); - $state.go('signOut'); - }); - } - openSocket(); - - setTimeout(function() { - $rootScope.$apply(function() { - sock.checkStatus(); - $log.debug('socket status: ' + $rootScope.socketStatus); - }); - }, 2000); - }); - + // $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState) { + // SocketService.subscribe(toState, toParams); + // }); $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState) { @@ -845,7 +802,7 @@ var tower = angular.module('Tower', [ ConfigService.getConfig().then(function() { Timer.init().then(function(timer) { $rootScope.sessionTimer = timer; - $rootScope.$emit('OpenSocket'); + SocketService.init(); pendoService.issuePendoIdentity(); CheckLicense.test(); FeaturesService.get(); @@ -873,10 +830,6 @@ var tower = angular.module('Tower', [ $('#' + tabs + ' #' + tab).tab('show'); }; - $rootScope.socketHelp = function() { - ShowSocketHelp(); - }; - $rootScope.leavePortal = function() { $rootScope.portalMode = false; $location.path('/home/'); diff --git a/awx/ui/client/src/controllers/Home.js b/awx/ui/client/src/controllers/Home.js index bbaa7d02ad..a4999487f6 100644 --- a/awx/ui/client/src/controllers/Home.js +++ b/awx/ui/client/src/controllers/Home.js @@ -28,7 +28,7 @@ export function Home($scope, $compile, $stateParams, $rootScope, $location, $log var dataCount = 0; - $rootScope.$on('JobStatusChange-home', function () { + $scope.$on('ws-jobs', function () { Rest.setUrl(GetBasePath('dashboard')); Rest.get() .success(function (data) { diff --git a/awx/ui/client/src/controllers/Jobs.js b/awx/ui/client/src/controllers/Jobs.js index 0e2f46f736..07e84df3ee 100644 --- a/awx/ui/client/src/controllers/Jobs.js +++ b/awx/ui/client/src/controllers/Jobs.js @@ -65,7 +65,7 @@ export function JobsListController ($rootScope, $log, $scope, $compile, $statePa jobs_scope.viewJob = function (id) { $state.transitionTo('jobDetail', {id: id}); }; - + jobs_scope.showJobType = true; LoadJobsScope({ parent_scope: $scope, @@ -110,17 +110,11 @@ export function JobsListController ($rootScope, $log, $scope, $compile, $statePa } }; - if ($rootScope.removeJobStatusChange) { - $rootScope.removeJobStatusChange(); - } - $rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange-jobs', function() { + $scope.$on('ws-jobs', function() { $scope.refreshJobs(); }); - if ($rootScope.removeScheduleStatusChange) { - $rootScope.removeScheduleStatusChange(); - } - $rootScope.removeScheduleStatusChange = $rootScope.$on('ScheduleStatusChange', function() { + $scope.$on('ws-schedules', function() { if (api_complete) { scheduled_scope.search('schedule'); } diff --git a/awx/ui/client/src/controllers/Projects.js b/awx/ui/client/src/controllers/Projects.js index f5db4a2b8c..0a7b1dcd64 100644 --- a/awx/ui/client/src/controllers/Projects.js +++ b/awx/ui/client/src/controllers/Projects.js @@ -86,11 +86,7 @@ export function ProjectsList ($scope, $rootScope, $location, $log, $stateParams, } }); - // Handle project update status changes - if ($rootScope.removeJobStatusChange) { - $rootScope.removeJobStatusChange(); - } - $rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange-projects', function(e, data) { + $scope.$on(`ws-jobs`, function(e, data) { var project; $log.debug(data); if ($scope.projects) { diff --git a/awx/ui/client/src/dashboard/graphs/job-status/job-status-graph.service.js b/awx/ui/client/src/dashboard/graphs/job-status/job-status-graph.service.js index 50a5a2968b..0e6a3b4dda 100644 --- a/awx/ui/client/src/dashboard/graphs/job-status/job-status-graph.service.js +++ b/awx/ui/client/src/dashboard/graphs/job-status/job-status-graph.service.js @@ -58,7 +58,7 @@ function JobStatusGraphData(Rest, getBasePath, processErrors, $rootScope, $q) { destroyWatcher: angular.noop, setupWatcher: function(period, jobType) { this.destroyWatcher = - $rootScope.$on('JobStatusChange-home', function() { + $rootScope.$on('ws-jobs', function() { getData(period, jobType).then(function(result) { $rootScope. $broadcast('DataReceived:JobStatusGraph', diff --git a/awx/ui/client/src/help.js b/awx/ui/client/src/help.js deleted file mode 100644 index 0c526d541f..0000000000 --- a/awx/ui/client/src/help.js +++ /dev/null @@ -1,10 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -import "./help/ChromeSocketHelp"; -import "./help/FirefoxSocketHelp"; -import "./help/InventoryGroups"; -import "./help/SafariSocketHelp"; diff --git a/awx/ui/client/src/help/ChromeSocketHelp.js b/awx/ui/client/src/help/ChromeSocketHelp.js deleted file mode 100644 index d2ea6ef44a..0000000000 --- a/awx/ui/client/src/help/ChromeSocketHelp.js +++ /dev/null @@ -1,47 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - - /** - * @ngdoc overview - * @name help - * @description These are the modal windows that are shown to the user to give additional guidance on certain tasks that might not be straightforward. -*/ - - /** - * @ngdoc function - * @name help.function:ChromeSocketHelp - * @description This help modal gives instructions on what the user should do if not connected to the web sockets while using Chrome. -*/ - - -angular.module('ChromeSocketHelpDefinition', []) - .value('ChromeSocketHelp', { - story: { - hdr: 'Live Events', - width: 510, - height: 560, - steps: [{ - intro: 'Connection status indicator:', - img: { - src: 'socket_indicator.png', - maxWidth: 360 - }, - box: "

indicates live events are streaming and the browser is connected to the live events server.

If the indicator continually shows " + - "or , then live events are not streaming, and the browser is having difficulty connecting to the live events server. In this case click Next for troubleshooting help.

" - }, { - intro: 'Live events connection:', - icon: { - "class": "fa fa-5x fa-rss {{ socketStatus }}-color", - style: "margin-top: 75px;", - containerHeight: 200 - }, - box: "

{{ browserName }} is connecting to the live events server on port {{ socketPort }}. The current connection status is " + - " {{ socketStatus }}.

If the connection status indicator is not green, have the " + - "system administrator verify this is the correct port and that access to the port is not blocked by a firewall." - }] - } - }); diff --git a/awx/ui/client/src/help/FirefoxSocketHelp.js b/awx/ui/client/src/help/FirefoxSocketHelp.js deleted file mode 100644 index 989bb2fb87..0000000000 --- a/awx/ui/client/src/help/FirefoxSocketHelp.js +++ /dev/null @@ -1,78 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name help.function:FirefoxSocketHelp - * @description This help modal gives instructions on what the user should do if not connected to the web sockets while using Firefox. -*/ - - -angular.module('FFSocketHelpDefinition', []) - .value('FFSocketHelp', { - story: { - hdr: 'Live Events', - width: 510, - height: 560, - steps: [{ - intro: 'Connection status indicator:', - img: { - src: 'socket_indicator.png', - maxWidth: 360 - }, - box: "

indicates live events are streaming and the browser is connected to the live events server.

If the indicator continually shows " + - "or , then live events are not streaming, and the browser is having difficulty connecting to the live events server. In this case click Next for troubleshooting help.

" - }, { - intro: 'Live events connection:', - icon: { - "class": "fa fa-5x fa-rss {{ socketStatus }}-color", - style: "margin-top: 75px;", - containerHeight: 200 - }, - box: "

{{ browserName }} is connecting to the live events server on port {{ socketPort }}. The current connection status is " + - " {{ socketStatus }}.

If the connection status indicator is not green, have the " + - "system administrator verify this is the correct port and that access to the port is not blocked by a firewall.

" - }, { - intro: 'Self signed certificate:', - icon: { - "class": "fa fa-5x fa-check ok-color", - style: "margin-top: 75px;", - containerHeight: 200 - }, - box: "

If the Tower web server is using a self signed security certificate, Firefox needs to accept the certificate and allow the " + - "connection.

Click Next for help accepting a self signed certificate.

" - }, { - intro: 'Accepting a self-signed certificate:', - img: { - src: 'understand_the_risk.png', - maxWidth: 440 - }, - box: "

Navigate to {{ socketURL }} The above warning will appear.

Click I Understand the Risks

" - }, { - intro: 'Accepting a self-signed certificate:', - img: { - src: 'add_exception.png', - maxWidth: 440 - }, - box: "

Click the Add Exception button." - }, { - intro: 'Accepting a self-signed certificate:', - img: { - src: 'confirm_exception.png', - maxWidth: 340 - }, - box: "

Click the Confirm the Security Exception button. This will add the self signed certificate from the Tower server to Firefox's list of trusted certificates.

" - }, { - intro: 'Accepting a self-signed certificate:', - img: { - src: 'refresh_firefox.png', - maxWidth: 480 - }, - box: "

Now that Firefox has accepted the security certificate the live event connection status indicator should turn green. If it does not, reload Tower by clicking the " + - "Firefox refresh button." - }] - } - }); diff --git a/awx/ui/client/src/help/InventoryGroups.js b/awx/ui/client/src/help/InventoryGroups.js deleted file mode 100644 index c9ee3b7432..0000000000 --- a/awx/ui/client/src/help/InventoryGroups.js +++ /dev/null @@ -1,86 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name help.function:InventoryGroups - * @description This help modal walks the user how to add groups to an inventory or a subgroup to an existing group. -*/ - - -angular.module('InventoryGroupsHelpDefinition', []) - .value('InventoryGroupsHelp', { - story: { - hdr: 'Inventory Setup', - width: 510, - height: 560, - steps: [{ - intro: 'Start by creating a group:', - img: { - src: 'groups001.png', - maxWidth: 257, - maxHeight: 114 - }, - box: "Click on the groups list (the left side of the page) to add a new group.", - autoOffNotice: true - }, { - intro: 'Enter group properties:', - img: { - src: 'groups002.png', - maxWidth: 443, - maxHeight: 251 - }, - box: 'Enter the group name, a description and any inventory variables. Variables can be entered using either JSON or YAML syntax. ' + - 'For more on inventory variables, see ' + - 'docs.ansible.com/intro_inventory.html' - }, { - intro: 'Cloud inventory: select cloud source', - img: { - src: 'groups003.png', - maxWidth: 412, - maxHeight: 215 - }, - box: "For a cloud inventory, choose the cloud provider from the list and select your credentials. If you have not already setup " + - "credentials for the provider, you will need to do that first on the Credentials tab." - }, { - intro: 'Cloud inventory: synchronize Tower with the cloud', - img: { - src: 'groups004.png', - maxWidth: 187, - maxHeight: 175 - }, - box: "To import a cloud inventory into Tower, initiate an inventory sync by clicking ." - }, { - intro: "Add subgroups:", - img: { - src: 'groups008.png', - maxWidth: 469, - maxHeight: 243 - }, - box: "

First, select an existing group.
" - }, { - intro: "Add subgroups:", - img: { - src: 'groups009.png', - maxWidth: 475, - maxHeight: 198 - }, - box: "
Then click to create a new group. The new group " + - "will be added to the selected group.
" - }, { - intro: 'Add hosts:', - img: { - src: 'groups010.png', - maxWidth: 475, - maxHeight: 122 - }, - box: "

First, select a Group. " + - "Then click on the hosts list (the right side of the page) to create a host. " + - "The new host will be part of the selected group.

" - }] - } - }); diff --git a/awx/ui/client/src/help/SafariSocketHelp.js b/awx/ui/client/src/help/SafariSocketHelp.js deleted file mode 100644 index 46b9cf48b0..0000000000 --- a/awx/ui/client/src/help/SafariSocketHelp.js +++ /dev/null @@ -1,50 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name help.function:SafariSocketHelp - * @description This help modal gives instructions on what the user should do if not connected to the web sockets while using Safari. Safari does not support websockets. -*/ - - -angular.module('SafariSocketHelpDefinition', []) - .value('SafariSocketHelp', { - story: { - hdr: 'Live Events', - width: 510, - height: 560, - steps: [{ - intro: 'Connection status indicator:', - img: { - src: 'socket_indicator.png', - maxWidth: 360 - }, - box: "

indicates live events are streaming and the browser is connected to the live events server.

If the indicator continually shows " + - "or , then live events are not streaming, and the browser is having difficulty connecting to the live events server. In this case click Next for troubleshooting help.

" - }, { - intro: 'Live events connection:', - icon: { - "class": "fa fa-5x fa-rss {{ socketStatus }}-color", - style: "margin-top: 75px;", - containerHeight: 200 - }, - box: "

{{ browserName }} is connecting to the live events server on port {{ socketPort }}. The current connection status is " + - " {{ socketStatus }}.

If the connection status indicator is not green, have the " + - "system administrator verify this is the correct port and that access to the port is not blocked by a firewall.

" - }, { - intro: 'Self signed certificate:', - icon: { - "class": "fa fa-5x fa-check ok-color", - style: "margin-top: 75px;", - containerHeight: 200 - }, - box: "

Safari will not connect to the live event port when the Tower web server is configured with a self signed certificate. Check with a system administrator to " + - "determine if Tower is using a self signed certificate. Installing a signed certificate will fix the problem.

" + - "

Switching browsers to either Chrome or Firefox will work as well.

" - }] - } - }); diff --git a/awx/ui/client/src/helpers.js b/awx/ui/client/src/helpers.js index aae8a17225..cf5f65e601 100644 --- a/awx/ui/client/src/helpers.js +++ b/awx/ui/client/src/helpers.js @@ -23,7 +23,6 @@ import ProjectPath from "./helpers/ProjectPath"; import Projects from "./helpers/Projects"; import Schedules from "./helpers/Schedules"; import Selection from "./helpers/Selection"; -import SocketHelper from "./helpers/SocketHelper"; import Users from "./helpers/Users"; import Variables from "./helpers/Variables"; import ApiDefaults from "./helpers/api-defaults"; @@ -55,7 +54,6 @@ export Projects, Schedules, Selection, - SocketHelper, Users, Variables, ApiDefaults, diff --git a/awx/ui/client/src/helpers/SocketHelper.js b/awx/ui/client/src/helpers/SocketHelper.js deleted file mode 100644 index ea0110cf01..0000000000 --- a/awx/ui/client/src/helpers/SocketHelper.js +++ /dev/null @@ -1,39 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name helpers.function:SocketHelper - * @description - * SocketHelper.js - * - * Show web socket troubleshooting help - * - */ - - -export default - angular.module('SocketHelper', ['Utilities', 'FFSocketHelpDefinition', 'SafariSocketHelpDefinition' , 'ChromeSocketHelpDefinition']) - - .factory('ShowSocketHelp', ['$location', '$rootScope', 'FFSocketHelp', 'SafariSocketHelp', 'ChromeSocketHelp', 'HelpDialog', 'browserData', - function($location, $rootScope, FFSocketHelp, SafariSocketHelp, ChromeSocketHelp, HelpDialog, browserData) { - return function() { - var scope = $rootScope.$new(); - scope.socketPort = $AnsibleConfig.websocket_port; - scope.socketURL = 'https://' + $location.host() + ':' + scope.socketPort + '/'; - scope.browserName = browserData.name; - - if (browserData.name === 'Firefox') { - HelpDialog({ defn: FFSocketHelp, scope: scope }); - } - else if (browserData.name === 'Safari') { - HelpDialog({ defn: SafariSocketHelp, scope: scope }); - } - else { - HelpDialog({ defn: ChromeSocketHelp, scope: scope }); - } - }; - }]); diff --git a/awx/ui/client/src/inventories/manage/adhoc/adhoc.route.js b/awx/ui/client/src/inventories/manage/adhoc/adhoc.route.js index d8eb57e735..935dac79f6 100644 --- a/awx/ui/client/src/inventories/manage/adhoc/adhoc.route.js +++ b/awx/ui/client/src/inventories/manage/adhoc/adhoc.route.js @@ -23,5 +23,10 @@ export default { }, ncyBreadcrumb: { label: "RUN COMMAND" + }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } } }; diff --git a/awx/ui/client/src/inventories/manage/copy-move/copy-move.route.js b/awx/ui/client/src/inventories/manage/copy-move/copy-move.route.js index 85d856c5ed..e133414ce1 100644 --- a/awx/ui/client/src/inventories/manage/copy-move/copy-move.route.js +++ b/awx/ui/client/src/inventories/manage/copy-move/copy-move.route.js @@ -22,6 +22,11 @@ var copyMoveGroup = { return GroupManageService.get({id: $stateParams.group_id}).then(res => res.data.results[0]); }] }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } + }, views: { 'form@inventoryManage' : { controller: CopyMoveGroupsController, @@ -40,6 +45,11 @@ var copyMoveHost = { return HostManageService.get({id: $stateParams.host_id}).then(res => res.data.results[0]); }] }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } + }, views: { 'form@inventoryManage': { templateUrl: templateUrl('inventories/manage/copy-move/copy-move'), diff --git a/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js b/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js index a2f843793b..f9a20a8830 100644 --- a/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js +++ b/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js @@ -5,12 +5,14 @@ *************************************************/ export default ['$scope', '$rootScope', '$state', '$stateParams', 'InventoryGroups', 'generateList', 'InventoryUpdate', 'GroupManageService', 'GroupsCancelUpdate', 'ViewUpdateStatus', - 'InventoryManageService', 'groupsUrl', 'SearchInit', 'PaginateInit', 'GetSyncStatusMsg', 'GetHostsStatusMsg', 'Rest', 'GetBasePath', 'rbacUiControlService', + 'InventoryManageService', 'groupsUrl', 'SearchInit', 'PaginateInit', 'GetSyncStatusMsg', 'GetHostsStatusMsg', 'Find', 'Rest', 'GetBasePath', 'rbacUiControlService', function($scope, $rootScope, $state, $stateParams, InventoryGroups, generateList, InventoryUpdate, GroupManageService, GroupsCancelUpdate, ViewUpdateStatus, - InventoryManageService, groupsUrl, SearchInit, PaginateInit, GetSyncStatusMsg, GetHostsStatusMsg, Rest, GetBasePath, rbacUiControlService){ + InventoryManageService, groupsUrl, SearchInit, PaginateInit, GetSyncStatusMsg, GetHostsStatusMsg, Find, Rest, GetBasePath, rbacUiControlService){ var list = InventoryGroups, view = generateList, pageSize = 20; + + $scope.inventory_id = $stateParams.inventory_id; $scope.canAdd = false; @@ -97,26 +99,27 @@ group_name: group.name, group_source: res.data.results[0].source })); - $scope.$emit('WatchUpdateStatus'); // init socket io conneciton and start watching for status updates - $rootScope.$on('JobStatusChange-inventory', (event, data) => { - switch(data.status){ - case 'failed' || 'successful': - $state.reload(); - break; - default: - var status = GetSyncStatusMsg({ - status: data.status, - has_inventory_sources: group.has_inventory_sources, - source: group.source - }); - group.status = data.status; - group.status_class = status.class; - group.status_tooltip = status.tooltip; - group.launch_tooltip = status.launch_tip; - group.launch_class = status.launch_class; - } - }); }; + + $scope.$on(`ws-jobs`, function(e, data){ + var group = Find({ list: $scope.groups, key: 'id', val: data.group_id }); + if(data.status === 'failed' || data.status === 'successful'){ + $state.reload(); + } + else{ + var status = GetSyncStatusMsg({ + status: data.status, + has_inventory_sources: group.has_inventory_sources, + source: group.source + }); + group.status = data.status; + group.status_class = status.class; + group.status_tooltip = status.tooltip; + group.launch_tooltip = status.launch_tip; + group.launch_class = status.launch_class; + } + }); + $scope.cancelUpdate = function (id) { GroupsCancelUpdate({ scope: $scope, id: id }); }; diff --git a/awx/ui/client/src/inventories/manage/groups/groups.route.js b/awx/ui/client/src/inventories/manage/groups/groups.route.js index 905a7d2997..e7a9ac8732 100644 --- a/awx/ui/client/src/inventories/manage/groups/groups.route.js +++ b/awx/ui/client/src/inventories/manage/groups/groups.route.js @@ -16,6 +16,11 @@ var ManageGroupsEdit = { data: { mode: 'edit' }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } + }, resolve: { groupData: ['$stateParams', 'GroupManageService', function($stateParams, GroupManageService){ return GroupManageService.get({id: $stateParams.group_id}).then(res => res.data.results[0]); @@ -41,6 +46,11 @@ var ManageGroupsAdd = { data: { mode: 'add' }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } + }, views: { 'form@inventoryManage': { controller: addController, diff --git a/awx/ui/client/src/inventories/manage/hosts/hosts.route.js b/awx/ui/client/src/inventories/manage/hosts/hosts.route.js index 86661e70f5..2edbf3518b 100644 --- a/awx/ui/client/src/inventories/manage/hosts/hosts.route.js +++ b/awx/ui/client/src/inventories/manage/hosts/hosts.route.js @@ -23,6 +23,11 @@ var ManageHostsEdit = { }); }] }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } + }, views: { 'form@inventoryManage': { controller: editController, @@ -40,6 +45,11 @@ var ManageHostsAdd = { data: { mode: 'add' }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } + }, views: { 'form@inventoryManage': { controller: addController, diff --git a/awx/ui/client/src/inventories/manage/inventory-manage.route.js b/awx/ui/client/src/inventories/manage/inventory-manage.route.js index 719ce3bf15..65d86d6569 100644 --- a/awx/ui/client/src/inventories/manage/inventory-manage.route.js +++ b/awx/ui/client/src/inventories/manage/inventory-manage.route.js @@ -13,6 +13,11 @@ import GroupsListController from './groups/groups-list.controller'; export default { name: 'inventoryManage', url: '/inventories/:inventory_id/manage?{group:int}{failed}', + socket: { + "groups":{ + "jobs": ["status_changed"] + } + }, params:{ group:{ array: true diff --git a/awx/ui/client/src/job-detail/host-event/host-event.route.js b/awx/ui/client/src/job-detail/host-event/host-event.route.js index 885034b747..b9fb2d4707 100644 --- a/awx/ui/client/src/job-detail/host-event/host-event.route.js +++ b/awx/ui/client/src/job-detail/host-event/host-event.route.js @@ -22,6 +22,12 @@ var hostEventModal = { return JobDetailService.getJobEventChildren($stateParams.taskId).then(res => res.data.results); }] }, + socket: { + "groups":{ + "jobs": ["status_changed", "summary"], + "job_events": [] + } + }, onExit: function() { // close the modal // using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X" @@ -36,28 +42,52 @@ var hostEventModal = { name: 'jobDetail.host-event.details', url: '/details', controller: 'HostEventController', - templateUrl: templateUrl('job-detail/host-event/host-event-details') + templateUrl: templateUrl('job-detail/host-event/host-event-details'), + socket: { + "groups":{ + "jobs": ["status_changed", "summary"], + "job_events": [] + } + } }; var hostEventJson = { name: 'jobDetail.host-event.json', url: '/json', controller: 'HostEventController', - templateUrl: templateUrl('job-detail/host-event/host-event-codemirror') + templateUrl: templateUrl('job-detail/host-event/host-event-codemirror'), + socket: { + "groups":{ + "jobs": ["status_changed", "summary"], + "job_events": [] + } + } }; var hostEventStdout = { name: 'jobDetail.host-event.stdout', url: '/stdout', controller: 'HostEventController', - templateUrl: templateUrl('job-detail/host-event/host-event-codemirror') + templateUrl: templateUrl('job-detail/host-event/host-event-codemirror'), + socket: { + "groups":{ + "jobs": ["status_changed", "summary"], + "job_events": [] + } + } }; var hostEventStderr = { name: 'jobDetail.host-event.stderr', url: '/stderr', controller: 'HostEventController', - templateUrl: templateUrl('job-detail/host-event/host-event-codemirror') + templateUrl: templateUrl('job-detail/host-event/host-event-codemirror'), + socket: { + "groups":{ + "jobs": ["status_changed", "summary"], + "job_events": [] + } + } }; diff --git a/awx/ui/client/src/job-detail/host-events/host-events.route.js b/awx/ui/client/src/job-detail/host-events/host-events.route.js index 835d17b2b9..710ef26e84 100644 --- a/awx/ui/client/src/job-detail/host-events/host-events.route.js +++ b/awx/ui/client/src/job-detail/host-events/host-events.route.js @@ -22,6 +22,12 @@ export default { $('.modal-backdrop').remove(); $('body').removeClass('modal-open'); }, + socket: { + "groups":{ + "jobs": ["status_changed", "summary"], + "job_events": [] + } + }, resolve: { hosts: ['JobDetailService','$stateParams', function(JobDetailService, $stateParams) { return JobDetailService.getRelatedJobEvents($stateParams.id, { diff --git a/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js b/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js index d5c826ac35..4f3e1be88d 100644 --- a/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js +++ b/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js @@ -48,23 +48,19 @@ $scope.status = res.results[0].status; }); }; - if ($rootScope.removeJobStatusChange) { - $rootScope.removeJobStatusChange(); + if ($rootScope.removeJobSummaryComplete) { + $rootScope.removeJobSummaryComplete(); } // emitted by the API in the same function used to persist host summary data // JobEvent.update_host_summary_from_stats() from /awx/main.models.jobs.py - $rootScope.removeJobStatusChange = $rootScope.$on('JobSummaryComplete', function(e, data) { + $scope.$on('ws-jobs-summary', function(e, data) { // discard socket msgs we don't care about in this context if (parseInt($stateParams.id) === data.unified_job_id){ init(); } }); - // UnifiedJob.def socketio_emit_status() from /awx/main.models.unified_jobs.py - if ($rootScope.removeJobSummaryComplete) { - $rootScope.removeJobSummaryComplete(); - } - $rootScope.removeJobSummaryComplete = $rootScope.$on('JobStatusChange-jobDetails', function(e, data) { + $scope.$on('ws-jobs', function(e, data) { if (parseInt($stateParams.id) === data.unified_job_id){ $scope.status = data.status; } diff --git a/awx/ui/client/src/job-detail/host-summary/host-summary.route.js b/awx/ui/client/src/job-detail/host-summary/host-summary.route.js index a2de70e5d4..8f5c1d2c0c 100644 --- a/awx/ui/client/src/job-detail/host-summary/host-summary.route.js +++ b/awx/ui/client/src/job-detail/host-summary/host-summary.route.js @@ -9,6 +9,12 @@ import {templateUrl} from '../../shared/template-url/template-url.factory'; export default { name: 'jobDetail.host-summary', url: '/event-summary', + socket: { + "groups":{ + "jobs": ["status_changed", "summary"], + "job_events": [] + } + }, views:{ 'host-summary': { controller: 'HostSummaryController', diff --git a/awx/ui/client/src/job-detail/job-detail.controller.js b/awx/ui/client/src/job-detail/job-detail.controller.js index 9181b21b20..81587e325d 100644 --- a/awx/ui/client/src/job-detail/job-detail.controller.js +++ b/awx/ui/client/src/job-detail/job-detail.controller.js @@ -197,32 +197,22 @@ export default "

Changed

\n" + "

Unreachable

\n" + "

Failed

\n"; - function openSocket() { - $rootScope.event_socket.on("job_events-" + job_id, function(data) { - // update elapsed time on each event received - scope.job_status.elapsed = GetElapsed({ - start: scope.job.created, - end: Date.now() - }); - if (api_complete && data.id > lastEventId) { - scope.waiting = false; - data.event = data.event_name; - DigestEvent({ scope: scope, event: data }); - } - UpdateDOM({ scope: scope }); - }); - // Unbind $rootScope socket event binding(s) so that they don't get triggered - // in another instance of this controller - scope.$on('$destroy', function() { - $rootScope.event_socket.removeAllListeners("job_events-" + job_id); - }); - } - openSocket(); - if ($rootScope.removeJobStatusChange) { - $rootScope.removeJobStatusChange(); - } - $rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange-jobDetails', function(e, data) { + scope.$on(`ws-job_events-${job_id}`, function(e, data) { + // update elapsed time on each event received + scope.job_status.elapsed = GetElapsed({ + start: scope.job.created, + end: Date.now() + }); + if (api_complete && data.id > lastEventId) { + scope.waiting = false; + data.event = data.event_name; + DigestEvent({ scope: scope, event: data }); + } + UpdateDOM({ scope: scope }); + }); + + scope.$on(`ws-jobs`, function(e, data) { // if we receive a status change event for the current job indicating the job // is finished, stop event queue processing and reload if (parseInt(data.unified_job_id, 10) === parseInt(job_id,10)) { @@ -236,10 +226,7 @@ export default } }); - if ($rootScope.removeJobSummaryComplete) { - $rootScope.removeJobSummaryComplete(); - } - $rootScope.removeJobSummaryComplete = $rootScope.$on('JobSummaryComplete', function() { + scope.$on('ws-jobs-summary', function() { // the job host summary should now be available from the API $log.debug('Trigging reload of job_host_summaries'); scope.$emit('InitialLoadComplete'); diff --git a/awx/ui/client/src/job-detail/job-detail.route.js b/awx/ui/client/src/job-detail/job-detail.route.js index dda2722511..c989d06ba4 100644 --- a/awx/ui/client/src/job-detail/job-detail.route.js +++ b/awx/ui/client/src/job-detail/job-detail.route.js @@ -13,21 +13,11 @@ export default { parent: 'jobs', label: "{{ job.id }} - {{ job.name }}" }, - resolve: { - jobEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { - if (!$rootScope.event_socket) { - $rootScope.event_socket = Socket({ - scope: $rootScope, - endpoint: "job_events" - }); - $rootScope.event_socket.init(); - // returns should really be providing $rootScope.event_socket - // otherwise, we have to inject the entire $rootScope into the controller - return true; - } else { - return true; - } - }] + socket: { + "groups":{ + "jobs": ["status_changed", "summary"], + "job_events": [] + } }, templateUrl: templateUrl('job-detail/job-detail'), controller: 'JobDetailController' diff --git a/awx/ui/client/src/job-templates/add/job-templates-add.route.js b/awx/ui/client/src/job-templates/add/job-templates-add.route.js index 68275c0f22..b4ede48910 100644 --- a/awx/ui/client/src/job-templates/add/job-templates-add.route.js +++ b/awx/ui/client/src/job-templates/add/job-templates-add.route.js @@ -15,6 +15,11 @@ export default { parent: "jobTemplates", label: "CREATE JOB TEMPLATE" }, + socket:{ + "groups":{ + "jobs": ["status_changed"] + } + }, onExit: function(){ // close the survey maker modal // using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X" diff --git a/awx/ui/client/src/job-templates/edit/job-templates-edit.route.js b/awx/ui/client/src/job-templates/edit/job-templates-edit.route.js index b2dffa229b..4e2d34f3c0 100644 --- a/awx/ui/client/src/job-templates/edit/job-templates-edit.route.js +++ b/awx/ui/client/src/job-templates/edit/job-templates-edit.route.js @@ -14,6 +14,11 @@ export default { data: { activityStreamId: 'id' }, + socket:{ + "groups":{ + "jobs": ["status_changed"] + } + }, ncyBreadcrumb: { parent: 'jobTemplates', label: "{{name}}" diff --git a/awx/ui/client/src/job-templates/list/job-templates-list.controller.js b/awx/ui/client/src/job-templates/list/job-templates-list.controller.js index 4e50f43fec..5273f1c0b4 100644 --- a/awx/ui/client/src/job-templates/list/job-templates-list.controller.js +++ b/awx/ui/client/src/job-templates/list/job-templates-list.controller.js @@ -37,6 +37,10 @@ export default view.inject(list, { mode: mode, scope: $scope }); $rootScope.flashMessage = null; + $scope.$on(`ws-jobs`, function () { + $scope.search(list.iterator); + }); + if ($scope.removePostRefresh) { $scope.removePostRefresh(); } diff --git a/awx/ui/client/src/job-templates/list/job-templates-list.route.js b/awx/ui/client/src/job-templates/list/job-templates-list.route.js index deeb1982bd..1a68cc8720 100644 --- a/awx/ui/client/src/job-templates/list/job-templates-list.route.js +++ b/awx/ui/client/src/job-templates/list/job-templates-list.route.js @@ -17,5 +17,10 @@ export default { }, ncyBreadcrumb: { label: "JOB TEMPLATES" + }, + socket:{ + "groups":{ + "jobs": ["status_changed"] + } } }; diff --git a/awx/ui/client/src/login/authenticationServices/authentication.service.js b/awx/ui/client/src/login/authenticationServices/authentication.service.js index c65ca0061d..73d42a3e50 100644 --- a/awx/ui/client/src/login/authenticationServices/authentication.service.js +++ b/awx/ui/client/src/login/authenticationServices/authentication.service.js @@ -65,6 +65,7 @@ export default var x, ConfigService = $injector.get('ConfigService'), + SocketService = $injector.get('SocketService'), scope = angular.element(document.getElementById('main-view')).scope(); if(scope){ @@ -94,6 +95,7 @@ export default $rootScope.lastUser = $cookieStore.get('current_user').id; } ConfigService.delete(); + SocketService.disconnect(); $cookieStore.remove('token_expires'); $cookieStore.remove('current_user'); $cookieStore.remove('token'); diff --git a/awx/ui/client/src/login/login.route.js b/awx/ui/client/src/login/login.route.js index 83b403ce6c..561cc3958a 100644 --- a/awx/ui/client/src/login/login.route.js +++ b/awx/ui/client/src/login/login.route.js @@ -9,6 +9,7 @@ import {templateUrl} from '../shared/template-url/template-url.factory'; export default { name: 'signIn', route: '/login', + socket: null, templateUrl: templateUrl('login/loginBackDrop'), resolve: { obj: ['$rootScope', 'Authorization', diff --git a/awx/ui/client/src/login/loginModal/loginModal.controller.js b/awx/ui/client/src/login/loginModal/loginModal.controller.js index 9bd5132ab1..69d509925f 100644 --- a/awx/ui/client/src/login/loginModal/loginModal.controller.js +++ b/awx/ui/client/src/login/loginModal/loginModal.controller.js @@ -57,10 +57,11 @@ export default ['$log', '$cookieStore', '$compile', '$window', '$rootScope', '$location', 'Authorization', 'ToggleClass', 'Alert', 'Wait', 'Timer', 'Empty', 'ClearScope', '$scope', 'pendoService', 'ConfigService', - 'CheckLicense', 'FeaturesService', + 'CheckLicense', 'FeaturesService', 'SocketService', function ($log, $cookieStore, $compile, $window, $rootScope, $location, Authorization, ToggleClass, Alert, Wait, Timer, Empty, ClearScope, - scope, pendoService, ConfigService, CheckLicense, FeaturesService) { + scope, pendoService, ConfigService, CheckLicense, FeaturesService, + SocketService) { var lastPath, lastUser, sessionExpired, loginAgain; loginAgain = function() { @@ -135,7 +136,7 @@ export default ['$log', '$cookieStore', '$compile', '$window', '$rootScope', Authorization.setUserInfo(data); Timer.init().then(function(timer){ $rootScope.sessionTimer = timer; - $rootScope.$emit('OpenSocket'); + SocketService.init(); $rootScope.user_is_superuser = data.results[0].is_superuser; $rootScope.user_is_system_auditor = data.results[0].is_system_auditor; scope.$emit('AuthorizationGetLicense'); diff --git a/awx/ui/client/src/organizations/linkout/controllers/organizations-job-templates.controller.js b/awx/ui/client/src/organizations/linkout/controllers/organizations-job-templates.controller.js index 58a8c60a17..c9669462b5 100644 --- a/awx/ui/client/src/organizations/linkout/controllers/organizations-job-templates.controller.js +++ b/awx/ui/client/src/organizations/linkout/controllers/organizations-job-templates.controller.js @@ -21,6 +21,10 @@ export default ['$scope', '$rootScope', '$location', '$log', generator = GenerateList, orgBase = GetBasePath('organizations'); + $scope.$on(`ws-jobs`, function () { + $scope.search(list.iterator); + }); + Rest.setUrl(orgBase + $stateParams.organization_id); Rest.get() .success(function (data) { diff --git a/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js b/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js index a718b423c2..5c3fde00fc 100644 --- a/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js +++ b/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js @@ -86,11 +86,7 @@ export default ['$scope', '$rootScope', '$location', '$log', } }); - // Handle project update status changes - if ($rootScope.removeJobStatusChange) { - $rootScope.removeJobStatusChange(); - } - $rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange-projects', function(e, data) { + $scope.$on(`ws-jobs`, function(e, data) { var project; $log.debug(data); if ($scope.projects) { diff --git a/awx/ui/client/src/organizations/linkout/organizations-linkout.route.js b/awx/ui/client/src/organizations/linkout/organizations-linkout.route.js index 13d51cc68f..fa909af4e3 100644 --- a/awx/ui/client/src/organizations/linkout/organizations-linkout.route.js +++ b/awx/ui/client/src/organizations/linkout/organizations-linkout.route.js @@ -99,6 +99,11 @@ export default [ features: ['FeaturesService', function(FeaturesService) { return FeaturesService.get(); }] + }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } } }, { @@ -121,6 +126,11 @@ export default [ features: ['FeaturesService', function(FeaturesService) { return FeaturesService.get(); }] + }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } } }, { diff --git a/awx/ui/client/src/portal-mode/portal-mode-jobs.controller.js b/awx/ui/client/src/portal-mode/portal-mode-jobs.controller.js index f6bd8ff9df..81d899e85f 100644 --- a/awx/ui/client/src/portal-mode/portal-mode-jobs.controller.js +++ b/awx/ui/client/src/portal-mode/portal-mode-jobs.controller.js @@ -13,12 +13,9 @@ export function PortalModeJobsController($scope, $rootScope, GetBasePath, Genera defaultUrl = GetBasePath('jobs') + '?created_by=' + $rootScope.current_user.id, pageSize = 12; - if ($rootScope.removeJobStatusChange) { - $rootScope.removeJobStatusChange(); - } - $rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange-portal', function() { + $scope.$on('ws-jobs', function() { $scope.search('job'); - }); + }); $scope.iterator = list.iterator; $scope.activeFilter = 'user'; diff --git a/awx/ui/client/src/portal-mode/portal-mode.route.js b/awx/ui/client/src/portal-mode/portal-mode.route.js index c0f7e5f3fb..788148dd52 100644 --- a/awx/ui/client/src/portal-mode/portal-mode.route.js +++ b/awx/ui/client/src/portal-mode/portal-mode.route.js @@ -9,6 +9,11 @@ export default { url: '/portal', ncyBreadcrumb: { label: "MY VIEW" + }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } }, views: { // the empty parent ui-view diff --git a/awx/ui/client/src/shared/Socket.js b/awx/ui/client/src/shared/Socket.js deleted file mode 100644 index 886b51d4a3..0000000000 --- a/awx/ui/client/src/shared/Socket.js +++ /dev/null @@ -1,226 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name shared.function:Socket - * @description - * Socket.js - * - * Wrapper for lib/socket.io-client/dist/socket.io.js. - */ - -/* global io */ - - -/** - * @ngdoc method - * @name shared.function:Socket#SocketIO - * @methodOf shared.function:Socket - * @description - */ -export default -angular.module('SocketIO', ['Utilities']) - - .factory('Socket', ['$rootScope', '$location', '$log', 'Authorization', 'Store', function ($rootScope, $location, $log, Authorization, Store) { - return function(params) { - var scope = params.scope, - host = $location.host(), - endpoint = params.endpoint, - protocol = $location.protocol(), - io = require('socket.io-client'), - config, socketPort, - url; - - // Since some pages are opened in a new tab, we might get here before AnsibleConfig is available. - // In that case, load from local storage. - if ($AnsibleConfig) { - socketPort = $AnsibleConfig.websocket_port; - } - else { - $log.debug('getting web socket port from local storage'); - config = Store('AnsibleConfig'); - socketPort = config.websocket_port; - } - url = protocol + '://' + host + ':' + socketPort + '/socket.io/' + endpoint; - $log.debug('opening socket connection to: ' + url); - - function getSocketTip(status) { - var result = ''; - switch(status) { - case 'error': - result = "Live events: error connecting to the Tower server."; - break; - case 'connecting': - result = "Live events: attempting to connect to the Tower server."; - break; - case "ok": - result = "Live events: connected. Pages containing job status information will automatically update in real-time."; - } - return result; - } - - return { - scope: scope, - url: url, - socket: null, - - init: function() { - var self = this, - token = Authorization.getToken(); - if (!$rootScope.sessionTimer || ($rootScope.sessionTimer && !$rootScope.sessionTimer.isExpired())) { - // We have a valid session token, so attempt socket connection - $log.debug('Socket connecting to: ' + url); - self.scope.socket_url = url; - self.socket = io.connect(url, { - query: "Token="+token, - headers: - { - 'Authorization': 'Token ' + token, // i don't think these are actually inserted into the header--jt - 'X-Auth-Token': 'Token ' + token - }, - 'connect timeout': 3000, - 'try multiple transports': false, - 'max reconnection attempts': 10, - 'reconnection limit': 2000, - 'force new connection': true - }); - - self.socket.on('connection', function() { - $log.debug('Socket connecting...'); - self.scope.$apply(function () { - self.scope.socketStatus = 'connecting'; - self.scope.socketTip = getSocketTip(self.scope.socketStatus); - }); - }); - self.socket.on('connect', function() { - $log.debug('Socket connection established'); - self.scope.$apply(function () { - self.scope.socketStatus = 'ok'; - self.scope.socketTip = getSocketTip(self.scope.socketStatus); - }); - }); - self.socket.on('connect_failed', function(reason) { - var r = reason || 'connection refused by host', - token_actual = Authorization.getToken(); - - $log.debug('Socket connection failed: ' + r); - - if (token_actual === token) { - self.socket.socket.disconnect(); - } - - self.scope.$apply(function () { - self.scope.socketStatus = 'error'; - self.scope.socketTip = getSocketTip(self.scope.socketStatus); - }); - - }); - self.socket.on('diconnect', function() { - $log.debug('Socket disconnected'); - self.scope.$apply(function() { - self.scope.socketStatus = 'error'; - self.scope.socketTip = getSocketTip(self.scope.socketStatus); - }); - }); - self.socket.on('error', function(reason) { - var r = reason || 'connection refused by host'; - $log.debug('Socket error: ' + r); - $log.error('Socket error: ' + r); - self.scope.$apply(function() { - self.scope.socketStatus = 'error'; - self.scope.socketTip = getSocketTip(self.scope.socketStatus); - }); - }); - self.socket.on('reconnecting', function() { - $log.debug('Socket attempting reconnect...'); - self.scope.$apply(function() { - self.scope.socketStatus = 'connecting'; - self.scope.socketTip = getSocketTip(self.scope.socketStatus); - }); - }); - self.socket.on('reconnect', function() { - $log.debug('Socket reconnected'); - self.scope.$apply(function() { - self.scope.socketStatus = 'ok'; - self.scope.socketTip = getSocketTip(self.scope.socketStatus); - }); - }); - self.socket.on('reconnect_failed', function(reason) { - $log.error('Socket reconnect failed: ' + reason); - self.scope.$apply(function() { - self.scope.socketStatus = 'error'; - self.scope.socketTip = getSocketTip(self.scope.socketStatus); - }); - }); - } - else { - // encountered expired token, redirect to login page - $rootScope.sessionTimer.expireSession('idle'); - $location.url('/login'); - } - }, - checkStatus: function() { - // Check connection status - var self = this; - if(self){ - if(self.socket){ - if(self.socket.socket){ - if (self.socket.socket.connected) { - self.scope.socketStatus = 'ok'; - } - else if (self.socket.socket.connecting || self.socket.reconnecting) { - self.scope.socketStatus = 'connecting'; - } - else { - self.scope.socketStatus = 'error'; - } - self.scope.socketTip = getSocketTip(self.scope.socketStatus); - return self.scope.socketStatus; - } - } - } - - }, - on: function (eventName, callback) { - var self = this; - if(self){ - if(self.socket){ - self.socket.on(eventName, function () { - var args = arguments; - self.scope.$apply(function () { - callback.apply(self.socket, args); - }); - }); - } - } - - }, - emit: function (eventName, data, callback) { - var self = this; - self.socket.emit(eventName, data, function () { - var args = arguments; - self.scope.$apply(function () { - if (callback) { - callback.apply(self.socket, args); - } - }); - }); - }, - getUrl: function() { - return url; - }, - removeAllListeners: function (eventName) { - var self = this; - if(self){ - if(self.socket){ - self.socket.removeAllListeners(eventName); - } - } - }, - }; - }; - }]); diff --git a/awx/ui/client/src/shared/icon/main.js b/awx/ui/client/src/shared/icon/main.js index a2dcf5a30c..87c8a0d474 100644 --- a/awx/ui/client/src/shared/icon/main.js +++ b/awx/ui/client/src/shared/icon/main.js @@ -3,5 +3,5 @@ import icon from './icon.directive'; export default angular.module('awIcon', []) - .directive('awIcon', icon) + .directive('awIcon', icon); //.directive('includeSvg', includeSvg); diff --git a/awx/ui/client/src/shared/main.js b/awx/ui/client/src/shared/main.js index 60c812e12c..8f92fab287 100644 --- a/awx/ui/client/src/shared/main.js +++ b/awx/ui/client/src/shared/main.js @@ -6,21 +6,21 @@ import listGenerator from './list-generator/main'; import pagination from './pagination/main'; -import title from './title.directive'; import lodashAsPromised from './lodash-as-promised'; import stringFilters from './string-filters/main'; import truncatedText from './truncated-text.directive'; import stateExtender from './stateExtender.provider'; import rbacUiControl from './rbacUiControl'; +import socket from './socket/main'; export default angular.module('shared', [listGenerator.name, pagination.name, stringFilters.name, 'ui.router', - rbacUiControl.name + rbacUiControl.name, + socket.name ]) .factory('lodashAsPromised', lodashAsPromised) .directive('truncatedText', truncatedText) - //.directive('title', title) .provider('$stateExtender', stateExtender); diff --git a/awx/ui/client/src/shared/socket/main.js b/awx/ui/client/src/shared/socket/main.js new file mode 100644 index 0000000000..3b38053762 --- /dev/null +++ b/awx/ui/client/src/shared/socket/main.js @@ -0,0 +1,13 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +// import awFeatureDirective from './features.directive'; +import socketService from './socket.service'; + +export default + angular.module('socket', []) + // .directive('awFeature', awFeatureDirective) + .service('SocketService', socketService); diff --git a/awx/ui/client/src/shared/socket/socket.service.js b/awx/ui/client/src/shared/socket/socket.service.js new file mode 100644 index 0000000000..6a992d4e5f --- /dev/null +++ b/awx/ui/client/src/shared/socket/socket.service.js @@ -0,0 +1,216 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ +import ReconnectingWebSocket from 'reconnectingwebsocket'; +export default +['$rootScope', '$location', '$log','$state', '$q', + function ($rootScope, $location, $log, $state, $q) { + var needsResubscribing = false, + socketPromise = $q.defer(); + return { + init: function() { + var self = this, + host = window.location.host, + url = "ws://" + host + "/websocket/"; + if (!$rootScope.sessionTimer || ($rootScope.sessionTimer && !$rootScope.sessionTimer.isExpired())) { + // We have a valid session token, so attempt socket connection + $log.debug('Socket connecting to: ' + url); + + self.socket = new ReconnectingWebSocket(url, null, { + timeoutInterval: 3000, + maxReconnectAttempts: 10 + }); + + self.socket.onopen = function () { + $log.debug("Websocket connection opened."); + socketPromise.resolve(); + self.checkStatus(); + if(needsResubscribing){ + self.subscribe(self.getLast()); + needsResubscribing = false; + } + + }; + + self.socket.onerror = function (error) { + self.checkStatus(); + $log.debug('Websocket Error Logged: ' + error); //log errors + }; + + self.socket.onconnecting = function (event) { + self.checkStatus(); + $log.debug('Websocket reconnecting'); + needsResubscribing = true; + }; + + self.socket.onclose = function (event) { + self.checkStatus(); + $log.debug(`Websocket disconnected`); + }; + + self.socket.onmessage = this.onMessage; + + return self.socket; + } + else { + // encountered expired token, redirect to login page + $rootScope.sessionTimer.expireSession('idle'); + $location.url('/login'); + } + }, + onMessage: function(e){ + // Function called when messages are received on by the UI from + // the API over the websocket. This will route each message to + // the appropriate controller for the current $state. + e.data = e.data.replace(/\\/g, ''); + e.data = e.data.substr(0, e.data.length-1); + e.data = e.data.substr(1); + $log.debug('Received From Server: ' + e.data); + + var data = JSON.parse(e.data), str = ""; + if(data.group_name==="jobs" && !('status' in data)){ + // we know that this must have been a + // summary complete message b/c status is missing. + // A an object w/ group_name === "jobs" AND a 'status' key + // means it was for the event: status_changed. + $log.debug('Job summary_complete ' + data.unified_job_id); + $rootScope.$broadcast('ws-jobs-summary', data); + return; + } + else if(data.group_name==="job_events"){ + // The naming scheme is "ws" then a + // dash (-) and the group_name, then the job ID + // ex: 'ws-jobs-' + str = `ws-${data.group_name}-${data.job}` + } + else if(data.group_name==="ad_hoc_command_events"){ + // The naming scheme is "ws" then a + // dash (-) and the group_name, then the job ID + // ex: 'ws-jobs-' + str = `ws-${data.group_name}-${data.ad_hoc_command}`; + } + else if(data.group_name==="control"){ + // As of Tower v. 3.1.0, there is only 1 "control" + // message, which is for expiring the session if the + // session limit is breached. + $log.debug(data.reason); + $rootScope.sessionTimer.expireSession('session_limit'); + $state.go('signOut'); + } + else { + // The naming scheme is "ws" then a + // dash (-) and the group_name. + // ex: 'ws-jobs' + str = `ws-${data.group_name}`; + } + $rootScope.$broadcast(str, data); + }, + disconnect: function(){ + if(this.socket){ + this.socket.close(); + } + }, + subscribe: function(state){ + // Subscribe is used to tell the API that the UI wants to + // listen for specific messages. A subscription object could + // look like {"groups":{"jobs": ["status_changed", "summary"]}. + // This is used by all socket-enabled $states + this.emit(JSON.stringify(state.socket)); + this.setLast(state); + }, + unsubscribe: function(state){ + // Unsubscribing tells the API that the user is no longer on + // on a socket-enabled page, and sends an empty groups object + // to the API: {"groups": {}}. + // This is used for all pages that are socket-disabled + if(this.requiresNewSubscribe(state)){ + this.emit(JSON.stringify(state.socket)); + } + this.setLast(state); + }, + setLast: function(state){ + this.last = state; + }, + getLast: function(){ + return this.last; + }, + requiresNewSubscribe(state){ + // This function is used for unsubscribing. If the last $state + // required an "unsubscribe", then we don't need to unsubscribe + // again, b/c the UI is already unsubscribed from all groups + if (this.getLast() !== undefined){ + if( _.isEmpty(state.socket.groups) && _.isEmpty(this.getLast().socket.groups)){ + return false; + } + else { + return true; + } + } + else { + return true; + } + }, + checkStatus: function() { + // Function for changing the socket indicator icon in the nav bar + var self = this; + if(self){ + if(self.socket){ + if (self.socket.readyState === 0 ) { + $rootScope.socketStatus = 'connecting'; + $rootScope.socketTip = "Live events: attempting to connect to the Tower server."; + } + else if (self.socket.readyState === 1){ + $rootScope.socketStatus = 'ok'; + $rootScope.socketTip = "Live events: connected. Pages containing job status information will automatically update in real-time."; + } + else if (self.socket.readyState === 2 || self.socket.readyState === 3 ){ + $rootScope.socketStatus = 'error'; + $rootScope.socketTip = "Live events: error connecting to the Tower server."; + } + return; + } + } + + }, + emit: function(data, callback) { + // Function used for sending objects to the API over the + // websocket. + var self = this; + $log.debug('Sent to Websocket Server: ' + data); + socketPromise.promise.then(function(){ + self.socket.send(data, function () { + var args = arguments; + self.scope.$apply(function () { + if (callback) { + callback.apply(self.socket, args); + } + }); + }); + }); + }, + addStateResolve: function(state, id){ + // This function is used for add a state resolve to all states, + // socket-enabled AND socket-disabled, and whether the $state + // requires a subscribe or an unsubscribe + self = this; + socketPromise.promise.then(function(){ + if(!state.socket){ + state.socket = {groups: {}}; + self.unsubscribe(state); + } + else{ + if(state.socket.groups.hasOwnProperty( "job_events")){ + state.socket.groups.job_events = [id]; + } + if(state.socket.groups.hasOwnProperty( "ad_hoc_command_events")){ + state.socket.groups.ad_hoc_command_events = [id]; + } + self.subscribe(state); + } + return true; + }); + } + }; + }]; diff --git a/awx/ui/client/src/shared/stateExtender.provider.js b/awx/ui/client/src/shared/stateExtender.provider.js index 89f6ff97ba..9c5bf0bfae 100644 --- a/awx/ui/client/src/shared/stateExtender.provider.js +++ b/awx/ui/client/src/shared/stateExtender.provider.js @@ -1,10 +1,24 @@ export default function($stateProvider) { this.$get = function() { return { + addSocket: function(state){ + // The login route has a 'null' socket because it should + // neither subscribe or unsubscribe + if(state.socket!==null){ + if(!state.resolve){ + state.resolve = {}; + } + state.resolve.socket = ['SocketService', '$stateParams', + function(SocketService, $stateParams) { + SocketService.addStateResolve(state, $stateParams.id); + } + ]; + } + }, addState: function(state) { var route = state.route || state.url; - + this.addSocket(state); $stateProvider.state(state.name, { url: route, controller: state.controller, diff --git a/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.route.js b/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.route.js index f878ef02f8..1b7d546231 100644 --- a/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.route.js +++ b/awx/ui/client/src/standard-out/adhoc/standard-out-adhoc.route.js @@ -11,25 +11,17 @@ export default { route: '/ad_hoc_commands/:id', templateUrl: templateUrl('standard-out/adhoc/standard-out-adhoc'), controller: 'JobStdoutController', + socket: { + "groups":{ + "jobs": ["status_changed"], + "ad_hoc_command_events": [] + } + }, ncyBreadcrumb: { parent: "jobs", label: "{{ job.module_name }}" }, data: { jobType: 'ad_hoc_commands' - }, - resolve: { - adhocEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { - if (!$rootScope.adhoc_event_socket) { - $rootScope.adhoc_event_socket = Socket({ - scope: $rootScope, - endpoint: "ad_hoc_command_events" - }); - $rootScope.adhoc_event_socket.init(); - return true; - } else { - return true; - } - }] } }; diff --git a/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.route.js b/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.route.js index e9bfe68f63..3cff062144 100644 --- a/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.route.js +++ b/awx/ui/client/src/standard-out/inventory-sync/standard-out-inventory-sync.route.js @@ -13,17 +13,16 @@ export default { route: '/inventory_sync/:id', templateUrl: templateUrl('standard-out/inventory-sync/standard-out-inventory-sync'), controller: 'JobStdoutController', + socket: { + "groups":{ + "jobs": ["status_changed"] + } + }, ncyBreadcrumb: { parent: "jobs", label: "{{ inventory_source_name }}" }, data: { jobType: 'inventory_updates' - }, - resolve: { - inventorySyncSocket: [function() { - // TODO: determine whether or not we have socket support for inventory sync standard out - return true; - }] } }; diff --git a/awx/ui/client/src/standard-out/log/standard-out-log.controller.js b/awx/ui/client/src/standard-out/log/standard-out-log.controller.js index 06e9cd7b64..45564fffc6 100644 --- a/awx/ui/client/src/standard-out/log/standard-out-log.controller.js +++ b/awx/ui/client/src/standard-out/log/standard-out-log.controller.js @@ -22,31 +22,21 @@ export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'Proce function openSockets() { if ($state.current.name === 'jobDetail') { $log.debug("socket watching on job_events-" + job_id); - $rootScope.event_socket.on("job_events-" + job_id, function() { + $scope.$on(`ws-job_events-${job_id}`, function() { $log.debug("socket fired on job_events-" + job_id); if (api_complete) { event_queue++; } }); - // Unbind $rootScope socket event binding(s) so that they don't get triggered - // in another instance of this controller - $scope.$on('$destroy', function() { - $rootScope.event_socket.removeAllListeners("job_events-" + job_id); - }); } if ($state.current.name === 'adHocJobStdout') { $log.debug("socket watching on ad_hoc_command_events-" + job_id); - $rootScope.adhoc_event_socket.on("ad_hoc_command_events-" + job_id, function() { + $scope.$on(`ws-ad_hoc_command_events-${job_id}`, function() { $log.debug("socket fired on ad_hoc_command_events-" + job_id); if (api_complete) { event_queue++; } }); - // Unbind $rootScope socket event binding(s) so that they don't get triggered - // in another instance of this controller - $scope.$on('$destroy', function() { - $rootScope.adhoc_event_socket.removeAllListeners("ad_hoc_command_events-" + job_id); - }); } } @@ -189,10 +179,7 @@ export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'Proce // We watch for job status changes here. If the job completes we want to clear out the // stdout interval and kill the live_event_processing flag. - if ($scope.removeJobStatusChange) { - $scope.removeJobStatusChange(); - } - $scope.removeJobStatusChange = $rootScope.$on('JobStatusChange-jobStdout', function(e, data) { + $scope.$on(`ws-jobs`, function(e, data) { if (parseInt(data.unified_job_id, 10) === parseInt(job_id,10)) { if (data.status === 'failed' || data.status === 'canceled' || data.status === 'error' || data.status === 'successful') { diff --git a/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.route.js b/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.route.js index d98a2bd1d4..c93cbd7a92 100644 --- a/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.route.js +++ b/awx/ui/client/src/standard-out/management-jobs/standard-out-management-jobs.route.js @@ -11,17 +11,16 @@ export default { route: '/management_jobs/:id', templateUrl: templateUrl('standard-out/management-jobs/standard-out-management-jobs'), controller: 'JobStdoutController', + socket: { + "groups":{ + "jobs": ["status_changed"] + } + }, ncyBreadcrumb: { parent: "jobs", label: "{{ job.name }}" }, data: { jobType: 'system_jobs' - }, - resolve: { - managementJobSocket: [function() { - // TODO: determine whether or not we have socket support for management job standard out - return true; - }] } }; diff --git a/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.route.js b/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.route.js index 9d399f05a9..d027050444 100644 --- a/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.route.js +++ b/awx/ui/client/src/standard-out/scm-update/standard-out-scm-update.route.js @@ -17,13 +17,12 @@ export default { parent: "jobs", label: "{{ project_name }}" }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } + }, data: { jobType: 'project_updates' - }, - resolve: { - scmUpdateSocket: [function() { - // TODO: determine whether or not we have socket support for scm update standard out - return true; - }] } }; diff --git a/awx/ui/client/src/standard-out/standard-out.controller.js b/awx/ui/client/src/standard-out/standard-out.controller.js index acdd5815a2..663d165cf3 100644 --- a/awx/ui/client/src/standard-out/standard-out.controller.js +++ b/awx/ui/client/src/standard-out/standard-out.controller.js @@ -25,10 +25,7 @@ export function JobStdoutController ($rootScope, $scope, $state, $stateParams, // Listen for job status updates that may come across via sockets. We need to check the payload // to see whethere the updated job is the one that we're currently looking at. - if ($scope.removeJobStatusChange) { - $scope.removeJobStatusChange(); - } - $scope.removeJobStatusChange = $rootScope.$on('JobStatusChange-jobStdout', function(e, data) { + $scope.$on(`ws-jobs`, function(e, data) { if (parseInt(data.unified_job_id, 10) === parseInt(job_id,10) && $scope.job) { $scope.job.status = data.status; } @@ -39,12 +36,6 @@ export function JobStdoutController ($rootScope, $scope, $state, $stateParams, } }); - // Unbind $rootScope socket event binding(s) so that they don't get triggered - // in another instance of this controller - $scope.$on('$destroy', function() { - $scope.removeJobStatusChange(); - }); - // Set the parse type so that CodeMirror knows how to display extra params YAML/JSON $scope.parseType = 'yaml'; diff --git a/awx/ui/npm-shrinkwrap.json b/awx/ui/npm-shrinkwrap.json deleted file mode 100644 index 376a395a52..0000000000 --- a/awx/ui/npm-shrinkwrap.json +++ /dev/null @@ -1,4865 +0,0 @@ -{ - "name": "ansible-tower", - "version": "3.1.0", - "dependencies": { - "abbrev": { - "version": "1.0.9", - "from": "abbrev@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" - }, - "accepts": { - "version": "1.3.3", - "from": "accepts@>=1.3.3 <1.4.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz" - }, - "acorn": { - "version": "3.3.0", - "from": "acorn@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz" - }, - "active-x-obfuscator": { - "version": "0.0.1", - "from": "active-x-obfuscator@0.0.1", - "resolved": "https://registry.npmjs.org/active-x-obfuscator/-/active-x-obfuscator-0.0.1.tgz" - }, - "adm-zip": { - "version": "0.4.7", - "from": "adm-zip@>=0.4.3 <0.5.0", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz" - }, - "after": { - "version": "0.8.1", - "from": "after@0.8.1", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.1.tgz" - }, - "agent-base": { - "version": "2.0.1", - "from": "agent-base@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz", - "dependencies": { - "semver": { - "version": "5.0.3", - "from": "semver@>=5.0.1 <5.1.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz" - } - } - }, - "align-text": { - "version": "0.1.4", - "from": "align-text@>=0.1.3 <0.2.0", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz" - }, - "almond": { - "version": "0.3.3", - "from": "almond@>=0.3.1 <0.4.0", - "resolved": "https://registry.npmjs.org/almond/-/almond-0.3.3.tgz" - }, - "amdefine": { - "version": "1.0.0", - "from": "amdefine@>=0.0.4", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" - }, - "angular": { - "version": "1.4.12", - "from": "angular@>=1.4.7 <1.5.0", - "resolved": "https://registry.npmjs.org/angular/-/angular-1.4.12.tgz" - }, - "angular-breadcrumb": { - "version": "0.4.1", - "from": "leigh-johnson/angular-breadcrumb#0.4.1", - "resolved": "git://github.com/leigh-johnson/angular-breadcrumb.git#6c2b1ad45ad5fbe7adf39af1ef3b294ca8e207a9" - }, - "angular-codemirror": { - "version": "1.0.4", - "from": "chouseknecht/angular-codemirror#1.0.4", - "resolved": "git://github.com/chouseknecht/angular-codemirror.git#75c3a2d0ccdf2e4c836fab7d7617d5db6c585c1b", - "dependencies": { - "angular": { - "version": "1.4.7", - "from": "angular@1.4.7", - "resolved": "https://registry.npmjs.org/angular/-/angular-1.4.7.tgz" - } - } - }, - "angular-cookies": { - "version": "1.5.8", - "from": "angular-cookies@>=1.4.3 <2.0.0", - "resolved": "https://registry.npmjs.org/angular-cookies/-/angular-cookies-1.5.8.tgz" - }, - "angular-drag-and-drop-lists": { - "version": "1.4.0", - "from": "leigh-johnson/angular-drag-and-drop-lists#1.4.0", - "resolved": "git://github.com/leigh-johnson/angular-drag-and-drop-lists.git#4d32654ab7159689a7767b9be8fc85f9812ca5a8" - }, - "angular-filters": { - "version": "1.1.2", - "from": "angular-filters@>=1.1.2 <2.0.0", - "resolved": "https://registry.npmjs.org/angular-filters/-/angular-filters-1.1.2.tgz" - }, - "angular-md5": { - "version": "0.1.10", - "from": "angular-md5@>=0.1.8 <0.2.0", - "resolved": "https://registry.npmjs.org/angular-md5/-/angular-md5-0.1.10.tgz" - }, - "angular-moment": { - "version": "0.10.3", - "from": "angular-moment@>=0.10.1 <0.11.0", - "resolved": "https://registry.npmjs.org/angular-moment/-/angular-moment-0.10.3.tgz", - "dependencies": { - "moment": { - "version": "2.10.6", - "from": "moment@>=2.8.0 <2.11.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.10.6.tgz" - } - } - }, - "angular-resource": { - "version": "1.5.8", - "from": "angular-resource@>=1.4.3 <2.0.0", - "resolved": "https://registry.npmjs.org/angular-resource/-/angular-resource-1.5.8.tgz" - }, - "angular-sanitize": { - "version": "1.5.8", - "from": "angular-sanitize@>=1.4.3 <2.0.0", - "resolved": "https://registry.npmjs.org/angular-sanitize/-/angular-sanitize-1.5.8.tgz" - }, - "angular-scheduler": { - "version": "0.1.0", - "from": "chouseknecht/angular-scheduler#0.1.0", - "resolved": "git://github.com/chouseknecht/angular-scheduler.git#784693054597b9a1c1e49efb4cf94e9054b92e66", - "dependencies": { - "angular-tz-extensions": { - "version": "0.3.11", - "from": "chouseknecht/angular-tz-extensions", - "resolved": "git://github.com/chouseknecht/angular-tz-extensions.git#a9b70c69ba27a19e1b1f9facbd85e870060aace9", - "dependencies": { - "angular": { - "version": "1.4.7", - "from": "angular@1.4.7", - "resolved": "https://registry.npmjs.org/angular/-/angular-1.4.7.tgz" - }, - "jquery": { - "version": "3.1.0", - "from": "jquery@>=3.1.0 <4.0.0", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.1.0.tgz" - } - } - }, - "lodash": { - "version": "3.8.0", - "from": "lodash@>=3.8.0 <3.9.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.8.0.tgz" - } - } - }, - "angular-tz-extensions": { - "version": "0.3.11", - "from": "chouseknecht/angular-tz-extensions#0.3.11", - "resolved": "git://github.com/chouseknecht/angular-tz-extensions.git#a9b70c69ba27a19e1b1f9facbd85e870060aace9", - "dependencies": { - "angular": { - "version": "1.4.7", - "from": "angular@1.4.7", - "resolved": "https://registry.npmjs.org/angular/-/angular-1.4.7.tgz" - }, - "jquery": { - "version": "3.1.0", - "from": "jquery@>=3.1.0 <4.0.0", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.1.0.tgz" - } - } - }, - "angular-ui-router": { - "version": "0.2.18", - "from": "angular-ui-router@>=0.2.15 <0.3.0", - "resolved": "https://registry.npmjs.org/angular-ui-router/-/angular-ui-router-0.2.18.tgz" - }, - "ansi-regex": { - "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" - }, - "ansi-styles": { - "version": "2.2.1", - "from": "ansi-styles@>=2.2.1 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" - }, - "anymatch": { - "version": "1.3.0", - "from": "anymatch@>=1.3.0 <2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz" - }, - "archiver": { - "version": "0.14.4", - "from": "archiver@>=0.14.0 <0.15.0", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-0.14.4.tgz", - "dependencies": { - "async": { - "version": "0.9.2", - "from": "async@>=0.9.0 <0.10.0", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz" - }, - "glob": { - "version": "4.3.5", - "from": "glob@>=4.3.0 <4.4.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.3.5.tgz" - }, - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "lodash": { - "version": "3.2.0", - "from": "lodash@>=3.2.0 <3.3.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.2.0.tgz" - }, - "minimatch": { - "version": "2.0.10", - "from": "minimatch@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz" - }, - "readable-stream": { - "version": "1.0.34", - "from": "readable-stream@>=1.0.26 <1.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz" - } - } - }, - "argparse": { - "version": "1.0.7", - "from": "argparse@>=1.0.7 <2.0.0", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.7.tgz" - }, - "arr-diff": { - "version": "2.0.0", - "from": "arr-diff@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz" - }, - "arr-flatten": { - "version": "1.0.1", - "from": "arr-flatten@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz" - }, - "array-differ": { - "version": "1.0.0", - "from": "array-differ@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz" - }, - "array-find-index": { - "version": "1.0.1", - "from": "array-find-index@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.1.tgz" - }, - "array-flatten": { - "version": "1.1.1", - "from": "array-flatten@1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" - }, - "array-slice": { - "version": "0.2.3", - "from": "array-slice@>=0.2.3 <0.3.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz" - }, - "array-union": { - "version": "1.0.2", - "from": "array-union@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz" - }, - "array-uniq": { - "version": "1.0.3", - "from": "array-uniq@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" - }, - "array-unique": { - "version": "0.2.1", - "from": "array-unique@>=0.2.1 <0.3.0", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz" - }, - "arraybuffer.slice": { - "version": "0.0.6", - "from": "arraybuffer.slice@0.0.6", - "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz" - }, - "arrify": { - "version": "1.0.1", - "from": "arrify@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" - }, - "asap": { - "version": "2.0.4", - "from": "asap@>=2.0.3 <2.1.0", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.4.tgz" - }, - "asn1": { - "version": "0.2.3", - "from": "asn1@>=0.2.3 <0.3.0", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz" - }, - "assert": { - "version": "1.4.1", - "from": "assert@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz" - }, - "assert-plus": { - "version": "0.2.0", - "from": "assert-plus@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz" - }, - "async": { - "version": "1.5.2", - "from": "async@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz" - }, - "async-each": { - "version": "1.0.1", - "from": "async-each@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz" - }, - "async-each-series": { - "version": "0.1.1", - "from": "async-each-series@0.1.1", - "resolved": "https://registry.npmjs.org/async-each-series/-/async-each-series-0.1.1.tgz" - }, - "asynckit": { - "version": "0.4.0", - "from": "asynckit@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" - }, - "autoprefixer": { - "version": "6.4.1", - "from": "autoprefixer@>=6.0.0 <7.0.0", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.4.1.tgz" - }, - "aws-sign2": { - "version": "0.6.0", - "from": "aws-sign2@>=0.6.0 <0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz" - }, - "aws4": { - "version": "1.4.1", - "from": "aws4@>=1.2.1 <2.0.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.4.1.tgz" - }, - "babel-code-frame": { - "version": "6.11.0", - "from": "babel-code-frame@>=6.8.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.11.0.tgz" - }, - "babel-core": { - "version": "6.14.0", - "from": "babel-core@>=6.11.4 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.14.0.tgz", - "dependencies": { - "json5": { - "version": "0.4.0", - "from": "json5@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz" - }, - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.2.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz" - }, - "source-map": { - "version": "0.5.6", - "from": "source-map@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz" - } - } - }, - "babel-generator": { - "version": "6.14.0", - "from": "babel-generator@>=6.14.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.14.0.tgz", - "dependencies": { - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.2.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz" - }, - "source-map": { - "version": "0.5.6", - "from": "source-map@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz" - } - } - }, - "babel-helper-call-delegate": { - "version": "6.8.0", - "from": "babel-helper-call-delegate@>=6.8.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.8.0.tgz" - }, - "babel-helper-define-map": { - "version": "6.9.0", - "from": "babel-helper-define-map@>=6.9.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.9.0.tgz", - "dependencies": { - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.2.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz" - } - } - }, - "babel-helper-function-name": { - "version": "6.8.0", - "from": "babel-helper-function-name@>=6.8.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.8.0.tgz" - }, - "babel-helper-get-function-arity": { - "version": "6.8.0", - "from": "babel-helper-get-function-arity@>=6.8.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.8.0.tgz" - }, - "babel-helper-hoist-variables": { - "version": "6.8.0", - "from": "babel-helper-hoist-variables@>=6.8.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.8.0.tgz" - }, - "babel-helper-optimise-call-expression": { - "version": "6.8.0", - "from": "babel-helper-optimise-call-expression@>=6.8.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.8.0.tgz" - }, - "babel-helper-regex": { - "version": "6.9.0", - "from": "babel-helper-regex@>=6.8.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.9.0.tgz", - "dependencies": { - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.2.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz" - } - } - }, - "babel-helper-replace-supers": { - "version": "6.14.0", - "from": "babel-helper-replace-supers@>=6.14.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.14.0.tgz" - }, - "babel-helpers": { - "version": "6.8.0", - "from": "babel-helpers@>=6.8.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.8.0.tgz" - }, - "babel-messages": { - "version": "6.8.0", - "from": "babel-messages@>=6.8.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.8.0.tgz" - }, - "babel-plugin-check-es2015-constants": { - "version": "6.8.0", - "from": "babel-plugin-check-es2015-constants@>=6.3.13 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.8.0.tgz" - }, - "babel-plugin-syntax-async-functions": { - "version": "6.13.0", - "from": "babel-plugin-syntax-async-functions@>=6.8.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz" - }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.8.0", - "from": "babel-plugin-transform-es2015-arrow-functions@>=6.3.13 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.8.0.tgz" - }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.8.0", - "from": "babel-plugin-transform-es2015-block-scoped-functions@>=6.3.13 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.8.0.tgz" - }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.15.0", - "from": "babel-plugin-transform-es2015-block-scoping@>=6.14.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.15.0.tgz", - "dependencies": { - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.2.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz" - } - } - }, - "babel-plugin-transform-es2015-classes": { - "version": "6.14.0", - "from": "babel-plugin-transform-es2015-classes@>=6.14.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.14.0.tgz" - }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.8.0", - "from": "babel-plugin-transform-es2015-computed-properties@>=6.3.13 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.8.0.tgz" - }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.9.0", - "from": "babel-plugin-transform-es2015-destructuring@>=6.9.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.9.0.tgz" - }, - "babel-plugin-transform-es2015-duplicate-keys": { - "version": "6.8.0", - "from": "babel-plugin-transform-es2015-duplicate-keys@>=6.6.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.8.0.tgz" - }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.8.0", - "from": "babel-plugin-transform-es2015-for-of@>=6.6.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.8.0.tgz" - }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.9.0", - "from": "babel-plugin-transform-es2015-function-name@>=6.9.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.9.0.tgz" - }, - "babel-plugin-transform-es2015-literals": { - "version": "6.8.0", - "from": "babel-plugin-transform-es2015-literals@>=6.3.13 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.8.0.tgz" - }, - "babel-plugin-transform-es2015-modules-amd": { - "version": "6.8.0", - "from": "babel-plugin-transform-es2015-modules-amd@>=6.8.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.8.0.tgz" - }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.14.0", - "from": "babel-plugin-transform-es2015-modules-commonjs@>=6.14.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.14.0.tgz" - }, - "babel-plugin-transform-es2015-modules-systemjs": { - "version": "6.14.0", - "from": "babel-plugin-transform-es2015-modules-systemjs@>=6.14.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.14.0.tgz" - }, - "babel-plugin-transform-es2015-modules-umd": { - "version": "6.12.0", - "from": "babel-plugin-transform-es2015-modules-umd@>=6.12.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.12.0.tgz" - }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.8.0", - "from": "babel-plugin-transform-es2015-object-super@>=6.3.13 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.8.0.tgz" - }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.11.4", - "from": "babel-plugin-transform-es2015-parameters@>=6.9.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.11.4.tgz" - }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.8.0", - "from": "babel-plugin-transform-es2015-shorthand-properties@>=6.3.13 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.8.0.tgz" - }, - "babel-plugin-transform-es2015-spread": { - "version": "6.8.0", - "from": "babel-plugin-transform-es2015-spread@>=6.3.13 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.8.0.tgz" - }, - "babel-plugin-transform-es2015-sticky-regex": { - "version": "6.8.0", - "from": "babel-plugin-transform-es2015-sticky-regex@>=6.3.13 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.8.0.tgz" - }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.8.0", - "from": "babel-plugin-transform-es2015-template-literals@>=6.6.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.8.0.tgz" - }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.8.0", - "from": "babel-plugin-transform-es2015-typeof-symbol@>=6.6.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.8.0.tgz" - }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.11.0", - "from": "babel-plugin-transform-es2015-unicode-regex@>=6.3.13 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.11.0.tgz" - }, - "babel-plugin-transform-regenerator": { - "version": "6.14.0", - "from": "babel-plugin-transform-regenerator@>=6.14.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.14.0.tgz" - }, - "babel-plugin-transform-strict-mode": { - "version": "6.11.3", - "from": "babel-plugin-transform-strict-mode@>=6.8.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.11.3.tgz" - }, - "babel-register": { - "version": "6.14.0", - "from": "babel-register@>=6.14.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.14.0.tgz", - "dependencies": { - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.2.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz" - } - } - }, - "babel-runtime": { - "version": "6.11.6", - "from": "babel-runtime@>=6.9.1 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.11.6.tgz" - }, - "babel-template": { - "version": "6.15.0", - "from": "babel-template@>=6.14.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.15.0.tgz", - "dependencies": { - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.2.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz" - } - } - }, - "babel-traverse": { - "version": "6.15.0", - "from": "babel-traverse@>=6.14.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.15.0.tgz", - "dependencies": { - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.2.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz" - } - } - }, - "babel-types": { - "version": "6.15.0", - "from": "babel-types@>=6.14.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.15.0.tgz", - "dependencies": { - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.2.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz" - } - } - }, - "babylon": { - "version": "6.10.0", - "from": "babylon@>=6.9.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.10.0.tgz" - }, - "backo2": { - "version": "1.0.2", - "from": "backo2@1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz" - }, - "balanced-match": { - "version": "0.4.2", - "from": "balanced-match@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz" - }, - "Base64": { - "version": "0.2.1", - "from": "Base64@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/Base64/-/Base64-0.2.1.tgz" - }, - "base64-arraybuffer": { - "version": "0.1.2", - "from": "base64-arraybuffer@0.1.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.2.tgz" - }, - "base64-js": { - "version": "1.1.2", - "from": "base64-js@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.1.2.tgz" - }, - "base64id": { - "version": "0.1.0", - "from": "base64id@0.1.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz" - }, - "batch": { - "version": "0.5.3", - "from": "batch@0.5.3", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.5.3.tgz" - }, - "bcrypt-pbkdf": { - "version": "1.0.0", - "from": "bcrypt-pbkdf@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz", - "dependencies": { - "tweetnacl": { - "version": "0.14.3", - "from": "tweetnacl@>=0.14.3 <0.15.0", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.3.tgz" - } - } - }, - "beeper": { - "version": "1.1.0", - "from": "beeper@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.0.tgz" - }, - "benchmark": { - "version": "1.0.0", - "from": "benchmark@1.0.0", - "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-1.0.0.tgz" - }, - "better-assert": { - "version": "1.0.2", - "from": "better-assert@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz" - }, - "big.js": { - "version": "3.1.3", - "from": "big.js@>=3.1.3 <4.0.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz" - }, - "binary-extensions": { - "version": "1.6.0", - "from": "binary-extensions@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.6.0.tgz" - }, - "bindings": { - "version": "1.2.1", - "from": "bindings@>=1.2.1 <2.0.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz" - }, - "bl": { - "version": "1.1.2", - "from": "bl@>=1.1.2 <1.2.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz" - }, - "blob": { - "version": "0.0.4", - "from": "blob@0.0.4", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz" - }, - "bluebird": { - "version": "3.4.6", - "from": "bluebird@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.6.tgz" - }, - "body-parser": { - "version": "1.14.2", - "from": "body-parser@>=1.14.0 <1.15.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.14.2.tgz", - "dependencies": { - "http-errors": { - "version": "1.3.1", - "from": "http-errors@>=1.3.1 <1.4.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz" - }, - "qs": { - "version": "5.2.0", - "from": "qs@5.2.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz" - } - } - }, - "boom": { - "version": "2.10.1", - "from": "boom@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz" - }, - "bootstrap": { - "version": "3.3.7", - "from": "bootstrap@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.3.7.tgz" - }, - "bootstrap-datepicker": { - "version": "1.6.4", - "from": "bootstrap-datepicker@>=1.4.0 <2.0.0", - "resolved": "https://registry.npmjs.org/bootstrap-datepicker/-/bootstrap-datepicker-1.6.4.tgz" - }, - "brace-expansion": { - "version": "1.1.6", - "from": "brace-expansion@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz" - }, - "braces": { - "version": "1.8.5", - "from": "braces@>=1.8.2 <2.0.0", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz" - }, - "browser-sync": { - "version": "2.16.0", - "from": "browser-sync@>=2.14.0 <3.0.0", - "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.16.0.tgz", - "dependencies": { - "cliui": { - "version": "3.2.0", - "from": "cliui@>=3.2.0 <4.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz" - }, - "window-size": { - "version": "0.2.0", - "from": "window-size@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz" - }, - "yargs": { - "version": "5.0.0", - "from": "yargs@5.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz" - } - } - }, - "browser-sync-client": { - "version": "2.4.2", - "from": "browser-sync-client@>=2.3.3 <3.0.0", - "resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.4.2.tgz" - }, - "browser-sync-ui": { - "version": "0.6.1", - "from": "browser-sync-ui@0.6.1", - "resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-0.6.1.tgz" - }, - "browserify-zlib": { - "version": "0.1.4", - "from": "browserify-zlib@>=0.1.4 <0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz" - }, - "browserslist": { - "version": "1.3.6", - "from": "browserslist@>=1.3.6 <1.4.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.3.6.tgz" - }, - "bs-recipes": { - "version": "1.2.3", - "from": "bs-recipes@1.2.3", - "resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.2.3.tgz" - }, - "buffer": { - "version": "4.9.1", - "from": "buffer@>=4.9.0 <5.0.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz" - }, - "buffer-crc32": { - "version": "0.2.5", - "from": "buffer-crc32@>=0.2.1 <0.3.0", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.5.tgz" - }, - "builtin-modules": { - "version": "1.1.1", - "from": "builtin-modules@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz" - }, - "bytes": { - "version": "2.2.0", - "from": "bytes@2.2.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.2.0.tgz" - }, - "callsite": { - "version": "1.0.0", - "from": "callsite@1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz" - }, - "camelcase": { - "version": "1.2.1", - "from": "camelcase@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" - }, - "camelcase-keys": { - "version": "2.1.0", - "from": "camelcase-keys@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "dependencies": { - "camelcase": { - "version": "2.1.1", - "from": "camelcase@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz" - } - } - }, - "caniuse-db": { - "version": "1.0.30000539", - "from": "caniuse-db@>=1.0.30000527 <2.0.0", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000539.tgz" - }, - "caseless": { - "version": "0.11.0", - "from": "caseless@>=0.11.0 <0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz" - }, - "center-align": { - "version": "0.1.3", - "from": "center-align@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz" - }, - "chalk": { - "version": "1.1.3", - "from": "chalk@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz" - }, - "chokidar": { - "version": "1.6.0", - "from": "chokidar@1.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.6.0.tgz" - }, - "cli": { - "version": "1.0.0", - "from": "cli@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.0.tgz", - "dependencies": { - "glob": { - "version": "7.1.0", - "from": "glob@>=7.0.5 <8.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.0.tgz" - } - } - }, - "cli-width": { - "version": "1.1.1", - "from": "cli-width@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz" - }, - "cliui": { - "version": "2.1.0", - "from": "cliui@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "dependencies": { - "wordwrap": { - "version": "0.0.2", - "from": "wordwrap@0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" - } - } - }, - "clone": { - "version": "1.0.2", - "from": "clone@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz" - }, - "code-point-at": { - "version": "1.0.0", - "from": "code-point-at@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.0.0.tgz" - }, - "codemirror": { - "version": "5.19.0", - "from": "codemirror@>=5.17.0 <6.0.0", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.19.0.tgz" - }, - "coffee-script": { - "version": "1.10.0", - "from": "coffee-script@>=1.10.0 <1.11.0", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz" - }, - "colors": { - "version": "1.1.2", - "from": "colors@>=1.1.2 <1.2.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz" - }, - "combine-lists": { - "version": "1.0.1", - "from": "combine-lists@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", - "dependencies": { - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.5.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz" - } - } - }, - "combined-stream": { - "version": "1.0.5", - "from": "combined-stream@>=1.0.5 <1.1.0", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz" - }, - "commander": { - "version": "2.9.0", - "from": "commander@>=2.9.0 <3.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz" - }, - "component-bind": { - "version": "1.0.0", - "from": "component-bind@1.0.0", - "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz" - }, - "component-emitter": { - "version": "1.1.2", - "from": "component-emitter@1.1.2", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz" - }, - "component-inherit": { - "version": "0.0.3", - "from": "component-inherit@0.0.3", - "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz" - }, - "components-font-awesome": { - "version": "4.6.1", - "from": "components-font-awesome@>=4.6.1 <5.0.0", - "resolved": "https://registry.npmjs.org/components-font-awesome/-/components-font-awesome-4.6.1.tgz" - }, - "compress-commons": { - "version": "0.2.9", - "from": "compress-commons@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-0.2.9.tgz", - "dependencies": { - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "readable-stream": { - "version": "1.0.34", - "from": "readable-stream@>=1.0.26 <1.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz" - } - } - }, - "compressible": { - "version": "2.0.8", - "from": "compressible@>=2.0.8 <2.1.0", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.8.tgz" - }, - "compression": { - "version": "1.6.2", - "from": "compression@>=1.5.2 <2.0.0", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.6.2.tgz", - "dependencies": { - "bytes": { - "version": "2.3.0", - "from": "bytes@2.3.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.3.0.tgz" - } - } - }, - "concat-map": { - "version": "0.0.1", - "from": "concat-map@0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - }, - "concat-stream": { - "version": "1.5.0", - "from": "concat-stream@1.5.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz" - }, - "connect": { - "version": "3.4.1", - "from": "connect@3.4.1", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.4.1.tgz" - }, - "connect-history-api-fallback": { - "version": "1.3.0", - "from": "connect-history-api-fallback@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz" - }, - "console-browserify": { - "version": "1.1.0", - "from": "console-browserify@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz" - }, - "constants-browserify": { - "version": "0.0.1", - "from": "constants-browserify@0.0.1", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-0.0.1.tgz" - }, - "content-disposition": { - "version": "0.5.1", - "from": "content-disposition@0.5.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.1.tgz" - }, - "content-type": { - "version": "1.0.2", - "from": "content-type@>=1.0.1 <1.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz" - }, - "contextify": { - "version": "0.1.15", - "from": "contextify@>=0.1.5 <0.2.0", - "resolved": "https://registry.npmjs.org/contextify/-/contextify-0.1.15.tgz" - }, - "convert-source-map": { - "version": "1.3.0", - "from": "convert-source-map@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.3.0.tgz" - }, - "cookie": { - "version": "0.3.1", - "from": "cookie@0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz" - }, - "cookie-signature": { - "version": "1.0.6", - "from": "cookie-signature@1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" - }, - "core-js": { - "version": "2.4.1", - "from": "core-js@>=2.4.0 <3.0.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz" - }, - "core-util-is": { - "version": "1.0.2", - "from": "core-util-is@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" - }, - "crc32-stream": { - "version": "0.3.4", - "from": "crc32-stream@>=0.3.1 <0.4.0", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-0.3.4.tgz", - "dependencies": { - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "readable-stream": { - "version": "1.0.34", - "from": "readable-stream@>=1.0.24 <1.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz" - } - } - }, - "cryptiles": { - "version": "2.0.5", - "from": "cryptiles@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz" - }, - "crypto-browserify": { - "version": "3.2.8", - "from": "crypto-browserify@>=3.2.6 <3.3.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.2.8.tgz" - }, - "cson-parser": { - "version": "1.3.3", - "from": "cson-parser@>=1.0.9 <2.0.0", - "resolved": "https://registry.npmjs.org/cson-parser/-/cson-parser-1.3.3.tgz" - }, - "cssom": { - "version": "0.2.5", - "from": "cssom@>=0.2.5 <0.3.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.2.5.tgz" - }, - "cssstyle": { - "version": "0.2.37", - "from": "cssstyle@>=0.2.3 <0.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", - "dependencies": { - "cssom": { - "version": "0.3.1", - "from": "cssom@>=0.3.0 <0.4.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.1.tgz" - } - } - }, - "ctype": { - "version": "0.5.3", - "from": "ctype@0.5.3", - "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz" - }, - "currently-unhandled": { - "version": "0.4.1", - "from": "currently-unhandled@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz" - }, - "custom-event": { - "version": "1.0.0", - "from": "custom-event@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.0.tgz" - }, - "d3": { - "version": "3.5.17", - "from": "d3@>=3.3.13 <4.0.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz" - }, - "dashdash": { - "version": "1.14.0", - "from": "dashdash@>=1.12.0 <2.0.0", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.0.tgz", - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "from": "assert-plus@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" - } - } - }, - "date-now": { - "version": "0.1.4", - "from": "date-now@>=0.1.4 <0.2.0", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz" - }, - "date-time": { - "version": "1.1.0", - "from": "date-time@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/date-time/-/date-time-1.1.0.tgz" - }, - "dateformat": { - "version": "1.0.12", - "from": "dateformat@>=1.0.12 <1.1.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz" - }, - "debug": { - "version": "2.2.0", - "from": "debug@>=2.1.1 <3.0.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz" - }, - "decamelize": { - "version": "1.2.0", - "from": "decamelize@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" - }, - "deep-is": { - "version": "0.1.3", - "from": "deep-is@>=0.1.3 <0.2.0", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" - }, - "delayed-stream": { - "version": "1.0.0", - "from": "delayed-stream@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" - }, - "depd": { - "version": "1.1.0", - "from": "depd@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz" - }, - "destroy": { - "version": "1.0.4", - "from": "destroy@>=1.0.4 <1.1.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz" - }, - "detect-indent": { - "version": "3.0.1", - "from": "detect-indent@>=3.0.1 <4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz" - }, - "dev-ip": { - "version": "1.0.1", - "from": "dev-ip@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/dev-ip/-/dev-ip-1.0.1.tgz" - }, - "di": { - "version": "0.0.1", - "from": "di@>=0.0.1 <0.0.2", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz" - }, - "dom-serialize": { - "version": "2.2.1", - "from": "dom-serialize@>=2.2.0 <3.0.0", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz" - }, - "dom-serializer": { - "version": "0.1.0", - "from": "dom-serializer@>=0.0.0 <1.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", - "dependencies": { - "domelementtype": { - "version": "1.1.3", - "from": "domelementtype@>=1.1.1 <1.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz" - }, - "entities": { - "version": "1.1.1", - "from": "entities@>=1.1.1 <1.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz" - } - } - }, - "domain-browser": { - "version": "1.1.7", - "from": "domain-browser@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz" - }, - "domelementtype": { - "version": "1.3.0", - "from": "domelementtype@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz" - }, - "domhandler": { - "version": "2.3.0", - "from": "domhandler@>=2.3.0 <2.4.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz" - }, - "domutils": { - "version": "1.5.1", - "from": "domutils@>=1.5.0 <1.6.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz" - }, - "duplexify": { - "version": "3.4.5", - "from": "duplexify@>=3.1.2 <4.0.0", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.4.5.tgz" - }, - "easy-extender": { - "version": "2.3.2", - "from": "easy-extender@2.3.2", - "resolved": "https://registry.npmjs.org/easy-extender/-/easy-extender-2.3.2.tgz" - }, - "eazy-logger": { - "version": "3.0.2", - "from": "eazy-logger@3.0.2", - "resolved": "https://registry.npmjs.org/eazy-logger/-/eazy-logger-3.0.2.tgz" - }, - "ecc-jsbn": { - "version": "0.1.1", - "from": "ecc-jsbn@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz" - }, - "ee-first": { - "version": "1.1.1", - "from": "ee-first@1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" - }, - "emitter-steward": { - "version": "1.0.0", - "from": "emitter-steward@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/emitter-steward/-/emitter-steward-1.0.0.tgz" - }, - "emojis-list": { - "version": "2.0.1", - "from": "emojis-list@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.0.1.tgz" - }, - "encodeurl": { - "version": "1.0.1", - "from": "encodeurl@>=1.0.1 <1.1.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz" - }, - "end-of-stream": { - "version": "1.0.0", - "from": "end-of-stream@1.0.0", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz", - "dependencies": { - "once": { - "version": "1.3.3", - "from": "once@>=1.3.0 <1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz" - } - } - }, - "engine.io": { - "version": "1.6.11", - "from": "engine.io@1.6.11", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.6.11.tgz", - "dependencies": { - "accepts": { - "version": "1.1.4", - "from": "accepts@1.1.4", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.1.4.tgz" - }, - "mime-db": { - "version": "1.12.0", - "from": "mime-db@>=1.12.0 <1.13.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.12.0.tgz" - }, - "mime-types": { - "version": "2.0.14", - "from": "mime-types@>=2.0.4 <2.1.0", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.14.tgz" - }, - "negotiator": { - "version": "0.4.9", - "from": "negotiator@0.4.9", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.4.9.tgz" - }, - "ws": { - "version": "1.1.0", - "from": "ws@1.1.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.0.tgz" - } - } - }, - "engine.io-client": { - "version": "1.6.11", - "from": "engine.io-client@1.6.11", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.6.11.tgz", - "dependencies": { - "ws": { - "version": "1.0.1", - "from": "ws@1.0.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.0.1.tgz" - } - } - }, - "engine.io-parser": { - "version": "1.2.4", - "from": "engine.io-parser@1.2.4", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.2.4.tgz", - "dependencies": { - "has-binary": { - "version": "0.1.6", - "from": "has-binary@0.1.6", - "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz" - }, - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - } - } - }, - "enhanced-resolve": { - "version": "0.9.1", - "from": "enhanced-resolve@>=0.9.0 <0.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz", - "dependencies": { - "memory-fs": { - "version": "0.2.0", - "from": "memory-fs@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz" - } - } - }, - "ent": { - "version": "2.2.0", - "from": "ent@>=2.2.0 <2.3.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz" - }, - "entities": { - "version": "1.0.0", - "from": "entities@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz" - }, - "errno": { - "version": "0.1.4", - "from": "errno@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz" - }, - "error-ex": { - "version": "1.3.0", - "from": "error-ex@>=1.2.0 <2.0.0", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz" - }, - "es6-promise": { - "version": "3.2.1", - "from": "es6-promise@>=3.2.1 <3.3.0", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz" - }, - "escape-html": { - "version": "1.0.3", - "from": "escape-html@>=1.0.3 <1.1.0", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" - }, - "escape-string-regexp": { - "version": "1.0.5", - "from": "escape-string-regexp@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - }, - "escodegen": { - "version": "1.8.1", - "from": "escodegen@>=1.8.0 <1.9.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "dependencies": { - "source-map": { - "version": "0.2.0", - "from": "source-map@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz" - } - } - }, - "esprima": { - "version": "2.7.3", - "from": "esprima@>=2.6.0 <3.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz" - }, - "estraverse": { - "version": "1.9.3", - "from": "estraverse@>=1.9.1 <2.0.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz" - }, - "esutils": { - "version": "2.0.2", - "from": "esutils@>=2.0.2 <3.0.0", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz" - }, - "etag": { - "version": "1.7.0", - "from": "etag@>=1.7.0 <2.0.0", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz" - }, - "eventemitter2": { - "version": "0.4.14", - "from": "eventemitter2@>=0.4.13 <0.5.0", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz" - }, - "eventemitter3": { - "version": "1.2.0", - "from": "eventemitter3@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz" - }, - "events": { - "version": "1.1.1", - "from": "events@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz" - }, - "eventsource": { - "version": "0.1.6", - "from": "eventsource@>=0.1.6 <0.2.0", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz" - }, - "exit": { - "version": "0.1.2", - "from": "exit@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" - }, - "expand-braces": { - "version": "0.1.2", - "from": "expand-braces@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", - "dependencies": { - "braces": { - "version": "0.1.5", - "from": "braces@>=0.1.2 <0.2.0", - "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz" - }, - "expand-range": { - "version": "0.1.1", - "from": "expand-range@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz" - }, - "is-number": { - "version": "0.1.1", - "from": "is-number@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz" - }, - "repeat-string": { - "version": "0.2.2", - "from": "repeat-string@>=0.2.2 <0.3.0", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz" - } - } - }, - "expand-brackets": { - "version": "0.1.5", - "from": "expand-brackets@>=0.1.4 <0.2.0", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz" - }, - "expand-range": { - "version": "1.8.2", - "from": "expand-range@>=1.8.1 <2.0.0", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz" - }, - "express": { - "version": "2.5.11", - "from": "express@>=2.5.0 <2.6.0", - "resolved": "https://registry.npmjs.org/express/-/express-2.5.11.tgz", - "dependencies": { - "connect": { - "version": "1.9.2", - "from": "connect@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-1.9.2.tgz" - }, - "mkdirp": { - "version": "0.3.0", - "from": "mkdirp@0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz" - }, - "qs": { - "version": "0.4.2", - "from": "qs@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-0.4.2.tgz" - } - } - }, - "extend": { - "version": "3.0.0", - "from": "extend@>=3.0.0 <3.1.0", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz" - }, - "extglob": { - "version": "0.3.2", - "from": "extglob@>=0.3.1 <0.4.0", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz" - }, - "extract-zip": { - "version": "1.5.0", - "from": "extract-zip@>=1.5.0 <1.6.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz", - "dependencies": { - "debug": { - "version": "0.7.4", - "from": "debug@0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz" - }, - "minimist": { - "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" - }, - "mkdirp": { - "version": "0.5.0", - "from": "mkdirp@0.5.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz" - } - } - }, - "extsprintf": { - "version": "1.0.2", - "from": "extsprintf@1.0.2", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz" - }, - "fast-levenshtein": { - "version": "2.0.4", - "from": "fast-levenshtein@>=2.0.4 <2.1.0", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.4.tgz" - }, - "faye-websocket": { - "version": "0.10.0", - "from": "faye-websocket@>=0.10.0 <0.11.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz" - }, - "fd-slicer": { - "version": "1.0.1", - "from": "fd-slicer@>=1.0.1 <1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz" - }, - "figures": { - "version": "1.7.0", - "from": "figures@>=1.3.5 <2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz" - }, - "file-sync-cmp": { - "version": "0.1.1", - "from": "file-sync-cmp@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz" - }, - "filename-regex": { - "version": "2.0.0", - "from": "filename-regex@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz" - }, - "fileset": { - "version": "0.2.1", - "from": "fileset@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz", - "dependencies": { - "minimatch": { - "version": "2.0.10", - "from": "minimatch@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz" - } - } - }, - "fill-range": { - "version": "2.2.3", - "from": "fill-range@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz" - }, - "finalhandler": { - "version": "0.4.1", - "from": "finalhandler@0.4.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.1.tgz" - }, - "find-up": { - "version": "1.1.2", - "from": "find-up@>=1.1.2 <2.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "dependencies": { - "path-exists": { - "version": "2.1.0", - "from": "path-exists@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz" - } - } - }, - "findup-sync": { - "version": "0.3.0", - "from": "findup-sync@>=0.3.0 <0.4.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz" - }, - "for-in": { - "version": "0.1.6", - "from": "for-in@>=0.1.5 <0.2.0", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.6.tgz" - }, - "for-own": { - "version": "0.1.4", - "from": "for-own@>=0.1.3 <0.2.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.4.tgz" - }, - "forever-agent": { - "version": "0.6.1", - "from": "forever-agent@>=0.6.1 <0.7.0", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" - }, - "form-data": { - "version": "2.0.0", - "from": "form-data@>=2.0.0 <2.1.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz" - }, - "formidable": { - "version": "1.0.17", - "from": "formidable@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.17.tgz" - }, - "forwarded": { - "version": "0.1.0", - "from": "forwarded@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz" - }, - "fresh": { - "version": "0.3.0", - "from": "fresh@>=0.3.0 <0.4.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz" - }, - "fs": { - "version": "0.0.2", - "from": "fs@0.0.2", - "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.2.tgz" - }, - "fs-access": { - "version": "1.0.0", - "from": "fs-access@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.0.tgz" - }, - "fs-extra": { - "version": "0.30.0", - "from": "fs-extra@0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz" - }, - "fs.realpath": { - "version": "1.0.0", - "from": "fs.realpath@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - }, - "fsevents": { - "version": "1.0.14", - "from": "fsevents@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.0.14.tgz", - "dependencies": { - "abbrev": { - "version": "1.0.9", - "from": "abbrev@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" - }, - "ansi-regex": { - "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" - }, - "ansi-styles": { - "version": "2.2.1", - "from": "ansi-styles@>=2.2.1 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" - }, - "aproba": { - "version": "1.0.4", - "from": "aproba@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.0.4.tgz" - }, - "are-we-there-yet": { - "version": "1.1.2", - "from": "are-we-there-yet@>=1.1.2 <1.2.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz" - }, - "asn1": { - "version": "0.2.3", - "from": "asn1@>=0.2.3 <0.3.0", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz" - }, - "assert-plus": { - "version": "0.2.0", - "from": "assert-plus@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz" - }, - "async": { - "version": "1.5.2", - "from": "async@>=1.5.2 <2.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz" - }, - "aws-sign2": { - "version": "0.6.0", - "from": "aws-sign2@>=0.6.0 <0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz" - }, - "aws4": { - "version": "1.4.1", - "from": "aws4@>=1.2.1 <2.0.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.4.1.tgz" - }, - "balanced-match": { - "version": "0.4.2", - "from": "balanced-match@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz" - }, - "bl": { - "version": "1.1.2", - "from": "bl@>=1.1.2 <1.2.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", - "dependencies": { - "readable-stream": { - "version": "2.0.6", - "from": "readable-stream@>=2.0.5 <2.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz" - } - } - }, - "block-stream": { - "version": "0.0.9", - "from": "block-stream@*", - "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz" - }, - "boom": { - "version": "2.10.1", - "from": "boom@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz" - }, - "brace-expansion": { - "version": "1.1.5", - "from": "brace-expansion@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz" - }, - "buffer-shims": { - "version": "1.0.0", - "from": "buffer-shims@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz" - }, - "caseless": { - "version": "0.11.0", - "from": "caseless@>=0.11.0 <0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz" - }, - "chalk": { - "version": "1.1.3", - "from": "chalk@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz" - }, - "code-point-at": { - "version": "1.0.0", - "from": "code-point-at@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.0.0.tgz" - }, - "combined-stream": { - "version": "1.0.5", - "from": "combined-stream@>=1.0.5 <1.1.0", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz" - }, - "commander": { - "version": "2.9.0", - "from": "commander@>=2.9.0 <3.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz" - }, - "concat-map": { - "version": "0.0.1", - "from": "concat-map@0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - }, - "console-control-strings": { - "version": "1.1.0", - "from": "console-control-strings@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" - }, - "core-util-is": { - "version": "1.0.2", - "from": "core-util-is@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" - }, - "cryptiles": { - "version": "2.0.5", - "from": "cryptiles@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz" - }, - "dashdash": { - "version": "1.14.0", - "from": "dashdash@>=1.12.0 <2.0.0", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.0.tgz", - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "from": "assert-plus@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" - } - } - }, - "debug": { - "version": "2.2.0", - "from": "debug@>=2.2.0 <2.3.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz" - }, - "deep-extend": { - "version": "0.4.1", - "from": "deep-extend@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.1.tgz" - }, - "delayed-stream": { - "version": "1.0.0", - "from": "delayed-stream@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" - }, - "delegates": { - "version": "1.0.0", - "from": "delegates@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" - }, - "ecc-jsbn": { - "version": "0.1.1", - "from": "ecc-jsbn@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz" - }, - "escape-string-regexp": { - "version": "1.0.5", - "from": "escape-string-regexp@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - }, - "extend": { - "version": "3.0.0", - "from": "extend@>=3.0.0 <3.1.0", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz" - }, - "extsprintf": { - "version": "1.0.2", - "from": "extsprintf@1.0.2", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz" - }, - "forever-agent": { - "version": "0.6.1", - "from": "forever-agent@>=0.6.1 <0.7.0", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" - }, - "form-data": { - "version": "1.0.0-rc4", - "from": "form-data@>=1.0.0-rc4 <1.1.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc4.tgz" - }, - "fs.realpath": { - "version": "1.0.0", - "from": "fs.realpath@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - }, - "fstream": { - "version": "1.0.10", - "from": "fstream@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.10.tgz" - }, - "fstream-ignore": { - "version": "1.0.5", - "from": "fstream-ignore@>=1.0.5 <1.1.0", - "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz" - }, - "gauge": { - "version": "2.6.0", - "from": "gauge@>=2.6.0 <2.7.0", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.6.0.tgz" - }, - "generate-function": { - "version": "2.0.0", - "from": "generate-function@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz" - }, - "generate-object-property": { - "version": "1.2.0", - "from": "generate-object-property@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz" - }, - "getpass": { - "version": "0.1.6", - "from": "getpass@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz", - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "from": "assert-plus@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" - } - } - }, - "glob": { - "version": "7.0.5", - "from": "glob@>=7.0.5 <8.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.5.tgz" - }, - "graceful-fs": { - "version": "4.1.4", - "from": "graceful-fs@>=4.1.2 <5.0.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz" - }, - "graceful-readlink": { - "version": "1.0.1", - "from": "graceful-readlink@>=1.0.0", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" - }, - "har-validator": { - "version": "2.0.6", - "from": "har-validator@>=2.0.6 <2.1.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz" - }, - "has-ansi": { - "version": "2.0.0", - "from": "has-ansi@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz" - }, - "has-color": { - "version": "0.1.7", - "from": "has-color@>=0.1.7 <0.2.0", - "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz" - }, - "has-unicode": { - "version": "2.0.1", - "from": "has-unicode@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" - }, - "hawk": { - "version": "3.1.3", - "from": "hawk@>=3.1.3 <3.2.0", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz" - }, - "hoek": { - "version": "2.16.3", - "from": "hoek@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz" - }, - "http-signature": { - "version": "1.1.1", - "from": "http-signature@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz" - }, - "inflight": { - "version": "1.0.5", - "from": "inflight@>=1.0.4 <2.0.0", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz" - }, - "inherits": { - "version": "2.0.1", - "from": "inherits@>=2.0.1 <2.1.0", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" - }, - "ini": { - "version": "1.3.4", - "from": "ini@>=1.3.0 <1.4.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "from": "is-fullwidth-code-point@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz" - }, - "is-my-json-valid": { - "version": "2.13.1", - "from": "is-my-json-valid@>=2.12.4 <3.0.0", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.1.tgz" - }, - "is-property": { - "version": "1.0.2", - "from": "is-property@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" - }, - "is-typedarray": { - "version": "1.0.0", - "from": "is-typedarray@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" - }, - "isarray": { - "version": "1.0.0", - "from": "isarray@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - }, - "isstream": { - "version": "0.1.2", - "from": "isstream@>=0.1.2 <0.2.0", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" - }, - "jodid25519": { - "version": "1.0.2", - "from": "jodid25519@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz" - }, - "jsbn": { - "version": "0.1.0", - "from": "jsbn@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz" - }, - "json-schema": { - "version": "0.2.2", - "from": "json-schema@0.2.2", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz" - }, - "json-stringify-safe": { - "version": "5.0.1", - "from": "json-stringify-safe@>=5.0.1 <5.1.0", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" - }, - "jsonpointer": { - "version": "2.0.0", - "from": "jsonpointer@2.0.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" - }, - "jsprim": { - "version": "1.3.0", - "from": "jsprim@>=1.2.2 <2.0.0", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.0.tgz" - }, - "mime-db": { - "version": "1.23.0", - "from": "mime-db@>=1.23.0 <1.24.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.23.0.tgz" - }, - "mime-types": { - "version": "2.1.11", - "from": "mime-types@>=2.1.7 <2.2.0", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.11.tgz" - }, - "minimatch": { - "version": "3.0.2", - "from": "minimatch@>=3.0.2 <4.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz" - }, - "minimist": { - "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" - }, - "mkdirp": { - "version": "0.5.1", - "from": "mkdirp@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz" - }, - "ms": { - "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" - }, - "node-pre-gyp": { - "version": "0.6.29", - "from": "node-pre-gyp@>=0.6.29 <0.7.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.29.tgz" - }, - "node-uuid": { - "version": "1.4.7", - "from": "node-uuid@>=1.4.7 <1.5.0", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz" - }, - "nopt": { - "version": "3.0.6", - "from": "nopt@>=3.0.1 <3.1.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz" - }, - "npmlog": { - "version": "3.1.2", - "from": "npmlog@>=3.1.2 <3.2.0", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-3.1.2.tgz" - }, - "number-is-nan": { - "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" - }, - "oauth-sign": { - "version": "0.8.2", - "from": "oauth-sign@>=0.8.1 <0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz" - }, - "object-assign": { - "version": "4.1.0", - "from": "object-assign@>=4.1.0 <5.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz" - }, - "once": { - "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz" - }, - "path-is-absolute": { - "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" - }, - "pinkie": { - "version": "2.0.4", - "from": "pinkie@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" - }, - "pinkie-promise": { - "version": "2.0.1", - "from": "pinkie-promise@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" - }, - "process-nextick-args": { - "version": "1.0.7", - "from": "process-nextick-args@>=1.0.6 <1.1.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" - }, - "qs": { - "version": "6.2.0", - "from": "qs@>=6.2.0 <6.3.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.0.tgz" - }, - "rc": { - "version": "1.1.6", - "from": "rc@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.1.6.tgz", - "dependencies": { - "minimist": { - "version": "1.2.0", - "from": "minimist@>=1.2.0 <2.0.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz" - } - } - }, - "readable-stream": { - "version": "2.1.4", - "from": "readable-stream@>=2.0.0 <3.0.0||>=1.1.13 <2.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz" - }, - "request": { - "version": "2.73.0", - "from": "request@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.73.0.tgz" - }, - "rimraf": { - "version": "2.5.3", - "from": "rimraf@>=2.5.0 <2.6.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.3.tgz" - }, - "semver": { - "version": "5.2.0", - "from": "semver@>=5.2.0 <5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.2.0.tgz" - }, - "set-blocking": { - "version": "2.0.0", - "from": "set-blocking@>=2.0.0 <2.1.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" - }, - "signal-exit": { - "version": "3.0.0", - "from": "signal-exit@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.0.tgz" - }, - "sntp": { - "version": "1.0.9", - "from": "sntp@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz" - }, - "sshpk": { - "version": "1.8.3", - "from": "sshpk@>=1.7.0 <2.0.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.8.3.tgz", - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "from": "assert-plus@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" - } - } - }, - "string_decoder": { - "version": "0.10.31", - "from": "string_decoder@>=0.10.0 <0.11.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" - }, - "string-width": { - "version": "1.0.1", - "from": "string-width@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.1.tgz" - }, - "stringstream": { - "version": "0.0.5", - "from": "stringstream@>=0.0.4 <0.1.0", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz" - }, - "strip-ansi": { - "version": "3.0.1", - "from": "strip-ansi@>=3.0.1 <4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" - }, - "strip-json-comments": { - "version": "1.0.4", - "from": "strip-json-comments@>=1.0.4 <1.1.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz" - }, - "supports-color": { - "version": "2.0.0", - "from": "supports-color@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" - }, - "tar": { - "version": "2.2.1", - "from": "tar@>=2.2.0 <2.3.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz" - }, - "tar-pack": { - "version": "3.1.4", - "from": "tar-pack@>=3.1.0 <3.2.0", - "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.1.4.tgz" - }, - "tough-cookie": { - "version": "2.2.2", - "from": "tough-cookie@>=2.2.0 <2.3.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz" - }, - "tunnel-agent": { - "version": "0.4.3", - "from": "tunnel-agent@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz" - }, - "tweetnacl": { - "version": "0.13.3", - "from": "tweetnacl@>=0.13.0 <0.14.0", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.3.tgz" - }, - "uid-number": { - "version": "0.0.6", - "from": "uid-number@>=0.0.6 <0.1.0", - "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz" - }, - "util-deprecate": { - "version": "1.0.2", - "from": "util-deprecate@>=1.0.1 <1.1.0", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - }, - "verror": { - "version": "1.3.6", - "from": "verror@1.3.6", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz" - }, - "wide-align": { - "version": "1.1.0", - "from": "wide-align@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.0.tgz" - }, - "wrappy": { - "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - }, - "xtend": { - "version": "4.0.1", - "from": "xtend@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" - } - } - }, - "gaze": { - "version": "1.1.1", - "from": "gaze@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.1.tgz" - }, - "generate-function": { - "version": "2.0.0", - "from": "generate-function@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz" - }, - "generate-object-property": { - "version": "1.2.0", - "from": "generate-object-property@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz" - }, - "get-caller-file": { - "version": "1.0.2", - "from": "get-caller-file@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz" - }, - "get-stdin": { - "version": "4.0.1", - "from": "get-stdin@>=4.0.1 <5.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz" - }, - "getobject": { - "version": "0.1.0", - "from": "getobject@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz" - }, - "getpass": { - "version": "0.1.6", - "from": "getpass@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz", - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "from": "assert-plus@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" - } - } - }, - "glob": { - "version": "5.0.15", - "from": "glob@>=5.0.0 <6.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz" - }, - "glob-base": { - "version": "0.3.0", - "from": "glob-base@>=0.3.0 <0.4.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz" - }, - "glob-parent": { - "version": "2.0.0", - "from": "glob-parent@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz" - }, - "globals": { - "version": "8.18.0", - "from": "globals@>=8.3.0 <9.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz" - }, - "globule": { - "version": "1.0.0", - "from": "globule@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.0.0.tgz", - "dependencies": { - "glob": { - "version": "7.0.6", - "from": "glob@>=7.0.3 <7.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz" - }, - "lodash": { - "version": "4.9.0", - "from": "lodash@>=4.9.0 <4.10.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.9.0.tgz" - } - } - }, - "graceful-fs": { - "version": "4.1.6", - "from": "graceful-fs@>=4.1.2 <5.0.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.6.tgz" - }, - "graceful-readlink": { - "version": "1.0.1", - "from": "graceful-readlink@>=1.0.0", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" - }, - "grunt-cli": { - "version": "1.2.0", - "from": "grunt-cli@>=1.2.0 <2.0.0", - "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz" - }, - "grunt-known-options": { - "version": "1.1.0", - "from": "grunt-known-options@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.0.tgz" - }, - "grunt-legacy-log": { - "version": "1.0.0", - "from": "grunt-legacy-log@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-1.0.0.tgz" - }, - "grunt-legacy-log-utils": { - "version": "1.0.0", - "from": "grunt-legacy-log-utils@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-1.0.0.tgz", - "dependencies": { - "lodash": { - "version": "4.3.0", - "from": "lodash@>=4.3.0 <4.4.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz" - } - } - }, - "grunt-legacy-util": { - "version": "1.0.0", - "from": "grunt-legacy-util@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.0.0.tgz", - "dependencies": { - "lodash": { - "version": "4.3.0", - "from": "lodash@>=4.3.0 <4.4.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz" - } - } - }, - "handlebars": { - "version": "4.0.5", - "from": "handlebars@>=4.0.0 <4.1.0", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.5.tgz", - "dependencies": { - "source-map": { - "version": "0.4.4", - "from": "source-map@>=0.4.4 <0.5.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz" - }, - "uglify-js": { - "version": "2.7.3", - "from": "uglify-js@>=2.6.0 <3.0.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.3.tgz", - "dependencies": { - "async": { - "version": "0.2.10", - "from": "async@>=0.2.6 <0.3.0", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz" - }, - "source-map": { - "version": "0.5.6", - "from": "source-map@>=0.5.1 <0.6.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz" - } - } - } - } - }, - "har-validator": { - "version": "2.0.6", - "from": "har-validator@>=2.0.6 <2.1.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz" - }, - "has-ansi": { - "version": "2.0.0", - "from": "has-ansi@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz" - }, - "has-binary": { - "version": "0.1.7", - "from": "has-binary@0.1.7", - "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", - "dependencies": { - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - } - } - }, - "has-cors": { - "version": "1.1.0", - "from": "has-cors@1.1.0", - "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz" - }, - "has-flag": { - "version": "1.0.0", - "from": "has-flag@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz" - }, - "hasha": { - "version": "2.2.0", - "from": "hasha@>=2.2.0 <2.3.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz" - }, - "hawk": { - "version": "3.1.3", - "from": "hawk@>=3.1.3 <3.2.0", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz" - }, - "hoek": { - "version": "2.16.3", - "from": "hoek@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz" - }, - "home-or-tmp": { - "version": "1.0.0", - "from": "home-or-tmp@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz" - }, - "hooker": { - "version": "0.2.3", - "from": "hooker@>=0.2.3 <0.3.0", - "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz" - }, - "hosted-git-info": { - "version": "2.1.5", - "from": "hosted-git-info@>=2.1.4 <3.0.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz" - }, - "htmlparser": { - "version": "1.7.7", - "from": "htmlparser@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/htmlparser/-/htmlparser-1.7.7.tgz" - }, - "htmlparser2": { - "version": "3.8.3", - "from": "htmlparser2@>=3.8.0 <3.9.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "dependencies": { - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "readable-stream": { - "version": "1.1.14", - "from": "readable-stream@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz" - } - } - }, - "http-browserify": { - "version": "1.7.0", - "from": "http-browserify@>=1.3.2 <2.0.0", - "resolved": "https://registry.npmjs.org/http-browserify/-/http-browserify-1.7.0.tgz" - }, - "http-errors": { - "version": "1.5.0", - "from": "http-errors@>=1.5.0 <1.6.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.0.tgz", - "dependencies": { - "inherits": { - "version": "2.0.1", - "from": "inherits@2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" - } - } - }, - "http-proxy": { - "version": "1.14.0", - "from": "http-proxy@1.14.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.14.0.tgz" - }, - "http-proxy-middleware": { - "version": "0.17.1", - "from": "http-proxy-middleware@>=0.17.1 <0.18.0", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.1.tgz", - "dependencies": { - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.14.2 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz" - } - } - }, - "http-signature": { - "version": "1.1.1", - "from": "http-signature@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz" - }, - "https-browserify": { - "version": "0.0.0", - "from": "https-browserify@0.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.0.tgz" - }, - "https-proxy-agent": { - "version": "1.0.0", - "from": "https-proxy-agent@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz" - }, - "iconv-lite": { - "version": "0.4.13", - "from": "iconv-lite@>=0.4.13 <0.5.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz" - }, - "ieee754": { - "version": "1.1.6", - "from": "ieee754@>=1.1.4 <2.0.0", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.6.tgz" - }, - "image-size": { - "version": "0.5.0", - "from": "image-size@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.0.tgz" - }, - "immutable": { - "version": "3.8.1", - "from": "immutable@3.8.1", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.1.tgz" - }, - "indent-string": { - "version": "2.1.0", - "from": "indent-string@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "dependencies": { - "repeating": { - "version": "2.0.1", - "from": "repeating@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz" - } - } - }, - "indexof": { - "version": "0.0.1", - "from": "indexof@0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz" - }, - "inflight": { - "version": "1.0.5", - "from": "inflight@>=1.0.4 <2.0.0", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz" - }, - "inherits": { - "version": "2.0.3", - "from": "inherits@>=2.0.1 <2.1.0", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz" - }, - "inquirer": { - "version": "0.8.5", - "from": "inquirer@>=0.8.2 <0.9.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz", - "dependencies": { - "ansi-regex": { - "version": "1.1.1", - "from": "ansi-regex@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz" - }, - "rx": { - "version": "2.5.3", - "from": "rx@>=2.4.3 <3.0.0", - "resolved": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz" - } - } - }, - "interpret": { - "version": "0.6.6", - "from": "interpret@>=0.6.4 <0.7.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-0.6.6.tgz" - }, - "invariant": { - "version": "2.2.1", - "from": "invariant@>=2.2.0 <3.0.0", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.1.tgz" - }, - "invert-kv": { - "version": "1.0.0", - "from": "invert-kv@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz" - }, - "ipaddr.js": { - "version": "1.1.1", - "from": "ipaddr.js@1.1.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.1.1.tgz" - }, - "irregular-plurals": { - "version": "1.2.0", - "from": "irregular-plurals@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.2.0.tgz" - }, - "is-arrayish": { - "version": "0.2.1", - "from": "is-arrayish@>=0.2.1 <0.3.0", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" - }, - "is-binary-path": { - "version": "1.0.1", - "from": "is-binary-path@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz" - }, - "is-buffer": { - "version": "1.1.4", - "from": "is-buffer@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.4.tgz" - }, - "is-builtin-module": { - "version": "1.0.0", - "from": "is-builtin-module@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz" - }, - "is-dotfile": { - "version": "1.0.2", - "from": "is-dotfile@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz" - }, - "is-equal-shallow": { - "version": "0.1.3", - "from": "is-equal-shallow@>=0.1.3 <0.2.0", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz" - }, - "is-extendable": { - "version": "0.1.1", - "from": "is-extendable@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz" - }, - "is-extglob": { - "version": "1.0.0", - "from": "is-extglob@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz" - }, - "is-finite": { - "version": "1.0.1", - "from": "is-finite@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "from": "is-fullwidth-code-point@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz" - }, - "is-glob": { - "version": "2.0.1", - "from": "is-glob@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz" - }, - "is-my-json-valid": { - "version": "2.14.0", - "from": "is-my-json-valid@>=2.12.4 <3.0.0", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.14.0.tgz" - }, - "is-number": { - "version": "2.1.0", - "from": "is-number@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz" - }, - "is-posix-bracket": { - "version": "0.1.1", - "from": "is-posix-bracket@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz" - }, - "is-primitive": { - "version": "2.0.0", - "from": "is-primitive@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz" - }, - "is-property": { - "version": "1.0.2", - "from": "is-property@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" - }, - "is-stream": { - "version": "1.1.0", - "from": "is-stream@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz" - }, - "is-typedarray": { - "version": "1.0.0", - "from": "is-typedarray@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" - }, - "is-utf8": { - "version": "0.2.1", - "from": "is-utf8@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz" - }, - "isarray": { - "version": "1.0.0", - "from": "isarray@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - }, - "isbinaryfile": { - "version": "3.0.1", - "from": "isbinaryfile@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.1.tgz" - }, - "isexe": { - "version": "1.1.2", - "from": "isexe@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz" - }, - "isobject": { - "version": "2.1.0", - "from": "isobject@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz" - }, - "isstream": { - "version": "0.1.2", - "from": "isstream@>=0.1.2 <0.2.0", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" - }, - "istanbul": { - "version": "0.4.5", - "from": "istanbul@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", - "dependencies": { - "supports-color": { - "version": "3.1.2", - "from": "supports-color@>=3.1.0 <4.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz" - } - } - }, - "istanbul-lib-coverage": { - "version": "1.0.0", - "from": "istanbul-lib-coverage@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.0.tgz" - }, - "istanbul-lib-instrument": { - "version": "1.1.3", - "from": "istanbul-lib-instrument@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.1.3.tgz" - }, - "javascript-detect-element-resize": { - "version": "0.5.3", - "from": "javascript-detect-element-resize@>=0.5.3 <0.6.0", - "resolved": "https://registry.npmjs.org/javascript-detect-element-resize/-/javascript-detect-element-resize-0.5.3.tgz" - }, - "jodid25519": { - "version": "1.0.2", - "from": "jodid25519@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz" - }, - "jquery": { - "version": "2.2.4", - "from": "jquery@2.2.4", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.2.4.tgz" - }, - "jquery-mousewheel": { - "version": "3.1.13", - "from": "jquery-mousewheel@>=3.1.13 <3.2.0", - "resolved": "https://registry.npmjs.org/jquery-mousewheel/-/jquery-mousewheel-3.1.13.tgz" - }, - "jquery-ui": { - "version": "1.10.5", - "from": "jquery-ui@1.10.5", - "resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.10.5.tgz" - }, - "js-base64": { - "version": "2.1.9", - "from": "js-base64@>=2.1.9 <3.0.0", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.1.9.tgz" - }, - "js-tokens": { - "version": "2.0.0", - "from": "js-tokens@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-2.0.0.tgz" - }, - "js-yaml": { - "version": "3.6.1", - "from": "js-yaml@>=3.2.7 <4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz" - }, - "jsbn": { - "version": "0.1.0", - "from": "jsbn@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz" - }, - "jsdom": { - "version": "0.5.7", - "from": "jsdom@0.5.7", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-0.5.7.tgz" - }, - "jsesc": { - "version": "0.5.0", - "from": "jsesc@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" - }, - "json-schema": { - "version": "0.2.3", - "from": "json-schema@0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz" - }, - "json-stringify-safe": { - "version": "5.0.1", - "from": "json-stringify-safe@>=5.0.1 <5.1.0", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" - }, - "json3": { - "version": "3.2.6", - "from": "json3@3.2.6", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.2.6.tgz" - }, - "json5": { - "version": "0.5.0", - "from": "json5@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.0.tgz" - }, - "jsonfile": { - "version": "2.4.0", - "from": "jsonfile@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz" - }, - "jsonpointer": { - "version": "2.0.0", - "from": "jsonpointer@2.0.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" - }, - "jsprim": { - "version": "1.3.1", - "from": "jsprim@>=1.2.2 <2.0.0", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.1.tgz" - }, - "jstimezonedetect": { - "version": "1.0.5", - "from": "jstimezonedetect@1.0.5", - "resolved": "https://registry.npmjs.org/jstimezonedetect/-/jstimezonedetect-1.0.5.tgz" - }, - "kew": { - "version": "0.7.0", - "from": "kew@>=0.7.0 <0.8.0", - "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz" - }, - "kind-of": { - "version": "3.0.4", - "from": "kind-of@>=3.0.2 <4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.4.tgz" - }, - "klaw": { - "version": "1.3.0", - "from": "klaw@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.0.tgz" - }, - "lazy-cache": { - "version": "1.0.4", - "from": "lazy-cache@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz" - }, - "lazy.js": { - "version": "0.4.2", - "from": "lazy.js@>=0.4.2 <0.5.0", - "resolved": "https://registry.npmjs.org/lazy.js/-/lazy.js-0.4.2.tgz" - }, - "lazystream": { - "version": "0.1.0", - "from": "lazystream@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-0.1.0.tgz", - "dependencies": { - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "readable-stream": { - "version": "1.0.34", - "from": "readable-stream@>=1.0.2 <1.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz" - } - } - }, - "lcid": { - "version": "1.0.0", - "from": "lcid@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz" - }, - "legacy-loader": { - "version": "0.0.2", - "from": "legacy-loader@0.0.2", - "resolved": "https://registry.npmjs.org/legacy-loader/-/legacy-loader-0.0.2.tgz" - }, - "less": { - "version": "2.7.1", - "from": "less@>=2.7.1 <2.8.0", - "resolved": "https://registry.npmjs.org/less/-/less-2.7.1.tgz", - "dependencies": { - "mime": { - "version": "1.3.4", - "from": "mime@>=1.2.11 <2.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz" - }, - "source-map": { - "version": "0.5.6", - "from": "source-map@>=0.5.3 <0.6.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz" - } - } - }, - "levn": { - "version": "0.3.0", - "from": "levn@>=0.3.0 <0.4.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" - }, - "limiter": { - "version": "1.1.0", - "from": "limiter@>=1.0.5 <2.0.0", - "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.0.tgz" - }, - "livereload-js": { - "version": "2.2.2", - "from": "livereload-js@>=2.2.0 <3.0.0", - "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz" - }, - "load-json-file": { - "version": "1.1.0", - "from": "load-json-file@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz" - }, - "loader-utils": { - "version": "0.2.16", - "from": "loader-utils@>=0.2.6 <0.3.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.16.tgz" - }, - "localtunnel": { - "version": "1.8.1", - "from": "localtunnel@1.8.1", - "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-1.8.1.tgz", - "dependencies": { - "asn1": { - "version": "0.1.11", - "from": "asn1@0.1.11", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz" - }, - "assert-plus": { - "version": "0.1.5", - "from": "assert-plus@>=0.1.5 <0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz" - }, - "async": { - "version": "2.0.1", - "from": "async@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.0.1.tgz" - }, - "bl": { - "version": "1.0.3", - "from": "bl@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz" - }, - "cliui": { - "version": "3.2.0", - "from": "cliui@>=3.0.3 <4.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz" - }, - "form-data": { - "version": "1.0.1", - "from": "form-data@>=1.0.0-rc3 <1.1.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz" - }, - "http-signature": { - "version": "0.11.0", - "from": "http-signature@>=0.11.0 <0.12.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz" - }, - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.8.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz" - }, - "qs": { - "version": "5.2.1", - "from": "qs@>=5.2.0 <5.3.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.1.tgz" - }, - "request": { - "version": "2.65.0", - "from": "request@2.65.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz" - }, - "tough-cookie": { - "version": "2.2.2", - "from": "tough-cookie@>=2.2.0 <2.3.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz" - }, - "window-size": { - "version": "0.1.4", - "from": "window-size@>=0.1.2 <0.2.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz" - }, - "yargs": { - "version": "3.29.0", - "from": "yargs@3.29.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.29.0.tgz" - } - } - }, - "lodash": { - "version": "3.10.1", - "from": "lodash@>=3.8.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" - }, - "lodash.assign": { - "version": "4.2.0", - "from": "lodash.assign@>=4.1.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz" - }, - "lodash.clonedeep": { - "version": "4.5.0", - "from": "lodash.clonedeep@>=4.3.2 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz" - }, - "log-symbols": { - "version": "1.0.2", - "from": "log-symbols@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz" - }, - "log4js": { - "version": "0.6.38", - "from": "log4js@>=0.6.31 <0.7.0", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz", - "dependencies": { - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "readable-stream": { - "version": "1.0.34", - "from": "readable-stream@>=1.0.2 <1.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz" - }, - "semver": { - "version": "4.3.6", - "from": "semver@>=4.3.3 <4.4.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz" - } - } - }, - "longest": { - "version": "1.0.1", - "from": "longest@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" - }, - "loose-envify": { - "version": "1.2.0", - "from": "loose-envify@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.2.0.tgz", - "dependencies": { - "js-tokens": { - "version": "1.0.3", - "from": "js-tokens@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.3.tgz" - } - } - }, - "loud-rejection": { - "version": "1.6.0", - "from": "loud-rejection@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz" - }, - "lr-infinite-scroll": { - "version": "1.0.0", - "from": "lorenzofox3/lrInfiniteScroll", - "resolved": "git://github.com/lorenzofox3/lrInfiniteScroll.git#59d348bc5c18f164438d2a30f1fd79b333c3b649" - }, - "lru-cache": { - "version": "2.2.4", - "from": "lru-cache@>=2.2.0 <2.3.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz" - }, - "map-obj": { - "version": "1.0.1", - "from": "map-obj@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz" - }, - "media-typer": { - "version": "0.3.0", - "from": "media-typer@0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" - }, - "memory-fs": { - "version": "0.3.0", - "from": "memory-fs@>=0.3.0 <0.4.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.3.0.tgz" - }, - "meow": { - "version": "3.7.0", - "from": "meow@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz" - }, - "merge-descriptors": { - "version": "1.0.1", - "from": "merge-descriptors@1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" - }, - "methods": { - "version": "1.1.2", - "from": "methods@>=1.1.2 <1.2.0", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" - }, - "micromatch": { - "version": "2.3.11", - "from": "micromatch@>=2.3.11 <3.0.0", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz" - }, - "mime": { - "version": "1.2.4", - "from": "mime@1.2.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.4.tgz" - }, - "mime-db": { - "version": "1.24.0", - "from": "mime-db@>=1.24.0 <1.25.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.24.0.tgz" - }, - "mime-types": { - "version": "2.1.12", - "from": "mime-types@>=2.1.7 <2.2.0", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.12.tgz" - }, - "minimatch": { - "version": "3.0.3", - "from": "minimatch@>=3.0.2 <4.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz" - }, - "minimist": { - "version": "1.2.0", - "from": "minimist@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz" - }, - "mkdirp": { - "version": "0.5.1", - "from": "mkdirp@>=0.5.1 <0.6.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "dependencies": { - "minimist": { - "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" - } - } - }, - "moment": { - "version": "2.15.1", - "from": "moment@>=2.10.2 <3.0.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.15.1.tgz" - }, - "ms": { - "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" - }, - "multimatch": { - "version": "2.1.0", - "from": "multimatch@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz" - }, - "mute-stream": { - "version": "0.0.4", - "from": "mute-stream@0.0.4", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz" - }, - "nan": { - "version": "2.4.0", - "from": "nan@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz" - }, - "negotiator": { - "version": "0.6.1", - "from": "negotiator@0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz" - }, - "ng-toast": { - "version": "2.0.0", - "from": "leigh-johnson/ngToast#2.0.1", - "resolved": "git://github.com/leigh-johnson/ngToast.git#fea95bb34d27687e414619b4f72c11735d909f93" - }, - "node-int64": { - "version": "0.3.3", - "from": "node-int64@>=0.3.0 <0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.3.3.tgz" - }, - "node-libs-browser": { - "version": "0.6.0", - "from": "node-libs-browser@>=0.6.0 <0.7.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-0.6.0.tgz", - "dependencies": { - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "readable-stream": { - "version": "1.1.14", - "from": "readable-stream@>=1.1.13 <2.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz" - } - } - }, - "node-uuid": { - "version": "1.4.7", - "from": "node-uuid@>=1.4.7 <1.5.0", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz" - }, - "nopt": { - "version": "3.0.6", - "from": "nopt@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz" - }, - "normalize-package-data": { - "version": "2.3.5", - "from": "normalize-package-data@>=2.3.2 <3.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz" - }, - "normalize-path": { - "version": "2.0.1", - "from": "normalize-path@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz" - }, - "normalize-range": { - "version": "0.1.2", - "from": "normalize-range@>=0.1.2 <0.2.0", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz" - }, - "null-check": { - "version": "1.0.0", - "from": "null-check@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz" - }, - "num2fraction": { - "version": "1.2.2", - "from": "num2fraction@>=1.2.2 <2.0.0", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz" - }, - "number-is-nan": { - "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" - }, - "nvd3": { - "version": "1.7.1", - "from": "leigh-johnson/nvd3#1.7.1", - "resolved": "git://github.com/leigh-johnson/nvd3.git#a28bcd494a1df0677be7cf2ebc0578f44eb21102", - "dependencies": { - "d3": { - "version": "3.3.13", - "from": "d3@>=3.3.13 <3.4.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-3.3.13.tgz" - } - } - }, - "nwmatcher": { - "version": "1.3.8", - "from": "nwmatcher@>=1.3.1 <1.4.0", - "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.3.8.tgz" - }, - "oauth-sign": { - "version": "0.8.2", - "from": "oauth-sign@>=0.8.1 <0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz" - }, - "object-assign": { - "version": "4.1.0", - "from": "object-assign@>=4.0.1 <5.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz" - }, - "object-component": { - "version": "0.0.3", - "from": "object-component@0.0.3", - "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz" - }, - "object-path": { - "version": "0.9.2", - "from": "object-path@>=0.9.0 <0.10.0", - "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.9.2.tgz" - }, - "object.omit": { - "version": "2.0.0", - "from": "object.omit@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.0.tgz" - }, - "on-finished": { - "version": "2.3.0", - "from": "on-finished@>=2.3.0 <2.4.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" - }, - "on-headers": { - "version": "1.0.1", - "from": "on-headers@>=1.0.1 <1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz" - }, - "once": { - "version": "1.4.0", - "from": "once@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz" - }, - "open": { - "version": "0.0.5", - "from": "open@0.0.5", - "resolved": "https://registry.npmjs.org/open/-/open-0.0.5.tgz" - }, - "openurl": { - "version": "1.1.0", - "from": "openurl@1.1.0", - "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.0.tgz" - }, - "opn": { - "version": "4.0.2", - "from": "opn@4.0.2", - "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz" - }, - "optimist": { - "version": "0.6.1", - "from": "optimist@>=0.6.1 <0.7.0", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "dependencies": { - "minimist": { - "version": "0.0.10", - "from": "minimist@>=0.0.1 <0.1.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz" - }, - "wordwrap": { - "version": "0.0.3", - "from": "wordwrap@>=0.0.2 <0.1.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" - } - } - }, - "optionator": { - "version": "0.8.2", - "from": "optionator@>=0.8.1 <0.9.0", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz" - }, - "options": { - "version": "0.0.6", - "from": "options@>=0.0.5", - "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz" - }, - "original": { - "version": "1.0.0", - "from": "original@>=0.0.5", - "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz", - "dependencies": { - "url-parse": { - "version": "1.0.5", - "from": "url-parse@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.0.5.tgz" - } - } - }, - "os-browserify": { - "version": "0.1.2", - "from": "os-browserify@>=0.1.2 <0.2.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.1.2.tgz" - }, - "os-locale": { - "version": "1.4.0", - "from": "os-locale@>=1.4.0 <2.0.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz" - }, - "os-tmpdir": { - "version": "1.0.1", - "from": "os-tmpdir@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz" - }, - "pad-stream": { - "version": "1.2.0", - "from": "pad-stream@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/pad-stream/-/pad-stream-1.2.0.tgz", - "dependencies": { - "repeating": { - "version": "2.0.1", - "from": "repeating@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz" - } - } - }, - "pako": { - "version": "0.2.9", - "from": "pako@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz" - }, - "parse-glob": { - "version": "3.0.4", - "from": "parse-glob@>=3.0.4 <4.0.0", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz" - }, - "parse-json": { - "version": "2.2.0", - "from": "parse-json@>=2.2.0 <3.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz" - }, - "parse-ms": { - "version": "1.0.1", - "from": "parse-ms@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz" - }, - "parsejson": { - "version": "0.0.1", - "from": "parsejson@0.0.1", - "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.1.tgz" - }, - "parseqs": { - "version": "0.0.2", - "from": "parseqs@0.0.2", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.2.tgz" - }, - "parseuri": { - "version": "0.0.4", - "from": "parseuri@0.0.4", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.4.tgz" - }, - "parseurl": { - "version": "1.3.1", - "from": "parseurl@>=1.3.1 <1.4.0", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz" - }, - "path-browserify": { - "version": "0.0.0", - "from": "path-browserify@0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz" - }, - "path-exists": { - "version": "1.0.0", - "from": "path-exists@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz" - }, - "path-is-absolute": { - "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" - }, - "path-to-regexp": { - "version": "0.1.7", - "from": "path-to-regexp@0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" - }, - "path-type": { - "version": "1.1.0", - "from": "path-type@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz" - }, - "pbkdf2-compat": { - "version": "2.0.1", - "from": "pbkdf2-compat@2.0.1", - "resolved": "https://registry.npmjs.org/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz" - }, - "pend": { - "version": "1.2.0", - "from": "pend@>=1.2.0 <1.3.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz" - }, - "phantomjs-prebuilt": { - "version": "2.1.12", - "from": "phantomjs-prebuilt@>=2.1.12 <3.0.0", - "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.12.tgz", - "dependencies": { - "async": { - "version": "2.0.1", - "from": "async@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.0.1.tgz" - }, - "form-data": { - "version": "1.0.1", - "from": "form-data@>=1.0.0-rc4 <1.1.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz" - }, - "lodash": { - "version": "4.16.1", - "from": "lodash@>=4.8.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.1.tgz" - }, - "request": { - "version": "2.74.0", - "from": "request@>=2.74.0 <2.75.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.74.0.tgz" - } - } - }, - "pify": { - "version": "2.3.0", - "from": "pify@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" - }, - "pinkie": { - "version": "2.0.4", - "from": "pinkie@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" - }, - "pinkie-promise": { - "version": "2.0.1", - "from": "pinkie-promise@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" - }, - "pkg-up": { - "version": "1.0.0", - "from": "pkg-up@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz" - }, - "plur": { - "version": "2.1.2", - "from": "plur@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz" - }, - "portscanner": { - "version": "1.0.0", - "from": "portscanner@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-1.0.0.tgz", - "dependencies": { - "async": { - "version": "0.1.15", - "from": "async@0.1.15", - "resolved": "https://registry.npmjs.org/async/-/async-0.1.15.tgz" - } - } - }, - "postcss": { - "version": "5.2.0", - "from": "postcss@>=5.0.0 <6.0.0", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.0.tgz", - "dependencies": { - "source-map": { - "version": "0.5.6", - "from": "source-map@>=0.5.6 <0.6.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz" - }, - "supports-color": { - "version": "3.1.2", - "from": "supports-color@>=3.1.2 <4.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz" - } - } - }, - "postcss-value-parser": { - "version": "3.3.0", - "from": "postcss-value-parser@>=3.2.3 <4.0.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz" - }, - "prelude-ls": { - "version": "1.1.2", - "from": "prelude-ls@>=1.1.2 <1.2.0", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" - }, - "preserve": { - "version": "0.2.0", - "from": "preserve@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz" - }, - "pretty-ms": { - "version": "2.1.0", - "from": "pretty-ms@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz", - "dependencies": { - "plur": { - "version": "1.0.0", - "from": "plur@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz" - } - } - }, - "private": { - "version": "0.1.6", - "from": "private@>=0.1.6 <0.2.0", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.6.tgz" - }, - "process": { - "version": "0.11.9", - "from": "process@>=0.11.0 <0.12.0", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.9.tgz" - }, - "process-nextick-args": { - "version": "1.0.7", - "from": "process-nextick-args@>=1.0.6 <1.1.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" - }, - "progress": { - "version": "1.1.8", - "from": "progress@>=1.1.8 <1.2.0", - "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz" - }, - "promise": { - "version": "7.1.1", - "from": "promise@>=7.1.1 <8.0.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.1.1.tgz" - }, - "proxy-addr": { - "version": "1.1.2", - "from": "proxy-addr@>=1.1.2 <1.2.0", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.2.tgz" - }, - "prr": { - "version": "0.0.0", - "from": "prr@>=0.0.0 <0.1.0", - "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz" - }, - "pump": { - "version": "1.0.1", - "from": "pump@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.1.tgz", - "dependencies": { - "end-of-stream": { - "version": "1.1.0", - "from": "end-of-stream@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz", - "dependencies": { - "once": { - "version": "1.3.3", - "from": "once@>=1.3.0 <1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz" - } - } - } - } - }, - "pumpify": { - "version": "1.3.5", - "from": "pumpify@>=1.3.3 <2.0.0", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.3.5.tgz" - }, - "punycode": { - "version": "1.4.1", - "from": "punycode@>=1.2.4 <2.0.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz" - }, - "q": { - "version": "1.4.1", - "from": "q@>=1.4.1 <2.0.0", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz" - }, - "qjobs": { - "version": "1.1.5", - "from": "qjobs@>=1.1.4 <2.0.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.1.5.tgz" - }, - "qs": { - "version": "6.2.1", - "from": "qs@>=6.2.0 <6.3.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.1.tgz" - }, - "querystring": { - "version": "0.2.0", - "from": "querystring@0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz" - }, - "querystring-es3": { - "version": "0.2.1", - "from": "querystring-es3@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz" - }, - "querystringify": { - "version": "0.0.4", - "from": "querystringify@>=0.0.0 <0.1.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz" - }, - "randomatic": { - "version": "1.1.5", - "from": "randomatic@>=1.1.3 <2.0.0", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.5.tgz" - }, - "range-parser": { - "version": "1.2.0", - "from": "range-parser@>=1.2.0 <1.3.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz" - }, - "raw-body": { - "version": "2.1.7", - "from": "raw-body@>=2.1.5 <2.2.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", - "dependencies": { - "bytes": { - "version": "2.4.0", - "from": "bytes@2.4.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz" - } - } - }, - "rcfinder": { - "version": "0.1.9", - "from": "rcfinder@>=0.1.6 <0.2.0", - "resolved": "https://registry.npmjs.org/rcfinder/-/rcfinder-0.1.9.tgz" - }, - "rcloader": { - "version": "0.1.2", - "from": "rcloader@0.1.2", - "resolved": "https://registry.npmjs.org/rcloader/-/rcloader-0.1.2.tgz", - "dependencies": { - "lodash": { - "version": "2.4.2", - "from": "lodash@>=2.4.1 <2.5.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz" - } - } - }, - "read-pkg": { - "version": "1.1.0", - "from": "read-pkg@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz" - }, - "read-pkg-up": { - "version": "1.0.1", - "from": "read-pkg-up@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz" - }, - "readable-stream": { - "version": "2.0.6", - "from": "readable-stream@>=2.0.5 <2.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz" - }, - "readdirp": { - "version": "2.1.0", - "from": "readdirp@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz" - }, - "readline2": { - "version": "0.1.1", - "from": "readline2@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz", - "dependencies": { - "ansi-regex": { - "version": "1.1.1", - "from": "ansi-regex@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz" - }, - "strip-ansi": { - "version": "2.0.1", - "from": "strip-ansi@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz" - } - } - }, - "redent": { - "version": "1.0.0", - "from": "redent@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz" - }, - "regenerate": { - "version": "1.3.1", - "from": "regenerate@>=1.2.1 <2.0.0", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.1.tgz" - }, - "regenerator-runtime": { - "version": "0.9.5", - "from": "regenerator-runtime@>=0.9.5 <0.10.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.9.5.tgz" - }, - "regex-cache": { - "version": "0.4.3", - "from": "regex-cache@>=0.4.2 <0.5.0", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz" - }, - "regexpu-core": { - "version": "2.0.0", - "from": "regexpu-core@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz" - }, - "regjsgen": { - "version": "0.2.0", - "from": "regjsgen@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz" - }, - "regjsparser": { - "version": "0.1.5", - "from": "regjsparser@>=0.1.4 <0.2.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz" - }, - "repeat-element": { - "version": "1.1.2", - "from": "repeat-element@>=1.1.2 <2.0.0", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz" - }, - "repeat-string": { - "version": "1.5.4", - "from": "repeat-string@>=1.5.2 <2.0.0", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" - }, - "repeating": { - "version": "1.1.3", - "from": "repeating@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz" - }, - "request": { - "version": "2.75.0", - "from": "request@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.75.0.tgz" - }, - "request-progress": { - "version": "2.0.1", - "from": "request-progress@>=2.0.1 <2.1.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz" - }, - "require-directory": { - "version": "2.1.1", - "from": "require-directory@>=2.1.1 <3.0.0", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" - }, - "require-main-filename": { - "version": "1.0.1", - "from": "require-main-filename@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz" - }, - "requires-port": { - "version": "1.0.0", - "from": "requires-port@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" - }, - "resolve": { - "version": "1.1.7", - "from": "resolve@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" - }, - "resolve-from": { - "version": "2.0.0", - "from": "resolve-from@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz" - }, - "resolve-pkg": { - "version": "0.1.0", - "from": "resolve-pkg@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-0.1.0.tgz" - }, - "resp-modifier": { - "version": "6.0.2", - "from": "resp-modifier@6.0.2", - "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz" - }, - "right-align": { - "version": "0.1.3", - "from": "right-align@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz" - }, - "rimraf": { - "version": "2.5.4", - "from": "rimraf@>=2.2.8 <3.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", - "dependencies": { - "glob": { - "version": "7.1.0", - "from": "glob@>=7.0.5 <8.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.0.tgz" - } - } - }, - "ripemd160": { - "version": "0.2.0", - "from": "ripemd160@0.2.0", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-0.2.0.tgz" - }, - "rrule": { - "version": "2.2.0-dev", - "from": "jkbrzt/rrule#4ff63b2f8524fd6d5ba6e80db770953b5cd08a0c", - "resolved": "git://github.com/jkbrzt/rrule.git#4ff63b2f8524fd6d5ba6e80db770953b5cd08a0c" - }, - "rx": { - "version": "4.1.0", - "from": "rx@4.1.0", - "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz" - }, - "sauce-connect-launcher": { - "version": "0.13.0", - "from": "sauce-connect-launcher@>=0.13.0 <0.14.0", - "resolved": "https://registry.npmjs.org/sauce-connect-launcher/-/sauce-connect-launcher-0.13.0.tgz", - "dependencies": { - "async": { - "version": "1.4.0", - "from": "async@1.4.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.4.0.tgz" - }, - "rimraf": { - "version": "2.4.3", - "from": "rimraf@2.4.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.3.tgz" - } - } - }, - "saucelabs": { - "version": "1.3.0", - "from": "saucelabs@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.3.0.tgz" - }, - "select2": { - "version": "4.0.3", - "from": "select2@>=4.0.2 <5.0.0", - "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.3.tgz" - }, - "semver": { - "version": "5.3.0", - "from": "semver@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0||>=4.0.0 <5.0.0||>=5.0.0 <6.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz" - }, - "send": { - "version": "0.14.1", - "from": "send@0.14.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.14.1.tgz", - "dependencies": { - "mime": { - "version": "1.3.4", - "from": "mime@1.3.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz" - } - } - }, - "serve-index": { - "version": "1.8.0", - "from": "serve-index@1.8.0", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.8.0.tgz" - }, - "serve-static": { - "version": "1.11.1", - "from": "serve-static@1.11.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.11.1.tgz" - }, - "server-destroy": { - "version": "1.0.1", - "from": "server-destroy@1.0.1", - "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz" - }, - "set-blocking": { - "version": "2.0.0", - "from": "set-blocking@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" - }, - "set-immediate-shim": { - "version": "1.0.1", - "from": "set-immediate-shim@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz" - }, - "setprototypeof": { - "version": "1.0.1", - "from": "setprototypeof@1.0.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.1.tgz" - }, - "sha.js": { - "version": "2.2.6", - "from": "sha.js@2.2.6", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.2.6.tgz" - }, - "shebang-regex": { - "version": "1.0.0", - "from": "shebang-regex@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" - }, - "shelljs": { - "version": "0.3.0", - "from": "shelljs@>=0.3.0 <0.4.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz" - }, - "signal-exit": { - "version": "3.0.1", - "from": "signal-exit@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.1.tgz" - }, - "slash": { - "version": "1.0.0", - "from": "slash@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz" - }, - "sntp": { - "version": "1.0.9", - "from": "sntp@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz" - }, - "socket.io": { - "version": "1.4.8", - "from": "socket.io@1.4.8", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.4.8.tgz", - "dependencies": { - "component-emitter": { - "version": "1.2.0", - "from": "component-emitter@1.2.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.0.tgz" - }, - "socket.io-client": { - "version": "1.4.8", - "from": "socket.io-client@1.4.8", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.4.8.tgz" - } - } - }, - "socket.io-adapter": { - "version": "0.4.0", - "from": "socket.io-adapter@0.4.0", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.4.0.tgz", - "dependencies": { - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "socket.io-parser": { - "version": "2.2.2", - "from": "socket.io-parser@2.2.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.2.2.tgz", - "dependencies": { - "debug": { - "version": "0.7.4", - "from": "debug@0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz" - } - } - } - } - }, - "socket.io-client": { - "version": "0.9.17", - "from": "socket.io-client@>=0.9.17 <0.10.0", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-0.9.17.tgz" - }, - "socket.io-parser": { - "version": "2.2.6", - "from": "socket.io-parser@2.2.6", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.2.6.tgz", - "dependencies": { - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "json3": { - "version": "3.3.2", - "from": "json3@3.3.2", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz" - } - } - }, - "sockjs": { - "version": "0.3.17", - "from": "sockjs@>=0.3.15 <0.4.0", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.17.tgz" - }, - "sockjs-client": { - "version": "1.1.1", - "from": "sockjs-client@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.1.tgz", - "dependencies": { - "faye-websocket": { - "version": "0.11.0", - "from": "faye-websocket@>=0.11.0 <0.12.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.0.tgz" - }, - "json3": { - "version": "3.3.2", - "from": "json3@>=3.3.2 <4.0.0", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz" - } - } - }, - "source-list-map": { - "version": "0.1.6", - "from": "source-list-map@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.6.tgz" - }, - "source-map": { - "version": "0.3.0", - "from": "source-map@>=0.3.0 <0.4.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.3.0.tgz" - }, - "source-map-support": { - "version": "0.2.10", - "from": "source-map-support@>=0.2.10 <0.3.0", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz", - "dependencies": { - "source-map": { - "version": "0.1.32", - "from": "source-map@0.1.32", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz" - } - } - }, - "spdx-correct": { - "version": "1.0.2", - "from": "spdx-correct@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz" - }, - "spdx-expression-parse": { - "version": "1.0.3", - "from": "spdx-expression-parse@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.3.tgz" - }, - "spdx-license-ids": { - "version": "1.2.2", - "from": "spdx-license-ids@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz" - }, - "split2": { - "version": "1.1.1", - "from": "split2@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-1.1.1.tgz" - }, - "sprintf-js": { - "version": "1.0.3", - "from": "sprintf-js@>=1.0.2 <1.1.0", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" - }, - "sshpk": { - "version": "1.10.0", - "from": "sshpk@>=1.7.0 <2.0.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.0.tgz", - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "from": "assert-plus@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" - } - } - }, - "statuses": { - "version": "1.3.0", - "from": "statuses@>=1.3.0 <2.0.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.0.tgz" - }, - "stream-browserify": { - "version": "1.0.0", - "from": "stream-browserify@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-1.0.0.tgz", - "dependencies": { - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "readable-stream": { - "version": "1.1.14", - "from": "readable-stream@>=1.0.27-1 <2.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz" - } - } - }, - "stream-cache": { - "version": "0.0.2", - "from": "stream-cache@>=0.0.1 <0.1.0", - "resolved": "https://registry.npmjs.org/stream-cache/-/stream-cache-0.0.2.tgz" - }, - "stream-shift": { - "version": "1.0.0", - "from": "stream-shift@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz" - }, - "stream-throttle": { - "version": "0.1.3", - "from": "stream-throttle@>=0.1.3 <0.2.0", - "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz" - }, - "string_decoder": { - "version": "0.10.31", - "from": "string_decoder@>=0.10.0 <0.11.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" - }, - "string-length": { - "version": "1.0.1", - "from": "string-length@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz" - }, - "string-width": { - "version": "1.0.2", - "from": "string-width@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" - }, - "stringstream": { - "version": "0.0.5", - "from": "stringstream@>=0.0.4 <0.1.0", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz" - }, - "strip-ansi": { - "version": "3.0.1", - "from": "strip-ansi@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" - }, - "strip-bom": { - "version": "2.0.0", - "from": "strip-bom@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz" - }, - "strip-indent": { - "version": "1.0.1", - "from": "strip-indent@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz" - }, - "strip-json-comments": { - "version": "1.0.4", - "from": "strip-json-comments@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz" - }, - "supports-color": { - "version": "2.0.0", - "from": "supports-color@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" - }, - "tapable": { - "version": "0.1.10", - "from": "tapable@>=0.1.8 <0.2.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz" - }, - "tar-stream": { - "version": "1.1.5", - "from": "tar-stream@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.1.5.tgz", - "dependencies": { - "bl": { - "version": "0.9.5", - "from": "bl@>=0.9.0 <0.10.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.5.tgz" - }, - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "readable-stream": { - "version": "1.0.34", - "from": "readable-stream@>=1.0.33 <1.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz" - } - } - }, - "test-exclude": { - "version": "2.1.2", - "from": "test-exclude@>=2.1.1 <3.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-2.1.2.tgz" - }, - "text-table": { - "version": "0.2.0", - "from": "text-table@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" - }, - "tfunk": { - "version": "3.0.2", - "from": "tfunk@>=3.0.1 <4.0.0", - "resolved": "https://registry.npmjs.org/tfunk/-/tfunk-3.0.2.tgz" - }, - "throttleit": { - "version": "1.0.0", - "from": "throttleit@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz" - }, - "through": { - "version": "2.3.8", - "from": "through@>=2.3.6 <3.0.0", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" - }, - "through2": { - "version": "2.0.1", - "from": "through2@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.1.tgz" - }, - "time-zone": { - "version": "0.1.0", - "from": "time-zone@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-0.1.0.tgz" - }, - "timers-browserify": { - "version": "1.4.2", - "from": "timers-browserify@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz" - }, - "timezone-js": { - "version": "0.4.11", - "from": "leigh-johnson/timezone-js#0.4.13", - "resolved": "git://github.com/leigh-johnson/timezone-js.git#3b1de3f89106706483e79831312d3c325f95dd8a" - }, - "tiny-lr": { - "version": "0.2.1", - "from": "tiny-lr@>=0.2.1 <0.3.0", - "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-0.2.1.tgz", - "dependencies": { - "qs": { - "version": "5.1.0", - "from": "qs@>=5.1.0 <5.2.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-5.1.0.tgz" - } - } - }, - "tinycolor": { - "version": "0.0.1", - "from": "tinycolor@>=0.0.0 <1.0.0", - "resolved": "https://registry.npmjs.org/tinycolor/-/tinycolor-0.0.1.tgz" - }, - "tmp": { - "version": "0.0.28", - "from": "tmp@0.0.28", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz" - }, - "to-array": { - "version": "0.1.4", - "from": "to-array@0.1.4", - "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz" - }, - "to-fast-properties": { - "version": "1.0.2", - "from": "to-fast-properties@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz" - }, - "tough-cookie": { - "version": "2.3.1", - "from": "tough-cookie@>=2.3.0 <2.4.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.1.tgz" - }, - "trim-newlines": { - "version": "1.0.0", - "from": "trim-newlines@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz" - }, - "tty-browserify": { - "version": "0.0.0", - "from": "tty-browserify@0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz" - }, - "tunnel-agent": { - "version": "0.4.3", - "from": "tunnel-agent@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz" - }, - "tweetnacl": { - "version": "0.13.3", - "from": "tweetnacl@>=0.13.0 <0.14.0", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.3.tgz" - }, - "type-check": { - "version": "0.3.2", - "from": "type-check@>=0.3.2 <0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" - }, - "type-is": { - "version": "1.6.13", - "from": "type-is@>=1.6.10 <1.7.0", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.13.tgz" - }, - "typedarray": { - "version": "0.0.6", - "from": "typedarray@>=0.0.5 <0.1.0", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" - }, - "ua-parser-js": { - "version": "0.7.10", - "from": "ua-parser-js@0.7.10", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.10.tgz" - }, - "uglify-js": { - "version": "1.2.5", - "from": "uglify-js@1.2.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-1.2.5.tgz" - }, - "uglify-to-browserify": { - "version": "1.0.2", - "from": "uglify-to-browserify@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz" - }, - "ultron": { - "version": "1.0.2", - "from": "ultron@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz" - }, - "underscore": { - "version": "1.7.0", - "from": "underscore@>=1.7.0 <1.8.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz" - }, - "underscore.string": { - "version": "3.2.3", - "from": "underscore.string@>=3.2.3 <3.3.0", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz" - }, - "unpipe": { - "version": "1.0.0", - "from": "unpipe@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" - }, - "url": { - "version": "0.10.3", - "from": "url@>=0.10.1 <0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "dependencies": { - "punycode": { - "version": "1.3.2", - "from": "punycode@1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz" - } - } - }, - "url-parse": { - "version": "1.1.3", - "from": "url-parse@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.1.3.tgz" - }, - "user-home": { - "version": "1.1.1", - "from": "user-home@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz" - }, - "useragent": { - "version": "2.1.9", - "from": "useragent@>=2.1.9 <3.0.0", - "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.1.9.tgz" - }, - "utf8": { - "version": "2.1.0", - "from": "utf8@2.1.0", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.0.tgz" - }, - "util": { - "version": "0.10.3", - "from": "util@>=0.10.3 <0.11.0", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "dependencies": { - "inherits": { - "version": "2.0.1", - "from": "inherits@2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "from": "util-deprecate@>=1.0.1 <1.1.0", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - }, - "utils-merge": { - "version": "1.0.0", - "from": "utils-merge@1.0.0", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz" - }, - "uuid": { - "version": "2.0.3", - "from": "uuid@>=2.0.2 <3.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz" - }, - "validate-npm-package-license": { - "version": "3.0.1", - "from": "validate-npm-package-license@>=3.0.1 <4.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz" - }, - "vargs": { - "version": "0.1.0", - "from": "vargs@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/vargs/-/vargs-0.1.0.tgz" - }, - "vary": { - "version": "1.1.0", - "from": "vary@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.0.tgz" - }, - "verror": { - "version": "1.3.6", - "from": "verror@1.3.6", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz" - }, - "vm-browserify": { - "version": "0.0.4", - "from": "vm-browserify@0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz" - }, - "void-elements": { - "version": "2.0.1", - "from": "void-elements@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz" - }, - "watchpack": { - "version": "0.2.9", - "from": "watchpack@>=0.2.1 <0.3.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-0.2.9.tgz", - "dependencies": { - "async": { - "version": "0.9.2", - "from": "async@>=0.9.0 <0.10.0", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz" - } - } - }, - "wd": { - "version": "0.3.12", - "from": "wd@>=0.3.4 <0.4.0", - "resolved": "https://registry.npmjs.org/wd/-/wd-0.3.12.tgz", - "dependencies": { - "asn1": { - "version": "0.1.11", - "from": "asn1@0.1.11", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz" - }, - "assert-plus": { - "version": "0.1.5", - "from": "assert-plus@>=0.1.5 <0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz" - }, - "async": { - "version": "1.0.0", - "from": "async@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz" - }, - "aws-sign2": { - "version": "0.5.0", - "from": "aws-sign2@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz" - }, - "bl": { - "version": "0.9.5", - "from": "bl@>=0.9.0 <0.10.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.5.tgz" - }, - "bluebird": { - "version": "2.11.0", - "from": "bluebird@>=2.9.30 <3.0.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz" - }, - "caseless": { - "version": "0.9.0", - "from": "caseless@>=0.9.0 <0.10.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.9.0.tgz" - }, - "combined-stream": { - "version": "0.0.7", - "from": "combined-stream@>=0.0.5 <0.1.0", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz" - }, - "delayed-stream": { - "version": "0.0.5", - "from": "delayed-stream@0.0.5", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz" - }, - "form-data": { - "version": "0.2.0", - "from": "form-data@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.2.0.tgz", - "dependencies": { - "async": { - "version": "0.9.2", - "from": "async@>=0.9.0 <0.10.0", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz" - } - } - }, - "har-validator": { - "version": "1.8.0", - "from": "har-validator@>=1.4.0 <2.0.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-1.8.0.tgz" - }, - "hawk": { - "version": "2.3.1", - "from": "hawk@>=2.3.0 <2.4.0", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-2.3.1.tgz" - }, - "http-signature": { - "version": "0.10.1", - "from": "http-signature@>=0.10.0 <0.11.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz" - }, - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "lodash": { - "version": "3.9.3", - "from": "lodash@>=3.9.3 <3.10.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.9.3.tgz" - }, - "mime-db": { - "version": "1.12.0", - "from": "mime-db@>=1.12.0 <1.13.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.12.0.tgz" - }, - "mime-types": { - "version": "2.0.14", - "from": "mime-types@>=2.0.1 <2.1.0", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.14.tgz" - }, - "oauth-sign": { - "version": "0.6.0", - "from": "oauth-sign@>=0.6.0 <0.7.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.6.0.tgz" - }, - "qs": { - "version": "2.4.2", - "from": "qs@>=2.4.0 <2.5.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-2.4.2.tgz" - }, - "readable-stream": { - "version": "1.0.34", - "from": "readable-stream@>=1.0.26 <1.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz" - }, - "request": { - "version": "2.55.0", - "from": "request@>=2.55.0 <2.56.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.55.0.tgz" - }, - "underscore.string": { - "version": "3.0.3", - "from": "underscore.string@>=3.0.3 <3.1.0", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.0.3.tgz" - } - } - }, - "webpack-core": { - "version": "0.6.8", - "from": "webpack-core@>=0.6.0 <0.7.0", - "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.8.tgz", - "dependencies": { - "source-map": { - "version": "0.4.4", - "from": "source-map@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz" - } - } - }, - "webpack-dev-middleware": { - "version": "1.8.1", - "from": "webpack-dev-middleware@>=1.0.11 <2.0.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.8.1.tgz", - "dependencies": { - "mime": { - "version": "1.3.4", - "from": "mime@>=1.3.4 <2.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz" - } - } - }, - "websocket-driver": { - "version": "0.6.5", - "from": "websocket-driver@>=0.5.1", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz" - }, - "websocket-extensions": { - "version": "0.1.1", - "from": "websocket-extensions@>=0.1.1", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz" - }, - "weinre": { - "version": "2.0.0-pre-I0Z7U9OV", - "from": "weinre@>=2.0.0-pre-I0Z7U9OV <3.0.0", - "resolved": "https://registry.npmjs.org/weinre/-/weinre-2.0.0-pre-I0Z7U9OV.tgz" - }, - "which": { - "version": "1.2.11", - "from": "which@>=1.2.0 <1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.2.11.tgz" - }, - "which-module": { - "version": "1.0.0", - "from": "which-module@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz" - }, - "window-size": { - "version": "0.1.0", - "from": "window-size@0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz" - }, - "wordwrap": { - "version": "1.0.0", - "from": "wordwrap@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" - }, - "wrap-ansi": { - "version": "2.0.0", - "from": "wrap-ansi@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.0.0.tgz" - }, - "wrappy": { - "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - }, - "ws": { - "version": "0.4.32", - "from": "ws@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-0.4.32.tgz", - "dependencies": { - "commander": { - "version": "2.1.0", - "from": "commander@>=2.1.0 <2.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz" - }, - "nan": { - "version": "1.0.0", - "from": "nan@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-1.0.0.tgz" - } - } - }, - "xmlbuilder": { - "version": "8.2.2", - "from": "xmlbuilder@8.2.2", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz" - }, - "xmlhttprequest": { - "version": "1.4.2", - "from": "xmlhttprequest@1.4.2", - "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.4.2.tgz" - }, - "xmlhttprequest-ssl": { - "version": "1.5.1", - "from": "xmlhttprequest-ssl@1.5.1", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.1.tgz" - }, - "xtend": { - "version": "4.0.1", - "from": "xtend@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" - }, - "y18n": { - "version": "3.2.1", - "from": "y18n@>=3.2.0 <4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz" - }, - "yargs": { - "version": "3.10.0", - "from": "yargs@>=3.10.0 <3.11.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz" - }, - "yargs-parser": { - "version": "3.2.0", - "from": "yargs-parser@>=3.2.0 <4.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-3.2.0.tgz", - "dependencies": { - "camelcase": { - "version": "3.0.0", - "from": "camelcase@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz" - } - } - }, - "yauzl": { - "version": "2.4.1", - "from": "yauzl@2.4.1", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz" - }, - "yeast": { - "version": "0.1.2", - "from": "yeast@0.1.2", - "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz" - }, - "zeparser": { - "version": "0.0.5", - "from": "zeparser@0.0.5", - "resolved": "https://registry.npmjs.org/zeparser/-/zeparser-0.0.5.tgz" - }, - "zip-stream": { - "version": "0.5.2", - "from": "zip-stream@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-0.5.2.tgz", - "dependencies": { - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "lodash": { - "version": "3.2.0", - "from": "lodash@>=3.2.0 <3.3.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.2.0.tgz" - }, - "readable-stream": { - "version": "1.0.34", - "from": "readable-stream@>=1.0.26 <1.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz" - } - } - } - } -} diff --git a/awx/ui/package.json b/awx/ui/package.json index 414150fa49..2aadac00ff 100644 --- a/awx/ui/package.json +++ b/awx/ui/package.json @@ -7,7 +7,6 @@ }, "config": { "django_port": "8013", - "websocket_port": "8080", "django_host": "0.0.0.0", "sauce_username": "leigh-johnson", "sauce_access_key": "f740c3ad-c706-4e10-bb95-46e2cc50c2ac" @@ -17,7 +16,7 @@ "npm": "^3.10.3" }, "scripts": { - "build-docker-machine": "docker-machine ssh $DOCKER_MACHINE_NAME -f -N -L ${npm_package_config_websocket_port}:localhost:${npm_package_config_websocket_port}; ip=$(docker-machine ip $DOCKER_MACHINE_NAME); npm set ansible-tower:django_host ${ip}; grunt dev", + "build-docker-machine": "ip=$(docker-machine ip $DOCKER_MACHINE_NAME); npm set ansible-tower:django_host ${ip}; grunt dev", "build-docker-cid": "ip=`docker inspect --format '{{ .NetworkSettings.IPAddress }}' $DOCkER_CID` | npm set config ansible-tower:django_host ${ip}; grunt dev", "build-release": "grunt release", "pretest": "grunt clean:coverage", @@ -99,7 +98,7 @@ "moment": "^2.10.2", "ng-toast": "leigh-johnson/ngToast#2.0.1", "nvd3": "leigh-johnson/nvd3#1.7.1", - "select2": "^4.0.2", - "socket.io-client": "^0.9.17" + "reconnectingwebsocket": "^1.0.0", + "select2": "^4.0.2" } } diff --git a/awx/ui/tests/spec/socket/socket.service-test.js b/awx/ui/tests/spec/socket/socket.service-test.js new file mode 100644 index 0000000000..9310adfc92 --- /dev/null +++ b/awx/ui/tests/spec/socket/socket.service-test.js @@ -0,0 +1,30 @@ +'use strict'; + +describe('Service: SocketService', () => { + + let SocketService, + rootScope, + event; + + beforeEach(angular.mock.module('shared')); + beforeEach(angular.mock.module('socket', function($provide){ + $provide.value('$rootScope', rootScope); + $provide.value('$location', {url: function(){}}); + })); + beforeEach(angular.mock.inject(($rootScope, _SocketService_) => { + rootScope = $rootScope.$new(); + rootScope.$emit = jasmine.createSpy('$emit'); + SocketService = _SocketService_; + })); + + describe('socket onmessage() should broadcast to correct event listener', function(){ + + it('should send to ws-jobs-summary', function(){ + event = {data : {group_name: "jobs"}}; + event.data = JSON.stringify(event.data); + SocketService.onMessage(event); + expect(rootScope.$emit).toHaveBeenCalledWith('ws-jobs-summary', event.data); + }); + }); + +}); diff --git a/awx/ui/webpack.config.js b/awx/ui/webpack.config.js index a5e631aa9b..57d8dd880c 100644 --- a/awx/ui/webpack.config.js +++ b/awx/ui/webpack.config.js @@ -27,7 +27,7 @@ var vendorPkgs = [ 'ng-toast', 'nvd3', 'select2', - 'socket.io-client', + 'reconnectingwebsocket' ]; var dev = { diff --git a/requirements/requirements.txt b/requirements/requirements.txt index d236b5d1f1..c2effa3802 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -85,7 +85,8 @@ pycparser==2.14 pygerduty==0.32.1 PyJWT==1.4.0 pymongo==2.8 -pyOpenSSL==0.15.1 +pyOpenSSL==16.0.0 +cffi==1.7.0 pyparsing==2.0.7 pyrad==2.0 pyrax==1.9.7 @@ -131,3 +132,6 @@ wheel==0.24.0 wrapt==1.10.6 wsgiref==0.1.2 xmltodict==0.9.2 +channels==0.17.2 +asgi_amqp==0.3 +