text:
import sys
import unittest
from pprint import pprint

import pytest

from pp.latchpony.model import (
    LatchPonyError, CompetitionError, DuplicateNodeError,
    CompetitionFormatError, CompetitionValidationError, CompetitionDataError,
    LatchPonyNode,
    Rider, Pony, Action, Latch,
    Competition, ActionWithPermission,
    NODE_GROUPS,
    LATCH_DENY_ALL, UUID_LENGTH,
    get_orgs_from_mongo, data_for_org,
    )

skip = pytest.mark.skip

#     Go to this directory:
# bitbucket/project-admin/projects/latchpony/pp-latchpony-restservice/Model/pp
#     and run
# py.test
#     or
# py.test --cov-config .coveragerc --cov-report term-missing --cov latchpony

#TEST_COMPETITION_DICT = {
    # This would be a strange set of rules, but they are there to allow the
    # testing of various conditions. For instance, you wouldn't actually have
    # one rule that says Jane can edit salaries, and another that contradicts
    # it, with a different weight.
    ##'action': [{'name': 'create', 'groups': ['edit', 'maintain']},
               ##{'name': 'maintain', 'groups': ['view']},
               ##{'name': 'market', 'groups': ['view']},
               ##{'name': 'edit', 'groups': ['view']},
               ##{'name': 'view', 'groups': ['action']},
               ##],
    ##'anyone': [{'name': 'accounts-dept', 'groups': ['staff']},
               ##{'name': 'admin', 'groups': ['staff']},
               ##{'name': 'jane', 'groups': ['admin'], 'tags': ['pilates']},
               ##{'name': 'jim', 'groups': ['accounts-dept', 'admin']},
               ##{'name': 'staff', 'groups': ['anyone']},
               ##],
    ##'anything': [{'name': 'accounts', 'groups': ['financial']},
                 ##{'name': 'financial', 'groups': ['anything']},
                 ##{'name': 'salaries', 'groups': ['accounts']},
                 ##{'name': 'share-price', 'groups': ['financial']},
                 ##],
    ##'created': '2012-09-18T12:12:12',
    ##'name': 'comp_data_01',
    ##'permissions': ['deny anyone to action anything wt 10',
                    ##'allow jane to market share-price wt 30',
                    ##'allow anyone to view share-price wt 40',
                    ##'deny admin to view accounts wt 60',
                    ##'allow accounts-dept to create accounts wt 70',
                    ##'allow jane to edit salaries wt 85',
                    ##'deny accounts-dept to edit salaries wt 85',
                    ##'allow jim to create salaries wt 90',
                    ##'deny jane to view salaries wt 125'],
##}
TEST_COMPETITION_TREE = """\
... action
    ... view
        ... maintain
            ... create
        ... market
        ... edit
            ... create
... anyone
    ... staff
        ... accounts-dept
            ... jim
        ... admin
            ... jane
            ... jim
... anything
    ... financial
        ... accounts # comment 1
                # comment 2
            ... salaries
        ... share-price
... permissions
    ... deny anyone to action anything wt 10
    ... allow jane to market share-price wt 30
    ... allow anyone to view share-price wt 40
    ... deny admin to view accounts wt 60
    ... allow accounts-dept to create accounts wt 70
    ... allow jane to edit salaries wt 85
    ... deny accounts-dept to edit salaries wt 85
    ... allow jim to create salaries wt 90
    ... deny jane to view salaries wt 125
... doc
    ... doc_name: Winter 2012
    ... doc_id: cfccd77f-9088-43bd-aedf-b1b5cd67d855
    ... organisation: massaaage.com
    ... org_id: mass01
    ... author: Rob The Demo
    ... created: 2012-09-18T12:12:12
    ... updated: 2012-11-20T14:29:49
    ... version: 0.1.7
"""

### This prints as tree thus:
##"""
##... action
    ##... view
        ##... maintain
            ##... create
        ##... market
        ##... edit
            ##... create
##... anyone
    ##... staff
        ##... accounts-dept
            ##... jim
        ##... admin
            ##... jane
            ##... jim
##... anything
    ##... financial
        ##... accounts
            ##... salaries
        ##... share-price
##... permissions
    ##... deny anyone to action anything wt 10
    ##... allow jane to market share-price wt 30
    ##... allow anyone to view share-price wt 40
    ##... deny admin to view accounts wt 60
    ##... allow accounts-dept to create accounts wt 70
    ##... allow jane to edit salaries wt 85
    ##... deny accounts-dept to edit salaries wt 85
    ##... allow jim to create salaries wt 90
    ##... deny jane to view salaries wt 125
##"""

class DebugPrintingTestCase(unittest.TestCase):

    def debug_print(self, competition):
        print("-" * 50)
        pprint(competition.dump())
        print("-" * 50)
        competition.print_tree()
        print("-" * 50)

class TestNewLatchPonyNode(unittest.TestCase):

    def setUp(self):
        pass

    def test_make_competitor_node(self):
        name = 'jane'
        data_dict = {'groups': ['admin'], 'tags': ['tag95']}
        node = LatchPonyNode(name=name, **data_dict)
        assert node.name == name
        assert node.groups == ['admin']
        assert node.tags == ['tag95']
        assert node.members == []
        assert node.data == None

    def test_make_permission_node(self):
        data = "allow jane to edit salaries wt 85"
        node = LatchPonyNode(data=data)
        assert node.data == data

class TestMongoDB(DebugPrintingTestCase):

    def setUp(self):
        pass

    def test_get_orgs(self):
        orgs = get_orgs_from_mongo()
        sample = [u'com_example_massage', u'com_example_pilates']
        # Check that each of sample is found in orgs
        assert set(sample) & set(orgs) == set(sample)

    def test_load_data_for_org(self):
        assert data_for_org(u'com_example_massage') == dict(a=1, b=2)
        assert data_for_org(u'com_example_pilates') == dict(a=3, b=4)

class TestActionWithPermission(DebugPrintingTestCase):

    def setUp(self):
        self.act_with_perm = ActionWithPermission('test-action')

    @skip
    def test_add_permit(self):
        self.act_with_perm.add_permit('allow', 20)
        self.act_with_perm.add_permit('deny', 30)
        self.act_with_perm.add_permit('allow', 40)
        self.assertItemsEqual(self.act_with_perm.weighted_permits,
                              set([('allow', 20), ('deny', 30),
                                   ('allow', 40)]))

    @skip
    def test_add_duplicate_permit(self):
        self.act_with_perm.add_permit('allow', 20)
        self.act_with_perm.add_permit('deny', 30)
        self.act_with_perm.add_permit('allow', 20)
        self.assertItemsEqual(self.act_with_perm.weighted_permits,
                              set([('allow', 20), ('deny', 30)]))

    @skip
    def test_add_conflicting_permit(self):
        with self.assertRaises(CompetitionDataError):
            self.act_with_perm.add_permit('allow', 20)
            self.act_with_perm.add_permit('deny', 30)
            self.act_with_perm.add_permit('deny', 20)

    def test_sorted_permits(self):
        self.act_with_perm.add_permit('allow', 70)
        self.act_with_perm.add_permit('deny', 80)
        self.act_with_perm.add_permit('allow', 90)
        self.assertEqual(self.act_with_perm._sorted_permits(),
                         [('allow', 90), ('deny', 80), ('allow', 70)])

    def test_allowed(self):
        self.act_with_perm.add_permit('allow', 70)
        self.act_with_perm.add_permit('deny', 80)
        self.assertFalse(self.act_with_perm.allowed)
        self.act_with_perm.add_permit('allow', 90)
        self.assertTrue(self.act_with_perm.allowed)

    def test_representation(self):
        self.act_with_perm.add_permit('allow', 70)
        self.act_with_perm.add_permit('deny', 80)
        self.assertEqual(self.act_with_perm.__repr__(),
                         '<ActionWithPermission "test-action", ' + \
                         "perms=[('deny', 80), ('allow', 70)]>")

class TestEmptyCompetition(DebugPrintingTestCase):

    def setUp(self):
        self.competition = Competition(name='Empty competition')

    @skip
    def test_create_competition(self):
        self.assertEqual(self.competition.name, 'empty_competition')
        self.assertEqual(self.competition.caption, 'Empty Competition')
        descs = self.competition.descendants
        self.assertEqual(descs('anyone'), set())
        self.assertEqual(descs('anything'), set())
        self.assertEqual(descs('action'), set())
        self.assertEqual(descs('permissions'), {LATCH_DENY_ALL})

    @skip
    def test_adding_rider(self):
        rider = Rider(name='jim')
        self.competition.add(rider)
        self.assertEqual(self.competition.nodes['jim'], rider)

    @skip
    def test_removing_rider(self):
        rider = Rider(name='jane')
        self.competition.add(rider)
        self.competition.remove(rider)
        self.debug_print(self.competition)
        self.assertItemsEqual(self.competition.nodes.keys(),
                              NODE_GROUPS | {LATCH_DENY_ALL})

    @skip
    def test_removing_non_existent_rider(self):
        rider = Rider(name='jim')
        with self.assertRaises(CompetitionError) as ctxmgr:
            self.competition.remove(rider)
        self.assertIn("Unknown node key", ctxmgr.exception.message)

    @skip
    def test_removing_duplicate_rider(self):
        rider1 = Rider(name='jane')
        rider2 = Rider(name='jane')
        self.competition.add(rider1)
        with self.assertRaises(DuplicateNodeError) as ctxmgr:
            self.competition.remove(rider2)
        self.assertIn("Duplicate node", ctxmgr.exception.message)

    @skip
    def test_adding_pony(self):
        pony = Pony(name='salaries')
        self.competition.add(pony)
        self.assertEqual(self.competition.nodes['salaries'], pony)

    @skip
    def test_removing_pony(self):
        pony = Pony(name='finance')
        self.competition.add(pony)
        self.competition.remove(pony)
        self.assertItemsEqual(self.competition.nodes.keys(),
                              NODE_GROUPS | {LATCH_DENY_ALL})

    @skip
    def test_adding_latch(self):
        latch_data = 'allow admin to view accounts wt 60'
        latch = Latch(latch_data)
        self.competition.add(latch)
        self.assertItemsEqual(self.competition.nodes.keys(),
                              NODE_GROUPS | {latch_data, LATCH_DENY_ALL})

    @skip
    def test_removing_latch(self):
        latch_data = 'allow admin to view accounts wt 60'
        latch = Latch(latch_data)
        self.competition.add(latch)
        self.competition.remove(latch)
        self.assertItemsEqual(self.competition.nodes.keys(),
                              NODE_GROUPS | {LATCH_DENY_ALL})

    @skip
    def test_adding_unknown_class(self):
        class Jumper(LatchPonyNode):
            collection_name = '_jumpers'
            def __init__(self, name, **kwargs):
                super(Jumper, self).__init__(**kwargs)
                self.name = name

        jumper = Jumper('oops')
        self.competition.add(jumper)
        with self.assertRaises(CompetitionValidationError):
            self.competition.validate()

    def test_load_with_unknown_format(self):
        with self.assertRaises(CompetitionFormatError):
            competition = Competition.load({}, data_format='xml')
        with self.assertRaises(CompetitionFormatError):
            competition = Competition.load({}, data_format='soap')

class TestLatches(DebugPrintingTestCase):

    def setUp(self):
        self.competition = Competition.load(TEST_COMPETITION_TREE)

    def test_make_latch(self):
        latch = Latch('deny admin to view accounts wt 60')
        self.assertEqual(str(latch),
                         "<Latch: deny admin to view accounts wt 60, " + \
                         "groups=['permissions']>")

    def test_latches_for_rider(self):
        self.debug_print(self.competition)
        self.competition._make_latch_dicts()
        jims_latches = self.competition.latches_for('jim')
        self.assertListEqual(jims_latches,
                             [LATCH_DENY_ALL,
                              'allow anyone to view share-price wt 40',
                              'deny admin to view accounts wt 60',
                              'allow accounts-dept to create accounts wt 70',
                              'deny accounts-dept to edit salaries wt 85',
                              'allow jim to create salaries wt 90'])

    def test_latches_for_pony(self):
        self.debug_print(self.competition)
        salaries_latches = self.competition.latches_for('salaries')
        pprint(salaries_latches)
        self.assertListEqual(salaries_latches,
                             [LATCH_DENY_ALL,
                              'deny admin to view accounts wt 60',
                              'allow accounts-dept to create accounts wt 70',
                              'allow jane to edit salaries wt 85',
                              'deny accounts-dept to edit salaries wt 85',
                              'allow jim to create salaries wt 90',
                              'deny jane to view salaries wt 125'])
        accounts_latches = self.competition.latches_for('accounts')
        pprint(accounts_latches)
        self.assertListEqual(accounts_latches,
                             [LATCH_DENY_ALL,
                              'deny admin to view accounts wt 60',
                              'allow accounts-dept to create accounts wt 70'])

    def test_latches_for_both(self):
        latches3 = self.competition.latches_for('jim', 'salaries')
        self.assertListEqual(latches3,
                             [LATCH_DENY_ALL,
                              'deny admin to view accounts wt 60',
                              'allow accounts-dept to create accounts wt 70',
                              'deny accounts-dept to edit salaries wt 85',
                              'allow jim to create salaries wt 90'])
        latches4 = self.competition.latches_for('jim', 'accounts')
        self.assertListEqual(latches4,
                             [LATCH_DENY_ALL,
                              'deny admin to view accounts wt 60',
                              'allow accounts-dept to create accounts wt 70'])
        latches5 = self.competition.latches_for('jane', 'salaries')
        self.assertListEqual(latches5,
                             [LATCH_DENY_ALL,
                              'deny admin to view accounts wt 60',
                              'allow jane to edit salaries wt 85',
                              'deny jane to view salaries wt 125'])

    def test_expand_deny_permissions(self):
        cept = self.competition.expand_permission_type
        aie = self.assertItemsEqual
        aie(cept('deny', 'edit'), set([('deny', 'edit'),
                                        ('deny', 'create')]))
        aie(cept('deny', 'action'), set([('deny', 'view'),
                                          ('deny', 'maintain'),
                                          ('deny', 'create'),
                                          ('deny', 'market'),
                                          ('deny', 'edit')]))
        aie(cept('deny', 'market'), set([('deny', 'market')]))

    def test_expand_allow_permissions(self):
        cept = self.competition.expand_permission_type
        aie = self.assertItemsEqual
        aie(cept('allow', 'edit'), set([('allow', 'edit'),
                                         ('allow', 'view')]))
        aie(cept('allow', 'create'), set([('allow', 'view'),
                                          ('allow', 'maintain'),
                                          ('allow', 'edit'),
                                          ('allow', 'create')]))
        aie(cept('allow', 'action'), set())

    @pytest.mark.skip
    # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    def test_gate_for(self):
        gf = self.competition.gate_for
        saleq = self.assertListEqual
        saleq(gf('jim', 'accounts'), ['create', 'edit', 'maintain', 'view'])
        saleq(gf('jim', 'salaries'), ['create', 'edit', 'maintain', 'view'])
        saleq(gf('jim', 'financial'), [])
        saleq(gf('jim', 'share-price'), ['view'])
        saleq(gf('jane', 'share-price'), ['market', 'view'])
        saleq(gf('jane', 'salaries'), [])
        saleq(gf('admin', 'accounts'), [])
        self.assertEqual(str(self.competition.ancestors.cache_info()),
                   "CacheInfo(hits=10, misses=20, maxsize=1000, currsize=20)")
        self.assertEqual(str(self.competition.descendants.cache_info()),
                   "CacheInfo(hits=12, misses=15, maxsize=1000, currsize=15)")

    @pytest.mark.skip
    def test_cache_on_gate_for(self):
        gf = self.competition.gate_for
        saleq = self.assertListEqual
        saleq(gf('jim', 'share-price'), ['view'])
        saleq(gf('jim', 'share-price'), ['view'])
        saleq(gf('jane', 'salaries'), [])
        saleq(gf('jim', 'share-price'), ['view'])
        saleq(gf('jim', 'share-price'), ['view'])
        self.assertEqual(str(gf.cache_info()),
                   "CacheInfo(hits=3, misses=2, maxsize=1000, currsize=2)")
        self.assertEqual(str(self.competition.ancestors.cache_info()),
                   "CacheInfo(hits=0, misses=6, maxsize=1000, currsize=6)")
        self.assertEqual(str(self.competition.descendants.cache_info()),
                   "CacheInfo(hits=2, misses=9, maxsize=1000, currsize=9)")

    def test_ponies_for_rider(self):
        pfr = self.competition.ponies_for_rider
        sadeq = self.assertDictEqual
        sadeq(pfr('jim'), {'accounts': ['create', 'edit', 'maintain', 'view'],
                           'salaries': ['create', 'edit', 'maintain', 'view'],
                           'share-price': ['view']})
        sadeq(pfr('jane'), {'share-price': ['market', 'view']})
        sadeq(pfr('admin'), {'share-price': ['view']})
        sadeq(pfr('accounts-dept'),
              {'accounts': ['create', 'edit', 'maintain', 'view'],
               'salaries': ['maintain', 'view'],
               'share-price': ['view']})
        sadeq(pfr('staff'), {'share-price': ['view']})
        sadeq(pfr('anyone'), {'share-price': ['view']})

    def test_riders_for_pony(self):
        rfp = self.competition.riders_for_pony
        sadeq = self.assertDictEqual
        sadeq(rfp('share-price'), {'accounts-dept': ['view'],
                                   'admin': ['view'],
                                   'anyone': ['view'],
                                   'jane': ['market', 'view'],
                                   'jim': ['view'],
                                   'staff': ['view']})
        sadeq(rfp('salaries'), {'accounts-dept': ['maintain', 'view'],
                                'jim': ['create', 'edit', 'maintain', 'view'],
                                })
        sadeq(rfp('accounts'),
              {'accounts-dept': ['create', 'edit', 'maintain', 'view'],
               'jim': ['create', 'edit', 'maintain', 'view']})
        sadeq(rfp('financial'), {})
        sadeq(rfp('anything'), {})

class TestLatchPonyHandBuiltGraph(DebugPrintingTestCase):

    def setUp(self):
        self.maxDiff = None

    @pytest.mark.skip
    # Data has changed
    def test_build_graph_by_hand(self):
        # Check that this graph is dumped identical with the auto-loaded
        # graph. Then run the tests with auto-loaded. Easier to change data.
        competition = Competition(name='comp_data_01')
        competition.created = '2012-09-18T12:12:12'

        cp_add = competition.add
        nodes = competition.nodes
        # Add riders and groups
        cp_add(Rider('staff', groups=['anyone']))
        cp_add(Rider('admin', groups=['staff']))
        cp_add(Rider('accounts-dept'))
        cp_add(Rider('jane', groups=['admin']))
        cp_add(Rider('jim', groups=['admin', 'accounts-dept']))

        # Add other rider groups
        nodes['accounts-dept'].add_groups(['staff'])

        # Add ponies and groups
        cp_add(Pony('financial', groups=['anything']))
        cp_add(Pony('share-price'))
        cp_add(Pony('accounts'))
        cp_add(Pony('salaries', groups=['accounts']))

        # Add other pony groups
        nodes['share-price'].add_groups(['financial'])
        nodes['accounts'].add_groups(['financial'])

        # Add action

        cp_add(Action('view', groups=['action']))
        cp_add(Action('maintain', groups=['view']))
        cp_add(Action('market', groups=['view']))
        cp_add(Action('edit', groups=['view']))
        cp_add(Action('create'))
        nodes['create'].add_groups(['edit', 'maintain'])

        # Add latches
        cp_add(Latch('allow jane market share-price 30'))
        cp_add(Latch('allow anyone view share-price 40'))
        cp_add(Latch('deny admin view accounts 60'))
        cp_add(Latch('allow accounts-dept create accounts 70'))
        cp_add(Latch('allow jane edit salaries 85'))
        cp_add(Latch('deny accounts-dept edit salaries 85'))
        cp_add(Latch('allow jim create salaries 90'))
        cp_add(Latch('deny jane view salaries 125'))

        competition.validate()

        self.assertDictEqual(competition.dump(), TEST_COMPETITION_DICT)

class TestLatchPonyStandardGraph(DebugPrintingTestCase):

    def setUp(self):
        self.competition = Competition.load(TEST_COMPETITION_TREE)

    def __getattr__(self, attr):
        """Allow nodes to be found from test case, which delegates to
        self.competition.nodes
        """
        if attr == 'nodes':
            return self.competition.nodes
        else:
            raise AttributeError("{} attribute not found".format(attr))

    def tearDown(self):
        pass

    def test_competition_dump(self):
        self.assertDictEqual(self.competition.dump(), TEST_COMPETITION_DICT)

    def test_cant_make_instance_of_abstract_base_class(self):
        with self.assertRaises(TypeError) as ctxmgr:
            obj = LatchPonyNode('abstract')
        self.assertIn("Can't instantiate abstract class",
                      ctxmgr.exception.message)

    def test_rider_groups(self):
        self.assertEqual(self.nodes['jane'].groups, {'admin'})
        self.assertEqual(self.nodes['jim'].groups, {'admin', 'accounts-dept'})
        self.assertEqual(self.nodes['admin'].groups, {'staff'})
        self.assertEqual(self.nodes['staff'].groups, {'anyone'})
        self.assertEqual(self.nodes['anyone'].groups, set())

    def test_rider_members(self):
        self.assertEqual(self.nodes['anyone'].members, {'staff'})
        self.assertEqual(self.nodes['staff'].members,
                         {'admin', 'accounts-dept'})
        self.assertEqual(self.nodes['accounts-dept'].members, {'jim'})
        self.assertEqual(self.nodes['admin'].members, {'jane', 'jim'})

    def test_all_ponies(self):
        self.assertItemsEqual(self.competition.all_ponies,
                              ['accounts', 'anything', 'financial',
                               'salaries', 'share-price'])

    def test_all_riders(self):
        self.assertItemsEqual(self.competition.all_riders,
                              ['accounts-dept', 'admin', 'anyone',
                               'jane', 'jim', 'staff'])

    def test_latches(self):
        expected_latch_keys = {LATCH_DENY_ALL,
                               'allow jane to market share-price wt 30',
                               'allow anyone to view share-price wt 40',
                               'deny admin to view accounts wt 60',
                               'allow accounts-dept to create accounts wt 70',
                               'allow jane to edit salaries wt 85',
                               'deny accounts-dept to edit salaries wt 85',
                               'allow jim to create salaries wt 90',
                               'deny jane to view salaries wt 125'}
        self.assertItemsEqual(expected_latch_keys,
                              self.competition.descendants('permissions'))
        #self.debug_print(self.competition)
        #assert 0

    def test_add_duplicate_rider_changes_names_with_uuid(self):
        jim_duplicate = Rider(name='jim')
        self.assertEqual(jim_duplicate.name, 'jim')
        self.competition.add(jim_duplicate)
        self.assertTrue(jim_duplicate.name.startswith('jim$'))
        self.assertEqual(len(jim_duplicate.name), UUID_LENGTH + 4)

    def test_remove_group(self):
        self.nodes['admin'].remove_groups(['staff'])
        self.competition.validate()
        self.assertEqual(self.nodes['staff'].members, set(['accounts-dept']))
        self.assertEqual(self.nodes['admin'].groups, set())

    @pytest.mark.skip
    def test_rider_ancestors(self):
        ancs = self.competition.ancestors
        self.assertItemsEqual(ancs('jane'), {'admin', 'anyone', 'staff'})
        self.assertItemsEqual(ancs('jim'), {'accounts-dept', 'admin',
                                            'anyone', 'staff'})
        self.assertItemsEqual(ancs('accounts-dept'), {'anyone', 'staff'})
        self.assertItemsEqual(ancs('admin'), {'anyone', 'staff'})
        self.assertItemsEqual(ancs('staff'), {'anyone'})
        self.assertEqual(str(ancs.cache_info()),
                "CacheInfo(hits=128, misses=69, maxsize=1000, currsize=69)")

    @pytest.mark.skip
    def test_pony_ancestors(self):
        ancs = self.competition.ancestors
        sae = self.assertItemsEqual
        sae(ancs('accounts'), {'anything', 'financial'})
        sae(ancs('salaries'), {'accounts', 'anything', 'financial'})
        sae(ancs('share-price'), {'anything', 'financial'})
        sae(ancs('financial'), {'anything'})
        self.assertEqual(str(ancs.cache_info()),
                "CacheInfo(hits=128, misses=64, maxsize=1000, currsize=64)")

    def test_action_ancestors_for_deny(self):
        #self.debug_print(self.competition)
        ancs = self.competition.ancestors
        sae = self.assertItemsEqual
        sae(ancs('view'), {'action'})
        sae(ancs('edit'), {'action', 'view'})
        sae(ancs('create'), {'action', 'edit', 'maintain', 'view'})

    @pytest.mark.skip
    # Data has changed
    def test_descendants(self):
        descs = self.competition.descendants
        self.assertItemsEqual(descs('financial'),
                              {'accounts', 'salaries', 'share-price'})
        self.assertItemsEqual(descs('staff'),
                              {'accounts-dept', 'admin', 'jane', 'jim'})
        self.assertItemsEqual(descs('jane'), set())
        self.assertItemsEqual(descs('jim'), set())
        self.assertEqual(str(descs.cache_info()),
                "CacheInfo(hits=93, misses=45, maxsize=1000, currsize=45)")

    def test_action_descendants_for_allow(self):
        descs = self.competition.descendants
        sae = self.assertItemsEqual
        sae(descs('action'), {'create', 'maintain', 'market', 'edit',
                               'view'})
        sae(descs('view'), {'create', 'maintain', 'market', 'edit'})
        sae(descs('maintain'), {'create'})
        sae(descs('market'), set())

    def test_expand_permission_type(self):
        ept = self.competition.expand_permission_type
        self.assertEqual(ept('deny', 'view'),
                         set([('deny', 'market'), ('deny', 'view'),
                              ('deny', 'create'), ('deny', 'maintain'),
                              ('deny', 'edit')]))
        with self.assertRaises(CompetitionError):
            ept('probably', 'view')

    @pytest.mark.skip
    # Data has changed
    def test_competition_dump(self):
        output = self.competition.dump()
        # Fix the creation date/time to be the same
        output['created'] = TEST_COMPETITION_DICT['created']
        self.assertDictEqual(output, TEST_COMPETITION_DICT)

class TestRider(unittest.TestCase):

    def setUp(self):
        pass

    def test_setting_name(self):
        # We need to test these methods in a subclass of LatchPonyNode
        # because that class is abstract
        rider = Rider(name='jim')
        self.assertEqual(rider.name, 'jim')
        self.assertEqual(rider.caption, 'Jim')
        rider = Rider(name='jim')
        self.assertEqual(rider.name, 'jim')
        self.assertEqual(rider.caption, 'Jim')

    def test_add_and_remove_groups(self):
        rider = Rider(name='andrew')
        rider.add_groups(['red', 'blue'])
        self.assertItemsEqual(rider.groups, {'red', 'blue'})
        rider.remove_groups(['green', 'red'])
        self.assertItemsEqual(rider.groups, {'blue'})

if __name__ == '__main__':
    print("Starting...\n")
    #TestCompetition('test_load_with_unknown_format').run()
    #TestLatchPonyHandBuiltGraph('test_build_graph_by_hand').run()

    #TestLatches('test_latch_gates').run()
    #TestLatches('test_riders_for_pony').run()
    #TestCompetitionLoading('test_competition_load_and_dump').run()
    #TestLatchPonyStandardGraph('test_action_ancestors_for_deny').run()
    #TestActionWithPermission('test_allowed').run()
    #TestEmptyCompetition('test_adding_latch').run()
    TestNewLatchPonyNode('test_make_node').run()

    print("\nFinished.")


text:
package com.swfarm.biz.chain.web;

import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

import com.swfarm.biz.chain.utils.PdfUtils;
import com.swfarm.biz.warehouse.bo.AllocationProductVoucherList;
import com.swfarm.biz.warehouse.bo.Warehouse;
import com.swfarm.biz.warehouse.srv.WarehouseService;
import com.swfarm.pub.utils.DateUtils;

public class GenerateAllocationProductVoucherListFilesController extends
		AbstractController {

	private WarehouseService warehouseService;

	public void setWarehouseService(WarehouseService warehouseService) {
		this.warehouseService = warehouseService;
	}

	protected ModelAndView handleRequestInternal(HttpServletRequest req,
			HttpServletResponse res) throws Exception {
		String generateDateStr = req.getParameter("generateDate");
		Date generateDate = null;
		if (StringUtils.isNotEmpty(generateDateStr)) {
			generateDate = DateUtils.stringToDate(generateDateStr, "yyyyMMdd");
		} else {
			generateDate = DateUtils.getToday();
		}
		List apvlList = this.warehouseService
				.findAllocationProductVoucherListsByGenerateDate(generateDate);
		for (Iterator apvlIter = apvlList.iterator(); apvlIter.hasNext();) {
			AllocationProductVoucherList apvl = (AllocationProductVoucherList) apvlIter
					.next();
			String saleChannel = apvl.getSaleChannel();
			String warehouseCode = apvl.getWarehouseCode();
			Warehouse warehouse = this.warehouseService
					.findWarehouseByCode(warehouseCode);
			logger.warn("warehouse [" + warehouseCode + "] sale channel ["
					+ saleChannel + "]");
			if (warehouse.getDefaultWarehouse() == true
					&& ("Ebay".equalsIgnoreCase(saleChannel) || StringUtils
							.isEmpty(saleChannel))) {
				if (!"EUB".equalsIgnoreCase(apvl.getShippingForwarderMethod())) {
					PdfUtils.generateAllocationProductVoucherListFile(apvl);
				} else {
					PdfUtils.generateEubAllocationProductVoucherListFile(apvl);
				}
			}
		}
		return new ModelAndView(
				"redirect:/warehouse/allocationproductvoucherlists.ahtml");
	}

}

redpajama_set_name: RedPajamaGithub


text:
package com.ait.toolkit.titanium.mobile.client.core.events.media.audio;

import com.ait.toolkit.titanium.mobile.client.core.events.TiEvent;
import com.google.gwt.core.client.JavaScriptObject;

public class ChangeEvent extends TiEvent {

    public static String CHANGE = "change";

    protected ChangeEvent() {

    }

    private ChangeEvent(JavaScriptObject obj) {
        jsObj = obj;
    }

    /**
     * current state of playback
     */
    public native int getState() /*-{
		var jso = this.@com.ait.toolkit.core.client.JsObject::getJsObj()()
		return jso.state;
    }-*/;

    /**
     * textual description of the state of playback
     */
    public native String getDescription() /*-{
		var jso = this.@com.ait.toolkit.core.client.JsObject::getJsObj()()
		return jso.description;
    }-*/;

}


text:
using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
using Microsoft.Ajax.Utilities;

namespace Microsoft.NodejsTools.Parsing
{

    //-------------------------------------------------------------------------------------------------------
    // JScriptException
    //
    //  An error in JScript goes to a COM+ host/program in the form of a JScriptException. However a
    //  JScriptException is not always thrown. In fact a JScriptException is also a IVsaError and thus it can be
    //  passed to the host through IVsaSite.OnCompilerError(IVsaError error).
    //  When a JScriptException is not a wrapper for some other object (usually either a COM+ exception or
    //  any value thrown in a JScript throw statement) it takes a JSError value.
    //  The JSError enum is defined in JSError.cs. When introducing a new type of error perform
    //  the following four steps:
    //  1- Add the error in the JSError enum (JSError.cs)
    //  2- Update JScript.resx with the US English error message
    //  3- Update Severity.
    //-------------------------------------------------------------------------------------------------------
#if !SILVERLIGHT
    [Serializable]
#endif
    internal class JScriptException : Exception
    {
        #region private fields

#if !SILVERLIGHT
        [NonSerialized]
#endif

        private string m_valueObject;
        private bool m_isError;
        private JSError m_errorCode;
        private readonly IndexSpan _span;
        private readonly LocationResolver _resolver;
        private bool m_canRecover = true;

        #endregion

        #region constructors

        public JScriptException(string message) : this(message, null) { }
        public JScriptException(string message, Exception innerException)
            : base(message, innerException) {
            m_valueObject = message;
            m_errorCode = JSError.UncaughtException;
            SetHResult();
        }

        internal JScriptException(JSError errorNumber, IndexSpan span, LocationResolver resolver) {
            m_valueObject = null;
            _span = span;
            _resolver = resolver;
            m_errorCode = errorNumber;
            SetHResult();
        }

#if !SILVERLIGHT
        protected JScriptException(SerializationInfo info, StreamingContext context)
            : base(info, context) {
            if (info == null) {
                throw new ArgumentException(JScript.InternalCompilerError);
            }

            m_valueObject = info.GetString("Value");
            m_isError = info.GetBoolean("IsError");
            m_errorCode = (JSError)info.GetInt32("JSError");
            m_canRecover = info.GetBoolean("CanRecover");
        }
#endif

        #endregion

        #region public properties

        public IndexSpan Span {
            get {
                return _span;
            }
        }

        public bool CanRecover
        {
            get { return m_canRecover; }
            set { m_canRecover = value; }
        }

        public bool IsError
        {
            get { return m_isError; }
            set { m_isError = value; }
        }

        public string Value
        {
            get { return m_valueObject; }
            set { m_valueObject = value; }
        }

        public int StartColumn
        {
            get
            {
                return Column;
            }
        }

        public int Line
        {
            get
            {
                if (_resolver != null)
                {
                    return _resolver.IndexToLocation(_span.Start).Line;
                }
                else
                {
                    return 1;
                }
            }
        }

        public int Column
        {
            get
            {
                if (_resolver != null)
                {
                    // one-based column number
                    return _resolver.IndexToLocation(_span.Start).Column;
                }
                else
                {
                    return 0;
                }
            }
        }

        public int EndLine
        {
            get
            {
                if (_resolver != null)
                {
                    return _resolver.IndexToLocation(_span.End).Line;
                }
                else
                {
                    return 0;
                }
            }
        }

        public int EndColumn
        {
            get
            {
                if (_resolver != null)
                {
                    return _resolver.IndexToLocation(_span.End).Column;
                }
                else
                    return 0;
            }
        }

        public override String Message
        {
            get
            {
                string code = m_errorCode.ToString();
                if (m_valueObject != null)
                {
                    return (m_errorCode == JSError.DuplicateName)
                        ? JScript.ResourceManager.GetString(code, JScript.Culture).FormatInvariant(m_valueObject)
                        : m_valueObject;
                }

                // special case some errors with contextual information
                return JScript.ResourceManager.GetString(code, JScript.Culture).FormatInvariant(
                    "");    // TODO: Re-enable getting context code?
#if FALSE
                    m_context.IfNotNull(c => c.HasCode) ? string.Empty : m_context.Code);
#endif
            }
        }

        public JSError ErrorCode
        {
            get { return m_errorCode; }
        }

        public int Severity
        {
            get
            {
                return GetSeverity(m_errorCode);
            }
        }

        #endregion

        #region public methods

        #if !SILVERLIGHT
        [SecurityCritical]
        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null) throw new ArgumentNullException("info");
            base.GetObjectData(info, context);
            info.AddValue("Value", m_valueObject);
            info.AddValue("IsError", m_isError);
            info.AddValue("JSError", (int)m_errorCode);
            info.AddValue("CanRecover", m_canRecover);
        }
        #endif

        #endregion

        #region public static methods

        /// <summary>
        /// Return the default severity for a given JSError value
        /// guide: 0 == there will be a run-time error if this code executes
        ///        1 == the programmer probably did not intend to do this
        ///        2 == this can lead to cross-browser of future problems.
        ///        3 == this can lead to performance problems
        ///        4 == this is just not right
        /// </summary>
        /// <param name="errorCode">error code</param>
        /// <returns>severity</returns>
        public static int GetSeverity(JSError errorCode)
        {
            switch (errorCode)
            {
                case JSError.AmbiguousCatchVar:
                case JSError.AmbiguousNamedFunctionExpression:
                case JSError.NumericOverflow:
                case JSError.StrictComparisonIsAlwaysTrueOrFalse:
                    return 1;

                case JSError.DuplicateCatch:
                case JSError.DuplicateConstantDeclaration:
                case JSError.DuplicateLexicalDeclaration:
                case JSError.KeywordUsedAsIdentifier:
                case JSError.MisplacedFunctionDeclaration:
                case JSError.ObjectLiteralKeyword:
                    return 2;

                case JSError.ArgumentNotReferenced:
                case JSError.DuplicateName:
                case JSError.FunctionNotReferenced:
                case JSError.UndeclaredFunction:
                case JSError.UndeclaredVariable:
                case JSError.VariableDefinedNotReferenced:
                    return 3;

                case JSError.StatementBlockExpected:
                case JSError.SuspectAssignment:
                case JSError.SuspectSemicolon:
                case JSError.SuspectEquality:
                case JSError.WithNotRecommended:
                case JSError.ObjectConstructorTakesNoArguments:
                case JSError.NumericMaximum:
                case JSError.NumericMinimum:
                case JSError.OctalLiteralsDeprecated:
                case JSError.FunctionNameMustBeIdentifier:
                case JSError.SemicolonInsertion:
                    return 4;

                default:
                    // all others
                    return 0;
            }
        }

        #endregion

        #region private methods

        private void SetHResult()
        {
            this.HResult = //unchecked((int)(0x800A0000 + (int)m_errorCode));
                -2146828288 + (int)m_errorCode;
        }

        #endregion
    }

    internal class JScriptExceptionEventArgs : EventArgs
    {
        /// <summary>
        /// The JavaScript error information being fired
        /// </summary>
        public ContextError Error { get; private set; }

        /// <summary>
        /// JScriptException object. Don't use this; might go away in future versions. Use Error property instead.
        /// </summary>
        public JScriptException Exception { get; private set; }

        public JScriptExceptionEventArgs(JScriptException exception, ContextError error)
        {
            Error = error;
            Exception = exception;
        }
    }
}


text:
namespace g{namespace Uno{namespace Content{namespace Fonts{struct BitmapFont__GlyphInfo;}}}}

namespace g{
namespace Uno{
namespace Content{
namespace Fonts{

// public struct BitmapFont.GlyphInfo :10
// {
uStructType* BitmapFont__GlyphInfo_typeof();

struct BitmapFont__GlyphInfo
{
    float Advance;
    ::g::Uno::Float2 Bearing;
    ::g::Uno::Float2 Size;
    ::g::Uno::UShort2 UpperLeft;
    ::g::Uno::UShort2 LowerRight;
};
// }

}}}} // ::g::Uno::Content::Fonts


text:
package io.selendroid;

import org.openqa.selenium.Keys;

/**
 * Keystrokes to simulate Android native key events.
 *
 * <pre>{@code
 * ((HasInputDevices) driver).getKeyboard().sendKeys(SelendroidKeys.MENU);
 * }</pre>
 *
 * @author ddary
 */
public interface SelendroidKeys {
  // Keys that are shared with normal WebDriver (sorted alphabetically)
  public static final CharSequence ALT_LEFT = Keys.ALT;
  public static final CharSequence DEL = Keys.DELETE;
  public static final CharSequence DPAD_DOWN = Keys.ARROW_DOWN;
  public static final CharSequence DPAD_LEFT = Keys.ARROW_LEFT;
  public static final CharSequence DPAD_RIGHT = Keys.ARROW_RIGHT;
  public static final CharSequence DPAD_UP = Keys.ARROW_UP;
  public static final CharSequence ENTER = Keys.ENTER;
  public static final CharSequence SHIFT_LEFT = Keys.SHIFT;

  public static final CharSequence BACK = String.valueOf('\uE100');
  public static final CharSequence ANDROID_HOME = String.valueOf('\uE101');
  public static final CharSequence MENU = String.valueOf('\uE102');
  public static final CharSequence SEARCH = String.valueOf('\uE103');
  public static final CharSequence SYM = String.valueOf('\uE104');
  public static final CharSequence ALT_RIGHT = String.valueOf('\uE105');
  public static final CharSequence SHIFT_RIGHT = String.valueOf('\uE106');
}


text:
package org.eclipse.jdt.internal.ui.text.spelling;

import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;

import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
import org.eclipse.jface.text.source.ISourceViewer;

import org.eclipse.ui.texteditor.spelling.SpellingProblem;

import org.eclipse.jdt.internal.corext.util.Messages;

import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;

import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jdt.internal.ui.JavaUIMessages;
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellCheckEngine;
import org.eclipse.jdt.internal.ui.text.spelling.engine.ISpellChecker;

/**
 * Proposal to ignore the word during the current editing session.
 *
 * @since 3.0
 */
public class WordIgnoreProposal implements IJavaCompletionProposal {

	/** The invocation context */
	private IQuickAssistInvocationContext fContext;

	/** The word to ignore */
	private String fWord;

	/**
	 * Creates a new spell ignore proposal.
	 *
	 * @param word
	 *                   The word to ignore
	 * @param context
	 *                   The invocation context
	 */
	public WordIgnoreProposal(final String word, final IQuickAssistInvocationContext context) {
		fWord= word;
		fContext= context;
	}

	/*
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument)
	 */
	public final void apply(final IDocument document) {

		final ISpellCheckEngine engine= SpellCheckEngine.getInstance();
		final ISpellChecker checker= engine.getSpellChecker();

		if (checker != null) {
			checker.ignoreWord(fWord);
			ISourceViewer sourceViewer= fContext.getSourceViewer();
			if (sourceViewer != null)
				SpellingProblem.removeAll(sourceViewer, fWord);
		}
	}

	/*
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
	 */
	public String getAdditionalProposalInfo() {
		return Messages.format(JavaUIMessages.Spelling_ignore_info, new String[] { WordCorrectionProposal.getHtmlRepresentation(fWord)});
	}

	/*
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation()
	 */
	public final IContextInformation getContextInformation() {
		return null;
	}

	/*
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
	 */
	public String getDisplayString() {
		return Messages.format(JavaUIMessages.Spelling_ignore_label, new String[] { fWord });
	}

	/*
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage()
	 */
	public Image getImage() {
		return JavaPluginImages.get(JavaPluginImages.IMG_OBJS_NLS_NEVER_TRANSLATE);
	}
	/*
	 * @see org.eclipse.jdt.ui.text.java.IJavaCompletionProposal#getRelevance()
	 */
	public final int getRelevance() {
		return Integer.MIN_VALUE + 1;
	}

	/*
	 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument)
	 */
	public final Point getSelection(final IDocument document) {
		return new Point(fContext.getOffset(), fContext.getLength());
	}
}


text:
package net.techreadiness.service.exception;

import java.util.List;
import java.util.Map;

import javax.xml.ws.WebFault;

import net.techreadiness.service.common.ValidationError;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

@WebFault(name = "ServiceFault")
public class ValidationServiceException extends ServiceException {
	private static final long serialVersionUID = 1L;

	public ValidationServiceException() {

	}

	public ValidationServiceException(String message) {
		super(message);
	}

	public ValidationServiceException(String message, FaultInfo faultInfo) {
		super(message, faultInfo);
	}

	public ValidationServiceException(FaultInfo faultInfo) {
		super(faultInfo);
	}

	public Map<String, List<String>> getErrorMap() {
		return getErrorMap(null);
	}

	public Map<String, List<String>> getErrorMap(String baseFieldName) {
		Map<String, List<String>> errors = Maps.newHashMap();
		for (ValidationError error : getFaultInfo().getAttributeErrors()) {
			String fieldName = (baseFieldName == null ? "" : baseFieldName + ".") + error.getFieldName();
			if (!errors.containsKey(fieldName)) {
				errors.put(fieldName, Lists.<String> newArrayList());
			}
			errors.get(fieldName).add(error.getOnlineMessage());
		}
		return errors;
	}

	public Map<String, List<String>> getBatchErrorMap() {
		Map<String, List<String>> errors = Maps.newHashMap();
		for (ValidationError error : getFaultInfo().getAttributeErrors()) {
			String batchErrorCode = error.getBatchCode();

			if (!errors.containsKey(batchErrorCode)) {
				errors.put(batchErrorCode, Lists.<String> newArrayList());
			}
			errors.get(batchErrorCode).add(error.getBatchMessage());
		}
		return errors;
	}
}


text:
#ifndef ctrlplane_policy_graph_h
#define ctrlplane_policy_graph_h

#include <boost/function.hpp>
#include <boost/intrusive/list.hpp>

#include "routing-policy/policy_graph_base.h"
#include "routing-policy/policy_vertex.h"

class PolicyGraphEdge;
class PolicyGraphVertex;

class PolicyGraph : public PolicyGraphBase {
public:
    typedef PolicyGraphBase::edge_descriptor Edge;
    typedef PolicyGraphBase::vertex_descriptor Vertex;
    typedef boost::intrusive::member_hook<PolicyGraphVertex,
            boost::intrusive::list_member_hook<>,
            &PolicyGraphVertex::open_vertex_> OpenVertexListMember;
    typedef boost::intrusive::list<PolicyGraphVertex,
            OpenVertexListMember> OpenVertexList;
    typedef OpenVertexList::iterator OpenVertexIterator;

    void AddNode(PolicyGraphVertex *entry);

    void RemoveNode(PolicyGraphVertex *entry);

    Edge Link(PolicyGraphVertex *lhs, PolicyGraphVertex *rhs);

    void Unlink(PolicyGraphVertex *lhs, PolicyGraphVertex *rhs);

    void SetEdgeProperty(PolicyGraphEdge *edge);

    PolicyGraphEdge *GetEdge(const PolicyGraphVertex *src,
                             const PolicyGraphVertex *tgt);

    const graph_t *graph() const { return &root_; }

    PolicyGraphVertex *vertex_data(Vertex vertex) const {
        return root_[vertex].entry;
    }

    PolicyGraphEdge *edge_data(PolicyGraph::Edge edge) const {
        return root_[edge].edge;
    }

    void clear();

    size_t vertex_count() const;
    size_t edge_count() const;

    void WriteDot(const std::string &fname) const;

    OpenVertexIterator open_vertex_begin();

    OpenVertexIterator open_vertex_end();

    void AddOpenVertex(PolicyGraphVertex *vertex);

    void RemoveOpenVertex(PolicyGraphVertex *vertex);

    typedef std::pair<PolicyGraphVertex *,
            PolicyGraphEdge *> OpenVertexPathPair;
    class open_vertex_reverse_iterator : public boost::iterator_facade<
        open_vertex_reverse_iterator, OpenVertexPathPair,
        boost::forward_traversal_tag, OpenVertexPathPair> {
    public:
        open_vertex_reverse_iterator()
            : graph_(NULL), open_(NULL) {
        }

        open_vertex_reverse_iterator(PolicyGraph *graph,
                                     PolicyGraphVertex *start)
            : graph_(graph), open_(start) {
        }

    private:
        friend class boost::iterator_core_access;

        void increment();

        bool equal(const open_vertex_reverse_iterator &rhs) const;

        OpenVertexPathPair dereference() const;

        PolicyGraph *graph_;
        PolicyGraphVertex *open_;
    };

    open_vertex_reverse_iterator begin(PolicyGraphVertex *open) {
        return open_vertex_reverse_iterator(this, open);
    }

    open_vertex_reverse_iterator end(PolicyGraphVertex *open) {
        return open_vertex_reverse_iterator();
    }

    PolicyGraphVertex *GetRoot() const;
private:
    graph_t root_;
    OpenVertexList open_vertex_list_;
};

#endif // ctrlplane_policy_graph_h


text:
<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <solid android:color="@color/colorPrimary" />
    <corners android:radius="8dp" />

    <stroke
        android:width="0dp"
        android:color="@color/colorAccent" />

</shape>


text:
'use strict';

var todosService = require('../../../services/todos');
var redirect = require('../redirect');
var emit = require('../socket-emit');

function completeTodo (req, res, next) {
  var completed = req.body.completed === 'true';
  var todo = {
    id: req.params.id,
    completed: !completed
  };
  todosService.complete(todo, handler);

  function handler(err, todo) {
    if (err) {
      return next(err);
    }

    res.viewModel = {
      model: todo
    };

    redirect(req, res);

    var room = '/todos';
    emit(req, room, {
      updates: [{
        rooms: [room],
        operations: [{
          op: 'mark-completed',
          model: todo,
          concern: 'todos',
          query: { id: todo.id }
        }, {
          op: 'add',
          value: todo.completed ? -1 : 1,
          concern: 'activeTodosCount'
        }, {
          op: 'add',
          value: todo.completed ? 1 : -1,
          concern: 'completedTodosCount'
        }]
      }]
    });
  }
}

module.exports = completeTodo;


text:
<moya xmlns="http://moyaproject.com">

    <model xmlns="http://moyaproject.com/db" name="Post" libname="Post" repr="${slug}">
        <foreign-key model="auth#User" name="owner" null="yes" />
        <string name="title" length="100" null="no" />
        <string name="slug" length="100" null="no" blank="no" unique="yes" />
        <boolean name="published" default="no" />
        <datetime name="published_date" null="yes" />
        <datetime name="updated_date" null="yes" />
        <integer name="update" null="no" default="0" />
        <text name="content" null="no" default="" markup="${.app.settings.default_markup}" />
    </model>

</moya>