text:
import dateutil.relativedelta
from django.utils import timezone
import mock
from nose.tools import *  # noqa:
import pytest
from urlparse import urlparse

from api.base.settings.defaults import API_BASE
from api_tests.nodes.views.test_node_draft_registration_list import DraftRegistrationTestCase
from api_tests.subjects.mixins import SubjectsFilterMixin
from api_tests.registrations.filters.test_filters import RegistrationListFilteringMixin
from framework.auth.core import Auth
from osf.models import RegistrationSchema, DraftRegistration
from osf_tests.factories import (
    EmbargoFactory,
    ProjectFactory,
    RegistrationFactory,
    AuthUserFactory,
    CollectionFactory,
    DraftRegistrationFactory,
    OSFGroupFactory,
)
from rest_framework import exceptions
from tests.base import ApiTestCase
from website.views import find_bookmark_collection
from osf.utils import permissions

SCHEMA_VERSION = 2

@pytest.mark.enable_quickfiles_creation
class TestRegistrationList(ApiTestCase):

    def setUp(self):
        super(TestRegistrationList, self).setUp()
        self.user = AuthUserFactory()

        self.project = ProjectFactory(is_public=False, creator=self.user)
        self.registration_project = RegistrationFactory(
            creator=self.user, project=self.project)
        self.url = '/{}registrations/'.format(API_BASE)

        self.public_project = ProjectFactory(is_public=True, creator=self.user)
        self.public_registration_project = RegistrationFactory(
            creator=self.user, project=self.public_project, is_public=True)
        self.user_two = AuthUserFactory()

    def test_return_public_registrations_logged_out(self):
        res = self.app.get(self.url)
        assert_equal(len(res.json['data']), 1)
        assert_equal(res.status_code, 200)
        assert_equal(res.status_code, 200)
        assert_equal(res.content_type, 'application/vnd.api+json')
        url = res.json['data'][0]['relationships']['registered_from']['links']['related']['href']
        assert_equal(
            urlparse(url).path,
            '/{}nodes/{}/'.format(API_BASE, self.public_project._id)
        )

    def test_return_registrations_logged_in_contributor(self):
        res = self.app.get(self.url, auth=self.user.auth)
        assert_equal(len(res.json['data']), 2)
        assert_equal(res.status_code, 200)

        registered_from_one = urlparse(
            res.json['data'][0]['relationships']['registered_from']['links']['related']['href']).path
        registered_from_two = urlparse(
            res.json['data'][1]['relationships']['registered_from']['links']['related']['href']).path

        assert_equal(res.content_type, 'application/vnd.api+json')

        assert_items_equal(
            [registered_from_one, registered_from_two],
            ['/{}nodes/{}/'.format(API_BASE, self.public_project._id),
             '/{}nodes/{}/'.format(API_BASE, self.project._id)]
        )

    def test_return_registrations_logged_in_non_contributor(self):
        res = self.app.get(self.url, auth=self.user_two.auth)
        assert_equal(len(res.json['data']), 1)
        assert_equal(res.status_code, 200)
        registered_from = urlparse(
            res.json['data'][0]['relationships']['registered_from']['links']['related']['href']).path

        assert_equal(res.content_type, 'application/vnd.api+json')

        assert_equal(
            registered_from,
            '/{}nodes/{}/'.format(API_BASE, self.public_project._id))

    def test_total_biographic_contributor_in_registration(self):
        user3 = AuthUserFactory()
        registration = RegistrationFactory(is_public=True, creator=self.user)
        registration.add_contributor(self.user_two, auth=Auth(self.user))
        registration.add_contributor(
            user3, auth=Auth(self.user), visible=False)
        registration.save()
        registration_url = '/{0}registrations/{1}/?embed=contributors'.format(
            API_BASE, registration._id)

        res = self.app.get(registration_url)
        assert_true(
            res.json['data']['embeds']['contributors']['links']['meta']['total_bibliographic']
        )
        assert_equal(
            res.json['data']['embeds']['contributors']['links']['meta']['total_bibliographic'], 2
        )

    def test_exclude_nodes_from_registrations_endpoint(self):
        res = self.app.get(self.url, auth=self.user.auth)
        ids = [each['id'] for each in res.json['data']]
        assert_in(self.registration_project._id, ids)
        assert_in(self.public_registration_project._id, ids)
        assert_not_in(self.public_project._id, ids)
        assert_not_in(self.project._id, ids)

@pytest.mark.enable_bookmark_creation
class TestRegistrationFiltering(ApiTestCase):

    def setUp(self):
        super(TestRegistrationFiltering, self).setUp()
        self.user_one = AuthUserFactory()
        self.user_two = AuthUserFactory()
        self.project_one = ProjectFactory(
            title='Project One',
            description='Two',
            is_public=True,
            creator=self.user_one,
            category='hypothesis')
        self.project_two = ProjectFactory(
            title='Project Two',
            description='One Three',
            is_public=True,
            creator=self.user_one)
        self.project_three = ProjectFactory(
            title='Three',
            description='',
            is_public=True,
            creator=self.user_two
        )

        self.private_project_user_one = ProjectFactory(
            title='Private Project User One', is_public=False, creator=self.user_one)
        self.private_project_user_two = ProjectFactory(
            title='Private Project User Two', is_public=False, creator=self.user_two)

        self.project_one.add_tag('tag1', Auth(
            self.project_one.creator), save=False)
        self.project_one.add_tag('tag2', Auth(
            self.project_one.creator), save=False)
        self.project_one.save()
        self.project_two.add_tag('tag1', Auth(
            self.project_two.creator), save=True)
        self.project_two.save()

        self.project_one_reg = RegistrationFactory(
            creator=self.user_one, project=self.project_one, is_public=True)
        self.project_two_reg = RegistrationFactory(
            creator=self.user_one, project=self.project_two, is_public=True)
        self.project_three_reg = RegistrationFactory(
            creator=self.user_two, project=self.project_three, is_public=True, title='No search terms!')
        self.private_project_user_one_reg = RegistrationFactory(
            creator=self.user_one, project=self.private_project_user_one, is_public=False, title='No search terms!')
        self.private_project_user_two_reg = RegistrationFactory(
            creator=self.user_two, project=self.private_project_user_two, is_public=False, title='No search terms!')

        self.folder = CollectionFactory()
        self.bookmark_collection = find_bookmark_collection(self.user_one)

        self.url = '/{}registrations/'.format(API_BASE)

    def test_filtering_by_category(self):
        url = '/{}registrations/?filter[category]=hypothesis'.format(API_BASE)
        res = self.app.get(url, auth=self.user_one.auth)
        registration_json = res.json['data']
        ids = [each['id'] for each in registration_json]

        assert_in(self.project_one_reg._id, ids)
        assert_not_in(self.project_two_reg._id, ids)
        assert_not_in(self.project_three_reg._id, ids)
        assert_not_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

    def test_filtering_by_public(self):
        url = '/{}registrations/?filter[public]=false'.format(API_BASE)
        res = self.app.get(url, auth=self.user_one.auth)
        reg_json = res.json['data']

        # No public projects returned
        assert_false(
            any([each['attributes']['public'] for each in reg_json])
        )

        ids = [each['id'] for each in reg_json]
        assert_not_in(self.project_one_reg._id, ids)
        assert_not_in(self.project_two_reg._id, ids)

        url = '/{}registrations/?filter[public]=true'.format(API_BASE)
        res = self.app.get(url, auth=self.user_one.auth)
        reg_json = res.json['data']

        # No private projects returned
        assert_true(
            all([each['attributes']['public'] for each in reg_json])
        )

        ids = [each['id'] for each in reg_json]
        assert_in(self.project_one_reg._id, ids)
        assert_in(self.project_two_reg._id, ids)
        assert_in(self.project_three_reg._id, ids)
        assert_not_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

    def test_filtering_tags(self):

        # both project_one and project_two have tag1
        url = '/{}registrations/?filter[tags]={}'.format(API_BASE, 'tag1')

        res = self.app.get(url, auth=self.project_one.creator.auth)
        reg_json = res.json['data']

        ids = [each['id'] for each in reg_json]
        assert_in(self.project_one_reg._id, ids)
        assert_in(self.project_two_reg._id, ids)
        assert_not_in(self.project_three_reg._id, ids)
        assert_not_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

        # filtering two tags
        # project_one has both tags; project_two only has one
        url = '/{}registrations/?filter[tags]={}&filter[tags]={}'.format(
            API_BASE, 'tag1', 'tag2')

        res = self.app.get(url, auth=self.project_one.creator.auth)
        reg_json = res.json['data']

        ids = [each['id'] for each in reg_json]
        assert_in(self.project_one_reg._id, ids)
        assert_not_in(self.project_two_reg._id, ids)
        assert_not_in(self.project_three_reg._id, ids)
        assert_not_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

    def test_filtering_tags_exact(self):
        self.project_one.add_tag('cats', Auth(self.user_one))
        self.project_two.add_tag('cats', Auth(self.user_one))
        self.project_one.add_tag('cat', Auth(self.user_one))
        self.project_one_reg = RegistrationFactory(
            creator=self.user_one, project=self.project_one, is_public=True)
        self.project_two_reg = RegistrationFactory(
            creator=self.user_one, project=self.project_two, is_public=True)
        res = self.app.get(
            '/{}registrations/?filter[tags]=cat'.format(
                API_BASE
            ),
            auth=self.user_one.auth
        )
        assert_equal(len(res.json.get('data')), 1)

    def test_filtering_tags_capitalized_query(self):
        self.project_one.add_tag('cat', Auth(self.user_one))
        self.project_one_reg = RegistrationFactory(
            creator=self.user_one, project=self.project_one, is_public=True)
        res = self.app.get(
            '/{}registrations/?filter[tags]=CAT'.format(
                API_BASE
            ),
            auth=self.user_one.auth
        )
        assert_equal(len(res.json.get('data')), 1)

    def test_filtering_tags_capitalized_tag(self):
        self.project_one.add_tag('CAT', Auth(self.user_one))
        self.project_one_reg = RegistrationFactory(
            creator=self.user_one, project=self.project_one, is_public=True)
        res = self.app.get(
            '/{}registrations/?filter[tags]=cat'.format(
                API_BASE
            ),
            auth=self.user_one.auth
        )
        assert_equal(len(res.json.get('data')), 1)

    def test_filtering_on_multiple_tags(self):
        self.project_one.add_tag('cat', Auth(self.user_one))
        self.project_one.add_tag('sand', Auth(self.user_one))
        self.project_one_reg = RegistrationFactory(
            creator=self.user_one, project=self.project_one, is_public=True)
        res = self.app.get(
            '/{}registrations/?filter[tags]=cat&filter[tags]=sand'.format(
                API_BASE
            ),
            auth=self.user_one.auth
        )
        assert_equal(len(res.json.get('data')), 1)

    def test_filtering_on_multiple_tags_must_match_both(self):
        self.project_one.add_tag('cat', Auth(self.user_one))
        self.project_one_reg = RegistrationFactory(
            creator=self.user_one, project=self.project_one, is_public=True)
        res = self.app.get(
            '/{}registrations/?filter[tags]=cat&filter[tags]=sand'.format(
                API_BASE
            ),
            auth=self.user_one.auth
        )
        assert_equal(len(res.json.get('data')), 0)

    def test_filtering_tags_returns_distinct(self):
        # regression test for returning multiple of the same file
        self.project_one.add_tag('cat', Auth(self.user_one))
        self.project_one.add_tag('cAt', Auth(self.user_one))
        self.project_one.add_tag('caT', Auth(self.user_one))
        self.project_one.add_tag('CAT', Auth(self.user_one))
        self.project_one_reg = RegistrationFactory(
            creator=self.user_one, project=self.project_one, is_public=True, title='No search terms!')
        res = self.app.get(
            '/{}registrations/?filter[tags]=cat'.format(
                API_BASE
            ),
            auth=self.user_one.auth
        )
        assert_equal(len(res.json.get('data')), 1)

    def test_filtering_contributors(self):
        res = self.app.get(
            '/{}registrations/?filter[contributors]={}'.format(
                API_BASE, self.user_one._id
            ),
            auth=self.user_one.auth
        )
        assert_equal(len(res.json.get('data')), 3)

    def test_filtering_contributors_bad_id(self):
        res = self.app.get(
            '/{}registrations/?filter[contributors]=acatdresseduplikeahuman'.format(
                API_BASE
            ),
            auth=self.user_one.auth
        )
        assert_equal(len(res.json.get('data')), 0)

    def test_get_all_registrations_with_no_filter_logged_in(self):
        res = self.app.get(self.url, auth=self.user_one.auth)
        reg_json = res.json['data']

        ids = [each['id'] for each in reg_json]
        assert_in(self.project_one_reg._id, ids)
        assert_in(self.project_two_reg._id, ids)
        assert_in(self.project_three_reg._id, ids)
        assert_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

        assert_not_in(self.project_one._id, ids)
        assert_not_in(self.project_two._id, ids)
        assert_not_in(self.project_three._id, ids)
        assert_not_in(self.private_project_user_one._id, ids)
        assert_not_in(self.private_project_user_two._id, ids)
        assert_not_in(self.folder._id, ids)
        assert_not_in(self.bookmark_collection._id, ids)

    def test_get_all_registrations_with_no_filter_not_logged_in(self):
        res = self.app.get(self.url)
        reg_json = res.json['data']

        ids = [each['id'] for each in reg_json]
        assert_in(self.project_one_reg._id, ids)
        assert_in(self.project_two_reg._id, ids)
        assert_in(self.project_three_reg._id, ids)
        assert_not_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

        assert_not_in(self.project_one._id, ids)
        assert_not_in(self.project_two._id, ids)
        assert_not_in(self.project_three._id, ids)
        assert_not_in(self.private_project_user_one._id, ids)
        assert_not_in(self.private_project_user_two._id, ids)
        assert_not_in(self.folder._id, ids)
        assert_not_in(self.bookmark_collection._id, ids)

    def test_get_one_registration_with_exact_filter_logged_in(self):
        url = '/{}registrations/?filter[title]=Project%20One'.format(API_BASE)

        res = self.app.get(url, auth=self.user_one.auth)
        reg_json = res.json['data']

        ids = [each['id'] for each in reg_json]
        assert_in(self.project_one_reg._id, ids)
        assert_not_in(self.project_two_reg._id, ids)
        assert_not_in(self.project_three_reg._id, ids)
        assert_not_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

        assert_not_in(self.folder._id, ids)
        assert_not_in(self.bookmark_collection._id, ids)

    def test_get_one_registration_with_exact_filter_not_logged_in(self):
        url = '/{}registrations/?filter[title]=Private%20Project%20User%20One'.format(
            API_BASE)

        res = self.app.get(url)
        reg_json = res.json['data']

        ids = [each['id'] for each in reg_json]
        assert_not_in(self.project_one_reg._id, ids)
        assert_not_in(self.project_two_reg._id, ids)
        assert_not_in(self.project_three_reg._id, ids)
        assert_not_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

        assert_not_in(self.folder._id, ids)
        assert_not_in(self.bookmark_collection._id, ids)

    def test_get_some_registrations_with_substring_logged_in(self):
        url = '/{}registrations/?filter[title]=Two'.format(API_BASE)

        res = self.app.get(url, auth=self.user_one.auth)
        reg_json = res.json['data']

        ids = [each['id'] for each in reg_json]
        assert_not_in(self.project_one_reg._id, ids)
        assert_in(self.project_two_reg._id, ids)
        assert_not_in(self.project_three_reg._id, ids)
        assert_not_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

        assert_not_in(self.folder._id, ids)
        assert_not_in(self.bookmark_collection._id, ids)

    def test_get_some_registrations_with_substring_not_logged_in(self):
        url = '/{}registrations/?filter[title]=One'.format(API_BASE)

        res = self.app.get(url)
        reg_json = res.json['data']

        ids = [each['id'] for each in reg_json]
        assert_in(self.project_one_reg._id, ids)
        assert_not_in(self.project_two_reg._id, ids)
        assert_not_in(self.project_three_reg._id, ids)
        assert_not_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

        assert_not_in(self.folder._id, ids)
        assert_not_in(self.bookmark_collection._id, ids)

    def test_get_only_public_or_my_registrations_with_filter_logged_in(self):
        url = '/{}registrations/?filter[title]=Project'.format(API_BASE)

        res = self.app.get(url, auth=self.user_one.auth)
        reg_json = res.json['data']

        ids = [each['id'] for each in reg_json]
        assert_in(self.project_one_reg._id, ids)
        assert_in(self.project_two_reg._id, ids)
        assert_not_in(self.project_three_reg._id, ids)
        assert_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

        assert_not_in(self.folder._id, ids)
        assert_not_in(self.bookmark_collection._id, ids)

    def test_get_only_public_registrations_with_filter_not_logged_in(self):
        url = '/{}registrations/?filter[title]=Project'.format(API_BASE)

        res = self.app.get(url)
        reg_json = res.json['data']

        ids = [each['id'] for each in reg_json]
        assert_in(self.project_one_reg._id, ids)
        assert_in(self.project_two_reg._id, ids)
        assert_not_in(self.project_three_reg._id, ids)
        assert_not_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

        assert_not_in(self.folder._id, ids)
        assert_not_in(self.bookmark_collection._id, ids)

    def test_alternate_filtering_field_logged_in(self):
        url = '/{}registrations/?filter[description]=Three'.format(API_BASE)

        res = self.app.get(url, auth=self.user_one.auth)
        reg_json = res.json['data']

        ids = [each['id'] for each in reg_json]
        assert_not_in(self.project_one_reg._id, ids)
        assert_in(self.project_two_reg._id, ids)
        assert_not_in(self.project_three_reg._id, ids)
        assert_not_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

        assert_not_in(self.folder._id, ids)
        assert_not_in(self.bookmark_collection._id, ids)

    def test_alternate_filtering_field_not_logged_in(self):
        url = '/{}registrations/?filter[description]=Two'.format(API_BASE)

        res = self.app.get(url)
        reg_json = res.json['data']

        ids = [each['id'] for each in reg_json]
        assert_in(self.project_one_reg._id, ids)
        assert_not_in(self.project_two_reg._id, ids)
        assert_not_in(self.project_three_reg._id, ids)
        assert_not_in(self.private_project_user_one_reg._id, ids)
        assert_not_in(self.private_project_user_two_reg._id, ids)

        assert_not_in(self.folder._id, ids)
        assert_not_in(self.bookmark_collection._id, ids)

    def test_incorrect_filtering_field_not_logged_in(self):
        url = '/{}registrations/?filter[notafield]=bogus'.format(API_BASE)

        res = self.app.get(url, expect_errors=True)
        assert_equal(res.status_code, 400)
        errors = res.json['errors']
        assert_equal(len(errors), 1)
        assert_equal(
            errors[0]['detail'],
            "'notafield' is not a valid field for this endpoint.")

class TestRegistrationSubjectFiltering(SubjectsFilterMixin):
    @pytest.fixture()
    def resource(self, user):
        return RegistrationFactory(creator=user)

    @pytest.fixture()
    def resource_two(self, user):
        return RegistrationFactory(creator=user)

    @pytest.fixture()
    def url(self):
        return '/{}registrations/'.format(API_BASE)

class TestRegistrationCreate(DraftRegistrationTestCase):

    @pytest.fixture()
    def schema(self):
        return RegistrationSchema.objects.get(
            name='Replication Recipe (Brandt et al., 2013): Post-Completion',
            schema_version=SCHEMA_VERSION)

    @pytest.fixture()
    def project_public_child(self, project_public):
        return ProjectFactory(parent=project_public)

    @pytest.fixture()
    def project_public_grandchild(self, project_public_child):
        return ProjectFactory(parent=project_public_child)

    @pytest.fixture()
    def project_public_excluded_sibling(self, project_public):
        return ProjectFactory(parent=project_public)

    @pytest.fixture()
    def draft_registration(self, user, project_public, schema):
        return DraftRegistrationFactory(
            initiator=user,
            registration_schema=schema,
            branched_from=project_public,
            registration_metadata={
                'item29': {'value': 'Yes'},
                'item33': {'value': 'success'}
            }
        )

    @pytest.fixture()
    def url_registrations(self, project_public):
        return '/{}nodes/{}/registrations/'.format(
            API_BASE, project_public._id)

    @pytest.fixture()
    def payload(self, draft_registration):
        return {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'draft_registration': draft_registration._id,
                    'registration_choice': 'immediate'
                }
            }
        }

    @pytest.fixture()
    def payload_with_children(self, draft_registration, project_public_child, project_public_grandchild):
        return {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'draft_registration': draft_registration._id,
                    'children': [project_public_child._id, project_public_grandchild._id],
                    'registration_choice': 'immediate'

                }
            }
        }

    @pytest.fixture()
    def payload_with_grandchildren_but_no_children(self, draft_registration, project_public_child, project_public_grandchild):
        return {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'draft_registration': draft_registration._id,
                    'children': [project_public_grandchild._id],
                    'registration_choice': 'immediate'

                }
            }
        }

    @pytest.fixture()
    def payload_with_bad_child_node_guid(self, draft_registration):
        return {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'draft_registration': draft_registration._id,
                    'children': ['fake0', 'fake3'],
                    'registration_choice': 'immediate'

                }
            }
        }

    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_admin_can_create_registration(
            self, mock_enqueue, app, user, payload, url_registrations):
        res = app.post_json_api(url_registrations, payload, auth=user.auth)
        data = res.json['data']['attributes']
        assert res.status_code == 201
        assert data['registration'] is True
        assert data['pending_registration_approval'] is True
        assert data['public'] is False

    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_admin_can_create_registration_with_specific_children(
            self, mock_enqueue, app, user, payload_with_children, project_public, project_public_child, project_public_excluded_sibling, project_public_grandchild, url_registrations):
        res = app.post_json_api(url_registrations, payload_with_children, auth=user.auth)
        data = res.json['data']['attributes']
        assert res.status_code == 201
        assert data['registration'] is True
        assert data['pending_registration_approval'] is True
        assert data['public'] is False

        assert project_public.registrations.all().count() == 1
        assert project_public_child.registrations.all().count() == 1
        assert project_public_grandchild.registrations.all().count() == 1
        assert project_public_excluded_sibling.registrations.all().count() == 0

    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_admin_400_with_bad_child_node_guid(
            self, mock_enqueue, app, user, payload_with_bad_child_node_guid, url_registrations):
        res = app.post_json_api(url_registrations, payload_with_bad_child_node_guid, auth=user.auth, expect_errors=True)

        assert res.status_code == 400
        assert res.json['errors'][0]['detail'] == 'Some child nodes could not be found.'

    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_admin_cant_register_grandchildren_without_children(
            self, mock_enqueue, app, user, payload_with_grandchildren_but_no_children, url_registrations, project_public_grandchild):
        res = app.post_json_api(url_registrations, payload_with_grandchildren_but_no_children, auth=user.auth, expect_errors=True)

        assert res.status_code == 400
        assert res.json['errors'][0]['detail'] == 'The parents of all child nodes being registered must be registered.'

    def test_cannot_create_registration(
            self, app, user_write_contrib, user_read_contrib,
            payload, url_registrations, project_public):

        # def test_write_only_contributor_cannot_create_registration(self):
        res = app.post_json_api(
            url_registrations,
            payload,
            auth=user_write_contrib.auth,
            expect_errors=True)
        assert res.status_code == 403

    # def test_read_only_contributor_cannot_create_registration(self):
        res = app.post_json_api(
            url_registrations,
            payload,
            auth=user_read_contrib.auth,
            expect_errors=True)
        assert res.status_code == 403

    # def test_non_authenticated_user_cannot_create_registration(self):
        res = app.post_json_api(url_registrations, payload, expect_errors=True)
        assert res.status_code == 401

        # admin via a group cannot create registration
        group_mem = AuthUserFactory()
        group = OSFGroupFactory(creator=group_mem)
        project_public.add_osf_group(group, permissions.ADMIN)
        res = app.post_json_api(url_registrations, payload, auth=group_mem.auth, expect_errors=True)
        assert res.status_code == 403

    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_registration_draft_must_be_specified(
            self, mock_enqueue, app, user, url_registrations):
        payload = {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'registration_choice': 'immediate'
                }
            }
        }
        res = app.post_json_api(
            url_registrations,
            payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 400
        assert res.json['errors'][0]['source']['pointer'] == '/data/attributes/draft_registration'
        assert res.json['errors'][0]['detail'] == 'This field is required.'

    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_registration_draft_must_be_valid(
            self, mock_enqueue, app, user, url_registrations):
        payload = {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'registration_choice': 'immediate',
                    'draft_registration': '12345'
                }
            }
        }
        res = app.post_json_api(
            url_registrations,
            payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 404

    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_registration_draft_must_be_draft_of_current_node(
            self, mock_enqueue, app, user, schema, url_registrations):
        project_new = ProjectFactory(creator=user)
        draft_registration = DraftRegistrationFactory(
            initiator=user,
            registration_schema=schema,
            branched_from=project_new,
            registration_metadata={
                'item29': {'value': 'Yes'},
                'item33': {'value': 'success'}
            }
        )
        payload = {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'registration_choice': 'immediate',
                    'draft_registration': draft_registration._id
                }
            }
        }
        res = app.post_json_api(
            url_registrations,
            payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 400
        assert res.json['errors'][0]['detail'] == 'This draft registration is not created from the given node.'

    @pytest.mark.skip('TEMPORARY: Unskip when JSON Schemas are updated')
    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_required_top_level_questions_must_be_answered_on_draft(
            self, mock_enqueue, app, user, project_public,
            prereg_metadata, url_registrations):
        prereg_schema = RegistrationSchema.objects.get(
            name='Prereg Challenge',
            schema_version=SCHEMA_VERSION)

        prereg_draft_registration = DraftRegistrationFactory(
            initiator=user,
            registration_schema=prereg_schema,
            branched_from=project_public
        )

        registration_metadata = prereg_metadata(prereg_draft_registration)
        del registration_metadata['q1']
        prereg_draft_registration.registration_metadata = registration_metadata
        prereg_draft_registration.save()

        payload = {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'registration_choice': 'immediate',
                    'draft_registration': prereg_draft_registration._id,
                }
            }
        }

        res = app.post_json_api(
            url_registrations,
            payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 400
        assert res.json['errors'][0]['detail'] == 'For your registration the \'Title\' field is required'

    @pytest.mark.skip('TEMPORARY: Unskip when JSON Schemas are updated')
    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_required_second_level_questions_must_be_answered_on_draft(
            self, mock_enqueue, app, user, project_public, prereg_metadata, url_registrations):
        prereg_schema = RegistrationSchema.objects.get(
            name='Prereg Challenge',
            schema_version=SCHEMA_VERSION)

        prereg_draft_registration = DraftRegistrationFactory(
            initiator=user,
            registration_schema=prereg_schema,
            branched_from=project_public
        )

        registration_metadata = prereg_metadata(prereg_draft_registration)
        registration_metadata['q11'] = {'value': {}}
        prereg_draft_registration.registration_metadata = registration_metadata
        prereg_draft_registration.save()

        payload = {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'registration_choice': 'immediate',
                    'draft_registration': prereg_draft_registration._id,
                }
            }
        }

        res = app.post_json_api(
            url_registrations, payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 400
        assert res.json['errors'][0]['detail'] == 'For your registration your response to the \'Manipulated variables\' field is invalid.'

    @pytest.mark.skip('TEMPORARY: Unskip when JSON Schemas are updated')
    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_required_third_level_questions_must_be_answered_on_draft(
            self, mock_enqueue, app, user, project_public,
            prereg_metadata, url_registrations):
        prereg_schema = RegistrationSchema.objects.get(
            name='Prereg Challenge',
            schema_version=SCHEMA_VERSION)

        prereg_draft_registration = DraftRegistrationFactory(
            initiator=user,
            registration_schema=prereg_schema,
            branched_from=project_public
        )

        registration_metadata = prereg_metadata(prereg_draft_registration)
        registration_metadata['q11'] = {'value': {'question': {}}}

        prereg_draft_registration.registration_metadata = registration_metadata
        prereg_draft_registration.save()

        payload = {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'registration_choice': 'immediate',
                    'draft_registration': prereg_draft_registration._id,
                }
            }
        }

        res = app.post_json_api(
            url_registrations, payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 400
        assert res.json['errors'][0]['detail'] == 'For your registration your response to the \'Manipulated variables\' field is invalid.'

    @pytest.mark.skip('TEMPORARY: Unskip when JSON Schemas are updated')
    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_multiple_choice_in_registration_schema_must_match_one_of_choices(
            self, mock_enqueue, app, user, project_public, schema, payload, url_registrations):
        draft_registration = DraftRegistrationFactory(
            initiator=user,
            registration_schema=schema,
            branched_from=project_public,
            registration_metadata={
                'item29': {'value': 'Yes'},
                'item33': {'value': 'success!'}
            }
        )
        payload['data']['attributes']['draft_registration'] = draft_registration._id
        res = app.post_json_api(
            url_registrations,
            payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 400
        assert (
            res.json['errors'][0]['detail'] == 'For your registration your response to the \'I judge the replication to be a(n)\''
                                               ' field is invalid, your response must be one of the provided options.')

    def test_invalid_registration_choice(
            self, app, user, draft_registration, url_registrations):
        payload = {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'draft_registration': draft_registration._id,
                    'registration_choice': 'tomorrow'
                }
            }
        }
        res = app.post_json_api(
            url_registrations, payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 400
        assert res.json['errors'][0]['source']['pointer'] == '/data/attributes/registration_choice'
        assert res.json['errors'][0]['detail'] == '"tomorrow" is not a valid choice.'

        @mock.patch('framework.celery_tasks.handlers.enqueue_task')
        def test_embargo_end_date_provided_if_registration_choice_is_embargo(
                self, mock_enqueue, app, user, draft_registration, url_registrations):
            payload = {
                'data': {
                    'type': 'registrations',
                    'attributes': {
                        'draft_registration': draft_registration._id,
                        'registration_choice': 'embargo'
                    }
                }
            }

            res = app.post_json_api(
                url_registrations,
                payload,
                auth=user.auth,
                expect_errors=True)
            assert res.status_code == 400
            assert res.json['errors'][0]['detail'] == 'lift_embargo must be specified.'

    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_embargo_must_be_less_than_four_years(
            self, mock_enqueue, app, user, draft_registration,
            url_registrations):
        today = timezone.now()
        five_years = (
            today +
            dateutil.relativedelta.relativedelta(
                years=5)).strftime('%Y-%m-%dT%H:%M:%S')
        payload = {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'draft_registration': draft_registration._id,
                    'registration_choice': 'embargo',
                    'lift_embargo': five_years
                }
            }
        }

        res = app.post_json_api(
            url_registrations,
            payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 400
        assert res.json['errors'][0]['detail'] == 'Registrations can only be embargoed for up to four years.'

    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_embargo_registration(
            self, mock_enqueue, app, user,
            draft_registration, url_registrations):
        today = timezone.now()
        next_week = (
            today +
            dateutil.relativedelta.relativedelta(
                months=1)).strftime('%Y-%m-%dT%H:%M:%S')
        payload = {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'draft_registration': draft_registration._id,
                    'registration_choice': 'embargo',
                    'lift_embargo': next_week
                }
            }
        }

        res = app.post_json_api(
            url_registrations,
            payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 201
        data = res.json['data']['attributes']
        assert data['registration'] is True
        assert data['pending_embargo_approval'] is True

    def test_embargo_end_date_must_be_in_the_future(
            self, app, user, draft_registration, url_registrations):
        today = timezone.now().strftime('%Y-%m-%dT%H:%M:%S')
        payload = {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'draft_registration': draft_registration._id,
                    'registration_choice': 'embargo',
                    'lift_embargo': today
                }
            }
        }

        res = app.post_json_api(
            url_registrations,
            payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 400
        assert res.json['errors'][0]['detail'] == 'Embargo end date must be at least three days in the future.'

    def test_invalid_embargo_end_date_format(
            self, app, user, draft_registration, url_registrations):
        today = timezone.now().isoformat()
        payload = {
            'data': {
                'type': 'registrations',
                'attributes': {
                    'draft_registration': draft_registration._id,
                    'registration_choice': 'embargo',
                    'lift_embargo': today
                }
            }
        }

        res = app.post_json_api(
            url_registrations,
            payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 400
        assert res.json['errors'][0]['detail'] == 'Datetime has wrong format. Use one of these formats instead: YYYY-MM-DDThh:mm:ss.'

    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_cannot_register_draft_that_has_already_been_registered(
            self, mock_enqueue, app, user, payload, draft_registration, url_registrations):
        draft_registration.register(auth=Auth(user), save=True)
        res = app.post_json_api(
            url_registrations,
            payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 403
        assert res.json['errors'][0]['detail'] == 'This draft has already been registered and cannot be modified.'

    @mock.patch('framework.celery_tasks.handlers.enqueue_task')
    def test_cannot_register_draft_that_is_pending_review(
            self, mock_enqueue, app, user, payload, url_registrations):
        with mock.patch.object(DraftRegistration, 'is_pending_review', mock.PropertyMock(return_value=True)):
            res = app.post_json_api(
                url_registrations,
                payload,
                auth=user.auth,
                expect_errors=True)
        assert res.status_code == 403
        assert res.json['errors'][0]['detail'] == 'This draft is pending review and cannot be modified.'

    def test_cannot_register_draft_that_has_already_been_approved(
            self, app, user, payload, url_registrations):
        with mock.patch.object(DraftRegistration, 'requires_approval', mock.PropertyMock(return_value=True)), mock.patch.object(DraftRegistration, 'is_approved', mock.PropertyMock(return_value=True)):
            res = app.post_json_api(
                url_registrations,
                payload,
                auth=user.auth,
                expect_errors=True)
        assert res.status_code == 403
        assert res.json['errors'][0]['detail'] == 'This draft has already been approved and cannot be modified.'

    def test_cannot_register_draft_that_has_orphan_files(
            self, app, user, payload, draft_registration, url_registrations):
        schema = draft_registration.registration_schema
        schema.schema['pages'][0]['questions'][0].update({
            u'description': u'Upload files!',
            u'format': u'osf-upload-open',
            u'qid': u'qwhatever',
            u'title': u'Upload an analysis script with clear comments',
            u'type': u'osf-upload',
        })
        schema.save()

        draft_registration.registration_metadata = {
            'qwhatever': {
                'value': 'file 1',
                'extra': [{
                    'nodeId': 'badid',
                    'selectedFileName': 'file 1',
                }]
            }
        }
        draft_registration.save()
        res = app.post_json_api(
            url_registrations,
            payload,
            auth=user.auth,
            expect_errors=True)
        assert res.status_code == 400
        assert res.json['errors'][0]['detail'] == 'All files attached to this form must be registered to complete the' \
                                                  ' process. The following file(s) are attached, but are not part of' \
                                                  ' a component being registered: file 1'

@pytest.mark.django_db
class TestRegistrationBulkUpdate:

    @pytest.fixture()
    def url(self):
        return '/{}registrations/'.format(API_BASE)

    @pytest.fixture()
    def user(self):
        return AuthUserFactory()

    @pytest.fixture()
    def registration_one(self, user):
        return RegistrationFactory(
            creator=user,
            title='Birds',
            embargo=EmbargoFactory(
                user=user),
            is_public=False)

    @pytest.fixture()
    def registration_two(self, user):
        return RegistrationFactory(
            creator=user,
            title='Birds II',
            embargo=EmbargoFactory(
                user=user),
            is_public=False)

    @pytest.fixture()
    def private_payload(self, registration_one, registration_two):
        return {
            'data': [
                {
                    'id': registration_one._id,
                    'type': 'registrations',
                    'attributes': {
                        'public': False
                    }
                },
                {
                    'id': registration_two._id,
                    'type': 'registrations',
                    'attributes': {
                        'public': False
                    }
                }
            ]
        }

    @pytest.fixture()
    def public_payload(self, registration_one, registration_two):
        return {
            'data': [
                {
                    'id': registration_one._id,
                    'type': 'registrations',
                    'attributes': {
                        'public': True
                    }
                },
                {
                    'id': registration_two._id,
                    'type': 'registrations',
                    'attributes': {
                        'public': True
                    }
                }
            ]
        }

    @pytest.fixture()
    def empty_payload(self, registration_one, registration_two):
        return {
            'data': [
                {
                    'id': registration_one._id,
                    'type': 'registrations',
                    'attributes': {}
                },
                {
                    'id': registration_two._id,
                    'type': 'registrations',
                    'attributes': {}
                }
            ]
        }

    @pytest.fixture()
    def bad_payload(self, registration_one, registration_two):
        return {
            'data': [
                {
                    'id': registration_one._id,
                    'type': 'registrations',
                    'attributes': {
                        'public': True,
                    }
                },
                {
                    'id': registration_two._id,
                    'type': 'registrations',
                    'attributes': {
                        'title': 'Nerds II: Attack of the Nerds',
                    }
                }
            ]
        }

    def test_bulk_update_errors(
            self, app, user, registration_one, registration_two,
            public_payload, private_payload, url):

        # test_bulk_update_registrations_blank_request
        res = app.put_json_api(
            url,
            auth=user.auth,
            expect_errors=True,
            bulk=True)
        assert res.status_code == 400

        # test_bulk_update_registrations_one_not_found
        payload = {'data': [
            {
                'id': '12345',
                'type': 'registrations',
                'attributes': {
                    'public': True,
                }
            }, public_payload['data'][0]
        ]}

        res = app.put_json_api(
            url, payload,
            auth=user.auth,
            expect_errors=True,
            bulk=True)
        assert res.status_code == 400
        assert res.json['errors'][0]['detail'] == 'Could not find all objects to update.'

        # test_bulk_update_registrations_logged_out
        res = app.put_json_api(
            url, public_payload,
            expect_errors=True,
            bulk=True)
        assert res.status_code == 401
        assert res.json['errors'][0]['detail'] == exceptions.NotAuthenticated.default_detail

        # test_bulk_update_registrations_logged_in_non_contrib
        non_contrib = AuthUserFactory()
        res = app.put_json_api(
            url, private_payload,
            auth=non_contrib.auth,
            expect_errors=True,
            bulk=True)
        assert res.status_code == 403
        assert res.json['errors'][0]['detail'] == exceptions.PermissionDenied.default_detail

        # test_bulk_update_registrations_send_dictionary_not_list
        res = app.put_json_api(
            url, {
                'data': {
                    'id': registration_one._id,
                    'type': 'nodes',
                    'attributes': {'public': True}
                }
            },
            auth=user.auth,
            expect_errors=True, bulk=True)
        assert res.status_code == 400
        assert res.json['errors'][0]['detail'] == 'Expected a list of items but got type "dict".'

        # test_bulk_update_id_not_supplied
        res = app.put_json_api(
            url, {
                'data': [
                    public_payload['data'][1], {
                        'type': 'registrations',
                        'attributes': {'public': True}}
                ]
            },
            auth=user.auth,
            expect_errors=True, bulk=True)
        assert res.status_code == 400
        assert len(res.json['errors']) == 1
        assert res.json['errors'][0]['source']['pointer'] == '/data/1/id'
        assert res.json['errors'][0]['detail'] == 'This field may not be null.'

        # test_bulk_update_type_not_supplied
        res = app.put_json_api(
            url, {
                'data': [
                    public_payload['data'][1], {
                        'id': registration_one._id,
                        'attributes': {'public': True}
                    }
                ]
            }, auth=user.auth,
            expect_errors=True, bulk=True)
        assert res.status_code == 400
        assert len(res.json['errors']) == 1
        assert res.json['errors'][0]['source']['pointer'] == '/data/1/type'
        assert res.json['errors'][0]['detail'] == 'This field may not be null.'

        # test_bulk_update_incorrect_type
        res = app.put_json_api(
            url, {
                'data': [
                    public_payload['data'][1], {
                        'id': registration_one._id,
                        'type': 'Incorrect',
                        'attributes': {'public': True}
                    }
                ]
            }, auth=user.auth,
            expect_errors=True, bulk=True)
        assert res.status_code == 409

        # test_bulk_update_limits
        registration_update_list = {'data': [public_payload['data'][0]] * 101}
        res = app.put_json_api(
            url,
            registration_update_list,
            auth=user.auth,
            expect_errors=True,
            bulk=True)
        assert res.json['errors'][0]['detail'] == 'Bulk operation limit is 100, got 101.'
        assert res.json['errors'][0]['source']['pointer'] == '/data'

        # 400 from attempting to make a registration private
        res = app.put_json_api(
            url,
            private_payload,
            auth=user.auth,
            bulk=True,
            expect_errors=True)
        assert res.status_code == 400
        assert res.json['errors'][0]['detail'] == 'Registrations can only be turned from private to public.'

        # Confirm no changes have occured
        registration_one.refresh_from_db()
        registration_two.refresh_from_db()

        assert registration_one.embargo_termination_approval is None
        assert registration_two.embargo_termination_approval is None

        assert registration_one.is_public is False
        assert registration_two.is_public is False

        assert registration_one.title == 'Birds'
        assert registration_two.title == 'Birds II'

    def test_bulk_update_embargo_logged_in_read_only_contrib(
            self, app, user, registration_one, registration_two, public_payload, url):
        read_contrib = AuthUserFactory()
        registration_one.add_contributor(
            read_contrib, permissions=permissions.READ, save=True)
        registration_two.add_contributor(
            read_contrib, permissions=permissions.READ, save=True)

        res = app.put_json_api(
            url,
            public_payload,
            auth=read_contrib.auth,
            expect_errors=True,
            bulk=True)
        assert res.status_code == 403
        assert res.json['errors'][0]['detail'] == exceptions.PermissionDenied.default_detail

    def test_bulk_update_embargo_logged_in_contrib(
            self, app, user, registration_one, registration_two,
            public_payload, url):
        assert registration_one.is_pending_embargo_termination is False
        assert registration_two.is_pending_embargo_termination is False

        res = app.put_json_api(url, public_payload, auth=user.auth, bulk=True)
        assert res.status_code == 200
        assert ({registration_one._id, registration_two._id} == {
                res.json['data'][0]['id'], res.json['data'][1]['id']})

        # Needs confirmation before it will become public
        assert res.json['data'][0]['attributes']['public'] is False
        assert res.json['data'][1]['attributes']['public'] is False
        assert res.json['data'][0]['attributes']['pending_embargo_termination_approval'] is True
        assert res.json['data'][1]['attributes']['pending_embargo_termination_approval'] is True

        registration_one.refresh_from_db()
        registration_two.refresh_from_db()

        # registrations should have pending terminations
        assert registration_one.is_pending_embargo_termination is True
        assert registration_two.is_pending_embargo_termination is True

class TestRegistrationListFiltering(
        RegistrationListFilteringMixin,
        ApiTestCase):

    url = '/{}registrations/?'.format(API_BASE)


text:
extern "C" {
#endif

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#include "shaderc/env.h"
#include "shaderc/status.h"
#include "shaderc/visibility.h"

// Source language kind.
typedef enum {
  shaderc_source_language_glsl,
  shaderc_source_language_hlsl,
} shaderc_source_language;

typedef enum {
  // Forced shader kinds. These shader kinds force the compiler to compile the
  // source code as the specified kind of shader.
  shaderc_vertex_shader,
  shaderc_fragment_shader,
  shaderc_compute_shader,
  shaderc_geometry_shader,
  shaderc_tess_control_shader,
  shaderc_tess_evaluation_shader,

  shaderc_glsl_vertex_shader = shaderc_vertex_shader,
  shaderc_glsl_fragment_shader = shaderc_fragment_shader,
  shaderc_glsl_compute_shader = shaderc_compute_shader,
  shaderc_glsl_geometry_shader = shaderc_geometry_shader,
  shaderc_glsl_tess_control_shader = shaderc_tess_control_shader,
  shaderc_glsl_tess_evaluation_shader = shaderc_tess_evaluation_shader,

  // Deduce the shader kind from #pragma annotation in the source code. Compiler
  // will emit error if #pragma annotation is not found.
  shaderc_glsl_infer_from_source,
  // Default shader kinds. Compiler will fall back to compile the source code as
  // the specified kind of shader when #pragma annotation is not found in the
  // source code.
  shaderc_glsl_default_vertex_shader,
  shaderc_glsl_default_fragment_shader,
  shaderc_glsl_default_compute_shader,
  shaderc_glsl_default_geometry_shader,
  shaderc_glsl_default_tess_control_shader,
  shaderc_glsl_default_tess_evaluation_shader,
  shaderc_spirv_assembly,
#ifdef NV_EXTENSIONS
  shaderc_raygen_shader,
  shaderc_anyhit_shader,
  shaderc_closesthit_shader,
  shaderc_miss_shader,
  shaderc_intersection_shader,
  shaderc_callable_shader,
  shaderc_glsl_raygen_shader = shaderc_raygen_shader,
  shaderc_glsl_anyhit_shader = shaderc_anyhit_shader,
  shaderc_glsl_closesthit_shader = shaderc_closesthit_shader,
  shaderc_glsl_miss_shader = shaderc_miss_shader,
  shaderc_glsl_intersection_shader = shaderc_intersection_shader,
  shaderc_glsl_callable_shader = shaderc_callable_shader,
  shaderc_glsl_default_raygen_shader,
  shaderc_glsl_default_anyhit_shader,
  shaderc_glsl_default_closesthit_shader,
  shaderc_glsl_default_miss_shader,
  shaderc_glsl_default_intersection_shader,
  shaderc_glsl_default_callable_shader,
  shaderc_task_shader,
  shaderc_mesh_shader,
  shaderc_glsl_task_shader = shaderc_task_shader,
  shaderc_glsl_mesh_shader = shaderc_mesh_shader,
  shaderc_glsl_default_task_shader,
  shaderc_glsl_default_mesh_shader,
#endif
} shaderc_shader_kind;

typedef enum {
  shaderc_profile_none,  // Used if and only if GLSL version did not specify
                         // profiles.
  shaderc_profile_core,
  shaderc_profile_compatibility,
  shaderc_profile_es,
} shaderc_profile;

// Optimization level.
typedef enum {
  shaderc_optimization_level_zero,  // no optimization
  shaderc_optimization_level_size,  // optimize towards reducing code size
  shaderc_optimization_level_performance,  // optimize towards performance
} shaderc_optimization_level;

// Resource limits.
typedef enum {
  shaderc_limit_max_lights,
  shaderc_limit_max_clip_planes,
  shaderc_limit_max_texture_units,
  shaderc_limit_max_texture_coords,
  shaderc_limit_max_vertex_attribs,
  shaderc_limit_max_vertex_uniform_components,
  shaderc_limit_max_varying_floats,
  shaderc_limit_max_vertex_texture_image_units,
  shaderc_limit_max_combined_texture_image_units,
  shaderc_limit_max_texture_image_units,
  shaderc_limit_max_fragment_uniform_components,
  shaderc_limit_max_draw_buffers,
  shaderc_limit_max_vertex_uniform_vectors,
  shaderc_limit_max_varying_vectors,
  shaderc_limit_max_fragment_uniform_vectors,
  shaderc_limit_max_vertex_output_vectors,
  shaderc_limit_max_fragment_input_vectors,
  shaderc_limit_min_program_texel_offset,
  shaderc_limit_max_program_texel_offset,
  shaderc_limit_max_clip_distances,
  shaderc_limit_max_compute_work_group_count_x,
  shaderc_limit_max_compute_work_group_count_y,
  shaderc_limit_max_compute_work_group_count_z,
  shaderc_limit_max_compute_work_group_size_x,
  shaderc_limit_max_compute_work_group_size_y,
  shaderc_limit_max_compute_work_group_size_z,
  shaderc_limit_max_compute_uniform_components,
  shaderc_limit_max_compute_texture_image_units,
  shaderc_limit_max_compute_image_uniforms,
  shaderc_limit_max_compute_atomic_counters,
  shaderc_limit_max_compute_atomic_counter_buffers,
  shaderc_limit_max_varying_components,
  shaderc_limit_max_vertex_output_components,
  shaderc_limit_max_geometry_input_components,
  shaderc_limit_max_geometry_output_components,
  shaderc_limit_max_fragment_input_components,
  shaderc_limit_max_image_units,
  shaderc_limit_max_combined_image_units_and_fragment_outputs,
  shaderc_limit_max_combined_shader_output_resources,
  shaderc_limit_max_image_samples,
  shaderc_limit_max_vertex_image_uniforms,
  shaderc_limit_max_tess_control_image_uniforms,
  shaderc_limit_max_tess_evaluation_image_uniforms,
  shaderc_limit_max_geometry_image_uniforms,
  shaderc_limit_max_fragment_image_uniforms,
  shaderc_limit_max_combined_image_uniforms,
  shaderc_limit_max_geometry_texture_image_units,
  shaderc_limit_max_geometry_output_vertices,
  shaderc_limit_max_geometry_total_output_components,
  shaderc_limit_max_geometry_uniform_components,
  shaderc_limit_max_geometry_varying_components,
  shaderc_limit_max_tess_control_input_components,
  shaderc_limit_max_tess_control_output_components,
  shaderc_limit_max_tess_control_texture_image_units,
  shaderc_limit_max_tess_control_uniform_components,
  shaderc_limit_max_tess_control_total_output_components,
  shaderc_limit_max_tess_evaluation_input_components,
  shaderc_limit_max_tess_evaluation_output_components,
  shaderc_limit_max_tess_evaluation_texture_image_units,
  shaderc_limit_max_tess_evaluation_uniform_components,
  shaderc_limit_max_tess_patch_components,
  shaderc_limit_max_patch_vertices,
  shaderc_limit_max_tess_gen_level,
  shaderc_limit_max_viewports,
  shaderc_limit_max_vertex_atomic_counters,
  shaderc_limit_max_tess_control_atomic_counters,
  shaderc_limit_max_tess_evaluation_atomic_counters,
  shaderc_limit_max_geometry_atomic_counters,
  shaderc_limit_max_fragment_atomic_counters,
  shaderc_limit_max_combined_atomic_counters,
  shaderc_limit_max_atomic_counter_bindings,
  shaderc_limit_max_vertex_atomic_counter_buffers,
  shaderc_limit_max_tess_control_atomic_counter_buffers,
  shaderc_limit_max_tess_evaluation_atomic_counter_buffers,
  shaderc_limit_max_geometry_atomic_counter_buffers,
  shaderc_limit_max_fragment_atomic_counter_buffers,
  shaderc_limit_max_combined_atomic_counter_buffers,
  shaderc_limit_max_atomic_counter_buffer_size,
  shaderc_limit_max_transform_feedback_buffers,
  shaderc_limit_max_transform_feedback_interleaved_components,
  shaderc_limit_max_cull_distances,
  shaderc_limit_max_combined_clip_and_cull_distances,
  shaderc_limit_max_samples,
} shaderc_limit;

// Uniform resource kinds.
// In Vulkan, uniform resources are bound to the pipeline via descriptors
// with numbered bindings and sets.
typedef enum {
  // Image and image buffer.
  shaderc_uniform_kind_image,
  // Pure sampler.
  shaderc_uniform_kind_sampler,
  // Sampled texture in GLSL, and Shader Resource View in HLSL.
  shaderc_uniform_kind_texture,
  // Uniform Buffer Object (UBO) in GLSL.  Cbuffer in HLSL.
  shaderc_uniform_kind_buffer,
  // Shader Storage Buffer Object (SSBO) in GLSL.
  shaderc_uniform_kind_storage_buffer,
  // Unordered Access View, in HLSL.  (Writable storage image or storage
  // buffer.)
  shaderc_uniform_kind_unordered_access_view,
} shaderc_uniform_kind;

// Usage examples:
//
// Aggressively release compiler resources, but spend time in initialization
// for each new use.
//      shaderc_compiler_t compiler = shaderc_compiler_initialize();
//      shaderc_compilation_result_t result = shaderc_compile_into_spv(
//          compiler, "#version 450\nvoid main() {}", 27,
//          shaderc_glsl_vertex_shader, "main.vert", "main", nullptr);
//      // Do stuff with compilation results.
//      shaderc_result_release(result);
//      shaderc_compiler_release(compiler);
//
// Keep the compiler object around for a long time, but pay for extra space
// occupied.
//      shaderc_compiler_t compiler = shaderc_compiler_initialize();
//      // On the same, other or multiple simultaneous threads.
//      shaderc_compilation_result_t result = shaderc_compile_into_spv(
//          compiler, "#version 450\nvoid main() {}", 27,
//          shaderc_glsl_vertex_shader, "main.vert", "main", nullptr);
//      // Do stuff with compilation results.
//      shaderc_result_release(result);
//      // Once no more compilations are to happen.
//      shaderc_compiler_release(compiler);

// An opaque handle to an object that manages all compiler state.
typedef struct shaderc_compiler* shaderc_compiler_t;

// Returns a shaderc_compiler_t that can be used to compile modules.
// A return of NULL indicates that there was an error initializing the compiler.
// Any function operating on shaderc_compiler_t must offer the basic
// thread-safety guarantee.
// [http://herbsutter.com/2014/01/13/gotw-95-solution-thread-safety-and-synchronization/]
// That is: concurrent invocation of these functions on DIFFERENT objects needs
// no synchronization; concurrent invocation of these functions on the SAME
// object requires synchronization IF AND ONLY IF some of them take a non-const
// argument.
SHADERC_EXPORT shaderc_compiler_t shaderc_compiler_initialize(void);

// Releases the resources held by the shaderc_compiler_t.
// After this call it is invalid to make any future calls to functions
// involving this shaderc_compiler_t.
SHADERC_EXPORT void shaderc_compiler_release(shaderc_compiler_t);

// An opaque handle to an object that manages options to a single compilation
// result.
typedef struct shaderc_compile_options* shaderc_compile_options_t;

// Returns a default-initialized shaderc_compile_options_t that can be used
// to modify the functionality of a compiled module.
// A return of NULL indicates that there was an error initializing the options.
// Any function operating on shaderc_compile_options_t must offer the
// basic thread-safety guarantee.
SHADERC_EXPORT shaderc_compile_options_t
    shaderc_compile_options_initialize(void);

// Returns a copy of the given shaderc_compile_options_t.
// If NULL is passed as the parameter the call is the same as
// shaderc_compile_options_init.
SHADERC_EXPORT shaderc_compile_options_t shaderc_compile_options_clone(
    const shaderc_compile_options_t options);

// Releases the compilation options. It is invalid to use the given
// shaderc_compile_options_t object in any future calls. It is safe to pass
// NULL to this function, and doing such will have no effect.
SHADERC_EXPORT void shaderc_compile_options_release(
    shaderc_compile_options_t options);

// Adds a predefined macro to the compilation options. This has the same
// effect as passing -Dname=value to the command-line compiler.  If value
// is NULL, it has the same effect as passing -Dname to the command-line
// compiler. If a macro definition with the same name has previously been
// added, the value is replaced with the new value. The macro name and
// value are passed in with char pointers, which point to their data, and
// the lengths of their data. The strings that the name and value pointers
// point to must remain valid for the duration of the call, but can be
// modified or deleted after this function has returned. In case of adding
// a valueless macro, the value argument should be a null pointer or the
// value_length should be 0u.
SHADERC_EXPORT void shaderc_compile_options_add_macro_definition(
    shaderc_compile_options_t options, const char* name, size_t name_length,
    const char* value, size_t value_length);

// Sets the source language.  The default is GLSL.
SHADERC_EXPORT void shaderc_compile_options_set_source_language(
    shaderc_compile_options_t options, shaderc_source_language lang);

// Sets the compiler mode to generate debug information in the output.
SHADERC_EXPORT void shaderc_compile_options_set_generate_debug_info(
    shaderc_compile_options_t options);

// Sets the compiler optimization level to the given level. Only the last one
// takes effect if multiple calls of this function exist.
SHADERC_EXPORT void shaderc_compile_options_set_optimization_level(
    shaderc_compile_options_t options, shaderc_optimization_level level);

// Forces the GLSL language version and profile to a given pair. The version
// number is the same as would appear in the #version annotation in the source.
// Version and profile specified here overrides the #version annotation in the
// source. Use profile: 'shaderc_profile_none' for GLSL versions that do not
// define profiles, e.g. versions below 150.
SHADERC_EXPORT void shaderc_compile_options_set_forced_version_profile(
    shaderc_compile_options_t options, int version, shaderc_profile profile);

// Source text inclusion via #include is supported with a pair of callbacks
// to an "includer" on the client side.  The first callback processes an
// inclusion request, and returns an include result.  The includer owns
// the contents of the result, and those contents must remain valid until the
// second callback is invoked to release the result.  Both callbacks take a
// user_data argument to specify the client context.
// To return an error, set the source_name to an empty string and put your
// error message in content.

// An include result.
typedef struct shaderc_include_result {
  // The name of the source file.  The name should be fully resolved
  // in the sense that it should be a unique name in the context of the
  // includer.  For example, if the includer maps source names to files in
  // a filesystem, then this name should be the absolute path of the file.
  // For a failed inclusion, this string is empty.
  const char* source_name;
  size_t source_name_length;
  // The text contents of the source file in the normal case.
  // For a failed inclusion, this contains the error message.
  const char* content;
  size_t content_length;
  // User data to be passed along with this request.
  void* user_data;
} shaderc_include_result;

// The kinds of include requests.
enum shaderc_include_type {
  shaderc_include_type_relative,  // E.g. #include "source"
  shaderc_include_type_standard   // E.g. #include <source>
};

// An includer callback type for mapping an #include request to an include
// result.  The user_data parameter specifies the client context.  The
// requested_source parameter specifies the name of the source being requested.
// The type parameter specifies the kind of inclusion request being made.
// The requesting_source parameter specifies the name of the source containing
// the #include request.  The includer owns the result object and its contents,
// and both must remain valid until the release callback is called on the result
// object.
typedef shaderc_include_result* (*shaderc_include_resolve_fn)(
    void* user_data, const char* requested_source, int type,
    const char* requesting_source, size_t include_depth);

// An includer callback type for destroying an include result.
typedef void (*shaderc_include_result_release_fn)(
    void* user_data, shaderc_include_result* include_result);

// Sets includer callback functions.
SHADERC_EXPORT void shaderc_compile_options_set_include_callbacks(
    shaderc_compile_options_t options, shaderc_include_resolve_fn resolver,
    shaderc_include_result_release_fn result_releaser, void* user_data);

// Sets the compiler mode to suppress warnings, overriding warnings-as-errors
// mode. When both suppress-warnings and warnings-as-errors modes are
// turned on, warning messages will be inhibited, and will not be emitted
// as error messages.
SHADERC_EXPORT void shaderc_compile_options_set_suppress_warnings(
    shaderc_compile_options_t options);

// Sets the target shader environment, affecting which warnings or errors will
// be issued.  The version will be for distinguishing between different versions
// of the target environment.  The version value should be either 0 or
// a value listed in shaderc_env_version.  The 0 value maps to Vulkan 1.0 if
// |target| is Vulkan, and it maps to OpenGL 4.5 if |target| is OpenGL.
SHADERC_EXPORT void shaderc_compile_options_set_target_env(
    shaderc_compile_options_t options,
    shaderc_target_env target,
    uint32_t version);

// Sets the compiler mode to treat all warnings as errors. Note the
// suppress-warnings mode overrides this option, i.e. if both
// warning-as-errors and suppress-warnings modes are set, warnings will not
// be emitted as error messages.
SHADERC_EXPORT void shaderc_compile_options_set_warnings_as_errors(
    shaderc_compile_options_t options);

// Sets a resource limit.
SHADERC_EXPORT void shaderc_compile_options_set_limit(
    shaderc_compile_options_t options, shaderc_limit limit, int value);

// Sets whether the compiler should automatically assign bindings to uniforms
// that aren't already explicitly bound in the shader source.
SHADERC_EXPORT void shaderc_compile_options_set_auto_bind_uniforms(
    shaderc_compile_options_t options, bool auto_bind);

// Sets whether the compiler should use HLSL IO mapping rules for bindings.
// Defaults to false.
SHADERC_EXPORT void shaderc_compile_options_set_hlsl_io_mapping(
    shaderc_compile_options_t options, bool hlsl_iomap);

// Sets whether the compiler should determine block member offsets using HLSL
// packing rules instead of standard GLSL rules.  Defaults to false.  Only
// affects GLSL compilation.  HLSL rules are always used when compiling HLSL.
SHADERC_EXPORT void shaderc_compile_options_set_hlsl_offsets(
    shaderc_compile_options_t options, bool hlsl_offsets);

// Sets the base binding number used for for a uniform resource type when
// automatically assigning bindings.  For GLSL compilation, sets the lowest
// automatically assigned number.  For HLSL compilation, the regsiter number
// assigned to the resource is added to this specified base.
SHADERC_EXPORT void shaderc_compile_options_set_binding_base(
    shaderc_compile_options_t options,
    shaderc_uniform_kind kind,
    uint32_t base);

// Like shaderc_compile_options_set_binding_base, but only takes effect when
// compiling a given shader stage.  The stage is assumed to be one of vertex,
// fragment, tessellation evaluation, tesselation control, geometry, or compute.
SHADERC_EXPORT void shaderc_compile_options_set_binding_base_for_stage(
    shaderc_compile_options_t options, shaderc_shader_kind shader_kind,
    shaderc_uniform_kind kind, uint32_t base);

// Sets whether the compiler should automatically assign locations to
// uniform variables that don't have explicit locations in the shader source.
SHADERC_EXPORT void shaderc_compile_options_set_auto_map_locations(
    shaderc_compile_options_t options, bool auto_map);

// Sets a descriptor set and binding for an HLSL register in the given stage.
// This method keeps a copy of the string data.
SHADERC_EXPORT void shaderc_compile_options_set_hlsl_register_set_and_binding_for_stage(
    shaderc_compile_options_t options, shaderc_shader_kind shader_kind,
    const char* reg, const char* set, const char* binding);

// Like shaderc_compile_options_set_hlsl_register_set_and_binding_for_stage,
// but affects all shader stages.
SHADERC_EXPORT void shaderc_compile_options_set_hlsl_register_set_and_binding(
    shaderc_compile_options_t options, const char* reg, const char* set,
    const char* binding);

// Sets whether the compiler should enable extension
// SPV_GOOGLE_hlsl_functionality1.
SHADERC_EXPORT void shaderc_compile_options_set_hlsl_functionality1(
    shaderc_compile_options_t options, bool enable);

// An opaque handle to the results of a call to any shaderc_compile_into_*()
// function.
typedef struct shaderc_compilation_result* shaderc_compilation_result_t;

// Takes a GLSL source string and the associated shader kind, input file
// name, compiles it according to the given additional_options. If the shader
// kind is not set to a specified kind, but shaderc_glslc_infer_from_source,
// the compiler will try to deduce the shader kind from the source
// string and a failure in deducing will generate an error. Currently only
// #pragma annotation is supported. If the shader kind is set to one of the
// default shader kinds, the compiler will fall back to the default shader
// kind in case it failed to deduce the shader kind from source string.
// The input_file_name is a null-termintated string. It is used as a tag to
// identify the source string in cases like emitting error messages. It
// doesn't have to be a 'file name'.
// The source string will be compiled into SPIR-V binary and a
// shaderc_compilation_result will be returned to hold the results.
// The entry_point_name null-terminated string defines the name of the entry
// point to associate with this GLSL source. If the additional_options
// parameter is not null, then the compilation is modified by any options
// present.  May be safely called from multiple threads without explicit
// synchronization. If there was failure in allocating the compiler object,
// null will be returned.
SHADERC_EXPORT shaderc_compilation_result_t shaderc_compile_into_spv(
    const shaderc_compiler_t compiler, const char* source_text,
    size_t source_text_size, shaderc_shader_kind shader_kind,
    const char* input_file_name, const char* entry_point_name,
    const shaderc_compile_options_t additional_options);

// Like shaderc_compile_into_spv, but the result contains SPIR-V assembly text
// instead of a SPIR-V binary module.  The SPIR-V assembly syntax is as defined
// by the SPIRV-Tools open source project.
SHADERC_EXPORT shaderc_compilation_result_t shaderc_compile_into_spv_assembly(
    const shaderc_compiler_t compiler, const char* source_text,
    size_t source_text_size, shaderc_shader_kind shader_kind,
    const char* input_file_name, const char* entry_point_name,
    const shaderc_compile_options_t additional_options);

// Like shaderc_compile_into_spv, but the result contains preprocessed source
// code instead of a SPIR-V binary module
SHADERC_EXPORT shaderc_compilation_result_t shaderc_compile_into_preprocessed_text(
    const shaderc_compiler_t compiler, const char* source_text,
    size_t source_text_size, shaderc_shader_kind shader_kind,
    const char* input_file_name, const char* entry_point_name,
    const shaderc_compile_options_t additional_options);

// Takes an assembly string of the format defined in the SPIRV-Tools project
// (https://github.com/KhronosGroup/SPIRV-Tools/blob/master/syntax.md),
// assembles it into SPIR-V binary and a shaderc_compilation_result will be
// returned to hold the results.
// The assembling will pick options suitable for assembling specified in the
// additional_options parameter.
// May be safely called from multiple threads without explicit synchronization.
// If there was failure in allocating the compiler object, null will be
// returned.
SHADERC_EXPORT shaderc_compilation_result_t shaderc_assemble_into_spv(
    const shaderc_compiler_t compiler, const char* source_assembly,
    size_t source_assembly_size,
    const shaderc_compile_options_t additional_options);

// The following functions, operating on shaderc_compilation_result_t objects,
// offer only the basic thread-safety guarantee.

// Releases the resources held by the result object. It is invalid to use the
// result object for any further operations.
SHADERC_EXPORT void shaderc_result_release(shaderc_compilation_result_t result);

// Returns the number of bytes of the compilation output data in a result
// object.
SHADERC_EXPORT size_t shaderc_result_get_length(const shaderc_compilation_result_t result);

// Returns the number of warnings generated during the compilation.
SHADERC_EXPORT size_t shaderc_result_get_num_warnings(
    const shaderc_compilation_result_t result);

// Returns the number of errors generated during the compilation.
SHADERC_EXPORT size_t shaderc_result_get_num_errors(const shaderc_compilation_result_t result);

// Returns the compilation status, indicating whether the compilation succeeded,
// or failed due to some reasons, like invalid shader stage or compilation
// errors.
SHADERC_EXPORT shaderc_compilation_status shaderc_result_get_compilation_status(
    const shaderc_compilation_result_t);

// Returns a pointer to the start of the compilation output data bytes, either
// SPIR-V binary or char string. When the source string is compiled into SPIR-V
// binary, this is guaranteed to be castable to a uint32_t*. If the result
// contains assembly text or preprocessed source text, the pointer will point to
// the resulting array of characters.
SHADERC_EXPORT const char* shaderc_result_get_bytes(const shaderc_compilation_result_t result);

// Returns a null-terminated string that contains any error messages generated
// during the compilation.
SHADERC_EXPORT const char* shaderc_result_get_error_message(
    const shaderc_compilation_result_t result);

// Provides the version & revision of the SPIR-V which will be produced
SHADERC_EXPORT void shaderc_get_spv_version(unsigned int* version, unsigned int* revision);

// Parses the version and profile from a given null-terminated string
// containing both version and profile, like: '450core'. Returns false if
// the string can not be parsed. Returns true when the parsing succeeds. The
// parsed version and profile are returned through arguments.
SHADERC_EXPORT bool shaderc_parse_version_profile(const char* str, int* version,
                                   shaderc_profile* profile);

#ifdef __cplusplus
}
#endif  // __cplusplus

#endif  // SHADERC_SHADERC_H_

redpajama_set_name: RedPajamaGithub


text:
<?php

declare(strict_types=1);

/**
 * This file is part of Narrowspark Framework.
 *
 * (c) Daniel Bannert <d.bannert@anolilab.de>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Viserio\Component\Translation\Formatter;

use IntlException;
use MessageFormatter;
use Viserio\Contract\Translation\Exception\CannotFormatException;
use Viserio\Contract\Translation\Exception\CannotInstantiateFormatterException;
use Viserio\Contract\Translation\MessageFormatter as MessageFormatterContract;

class IntlMessageFormatter implements MessageFormatterContract
{
    /**
     * {@inheritdoc}
     */
    public function format(string $message, string $locale, array $parameters = []): string
    {
        if ($message === '') {
            // Empty strings are not accepted as message pattern by the \MessageFormatter.
            return $message;
        }

        try {
            $formatter = new MessageFormatter($locale, $message);
        } catch (IntlException $exception) {
            throw new CannotInstantiateFormatterException($exception->getMessage(), $exception->getCode(), $exception);
        }

        /** @codeCoverageIgnoreStart */
        if ($formatter === null) {
            throw new CannotInstantiateFormatterException(\intl_get_error_message(), \intl_get_error_code());
        }
        // @codeCoverageIgnoreEnd
        $result = $formatter->format($parameters);

        if ($formatter->getErrorCode() !== \U_ZERO_ERROR) {
            throw new CannotFormatException(\sprintf('Unable to format message. Reason: %s (error #%s).', $formatter->getErrorMessage(), $formatter->getErrorCode()));
        }

        return $result;
    }
}


text:
require('datejs');
Date.i18n.setLanguage('es-AR');

var _ = require('lodash');
var Q = require('q');

var SerialPortFactory = require('./serialPortFactory');
var transformData = require('./transformData');

function SerialDispatcher(serverConfig) {
  var _self = this,
      _serialPort = null,
      _connHandler = new ConnHandler(),
      _callback = function() {},
      _requests = [],
      _running = false,
      _samplesMaxErrorCount = 5,
      _samplesTimeoutId,
      _lastRequest = null;

  function addGlobalRequest(request) {
    _requests.push({ request: request });
  }
  function addRequest(socket, request) {
    _requests.push({socket: socket, request: request });
  }
  function ConnHandler() {
    this.sockets = {};
    this.selectedSocket = null;
    //this.actual = null;
    this.addSocket = function(socket) {
        this.sockets[socket.id] = socket;
    };
    this.removeSocket = function(id) {
        delete this.sockets[id];
    };
    this.broadcast = function(event) {
        _.each(this.sockets, function(socket) {
            socket.emit(event.type, event.data);
        });
    };
    this.emit = function(event) {
      if(this.selectedSocket) {
        this.selectedSocket.emit(event.type, event.data);
      }
    }
  }
  function convertInterval(interval) {
    // segun esta expresado en los comandos, 1 seg = 100 unidades
    var _interval = interval * 100,
    // obtengo la representacion en string
        __interval = String(_interval),
    // cuento la cantidad de caracteres
        count = __interval.length,
    // me fijo cuantos ceros me faltan
        missing = 5 - count;
    // agrego los ceros que faltan
    for(var i = 0; i < missing; i++) {
      __interval = '0' + __interval;
    }
    return __interval;
  }
  function init() {
    var defer = Q.defer(),
        sConfig = serverConfig;

    serverConfig.config().then(function(config) {
      _serialPort = SerialPortFactory(config.port, onDataCallback, null, sConfig);
      _serialPort.on('open', function(){
        // detener adquisicion si la placa estaba en eso
        addGlobalRequest({ command: 'DETA' });
        // incluir todos los canales analogicos
        addGlobalRequest({ command: 'SCAN', params: '02'});
        // incluir canales digitales
        addGlobalRequest({ command: 'CLDIS', dont_wait: true });
        // sincronizar las luces con la configuracion
        if(!config.estacion.luces.on) {
          addGlobalRequest({ command: 'WRDO', params: '3' });
        }
        // procesar los comandos
        processQueue();
      });
    });
    return defer.promise;
  }
  function onDataCallback(data) {
    if(data.indexOf(';') >= 0) {
      // son datos para enviar a los clientes
      processData(data);
    } else {
      // respuesta de un comando
      processCommands(data);
    }
    processQueue();
  }
  function processAlarms(code) {
    serverConfig.config().then(function(sConfig) {
      var alarms = [];
      if(code > 0) {
        // es una alarma
        var _general = sConfig.sendAlarms,
            _alarmas = sConfig.estacion.alarmas,
            _date = (new Date).toString('yyyy/MM/dd HH:mm:ss');
        if (code === 3) {
          if (_general && _alarmas.openDoor) {
            alarms.push({type: 'OPEN_DOOR', message: 'Puerta abierta', date: _date})
          }
          if (_general && _alarmas.lowBattery) {
            alarms.push({type: 'LOW_BATTERY', message: 'Celda solar desconectada', date: _date})
          }
        } else if (code == 2 && _general && _alarmas.openDoor) {
          alarms.push({type: 'OPEN_DOOR', message: 'Puerta abierta', date: _date})
        } else if (code == 1 && _general && _alarmas.lowBattery) {
          alarms.push({type: 'LOW_BATTERY', message: 'Celda solar desconectada', date: _date})
        }
        if(_general) {
          // envio mail
          serverConfig.sendMail(alarms);
          // envio las alarmas a los clientes conectados
          _connHandler.broadcast({
            type: 'server:alarm',
            data: {
              message: alarms
            }
          });
        }
      }
    });
  }
  function processCommands(data) {
    _connHandler.emit({
      type: 'server:data',
      data: {
        //request: _lastRequest,
        message: data
      }
    });
  }
  function processData(data) {
    stopTimeout();
    // si se desconecto por mucho tiempo, queda desfasado. si estaba adquiriendo datos, lo detengo
    if(!_running) {
      _self.stopAdq();
    }
    processRawData(data).then(function(_data) {
      // exportar la respuesta
      _callback({
        humedad: _data.humedad.value,
        viento: _data.viento.value,
        temperatura: _data.temperatura.value
      }).then(function(response) {
        _connHandler.broadcast({
          type: 'server:data',
          data: {
            message: 'Datos obtenidos',
            data: _.extend(_data, response)
          }
        });
      });
      startTimeout();
    });
  }
  function processQueue() {
    console.log((new Date).toString('yyyy/MM/dd HH:mm:ss') + ' --- pending ' + _requests.length + ' requests');
    if(_requests.length > 0) {
      processRequest(_requests.shift());
    }
  }
  function processRawData(data) {
    var defer = Q.defer();
    serverConfig.config().then(function(sConfig) {
      var values = _.chain(data.replace(/\r/g, '').split(';'))
            .remove(function (item) { return item.length !== 0; })
            .map(function (item) { return parseInt(item) })
            .value(),
          response = {},
          sensores = sConfig.estacion.sensores;
      _.each(sensores, function(sensor) {
        response[sensor.id] = transformData(values[sensor.channel], sensor.transfer, sensor.thresholds)
      });
      processAlarms(values[3]);
      defer.resolve(response);
    });
    return defer.promise;
  }
  function processRequest(requestItem) {
    if(_serialPort && requestItem) {
      var command = requestItem.request.command,
          value = requestItem.request.params ? requestItem.request.params: '';
      // guardar la referencia como ultimo request
      _lastRequest = requestItem;
      // si el origen es un socket, la respuesta debe ir a ese socket
      _connHandler.selectedSocket = requestItem.socket ? requestItem.socket : null;
      // enviar el comando a la interface serie
      write(command + value + "\n").then(function(response) {
        console.log((new Date).toString('yyyy/MM/dd HH:mm:ss') + ' --> Comando enviado: ' + command + value + ' (' + response.results + ' caracteres)');
        // algunos comandos no tienen respuesta, por lo tanto no hay que esperarlos para continuar
        if(requestItem.request.dont_wait) {
          processQueue();
        }
      });
    }
  }
  function samplingError() {
    var date = (new Date).toString('yyyy/MM/dd HH:mm:ss');
    console.log(date + ' --- Error de muestreo');
    serverConfig.sendMail([{
      type: 'SAMPLING_ERROR',
      message: 'Error de muestreo',
      date: date
    }]);
    // envio las alarmas a los clientes conectados
    _connHandler.broadcast({
      type: 'server:alarm',
      data: {
        type: 'SAMPLING_ERROR',
        message: 'Error de muestreo'
      }
    });
    _self.stopAdq();
  }
  function startTimeout() {
    serverConfig.config().then(function(config) {
      _samplesTimeoutId = setTimeout(samplingError, config.interval * 1000 * _samplesMaxErrorCount)
    });
  }
  function stopTimeout() {
    clearTimeout(_samplesTimeoutId);
  }
  function write(message) {
    var defer = Q.defer();
    if(!_serialPort.isOpen()) {
      _serialPort.open(function() {
        _serialPort.write(message, function(err, results) {
          _serialPort.drain(function() {
            defer.resolve({ err: err, results: results });
          });
        });
      });
    } else {
      _serialPort.write(message, function(err, results) {
        _serialPort.drain(function() {
          defer.resolve({ err: err, results: results });
        });
      });
    }
    return defer.promise;
  }

  this.setCallback = function(callback) {
    if(typeof callback === 'function') {
      _callback = callback;
    } else {
      console.log(callback, ' no es una funcion valida');
      _callback = function() {};
    }
  };
  this.iden = function(socket) {
    addRequest(socket, { command: 'IDEN' });
    processQueue();
  };
  this.startAdq = function() {
    serverConfig.config().then(function(config) {
      // incluir todos los canales analogicos
      addGlobalRequest({ command: 'SCAN', params: '02'});
      // incluir entradas digitales
      addGlobalRequest({ command: 'CLDIS', dont_wait: true });
      // iniciar adquisicion
      addGlobalRequest({ command: 'INIL', params: convertInterval(config.interval) });
      // procesar los comandos
      processQueue();
      // avisar a todos
      _connHandler.broadcast({ type:'server:set_acq_status', data:true });
      _running = true;
    });
  };
  this.stopAdq = function() {
    clearTimeout(_samplesTimeoutId);
    addGlobalRequest({ command: 'DETA' });
    processQueue();
    _connHandler.broadcast({ type:'server:set_acq_status', data:false });
    _running = false;
  };
  this.restart = function() {
    _serialPort.close();
  };
  this.init = function() {
    init();
  };
  this.running = function() {
    return _running;
  };
  this.turnOn = function() {
    addGlobalRequest({ command: 'WRDO', params: '0' });
    processQueue();
    _connHandler.broadcast({ type: 'server:lights', data: true });
  };
  this.turnOff = function() {
    addGlobalRequest({ command: 'WRDO', params: '3' });
    processQueue();
    _connHandler.broadcast({ type: 'server:lights', data: false });
  };
  this.addSocket = function(socket) {
    _connHandler.addSocket(socket);
  };
  this.removeSocket = function(socketId) {
    _connHandler.removeSocket(socketId);
  };
  this.broadcast = function(event) {
    _connHandler.broadcast(event);
  };

}

module.exports = SerialDispatcher;


text:
<?php
$this->title = Yum::t('Update role');

$this->breadcrumbs=array(
	Yum::t('Roles')=>array('index'),
	Yum::t('Update'));

?>

<?php echo $this->renderPartial('_form', array('model'=>$model)); ?>