{"id":17202498,"url":"https://github.com/roualdes/testbank","last_synced_at":"2025-04-06T06:43:37.427Z","repository":{"id":21494674,"uuid":"71289394","full_name":"roualdes/testbank","owner":"roualdes","description":"A database manager for test questions.","archived":false,"fork":false,"pushed_at":"2024-02-24T22:42:21.000Z","size":1845,"stargazers_count":1,"open_issues_count":8,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-13T23:54:20.853Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/roualdes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-10-18T20:39:54.000Z","updated_at":"2024-04-13T23:54:20.854Z","dependencies_parsed_at":"2024-10-15T02:14:51.489Z","dependency_job_id":"96fc3239-ceae-4de0-b5ca-201bb6e665c9","html_url":"https://github.com/roualdes/testbank","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roualdes%2Ftestbank","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roualdes%2Ftestbank/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roualdes%2Ftestbank/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roualdes%2Ftestbank/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/roualdes","download_url":"https://codeload.github.com/roualdes/testbank/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247445651,"owners_count":20939953,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-15T02:14:49.601Z","updated_at":"2025-04-06T06:43:37.408Z","avatar_url":"https://github.com/roualdes.png","language":"JavaScript","readme":"# TestBank\n\nTestBank is hosted at `https://testbank.roualdes.us/`. To generate an instance\nof exercise `0Y7x`, run\n\n```\ncurl https://testbank.roualdes.us/0Y7x\n```\n\nRerun the above command. Notice that there is a random component to\nthe exercise. This is the crux of TestBank: exercise templates with\nrandom components generated from code run in a\n[Jupyter](https://jupyter.org/) backend. Right now, only\n[Python3](https://www.python.org/) and [R](https://www.r-project.org/)\nare available.\n\n## Examples\n\nThe directory `examples` contains two primary examples. First, an\napproximate exam from my MATH 314 course at [Chico\nState](https://www.csuchico.edu/). The second a working example of how\none could leverage TestBank with\n[check50](https://cs50.readthedocs.io/check50/). Each subfolder has\nits own README.\n\nThe files `exampels/add.r` and `examples/add.json` are intended to\ndemonstrate the file structure necessary for adding an exercise to\nTestBank's databases.\n\n## Data\n\nFor now, let's simplify things and store exercises in .json files. I'll use\n[lowdb](https://github.com/typicode/lowdb) to interact with the JSON\nfiles. There will be one file for exercises and one file for tags.\nThe last bit will be how each exercise is returned to the end user.\n\n### Exercise schema\n\n```\n{\n    id: \"a unique ID, 4 characters long; [0-9a-zA-Z]{4}\", # generated by TestBank\n    language: python | r,\n    exercise: \"code to produce an exercise\",\n    tags: [\"tag1\", ..., \"tagT\"] # planned but not implemented,\n}\n```\n\n### Tags\n\nIf a user searches the database with a complex query such as `tags: tag1 AND (tag2 OR tag3)`, then the following secondary database should\nmake for more efficient searching.\n\n```\n{\n    tag1: [id1, ..., idA],\n    tag2: [id1, ..., idB],\n    ...\n    tagT: [id1, ..., idT]\n}\n```\n\nAfter collecting the queried tags' arrays, simple set operations\nshould enable direct replacement of AND with `\u0026\u0026` and OR with `||`.\n\n### Output schema\n\nEach exercise will be returned from the TestBank server as a JSON\nobject with one of the two following structures. If an exercise\nis requested, the user will receive a JSON object with the following schema\n\n```\n{\n    id: \"a unique ID\",\n    seed: 1234,\n    context: \"the context of this exercise\",\n    questions: [\"partA\", ..., \"partZ\"],\n    random: {X: x, μ: m, σ: s} # Associative Array specific to language\n    # eg R =\u003e list(), Python =\u003e dict() or {}\n}\n```\n\nThe order of the following elements of an exercise's output schema is not important.\n\n- `id` string. A string of 4 characters, [0-9a-zA-Z]{4}, that uniquely\n  identifies each exercise. TestBank will generate these autmatically\n  upon insertion of an exercise into its database.\n- `seed` int. A seed for the (pseudo) random number generation which is\n  constrained to be in `[1, min(R int, or Numpy np.uint32)] = [1, 2147483647]`. If no seed is specified with each request for an\n  exercise (or its solution), TestBank will randomly chose a seed.\n- `context` string. A string the sets up the exercise's context. If no\n  follow up questions are involved in an exercise, the `context` can\n  contain the question/prompt.\n- `questions` array of strings. The `questions` array holds parts,\n  say A, B, C, D, and E, of an exercise as strings. While the\n  `questions` key is required, the value may be an empty array..\n- `random` Object, aka associative array. The `random` object holds named\n  elements of the randomly generated components of an exercise. While\n  the `random` key is required, the value may be an empty associative\n  array\n\nIf a solution is requested, the user will receive a JSON object with\nthe following schema\n\n```\n{\n  id: \"a unique ID\",\n  seed: 1234,\n  solutions: 0.314 || \"0.314\" || [\"partA\", ..., \"partZ\"],\n  random: {X: x, μ: m, σ: s} # Associative Array specific to language\n  # eg R =\u003e list(), Python =\u003e dict() or {}\n}\n```\n\nAgain, the order is not important. `solutions` is the only new key.\n\n- `solutions` number, string, or array of strings. If questions is an\n  array, then `solutions` should be an array containing answers to\n  each part of the exercise's `questions`. If questions is an empty\n  array, then `solutions` can be a number or a string, appropriately\n  matching the prompt of `context`.\n\n## Writing exercises\n\nTo write an exercise, you must at least use the following structure,\ninclusive of the custom [Mustache](https://github.com/janl/mustache.js) tags\nfor the exercise's ID:\n\n```\nid = '#\u003c ID \u003e#'\n... code to produce Output schema\n```\n\nThese custom Mustache tags have two benefits. First, they help\nprevent my text editor from getting confused while developing TestBank\nexercises, at least within some fairly standard data science\nprogramming languages, R, Python, Julia. Second, they simplify writing LaTeX\nwithin Python strings, since Python's string formatting insists on\ndouble curly braces (otherwise used in Mustache) to get single curly\nbraces (used in LaTeX) into a string.\n\nExamples exist in the\n[examples](https://github.com/roualdes/testbank/tree/master/examples)\ndirectory.\n\n### Extra Mustache tags\n\nIf you want to provide a seed and/or solutions, and keep the solution\nhidden from the (not yet developed) website, use Mustache tags that allow TestBank to\nselectively ignore the exercise and/or the solution.\n\n```\n... code necessary for both exercise and solution\nid = '#\u003c ID \u003e#'\nseeed = #\u003c SEED \u003e#\n\n#\u003c #exercise \u003e#\n... code to produce exercise Output schema\n#\u003c /exercise \u003e#\n\n#\u003c #solution \u003e#\n... code to produce solution Output schema\n#\u003c /solution \u003e#\n```\n\nIt is possible to ignore the seed template entirely. Simply don't put\nthe seed template within the exercise's code.\n\nThe solution template has two goals. First, to enable a request for a\nspecific exercise to return only the solution. Second, when a website\nthat permits searching through TestBank's database is developed, the\nsolution template is intended to allow for hidden solutions. Thus any\nexercise could be searched, found, and read without displaying the\nsolution.\n\nExamples exist in the\n[examples](https://github.com/roualdes/testbank/tree/master/examples)\ndirectory.\n\n## Check an exercise before entering it into the database\n\nThe goal is to make entering exercises into the database as automatic\nas possible, while simultaneously addressing _security_ of the TestBank\nsever, _stability_ of the kernel, and _response_ time.\n\nFor instance, if you wanted to add the problem `examples/add.r` (with\nassociated meta data file at `examples/add.json`) follow these steps.\n\n1. Eyeball code in `add.r` for malicious content.\n2. From this project's root directory, run\n\n```\ntest/exercise.sh examples/add.json\n```\n\nIf the tests above pass, insert the exercise to TestBank's database\nwith the `upsert` command from TestBank's CLI.\n\nThe directory\n[test](https://github.com/roualdes/testbank/tree/master/test) contains\nmore details on tests.\n\n## TestBank command line interface (CLI)\n\nTestBank's GitHub repository comes with a command line interface,\n`cli.js`, which attempts to help with testing exercises and entering\nexercises into the database. The `node` commands below must be run\nfrom the root directory of this repository.\n\n### Testing\n\nTo test whether or not an exercise will run (after the Mustache tags\nare entered), consider the file\n[examples/add.r](https://github.com/roualdes/testbank/tree/master/examples/add.r).\nAt the command line, with\n[littler](http://dirk.eddelbuettel.com/code/littler.html)\ninstalled/aliased as `lr` run\n\n```\n$ lr -e \"$(node cli.js test examples/add.json exercise)\"\n```\n\nIf the above command runs just fine, then there's a hope that your\ncode will run on the TestBank kernel after being entered into the\nTestBank database.\n\nTo test a Python solution, run\n\n```\n$ node cli.js test examples/ex01.json solution | python3\n```\n\nTo ensure that the output is a correctly formatted JSON object, run\n\n```\n$ node cli.js test examples/ex01.json solution | python3 | python3 -m json.tool\n```\n\nTo ensure that the output, and correctly formatted, JSON object\nappropriately follows the Output schema run\n\n```\n$ node cli.js test examples/ex01.json solution | python3 | python3 -m\njson.tool | bash test/schema.sh\n```\n\nThe script `exercise.sh` in directory\n[test](https://github.com/roualdes/testbank/tree/master/test) will run\nall of these steps for you, and for both the exercise and solution\nsection of the code, by running\n\n```\ntest/schema.sh examples/add.json\n```\n\n### Inserting an exercise into TestBanks's database\n\nTo insert an exercise into TestBank's database, use the command line\ninterface as\n\n```\n$ node cli.js insert ex.json\n```\n\nWhere `ex.json` is JSON file for an exercise which provides some meta\ninformation about the exercise to be entered. See examples in the\n[examples](https://github.com/roualdes/testbank/tree/master/examples)\ndirectory for more information.\n\n## TODO\n\n[] Add to README something about requesting solutions based on\nevenness of seed.\n\n[] Enable more complete/robust testing of the database and TestBank\nbackend.\n\n[] Develop a database searchable landing/home page for TestBank.\n\n[] Add HTML, online homework system-esque, example. Maybe\n[bootswatch](https://bootswatch.com/)'s theme\n[flatly](https://bootswatch.com/flatly/)?\n\n[] Authorization? I'm thinking anybody can see questions and the code\nthat generates them. Anybody can request a solution. But it should\nnecessitate some form of authorization to see the code the produces\nthe solutions. If seeds are used appropriately, then just knowing the\nanswer is 0.532 for a specific seed won't help much. And if no\nrandomization is appropriate for a question, then no likely no\nsolution code is appropriate.\n\n[] Figure out versions of dependencies.\n\n[] Insert (possible) FAQs as exercises in the database. Should double\nas helping to explain how to use TestBank and show off some of the\nfeatures, like showing/hiding solutions and ignoring the SEED.\n\n[] GZIP databases.\n\n[] Restart Jupyter kernel's when/if they crash.\n\n## Development\n\nTo work on TestBank, the following dependencies are necessary. There\nis an [Ansible](https://www.ansible.com/) playbook named `ansible.yml`\nthat can set up an Ubuntu 18 machine, if you prefer.\n\n- [Node.js](https://nodejs.org/)\n  - all of the Node.js packages within the file `package.json`, which\n    can be installed with `npm install` from within this directory.\n- [Python3](https://www.python.org/)\n- [R](https://www.r-project.org/)\n\nThe following packages within each language's ecosystem\n\n- For Python use [pip](https://pip.pypa.io/en/stable/) to obtain\n  - [jupyterlab](https://jupyterlab.readthedocs.io/en/stable/)\n  - [numpy](https://www.numpy.org/)\n  - [scipy](https://www.scipy.org/)\n  - [pandas](https://pandas.pydata.org/)\n- For R use the function `install.packages()` to obtain\n  - [IRkernel](https://github.com/IRkernel/IRkernel)\n    - After installation, in R (not RStudio), within a Terminal that\n      has access to the Python envirnoment containing jupyterlab, run\n      ```\n      library(IRkernel)\n      IRkernel::installspec()\n      ```\n  - [dplyr](https://dplyr.tidyverse.org/)\n  - [tidyverse](https://ggplot2.tidyverse.org/)\n  - [jsonlite](https://cran.r-project.org/web/packages/jsonlite/index.html)\n  - [pander](https://rapporter.github.io/pander/)\n\nAnd for tests one needs,\n\n- [littler](http://dirk.eddelbuettel.com/code/littler.html)\n  - This can not be installed as an alias, since some scripts\n    necessitate `lr` being on the path.\n- [bash](https://www.gnu.org/software/bash/)\n- [jq](https://stedolan.github.io/jq/)\n\nThis is my best attempt at a complete list, but I'm still iffy about\nversions of everything. Let me know what I've missed.\n\nPRs welcome.\n\n## License\n\nLicense: Open source, [BSD (3-clause)](https://opensource.org/licenses/BSD-3-Clause).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froualdes%2Ftestbank","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Froualdes%2Ftestbank","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froualdes%2Ftestbank/lists"}