{"id":22360829,"url":"https://github.com/renehorstmann/mathc","last_synced_at":"2025-07-30T13:32:03.131Z","repository":{"id":41060914,"uuid":"206783334","full_name":"renehorstmann/Mathc","owner":"renehorstmann","description":"A simple and clean, glsl like, math (linear algebra) header only library for C.","archived":false,"fork":false,"pushed_at":"2023-04-20T11:57:04.000Z","size":781,"stargazers_count":16,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-06T09:03:24.884Z","etag":null,"topics":["c","glsl","header","header-only","linear-algebra","math","matrix","vector"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/renehorstmann.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":"2019-09-06T11:52:50.000Z","updated_at":"2024-05-07T11:35:55.000Z","dependencies_parsed_at":"2024-12-04T16:18:50.865Z","dependency_job_id":"2a2a4af0-0be6-4f78-945c-edfe7697d012","html_url":"https://github.com/renehorstmann/Mathc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/renehorstmann/Mathc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renehorstmann%2FMathc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renehorstmann%2FMathc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renehorstmann%2FMathc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renehorstmann%2FMathc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/renehorstmann","download_url":"https://codeload.github.com/renehorstmann/Mathc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renehorstmann%2FMathc/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267875505,"owners_count":24158780,"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","status":"online","status_checked_at":"2025-07-30T02:00:09.044Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["c","glsl","header","header-only","linear-algebra","math","matrix","vector"],"created_at":"2024-12-04T16:18:46.397Z","updated_at":"2025-07-30T13:32:02.746Z","avatar_url":"https://github.com/renehorstmann.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mathc\nA simple and clean, glsl like, math (linear algebra) header only library for C.\n\n## Getting Started\nCopy the header files into your project and have fun.\n\nThe libraries are written in C11 (tested on GCC 9.3.0, MSVC).\n\nC++11 should also work (also tested with GCC 9.3.0, MSVC).\n\n## Content\n- publictypes: definitions of the vector and matrix types (mathc_vec3, mathc_mat4, ...)\n- types: typedefs to publictypes (vec3, mat4, ...)\n- io: debug print for the types\n- vec: vector math\n- mat: matrix math\n- sca: scalar math (provides functions like min, max, clamp, ... for float, double, int, ...)\n- utils: some useful functions\n\n\n## The Types\nThere are multiple types for different sizes and value types: (sizes (*): 2 - 4)\n- vec* for float vectors\n- mat* for float square matrices\n- dvec*, dmat* for double vectors / square matrices\n- ivec*, imat* for int vectors / square matrices\n- ucvec*, ucmat* for unsigned char vectors / square matrices\n- bvec* for bool vectors\n\n### Vector type usage:\n```c\n#include \"mathc/mathc.h\"\nint main() {\n    vec3 a = {{1, 2, 3}};\n\n    vec3 b;\n    b.x = 10;\n    b.y = 20;\n    b.z = 30;\n\n    vec3 c;\n    c.x = a.x + b.x;\n    c.y = a.y + b.y;\n    c.z = a.z + b.z;\n\n    // or by index:\n    c.v0 = a.v0 + b.v0;\n    c.v1 = a.v1 + b.v1;\n    c.v2 = a.v2 + b.v2;\n\n    // or by raw float *:\n    c.v[0] = a.v[0] + b.v[0];\n    c.v[1] = a.v[1] + b.v[1];\n    c.v[2] = a.v[2] + b.v[2];\n\n    // or with the macro\n    c = vec3_(11, 22, 33);\n    // evaluates as c = (vec3) {{11, 22, 33}};\n\n    // copies c into copy1\n    vec3 copy1 = c;\n    vec3_println(copy1);  // mathc/io\n\n    // or print using the format strings\n    // mathc_uX is a macro tu unpack the values\n    //    replaced by: c.v0, c.v1, c.v2\n    printf(\"c: \" VEC3_PRINT_FORMAT \"\\n\", mathc_u3(c));\n\n    // copies c into copy2, by a memcpy and the raw pointer\n    vec3 copy2;\n    memcpy(copy2.v, c.v, sizeof(vec3));\n    vec3_println(copy2);\n\n\n    vec3 rgb = {{0, 1, 0.5}};\n\n    vec4 rgba;\n\n    // .xyz returns a vec3\n    rgba.xyz = rgb;         // or .rgb\n\n    // .w is the 4. component (xyzw, rgba)\n    rgba.w = 1;             // or .a\n\n    // copies gb (vec2)\n    vec2 gb = rgba.gb;      // or .yz\n    vec2_println(gb);\n}\n```\n\n### Vector type casting:\nAll types can be casted from raw pointers.\nFunctions, that operates on the types, normally have the type as prefix: vec3_*\n```c\n#include \"mathc/mathc.h\"\n\n// use the types from raw pointers\nvoid foo1(float *result3, const float *vector3) {\n    // tmp = vector3 * 1000\n    // MATHC_AS_VEC3() casts a raw pointer into a vec3\n    vec3 tmp = vec3_scale(MATHC_AS_VEC3(vector3), 1000);\n\n    // tmp = tmp + 50\n    tmp = vec3_add(tmp, 50);\n\n    // cast result3 into a vec3 and copy tmp into it\n    MATHC_AS_VEC3(result3) = tmp;\n}\n\n// like foo1, but without tmp\nvoid foo2(float *result3, const float *vector3) {\n    // result3 = (vector3 * 1000) + 50\n    MATHC_AS_VEC3(result3) = vec3_add(\n            vec3_scale(MATHC_AS_VEC3(vector3), 1000),\n            50);\n}\n\n// like foo2, but with a different cast style\nvoid foo3(float *result3, const float *vector3) {\n    vec3 *res = (vec3*) result3;\n    const vec3 *v = (const vec3*) vector3;\n    // result3 = (vector3 * 1000) + 50\n    *res = vec3_add(\n            vec3_scale(*v, 1000),\n            50);\n}\n\n// add foo functionality\nvec3 vec3_scale_add(vec3 vector, float scale, float add) {\n    return vec3_add(vec3_scale(vector, scale), add);\n}\n\nint main() {\n    float vec_raw[3] = {1, 2, 3};\n    float res_raw[3];\n    foo1(res_raw, vec_raw);\n    vec3_println(MATHC_AS_VEC3(res_raw));\n\n    vec3 vec = {{1, 2, 3}};\n    vec3 res;\n    foo2(res.v, vec.v);\n    vec3_println(res);\n\n    res = vec3_scale_add(vec, 1000, 50);\n    vec3_println(res);\n}\n```\n\n### Matrix type:\nThe matrices are stored in column major order.\n```c\n#include \"mathc/mathc.h\"\n\nint main() {\n\n    // 180° via Z matrix (X points to -X, Y to -Y)\n    mat3 rotation_matrix = {{\n        -1, 0, 0,   // X\n        0, -1, 0,   // Y\n        0, 0, 1     // Z\n    }};\n\n    // identity matrix\n    rotation_matrix = mat3_eye();\n\n    // Access via matrix position\n    rotation_matrix.m00 = -1;\n    rotation_matrix.m11 = -1;\n\n    // or by the raw pointer as matrix[3][3]\n    rotation_matrix.m[0][0] = -1;\n    rotation_matrix.m[1][1] = -1;\n\n    // or as vector[9] position\n    rotation_matrix.v0 = -1;\n    rotation_matrix.v4 = -1;\n\n    // or by the raw pointer as vector[9]\n    rotation_matrix.v[0] = -1;\n    rotation_matrix.v[4] = -1;\n\n    // or by each column as vec3[3]\n    rotation_matrix.col[0].x = -1;      // x column, value x\n    rotation_matrix.col[1].y = -1;      // y column, value y\n\n    mat3_println(rotation_matrix);      // nice to view\n    mat3_println_line(rotation_matrix); // in a single line\n\n    // eye by col vectors\n    vec3 x = vec3_unit_x();\n    vec3 y = vec3_unit_y();\n    vec3 z = vec3_unit_z();\n    rotation_matrix.col[0] = x;\n    rotation_matrix.col[1] = y;\n    rotation_matrix.col[2] = z;\n\n    mat3_println(rotation_matrix);\n\n    // casts are like vector casts:\n    float rot_mat_raw[9];\n    MATHC_AS_MAT3(rot_mat_raw) = rotation_matrix;\n}\n```\n\n\n### Type implementation\nVectors and matrices are defined as unions.\nWith this convention (instead of passing pointers), \nvectors and matrices can be copied with the ```operator=``` in C.\nIn addition to that the compiler generates errors,\nif a program wants to pass a vec3 where a vec4 is needed.\nThe copying seems like an overhead, but the compiler can optimize this out.\nNot only that, he can do better because he knows more about the data.\n\n\nThe vec2 is defined as:\n```c\n// publictypes:\ntypedef union {\n    float v[2];\n    struct {\n        float v0, v1;\n    };\n    struct {\n        float x, y;\n    };\n    struct {\n        float r, g;\n    };\n} mathc_vec2;\nstatic_assert(sizeof(mathc_vec2) == sizeof(float) * 2, \"[Mathc] wrong expected size\");\n// types:\ntypedef mathc_vec2 vec2;\n```\n\n\nThere are different options to access the data in the vec2:\n```c\nvec2 a = {{1, 2}};\nprintf(\"a.x = %f = %f = %f = %f\\n\",\n    a.v[0],     // raw vector data\n    a.v0,       // vector data 0-1\n    a.x,        // x, y\n    a.r         // r, g\n);\n```\n\n\nThe type vec3 can do a little bit more:\n```c\n// publictypes:\ntypedef union {\n    float v[3];\n    struct {\n        float v0, v1, v2;\n    };\n    mathc_vec2 xy;\n    struct {\n        float x;\n        union {\n            struct {\n                float y, z;\n            };\n            mathc_vec2 yz;\n        };\n    };\n    mathc_vec2 rg;\n    struct {\n        float r;\n        union {\n            struct {\n                float g, b;\n            };\n            mathc_vec2 gb;\n        };\n    };\n} mathc_vec3;\nstatic_assert(sizeof(mathc_vec3) == sizeof(float) * 3, \"[Mathc] wrong expected size\");\n// types:\ntypedef mathc_vec3 vec3;\n```\n\n\nIn addition to v, v0-2, xyz, rgb, a vec3 lets you access subdata vec2:\n```c\nvec3 a = {{1, 2, 3}};\nvec2 b = a.yz;\nassert(b.v0 == 2 \u0026\u0026 b.v1 == 3);\n```\n\n\nvec4 has subdata for both, vec2 and vec3 (.xy, .xyz, .yz, .yzw, .zw, .rg, .rgb, .gb, .gba, .ba...).\nThere are also variants for double, int, uchar and bool with d, i, uc and b prefix.\n\n\n## Basic functions\nThere are a lot of functions to use with the types:\n- vec*_unit*\n- vec*_new\n- vec*_set\n- vec*_cast_from\n- vec*_cmp\n- vec*_neg\n- vec*_add\n- vec*_add_vec\n- vec*_sub\n- vec*_sub_vec\n- vec*_scale\n- vec*_scale_vec\n- vec*_div\n- vec*_div_vec\n- vec*_add_scaled\n- vec*_add_scaled_vec\n- vec*_radians\n- vec*_degrees\n- vec*_sin\n- vec*_cos\n- vec*_tan\n- vec*_asin\n- vec*_acos\n- vec*_atan\n- vec*_atan2\n- vec*_pow\n- vec*_pow_vec\n- vec*_exp\n- vec*_log\n- vec*_exp2\n- vec*_log2\n- vec*_sqrt\n- vec*_inversesqrt\n- vec*_abs\n- vec*_sign\n- vec*_floor\n- vec*_ceil\n- vec*_fract\n- vec*_mod\n- vec*_mod_vec\n- vec*_min\n- vec*_min_vec\n- vec*_max\n- vec*_max_vec\n- vec*_clamp\n- vec*_clamp_vec\n- vec*_mix\n- vec*_mix_vec\n- vec*_step\n- vec*_step_vec\n- vec*_smoothstep\n- vec*_smoothstep_vec\n- vec*_sum\n- vec*_dot\n- vec*_cross\n- vec*_norm\n- vec*_norm_p\n- vec*_norm_1\n- vec*_norm_inf\n- vec*_normalize\n- vec*_cross_normalized\n- vec*_length\n- vec*_distance\n- vec*_sqr_distance\n- vec*_faceforward\n- vec*_reflect\n- vec*_refract\n- vec*_less_than\n- vec*_less_than_vec\n- vec*_less_than_equal_vec\n- vec*_...\n- vec*_isnan\n\n\nSpecial bool vector functions:\n- bvec*_not\n- bvec*_or\n- bvec*_and\n- bvec*_...\n- bvec*_any\n- bvec*_all\n\n\nMatrix functions:\n- mat*_eye\n- mat*_cast_from\n- mat*_cmp\n- mat*_get_row\n- mat*_get_col\n- mat*_set_row\n- mat*_set_col\n- mat*_trace\n- mat*_transpose\n- mat*_mul_mat\n- mat*_mul_vec\n- mat*_det\n- mat*_inv\n- mat*_get_block*\n- mat*_set_block*\n- mat*_get_upper_left*\n- mat*_set_upper_left*\n\n\nScalar function:\n- sca_radians\n- sca_degrees\n- sca_sin\n- sca_cos\n- sca_tan\n- sca_asin\n- sca_acos\n- sca_atan\n- sca_atan2\n- sca_pow\n- sca_exp\n- sca_log\n- sca_exp2\n- sca_log2\n- sca_sqrt\n- sca_inversesqrt\n- sca_abs\n- sca_sign\n- sca_floor\n- sca_ceil\n- sca_fract\n- sca_mod\n- sca_min\n- sca_max\n- sca_clamp\n- sca_mix\n- sca_step\n- sca_smoothstep\n- sca_signal_wave\n- sca_signal_block\n- sca_signal_saw\n- sca_signal_ramp\n- sca_signal_smoothsaw_single\n- sca_signal_smoothsaw\n- sca_signal_smoothramp\n- sca_isnan\n- sca_isinf\n\n### Typeless functions\nMost functions have their base function as vecN_* or matN_*.\nThese functions take raw pointers as in and output and the size as last parameter:\n```c\n#include \"mathc/mathc.h\"\n\nint main() {\n    float a[7];\n    float res[7];\n    vecN_scale(res, a, 1000, 7);\n    vecN_add(res, res, 50, 7);\n}\n```\n\n### Utils functions\nWithin the sub folder utils/ are some additional libraries:\n- [camera.h](include/mathc/utils/camera.h): for camera matrices for view and projection\n- [color.h](include/mathc/utils/color.h): for rgb hsv conversions\n- [intersection.h](include/mathc/utils/intersection.h): for plane, line, triangle intersections\n- [rotation.h](include/mathc/utils/rotation.h): for angle axis to matrix rotations\n- [quat.h](include/mathc/utils/quat.h): for Quaternion math\n- [random.h](include/mathc/utils/random.h): for random number generation (rand function can be user defined)\n\nAll these libraries should have a d* prefix for double versions\n\n## Import system\nImport everything from Mathc:\n```#include \"mathc/mathc.h\"```\n\nImport float related functions (except of utils/):\n```#include \"mathc/float.h\"```\n\nImport float related utils functions:\n```#include \"mathc/utils/float.h\"```\n\nImport only float vector functions:\n```#include \"mathc/vec/float.h\"```\n\nImport only float typeless vector functions:\n```#include \"mathc/vec/vecn.h\"```\n\nImport only float vector4 functions:\n```#include \"mathc/vec/vec4.h\"```\n\nSame for double, int, uchar and bool.\n\nOnly importing a subset (like mathc/float.h), speeds up the compilation process\n\n## Namespace\nAll functions start as namespace with the type.\nIf you collide with other libraries, use the publictypes header, which defines the types under the `mathc_` namespace.\nThe only functions that may have different namespaces are in the dir utils, \nlike the functions in [intersection.h](include/mathc/utils/intersection.h) which start with the `intersection_` namespace.\n\n## Example usage\n```c\n// includes float related vector and matrix functions\n#include \"mathc/float.h\"\n\n// includes all float related utils functions\n#include \"mathc/utils/float.h\"\n\n// includes bool related vector functions\n#include \"mathc/bool.h\"\n\n\n/** Transform a 3d point with a transformation matrix M */\nvec3 transform_point(mat4 M, vec3 point) {\n    // Create a homogenous 3d point\n    vec4 hpoint;\n    hpoint.xyz = point;\n    // 1 for points, 0 for vectors\n    hpoint.w = 1;\n\n    // return only xyz=vec3 of the resulting vec4 point\n    return mat4_mul_vec(M, hpoint).xyz;\n}\n\n/** Transform a 3d vector with a transformation matrix M */\nvec3 transform_vector(mat4 M, vec3 vector) {\n    // vectors need (M^-1)^t for transformations\n    // (if the matrix uses scaling and sheering)\n    // its safe to override (copies)\n    M = mat4_transpose(mat4_inv(M));\n    vec4 hvector;\n    hvector.xyz = vector;\n    hvector.w = 0;\n    return mat4_mul_vec(M, hvector).xyz;\n}\n\ntypedef struct {\n    float x, y, z, radius;\n    // ...\n} Sphere_s;\n\n/** Test collision between spheres */\nbool sphere_collision(Sphere_s a, Sphere_s b) {\n    // MATHC_AS_* casts a pointer into a mathc type\n    // these macros do the same thing as the second parameter:\n    vec3 dist = vec3_sub_vec(MATHC_AS_VEC3(\u0026b.x), *((vec3*)(\u0026a.x)));\n\n    // norm(dist) \u003c a.r+b.r\n    // powf(,2) is much faster than sqrt\n    return vec3_dot(dist, dist) \u003c powf(a.radius + b.radius, 2);\n}\n\n/** calculates the angle between vector a and b */\nfloat vec_angle(vec3 a, vec3 b) {\n    // Safe to override (copies)\n    a = vec3_normalize(a);\n    b = vec3_normalize(b);\n    return acosf(vec3_dot(a, b));\n}\n\n/** creates a pose from a ray. dir -\u003e Z axis */\nmat4 ray_to_pose(vec3 pos, vec3 dir) {\n    vec3 z = vec3_normalize(dir);\n\n    // align x axis of pose to unit x\n    vec3 y = vec3_cross(z, vec3_unit_x());\n    if(vec3_norm(y) \u003c 0.01f) {\n        // z is parallel to x, using y for x instead\n        y = vec3_cross(z, vec3_unit_y());\n    }\n    y = vec3_normalize(y);\n\n    vec3 x = vec3_cross(y, z);\n    // no need to normalize, cause y and z are orthogonal and normalized\n\n    mat4 pose = mat4_eye();\n    pose.col[0].xyz = x;\n    pose.col[1].xyz = y;\n    pose.col[2].xyz = z;\n    pose.col[3].xyz = pos;\n    return pose;\n}\n\n/** creates a camera VP matrix */\nmat4 create_camera_VP(vec3 eye, vec3 dir, vec3 up, bool orhto) {\n    vec3 center = vec3_add_vec(eye, dir);\n    mat4 V = mat4_camera_lookat(eye, center, up);\n    mat4 P;\n    if(orhto)\n        P = mat4_camera_ortho(-1, 1, -1, 1, -2, 10);\n    else\n        P = mat4_camera_frustum(-1, 1, -1, 1, -2, 10);\n    return mat4_mul_mat(P, V);\n}\n\nbool axles_in_limits(vec3 axles) {\n\n    // lower, upper limits in degree\n    vec3 limits_deg[2] = {\n            {{-5, 10, 0}},\n            {{50, 170, 90}}\n    };\n\n    vec3 limits[2] = {\n            vec3_radians(limits_deg[0]),\n            vec3_radians(limits_deg[1])\n    };\n\n    bvec3 in_lower_limit = vec3_greater_than_equal_vec(axles, limits[0]);\n    bvec3 in_upper_limit = vec3_less_than_equal_vec(axles, limits[1]);\n    bvec3 in_limit = bvec3_and(in_lower_limit, in_upper_limit);\n\n    // returns true if all axles are in limits\n    return bvec3_all(in_limit);\n}\n\nbool vec_equals(vec3 a, vec3 b) {\n    return bvec3_all(vec3_equal_eps_vec(a, b, 0.01f));\n}\n\nint main() {\n    mat4 pose = ray_to_pose((vec3) {{100, 100, 50}}, (vec3) {{0, 0, 1}});\n    vec3 point = {{10, 20, 30}};\n    point = transform_point(mat4_inv(pose), point);\n    vec3_println(point);\n\n    mat4 VP = create_camera_VP((vec3) {{10, 20, 30}},\n                               vec3_neg(vec3_unit_z()),\n                               vec3_unit_y(),\n                               false);\n    vec3 normal = {{0, 1, 0}};\n    normal = transform_vector(VP, normal);\n    vec3_println(normal);\n\n    printf(\"angle: %f\\n\", vec_angle(vec3_unit_x(), vec3_unit_y()));\n\n    printf(\"in_limits: %d\\n\", axles_in_limits((vec3) {{0, SCA_PI_2, SCA_PI_4}}));\n}\n```\n\n## Templates\nThe Mathc library is template generated.\nThe template files are written for the float types (vec*).\nEach other size and type is generated by that files via a regex search and replace script: [template.py](template/template.py).\n\nYou can generate more different data types like signed char, short, unsigned short, unsigned int, long long, ...\nOr different vecX types like vec6, vec12, ...\nSee the main \"function\" of the script.\n\nBecause Mathc uses prefixes for all stuff (e. g: sca_abs and isca_abs instead of fasbs and abs) \nits easy to generate different C files for different primitive formats (float -\u003e double) with the regex replace system\n\n## Performance\nIt seems that there will be an overhead due to the casts and copying. \nThe [performance test](examples/performance_test_lib.c) shows that the overhead is only noticeable in debug mode of the compiler.\nIn Optimising mode, my compiler generated a better result than a manual, not copying example.\n\n## Running the examples\nThe top directory of this project contains a CmakeLists.txt file, which sets up the examples for each library\n\n## Author\n\n* **René Horstmann**\n* Copied some function implementations of: [cglm](https://github.com/recp/cglm) (noted in my comments) (MIT License)\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frenehorstmann%2Fmathc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frenehorstmann%2Fmathc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frenehorstmann%2Fmathc/lists"}