#define _POSIX_SOURCE
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stddef.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct functionInfo {
    char* name;
    int timesCalled;
    char marked;
};
void addToList(struct functionInfo** list, struct functionInfo toAdd, \
               size_t* numElements, size_t* allocatedSize)
{
    static const char* keywords[32] = {"auto", "break", "case", "char", "const", \
                                       "continue", "default", "do", "double", \
                                       "else", "enum", "extern", "float", "for", \
                                       "goto", "if", "int", "long", "register", \
                                       "return", "short", "signed", "sizeof", \
                                       "static", "struct", "switch", "typedef", \
                                       "union", "unsigned", "void", "volatile", \
                                       "while"
                                      };
    int i;
    /* If the "function" being called is actually a keyword, then ignore it */
    for (i = 0; i < 32; i++) {
        if (!strcmp(toAdd.name, keywords[i])) {
            return;
        }
    }
    if (!*list) {
        *allocatedSize = 10;
        *list = calloc(*allocatedSize, sizeof(struct functionInfo));
        if (!*list) {
            printf("Failed to allocate %lu elements of %lu bytes each.\n", \
                   *allocatedSize, sizeof(struct functionInfo));
            abort();
        }
        (*list)[0].name = malloc(strlen(toAdd.name)+1);
        if (!(*list)[0].name) {
            printf("Failed to allocate %lu bytes.\n", strlen(toAdd.name)+1);
            abort();
        }
        strcpy((*list)[0].name, toAdd.name);
        (*list)[0].timesCalled = 1;
        (*list)[0].marked = 0;
        *numElements = 1;
    } else {
        char found = 0;
        unsigned int i;
        for (i = 0; i < *numElements; i++) {
            if (!strcmp((*list)[i].name, toAdd.name)) {
                found = 1;
                (*list)[i].timesCalled++;
                break;
            }
        }
        if (!found) {
            struct functionInfo* newList = calloc((*allocatedSize)+10, \
                                                  sizeof(struct functionInfo));
            if (!newList) {
                printf("Failed to allocate %lu elements of %lu bytes each.\n", \
                       (*allocatedSize)+10, sizeof(struct functionInfo));
                abort();
            }
            memcpy(newList, *list, (*allocatedSize)*sizeof(struct functionInfo));
            free(*list);
            *allocatedSize += 10;
            *list = newList;
            (*list)[*numElements].name = malloc(strlen(toAdd.name)+1);
            if (!(*list)[*numElements].name) {
                printf("Failed to allocate %lu bytes.\n", strlen(toAdd.name)+1);
                abort();
            }
            strcpy((*list)[*numElements].name, toAdd.name);
            (*list)[*numElements].timesCalled = 1;
            (*list)[*numElements].marked = 0;
            (*numElements)++;
        }
    }
}
void printList(struct functionInfo** list, size_t numElements)
{
    char maxSet = 0;
    unsigned int i;
    size_t maxIndex = 0;
    for (i = 0; i<10; i++) {
        maxSet = 0;
        size_t j;
        for (j = 0; j<numElements; j++) {
            if (!maxSet || (*list)[j].timesCalled > (*list)[maxIndex].timesCalled) {
                if (!(*list)[j].marked) {
                    maxSet = 1;
                    maxIndex = j;
                }
            }
        }
        (*list)[maxIndex].marked = 1;
        printf("%s() called %d times.\n", (*list)[maxIndex].name, \
               (*list)[maxIndex].timesCalled);
    }
}
void freeList(struct functionInfo** list, size_t numElements)
{
    size_t i;
    for (i = 0; i<numElements; i++) {
        free((*list)[i].name);
    }
    free(*list);
}
char* extractFunctionName(char* readHead)
{
    char* identifier = readHead;
    if (isalpha(*identifier) || *identifier == '_') {
        while (isalnum(*identifier) || *identifier == '_') {
            identifier++;
        }
    }
    /* Search forward for spaces and then an open parenthesis
     * but do not include this in the function name.
     */
    char* toParen = identifier;
    if (toParen == readHead) return NULL;
    while (isspace(*toParen)) {
        toParen++;
    }
    if (*toParen != '(') return NULL;
    /* Copy the found function name to the output string */
    ptrdiff_t size = (ptrdiff_t)((ptrdiff_t)identifier) \
                     - ((ptrdiff_t)readHead)+1;
    char* const name = malloc(size);
    if (!name) {
        printf("Failed to allocate %lu bytes.\n", size);
        abort();
    }
    name[size-1] = '\0';
    memcpy(name, readHead, size-1);
    /* Function names can't be blank */
    if (strcmp(name, "")) {
        return name;
    }
    free(name);
    return NULL;
}
int main(int argc, char** argv)
{
    int i;
    for (i = 1; i<argc; i++) {
        errno = 0;
        FILE* file = fopen(argv[i], "r");
        if (errno || !file) {
            printf("fopen() failed with error code \"%s\"\n", \
                   strerror(errno));
            abort();
        }
        char comment = 0;
#define DOUBLEQUOTE 1
#define SINGLEQUOTE 2
        int string = 0;
        struct functionInfo* functions = NULL;
        struct functionInfo toAdd;
        size_t numElements = 0;
        size_t allocatedSize = 0;
        struct stat metaData;
        errno = 0;
        if (fstat(fileno(file), &metaData) < 0) {
            printf("fstat() returned error \"%s\"\n", strerror(errno));
            abort();
        }
        char* mmappedSource = (char*)mmap(NULL, metaData.st_size, PROT_READ, \
                                          MAP_PRIVATE, fileno(file), 0);
        if (errno) {
            printf("mmap() failed with error \"%s\"\n", strerror(errno));
            abort();
        }
        if (!mmappedSource) {
            printf("mmap() returned NULL.\n");
            abort();
        }
        char* readHead = mmappedSource;
        while (readHead < mmappedSource + metaData.st_size) {
            while (*readHead) {
                /* Ignore comments inside strings */
                if (!string) {
                    if (*readHead == '/' && !strncmp(readHead, "/*", 2)) {
                        comment = 1;
                    }
                    if (*readHead == '*' && !strncmp(readHead, "*/", 2)) {
                        comment = 0;
                    }
                }
                /* Ignore strings inside comments */
                if (!comment) {
                    if (*readHead == '"') {
                        if (!string) {
                            string = DOUBLEQUOTE;
                        } else if (string == DOUBLEQUOTE) {
                            /* Only toggle string mode if the quote character
                             * is not escaped
                             */
                            if (strncmp((readHead-1), "\\\"", 2)) {
                                string = 0;
                            }
                        }
                    }
                    if (*readHead == '\'') {
                        if (!string) {
                            string = SINGLEQUOTE;
                        } else if (string == SINGLEQUOTE) {
                            if (strncmp((readHead-1), "\\\'", 2)) {
                                string = 0;
                            }
                        }
                    }
                }
                /* Look for identifiers outside of any comment or string */
                if (!comment && !string) {
                    char* name = extractFunctionName(readHead);
                    /* Don't read part of an identifier on the next iteration */
                    if (name) {
                        toAdd.name = name;
                        addToList(&functions, toAdd, &numElements, &allocatedSize);
                        readHead += strlen(name);
                    }
                    free(name);
                }
                readHead++;
            }
        }
        errno = 0;
        munmap(mmappedSource, metaData.st_size);
        if (errno) {
            printf("munmap() returned error \"%s\"\n", strerror(errno));
            abort();
        }
        errno = 0;
        fclose(file);
        if (errno) {
            printf("fclose() returned error \"%s\"\n", strerror(errno));
            abort();
        }
        printList(&functions, numElements);
        freeList(&functions, numElements);
    }
    return 0;
}


{-# LANGUAGE OverloadedStrings #-}

import Data.Bifunctor (first)
import Data.Bool (bool)
import Data.Char (isSpace)
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Text.Read as T
import Data.Tree (Forest, Tree (..), foldTree)
import Numeric (showFFloat)
import System.Directory (doesFileExist)

----------------- FUNCTIONAL COVERAGE TREE ---------------

data Coverage = Coverage
  { name :: T.Text,
    weight :: Float,
    coverage :: Float,
    share :: Float
  }
  deriving (Show)

--------------------------- TEST -------------------------
fp = "./coverageOutline.txt"

main :: IO ()
main =
  doesFileExist fp
    >>= bool
      (print $ "File not found: " <> fp)
      (T.readFile fp >>= T.putStrLn . updatedCoverageOutline)

----------------- UPDATED COVERAGE OUTLINE ---------------
updatedCoverageOutline :: T.Text -> T.Text
updatedCoverageOutline s =
  let delimiter = "|"
      indentedLines = T.lines s
      columnNames =
        init $
          tokenizeWith
            delimiter
            ( head indentedLines
            )
   in T.unlines
        [ tabulation
            delimiter
            (columnNames <> ["SHARE OF RESIDUE"]),
          indentedLinesFromTree
            "    "
            (showCoverage delimiter)
            $ withResidueShares 1.0 $
              foldTree
                weightedCoverage
                (parseTreeFromOutline delimiter indentedLines)
        ]

------ WEIGHTED COVERAGE AND SHARES OF REMAINING WORK ----
weightedCoverage ::
  Coverage ->
  Forest Coverage ->
  Tree Coverage
weightedCoverage x xs =
  let cws = ((,) . coverage <*> weight) . rootLabel <$> xs
      totalWeight = foldr ((+) . snd) 0 cws
   in Node
        ( x
            { coverage =
                foldr
                  (\(c, w) a -> (c * w) + a)
                  (coverage x)
                  cws
                  / bool 1 totalWeight (0 < totalWeight)
            }
        )
        xs

withResidueShares :: Float -> Tree Coverage -> Tree Coverage
withResidueShares shareOfTotal tree =
  let go fraction node =
        let forest = subForest node
            weights = weight . rootLabel <$> forest
            weightTotal = sum weights
            nodeRoot = rootLabel node
         in Node
              ( nodeRoot
                  { share =
                      fraction
                        * (1 - coverage nodeRoot)
                  }
              )
              ( zipWith
                  go
                  ((fraction *) . (/ weightTotal) <$> weights)
                  forest
              )
   in go shareOfTotal tree

---------------------- OUTLINE PARSE ---------------------
parseTreeFromOutline :: T.Text -> [T.Text] -> Tree Coverage
parseTreeFromOutline delimiter indentedLines =
  partialRecord . tokenizeWith delimiter
    <$> head
      ( forestFromLineIndents $
          indentLevelsFromLines $ tail indentedLines
      )

forestFromLineIndents :: [(Int, T.Text)] -> [Tree T.Text]
forestFromLineIndents pairs =
  let go [] = []
      go ((n, s) : xs) =
        let (firstTreeLines, rest) = span ((n <) . fst) xs
         in Node s (go firstTreeLines) : go rest
   in go pairs

indentLevelsFromLines :: [T.Text] -> [(Int, T.Text)]
indentLevelsFromLines xs =
  let pairs = T.span isSpace <$> xs
      indentUnit =
        foldr
          ( \x a ->
              let w = (T.length . fst) x
               in bool a w (w < a && 0 < w)
          )
          (maxBound :: Int)
          pairs
   in first (flip div indentUnit . T.length) <$> pairs

partialRecord :: [T.Text] -> Coverage
partialRecord xs =
  let [name, weightText, coverageText] =
        take
          3
          (xs <> repeat "")
   in Coverage
        { name = name,
          weight = defaultOrRead 1.0 weightText,
          coverage = defaultOrRead 0.0 coverageText,
          share = 0.0
        }

defaultOrRead :: Float -> T.Text -> Float
defaultOrRead n txt = either (const n) fst $ T.rational txt

tokenizeWith :: T.Text -> T.Text -> [T.Text]
tokenizeWith delimiter = fmap T.strip . T.splitOn delimiter

-------- SERIALISATION OF TREE TO TABULATED OUTLINE ------
indentedLinesFromTree ::
  T.Text ->
  (T.Text -> a -> T.Text) ->
  Tree a ->
  T.Text
indentedLinesFromTree tab showRoot tree =
  let go indent node =
        showRoot indent (rootLabel node) :
        (subForest node >>= go (T.append tab indent))
   in T.unlines $ go "" tree

showCoverage :: T.Text -> T.Text -> Coverage -> T.Text
showCoverage delimiter indent x =
  tabulation
    delimiter
    ( [T.append indent (name x), T.pack (showN 0 (weight x))]
        <> (T.pack . showN 4 <$> ([coverage, share] <*> [x]))
    )

tabulation :: T.Text -> [T.Text] -> T.Text
tabulation delimiter =
  T.intercalate (T.append delimiter " ")
    . zipWith (`T.justifyLeft` ' ') [31, 9, 9, 9]

justifyRight :: Int -> a -> [a] -> [a]
justifyRight n c = (drop . length) <*> (replicate n c <>)

showN :: Int -> Float -> String
showN p n = justifyRight 7 ' ' (showFFloat (Just p) n "")


(defun mapc-tree (fn tree)
  "Apply FN to all elements in TREE."
  (cond ((consp tree)
         (mapc-tree fn (car tree))
         (mapc-tree fn (cdr tree)))
        (t (funcall fn tree))))

(defun count-source (source)
  "Load and count all function-bound symbols in a SOURCE file."
  (load source)
  (with-open-file (s source)
    (let ((table (make-hash-table)))
      (loop for data = (read s nil nil)
         while data
         do (mapc-tree
             (lambda (x)
               (when (and (symbolp x) (fboundp x))
                 (incf (gethash x table 0))))
             data))
      table)))

(defun hash-to-alist (table)
  "Convert a hashtable to an alist."
  (let ((alist))
    (maphash (lambda (k v) (push (cons k v) alist)) table)
    alist))

(defun take (n list)
  "Take at most N elements from LIST."
  (loop repeat n for x in list collect x))

(defun top-10 (table)
  "Get the top 10 from the source counts TABLE."
  (take 10 (sort (hash-to-alist table) '> :key 'cdr)))


-module( function_frequency ).

-export( [erlang_source/1, task/0] ).

erlang_source( File ) ->
    {ok, IO} = file:open( File, [read] ),
    Forms = parse_all( IO, io:parse_erl_form(IO, ''), [] ),
    Functions = lists:flatten( [erl_syntax_lib:fold(fun accumulate_functions/2, [], X) || X <- Forms] ),
    dict:to_list( lists:foldl(fun count/2, dict:new(), Functions) ).

task() ->
    Function_frequencies = erlang_source( "function_frequency.erl" ),
    {Top_tens, _Rest} = lists:split( 10, lists:reverse(lists:keysort(2, Function_frequencies)) ),
    [io:fwrite("Function ~p called ~p times.~n", [X, Y]) || {X, Y} <- Top_tens].

accumulate_functions( Tree, Acc ) -> accumulate_functions( erlang:element(1, Tree), Tree, Acc ).

accumulate_functions( call, Tree, Acc ) -> [accumulate_functions_name(Tree) | Acc];
accumulate_functions( _Other, _Tree, Acc ) -> Acc.

accumulate_functions_name( Tree ) -> accumulate_functions_name_scoop( erlang:element(3, Tree) ).

accumulate_functions_name_scoop( {atom, _Line, Name} ) -> Name;
accumulate_functions_name_scoop( {remote, _Line, {atom, _Line, Module}, {atom, _Line, Name}} ) -> {Module, Name}.

count( Key, Dict ) -> dict:update_counter( Key, 1, Dict ).

parse_all( _IO, {eof, _End}, Acc ) -> Acc;
parse_all( IO, {ok, Tokens, Location}, Acc ) -> parse_all( IO, io:parse_erl_form(IO, '', Location), [Tokens | Acc] ).


raw=: 0 :0
NAME_HIERARCHY                  |WEIGHT  |COVERAGE  |
cleaning                        |        |          |
    house1                      |40      |          |
        bedrooms                |        |0.25      |
        bathrooms               |        |          |
            bathroom1           |        |0.5       |
            bathroom2           |        |          |
            outside_lavatory    |        |1         |
        attic                   |        |0.75      |
        kitchen                 |        |0.1       |
        living_rooms            |        |          |
            lounge              |        |          |
            dining_room         |        |          |
            conservatory        |        |          |
            playroom            |        |1         |
        basement                |        |          |
        garage                  |        |          |
        garden                  |        |0.8       |
    house2                      |60      |          |
        upstairs                |        |          |
            bedrooms            |        |          |
                suite_1         |        |          |
                suite_2         |        |          |
                bedroom_3       |        |          |
                bedroom_4       |        |          |
            bathroom            |        |          |
            toilet              |        |          |
            attics              |        |0.6       |
        groundfloor             |        |          |
            kitchen             |        |          |
            living_rooms        |        |          |
                lounge          |        |          |
                dining_room     |        |          |
                conservatory    |        |          |
                playroom        |        |          |
            wet_room_&_toilet   |        |          |
            garage              |        |          |
            garden              |        |0.9       |
            hot_tub_suite       |        |1         |
        basement                |        |          |
            cellars             |        |1         |
            wine_cellar         |        |1         |
            cinema              |        |0.75      |
)


(() => {
    'use strict';

    // updatedCoverageOutline :: String -> String
    const updatedCoverageOutline = outlineText => {
        const
            delimiter = '|',
            indentedLines = indentLevelsFromLines(lines(outlineText)),
            columns = init(tokenizeWith(delimiter)(snd(indentedLines[0])));

        // SERIALISATION OF UPDATED PARSE TREE (TO NEW OUTLINE TEXT)
        return tabulation(delimiter)(
            columns.concat('SHARE OF RESIDUE\n')
        ) + unlines(
            indentedLinesFromTree(
                showCoverage(delimiter))('    ')(

                // TWO TRAVERSAL COMPUTATIONS

                withResidueShares(1.0)(
                    foldTree(weightedCoverage)(

                        // PARSE TREE (FROM OUTLINE TEXT)
                        fmapTree(compose(
                            partialRecord, tokenizeWith(delimiter)
                        ))(fst(
                            forestFromLineIndents(tail(indentedLines))
                        ))
                    )
                ))
        );
    };

    // TEST -----------------------------------------------
    // main :: IO ()
    const main = () =>
        console.log(
            // strOutline is included as literal text
            // at the foot of this code listing.
            updatedCoverageOutline(strOutline)
        );

    // COVERAGE AND SHARES OF RESIDUE ---------------------

    // weightedCoverage :: Dict -> Forest Dict -> Tree Dict
    const weightedCoverage = x => xs => {
        const
            cws = map(compose(
                fanArrow(x => x.coverage)(x => x.weight),
                root
            ))(xs),
            totalWeight = cws.reduce((a, tpl) => a + snd(tpl), 0);
        return Node(
            insertDict('coverage')(
                cws.reduce((a, tpl) => {
                    const [c, w] = Array.from(tpl);
                    return a + (c * w);
                }, x.coverage) / (
                    0 < totalWeight ? totalWeight : 1
                )
            )(x)
        )(xs);
    };

    // withResidueShares :: Float -> Tree Dict -> Tree Dict
    const withResidueShares = shareOfTotal => tree => {
        const go = fraction => node => {
            const
                nodeRoot = node.root,
                forest = node.nest,
                weights = forest.map(x => x.root.weight),
                weightTotal = sum(weights);
            return Node(
                insertDict('share')(
                    fraction * (1 - nodeRoot.coverage)
                )(nodeRoot)
            )(
                zipWith(go)(
                    weights.map(w => fraction * (w / weightTotal))
                )(forest)
            );
        };
        return go(shareOfTotal)(tree);
    };

    // OUTLINE PARSED TO TREE -----------------------------

    // forestFromLineIndents :: [(Int, String)] -> [Tree String]
    const forestFromLineIndents = tuples => {
        const go = xs =>
            0 < xs.length ? (() => {
                const [n, s] = Array.from(xs[0]);
                // Lines indented under this line,
                // tupled with all the rest.
                const [firstTreeLines, rest] = Array.from(
                    span(x => n < x[0])(xs.slice(1))
                );
                // This first tree, and then the rest.
                return [Node(s)(go(firstTreeLines))]
                    .concat(go(rest));
            })() : [];
        return go(tuples);
    };

    // indentLevelsFromLines :: [String] -> [(Int, String)]
    const indentLevelsFromLines = xs => {
        const
            indentTextPairs = xs.map(compose(
                firstArrow(length), span(isSpace)
            )),
            indentUnit = minimum(indentTextPairs.flatMap(pair => {
                const w = fst(pair);
                return 0 < w ? [w] : [];
            }));
        return indentTextPairs.map(
            firstArrow(flip(div)(indentUnit))
        );
    };

    // partialRecord :: [String] -> Dict
    const partialRecord = xs => {
        const [name, weightText, coverageText] = take(3)(
            xs.concat(['', '', ''])
        );
        return {
            name: name || '?',
            weight: parseFloat(weightText) || 1.0,
            coverage: parseFloat(coverageText) || 0.0,
            share: 0.0
        };
    };

    // tokenizeWith :: String -> String -> [String]
    const tokenizeWith = delimiter =>
        // A sequence of trimmed tokens obtained by
        // splitting s on the supplied delimiter.
        s => s.split(delimiter).map(x => x.trim());

    // TREE SERIALIZED TO OUTLINE -------------------------

    // indentedLinesFromTree :: (String -> a -> String) ->
    // String -> Tree a -> [String]
    const indentedLinesFromTree = showRoot =>
        strTab => tree => {
            const go = indent =>
                node => [showRoot(indent)(node.root)]
                .concat(node.nest.flatMap(go(strTab + indent)));
            return go('')(tree);
        };

    // showN :: Int -> Float -> String
    const showN = p =>
        n => justifyRight(7)(' ')(n.toFixed(p));

    // showCoverage :: String -> String -> Dict -> String
    const showCoverage = delimiter =>
        indent => x => tabulation(delimiter)(
            [indent + x.name, showN(0)(x.weight)]
            .concat([x.coverage, x.share].map(showN(4)))
        );

    // tabulation :: String -> [String] -> String
    const tabulation = delimiter =>
        // Up to 4 tokens drawn from the argument list,
        // as a single string with fixed left-justified
        // white-space widths, between delimiters.
        compose(
            intercalate(delimiter + ' '),
            zipWith(flip(justifyLeft)(' '))([31, 9, 9, 9])
        );

    // GENERIC AND REUSABLE FUNCTIONS ---------------------

    // Node :: a -> [Tree a] -> Tree a
    const Node = v => xs => ({
        type: 'Node',
        root: v, // any type of value (consistent across tree)
        nest: xs || []
    });

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = a => b => ({
        type: 'Tuple',
        '0': a,
        '1': b,
        length: 2
    });

    // compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
    const compose = (...fs) =>
        x => fs.reduceRight((a, f) => f(a), x);

    // concat :: [[a]] -> [a]
    // concat :: [String] -> String
    const concat = xs =>
        0 < xs.length ? (() => {
            const unit = 'string' !== typeof xs[0] ? (
                []
            ) : '';
            return unit.concat.apply(unit, xs);
        })() : [];

    // div :: Int -> Int -> Int
    const div = x => y => Math.floor(x / y);

    // either :: (a -> c) -> (b -> c) -> Either a b -> c
    const either = fl => fr => e =>
        'Either' === e.type ? (
            undefined !== e.Left ? (
                fl(e.Left)
            ) : fr(e.Right)
        ) : undefined;

    // Compose a function from a simple value to a tuple of
    // the separate outputs of two different functions

    // fanArrow (&&&) :: (a -> b) -> (a -> c) -> (a -> (b, c))
    const fanArrow = f => g => x => Tuple(f(x))(
        g(x)
    );

    // Lift a simple function to one which applies to a tuple,
    // transforming only the first item of the tuple

    // firstArrow :: (a -> b) -> ((a, c) -> (b, c))
    const firstArrow = f => xy => Tuple(f(xy[0]))(
        xy[1]
    );

    // flip :: (a -> b -> c) -> b -> a -> c
    const flip = f =>
        1 < f.length ? (
            (a, b) => f(b, a)
        ) : (x => y => f(y)(x));

    // fmapTree :: (a -> b) -> Tree a -> Tree b
    const fmapTree = f => tree => {
        const go = node => Node(f(node.root))(
            node.nest.map(go)
        );
        return go(tree);
    };

    // foldTree :: (a -> [b] -> b) -> Tree a -> b
    const foldTree = f => tree => {
        const go = node => f(node.root)(
            node.nest.map(go)
        );
        return go(tree);
    };

    // foldl1 :: (a -> a -> a) -> [a] -> a
    const foldl1 = f => xs =>
        1 < xs.length ? xs.slice(1)
        .reduce(uncurry(f), xs[0]) : xs[0];

    // fst :: (a, b) -> a
    const fst = tpl => tpl[0];

    // init :: [a] -> [a]
    const init = xs =>
        0 < xs.length ? (
            xs.slice(0, -1)
        ) : undefined;

    // insertDict :: String -> a -> Dict -> Dict
    const insertDict = k => v => dct =>
        Object.assign({}, dct, {
            [k]: v
        });

    // intercalate :: [a] -> [[a]] -> [a]
    // intercalate :: String -> [String] -> String
    const intercalate = sep =>
        xs => xs.join(sep);

    // isSpace :: Char -> Bool
    const isSpace = c => /\s/.test(c);

    // justifyLeft :: Int -> Char -> String -> String
    const justifyLeft = n => cFiller => s =>
        n > s.length ? (
            s.padEnd(n, cFiller)
        ) : s;

    // justifyRight :: Int -> Char -> String -> String
    const justifyRight = n => cFiller => s =>
        n > s.length ? (
            s.padStart(n, cFiller)
        ) : s;

    // length :: [a] -> Int
    const length = xs =>
        (Array.isArray(xs) || 'string' === typeof xs) ? (
            xs.length
        ) : Infinity;

    // lines :: String -> [String]
    const lines = s => s.split(/[\r\n]/);

    // map :: (a -> b) -> [a] -> [b]
    const map = f => xs =>
        (Array.isArray(xs) ? (
            xs
        ) : xs.split('')).map(f);

    // minimum :: Ord a => [a] -> a
    const minimum = xs =>
        0 < xs.length ? (
            foldl1(a => x => x < a ? x : a)(xs)
        ) : undefined;

    // root :: Tree a -> a
    const root = tree => tree.root;

    // showLog :: a -> IO ()
    const showLog = (...args) =>
        console.log(
            args
            .map(JSON.stringify)
            .join(' -> ')
        );

    // snd :: (a, b) -> b
    const snd = tpl => tpl[1];

    // span :: (a -> Bool) -> [a] -> ([a], [a])
    const span = p => xs => {
        const iLast = xs.length - 1;
        return splitAt(
            until(i => iLast < i || !p(xs[i]))(
                succ
            )(0)
        )(xs);
    };

    // splitAt :: Int -> [a] -> ([a], [a])
    const splitAt = n => xs =>
        Tuple(xs.slice(0, n))(
            xs.slice(n)
        );

    // succ :: Enum a => a -> a
    const succ = x =>
        1 + x;

    // sum :: [Num] -> Num
    const sum = xs =>
        xs.reduce((a, x) => a + x, 0);

    // tail :: [a] -> [a]
    const tail = xs =>
        0 < xs.length ? xs.slice(1) : [];

    // take :: Int -> [a] -> [a]
    // take :: Int -> String -> String
    const take = n => xs =>
        'GeneratorFunction' !== xs.constructor.constructor.name ? (
            xs.slice(0, n)
        ) : [].concat.apply([], Array.from({
            length: n
        }, () => {
            const x = xs.next();
            return x.done ? [] : [x.value];
        }));

    // uncurry :: (a -> b -> c) -> ((a, b) -> c)
    const uncurry = f =>
        (x, y) => f(x)(y);

    // unlines :: [String] -> String
    const unlines = xs => xs.join('\n');

    // until :: (a -> Bool) -> (a -> a) -> a -> a
    const until = p => f => x => {
        let v = x;
        while (!p(v)) v = f(v);
        return v;
    };

    // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    const zipWith = f => xs => ys =>
        xs.slice(
            0, Math.min(xs.length, ys.length)
        ).map((x, i) => f(x)(ys[i]));

    // SOURCE OUTLINE -----------------------------------------

    const strOutline = `NAME_HIERARCHY                  |WEIGHT  |COVERAGE  |
cleaning                        |        |          |
    house1                      |40      |          |
        bedrooms                |        |0.25      |
        bathrooms               |        |          |
            bathroom1           |        |0.5       |
            bathroom2           |        |          |
            outside_lavatory    |        |1         |
        attic                   |        |0.75      |
        kitchen                 |        |0.1       |
        living_rooms            |        |          |
            lounge              |        |          |
            dining_room         |        |          |
            conservatory        |        |          |
            playroom            |        |1         |
        basement                |        |          |
        garage                  |        |          |
        garden                  |        |0.8       |
    house2                      |60      |          |
        upstairs                |        |          |
            bedrooms            |        |          |
                suite_1         |        |          |
                suite_2         |        |          |
                bedroom_3       |        |          |
                bedroom_4       |        |          |
            bathroom            |        |          |
            toilet              |        |          |
            attics              |        |0.6       |
        groundfloor             |        |          |
            kitchen             |        |          |
            living_rooms        |        |          |
                lounge          |        |          |
                dining_room     |        |          |
                conservatory    |        |          |
                playroom        |        |          |
            wet_room_&_toilet   |        |          |
            garage              |        |          |
            garden              |        |0.9       |
            hot_tub_suite       |        |1         |
        basement                |        |          |
            cellars             |        |1         |
            wine_cellar         |        |1         |
            cinema              |        |0.75      |`;

    // MAIN ---
    return main();
})();


USING: accessors kernel math.statistics prettyprint sequences
sequences.deep source-files vocabs words ;

"resource:core/sequences/sequences.factor" "sequences"
[ path>source-file top-level-form>> ]
[ vocab-words [ def>> ] [ ] map-as ] bi* compose [ word? ]
deep-filter sorted-histogram <reversed> 7 head .


' noop is bootmessage

\ --- LIST OF CONSTANTS
\ WORD#		maximum word size
\ RING#		size of `Rings' element
\ DEFS		definitions
\ KEYS
\
\ --- LIST OF VARIABLES
\ cmpl?		is compiling?
\ cword		current compiled word

    wordlist constant DEFS
    wordlist constant KEYS

\ --- Compiling
50 constant WORD#
: >>fPAD	( ca u -- ; u < 51 )
	PAD 80 blank s" create " PAD swap MOVE
	s"  1 , DOES> 1 swap +! ;" PAD 57 + swap MOVE
	WORD# min PAD 7 + swap MOVE ;

: funcmpl	( ca u -- )
	>>fPAD current @ DEFS current !
	PAD 80 evaluate current ! ;

: >>kPAD	( ca u -- ; )
	PAD 80 blank s" : " PAD swap MOVE
	s"  parse-name funcmpl ;" PAD 59 + swap MOVE
	WORD# min PAD 2 + swap MOVE ;

: keycmpl	( ca u -- )
	 >>kPAD current @ KEYS current !
	PAD 80 evaluate current ! ;

\ --- Interpreter
: intp	BEGIN parse-name dup
	WHILE	( ca u )
		2dup KEYS search-wordlist
		IF   execute 2drop
		ELSE DEFS search-wordlist IF execute THEN
		THEN
	REPEAT 2drop ;

: run 	BEGIN refill WHILE intp REPEAT ;

\ --- Lists&Rings
warnings OFF
: LIST	( node -- )	]] BEGIN @ dup WHILE >R [[ ; immediate
warnings ON
: LOOP-LIST	( -- )	]] R> REPEAT drop [[ ; immediate

: empty-ring?	( node -- f )	dup @ = ;
: RING	( node -- )	]] dup BEGIN @ 2dup <> WHILE 2>R [[ ; immediate
: LOOP-RING	( -- )	]] 2R> REPEAT 2drop [[ ; immediate

: new-node	( -- node )
	here dup , ;
: do-link		( node new-node  -- ; do link after current node )
	over @ over ! swap ! ;

\ --- Sorting..
: nt>freq	( nt -- n ;frequency of uses )
	name>int >BODY @ ;

: @maxfreq	( wid -- n ;maximum frequency )
	0 swap cell+
	LIST	( max )
		I nt>freq 2dup <
		IF nip ELSE drop THEN
	LOOP-LIST ;

    2 cells constant RING#
: rings-vec	( u -- a size ; create vector of rings )
	here over 1+ 0
	DO new-node drop 0 , LOOP
	swap RING# * ;

: populate-by 	( a wid -- )
	cell+
	LIST
		dup  I nt>freq RING# *   +	\ root-node
		new-node I ,			\ new-node
		do-link
	LOOP-LIST drop ;

\ --- Display TOP
: node>nt	cell+ @ ;

: .ring		( root-node -- )
	0 swap
	RING
		dup 0= IF I node>nt nt>freq . THEN
		space I node>nt name>string type
		1+
	LOOP-RING drop cr ;

: .top	( a size n -- )
	-rot BOUNDS swap
	?DO	( n )
		I empty-ring?	0= IF 1- I .ring THEN
		dup 		0= IF drop UNLOOP EXIT THEN
	[ RING# negate ] LITERAL +LOOP drop ;

: args>top#	( -- n )
	1 arg 2dup 0 0 d<>
	IF	>float
		IF 	f>d d>s dup 0= IF drop 4 THEN
		ELSE 	4 THEN
	ELSE	2drop 4 THEN ;

\ --- KEYS behaviour
    variable  cmpl?	cmpl? OFF
    2variable cword
here WORD# allot 0 cword 2!

current @ KEYS current !
: create
	cmpl? @
	IF   cword [email protected]   keycmpl
	ELSE parse-name funcmpl THEN ;

: constant
	cmpl? @
	IF   cword [email protected]   keycmpl
	ELSE parse-name funcmpl THEN ;

: variable	parse-name funcmpl ;
: value		parse-name funcmpl ;
: defer		parse-name funcmpl ;

: (	BEGIN >in @ [char] ) parse nip >in @ rot - =
	WHILE refill 0= IF exit THEN REPEAT ;
: \	10 parse 2drop ;
: \G	10 parse 2drop ;
: S"	[char] " parse 2drop ;
: ."	[char] " parse 2drop ;

: [']
	parse-name DEFS search-wordlist IF execute THEN ;
: postpone
	parse-name DEFS search-wordlist IF execute THEN ;

: ; 	cmpl? OFF ;
: :	warnings OFF
	parse-name
	cword [email protected] drop WORD# rot  umin dup >R MOVE
	cword [email protected] drop R> cword 2!
	cword [email protected] cmpl? @
	IF	keycmpl		\ `:' inside def. = a defining word
	ELSE	funcmpl	THEN
	cmpl? ON
	warnings ON
;
current !

\ Run, ruuun!
stdin ' run execute-parsing-file  DEFS @maxfreq rings-vec  over DEFS populate-by  args>top# .top bye


package main

import (
    "fmt"
    "go/ast"
    "go/parser"
    "go/token"
    "io/ioutil"
    "os"
    "sort"
)

func main() {
    if len(os.Args) != 2 {
        fmt.Println("usage ff <go source filename>")
        return
    }
    src, err := ioutil.ReadFile(os.Args[1])
    if err != nil {
        fmt.Println(err)
        return
    }
    fs := token.NewFileSet()
    a, err := parser.ParseFile(fs, os.Args[1], src, 0)
    if err != nil {
        fmt.Println(err)
        return
    }
    f := fs.File(a.Pos())
    m := make(map[string]int)
    ast.Inspect(a, func(n ast.Node) bool {
        if ce, ok := n.(*ast.CallExpr); ok {
            start := f.Offset(ce.Pos())
            end := f.Offset(ce.Lparen)
            m[string(src[start:end])]++
        }
        return true
    })
    cs := make(calls, 0, len(m))
    for k, v := range m {
        cs = append(cs, &call{k, v})
    }
    sort.Sort(cs)
    for i, c := range cs {
        fmt.Printf("%-20s %4d\n", c.expr, c.count)
        if i == 9 {
            break
        }
    }
}

type call struct {
    expr  string
    count int
}
type calls []*call

func (c calls) Len() int           { return len(c) }
func (c calls) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }
func (c calls) Less(i, j int) bool { return c[i].count > c[j].count }


using CSV, DataFrames, Formatting

function updatecoverage(dfname, outputname)
    df = CSV.read(dfname)
    dchild = Dict{Int, Vector{Int}}([i => Int[] for i in 0:maximum(df[!, 1])])

    for row in eachrow(df)
        push!(dchild[row[3]], row[1])
    end

    function coverage(t)
        return dchild[t] == [] ? df[t, :COVERAGE] * df[t, :WEIGHT] :
            sum(coverage, dchild[t]) / sum(x -> df[x, :WEIGHT], dchild[t]) * df[t, :WEIGHT]
    end

    df[!, :COVERAGE] .= coverage.(df.NUMBER)

    function possibleincrease(t)
        if !isempty(dchild[t])
            return 0.0
        else
            newcoverage = deepcopy(df.COVERAGE)
            newcoverage[t] = 1.0
            oldcoverage = newcoverage[1]
            function potentialcoverage(t)
                return dchild[t] == [] ? newcoverage[t] * df[t, :WEIGHT] :
                    sum(potentialcoverage, dchild[t]) / sum(x -> df[x, :WEIGHT],
                        dchild[t]) * df[t, :WEIGHT]
            end

            newcoverage .= potentialcoverage.(df[!, 1])
            return newcoverage[1] - oldcoverage
        end
    end

    df.POTENTIAL = possibleincrease.(df[!, 1])

    CSV.write(outputname, df)
end

function displaycoveragedb(dfname)
    df = CSV.read(dfname)
    indentlevel(t) = (i = 0; while (j = df[t, 3]) != 0 i += 1; t = j end; i)
    indent1 = [indentlevel(i) for i in df.NUMBER]
    maxindent = maximum(indent1)
    indent2 = maxindent .- indent1
    showpot = size(df)[2] == 6
    println("INDEX       NAME_HIERARCHY                         WEIGHT      COVERAGE    (POTENTIAL INCREASE)")
    for (i, row) in enumerate(eachrow(df))
        println(rpad(row[1], 7), "       "^indent1[i], rpad(row[2], 20), "       "^indent2[i],
            rpad(row[4], 8), rpad(format(row[5]), 12), showpot && row[6] != 0 ? format(row[6]) : "")
    end
end

const dbname = "coverage.csv"
const newdbname = "coverageupdated.csv"

println("Input data:")
displaycoveragedb(dbname)
updatecoverage(dbname, newdbname)
println("\nUpdated data:")
displaycoveragedb(newdbname)


// version 1.2.10

class FCNode(val name: String, val weight: Int = 1, coverage: Double = 0.0) {

    var coverage = coverage
        set(value) {
            if (field != value) {
               field = value
               // update any parent's coverage
               if (parent != null) parent!!.updateCoverage()
            }
        }

    val children = mutableListOf<FCNode>()
    var parent: FCNode? = null

    fun addChildren(nodes: List<FCNode>) {
        children.addAll(nodes)
        nodes.forEach { it.parent = this }
        updateCoverage()
    }

    private fun updateCoverage() {
        val v1 = children.sumByDouble { it.weight * it.coverage }
        val v2 = children.sumBy { it.weight }
        coverage = v1 / v2
    }

    fun show(level: Int = 0) {
        val indent = level * 4
        val nl = name.length + indent
        print(name.padStart(nl))
        print("|".padStart(32 - nl))
        print("  %3d   |".format(weight))
        println(" %8.6f |".format(coverage))
        if (children.size == 0) return
        for (child in children) child.show(level + 1)
    }
}

val houses = listOf(
    FCNode("house1", 40),
    FCNode("house2", 60)
)

val house1 = listOf(
    FCNode("bedrooms", 1, 0.25),
    FCNode("bathrooms"),
    FCNode("attic", 1, 0.75),
    FCNode("kitchen", 1, 0.1),
    FCNode("living_rooms"),
    FCNode("basement"),
    FCNode("garage"),
    FCNode("garden", 1, 0.8)
)

val house2 = listOf(
    FCNode("upstairs"),
    FCNode("groundfloor"),
    FCNode("basement")
)

val h1Bathrooms = listOf(
    FCNode("bathroom1", 1, 0.5),
    FCNode("bathroom2"),
    FCNode("outside_lavatory", 1, 1.0)
)

val h1LivingRooms = listOf(
    FCNode("lounge"),
    FCNode("dining_room"),
    FCNode("conservatory"),
    FCNode("playroom", 1, 1.0)
)

val h2Upstairs = listOf(
    FCNode("bedrooms"),
    FCNode("bathroom"),
    FCNode("toilet"),
    FCNode("attics", 1, 0.6)
)

val h2Groundfloor = listOf(
    FCNode("kitchen"),
    FCNode("living_rooms"),
    FCNode("wet_room_&_toilet"),
    FCNode("garage"),
    FCNode("garden", 1, 0.9),
    FCNode("hot_tub_suite", 1, 1.0)
)

val h2Basement = listOf(
    FCNode("cellars", 1, 1.0),
    FCNode("wine_cellar", 1, 1.0),
    FCNode("cinema", 1, 0.75)
)

val h2UpstairsBedrooms = listOf(
    FCNode("suite_1"),
    FCNode("suite_2"),
    FCNode("bedroom_3"),
    FCNode("bedroom_4")
)

val h2GroundfloorLivingRooms = listOf(
    FCNode("lounge"),
    FCNode("dining_room"),
    FCNode("conservatory"),
    FCNode("playroom")
)

fun main(args: Array<String>) {
    val cleaning = FCNode("cleaning")

    house1[1].addChildren(h1Bathrooms)
    house1[4].addChildren(h1LivingRooms)
    houses[0].addChildren(house1)

    h2Upstairs[0].addChildren(h2UpstairsBedrooms)
    house2[0].addChildren(h2Upstairs)
    h2Groundfloor[1].addChildren(h2GroundfloorLivingRooms)
    house2[1].addChildren(h2Groundfloor)
    house2[2].addChildren(h2Basement)
    houses[1].addChildren(house2)

    cleaning.addChildren(houses)
    val topCoverage = cleaning.coverage
    println("TOP COVERAGE = ${"%8.6f".format(topCoverage)}\n")
    println("NAME HIERARCHY                 | WEIGHT | COVERAGE |")
    cleaning.show()

    h2Basement[2].coverage = 1.0  // change Cinema node coverage to 1.0
    val diff = cleaning.coverage - topCoverage
    println("\nIf the coverage of the Cinema node were increased from 0.75 to 1.0")
    print("the top level coverage would increase by ")
    println("${"%8.6f".format(diff)} to ${"%8.6f".format(topCoverage + diff)}")
    h2Basement[2].coverage = 0.75  // restore to original value if required
}


import Language.Haskell.Parser (parseModule)
import Data.List.Split (splitOn)
import Data.List (nub, sortOn, elemIndices)

findApps src = freq $ concat [apps, comps]
  where
    ast = show $ parseModule src
    apps = extract <$> splitApp ast
    comps = extract <$> concat (splitComp <$> splitInfix ast)
    splitApp = tail . splitOn "(HsApp (HsVar (UnQual (HsIdent \""
    splitInfix = tail . splitOn "(HsInfixApp (HsVar (UnQual (HsIdent \""
    splitComp = take 1 . splitOn "(HsQVarOp (UnQual (HsSymbol \""
    extract = takeWhile (/= '\"')
    freq lst = [ (count x lst, x) | x <- nub lst ]
    count x = length . elemIndices x

main = do
  src <- readFile "CountFunctions.hs"
  let res = sortOn (negate . fst) $ findApps src
  mapM_ (\(n, f) -> putStrLn $ show n ++ "\t" ++ f) res


   IGNORE=: ;:'y(0)1',CR

   Filter=: (#~`)(`:6)

   NB. extract tokens from a large body newline terminated of text
   roughparse=: ;@(<@;: ::(''"_);._2)

   NB. count frequencies and get the top x
   top=: top=: {. \:[email protected]:((#;{.)/.~)

   NB. read all installed script (.ijs) files and concatenate them
   JSOURCE=: ;fread each 1&[email protected]('.ijs'&E.)@>Filter {."1 dirtree jpath '~install'

   10 top (roughparse JSOURCE)-.IGNORE
┌─────┬──┐
│49591│, │
├─────┼──┤
│40473│=:│
├─────┼──┤
│35593│; │
├─────┼──┤
│34096│=.│
├─────┼──┤
│24757│+ │
├─────┼──┤
│18726│" │
├─────┼──┤
│18564│< │
├─────┼──┤
│18446│/ │
├─────┼──┤
│16984│> │
├─────┼──┤
│14655│@ │
└─────┴──┘


using Printf, DataStructures

function funcfreqs(expr::Expr)
    cnt = counter(Symbol)
    expr.head == :call &&
        push!(cnt, expr.args[1])
    for e in expr.args
        e isa Expr && merge!(cnt, funcfreqs(e))
    end
    return cnt
end

function parseall(str::AbstractString)
    exs = Any[]
    pos = start(str)
    while !done(str, pos)
        ex, pos = parse(str, pos) # returns next starting point as well as expr
        ex.head == :toplevel ? append!(exs, ex.args) : push!(exs, ex)
    end
    if isempty(exs)
        throw(ParseError("end of input"))
    elseif length(exs) == 1
        return exs[1]
    else
        return Expr(:block, exs...)
    end
end

freqs = readstring("src/Function_frequency.jl") |> parseall |> funcfreqs

for (v, f) in freqs
    @printf("%10s → %i\n", v, f)
end


-- DATA:
local function node(name, weight, coverage, children)
  return { name=name, weight=weight or 1.0, coverage=coverage or 0.0, sumofweights=0, delta=0, children=children }
end

local root =
node("cleaning", nil, nil, {
  node("house1", 40, nil, {
    node("bedrooms", nil, 0.25),
    node("bathrooms", nil, nil, {
      node("bathroom1", nil, 0.5),
      node("bathroom2"),
      node("outside_lavatory", nil, 1)
    }),
    node("attic", nil, 0.75),
    node("kitchen", nil, 0.1),
    node("living_rooms", nil, nil, {
      node("lounge"),
      node("dining_room"),
      node("conservatory"),
      node("playroom",nil,1)
    }),
    node("basement"),
    node("garage"),
    node("garden", nil, 0.8)
  }),
  node("house2", 60, nil, {
    node("upstairs", nil, nil, {
      node("bedrooms", nil, nil, {
        node("suite_1"),
        node("suite_2"),
        node("bedroom_3"),
        node("bedroom_4")
      }),
      node("bathroom"),
      node("toilet"),
      node("attics", nil, 0.6)
    }),
    node("groundfloor", nil, nil, {
      node("kitchen"),
      node("living_rooms", nil, nil, {
        node("lounge"),
        node("dining_room"),
        node("conservatory"),
        node("playroom")
      }),
      node("wet_room_&_toilet"),
      node("garage"),
      node("garden", nil, 0.9),
      node("hot_tub_suite", nil, 1)
    }),
    node("basement", nil, nil, {
      node("cellars", nil, 1),
      node("wine_cellar", nil, 1),
      node("cinema", nil, 0.75)
    })
  })
})

-- TASK:
local function calccover(node)
  if (node.children) then
    local cnt, sum = 0, 0
    for _,child in ipairs(node.children) do
      local ccnt, csum = calccover(child)
      cnt, sum = cnt+ccnt, sum+csum
    end
    node.coverage = sum/cnt
    node.sumofweights = cnt -- just as prep for extra credit
  end
  return node.weight, node.coverage * node.weight
end
calccover(root)

-- EXTRA CREDIT:
local function calcdelta(node, power)
  node.delta = (1.0 - node.coverage) * power
  if (node.children) then
    for _,child in ipairs(node.children) do
      calcdelta(child, power * child.weight / node.sumofweights)
    end
  end
end
calcdelta(root,1)

-- OUTPUT:
local function printnode(node, space)
  print(string.format("%-32s|  %3.f   | %8.6f | %8.6f |", string.rep(" ",space)..node.name, node.weight, node.coverage, node.delta))
  if node.children then
    for _,child in ipairs(node.children) do printnode(child,space+4) end
  end
end
print("NAME_HIERARCHY                  |WEIGHT  |COVERAGE  |DELTA     |")
printnode(root,0)


function handlerNames pScript
    put pScript into pScriptCopy
    filter pScript with regex pattern "^(on|function).*"
    -- add in the built-in commands & functions
    put the commandNames & the functionnames into cmdfunc
    repeat for each line builtin in cmdfunc
        put 0 into handlers[builtin]
    end repeat

    -- add user defined handlers, remove this section of you do not want your own functions included
    repeat with x = 1 to the number of lines of pScript
        put word 2 of line x of pScript into handlername
        put 0 into handlers[handlername]
    end repeat

    -- count handlers used
    repeat with x = 1 to the number of lines of pScriptCopy
        repeat for each key k in handlers
            if k is among the tokens of line x of pScriptCopy then
                add 1 to handlers[k]
            end if
        end repeat
    end repeat

    combine handlers using cr and space
    sort lines of handlers descending by word 2 of each
    put line 1 to 10 of handlers into handlers
    return handlers
end handlerNames


programCount[fn_] :=  Reverse[If[Length[#] > 10, Take[#, -10], #] &[SortBy[Tally[Cases[DownValues[fn], s_Symbol, \[Infinity], Heads -> True]], Last]]]


# naive function calling counter
# TODO consider a more sophisticated condition on counting function callings
# without parenthesis which are common in nim lang. Be aware that the AST of
# object accessor and procedure calling without parenthesis are same.

import macros, tables, strformat, os
proc visitCall(node: NimNode, table: CountTableRef) =
  if node.kind == nnkCall:
    if node[0].kind == nnkDotExpr:
      table.inc($node[0][1])
      visitCall(node[0][0], table)
    else:
      if node[0].kind == nnkBracketExpr:
        if node[0][0].kind == nnkDotExpr:
          table.inc($node[0][0][1])
          visitCall(node[0][0][0], table)
          return
        else:
          table.inc($node[0][0])
          if len(node[0]) > 1:
            for child in node[0][1..^1]:
              visitCall(child, table)
      elif node[0].kind == nnkPar:
        visitCall(node[0], table)
      else:
        table.inc($node[0])
      if len(node) > 1:
        for child in node[1..^1]:
          visitCall(child, table)
  else:
    for child in node.children():
      visitCall(child, table)

static:
  const code = staticRead(expandTilde(&"~/.choosenim/toolchains/nim-{NimVersion}/lib/system.nim"))
  var
    ast = parseStmt(code)
    callCounts = newCountTable[string]()
  ast.visitCall(callCounts)
  sort(callCounts)
  var total = 10
  for ident, times in callCounts.pairs():
    echo(&"{ident} called {times} times")
    total-=1
    if total == 0:
      break


use PPI::Tokenizer;
my $Tokenizer = PPI::Tokenizer->new( '/path/to/your/script.pl' );
my %counts;
while (my $token = $Tokenizer->get_token) {
    # We consider all Perl identifiers. The following regex is close enough.
    if ($token =~ /\A[\$\@\%*[:alpha:]]/) {
        $counts{$token}++;
    }
}
my @desc_by_occurrence =
    sort {$counts{$b} <=> $counts{$a} || $a cmp $b}
         keys(%counts);
my @top_ten_by_occurrence = @desc_by_occurrence[0 .. 9];
foreach my $token (@top_ten_by_occurrence) {
    print $counts{$token}, "\t", $token, "\n";
}


    else -- rType=FUNC|TYPE
        log_function_call(rtnNo)


import strformat, strutils

type

  FCNode = ref object
    name: string
    weight: int
    coverage: float
    children: seq[FCNode]
    parent: FCNode

func newFCNode(name: string; weight: int; coverage: float): FCNode =
  FCNode(name: name, weight: weight, coverage: coverage)

# Forward reference.
func updateCoverage(n: FCNode)

func addChildren(n: FCNode; nodes: openArray[FCNode]) =
  for node in nodes:
    node.parent = n
  n.children = @nodes
  n.updateCoverage()

func setCoverage(n: FCNode; value: float) =
  if n.coverage != value:
    n.coverage = value
    # Update any parent's coverage.
    if not n.parent.isNil:
      n.parent.updateCoverage()

func updateCoverage(n: FCNode) =
  var v1 = 0.0
  var v2 = 0
  for node in n.children:
    v1 += node.weight.toFloat * node.coverage
    v2 += node.weight
  n.setCoverage(v1 / v2.toFloat)

proc show(n: FCNode; level: int) =
  let indent = level * 4
  let nl = n.name.len + indent
  const Sep = "|"
  echo &"{n.name.align(nl)}{Sep.align(32-nl)}  {n.weight:>3d}   | {n.coverage:8.6f} |"
  for child in n.children:
    child.show(level + 1)

#———————————————————————————————————————————————————————————————————————————————————————————————————

let houses = [newFCNode("house1", 40, 0), newFCNode("house2", 60, 0)]

let house1 = [
    newFCNode("bedrooms", 1, 0.25),
    newFCNode("bathrooms", 1, 0),
    newFCNode("attic", 1, 0.75),
    newFCNode("kitchen", 1, 0.1),
    newFCNode("living_rooms", 1, 0),
    newFCNode("basement", 1, 0),
    newFCNode("garage", 1, 0),
    newFCNode("garden", 1, 0.8)]

let house2 = [
    newFCNode("upstairs", 1, 0),
    newFCNode("groundfloor", 1, 0),
    newFCNode("basement", 1, 0)]

let h1Bathrooms = [
    newFCNode("bathroom1", 1, 0.5),
    newFCNode("bathroom2", 1, 0),
    newFCNode("outside_lavatory", 1, 1)]

let h1LivingRooms = [
    newFCNode("lounge", 1, 0),
    newFCNode("dining_room", 1, 0),
    newFCNode("conservatory", 1, 0),
    newFCNode("playroom", 1, 1)]

let h2Upstairs = [
    newFCNode("bedrooms", 1, 0),
    newFCNode("bathroom", 1, 0),
    newFCNode("toilet", 1, 0),
    newFCNode("attics", 1, 0.6)]

let h2Groundfloor = [
    newFCNode("kitchen", 1, 0),
    newFCNode("living_rooms", 1, 0),
    newFCNode("wet_room_&_toilet", 1, 0),
    newFCNode("garage", 1, 0),
    newFCNode("garden", 1, 0.9),
    newFCNode("hot_tub_suite", 1, 1)]

let h2Basement = [
    newFCNode("cellars", 1, 1),
    newFCNode("wine_cellar", 1, 1),
    newFCNode("cinema", 1, 0.75)]

let h2UpstairsBedrooms = [
    newFCNode("suite_1", 1, 0),
    newFCNode("suite_2", 1, 0),
    newFCNode("bedroom_3", 1, 0),
    newFCNode("bedroom_4", 1, 0)]

let h2GroundfloorLivingRooms = [
    newFCNode("lounge", 1, 0),
    newFCNode("dining_room", 1, 0),
    newFCNode("conservatory", 1, 0),
    newFCNode("playroom", 1, 0)]

let cleaning = newFCNode("cleaning", 1, 0)

house1[1].addChildren(h1Bathrooms)
house1[4].addChildren(h1LivingRooms)
houses[0].addChildren(house1)

h2Upstairs[0].addChildren(h2UpstairsBedrooms)
house2[0].addChildren(h2Upstairs)
h2Groundfloor[1].addChildren(h2GroundfloorLivingRooms)
house2[1].addChildren(h2Groundfloor)
house2[2].addChildren(h2Basement)
houses[1].addChildren(house2)

cleaning.addChildren(houses)
let topCoverage = cleaning.coverage
echo &"TOP COVERAGE = {topCoverage:8.6f}\n"
echo "NAME HIERARCHY                 | WEIGHT | COVERAGE |"
cleaning.show(0)

h2Basement[2].setCoverage(1)  # Change Cinema node coverage to 1.
let diff = cleaning.coverage - topCoverage
echo "\nIf the coverage of the Cinema node were increased from 0.75 to 1"
echo &"the top level coverage would increase by {diff:8.6f} to {topCoverage + diff:8.6f}"
h2Basement[2].setCoverage(0.75)   # Restore to original value if required.


use strict;
use warnings;

sub walktree {
    my @parts;
    while( $_[0] =~ /(?<head> (\s*)   \N+\n  )         # split off one level as 'head' (or terminal 'leaf')
                     (?<body> (?:\2 \s\N+\n)*)/gx ) {  # next sub-level is 'body' (defined by extra depth of indentation)

        my($head, $body) = ($+{head}, $+{body});
        $head =~ /^.*?      \|      # ignore name
                  (\S*) \s* \|      # save weight
                  (\S*)       /x;   # save coverage
        my $weight   = sprintf '%-8s',  $1 || 1;
        my $coverage = sprintf '%-10s', $2 || 0;
        my($w, $wsum) = (0, 0);

        $head .= $_->[0],
        $w    += $_->[1],
        $wsum += $_->[1] * $_->[2]
              for walktree( $body );

        $coverage = sprintf '%-10.2g', $wsum/$w unless $w == 0;
        push @parts, [ $head =~ s/\|.*/|$weight|$coverage|/r, $weight, $coverage ];
    }
    return @parts;
}

print $_->[0] for walktree( join '', <DATA> );

__DATA__
NAME_HIERARCHY                  |WEIGHT  |COVERAGE  |
cleaning                        |        |          |
    house1                      |40      |          |
        bedrooms                |        |0.25      |
        bathrooms               |        |          |
            bathroom1           |        |0.5       |
            bathroom2           |        |          |
            outside_lavatory    |        |1         |
        attic                   |        |0.75      |
        kitchen                 |        |0.1       |
        living_rooms            |        |          |
            lounge              |        |          |
            dining_room         |        |          |
            conservatory        |        |          |
            playroom            |        |1         |
        basement                |        |          |
        garage                  |        |          |
        garden                  |        |0.8       |
    house2                      |60      |          |
        upstairs                |        |          |
            bedrooms            |        |          |
                suite_1         |        |          |
                suite_2         |        |          |
                bedroom_3       |        |          |
                bedroom_4       |        |          |
            bathroom            |        |          |
            toilet              |        |          |
            attics              |        |0.6       |
        groundfloor             |        |          |
            kitchen             |        |          |
            living_rooms        |        |          |
                lounge          |        |          |
                dining_room     |        |          |
                conservatory    |        |          |
                playroom        |        |          |
            wet_room_&_toilet   |        |          |
            garage              |        |          |
            garden              |        |0.9       |
            hot_tub_suite       |        |1         |
        basement                |        |          |
            cellars             |        |1         |
            wine_cellar         |        |1         |
            cinema              |        |0.75      |


(let Freq NIL
   (for "L" (filter pair (extract getd (all)))
      (for "F"
         (filter atom
            (fish '((X) (or (circ? X) (getd X)))
               "L" ) )
         (accu 'Freq "F" 1) ) )
   (for X (head 10 (flip (by cdr sort Freq)))
      (tab (-7 4) (car X) (cdr X)) ) )


import ast

class CallCountingVisitor(ast.NodeVisitor):

    def __init__(self):
        self.calls = {}

    def visit_Call(self, node):
        if isinstance(node.func, ast.Name):
            fun_name = node.func.id
            call_count = self.calls.get(fun_name, 0)
            self.calls[fun_name] = call_count + 1
        self.generic_visit(node)

filename = input('Enter a filename to parse: ')
with open(filename, encoding='utf-8') as f:
    contents = f.read()
root = ast.parse(contents, filename=filename) #NOTE: this will throw a SyntaxError if the file isn't valid Python code
visitor = CallCountingVisitor()
visitor.visit(root)
top10 = sorted(visitor.calls.items(), key=lambda x: x[1], reverse=True)[:10]
for name, count in top10:
    print(name,'called',count,'times')


#lang racket
(require math)
(define in (open-input-file "function-frequency.rkt"))
(void (read-language in))
(define s-exprs (for/list ([s (in-port read in)]) s))
(define symbols (filter symbol? (flatten s-exprs)))
(define counts  (sort (hash->list (samples->hash symbols)) >= #:key cdr))
(take counts (min 10 (length counts)))


my $text = qqx[raku --target=ast @*ARGS[]];
my %fun;
for $text.lines {
    %fun{$0}++ if / '(call &' (.*?) ')' /
}

for %fun.invert.sort.reverse[^10] { .value.say }


--
-- demo\rosetta\Functional_coverage_tree.exw
-- =========================================
--
with javascript_semantics
constant data = """
NAME_HIERARCHY                  | WEIGHT | COVERAGE |
cleaning                        |        |          |
    house1                      |40      |          |
        bedrooms                |        |0.25      |
        bathrooms               |        |          |
            bathroom1           |        |0.5       |
            bathroom2           |        |          |
            outside_lavatory    |        |1         |
        attic                   |        |0.75      |
        kitchen                 |        |0.1       |
        living_rooms            |        |          |
            lounge              |        |          |
            dining_room         |        |          |
            conservatory        |        |          |
            playroom            |        |1         |
        basement                |        |          |
        garage                  |        |          |
        garden                  |        |0.8       |
    house2                      |60      |          |
        upstairs                |        |          |
            bedrooms            |        |          |
                suite_1         |        |          |
                suite_2         |        |          |
                bedroom_3       |        |          |
                bedroom_4       |        |          |
            bathroom            |        |          |
            toilet              |        |          |
            attics              |        |0.6       |
        groundfloor             |        |          |
            kitchen             |        |          |
            living_rooms        |        |          |
                lounge          |        |          |
                dining_room     |        |          |
                conservatory    |        |          |
                playroom        |        |          |
            wet_room_&_toilet   |        |          |
            garage              |        |          |
            garden              |        |0.9       |
            hot_tub_suite       |        |1         |
        basement                |        |          |
            cellars             |        |1         |
            wine_cellar         |        |1         |
            cinema              |        |0.75      |
"""
sequence lines = split(data,"\n"),
         pi = {},   -- indents (to locate parents)
         pdx = {},  -- indexes for ""
         children
string desc, weights, covers
integer parent, child
atom weight, coverage, childw = 0
enum DESC, WEIGHT, COVERAGE, PARENT, CHILDREN, CHILDW
lines[1] &= " SHARE OF RESIDUE"
for i=2 to length(lines) do
    -- decode text to useable data, link up parents & children
    {desc,weights,covers} = split(lines[i],"|")
    -- (nb this assumes /totally/ consistent indenting)
    integer indent = length(desc)-length(trim_head(desc)),
            k = find(indent,pi)
    if k=0 then
        pi = append(pi,indent)
        pdx = append(pdx,0)
        k = length(pi)
    end if
    pdx[k] = i
    parent = 0
    if k>1 then
        parent = pdx[k-1]
--      lines[parent][CHILDREN] &= i
        lines[parent][CHILDREN] = deep_copy(lines[parent][CHILDREN]) & i
    end if
    children = {}
    weight = to_number(trim(weights),1)
    coverage = to_number(trim(covers),0)
    lines[i] = {desc, weight, coverage, parent, children, childw}
end for
for i=length(lines) to 2 by -1 do
    -- calculate the parent coverages, and save child weight sums
    children = lines[i][CHILDREN]
    if length(children) then
        coverage = 0
        childw = 0
        for c=1 to length(children) do
            child = children[c]
            atom w = lines[child][WEIGHT]
            coverage += lines[child][COVERAGE]*w
            childw += w
        end for
        lines[i][COVERAGE] = coverage/childw
        lines[i][CHILDW] = childw -- (save for next loop)
    end if
end for
for i=length(lines) to 2 by -1 do
    -- calculate the share of residue, and format lines
    child = i
    {desc, weight, coverage, parent} = lines[i]
    atom residue = 1-coverage
    while parent do
        residue *= lines[child][WEIGHT]/lines[parent][CHILDW]
        {child, parent} = {parent, lines[parent][PARENT]}
    end while
    lines[i] = sprintf("%-32s| %6d | %-8g | %g",{desc,weight,coverage,residue})
end for
puts(1,join(lines,"\n")&"\n")
{} = wait_key()


fid='pgm.rex'
cnt.=0
funl=''
Do While lines(fid)>0
  l=linein(fid)
  Do Until p=0
    p=pos('(',l)
    If p>0 Then Do
      do i=p-1 To 1 By -1 While is_tc(substr(l,i,1))
        End
      fn=substr(l,i+1,p-i-1)
      If fn<>'' Then
        Call store fn
      l=substr(l,p+1)
      End
    End
  End
Do While funl<>''
  Parse Var funl fn funl
  Say right(cnt.fn,3) fn
  End
Exit
x=a(3)+bbbbb(5,c(555))
special=date('S') 'DATE'() "date"()
is_tc:
abc='abcdefghijklmnopqrstuvwxyz'
Return pos(arg(1),abc||translate(abc)'1234567890_''"')>0

store:
Parse Arg fun
cnt.fun=cnt.fun+1
If cnt.fun=1 Then
  funl=funl fun
Return


func foo { }
func bar { }

foo(); foo(); foo()
bar(); bar();

var data = Perl.to_sidef(Parser{:vars}{:main}).flatten

data.sort_by { |v| -v{:count} }.first(10).each { |entry|
    if (entry{:type} == :func) {
        say ("Function `#{entry{:name}}` (declared at line",
             " #{entry{:line}}) is used #{entry{:count}} times")
    }
}


bagOfCalls := Bag new.
Smalltalk allClassesDo:[:cls |
    cls instAndClassMethodsDo:[:mthd |
        bagOfCalls addAll:mthd messagesSent
    ].
].
(bagOfCalls sortedCounts to:10) do:[:assoc |
    Stdout printCR: e'method {assoc value} is called {assoc key} times.'
].


from itertools import zip_longest

fc2 = '''\
cleaning,,
    house1,40,
        bedrooms,,.25
        bathrooms,,
            bathroom1,,.5
            bathroom2,,
            outside_lavatory,,1
        attic,,.75
        kitchen,,.1
        living_rooms,,
            lounge,,
            dining_room,,
            conservatory,,
            playroom,,1
        basement,,
        garage,,
        garden,,.8
    house2,60,
        upstairs,,
            bedrooms,,
                suite_1,,
                suite_2,,
                bedroom_3,,
                bedroom_4,,
            bathroom,,
            toilet,,
            attics,,.6
        groundfloor,,
            kitchen,,
            living_rooms,,
                lounge,,
                dining_room,,
                conservatory,,
                playroom,,
            wet_room_&_toilet,,
            garage,,
            garden,,.9
            hot_tub_suite,,1
        basement,,
            cellars,,1
            wine_cellar,,1
            cinema,,.75

'''

NAME, WT, COV = 0, 1, 2

def right_type(txt):
    try:
        return float(txt)
    except ValueError:
        return txt

def commas_to_list(the_list, lines, start_indent=0):
    '''
    Output format is a nest of lists and tuples
    lists are for coverage leaves without children items in the list are name, weight, coverage
    tuples are 2-tuples for nodes with children. The first element is a list representing the
    name, weight, coverage of the node (some to be calculated); the second element is a list of
    child elements which may be 2-tuples or lists as above.

    the_list is modified in-place
    lines must be a generator of successive lines of input like fc2
    '''
    for n, line in lines:
        indent = 0
        while line.startswith(' ' * (4 * indent)):
            indent += 1
        indent -= 1
        fields = [right_type(f) for f in line.strip().split(',')]
        if indent == start_indent:
            the_list.append(fields)
        elif indent > start_indent:
            lst = [fields]
            sub = commas_to_list(lst, lines, indent)
            the_list[-1] = (the_list[-1], lst)
            if sub not in (None, ['']) :
                the_list.append(sub)
        else:
            return fields if fields else None
    return None

def pptreefields(lst, indent=0, widths=['%-32s', '%-8g', '%-10g']):
    '''
    Pretty prints the format described from function commas_to_list as a table with
    names in the first column suitably indented and all columns having a fixed
    minimum column width.
    '''
    lhs = ' ' * (4 * indent)
    for item in lst:
        if type(item) != tuple:
            name, *rest = item
            print(widths[0] % (lhs + name), end='|')
            for width, item in zip_longest(widths[1:len(rest)], rest, fillvalue=widths[-1]):
                if type(item) == str:
                    width = width[:-1] + 's'
                print(width % item, end='|')
            print()
        else:
            item, children = item
            name, *rest = item
            print(widths[0] % (lhs + name), end='|')
            for width, item in zip_longest(widths[1:len(rest)], rest, fillvalue=widths[-1]):
                if type(item) == str:
                    width = width[:-1] + 's'
                print(width % item, end='|')
            print()
            pptreefields(children, indent+1)

def default_field(node_list):
    node_list[WT] = node_list[WT] if node_list[WT] else 1.0
    node_list[COV] = node_list[COV] if node_list[COV] else 0.0

def depth_first(tree, visitor=default_field):
    for item in tree:
        if type(item) == tuple:
            item, children = item
            depth_first(children, visitor)
        visitor(item)

def covercalc(tree):
    '''
    Depth first weighted average of coverage
    '''
    sum_covwt, sum_wt = 0, 0
    for item in tree:
        if type(item) == tuple:
            item, children = item
            item[COV] = covercalc(children)
        sum_wt  += item[WT]
        sum_covwt += item[COV] * item[WT]
    cov = sum_covwt / sum_wt
    return cov

if __name__ == '__main__':
    lstc = []
    commas_to_list(lstc, ((n, ln) for n, ln in enumerate(fc2.split('\n'))))
    #pp(lstc, width=1, indent=4, compact=1)

    #print('\n\nEXPANDED DEFAULTS\n')
    depth_first(lstc)
    #pptreefields(['NAME_HIERARCHY WEIGHT COVERAGE'.split()] + lstc)

    print('\n\nTOP COVERAGE = %f\n' % covercalc(lstc))
    depth_first(lstc)
    pptreefields(['NAME_HIERARCHY WEIGHT COVERAGE'.split()] + lstc)


package require Tcl 8.6

proc examine {filename} {
    global cmds
    set RE "(?:^|\[\[\{\])\[\\w:.\]+"
    set f [open $filename]
    while {[gets $f line] >= 0} {
	set line [string trim $line]
	if {$line eq "" || [string match "#*" $line]} {
	    continue
	}
	foreach cmd [regexp -all -inline $RE $line] {
	    incr cmds([string trim $cmd "\{\["])
	}
    }
    close $f
}

# Parse each file on the command line
foreach filename $argv {
    examine $filename
}
# Get the command list in order of frequency
set cmdinfo [lsort -stride 2 -index 1 -integer -decreasing [array get cmds]]
# Print the top 10 (two list items per entry, so 0-19, not 0-9)
foreach {cmd count} [lrange $cmdinfo 0 19] {
    puts [format "%-20s%d" $cmd $count]
}


import "io" for File
import "os" for Process
import "/pattern" for Pattern
import "/set" for Bag
import "/sort" for Sort
import "/fmt" for Fmt

var args = Process.arguments
if (args.count != 1) {
    Fiber.abort("There should be exactly one argument - the file path to be analyzed")
}
var p = Pattern.new("[+1/x.+1/x](")
var source = File.read(args[0])
var matches = p.findAll(source)
var bag = Bag.new(matches.map { |m| m.captures[0].text })
var methodCalls = bag.toMap.toList
var cmp = Fn.new { |i, j| (j.value - i.value).sign }
Sort.quick(methodCalls, 0, methodCalls.count-1, cmp)
System.print("Top ten method/function calls in %(args[0]):\n")
System.print("Called  Method/Function")
System.print("------  ----------------")
for (mc in methodCalls.take(10)) {
    Fmt.print(" $2d     $s", mc.value, mc.key)
}


#lang racket/base
(require racket/list racket/string racket/match racket/format racket/file)

(struct Coverage (name weight coverage weighted-coverage children) #:transparent #:mutable)

;; -| read/parse |------------------------------------------------------------------------------------
(define (build-hierarchies parsed-lines)
  (define inr
    (match-lambda
      ['() (values null null)]
      [`((,head-indent . ,C) ,tail-lines ...)
       (define child? (match-lambda [(cons i _) #:when (> i head-indent) #t] [_ #f]))
       (define-values (chlds rels) (splitf-at tail-lines child?))
       (define-values (rels-tree rels-rem) (inr rels))
       (values (cons (struct-copy Coverage C (children (build-hierarchies chlds))) rels-tree)
               rels-rem)]))
  (define-values (hierarchies remaining-lines) (inr parsed-lines))
  hierarchies)

(define report-line->indent.c/e-line
  (match-lambda
    [(regexp #px"^( *)([^ ]*) *\\| *([^ ]*) *\\| *([^ ]*) *\\|$"
             (list _
                   (app string-length indent-length)
                   name
                   (or (and (not "") (app string->number wght)) (app (λ (x) 1) wght))
                   (or (and (not "") (app string->number cvrg)) (app (λ (x) 0) cvrg))))
     (cons indent-length (Coverage name wght cvrg 0 #f))]))

(define (report->indent.c/e-list rprt)
  (map report-line->indent.c/e-line (drop (string-split rprt "\n") 1)))

;; -| evaluate |--------------------------------------------------------------------------------------
(define find-wght-cvrg
  (match-lambda
    [(and e (Coverage _ w c _ '())) (struct-copy Coverage e (weighted-coverage (* w c)))]
    [(and e (Coverage _ _ _ _ `(,(app find-wght-cvrg (and cdn+ (Coverage _ c-ws _ c-w/cs _))) ...)))
     (define chld-wghtd-avg (for/sum ((w (in-list c-ws)) (w/c (in-list c-w/cs))) (* w w/c)))
     (struct-copy Coverage e (weighted-coverage (/ chld-wghtd-avg (apply + c-ws))) (children cdn+))]))

;; -| printing |--------------------------------------------------------------------------------------
(define max-description-length
  (match-lambda
    [(Coverage (app string-length name-length) _ _ _
               (list (app max-description-length children-lengths) ...))
     (apply max name-length (map add1 children-lengths))]))

(define (~a/right w x)
  (~a x #:width w #:align 'right))

(define (~a/decimal n dec-dgts)
  (~a/right (+ dec-dgts 3) (if (zero? n) "" (real->decimal-string n dec-dgts))))

(define (print-coverage-tree tree)
  (define mdl (max-description-length tree))
  (printf "| ~a |WEIGT| COVER |WGHTD CVRG|~%" (~a "NAME" #:width mdl #:align 'center))
  (let inr ((depth 0) (tree tree))
    (unless (null? tree)
      (match tree
        [(Coverage name w c w/c chlds)
         (printf "| ~a | ~a | ~a | ~a |~%"
                 (~a (string-append (make-string depth #\space) name) #:width mdl)
                 (~a/right 3 w) (~a/decimal c 2) (~a/decimal w/c 5))
         (for ((c chlds)) (inr (add1 depth) c))]))))

;; ---------------------------------------------------------------------------------------------------
(module+ main
;; data/functional-coverage.txt contains a verbatim copy of
;; the table in the task's description
(for-each
 (compose print-coverage-tree find-wght-cvrg)
 (build-hierarchies (report->indent.c/e-list (file->string "data/functional-coverage.txt")))))


sub walktree ($data) {
    my (@parts, $cnt);

    while ($data ~~ m:nth(++$cnt)/$<head>=[(\s*)    \N+\n  ]      # split off one level as 'head' (or terminal 'leaf')
                                  $<body>=[[$0  \s+ \N+\n]*]/ ) { # next sub-level is 'body' (defined by extra depth of indentation)

        my ($head, $body) = ($<head>, $<body>);
        $head ~~ /'|' $<weight>=[\S*] \s* '|' $<coverage>=[\S*]/; # save values of weight and coverage (if any) for later

        my ($w, $wsum) = (0, 0);
        $head ~= .[0],
        $w    += .[1],
        $wsum += .[1] * .[2]
            for walktree $body;

        my $weight   = (~$<weight>   or 1).fmt('%-8s');
        my $coverage = $w == 0
                    ?? (~$<coverage> or 0).fmt('%-10s')
                    !! ($wsum/$w)         .fmt('%-10.2g');
        @parts.push: [$head.subst(/'|' \N+/, "|$weight|$coverage|"), $weight, $coverage ];
    }
    return @parts;
}

(say .[0] for walktree $_) given

    q:to/END/
    NAME_HIERARCHY                  |WEIGHT  |COVERAGE  |
    cleaning                        |        |          |
        house1                      |40      |          |
            bedrooms                |        |0.25      |
            bathrooms               |        |          |
                bathroom1           |        |0.5       |
                bathroom2           |        |          |
                outside_lavatory    |        |1         |
            attic                   |        |0.75      |
            kitchen                 |        |0.1       |
            living_rooms            |        |          |
                lounge              |        |          |
                dining_room         |        |          |
                conservatory        |        |          |
                playroom            |        |1         |
            basement                |        |          |
            garage                  |        |          |
            garden                  |        |0.8       |
        house2                      |60      |          |
            upstairs                |        |          |
                bedrooms            |        |          |
                    suite_1         |        |          |
                    suite_2         |        |          |
                    bedroom_3       |        |          |
                    bedroom_4       |        |          |
                bathroom            |        |          |
                toilet              |        |          |
                attics              |        |0.6       |
            groundfloor             |        |          |
                kitchen             |        |          |
                living_rooms        |        |          |
                    lounge          |        |          |
                    dining_room     |        |          |
                    conservatory    |        |          |
                    playroom        |        |          |
                wet_room_&_toilet   |        |          |
                garage              |        |          |
                garden              |        |0.9       |
                hot_tub_suite       |        |1         |
            basement                |        |          |
                cellars             |        |1         |
                wine_cellar         |        |1         |
                cinema              |        |0.75      |
    END


import Foundation

extension String {
  func paddedLeft(totalLen: Int) -> String {
    let needed = totalLen - count

    guard needed > 0 else {
      return self
    }

    return String(repeating: " ", count: needed) + self
  }
}

class FCNode {
  let name: String
  let weight: Int

  var coverage: Double {
    didSet {
      if oldValue != coverage {
        parent?.updateCoverage()
      }
    }
  }

  weak var parent: FCNode?
  var children = [FCNode]()

  init(name: String, weight: Int = 1, coverage: Double = 0) {
    self.name = name
    self.weight = weight
    self.coverage = coverage
  }

  func addChildren(_ children: [FCNode]) {
    for child in children {
      child.parent = self
    }

    self.children += children

    updateCoverage()
  }

  func show(level: Int = 0) {
    let indent = level * 4
    let nameLen = name.count + indent

    print(name.paddedLeft(totalLen: nameLen), terminator: "")
    print("|".paddedLeft(totalLen: 32 - nameLen), terminator: "")
    print(String(format: "  %3d   |", weight), terminator: "")
    print(String(format: " %8.6f |", coverage))

    for child in children {
      child.show(level: level + 1)
    }
  }

  func updateCoverage() {
    let v1 = children.reduce(0.0, { $0 + $1.coverage * Double($1.weight) })
    let v2 = children.reduce(0.0, { $0 + Double($1.weight) })

    coverage = v1 / v2
  }
}

let houses = [
  FCNode(name: "house1", weight: 40),
  FCNode(name: "house2", weight: 60)
]

let house1 = [
  FCNode(name: "bedrooms", weight: 1, coverage: 0.25),
  FCNode(name: "bathrooms"),
  FCNode(name: "attic", weight: 1, coverage: 0.75),
  FCNode(name: "kitchen", weight: 1, coverage: 0.1),
  FCNode(name: "living_rooms"),
  FCNode(name: "basement"),
  FCNode(name: "garage"),
  FCNode(name: "garden", weight: 1, coverage: 0.8)
]

let house2 = [
  FCNode(name: "upstairs"),
  FCNode(name: "groundfloor"),
  FCNode(name: "basement")
]

let h1Bathrooms = [
  FCNode(name: "bathroom1", weight: 1, coverage: 0.5),
  FCNode(name: "bathroom2"),
  FCNode(name: "outside_lavatory", weight: 1, coverage: 1.0)
]

let h1LivingRooms = [
  FCNode(name: "lounge"),
  FCNode(name: "dining_room"),
  FCNode(name: "conservatory"),
  FCNode(name: "playroom", weight: 1, coverage: 1.0)
]

let h2Upstairs = [
  FCNode(name: "bedrooms"),
  FCNode(name: "bathroom"),
  FCNode(name: "toilet"),
  FCNode(name: "attics", weight: 1, coverage: 0.6)
]

let h2Groundfloor = [
  FCNode(name: "kitchen"),
  FCNode(name: "living_rooms"),
  FCNode(name: "wet_room_&_toilet"),
  FCNode(name: "garage"),
  FCNode(name: "garden", weight: 1, coverage: 0.9),
  FCNode(name: "hot_tub_suite", weight: 1, coverage: 1.0)
]

let h2Basement = [
  FCNode(name: "cellars", weight: 1, coverage: 1.0),
  FCNode(name: "wine_cellar", weight: 1, coverage: 1.0),
  FCNode(name: "cinema", weight: 1, coverage: 0.75)
]

let h2UpstairsBedrooms = [
  FCNode(name: "suite_1"),
  FCNode(name: "suite_2"),
  FCNode(name: "bedroom_3"),
  FCNode(name: "bedroom_4")
]

let h2GroundfloorLivingRooms = [
  FCNode(name: "lounge"),
  FCNode(name: "dining_room"),
  FCNode(name: "conservatory"),
  FCNode(name: "playroom")
]

let cleaning = FCNode(name: "cleaning")

house1[1].addChildren(h1Bathrooms)
house1[4].addChildren(h1LivingRooms)
houses[0].addChildren(house1)

h2Upstairs[0].addChildren(h2UpstairsBedrooms)
house2[0].addChildren(h2Upstairs)
h2Groundfloor[1].addChildren(h2GroundfloorLivingRooms)
house2[1].addChildren(h2Groundfloor)
house2[2].addChildren(h2Basement)
houses[1].addChildren(house2)

cleaning.addChildren(houses)

let top = cleaning.coverage

print("Top Coverage: \(String(format: "%8.6f", top))")
print("Name Hierarchy                 | Weight | Coverage |")

cleaning.show()

h2Basement[2].coverage = 1.0

let diff = cleaning.coverage - top

print("\nIf the coverage of the Cinema node were increased from 0.75 to 1.0")
print("the top level coverage would increase by ")
print("\(String(format: "%8.6f", diff)) to \(String(format: "%8.6f", top))")


import "/fmt" for Fmt

class FCNode {
    construct new(name, weight, coverage) {
        _name = name
        _weight = weight
        _coverage = coverage
        _children = []
        _parent = null
    }

    static new(name, weight) { new(name, weight, 0) }
    static new(name)         { new(name, 1, 0) }

    name     { _name }
    weight   { _weight }
    coverage { _coverage }

    coverage=(value) {
        if (_coverage != value) {
            _coverage = value
            if (_parent) {
                _parent.updateCoverage_() // update any parent's coverage
            }
        }
    }

    parent     { _parent }
    parent=(p) { _parent = p }

    addChildren(nodes) {
        _children.addAll(nodes)
        for (node in nodes) node.parent = this
        updateCoverage_()
    }

    updateCoverage_() {
        var v1 = _children.reduce(0) { |acc, n| acc + n.weight * n.coverage }
        var v2 = _children.reduce(0) { |acc, n| acc + n.weight }
        coverage = v1 / v2
    }

    show(level) {
        var indent = level * 4
        var nl = _name.count + indent
        Fmt.lprint("$*s$*s  $3d   | $8.6f |", [nl, _name, 32-nl, "|", _weight, _coverage])
        if (_children.isEmpty) return
        for (child in _children) child.show(level+1)
    }
}

var houses = [
    FCNode.new("house1", 40),
    FCNode.new("house2", 60)
]

var house1 = [
    FCNode.new("bedrooms", 1, 0.25),
    FCNode.new("bathrooms"),
    FCNode.new("attic", 1, 0.75),
    FCNode.new("kitchen", 1, 0.1),
    FCNode.new("living_rooms"),
    FCNode.new("basement"),
    FCNode.new("garage"),
    FCNode.new("garden", 1, 0.8)
]

var house2 = [
    FCNode.new("upstairs"),
    FCNode.new("groundfloor"),
    FCNode.new("basement")
]

var h1Bathrooms = [
    FCNode.new("bathroom1", 1, 0.5),
    FCNode.new("bathroom2"),
    FCNode.new("outside_lavatory", 1, 1)
]

var h1LivingRooms = [
    FCNode.new("lounge"),
    FCNode.new("dining_room"),
    FCNode.new("conservatory"),
    FCNode.new("playroom", 1, 1)
]

var h2Upstairs = [
    FCNode.new("bedrooms"),
    FCNode.new("bathroom"),
    FCNode.new("toilet"),
    FCNode.new("attics", 1, 0.6)
]

var h2Groundfloor = [
    FCNode.new("kitchen"),
    FCNode.new("living_rooms"),
    FCNode.new("wet_room_&_toilet"),
    FCNode.new("garage"),
    FCNode.new("garden", 1, 0.9),
    FCNode.new("hot_tub_suite", 1, 1)
]

var h2Basement = [
    FCNode.new("cellars", 1, 1),
    FCNode.new("wine_cellar", 1, 1),
    FCNode.new("cinema", 1, 0.75)
]

var h2UpstairsBedrooms = [
    FCNode.new("suite_1"),
    FCNode.new("suite_2"),
    FCNode.new("bedroom_3"),
    FCNode.new("bedroom_4")
]

var h2GroundfloorLivingRooms = [
    FCNode.new("lounge"),
    FCNode.new("dining_room"),
    FCNode.new("conservatory"),
    FCNode.new("playroom")
]

var cleaning = FCNode.new("cleaning")

house1[1].addChildren(h1Bathrooms)
house1[4].addChildren(h1LivingRooms)
houses[0].addChildren(house1)

h2Upstairs[0].addChildren(h2UpstairsBedrooms)
house2[0].addChildren(h2Upstairs)
h2Groundfloor[1].addChildren(h2GroundfloorLivingRooms)
house2[1].addChildren(h2Groundfloor)
house2[2].addChildren(h2Basement)
houses[1].addChildren(house2)

cleaning.addChildren(houses)
var topCoverage = cleaning.coverage
Fmt.print("TOP COVERAGE = $8.6f\n", topCoverage)
System.print("NAME HIERARCHY                 | WEIGHT | COVERAGE |")
cleaning.show(0)

h2Basement[2].coverage = 1 // change Cinema node coverage to 1
var diff = cleaning.coverage - topCoverage
System.print("\nIf the coverage of the Cinema node were increased from 0.75 to 1")
System.write("the top level coverage would increase by ")
Fmt.print("$8.6f to $8.6f", diff, topCoverage + diff)
h2Basement[2].coverage = 0.75  // restore to original value if required


F fusc(n)
   V res = [0] * n
   res[1] = 1
   L(i) 2 .< n
      res[i] = I i % 2 == 0 {res[i I/ 2]} E res[(i-1) I/ 2] + res[(i+1) I/ 2]
   R res

print(‘First 61 terms:’)
print(fusc(61))

print()
print(‘Points in the sequence where an item has more digits than any previous items:’)
V f = fusc(20'000'000)
V max_len = 0
L(i) 0 .< f.len
   I String(f[i]).len > max_len
      max_len = String(f[i]).len
      print((i, f[i]))


with Ada.Text_IO;
with Ada.Integer_Text_IO;

procedure Show_Fusc is

   generic
      Precalculate : Natural;
   package Fusc_Sequences is
      function Fusc (N : in Natural) return Natural;
   end Fusc_Sequences;

   package body Fusc_Sequences is

      Precalculated_Fusc : array (0 .. Precalculate) of Natural;

      function Fusc_Slow (N : in Natural) return Natural is
      begin
         if N = 0 or N = 1 then
            return N;
         elsif N mod 2 = 0 then
            return Fusc_Slow (N / 2);
         else
            return Fusc_Slow ((N - 1) / 2) + Fusc_Slow ((N + 1) / 2);
         end if;
      end Fusc_Slow;

      function Fusc (N : in Natural) return Natural is
      begin
         if N <= Precalculate then
            return Precalculated_Fusc (N);
         elsif N mod 2 = 0 then
            return Fusc (N / 2);
         else
            return Fusc ((N - 1) / 2) + Fusc ((N + 1) / 2);
         end if;
      end Fusc;

   begin
      for N in Precalculated_Fusc'Range loop
         Precalculated_Fusc (N) := Fusc_Slow (N);
      end loop;
   end Fusc_Sequences;

   package Fusc_Sequence is
      new Fusc_Sequences (Precalculate => 200_000);

   function Fusc (N : in Natural) return Natural
     renames Fusc_Sequence.Fusc;

   procedure Print_Small_Fuscs is
      use Ada.Text_IO;
   begin
      Put_Line ("First 61 numbers in the fusc sequence:");
      for N in 0 .. 60 loop
         Put (Fusc (N)'Image);
         Put (" ");
      end loop;
      New_Line;
   end Print_Small_Fuscs;

   procedure Print_Large_Fuscs (High : in Natural) is
      use Ada.Text_IO;
      use Ada.Integer_Text_IO;
      subtype N_Range is Natural range Natural'First .. High;
      F       : Natural;
      Len     : Natural;
      Max_Len : Natural := 0;
      Placeholder : String := "       n      fusc(n)";
      Image_N     : String renames Placeholder (1  .. 8);
      Image_Fusc  : String renames Placeholder (10 .. Placeholder'Last);
   begin
      New_Line;
      Put_Line ("Printing all largest Fusc numbers upto " & High'Image);
      Put_Line (Placeholder);

      for N in N_Range loop
         F   := Fusc (N);
         Len := F'Image'Length;

          if Len > Max_Len then
             Max_Len := Len;
             Put (Image_N,    N);
             Put (Image_Fusc, F);
             Put (Placeholder);
             New_Line;
          end if;
       end loop;
   end Print_Large_Fuscs;

begin
   Print_Small_Fuscs;
   Print_Large_Fuscs (High => 20_000_000);
end Show_Fusc;


BEGIN
    # calculate some members of the fusc sequence              #
    #    f0 = 0, f1 = 1, fn = f(n/2)                 if n even #
    #                       = f(n-1)/2) + f((n+1)/2) if n odd  #

    # constructs an array of the first n elements of the fusc sequence #
    PROC fusc sequence = ( INT n )[]INT:
         BEGIN
            [ 0 : n ]INT a;
            IF n > 0 THEN
                a[ 0 ] := 0;
                IF n > 1 THEN
                    a[ 1 ] := 1;
                    INT i2 := 1;
                    FOR i FROM 2 BY 2 TO n - 1 DO
                        a[ i     ] := a[ i2 ];
                        a[ i + 1 ] := a[ # j - i # i2 ] + a[ # ( j + 1 ) OVER 2 # i2 + 1 ];
                        i2 +:= 1
                    OD
                FI
            FI;
            a[ 0 : n - 1 AT 0 ]
         END ; # fusc #

    []INT f = fusc sequence( 800 000 );
    FOR i FROM 0 TO 60 DO print( ( " ", whole( f[ i ], 0 ) ) ) OD;
    print( ( newline ) );
    # find the lowest elements of the sequence that have 1, 2, 3, etc. digits #
    print( ( "Sequence elements where number of digits of the value increase:", newline ) );
    print( ( "       n    fusc(n)", newline ) );
    INT digit power := 0;
    FOR i FROM LWB f TO UPB f DO
        IF f[ i ] >= digit power THEN
            # found the first number with this many digits #
            print( ( whole( i, -8 ), " ", whole( f[ i ], -10 ), newline ) );
            IF digit power = 0 THEN digit power := 1 FI;
            digit power *:= 10
        FI
    OD
END


on fusc(n)
    if (n < 2) then
        return n
    else if (n mod 2 is 0) then
        return fusc(n div 2)
    else
        return fusc((n - 1) div 2) + fusc((n + 1) div 2)
    end if
end fusc

set sequence to {}
set longestSoFar to 0
repeat with i from 0 to 60
    set fuscNumber to fusc(i)
    set end of sequence to fuscNumber
    set len to (count (fuscNumber as text))
    if (len > longestSoFar) then
        set longestSoFar to len
        set firstLongest to fuscNumber
        set indexThereof to i + 1 -- AppleScript indices are 1-based.
    end if
end repeat

return {sequence:sequence, firstLongest:firstLongest, indexThereof:indexThereof}


fusc: function [n][
    if? or? n=0 n=1 -> n
    else [
        if? 0=n%2 -> fusc n/2
        else -> (fusc (n-1)/2) + fusc (n+1)/2
    ]
]

print "The first 61 Fusc numbers:"
print map 0..61 => fusc

print "\nThe Fusc numbers whose lengths are greater than those of previous Fusc numbers:"
print "        n   fusc(n)"
print "--------- ---------"
maxLength: 0

loop 0..40000 'i [
    f: fusc i
    l: size to :string f
    if l > maxLength [
        maxLength: l
        print [
            pad to :string i 9
            pad to :string f 9
        ]
    ]
]


fusc:=[], fusc[0]:=0, fusc[1]:=1, n:=1, l:=0, result:=""

while (StrLen(fusc[n]) < 5)
    fusc[++n] := Mod(n, 2) ? fusc[floor((n-1)/2)] + fusc[Floor((n+1)/2)] : fusc[floor(n/2)]

while (A_Index <= 61)
    result .= (result = "" ? "" : ",") fusc[A_Index-1]

result .= "`n`nfusc number whose length is greater than any previous fusc number length:`nindex`tnumber`n"
for i, v in fusc
    if (l < StrLen(v))
        l := StrLen(v), result .= i "`t" v "`n"

MsgBox % result


# syntax: GAWK -f FUSC_SEQUENCE.AWK
# converted from C
BEGIN {
    for (i=0; i<61; i++) {
      printf("%d ",fusc(i))
    }
    printf("\n")
    print("fusc numbers whose length is greater than any previous fusc number length")
    printf("%9s %9s\n","fusc","index")
    for (i=0; i<=700000; i++) {
      f = fusc(i)
      leng = num_leng(f)
      if (leng > max_leng) {
        max_leng = leng
        printf("%9s %9s\n",commatize(f),commatize(i))
      }
    }
    exit(0)
}
function commatize(x,  num) {
    if (x < 0) {
      return "-" commatize(-x)
    }
    x = int(x)
    num = sprintf("%d.",x)
    while (num ~ /^[0-9][0-9][0-9][0-9]/) {
      sub(/[0-9][0-9][0-9][,.]/,",&",num)
    }
    sub(/\.$/,"",num)
    return(num)
}
function fusc(n) {
    if (n == 0 || n == 1) {
      return(n)
    }
    else if (n % 2 == 0) {
      return fusc(n/2)
    }
    else {
      return fusc((n-1)/2) + fusc((n+1)/2)
    }
}
function num_leng(n,  sum) {
    sum = 1
    while (n > 9) {
      n = int(n/10)
      sum++
    }
    return(sum)
}


global f, max
max = 36000
dim f(max)

call fusc()

for i = 0 to 60
    print f[i]; " ";
next i

print : print
print "     Index         Value"
d = 0
for i = 0 to max-1
    if f[i] >= d then
	print rjust(string(i),10," "), rjust(string(f[i]),10," ")
	if d = 0 then d = 1
	d *= 10
    end if
next i
end

subroutine fusc()
    f[0] = 0 : f[1] = 1
    for n = 2 to max-1
	if (n mod 2) then
	    f[n] = f[(n-1)/2] + f[(n+1)/2]
	else
	    f[n] = f[n/2]
	end if
    next n
end subroutine


Fusc ← {
  {
   𝕩∾+´(⍷(⌈∾⌊)2÷˜≠𝕩)⊑¨<𝕩
  }⍟(𝕩-2)↕2
}

•Show Fusc 61

•Show >⟨"Index"‿"Number"⟩∾{((1+↕4)⊐˜(⌊1+10⋆⁼1⌈|)¨𝕩){𝕨∾𝕨⊑𝕩}¨<𝕩} Fusc 99999


#include<limits.h>
#include<stdio.h>

int fusc(int n){
        if(n==0||n==1)
                return n;
        else if(n%2==0)
                return fusc(n/2);
        else
                return fusc((n-1)/2) + fusc((n+1)/2);
}

int numLen(int n){
        int sum = 1;

        while(n>9){
                n = n/10;
                sum++;
        }

        return sum;
}

void printLargeFuscs(int limit){
        int i,f,len,maxLen = 1;

        printf("\n\nPrinting all largest Fusc numbers upto %d \nIndex-------Value",limit);

        for(i=0;i<=limit;i++){
                f = fusc(i);
                len = numLen(f);

                if(len>maxLen){
                        maxLen = len;
                        printf("\n%5d%12d",i,f);
                }
        }
}

int main()
{
        int i;

        printf("Index-------Value");
        for(i=0;i<61;i++)
                printf("\n%5d%12d",i,fusc(i));
        printLargeFuscs(INT_MAX);
        return 0;
}


using System;
using System.Collections.Generic;

static class program
{
    static int n = 61;
    static List<int> l = new List<int>() { 0, 1 };

    static int fusc(int n)
    {
        if (n < l.Count) return l[n];
        int f = (n & 1) == 0 ? l[n >> 1] : l[(n - 1) >> 1] + l[(n + 1) >> 1];
        l.Add(f); return f;
    }

    static void Main(string[] args)
    {
        bool lst = true; int w = -1, c = 0, t;
        string fs = "{0,11:n0}  {1,-9:n0}", res = "";
        Console.WriteLine("First {0} numbers in the fusc sequence:", n);
        for (int i = 0; i < int.MaxValue; i++)
        {
            int f = fusc(i); if (lst)
            {
                if (i < 61) Console.Write("{0} ", f);
                else
                {
                    lst = false;
                    Console.WriteLine();
                    Console.WriteLine("Points in the sequence where an item has more digits than any previous items:");
                    Console.WriteLine(fs, "Index\\", "/Value"); Console.WriteLine(res); res = "";
                }
            }
            if ((t = f.ToString().Length) > w)
            {
                w = t; res += (res == "" ? "" : "\n") + string.Format(fs, i, f);
                if (!lst) { Console.WriteLine(res); res = ""; } if (++c > 5) break;
            }
        }
        l.Clear();
    }
}


#include <iomanip>
#include <iostream>
#include <limits>
#include <sstream>
#include <vector>

const int n = 61;
std::vector<int> l{ 0, 1 };

int fusc(int n) {
    if (n < l.size()) return l[n];
    int f = (n & 1) == 0 ? l[n >> 1] : l[(n - 1) >> 1] + l[(n + 1) >> 1];
    l.push_back(f);
    return f;
}

int main() {
    bool lst = true;
    int w = -1;
    int c = 0;
    int t;
    std::string res;
    std::cout << "First " << n << " numbers in the fusc sequence:\n";
    for (int i = 0; i < INT32_MAX; i++) {
        int f = fusc(i);
        if (lst) {
            if (i < 61) {
                std::cout << f << ' ';
            } else {
                lst = false;
                std::cout << "\nPoints in the sequence where an item has more digits than any previous items:\n";
                std::cout << std::setw(11) << "Index\\" << "  " << std::left << std::setw(9) << "/Value\n";
                std::cout << res << '\n';
                res = "";
            }
        }
        std::stringstream ss;
        ss << f;
        t = ss.str().length();
        ss.str("");
        ss.clear();
        if (t > w) {
            w = t;
            res += (res == "" ? "" : "\n");
            ss << std::setw(11) << i << "  " << std::left << std::setw(9) << f;
            res += ss.str();
            if (!lst) {
                std::cout << res << '\n';
                res = "";
            }
            if (++c > 5) {
                break;
            }
        }
    }
    return 0;
}


fusc = iter () yields (int)
    q: array[int] := array[int]$[1]
    yield(0)
    yield(1)

    while true do
        x: int := array[int]$reml(q)
        array[int]$addh(q,x)
        yield(x)

        x := x + array[int]$bottom(q)
        array[int]$addh(q,x)
        yield(x)
    end
end fusc

longest_fusc = iter () yields (int,int)
    sofar: int := 0
    count: int := 0

    for f: int in fusc() do
        if f >= sofar then
            yield (count,f)
            sofar := 10*sofar
            if sofar=0 then sofar:=10 end
        end
        count := count + 1
    end
end longest_fusc

start_up = proc ()
    po: stream := stream$primary_output()

    stream$putl(po, "First 61:")
    n: int := 0
    for f: int in fusc() do
        stream$puts(po, int$unparse(f) || " ")
        n := n + 1
        if n = 61 then break end
    end

    stream$putl(po, "\nLength records:")
    n := 0
    for i, f: int in longest_fusc() do
        stream$putl(po, "fusc(" || int$unparse(i) || ") = " || int$unparse(f))
        n := n + 1
        if n = 5 then break end
    end
end start_up


import std.functional, std.stdio, std.format, std.conv;

ulong fusc(ulong n) =>
  memoize!fuscImp(n);

ulong fuscImp(ulong n) =>
  ( n < 2 ) ? n :
  ( n % 2 == 0 ) ? memoize!fuscImp( n/2 ) :
  memoize!fuscImp( (n-1)/2 ) + memoize!fuscImp( (n+1)/2 );

void main() {
  const N_FIRST=61;
  const MAX_N_DIGITS=5;

  format!"First %d fusc numbers: "(N_FIRST).write;
  foreach( n; 0..N_FIRST ) n.fusc.format!"%d ".write;
  writeln;

  format!"\nFusc numbers with more digits than any previous (1 to %d digits):"(MAX_N_DIGITS).writeln;
  for(auto n=0, ndigits=0; ndigits<MAX_N_DIGITS; n++)
    if( n.fusc.to!string.length > ndigits ){
      format!"fusc(%d)=%d"( n, n.fusc ).writeln;
      ndigits = n.fusc.to!string.length.to!int;
    }
}