1-- CXA4016.A 2-- 3-- Grant of Unlimited Rights 4-- 5-- Under contracts F33600-87-D-0337, F33600-84-D-0280, MDA903-79-C-0687, 6-- F08630-91-C-0015, and DCA100-97-D-0025, the U.S. Government obtained 7-- unlimited rights in the software and documentation contained herein. 8-- Unlimited rights are defined in DFAR 252.227-7013(a)(19). By making 9-- this public release, the Government intends to confer upon all 10-- recipients unlimited rights equal to those held by the Government. 11-- These rights include rights to use, duplicate, release or disclose the 12-- released technical data and computer software in whole or in part, in 13-- any manner and for any purpose whatsoever, and to have or permit others 14-- to do so. 15-- 16-- DISCLAIMER 17-- 18-- ALL MATERIALS OR INFORMATION HEREIN RELEASED, MADE AVAILABLE OR 19-- DISCLOSED ARE AS IS. THE GOVERNMENT MAKES NO EXPRESS OR IMPLIED 20-- WARRANTY AS TO ANY MATTER WHATSOEVER, INCLUDING THE CONDITIONS OF THE 21-- SOFTWARE, DOCUMENTATION OR OTHER INFORMATION RELEASED, MADE AVAILABLE 22-- OR DISCLOSED, OR THE OWNERSHIP, MERCHANTABILITY, OR FITNESS FOR A 23-- PARTICULAR PURPOSE OF SAID MATERIAL. 24--* 25-- 26-- OBJECTIVE: 27-- Check that the subprograms defined in package Ada.Strings.Wide_Fixed 28-- are available, and that they produce correct results. Specifically, 29-- check the subprograms Delete, Head, Insert, Overwrite, Replace_Slice, 30-- Tail, Trim, and "*". 31-- 32-- TEST DESCRIPTION: 33-- This test, when combined with tests CXA4013-15 will provide 34-- coverage of the functionality found in package Ada.Strings.Wide_Fixed. 35-- This test contains many small, specific test cases, situations that 36-- although common in user environments, are often difficult to generate 37-- in large numbers in a application-based test. They represent 38-- individual usage paradigms in-the-small. 39-- 40-- 41-- CHANGE HISTORY: 42-- 06 Dec 94 SAIC ACVC 2.0 43-- 10 Apr 94 SAIC Modified comments in a subtest failure message. 44-- 06 Nov 95 SAIC Corrected subtest results for ACVC 2.0.1 45-- 14 Mar 01 RLB Added checks that the lower bound is 1, similar 46-- to CXA4005. These changes were made to test 47-- Defect Report 8652/0049, as reflected in 48-- Technical Corrigendum 1. 49-- 50--! 51 52with Report; 53with Ada.Strings; 54with Ada.Strings.Wide_Fixed; 55with Ada.Strings.Wide_Maps; 56 57procedure CXA4016 is 58 59 type TC_Name_Holder is access String; 60 Name : TC_Name_Holder; 61 62 function TC_Check (S : Wide_String) return Wide_String is 63 begin 64 if S'First /= 1 then 65 Report.Failed ("Lower bound of result of function " & Name.all & 66 " is" & Integer'Image (S'First)); 67 end if; 68 return S; 69 end TC_Check; 70 71 procedure TC_Set_Name (N : String) is 72 begin 73 Name := new String'(N); 74 end TC_Set_Name; 75 76begin 77 78 Report.Test("CXA4016", "Check that the subprograms defined in " & 79 "package Ada.Strings.Wide_Fixed are available, " & 80 "and that they produce correct results"); 81 82 Test_Block: 83 declare 84 85 package ASW renames Ada.Strings.Wide_Fixed; 86 package Wide_Maps renames Ada.Strings.Wide_Maps; 87 88 Result_String, 89 Delete_String, 90 Insert_String, 91 Trim_String, 92 Overwrite_String : Wide_String(1..10) := 93 (others => Ada.Strings.Wide_Space); 94 Replace_String : Wide_String(10..30) := 95 (others => Ada.Strings.Wide_Space); 96 97 Source_String1 : Wide_String(1..5) := "abcde"; -- odd len wd str 98 Source_String2 : Wide_String(1..6) := "abcdef"; -- even len wd str 99 Source_String3 : Wide_String(1..12) := "abcdefghijkl"; 100 Source_String4 : Wide_String(1..12) := "abcdefghij "; -- last two ch pad 101 Source_String5 : Wide_String(1..12) := " cdefghijkl"; -- first two ch pad 102 Source_String6 : Wide_String(1..12) := "abcdefabcdef"; 103 104 Location : Natural := 0; 105 Slice_Start : Positive; 106 Slice_End, 107 Slice_Count : Natural := 0; 108 109 CD_Set : Wide_Maps.Wide_Character_Set := 110 Wide_Maps.To_Set("cd"); 111 X_Set : Wide_Maps.Wide_Character_Set := 112 Wide_Maps.To_Set('x'); 113 ABCD_Set : Wide_Maps.Wide_Character_Set := 114 Wide_Maps.To_Set("abcd"); 115 A_to_F_Set : Wide_Maps.Wide_Character_Set := 116 Wide_Maps.To_Set("abcdef"); 117 118 CD_to_XY_Map : Wide_Maps.Wide_Character_Mapping := 119 Wide_Maps.To_Mapping(From => "cd", To => "xy"); 120 121 begin 122 123 -- Procedure Replace_Slice 124 -- The functionality of this procedure is similar to procedure Move, 125 -- and is tested here in the same manner, evaluated with various 126 -- combinations of parameters. 127 128 -- Index_Error propagation when Low > Source'Last + 1 129 130 begin 131 ASW.Replace_Slice(Result_String, 132 Result_String'Last + 2, -- should raise exception 133 Result_String'Last, 134 "xxxxxxx"); 135 Report.Failed("Index_Error not raised by Replace_Slice - 1"); 136 exception 137 when Ada.Strings.Index_Error => null; -- OK, expected exception. 138 when others => 139 Report.Failed("Incorrect exception from Replace_Slice - 1"); 140 end; 141 142 -- Index_Error propagation when High < Source'First - 1 143 144 begin 145 ASW.Replace_Slice(Replace_String(20..30), 146 Replace_String'First, 147 Replace_String'First - 2, -- should raise exception 148 "xxxxxxx"); 149 Report.Failed("Index_Error not raised by Replace_Slice - 2"); 150 exception 151 when Ada.Strings.Index_Error => null; -- OK, expected exception. 152 when others => 153 Report.Failed("Incorrect exception from Replace_Slice - 2"); 154 end; 155 156 -- Justify = Left (default case) 157 158 Result_String := "XXXXXXXXXX"; 159 160 ASW.Replace_Slice(Source => Result_String, 161 Low => 1, 162 High => 10, 163 By => Source_String1); -- "abcde" 164 165 if Result_String /= "abcde " then 166 Report.Failed("Incorrect result from Replace_Slice - Justify = Left"); 167 end if; 168 169 -- Justify = Right 170 171 ASW.Replace_Slice(Source => Result_String, 172 Low => 1, 173 High => Result_String'Last, 174 By => Source_String2, -- "abcdef" 175 Drop => Ada.Strings.Error, 176 Justify => Ada.Strings.Right); 177 178 if Result_String /= " abcdef" then 179 Report.Failed("Incorrect result from Replace_Slice - Justify=Right"); 180 end if; 181 182 -- Justify = Center (two cases, odd and even pad lengths) 183 184 ASW.Replace_Slice(Result_String, 185 1, 186 Result_String'Last, 187 Source_String1, -- "abcde" 188 Ada.Strings.Error, 189 Ada.Strings.Center, 190 'x'); -- non-default padding. 191 192 if Result_String /= "xxabcdexxx" then -- Unequal padding added right 193 Report.Failed("Incorrect result, Replace_Slice - Justify=Center - 1"); 194 end if; 195 196 ASW.Replace_Slice(Result_String, 197 1, 198 Result_String'Last, 199 Source_String2, -- "abcdef" 200 Ada.Strings.Error, 201 Ada.Strings.Center); 202 203 if Result_String /= " abcdef " then -- Equal padding added on L/R. 204 Report.Failed("Incorrect result from Replace_Slice with " & 205 "Justify = Center - 2"); 206 end if; 207 208 -- When the source string is longer than the target string, several 209 -- cases can be examined, with the results depending on the value of 210 -- the Drop parameter. 211 212 -- Drop = Left 213 214 ASW.Replace_Slice(Result_String, 215 1, 216 Result_String'Last, 217 Source_String3, -- "abcdefghijkl" 218 Drop => Ada.Strings.Left); 219 220 if Result_String /= "cdefghijkl" then 221 Report.Failed("Incorrect result from Replace_Slice - Drop=Left"); 222 end if; 223 224 -- Drop = Right 225 226 ASW.Replace_Slice(Result_String, 227 1, 228 Result_String'Last, 229 Source_String3, -- "abcdefghijkl" 230 Ada.Strings.Right); 231 232 if Result_String /= "abcdefghij" then 233 Report.Failed("Incorrect result, Replace_Slice with Drop=Right"); 234 end if; 235 236 -- Drop = Error 237 238 -- The effect in this case depends on the value of the justify 239 -- parameter, and on whether any characters in Source other than 240 -- Pad would fail to be copied. 241 242 -- Drop = Error, Justify = Left, right overflow characters are pad. 243 244 ASW.Replace_Slice(Result_String, 245 1, 246 Result_String'Last, 247 Source_String4, -- "abcdefghij " 248 Drop => Ada.Strings.Error, 249 Justify => Ada.Strings.Left); 250 251 if not(Result_String = "abcdefghij") then -- leftmost 10 characters 252 Report.Failed("Incorrect result, Replace_Slice - Drop = Error - 1"); 253 end if; 254 255 -- Drop = Error, Justify = Right, left overflow characters are pad. 256 257 ASW.Replace_Slice(Source => Result_String, 258 Low => 1, 259 High => Result_String'Last, 260 By => Source_String5, -- " cdefghijkl" 261 Drop => Ada.Strings.Error, 262 Justify => Ada.Strings.Right); 263 264 if Result_String /= "cdefghijkl" then -- rightmost 10 characters 265 Report.Failed("Incorrect result, Replace_Slice - Drop = Error - 2"); 266 end if; 267 268 -- In other cases of Drop=Error, Length_Error is propagated, such as: 269 270 begin 271 272 ASW.Replace_Slice(Source => Result_String, 273 Low => 1, 274 High => Result_String'Last, 275 By => Source_String3, -- "abcdefghijkl" 276 Drop => Ada.Strings.Error); 277 278 Report.Failed("Length_Error not raised by Replace_Slice - 1"); 279 280 exception 281 when Ada.Strings.Length_Error => null; -- OK 282 when others => 283 Report.Failed("Incorrect exception from Replace_Slice - 3"); 284 end; 285 286 287 -- Function Replace_Slice 288 289 TC_Set_Name ("Replace_Slice"); 290 291 if TC_Check (ASW.Replace_Slice("abcde", 3, 3, "x")) 292 /= "abxde" or -- High = Low 293 TC_Check (ASW.Replace_Slice("abc", 2, 3, "xyz")) /= "axyz" or 294 TC_Check (ASW.Replace_Slice("abcd", 4, 1, "xy")) 295 /= "abcxyd" or -- High < Low 296 TC_Check (ASW.Replace_Slice("abc", 2, 3, "x")) /= "ax" or 297 TC_Check (ASW.Replace_Slice("a", 1, 1, "z")) /= "z" 298 then 299 Report.Failed("Incorrect result from Function Replace_Slice - 1"); 300 end if; 301 302 if TC_Check (ASW.Replace_Slice("abcde", 5, 5, "z")) 303 /= "abcdz" or -- By length 1 304 TC_Check (ASW.Replace_Slice("abc", 1, 3, "xyz")) 305 /= "xyz" or -- High > Low 306 TC_Check (ASW.Replace_Slice("abc", 3, 2, "xy")) 307 /= "abxyc" or -- insert 308 TC_Check (ASW.Replace_Slice("a", 1, 1, "xyz")) /= "xyz" 309 then 310 Report.Failed("Incorrect result from Function Replace_Slice - 2"); 311 end if; 312 313 314 315 -- Function Insert. 316 317 TC_Set_Name ("Insert"); 318 319 declare 320 New_String : constant Wide_String := 321 TC_Check ( 322 ASW.Insert(Source => Source_String1(2..5), -- "bcde" 323 Before => 2, 324 New_Item => Source_String2)); -- "abcdef" 325 begin 326 if New_String /= "abcdefbcde" then 327 Report.Failed("Incorrect result from Function Insert - 1"); 328 end if; 329 end; 330 331 if TC_Check (ASW.Insert("a", 1, "z")) /= "za" or 332 TC_Check (ASW.Insert("abc", 3, "")) /= "abc" or 333 TC_Check (ASW.Insert("abc", 4, "z")) /= "abcz" 334 then 335 Report.Failed("Incorrect result from Function Insert - 2"); 336 end if; 337 338 begin 339 if TC_Check (ASW.Insert(Source => Source_String1(2..5), -- "bcde" 340 Before => Report.Ident_Int(7), 341 New_Item => Source_String2)) -- "abcdef" 342 /= "babcdefcde" then 343 Report.Failed("Index_Error not raised by Insert - 3A"); 344 else 345 Report.Failed("Index_Error not raised by Insert - 3B"); 346 end if; 347 exception 348 when Ada.Strings.Index_Error => null; -- OK, expected exception. 349 when others => 350 Report.Failed("Incorrect exception from Insert - 3"); 351 end; 352 353 354 -- Procedure Insert 355 356 -- Drop = Right 357 358 ASW.Insert(Source => Insert_String, 359 Before => 6, 360 New_Item => Source_String2, -- "abcdef" 361 Drop => Ada.Strings.Right); 362 363 if Insert_String /= " abcde" then -- last char of New_Item dropped. 364 Report.Failed("Incorrect result from Insert with Drop = Right"); 365 end if; 366 367 -- Drop = Left 368 369 ASW.Insert(Source => Insert_String, -- 10 char string 370 Before => 2, -- 9 chars, 2..10 available 371 New_Item => Source_String3, -- 12 characters long. 372 Drop => Ada.Strings.Left); -- truncate from Left. 373 374 if Insert_String /= "l abcde" then -- 10 chars, leading blank. 375 Report.Failed("Incorrect result from Insert with Drop=Left"); 376 end if; 377 378 -- Drop = Error 379 380 begin 381 ASW.Insert(Source => Result_String, -- 10 chars 382 Before => Result_String'Last, 383 New_Item => "abcdefghijk", 384 Drop => Ada.Strings.Error); 385 Report.Failed("Exception not raised by Procedure Insert"); 386 exception 387 when Ada.Strings.Length_Error => null; -- OK, expected exception 388 when others => 389 Report.Failed("Incorrect exception raised by Procedure Insert"); 390 end; 391 392 393 394 -- Function Overwrite 395 396 TC_Set_Name ("Overwrite"); 397 398 Overwrite_String := TC_Check ( 399 ASW.Overwrite(Result_String, -- 10 chars 400 1, -- starting at pos=1 401 Source_String3(1..10))); 402 403 if Overwrite_String /= Source_String3(1..10) then 404 Report.Failed("Incorrect result from Function Overwrite - 1"); 405 end if; 406 407 408 if TC_Check (ASW.Overwrite("abcdef", 4, "xyz")) /= "abcxyz" or 409 TC_Check (ASW.Overwrite("a", 1, "xyz")) 410 /= "xyz" or -- chars appended 411 TC_Check (ASW.Overwrite("abc", 3, " ")) 412 /= "ab " or -- blanks appended 413 TC_Check (ASW.Overwrite("abcde", 1, "z" )) /= "zbcde" 414 then 415 Report.Failed("Incorrect result from Function Overwrite - 2"); 416 end if; 417 418 419 420 -- Procedure Overwrite, with truncation. 421 422 ASW.Overwrite(Source => Overwrite_String, -- 10 characters. 423 Position => 1, 424 New_Item => Source_String3, -- 12 characters. 425 Drop => Ada.Strings.Left); 426 427 if Overwrite_String /= "cdefghijkl" then 428 Report.Failed("Incorrect result from Overwrite with Drop=Left"); 429 end if; 430 431 -- The default drop value is Right, used here. 432 433 ASW.Overwrite(Source => Overwrite_String, -- 10 characters. 434 Position => 1, 435 New_Item => Source_String3); -- 12 characters. 436 437 if Overwrite_String /= "abcdefghij" then 438 Report.Failed("Incorrect result from Overwrite with Drop=Right"); 439 end if; 440 441 -- Drop = Error 442 443 begin 444 ASW.Overwrite(Source => Overwrite_String, -- 10 characters. 445 Position => 1, 446 New_Item => Source_String3, -- 12 characters. 447 Drop => Ada.Strings.Error); 448 Report.Failed("Exception not raised by Procedure Overwrite"); 449 exception 450 when Ada.Strings.Length_Error => null; -- OK, expected exception. 451 when others => 452 Report.Failed 453 ("Incorrect exception raised by Procedure Overwrite"); 454 end; 455 456 Overwrite_String := "ababababab"; 457 ASW.Overwrite(Overwrite_String, Overwrite_String'Last, "z"); 458 ASW.Overwrite(Overwrite_String, Overwrite_String'First,"z"); 459 ASW.Overwrite(Overwrite_String, 5, "zz"); 460 461 if Overwrite_String /= "zbabzzabaz" then 462 Report.Failed("Incorrect result from Procedure Overwrite"); 463 end if; 464 465 466 467 -- Function Delete 468 469 TC_Set_Name ("Delete"); 470 471 declare 472 New_String1 : constant Wide_String := -- Returns a 4 char wide str. 473 TC_Check (ASW.Delete(Source => Source_String3, 474 From => 3, 475 Through => 10)); 476 New_String2 : constant Wide_String := -- This returns Source. 477 TC_Check (ASW.Delete(Source_String3, 10, 3)); 478 begin 479 if New_String1 /= "abkl" or 480 New_String2 /= Source_String3 481 then 482 Report.Failed("Incorrect result from Function Delete - 1"); 483 end if; 484 end; 485 486 if TC_Check (ASW.Delete("a", 1, 1)) 487 /= "" or -- Source length = 1 488 TC_Check (ASW.Delete("abc", 1, 2)) 489 /= "c" or -- From = Source'First 490 TC_Check (ASW.Delete("abc", 3, 3)) 491 /= "ab" or -- From = Source'Last 492 TC_Check (ASW.Delete("abc", 3, 1)) 493 /= "abc" -- From > Through 494 then 495 Report.Failed("Incorrect result from Function Delete - 2"); 496 end if; 497 498 499 500 -- Procedure Delete 501 502 -- Justify = Left 503 504 Delete_String := Source_String3(1..10); -- Initialize to "abcdefghij" 505 506 ASW.Delete(Source => Delete_String, 507 From => 6, 508 Through => Delete_String'Last, 509 Justify => Ada.Strings.Left, 510 Pad => 'x'); -- pad with char 'x' 511 512 if Delete_String /= "abcdexxxxx" then 513 Report.Failed("Incorrect result from Delete - Justify = Left"); 514 end if; 515 516 -- Justify = Right 517 518 ASW.Delete(Source => Delete_String, -- Remove x"s from end and 519 From => 6, -- shift right. 520 Through => Delete_String'Last, 521 Justify => Ada.Strings.Right, 522 Pad => 'x'); -- pad with char 'x' on left. 523 524 if Delete_String /= "xxxxxabcde" then 525 Report.Failed("Incorrect result from Delete - Justify = Right"); 526 end if; 527 528 -- Justify = Center 529 530 ASW.Delete(Source => Delete_String, 531 From => 1, 532 Through => 5, 533 Justify => Ada.Strings.Center, 534 Pad => 'z'); 535 536 if Delete_String /= "zzabcdezzz" then -- extra pad char on right side. 537 Report.Failed("Incorrect result from Delete - Justify = Center"); 538 end if; 539 540 541 542 -- Function Trim 543 -- Use non-identity character sets to perform the trim operation. 544 545 TC_Set_Name ("Trim"); 546 547 Trim_String := "cdabcdefcd"; 548 549 -- Remove the "cd" from each end of the string. This will not effect 550 -- the "cd" slice at 5..6. 551 552 declare 553 New_String : constant Wide_String := 554 TC_Check (ASW.Trim(Source => Trim_String, 555 Left => CD_Set, Right => CD_Set)); 556 begin 557 if New_String /= Source_String2 then -- string "abcdef" 558 Report.Failed 559 ("Incorrect result from Trim with wide character sets"); 560 end if; 561 end; 562 563 if TC_Check (ASW.Trim("abcdef", Wide_Maps.Null_Set, Wide_Maps.Null_Set)) 564 /= "abcdef" then 565 Report.Failed("Incorrect result from Trim with Null sets"); 566 end if; 567 568 if TC_Check (ASW.Trim("cdxx", CD_Set, X_Set)) /= "" then 569 Report.Failed("Incorrect result from Trim, wide string removal"); 570 end if; 571 572 573 -- Procedure Trim 574 575 -- Justify = Right 576 577 ASW.Trim(Source => Trim_String, 578 Left => CD_Set, 579 Right => CD_Set, 580 Justify => Ada.Strings.Right, 581 Pad => 'x'); 582 583 if Trim_String /= "xxxxabcdef" then 584 Report.Failed("Incorrect result from Trim with Justify = Right"); 585 end if; 586 587 -- Justify = Left 588 589 ASW.Trim(Source => Trim_String, 590 Left => X_Set, 591 Right => Wide_Maps.Null_Set, 592 Justify => Ada.Strings.Left, 593 Pad => ' '); 594 595 if Trim_String /= "abcdef " then -- Padded with 4 blanks on right. 596 Report.Failed("Incorrect result from Trim with Justify = Left"); 597 end if; 598 599 -- Justify = Center 600 601 ASW.Trim(Source => Trim_String, 602 Left => ABCD_Set, 603 Right => CD_Set, 604 Justify => Ada.Strings.Center, 605 Pad => 'x'); 606 607 if Trim_String /= "xxef xx" then -- Padded with 4 pad chars on L/R 608 Report.Failed("Incorrect result from Trim with Justify = Center"); 609 end if; 610 611 612 613 -- Function Head, testing use of padding. 614 615 TC_Set_Name ("Head"); 616 617 -- Use the wide characters of Source_String1 ("abcde") and pad the 618 -- last five wide characters of Result_String with 'x' wide characters. 619 620 Result_String := TC_CHeck (ASW.Head(Source_String1, 10, 'x')); 621 622 if Result_String /= "abcdexxxxx" then 623 Report.Failed("Incorrect result from Function Head with padding"); 624 end if; 625 626 if TC_Check (ASW.Head(" ab ", 2)) /= " " or 627 TC_Check (ASW.Head("a", 6, 'A')) /= "aAAAAA" or 628 TC_Check (ASW.Head(ASW.Head("abc ", 7, 'x'), 10, 'X')) 629 /= "abc xxXXX" 630 then 631 Report.Failed("Incorrect result from Function Head"); 632 end if; 633 634 635 636 -- Function Tail, testing use of padding. 637 638 TC_Set_Name ("Tail"); 639 640 -- Use the wide characters of Source_String1 ("abcde") and pad the 641 -- first five wide characters of Result_String with 'x' wide characters. 642 643 Result_String := TC_Check (ASW.Tail(Source_String1, 10, 'x')); 644 645 if Result_String /= "xxxxxabcde" then 646 Report.Failed("Incorrect result from Function Tail with padding"); 647 end if; 648 649 if TC_Check (ASW.Tail("abcde ", 5)) 650 /= "cde " or -- blanks, back 651 TC_Check (ASW.Tail(" abc ", 8, ' ')) 652 /= " abc " or -- blanks, front/back 653 TC_Check (ASW.Tail("", 5, 'Z')) 654 /= "ZZZZZ" or -- pad characters only 655 TC_Check (ASW.Tail("abc", 0)) 656 /= "" or -- null result 657 TC_Check (ASW.Tail(ASW.Tail(" abc ", 6, 'x'), 658 10, 659 'X')) /= "XXXXx abc " 660 then 661 Report.Failed("Incorrect result from Function Tail"); 662 end if; 663 664 665 666 -- Function "*" - with (Natural, Wide_String) parameters 667 668 TC_Set_Name ("""*"""); 669 670 if TC_Check (ASW."*"(3, Source_String1)) /= "abcdeabcdeabcde" or 671 TC_Check (ASW."*"(2, Source_String2)) /= Source_String6 or 672 TC_Check (ASW."*"(4, Source_String1(1..2))) /= "abababab" or 673 TC_Check (ASW."*"(0, Source_String1)) /= "" 674 then 675 Report.Failed 676 ("Incorrect result from Function ""*"" with wide strings"); 677 end if; 678 679 exception 680 when others => Report.Failed("Exception raised in Test_Block"); 681 end Test_Block; 682 683 Report.Result; 684 685end CXA4016; 686