1f8369d7dSTobias Sarnowski<?php 2f8369d7dSTobias Sarnowski 3f8369d7dSTobias Sarnowskiclass auth_acl_test extends DokuWikiTest { 4f8369d7dSTobias Sarnowski 5f8369d7dSTobias Sarnowski var $oldConf; 6f8369d7dSTobias Sarnowski var $oldAuthAcl; 7f8369d7dSTobias Sarnowski 8f8369d7dSTobias Sarnowski function setup() { 9f8369d7dSTobias Sarnowski global $conf; 10f8369d7dSTobias Sarnowski global $AUTH_ACL; 11f8369d7dSTobias Sarnowski global $auth; 12f8369d7dSTobias Sarnowski $this->oldConf = $conf; 13f8369d7dSTobias Sarnowski $this->oldAuthAcl = $AUTH_ACL; 14f8369d7dSTobias Sarnowski $auth = new auth_basic(); 15f8369d7dSTobias Sarnowski } 16f8369d7dSTobias Sarnowski 17f8369d7dSTobias Sarnowski function teardown() { 18f8369d7dSTobias Sarnowski global $conf; 19f8369d7dSTobias Sarnowski global $AUTH_ACL; 20f8369d7dSTobias Sarnowski $conf = $this->oldConf; 21f8369d7dSTobias Sarnowski $AUTH_ACL = $this->oldAuthAcl; 22f8369d7dSTobias Sarnowski 23f8369d7dSTobias Sarnowski } 24f8369d7dSTobias Sarnowski 25f8369d7dSTobias Sarnowski function test_restricted(){ 26f8369d7dSTobias Sarnowski global $conf; 27f8369d7dSTobias Sarnowski global $AUTH_ACL; 28f8369d7dSTobias Sarnowski $conf['superuser'] = 'john'; 29f8369d7dSTobias Sarnowski $conf['useacl'] = 1; 30f8369d7dSTobias Sarnowski 31f8369d7dSTobias Sarnowski $AUTH_ACL = array( 32f8369d7dSTobias Sarnowski '* @ALL 0', 33f8369d7dSTobias Sarnowski '* @user 8', 34f8369d7dSTobias Sarnowski ); 35f8369d7dSTobias Sarnowski 36f8369d7dSTobias Sarnowski // anonymous user 37f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', '',array()), AUTH_NONE); 38f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','',array()), AUTH_NONE); 39f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', '',array()), AUTH_NONE); 40f8369d7dSTobias Sarnowski 41f8369d7dSTobias Sarnowski // user with no matching group 42f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jill',array('foo')), AUTH_NONE); 43f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','jill',array('foo')), AUTH_NONE); 44f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'jill',array('foo')), AUTH_NONE); 45f8369d7dSTobias Sarnowski 46f8369d7dSTobias Sarnowski // user with matching group 47f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jill',array('foo','user')), AUTH_UPLOAD); 48f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','jill',array('foo','user')), AUTH_UPLOAD); 49f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'jill',array('foo','user')), AUTH_UPLOAD); 50f8369d7dSTobias Sarnowski 51f8369d7dSTobias Sarnowski // super user 52f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'john',array('foo')), AUTH_ADMIN); 53f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','john',array('foo')), AUTH_ADMIN); 54f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'john',array('foo')), AUTH_ADMIN); 55f8369d7dSTobias Sarnowski } 56f8369d7dSTobias Sarnowski 57f8369d7dSTobias Sarnowski function test_restricted_ropage(){ 58f8369d7dSTobias Sarnowski global $conf; 59f8369d7dSTobias Sarnowski global $AUTH_ACL; 60f8369d7dSTobias Sarnowski $conf['superuser'] = 'john'; 61f8369d7dSTobias Sarnowski $conf['useacl'] = 1; 62f8369d7dSTobias Sarnowski 63f8369d7dSTobias Sarnowski $AUTH_ACL = array( 64f8369d7dSTobias Sarnowski '* @ALL 0', 65f8369d7dSTobias Sarnowski '* @user 8', 66f8369d7dSTobias Sarnowski 'namespace:page @user 1', 67f8369d7dSTobias Sarnowski ); 68f8369d7dSTobias Sarnowski 69f8369d7dSTobias Sarnowski // anonymous user 70f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', '',array()), AUTH_NONE); 71f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','',array()), AUTH_NONE); 72f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', '',array()), AUTH_NONE); 73f8369d7dSTobias Sarnowski 74f8369d7dSTobias Sarnowski // user with no matching group 75f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jill',array('foo')), AUTH_NONE); 76f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','jill',array('foo')), AUTH_NONE); 77f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'jill',array('foo')), AUTH_NONE); 78f8369d7dSTobias Sarnowski 79f8369d7dSTobias Sarnowski // user with matching group 80f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jill',array('foo','user')), AUTH_UPLOAD); 81f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','jill',array('foo','user')), AUTH_READ); 82f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'jill',array('foo','user')), AUTH_UPLOAD); 83f8369d7dSTobias Sarnowski 84f8369d7dSTobias Sarnowski // super user 85f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'john',array('foo')), AUTH_ADMIN); 86f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','john',array('foo')), AUTH_ADMIN); 87f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'john',array('foo')), AUTH_ADMIN); 88f8369d7dSTobias Sarnowski } 89f8369d7dSTobias Sarnowski 90f8369d7dSTobias Sarnowski function test_aclexample(){ 91f8369d7dSTobias Sarnowski global $conf; 92f8369d7dSTobias Sarnowski global $AUTH_ACL; 93f8369d7dSTobias Sarnowski $conf['superuser'] = 'john'; 94f8369d7dSTobias Sarnowski $conf['useacl'] = 1; 95f8369d7dSTobias Sarnowski 96f8369d7dSTobias Sarnowski $AUTH_ACL = array( 97f8369d7dSTobias Sarnowski '* @ALL 4', 98f8369d7dSTobias Sarnowski '* bigboss 16', 99f8369d7dSTobias Sarnowski 'start @ALL 1', 100f8369d7dSTobias Sarnowski 'marketing:* @marketing 8', 101f8369d7dSTobias Sarnowski 'devel:* @ALL 0', 102f8369d7dSTobias Sarnowski 'devel:* @devel 8', 103f8369d7dSTobias Sarnowski 'devel:* bigboss 16', 104f8369d7dSTobias Sarnowski 'devel:funstuff bigboss 0', 105f8369d7dSTobias Sarnowski 'devel:* @marketing 1', 106f8369d7dSTobias Sarnowski 'devel:marketing @marketing 2', 107f8369d7dSTobias Sarnowski ); 108f8369d7dSTobias Sarnowski 109f8369d7dSTobias Sarnowski 110f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', '' ,array()) , AUTH_CREATE); 111f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'bigboss' ,array('foo')) , AUTH_DELETE); 112f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jill' ,array('marketing')) , AUTH_CREATE); 113f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jane' ,array('devel')) , AUTH_CREATE); 114f8369d7dSTobias Sarnowski 115f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('start', '' ,array()) , AUTH_READ); 116f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('start', 'bigboss' ,array('foo')) , AUTH_READ); 117f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('start', 'jill' ,array('marketing')) , AUTH_READ); 118f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('start', 'jane' ,array('devel')) , AUTH_READ); 119f8369d7dSTobias Sarnowski 120f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('marketing:page', '' ,array()) , AUTH_CREATE); 121f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('marketing:page', 'bigboss' ,array('foo')) , AUTH_DELETE); 122f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('marketing:page', 'jill' ,array('marketing')) , AUTH_UPLOAD); 123f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('marketing:page', 'jane' ,array('devel')) , AUTH_CREATE); 124f8369d7dSTobias Sarnowski 125f8369d7dSTobias Sarnowski 126f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('devel:page', '' ,array()) , AUTH_NONE); 127f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('devel:page', 'bigboss' ,array('foo')) , AUTH_DELETE); 128f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('devel:page', 'jill' ,array('marketing')) , AUTH_READ); 129f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('devel:page', 'jane' ,array('devel')) , AUTH_UPLOAD); 130f8369d7dSTobias Sarnowski 131f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('devel:funstuff', '' ,array()) , AUTH_NONE); 132f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('devel:funstuff', 'bigboss' ,array('foo')) , AUTH_NONE); 133f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('devel:funstuff', 'jill' ,array('marketing')) , AUTH_READ); 134f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('devel:funstuff', 'jane' ,array('devel')) , AUTH_UPLOAD); 135f8369d7dSTobias Sarnowski 136f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('devel:marketing', '' ,array()) , AUTH_NONE); 137f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('devel:marketing', 'bigboss' ,array('foo')) , AUTH_DELETE); 138f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('devel:marketing', 'jill' ,array('marketing')) , AUTH_EDIT); 139f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('devel:marketing', 'jane' ,array('devel')) , AUTH_UPLOAD); 140f8369d7dSTobias Sarnowski 141f8369d7dSTobias Sarnowski } 142f8369d7dSTobias Sarnowski 143f8369d7dSTobias Sarnowski function test_multiadmin_restricted(){ 144f8369d7dSTobias Sarnowski global $conf; 145f8369d7dSTobias Sarnowski global $AUTH_ACL; 146f8369d7dSTobias Sarnowski $conf['superuser'] = 'john,@admin,doe,@roots'; 147f8369d7dSTobias Sarnowski $conf['useacl'] = 1; 148f8369d7dSTobias Sarnowski 149f8369d7dSTobias Sarnowski $AUTH_ACL = array( 150f8369d7dSTobias Sarnowski '* @ALL 0', 151f8369d7dSTobias Sarnowski '* @user 8', 152f8369d7dSTobias Sarnowski ); 153f8369d7dSTobias Sarnowski 154f8369d7dSTobias Sarnowski // anonymous user 155f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', '',array()), AUTH_NONE); 156f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','',array()), AUTH_NONE); 157f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', '',array()), AUTH_NONE); 158f8369d7dSTobias Sarnowski 159f8369d7dSTobias Sarnowski // user with no matching group 160f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jill',array('foo')), AUTH_NONE); 161f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','jill',array('foo')), AUTH_NONE); 162f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'jill',array('foo')), AUTH_NONE); 163f8369d7dSTobias Sarnowski 164f8369d7dSTobias Sarnowski // user with matching group 165f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jill',array('foo','user')), AUTH_UPLOAD); 166f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','jill',array('foo','user')), AUTH_UPLOAD); 167f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'jill',array('foo','user')), AUTH_UPLOAD); 168f8369d7dSTobias Sarnowski 169f8369d7dSTobias Sarnowski // super user john 170f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'john',array('foo')), AUTH_ADMIN); 171f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','john',array('foo')), AUTH_ADMIN); 172f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'john',array('foo')), AUTH_ADMIN); 173f8369d7dSTobias Sarnowski 174f8369d7dSTobias Sarnowski // super user doe 175f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'doe',array('foo')), AUTH_ADMIN); 176f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','doe',array('foo')), AUTH_ADMIN); 177f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'doe',array('foo')), AUTH_ADMIN); 178f8369d7dSTobias Sarnowski 179f8369d7dSTobias Sarnowski // user with matching admin group 180f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jill',array('foo','admin')), AUTH_ADMIN); 181f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','jill',array('foo','admin')), AUTH_ADMIN); 182f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'jill',array('foo','admin')), AUTH_ADMIN); 183f8369d7dSTobias Sarnowski 184f8369d7dSTobias Sarnowski // user with matching another admin group 185f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jill',array('foo','roots')), AUTH_ADMIN); 186f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','jill',array('foo','roots')), AUTH_ADMIN); 187f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'jill',array('foo','roots')), AUTH_ADMIN); 188f8369d7dSTobias Sarnowski } 189f8369d7dSTobias Sarnowski 190f8369d7dSTobias Sarnowski function test_multiadmin_restricted_ropage(){ 191f8369d7dSTobias Sarnowski global $conf; 192f8369d7dSTobias Sarnowski global $AUTH_ACL; 193f8369d7dSTobias Sarnowski $conf['superuser'] = 'john,@admin,doe,@roots'; 194f8369d7dSTobias Sarnowski $conf['useacl'] = 1; 195f8369d7dSTobias Sarnowski 196f8369d7dSTobias Sarnowski $AUTH_ACL = array( 197f8369d7dSTobias Sarnowski '* @ALL 0', 198f8369d7dSTobias Sarnowski '* @user 8', 199f8369d7dSTobias Sarnowski 'namespace:page @user 1', 200f8369d7dSTobias Sarnowski ); 201f8369d7dSTobias Sarnowski 202f8369d7dSTobias Sarnowski // anonymous user 203f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', '',array()), AUTH_NONE); 204f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','',array()), AUTH_NONE); 205f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', '',array()), AUTH_NONE); 206f8369d7dSTobias Sarnowski 207f8369d7dSTobias Sarnowski // user with no matching group 208f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jill',array('foo')), AUTH_NONE); 209f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','jill',array('foo')), AUTH_NONE); 210f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'jill',array('foo')), AUTH_NONE); 211f8369d7dSTobias Sarnowski 212f8369d7dSTobias Sarnowski // user with matching group 213f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jill',array('foo','user')), AUTH_UPLOAD); 214f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','jill',array('foo','user')), AUTH_READ); 215f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'jill',array('foo','user')), AUTH_UPLOAD); 216f8369d7dSTobias Sarnowski 217f8369d7dSTobias Sarnowski // super user john 218f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'john',array('foo')), AUTH_ADMIN); 219f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','john',array('foo')), AUTH_ADMIN); 220f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'john',array('foo')), AUTH_ADMIN); 221f8369d7dSTobias Sarnowski 222f8369d7dSTobias Sarnowski // super user doe 223f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'doe',array('foo')), AUTH_ADMIN); 224f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','doe',array('foo')), AUTH_ADMIN); 225f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'doe',array('foo')), AUTH_ADMIN); 226f8369d7dSTobias Sarnowski 227f8369d7dSTobias Sarnowski // user with matching admin group 228f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jill',array('foo','admin')), AUTH_ADMIN); 229f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','jill',array('foo','admin')), AUTH_ADMIN); 230f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'jill',array('foo','admin')), AUTH_ADMIN); 231f8369d7dSTobias Sarnowski 232f8369d7dSTobias Sarnowski // user with matching another admin group 233f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('page', 'jill',array('foo','roots')), AUTH_ADMIN); 234f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:page','jill',array('foo','roots')), AUTH_ADMIN); 235f8369d7dSTobias Sarnowski $this->assertEquals(auth_aclcheck('namespace:*', 'jill',array('foo','roots')), AUTH_ADMIN); 236f8369d7dSTobias Sarnowski } 237f8369d7dSTobias Sarnowski 238*32e82180SAndreas Gohr function test_wildcards(){ 239*32e82180SAndreas Gohr global $conf; 240*32e82180SAndreas Gohr global $AUTH_ACL; 241*32e82180SAndreas Gohr global $USERINFO; 242*32e82180SAndreas Gohr $conf['useacl'] = 1; 243*32e82180SAndreas Gohr 244*32e82180SAndreas Gohr $_SERVER['REMOTE_USER'] = 'john'; 245*32e82180SAndreas Gohr $USERINFO['grps'] = array('test','töst','foo bar'); 246*32e82180SAndreas Gohr $AUTH_ACL = auth_loadACL(); // default test file 247*32e82180SAndreas Gohr 248*32e82180SAndreas Gohr // default setting 249*32e82180SAndreas Gohr $this->assertEquals(AUTH_UPLOAD, auth_aclcheck('page', $_SERVER['REMOTE_USER'], $USERINFO['grps'])); 250*32e82180SAndreas Gohr 251*32e82180SAndreas Gohr // user namespace 252*32e82180SAndreas Gohr $this->assertEquals(AUTH_DELETE, auth_aclcheck('users:john:foo', $_SERVER['REMOTE_USER'], $USERINFO['grps'])); 253*32e82180SAndreas Gohr $this->assertEquals(AUTH_READ, auth_aclcheck('users:john:foo', 'schmock', array())); 254*32e82180SAndreas Gohr 255*32e82180SAndreas Gohr // group namespace 256*32e82180SAndreas Gohr $this->assertEquals(AUTH_DELETE, auth_aclcheck('groups:test:foo', $_SERVER['REMOTE_USER'], $USERINFO['grps'])); 257*32e82180SAndreas Gohr $this->assertEquals(AUTH_READ, auth_aclcheck('groups:test:foo', 'schmock', array())); 258*32e82180SAndreas Gohr $this->assertEquals(AUTH_DELETE, auth_aclcheck('groups:toest:foo', $_SERVER['REMOTE_USER'], $USERINFO['grps'])); 259*32e82180SAndreas Gohr $this->assertEquals(AUTH_READ, auth_aclcheck('groups:toest:foo', 'schmock', array())); 260*32e82180SAndreas Gohr $this->assertEquals(AUTH_DELETE, auth_aclcheck('groups:foo_bar:foo', $_SERVER['REMOTE_USER'], $USERINFO['grps'])); 261*32e82180SAndreas Gohr $this->assertEquals(AUTH_READ, auth_aclcheck('groups:foo_bar:foo', 'schmock', array())); 262*32e82180SAndreas Gohr 263*32e82180SAndreas Gohr } 264*32e82180SAndreas Gohr 265f8369d7dSTobias Sarnowski} 266f8369d7dSTobias Sarnowski 267f8369d7dSTobias Sarnowski//Setup VIM: ex: et ts=4 : 268