home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume5 / trouble < prev    next >
Internet Message Format  |  1989-02-03  |  30KB

  1. Path: xanth!nic.MR.NET!hal!ncoast!allbery
  2. From: rjs@a.cs.okstate.edu (Roland Stolfa)
  3. Newsgroups: comp.sources.misc
  4. Subject: v05i071: Trouble Reporting System
  5. Message-ID: <4227@okstate.UUCP>
  6. Date: 7 Dec 88 00:22:58 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: rjs@a.cs.okstate.edu (Roland Stolfa)
  9. Organization: Oklahoma State Univ., Stillwater
  10. Lines: 1334
  11. Approved: allbery@ncoast.UUCP
  12.  
  13. Posting-number: Volume 5, Issue 71
  14. Submitted-by: "Roland Stolfa" <rjs@a.cs.okstate.edu>
  15. Archive-name: trouble
  16.  
  17. echo x - README
  18. sed '1,$s/^X//' <<\!FUNKY!STUFF! > README
  19. XINTRODUCTION:
  20. X
  21. X    This is the Trouble Report System (TRS) by
  22. X
  23. X    Roland J. Stolfa
  24. X    Department of Computing and Information Sciences
  25. X    Oklahoma State University
  26. X
  27. X    Internet:       rjs@a.cs.okstate.edu
  28. X
  29. X
  30. XDISCLAIMER:
  31. X
  32. X    All code is public domain.  No guarentee, expressed nor implied,
  33. X    covers this code.  I will NOT be responsible for it's use or
  34. X    misuse in your application.  I just hope (Underline that in red)
  35. X    that it may prove useful to you.  If something doesn't compile,
  36. X    I hope that the comments that surround the troble line will be
  37. X    sufficient to fix the problem.
  38. X
  39. X
  40. XDESCRIPTION:
  41. X
  42. X    This is a set of Bourne shell scrips and C programs intended
  43. X    to maintain a database of trouble reports.  The actions supported
  44. X    in this package are open a trouble report (trouble), post a followup
  45. X    on a trouble report (followup), remove a 'thread' of trouble reports
  46. X    (rmthread), report all open trouble report ticket numbers (opentr),
  47. X    and summarize a class of trouble reports (report).
  48. X
  49. X
  50. XINSTALLATION PROCEDURES:
  51. X
  52. X1.    Make a directory and put this shar in it.  Then say "sh <fn>".
  53. X
  54. X2.    Edit the file "Localize" to point the "ROOT", "BIN" and
  55. X    shell script escape sequences at the localally correct
  56. X    values.  Then type "sh Localize" to install these values
  57. X    on all files in this directory.  Then edit the Makefile
  58. X    and change the -DSYS5 to either -DSYS5 or -DULTRIX.
  59. X
  60. X3.    Say "make install".  This makes the various directories &
  61. X    sets the permissions to allow the next procedure to function.
  62. X
  63. X4.    Say "make all".
  64. X
  65. X5.    Done.
  66. X
  67. X
  68. XDIRECTORY STRUCTURE:
  69. X
  70. X                    Trs
  71. X                     |
  72. X        +-------+------------+----------+---------------+-------+
  73. X            |    |         |        |        |    |
  74. X          Entry <Soundex1>      ...     <SoundexN>           tmp     bin
  75. X        |       |                |        |
  76. X        +---+-----+    +-------+-+       +----+----+     +-----+
  77. X        |   ...   |       |   ...   |       |   ...   |     | ... |
  78. X    <Timestamp1> ... <Timestamp1> ..<Timestamp1> ...  trs.seq <temps>
  79. X
  80. XEach TRS record is first built in a temporary.  It is then linked into the
  81. X.../Trs/Entry/<Timestamp>" file.  Then it is linked into a subdirectory
  82. Xfor each SOUNDEX encoded keyword given during data entry.
  83. X
  84. X
  85. XNOTES:
  86. X
  87. X1.    If you need to move this datastructure, please use a program
  88. X    that preserves the link relationships.
  89. X
  90. X2.    If the average TRS record size is small and the default
  91. X    block size on the storage device is large, you loose...
  92. X
  93. X3.    This system typically uses a large number of links.  This
  94. X    implies that a large number of inodes will be used.  This
  95. X    can be a problem on smaller systems...
  96. X
  97. X4.    Each user can override the default "ROOT" setting by having
  98. X    an environment variable "TRSROOT" set to some directory
  99. X    that has the same structure as the one above.
  100. X
  101. X
  102. XFILES:
  103. X
  104. X    Localize
  105. X
  106. X        This shell script patches all the files in this system to
  107. X        work with the locally chosen directories.
  108. X
  109. X    Makefile
  110. X
  111. X        Used to create all the executables for each program.
  112. X
  113. X    README
  114. X
  115. X        This file.
  116. X
  117. X    followup.sh
  118. X
  119. X        This program is used to enter a follow up report onto
  120. X        the end of a TRS thread.  It walks the thread, from anywhere
  121. X        on the thread, to then end and then doubly links the end
  122. X        of the current thread to the new report.
  123. X
  124. X    mkpath.c
  125. X
  126. X        A utility program to generate directories along a given
  127. X        path without complaining.
  128. X
  129. X    opentr.sh
  130. X
  131. X        This shell script lists the initial trouble report ticket
  132. X        number for all active trouble reports.
  133. X
  134. X    parse.awk
  135. X
  136. X        This "awk(1)" program is used to parse the command line
  137. X        arguments to "report.sh".
  138. X
  139. X    print.c
  140. X
  141. X        This simple program is used to print all the command line
  142. X        arguments on a line by itself without a carriage return
  143. X        on the end.
  144. X
  145. X    report.sh
  146. X
  147. X        This shell script attempts to extract data from the TRS
  148. X        database given any combination of keys.
  149. X
  150. X    reporter.awk
  151. X
  152. X        This "awk(1)" program is used in one stage of the "report.sh"
  153. X        program.
  154. X
  155. X    rmthread.sh
  156. X
  157. X        This shell script removes an entire linked list of trouble
  158. X        reports, given a report anywhere in the list.
  159. X
  160. X    soundex.c
  161. X
  162. X        This C program implements a "SOUNDEX" algorithm and is used
  163. X        in the TRS to encode keywords within the database to ease
  164. X        searching.
  165. X
  166. X    trouble.sh
  167. X
  168. X        This shell script does the actual data entry for the TRS system.
  169. X        It attempts to prompt for all the relavant data, generates
  170. X        some stuff by default, and then builds all the linked files
  171. X        that constitue the database.
  172. !FUNKY!STUFF!
  173. echo x - Localize
  174. sed '1,$s/^X//' <<\!FUNKY!STUFF! > Localize
  175. X#
  176. X# Localizing script for the (T)rouble (R)eport (S)ystem
  177. X#
  178. X
  179. Xfor i in Makefile *.sh
  180. Xdo
  181. X
  182. X    #
  183. X    # Attach the "ROOT" to some clean point like /usr/local/lib/trs
  184. X    # as this will need to be a publically writable directory that
  185. X    # will hold all trouble reports.
  186. X    #
  187. X    # Attach the "BIN" to some global point like /usr/lbin for all
  188. X    # the executables
  189. X    #
  190. Xed - $i <<'EOF'
  191. Xg;^ROOT;s;=.*$;=/u/rjs/lib/Trs;
  192. Xg;^BIN;s;=.*$;=/u/rjs/bin;
  193. Xw
  194. Xq
  195. XEOF
  196. X
  197. Xdone
  198. X
  199. Xfor i in *.sh
  200. Xdo
  201. X
  202. X    #
  203. X    # The ":" in the ed script below is the first line of all shell
  204. X    # scripts for SYS5.  For ULTRIX, it should be "#!/bin/sh".
  205. X    #
  206. Xed - $i <<'EOF'
  207. X1 s;^.*$;:;
  208. Xw
  209. Xq
  210. XEOF
  211. X
  212. Xdone
  213. !FUNKY!STUFF!
  214. echo x - Makefile
  215. sed '1,$s/^X//' <<\!FUNKY!STUFF! > Makefile
  216. X#
  217. X# Package    : TRS
  218. X# Module    : (Makefile)
  219. X# Programmer    : R. Stolfa
  220. X#
  221. X# Purpose :    To maintain a Trouble Report System for an
  222. X#        university environment
  223. X#
  224. X# Modification History:
  225. X#   04/11/88    Created
  226. X#   10/25/88    Updated for distribution outside of OSU
  227. X#
  228. XROOT=/u/rjs/lib/Trs
  229. XLIB=$(ROOT)/lib
  230. XBIN=/u/rjs/bin
  231. XCFLAGS=    -O -DSYS5
  232. X
  233. XDuMb:
  234. X    @echo Make what?
  235. X
  236. Xfollowup:    $(BIN)/followup
  237. X$(BIN)/followup:    followup.sh
  238. X    cp followup.sh $(BIN)/followup
  239. X    chmod 755 $(BIN)/followup
  240. X
  241. Xmkpath:    $(LIB)/mkpath
  242. X$(LIB)/mkpath:    mkpath.c
  243. X    cc $(CFLAGS) mkpath.c -o $(LIB)/mkpath
  244. X    chmod 755 $(LIB)/mkpath
  245. X
  246. Xopentr:    $(BIN)/opentr
  247. X$(BIN)/opentr:    opentr.sh
  248. X    cp opentr.sh $(BIN)/opentr
  249. X    chmod 755 $(BIN)/opentr
  250. X
  251. XParse.awk:    $(LIB)/parse.awk
  252. X$(LIB)/parse.awk:    parse.awk
  253. X    cp parse.awk $(LIB)/parse.awk
  254. X    chmod 644 $(LIB)/parse.awk
  255. X
  256. Xprint:    $(LIB)/print
  257. X$(LIB)/print:    print.c
  258. X    cc print.c -o $(LIB)/print
  259. X    chmod 755 $(LIB)/print
  260. X
  261. Xreport:    Parse.awk Reporter.awk $(BIN)/report
  262. X$(BIN)/report:    report.sh
  263. X    cp report.sh $(BIN)/report
  264. X    chmod 755 $(BIN)/report
  265. X
  266. XReporter.awk:    $(LIB)/reporter.awk
  267. X$(LIB)/reporter.awk:    reporter.awk
  268. X    cp reporter.awk $(LIB)/reporter.awk
  269. X    chmod 644 $(LIB)/reporter.awk
  270. X
  271. Xrmthread:    $(BIN)/rmthread
  272. X$(BIN)/rmthread:    rmthread.sh
  273. X    cp rmthread.sh $(BIN)/rmthread
  274. X    chmod 755 $(BIN)/rmthread
  275. X
  276. Xsoundex:    $(LIB)/soundex
  277. X$(LIB)/soundex:    soundex.c
  278. X    cc soundex.c -o $(LIB)/soundex
  279. X    chmod 755 $(LIB)/soundex
  280. X
  281. Xtrouble:    $(BIN)/trouble
  282. X$(BIN)/trouble:    trouble.sh
  283. X    cp trouble.sh $(BIN)/trouble
  284. X    chmod 755 $(BIN)/trouble
  285. X
  286. X#
  287. X# Housekeeping
  288. X#
  289. X
  290. Xall:    followup opentr mkpath print report rmthread soundex trouble
  291. X    @echo "Don't forget 'make install' to setup sequence file"
  292. X
  293. Xbackout:    clean
  294. X    rm -rf $(ROOT)
  295. X    rm -if $(BIN)/followup $(BIN)/opentr $(BIN)/report $(BIN)/rmthread \
  296. X        $(BIN)/trouble
  297. X
  298. Xclean:
  299. X    rm -f *.o a.out core
  300. X
  301. Xinstall:
  302. X    -mkdir $(ROOT) $(ROOT)/Entry $(ROOT)/tmp $(ROOT)/lib
  303. X    chmod 777 $(ROOT) $(ROOT)/Entry $(ROOT)/tmp
  304. X    chmod 755 $(ROOT)/lib
  305. X    echo "0" > $(ROOT)/sequence
  306. X
  307. Xshar:
  308. X    shar README Localize Makefile [a-z]* > Trs.shar
  309. X
  310. X#
  311. X# Dependancies
  312. X#
  313. Xmkpath.o print.o soundex.o :    /usr/include/stdio.h
  314. !FUNKY!STUFF!
  315. echo x - followup.1
  316. sed '1,$s/^X//' <<\!FUNKY!STUFF! > followup.1
  317. X.TH FOLLOWUP L
  318. X.SH NAME
  319. Xfollowup - post a followup trouble report
  320. X.SH SYNOPSIS
  321. X.B followup [ ticket number ]
  322. X.br
  323. X.SH DESCRIPTION
  324. X.I followup
  325. Xis intended to be the method of posting a new report in a "thread" of
  326. Xreports assoicated with a reported problem in hardware/software.
  327. X.PP
  328. XIf 
  329. X.I followup
  330. Xis invoked without a ticket number, it prompts for one.  Then an entire
  331. Xnew trouble report is attached to a thread of reports assoicated together.
  332. XThis list of reports is doubly linked in the trouble report file and then
  333. Xlinked (using "ln(1)") to all soundex encoded subdirectories relating
  334. Xto the keywords specified.
  335. X.PP
  336. XAll of the files and directories contained in the system are all plain
  337. Xtext files, with an easy format that can be used to your advantage.
  338. X.sp 1
  339. X.SH "INTERNALS"
  340. X.I followup
  341. Xuses a tree structured file data-base to store all trouble reports.  Each
  342. Xreport occupies one file in the "../Trs/Entry" directory with the name
  343. Xbeing equal to that of the date (in YYMMDD format) and a sequence number
  344. Xappended (i.e. 881025.1).  This file is then linked (using "ln(1)") to
  345. Xa subdirectory for each keyword specified in the
  346. X.I followup
  347. Xkeyword prompt.  Each keyword is encoded via the
  348. X.I soundex
  349. Xalgorythm to be the "link" directory.  This allows fast searches of
  350. Xrecurring problems (see "report(L)").
  351. X.SH "FILES"
  352. X"/usr/local/lib/trs/...."    - Root directory for help
  353. X.br
  354. X"/usr/local/lib/trs/entry/..."    - Directory where ALL trouble reports reside
  355. X.br
  356. X"/usr/local/lib/trs/sequence"    - Sequence file
  357. X.PP
  358. X.SH DIAGNOSTICS
  359. XThere are no real diagnostics.
  360. X.SH AUTHOR
  361. XRoland J. Stolfa
  362. X.br
  363. XDepartment of Computing and Information Sciences
  364. X.br
  365. XOklahoma State University
  366. X.br
  367. Xrjs@a.cs.okstate.edu
  368. !FUNKY!STUFF!
  369. echo x - followup.sh
  370. sed '1,$s/^X//' <<\!FUNKY!STUFF! > followup.sh
  371. X:
  372. X#
  373. X# Package    : TRS
  374. X# Module    : followup.sh
  375. X# Programmer    : R. Stolfa
  376. X#
  377. X# Purpose :    To 'needle & thread' TRS records together.
  378. X#
  379. X# Modification History:
  380. X#   04/12/88    Created
  381. X#   10/25/88    Added user configurable "ROOT" to allow more than
  382. X#        one TRS to exist on a particular system.
  383. X#
  384. X
  385. X#
  386. X# Some variables
  387. X#
  388. Xumask 000
  389. Xif [ "$TRSROOT" != "" ]
  390. Xthen
  391. X    ROOT=$TRSROOT
  392. Xelse
  393. XROOT=/u/rjs/lib/Trs
  394. Xfi
  395. XBIN=/u/rjs/bin
  396. XENTRY=$ROOT/Entry
  397. XLIB=$ROOT/lib
  398. Xtrap "rm -f $ROOT/tmp/* ; exit 1" 1 2 15
  399. X
  400. X#
  401. X# Ok.  Get the 'trouble ticket' number.
  402. X#
  403. Xnum="$*"
  404. Xif test ! -s $ENTRY/$num
  405. Xthen
  406. X    echo "Invalid trouble ticket number.  Try again."
  407. X    num=""
  408. Xfi
  409. Xwhile [ "$num" = "" ]
  410. Xdo
  411. X    $LIB/print "Enter trouble ticket number? "
  412. X    read num
  413. X
  414. X    if test ! -s $ENTRY/$num
  415. X    then
  416. X        echo "Invalid trouble ticket number.  Try again."
  417. X        num=""
  418. X    fi
  419. Xdone
  420. X
  421. X#
  422. X# Follow it's threads until you reach the last one.
  423. X#
  424. Xthread="+"
  425. Xwhile [ "$thread" != "" ]
  426. Xdo
  427. X    thread="`grep '^thread=' $ENTRY/$num | awk -F= '{print $2}'`"
  428. X    if [ "$thread" != "" ]
  429. X    then
  430. X        num="$thread"
  431. X    fi
  432. Xdone
  433. X
  434. X#
  435. X# Display last entry.
  436. X#
  437. Xecho "Last entry as follows:"
  438. Xecho ""
  439. Xecho "ticket=$num"
  440. Xecho "reporter=`ls -l $ENTRY/$num | awk '{print $3}'`"
  441. Xmore $ENTRY/$num
  442. Xecho ""
  443. Xyesno=""
  444. Xwhile [ "$yesno" = "" ]
  445. Xdo
  446. X    $LIB/print "Is this the correct one? (Y/N) "
  447. X    read yesno
  448. Xdone
  449. X
  450. X#
  451. X# If incorrect, try again.
  452. X#
  453. Xif [ "$yesno" = "N" -o "$yesno" = "n" ]
  454. Xthen
  455. X    exec $BIN/followup
  456. Xfi
  457. X
  458. X#
  459. X# Ok.  Generate a new trouble report and then fix the threading.
  460. X# Do this by 'including' the trouble ticket generator.
  461. X#
  462. Xnumber=$num
  463. X. $BIN/trouble
  464. Xecho "thread=$NTN" >> $ENTRY/$number
  465. Xecho "needle=$num" >> $ENTRY/$NTN
  466. !FUNKY!STUFF!
  467. echo x - mkpath.c
  468. sed '1,$s/^X//' <<\!FUNKY!STUFF! > mkpath.c
  469. X/*
  470. X * Package    : TRS
  471. X * Module    : mkpath.c
  472. X * Programmer    : R. Stolfa
  473. X *
  474. X * Purpose :    To create all  the subdirectories that are needed
  475. X *        for a file specified on the command line.
  476. X *
  477. X * Usage:
  478. X *        % mkpath foo/bar/cat/dog
  479. X *            Will make the directories foo, foo/bar, and foo/bar/cat
  480. X *            if they don't already exist.
  481. X *
  482. X * Modification History:
  483. X *   02/15/88    Created
  484. X */
  485. X
  486. X#include    <stdio.h>
  487. X
  488. Xmain (argc, argv)
  489. Xint    argc;
  490. Xchar    *argv[];
  491. X{
  492. X    int    i;
  493. X
  494. X    for (i = 1; i < argc; i ++)
  495. X        mkpath (argv[i]);
  496. X}
  497. X
  498. Xmkpath (name)
  499. Xchar    name[];
  500. X{
  501. X
  502. X    char    buff[512];
  503. X    int    i,
  504. X        dumb;
  505. X#ifdef SYS5
  506. X    char    cmd[512];
  507. X#endif
  508. X
  509. X    for (i = 0; i < strlen(name); i ++) {
  510. X        buff[i] = '\0';
  511. X        if (name[i] == '/') {
  512. X#ifdef ULTRIX
  513. X            dumb = mkdir (buff, 0755);
  514. X#endif
  515. X
  516. X#ifdef SYS5
  517. X            sprintf (cmd, "mkdir %s > /dev/null 2>&1", buff);
  518. X            system (cmd);
  519. X#endif
  520. X        }
  521. X        buff[i] = name[i];
  522. X    }
  523. X}
  524. !FUNKY!STUFF!
  525. echo x - opentr.1
  526. sed '1,$s/^X//' <<\!FUNKY!STUFF! > opentr.1
  527. X.TH OPENTR L
  528. X.SH NAME
  529. Xopentr - report all open trouble reports
  530. X.SH SYNOPSIS
  531. X.B opentr
  532. X.br
  533. X.SH DESCRIPTION
  534. X.I opentr
  535. Xis intended to be used to find all open trouble reports to give
  536. Xthe trouble manager something to do in their spare time :-).
  537. X.SH AUTHOR
  538. XRoland J. Stolfa
  539. X.br
  540. XDepartment of Computing and Information Sciences
  541. X.br
  542. XOklahoma State University
  543. X.br
  544. Xrjs@a.cs.okstate.edu
  545. !FUNKY!STUFF!
  546. echo x - opentr.sh
  547. sed '1,$s/^X//' <<\!FUNKY!STUFF! > opentr.sh
  548. X:
  549. X#
  550. X# Package    : TRS
  551. X# Module    : opentr.sh
  552. X# Programmer    : R. Stolfa
  553. X#
  554. X# Purpose :    To list all open trouble report ticket numbers
  555. X#        in the TRS database.
  556. X#
  557. X# Modification History:
  558. X#   04/15/88    Created
  559. X#   10/25/88    Added a user configurable "ROOT" to allow more than
  560. X#        one TRS on a system.
  561. X#
  562. X
  563. X#
  564. X# Some variables
  565. X#
  566. Xumask 000
  567. Xif [ "$TRSROOT" != "" ]
  568. Xthen
  569. X    ROOT=$TRSROOT
  570. Xelse
  571. XROOT=/u/rjs/lib/Trs
  572. Xfi
  573. XENTRY=$ROOT/Entry
  574. XLIB=$ROOT/lib
  575. Xif [ `ls $ENTRY | wc -l` -gt 0 ]
  576. Xthen
  577. X    for i in $ENTRY/*
  578. X    do
  579. X        if [ `grep "^needle=" $i | wc -l` -eq 0 ]
  580. X        then
  581. X            echo `basename $i`
  582. X        fi
  583. X    done
  584. Xfi
  585. !FUNKY!STUFF!
  586. echo x - parse.awk
  587. sed '1,$s/^X//' <<\!FUNKY!STUFF! > parse.awk
  588. X#
  589. X# Package    : TRS
  590. X# Module    : parse.awk
  591. X# Programmer    : R. Stolfa
  592. X#
  593. X# Purpose :    To parse the command line arguments to "report.sh".
  594. X#
  595. X# Modification History:
  596. X#   04/12/88    Created
  597. X#
  598. X
  599. XBEGIN    {
  600. X    FS = "=";
  601. X}
  602. X
  603. X{
  604. X    if (NF == 2) {
  605. X        char = substr ($1, 0, 1);
  606. X        if ((char == "t") || (char == "T"))
  607. X            printf "T\n";
  608. X        else if ((char == "k") || (char == "K"))
  609. X            printf "K\n";
  610. X        else if ((char == "d") || (char == "D"))
  611. X            printf "D\n";
  612. X        else if ((char == "r") || (char == "R"))
  613. X            printf "R\n";
  614. X        else if ((char == "e") || (char == "E"))
  615. X            printf "E\n";
  616. X    }
  617. X}
  618. !FUNKY!STUFF!
  619. echo x - print.c
  620. sed '1,$s/^X//' <<\!FUNKY!STUFF! > print.c
  621. X/*
  622. X * Package    : TRS
  623. X * Module    : print.c
  624. X * Programmer    : R. Stolfa
  625. X *
  626. X * Purpose :    To provide a portable way of printing a string
  627. X *        of text on stdout without having a newline at the
  628. X *        end.
  629. X *
  630. X * Modification History:
  631. X *   04/01/88    Created
  632. X */
  633. X
  634. X#include    <stdio.h>
  635. X
  636. Xmain (argc, argv)
  637. Xint    argc;
  638. Xchar    *argv[];
  639. X{
  640. X    int    i;
  641. X
  642. X    if (argc > 1) {
  643. X        for (i = 1; i < argc - 1 ; i ++)
  644. X            printf ("%s ", argv[i]);
  645. X
  646. X        printf ("%s", argv[argc-1]);
  647. X    }
  648. X}
  649. !FUNKY!STUFF!
  650. echo x - report.1
  651. sed '1,$s/^X//' <<\!FUNKY!STUFF! > report.1
  652. X.TH REPORT L
  653. X.SH NAME
  654. Xreport - extract all requested trouble reports by selection criteria
  655. X.SH SYNOPSIS
  656. X.B report [ t=<thread> ] [ k=<keyword> ] [ d=<date> ] [ r=<reporter> ] [ e=<equipment> ]
  657. X.br
  658. X.SH DESCRIPTION
  659. X.I report
  660. Xis intended to extract the utmost information from the (T)rouble (R)eport
  661. X(S)ystem.  With this shell script, you can extract an entire thread
  662. Xusing the
  663. X.B [ t=<thread id> ]
  664. Xoption, or you may select all reports with a particular keyword
  665. Xusing the
  666. X.B [ k=<keyword> ]
  667. Xoption.  In addition, you may select all reports on a particular day
  668. Xusing the
  669. X.B [ d=<date> ]
  670. Xoption.  If that isn't enough, you can select a particular reporter (read that
  671. Xas UN*X user login id) by using the
  672. X.B [ r=<reporter> ]
  673. Xoption.  Lastly, you can use the
  674. X.B [ e=<equipment id string> ]
  675. Xoption to extract all info about a particular peice of equipment and or a class
  676. Xof equipment, depending on what you use for the
  677. X.B <equipment id string>.
  678. X.PP
  679. XIn addition, you can use the different options of 
  680. X.I report
  681. Xadditvely.  Several examples follow.
  682. X.PP
  683. Xreport t=881025.1 e="terminal"
  684. X.br
  685. Xextracts all trouble report entries in the thread assoicated with the head
  686. Xof the thread pointed to by 881025.1 that deal with the "terminal" class
  687. Xof devices.
  688. X.PP
  689. Xreport d=881025 r=joe e="terminal"
  690. X.br
  691. Xextracts all trouble reports on 10/25/88 by user "joe" involving a
  692. X"terminal".
  693. X.PP
  694. Xreport k=broken e="terminal"
  695. X.br
  696. Xextracts all trouble reports about "broken" "terminal"s.
  697. X.PP
  698. XIn short, you get the idea.
  699. X.sp 1
  700. X.SH "INTERNALS"
  701. X.I report
  702. Xuses a single pass over the arguments above
  703. X.B IN THE LISTED ORDER
  704. Xto refine the eventual list of trouble report tickets to be printed
  705. Xas the "report".  Note that any missordering of the arguments will be
  706. Xhandled by re-ordering them as listed above BEFORE selection occurs.
  707. X.sp 1
  708. X.SH DIAGNOSTICS
  709. XThere are no real diagnostics.  You are expected to be able to fathom
  710. Xthe deep-dark recesses of shell programming & have a good working knowledge
  711. Xof links in order to do ANY debugging of this system.
  712. X.sp 1
  713. X.SH AUTHOR
  714. XRoland J. Stolfa
  715. X.br
  716. XDepartment of Computing and Information Sciences
  717. X.br
  718. XOklahoma State University
  719. X.br
  720. Xrjs@a.cs.okstate.edu
  721. !FUNKY!STUFF!
  722. echo x - report.sh
  723. sed '1,$s/^X//' <<\!FUNKY!STUFF! > report.sh
  724. X:
  725. X#
  726. X# Package    : TRS
  727. X# Module    : report.sh
  728. X# Programmer    : R. Stolfa
  729. X#
  730. X# Purpose :    To scan the TRS database and extract "reasonable"
  731. X#        information.  This information will be presented
  732. X#        on the screen in a format suitable for printing
  733. X#
  734. X# Command line syntax:
  735. X#        report <flags>
  736. X#        where <flags> are some set of the following
  737. X#
  738. X#        t=<thread id>
  739. X#        k=<keyword to search on>
  740. X#        d=<date in YYMMDD format>
  741. X#        r=<reporter (userid)>
  742. X#        e=<equipment id string (inventory number?)>
  743. X#
  744. X# Modification History:
  745. X#   04/12/88    Created
  746. X#   10/25/88    Added a user configurable "ROOT" to allow more than
  747. X#        one TRS on a system
  748. X#
  749. X
  750. X#
  751. X# Some variables
  752. X#
  753. Xumask 000
  754. Xif [ "$TRSROOT" != "" ]
  755. Xthen
  756. X    ROOT=$TRSROOT
  757. Xelse
  758. XROOT=/u/rjs/lib/Trs
  759. Xfi
  760. XENTRY=$ROOT/Entry
  761. XLIB=$ROOT/lib
  762. XTEMP=$ROOT/tmp/trs.$$
  763. XTEMP2=$ROOT/tmp/trs2.$$
  764. XTEMP3=$ROOT/tmp/trs3.$$
  765. Xtrap "rm -f $ROOT/tmp/* ; exit 1" 1 2 15
  766. X
  767. Xthread=""
  768. Xkey="Entry"
  769. Xdate="*"
  770. Xreporter=""
  771. Xequip=""
  772. X
  773. X#
  774. X# Parse the command line with "parse.awk"
  775. X#
  776. Xfor i in $*
  777. Xdo
  778. X    case `echo $i | awk -f $LIB/parse.awk` in
  779. X    T)
  780. X        thread="`echo $i | awk -F= '{print $2}'`"
  781. X        continue;;
  782. X    K)
  783. X        item=`echo $i | awk -F= '{print $2}'`
  784. X        key=`$LIB/soundex $item`
  785. X        continue;;
  786. X    D)
  787. X        date="`echo $i | awk -F= '{print $2}'`"
  788. X        continue;;
  789. X    R)
  790. X        reporter="`echo $i | awk -F= '{print $2}'`"
  791. X        continue;;
  792. X    E)
  793. X        equip="`echo $i | awk -F= '{print $2}'`"
  794. X        continue;;
  795. X    esac
  796. Xdone
  797. X
  798. X#
  799. X# Separate out a thread (if required).
  800. X#
  801. Xif [ "$thread" != "" ]
  802. Xthen
  803. X    #
  804. X    # Ok.  Let's generate a thread list.
  805. X    #
  806. X    if test ! -s $ENTRY/$thread
  807. X    then
  808. X        echo "Invalid thread id.  Try again."
  809. X        exit
  810. X    fi
  811. X    rm -f $TEMP
  812. X    #
  813. X    # Find head of thread
  814. X    #
  815. X    needle=$thread
  816. X    while [ "$needle" != "" ]
  817. X    do
  818. X        thread=$needle
  819. X        needle="`grep '^needle=' $ENTRY/$needle | awk -F= '{print $2}'`"
  820. X    done
  821. X    #
  822. X    # List the members of the thread
  823. X    #
  824. X    while [ "$thread" != "" ]
  825. X    do
  826. X        echo "$ENTRY/$thread" >> $TEMP
  827. X        thread="`grep '^thread=' $ENTRY/$thread | awk -F= '{print $2}'`"
  828. X    done
  829. Xelse
  830. X    #
  831. X    # Get all files
  832. X    #
  833. X    ls $ROOT/$key/$date* > $TEMP2 2>/dev/null
  834. X    sort -u < $TEMP2 > $TEMP
  835. X    date="*"
  836. X    key=""
  837. Xfi
  838. X
  839. X#
  840. X# Now lets get the key field taken care of.
  841. X#
  842. Xif [ "$key" != "" ]
  843. Xthen
  844. X    for i in `cat $TEMP`
  845. X    do
  846. X        ls $ROOT/$key/`basename $i` 2>/dev/null
  847. X    done > $TEMP2
  848. X    mv $TEMP2 $TEMP
  849. Xfi
  850. X
  851. X#
  852. X# Ok.  Now let's generate the subset of the list that has occured on
  853. X# the date in question.
  854. X#
  855. Xif [ "$date" != "*" ]
  856. Xthen
  857. X    grep "$date" < $TEMP > $TEMP2
  858. X    mv $TEMP2 $TEMP
  859. Xfi
  860. X
  861. X#
  862. X# Do the awking for a particular reporter (if necessary).
  863. X#
  864. Xif [ "$reporter" != "" ]
  865. Xthen
  866. X    echo "$reporter" > $TEMP2
  867. X    ls -l `cat $TEMP` >> $TEMP2
  868. X    awk -f $LIB/reporter.awk < $TEMP2 > $TEMP
  869. X    rm $TEMP2
  870. Xfi
  871. X
  872. X#
  873. X# Do the greping for a particular piece of equipment (if necessary).
  874. X#
  875. Xif [ "$equip" != "" ]
  876. Xthen
  877. X    grep -l "^equipment=$equip" `cat $TEMP` > $TEMP
  878. Xfi
  879. X
  880. X#
  881. X# Ok.  More the junk to the screen...
  882. X#
  883. Xfor i in `cat $TEMP`
  884. Xdo
  885. X    echo "ticket=`basename $i`"
  886. X    echo "reporter=`ls -l $i | awk '{print $3}'`"
  887. X    cat $i
  888. X    echo ""
  889. Xdone | more
  890. X
  891. X#
  892. X# Now clean up and exit.
  893. X#
  894. Xrm -f $TEMP $TEMP2 $TEMP3
  895. !FUNKY!STUFF!
  896. echo x - reporter.awk
  897. sed '1,$s/^X//' <<\!FUNKY!STUFF! > reporter.awk
  898. X#
  899. X# Package    : TRS
  900. X# Module    : reporter.awk
  901. X# Programmer    : R. Stolfa
  902. X#
  903. X# Purpose :    This program returns only those lines with the
  904. X#        correct user field as the reporter.
  905. X#
  906. X# Modification History:
  907. X#   04/12/88    Created
  908. X#
  909. X
  910. X{
  911. X    if (NR == 1)
  912. X        reporter = $1;
  913. X    else if (NF > 1) {
  914. X        if (substr($3, 0, length(reporter)) == reporter)
  915. X            printf "%s\n", $NF;
  916. X    }
  917. X}
  918. !FUNKY!STUFF!
  919. echo x - rmthread.1
  920. sed '1,$s/^X//' <<\!FUNKY!STUFF! > rmthread.1
  921. X.TH RMTHREAD L
  922. X.SH NAME
  923. Xrmthread - remove a trouble report system thread from anywhere on the thread
  924. X.SH SYNOPSIS
  925. X.B rmthread [threadid]
  926. X.br
  927. X.SH DESCRIPTION
  928. X.I rmthread
  929. Xis to be used when an entire thread of trouble reports have been delt with
  930. Xand the ammased information is no longer of any use.  This program finds
  931. Xthe head of the list of trouble reports (on the thread given) and then builds
  932. Xa list of thread files to remove.  It then displays the entire thread and
  933. Xasks you if you really want to remove it.  If so, it then gets rid of all
  934. Xoccurances of the associated thread from the trouble report system.
  935. X.sp 1
  936. X.SH "INTERNALS"
  937. X.I rmthread
  938. Xuses an text line in the thread file to provide both a forward link to the
  939. Xnext trouble report and another text line to provide the backward link to
  940. Xthe previous trouble report.  This is why it is so slow at times.
  941. X.sp 1
  942. X.SH AUTHOR
  943. XRoland J. Stolfa
  944. X.br
  945. XDepartment of Computing and Information Sciences
  946. X.br
  947. XOklahoma State University
  948. X.br
  949. Xrjs@a.cs.okstate.edu
  950. !FUNKY!STUFF!
  951. echo x - rmthread.sh
  952. sed '1,$s/^X//' <<\!FUNKY!STUFF! > rmthread.sh
  953. X:
  954. X#
  955. X# Package    : TRS
  956. X# Module    : rmthread.sh
  957. X# Programmer    : R. Stolfa
  958. X#
  959. X# Purpose :    To delete a thread of trouble reports in the TRS
  960. X#        database system.
  961. X#
  962. X# Modification History:
  963. X#   04/12/88    Created
  964. X#   10/25/88    Added a user configurable "ROOT" to allow more than
  965. X#        one TRS on a system
  966. X#
  967. X
  968. X#
  969. X# Some variables
  970. X#
  971. Xumask 000
  972. Xif [ "$TRSROOT" != "" ]
  973. Xthen
  974. X    ROOT=$TRSROOT
  975. Xelse
  976. XROOT=/u/rjs/lib/Trs
  977. Xfi
  978. XENTRY=$ROOT/Entry
  979. XLIB=$ROOT/lib
  980. Xtrap "rm -f $ROOT/tmp/* ; exit 1" 1 2 15
  981. X
  982. X#
  983. X# Get the tread to delete.
  984. X#
  985. Xthread="$*"
  986. Xwhile [ "$thread" = "" ]
  987. Xdo
  988. X    $LIB/print "Enter thread to delete? "
  989. X    read thread
  990. X
  991. X    if test ! -s $ENTRY/$thread
  992. X    then
  993. X        echo "Invalid thread.  Try again"
  994. X        thread=""
  995. X    fi
  996. Xdone
  997. X
  998. X#
  999. X# Search backwards (if possible) for head of thread.
  1000. X#
  1001. Xneedle="+"
  1002. Xwhile [ "$needle" != "" ]
  1003. Xdo
  1004. X    needle="`grep '^needle=' $ENTRY/$thread | awk -F= '{print $2}'`"
  1005. X    if [ "$needle" != "" ]
  1006. X    then
  1007. X        thread="$needle"
  1008. X    fi
  1009. Xdone
  1010. X
  1011. X#
  1012. X# ASSERT:
  1013. X#    At this point, thread is the original trouble report ticket
  1014. X#    number.  Now let's keep that number safe and display the thread
  1015. X#    to assure that it is the one that needs to be removed.
  1016. X#
  1017. X
  1018. Xptr="$thread"
  1019. Xecho "The following is the listing of this thread."
  1020. Xecho ""
  1021. Xwhile [ "$ptr" != "" ]
  1022. Xdo
  1023. X    echo "ticket=$ptr"
  1024. X    echo "reporter=`ls -l $ENTRY/$ptr | awk '{print $3}'`"
  1025. X    cat $ENTRY/$ptr
  1026. X    echo ""
  1027. X    ptr="`grep '^thread=' $ENTRY/$ptr | awk -F= '{print $2}'`"
  1028. Xdone | more
  1029. X
  1030. X#
  1031. X# Prompt for removal.
  1032. X#
  1033. Xyesno=""
  1034. Xwhile [ "$yesno" = "" ]
  1035. Xdo
  1036. X    $LIB/print "Is this the thread you want to delete? (Y/N) "
  1037. X    read yesno
  1038. Xdone
  1039. X
  1040. Xif [ "$yesno" = "n" -o "$yesno" = "N" ]
  1041. Xthen
  1042. X    exit
  1043. Xfi
  1044. X
  1045. X#
  1046. X# Ok.  We have permission.  Just remove the whole stupid thing...
  1047. X#
  1048. Xptr="$thread"
  1049. Xwhile [ "$ptr" != "" ]
  1050. Xdo
  1051. X    thread="`grep '^thread=' $ENTRY/$ptr | awk -F= '{print $2}'`"
  1052. X    rm -f $ROOT/*/$ptr
  1053. X    ptr="$thread"
  1054. Xdone
  1055. !FUNKY!STUFF!
  1056. echo x - soundex.c
  1057. sed '1,$s/^X//' <<\!FUNKY!STUFF! > soundex.c
  1058. X/*
  1059. X * Package    : TRS
  1060. X * Program    : soundex.c
  1061. X * Programmer    : Roland Stolfa
  1062. X *
  1063. X * Function :    This program implements the SOUNDEX procedure as
  1064. X *        outlined on page 655 of "Database Design" by
  1065. X *        Gio Wiederhold.  This procedure was originally
  1066. X *        introduced by Odell & Russel (1918) and was
  1067. X *        described by McEwen (1974).
  1068. X *
  1069. X * Usage :    soundex <string1> <string2> ... <stringN>
  1070. X */
  1071. X
  1072. X#include    <stdio.h>
  1073. X
  1074. X#define        BS        200
  1075. X
  1076. Xmain (argc, argv)
  1077. Xint    argc;
  1078. Xchar    *argv[];
  1079. X{
  1080. X    char    sound[BS];
  1081. X    int    i;
  1082. X
  1083. X    if (argc == 1) {
  1084. X        fprintf (stderr,
  1085. X            "Usage: soundex <string1> <string2> ... <stringN>\n");
  1086. X        exit (-1);
  1087. X    }
  1088. X
  1089. X    for (i = 1; i < argc; i ++) {
  1090. X        soundex (argv[i], sound);
  1091. X        printf ("%s\n", sound);
  1092. X    }
  1093. X}
  1094. X
  1095. Xsoundex (word, sound)
  1096. Xchar    word[],        /* String to convert to SOUNDEX */
  1097. X    sound[];    /* Output SOUNDEX */
  1098. X{
  1099. X    int    outpos,        /* Current output position in SOUNDEX */
  1100. X        j;        /* Index into word */
  1101. X
  1102. X    /* Initialize return word */
  1103. X    outpos = 0;
  1104. X    sound[outpos] = '\0';
  1105. X
  1106. X    /* If the word is null, then the output should be null */
  1107. X    if (strlen(word) == 0)
  1108. X        return;
  1109. X
  1110. X    /* Copy first character of word to SOUNDEX */
  1111. X    sound[outpos] = toupper (word[0]);
  1112. X
  1113. X    for (j = 1; j < strlen (word); j ++) {
  1114. X
  1115. X        /* Convert each character to uppercase */
  1116. X        word[j] = toupper(word[j]);
  1117. X
  1118. X        switch (word[j]) {
  1119. X
  1120. X        /* Replace Labials with "1" */
  1121. X        case 'B':
  1122. X        case 'F':
  1123. X        case 'P':
  1124. X        case 'V':
  1125. X            if (sound[outpos] != '1') {
  1126. X                outpos ++;
  1127. X                sound[outpos] = '1';
  1128. X            }
  1129. X            break;
  1130. X
  1131. X        /* Replace Gutterals & sibilants with "2" */
  1132. X        case 'C':
  1133. X        case 'G':
  1134. X        case 'J':
  1135. X        case 'K':
  1136. X        case 'Q':
  1137. X        case 'S':
  1138. X        case 'X':
  1139. X        case 'Z':
  1140. X            if (sound[outpos] != '2') {
  1141. X                outpos ++;
  1142. X                sound[outpos] = '2';
  1143. X            }
  1144. X            break;
  1145. X
  1146. X        /* Replace Dentals with "3" */
  1147. X        case 'D':
  1148. X        case 'T':
  1149. X            if (sound[outpos] != '3') {
  1150. X                outpos ++;
  1151. X                sound[outpos] = '3';
  1152. X            }
  1153. X            break;
  1154. X
  1155. X        /* Replace Longliquids with "4" */
  1156. X        case 'L':
  1157. X            if (sound[outpos] != '4') {
  1158. X                outpos ++;
  1159. X                sound[outpos] = '4';
  1160. X            }
  1161. X            break;
  1162. X
  1163. X        /* Replace Nasals with "5" */
  1164. X        case 'M':
  1165. X        case 'N':
  1166. X            if (sound[outpos] != '5') {
  1167. X                outpos ++;
  1168. X                sound[outpos] = '5';
  1169. X            }
  1170. X            break;
  1171. X
  1172. X        /* Replace Shortliquids with "6" */
  1173. X        case 'R':
  1174. X            if (sound[outpos] != '6') {
  1175. X                outpos ++;
  1176. X                sound[outpos] = '6';
  1177. X            }
  1178. X            break;
  1179. X        }
  1180. X    }
  1181. X
  1182. X    /* Terminate the soundex string */
  1183. X    outpos ++;
  1184. X    sound[outpos] = '\0';
  1185. X
  1186. X    /* Forcably trunicate soundex to 4 characters */
  1187. X    sound[4] = '\0';
  1188. X}
  1189. X
  1190. !FUNKY!STUFF!
  1191. echo x - trouble.1
  1192. sed '1,$s/^X//' <<\!FUNKY!STUFF! > trouble.1
  1193. X.TH TROUBLE L
  1194. X.SH NAME
  1195. Xtrouble - enter an initial trouble report
  1196. X.SH SYNOPSIS
  1197. X.B trouble
  1198. X.br
  1199. X.SH DESCRIPTION
  1200. X.I trouble
  1201. Xenters the inital trouble report in the trouble report system.  It is
  1202. Xused also by
  1203. X.I followup
  1204. Xto enter all followup trouble reports in the current thread.
  1205. X.PP
  1206. XThis program is self prompting and fairly self explanitory.
  1207. X.sp 1
  1208. X.SH AUTHOR
  1209. XRoland J. Stolfa
  1210. X.br
  1211. XDepartment of Computing and Information Sciences
  1212. X.br
  1213. XOklahoma State University
  1214. X.br
  1215. Xrjs@a.cs.okstate.edu
  1216. !FUNKY!STUFF!
  1217. echo x - trouble.sh
  1218. sed '1,$s/^X//' <<\!FUNKY!STUFF! > trouble.sh
  1219. X:
  1220. X#
  1221. X# Package    : TRS
  1222. X# Module    : trouble.sh
  1223. X# Programmer    : R. Stolfa
  1224. X#
  1225. X# Purpose :    To enter trouble reports into the TRS database system.
  1226. X#
  1227. X# Modification History:
  1228. X#   04/11/88    Created
  1229. X#   04/12/88    Added hooks for recording the new trouble number in the
  1230. X#        environment variable NTN for use in "followup"
  1231. X#   10/25/88    Added user configurable "ROOT" to allow more than
  1232. X#        one TRS on a system
  1233. X#
  1234. X
  1235. X#
  1236. X# Some variables
  1237. X#
  1238. Xumask 000
  1239. Xif [ "$TRSROOT" != "" ]
  1240. Xthen
  1241. X    ROOT=$TRSROOT
  1242. Xelse
  1243. XROOT=/u/rjs/lib/Trs
  1244. Xfi
  1245. XENTRY=$ROOT/Entry
  1246. XLIB=$ROOT/lib
  1247. XSEQ=$ROOT/sequence
  1248. XTEMP=$ROOT/tmp/trs.$$
  1249. Xtrap "rm -f $ROOT/tmp/* ; exit 1" 1 2 15
  1250. X
  1251. Xrm -f $TEMP
  1252. X
  1253. X#
  1254. X# Prompt for what piece of equipment is down.
  1255. X#
  1256. Xequipment=""
  1257. Xwhile [ "$equipment" = "" ]
  1258. Xdo
  1259. X    $LIB/print "Enter equipment ID string? "
  1260. X    read equipment
  1261. Xdone
  1262. Xecho "equipment=$equipment" >> $TEMP
  1263. X
  1264. X#
  1265. X# Get the keywords to link the file in "Entry" to under each
  1266. X# of their respective "SOUNDEX" equivalents.
  1267. X#
  1268. Xecho "Enter the keywords that are to be associated with this"
  1269. Xecho "report one per line, ending with a blank line."
  1270. X$LIB/print "keywords=" >> $TEMP
  1271. Xkeywords=""
  1272. Xdummy="+"
  1273. Xwhile [ "$dummy" != "" ]
  1274. Xdo
  1275. X    read dummy
  1276. X    if [ "$dummy" != "" ]
  1277. X    then
  1278. X        $LIB/print "$dummy " >> $TEMP
  1279. X        keywords="$keywords`$LIB/soundex $dummy` "
  1280. X    fi
  1281. Xdone
  1282. Xecho "" >> $TEMP
  1283. X
  1284. X#
  1285. X# Enter the report.
  1286. X#
  1287. Xecho "Enter report, ending with a blank line"
  1288. Xdummy="+"
  1289. Xwhile [ "$dummy" != "" ]
  1290. Xdo
  1291. X    read dummy
  1292. X    if [ "$dummy" != "" ]
  1293. X    then
  1294. X        echo "desc=$dummy" >> $TEMP
  1295. X    fi
  1296. Xdone
  1297. X
  1298. X#
  1299. X# Attempt to link in to "Entry" directory.  This could be an area
  1300. X# of contension (for the sequence file).  The following sheme was
  1301. X# choosen to give some reasonable operation.
  1302. X#
  1303. Xcond=1
  1304. Xwhile test $cond -ne 0
  1305. Xdo
  1306. X    entry="`date '+%y%m%d'`.`cat $SEQ`"
  1307. X    seq=`cat $SEQ`
  1308. X    expr $seq + 1 > $SEQ
  1309. X    ln $TEMP $ENTRY/$entry
  1310. X    cond=$?
  1311. X    if test $cond -ne 0
  1312. X    then
  1313. X        echo "Collision.  Attempting fix..."
  1314. X    fi
  1315. Xdone
  1316. Xrm $TEMP
  1317. X
  1318. X#
  1319. X# Report the "trouble ticket" number for future 'threading'.
  1320. X#
  1321. Xecho " "
  1322. Xecho "Your trouble ticket number is $entry"
  1323. Xecho "save this number for future reference."
  1324. X
  1325. X#
  1326. X# Record the new trouble number in the environment variable NTN.
  1327. X#
  1328. XNTN=$entry
  1329. X
  1330. X#
  1331. X# Now link the "Entry" directory trouble report to a file with
  1332. X# the same timestamp.sequence filename in a directory for each of
  1333. X# the "SOUNDEX" keywords.  This is in an attempt to make the
  1334. X# system easier to search.
  1335. X#
  1336. Xfor i in $keywords
  1337. Xdo
  1338. X    $LIB/mkpath $ROOT/$i/$entry
  1339. X    ln $ENTRY/$entry $ROOT/$i/$entry
  1340. Xdone
  1341. X
  1342. X#
  1343. X# Ok.  Let's be clean...
  1344. X#
  1345. Xrm -f $TEMP
  1346. !FUNKY!STUFF!
  1347.