{"id":22043525,"url":"https://github.com/dspearson/stalin","last_synced_at":"2025-03-23T13:47:38.284Z","repository":{"id":170993772,"uuid":"172944416","full_name":"dspearson/stalin","owner":"dspearson","description":"Stalin - a STAtic Language ImplementatioN","archived":false,"fork":false,"pushed_at":"2019-02-27T15:51:46.000Z","size":5259,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-28T19:49:18.993Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dspearson.png","metadata":{"files":{"readme":"README","changelog":null,"contributing":null,"funding":null,"license":"COPYING","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-02-27T15:50:59.000Z","updated_at":"2024-12-27T08:37:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"953ce730-0a59-42cd-b894-5c8fa3d01d76","html_url":"https://github.com/dspearson/stalin","commit_stats":null,"previous_names":["dspearson/stalin"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dspearson%2Fstalin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dspearson%2Fstalin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dspearson%2Fstalin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dspearson%2Fstalin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dspearson","download_url":"https://codeload.github.com/dspearson/stalin/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245111928,"owners_count":20562511,"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-11-30T12:16:27.961Z","updated_at":"2025-03-23T13:47:38.268Z","avatar_url":"https://github.com/dspearson.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\t\t  Stalin - a STAtic Language ImplementatioN\n\t     Finally, a Lisp compiler that does what it should...\n\n\t\t\t     Jeffrey Mark Siskind\n\t\tSchool of Electrical and Computer Engineering\n\t\t\t      Purdue University\n\t\t  Electrical Engineering Building, Room 330\n\t\t\t   465 Northwestern Avenue\n\t\t       West Lafayette IN 47907-2035 USA\n\t\t\t     voice: 765/496-3197\n\t\t\t      fax: 765/494-6440\n\t\t\t       qobi@purdue.edu\n\t\t       http://www.ece.purdue.edu/~qobi\n\n\t\t\t    Monday 2 October 2006\n\n\t\t\t\t INTRODUCTION\n\nThis is release 0.11 of Stalin, a global optimizing compiler for Scheme.  It is\nan alpha release and contains many known bugs.  Not everything is fully\nimplemented.  This is the first self-hosting release.  Stalin can now compile\nitself.  Unlike previous releases, this release does not require you to have\nScheme-\u003eC.  And it does not require you to install Infrastructure or\nQobiScheme.\n\nStalin is an extremely efficient compiler for Scheme.  It is designed to be\nused not as a development tool but rather as a means to generate efficient\nexecutable images either for application delivery or for production research\nruns.  In contrast to traditional Scheme implementations, Stalin is a\nbatch-mode compiler.  There is no interactive READ-EVAL-PRINT loop.  Stalin\ncompiles a single Scheme source file into an executable image (indirectly via\nC).  Running that image has equivalent semantics to loading the Scheme source\nfile into a virgin Scheme interpreter and then terminating its execution.  The\nchief limitation is that it is not possible to LOAD or EVAL new expressions or\nprocedure definitions into a running program after compilation.  In return for\nthis limitation, Stalin does substantial global compile-time analysis of the\nsource program under this closed-world assumption and produces executable\nimages that are small, stand-alone, and fast.\n\nStalin incorporates numerous strategies for generating efficient code.  Among\nthem, Stalin does global static type analysis using a soft type system that\nsupports recursive union types.  Stalin can determine a narrow or even\nmonomorphic type for each source code expression in arbitrary Scheme programs\nwith no type declarations.  This allows Stalin to reduce, or often eliminate,\nrun-time type checking and dispatching.  Stalin also does low-level\nrepresentation selection on a per-expression basis.  This allows the use of\nunboxed base machine data representations for all monomorphic types resulting\nin extremely high-performance numeric code.  Stalin also does global static\nlife-time analysis for all allocated data.  This allows much temporary\nallocated storage to be reclaimed without garbage collection.  Finally, Stalin\nhas very efficient strategies for compiling closures.  Together, these\ncompilation techniques synergistically yield efficient object code.\nFurthermore, the executable images created by Stalin do not contain\n(user-defined or library) procedures that aren't called, variables and\nparameters that aren't used, and expressions that cannot be reached.  This\nencourages a programming style whereby one creates and uses very general\nlibrary procedures without fear that executable images will suffer from code\nbloat.\n\n\t\t\t\tIMPORTANT NOTE\n\nContrary to any other indication in the documentation, this release does not\nrun on DEC/Alpha under Linux due to limitations of gcc (it is not able to\ncompile the file stalin-Alpha.c because it has too many global variables).  It\nis possible to run Stalin under Linux on DEC/Alpha when it is compiled with\nScheme-\u003eC (rather than self compiled) but I am not currently distributing that\nversion.  Contact me if you need to run Stalin under Alpha Linux and I will\nsend you the Scheme-\u003eC version.\n\nIt might be possible to compile stalin-Alpha.c with the DEC C compiler under\nDigital Unix.  I do not have access to this environment to try this.  If\nanybody else does, I would appreciate any feedback as to whether this works.\n\n\t\t\t\t  DEVIATIONS\n\nStalin nominally accepts the language defined by The Revised^4 Report on the\nAlgorithmic Language Scheme (R4RS).  The language accepted by Stalin is known\nto deviate from R4RS in a number of ways as described below.  (If you discover\nadditional differences, please send mail to Big-Stalin@AI.MIT.EDU.)  Many of\nthese simply are features that are not (yet) implemented though I make no\ncommitment to fully comply with R4RS and reserve the right to deviate from\nR4RS for any reason whatsoever, particularly performance.\n\n 1. Unimplemented syntax:\n    4.2.6 Nested quasiquotation is not supported.\n    appendix Macros\n 2. Unimplemented procedures:\n    6.5.5    NUMERATOR\n             DENOMINATOR\n             RATIONALIZE\n             MAKE-RECTANGULAR\n             MAKE-POLAR\n             REAL-PART\n             IMAG-PART\n             MAGNITUDE\n             ANGLE\n    6.10.4   LOAD\n             TRANSCRIPT-ON\n             TRANSCRIPT-OFF\n 3. (1.1) Tail recursion optimization is done only on self calls.\n 4. (6.5) The following numeric data types are not supported:\n    a. bignums: exact integers of arbitrary magnitude\n       Furthermore, exact integer arithmetic can overflow without signaling an\n       error and without yielding an inexact floating point number.\n    b. ratios: exact non-integer rationals\n    c. polar format complex numbers\n    d. exact rectangular format complex numbers\n 5. It is not possible to access all of the underlying C scalar types.  (This\n    is not an incompatibility with R4RS but nonetheless important for other\n    reasons.)\n    a. No independent control over the float/double distinction.\n    b. No long/short chars/ints/floats/doubles\n    c. No unsigned chars/ints\n 6. (1.3.1) No R4RS compliance mode is provided.\n 7. Limitations of (6.5.6) STRING-\u003eNUMBER, (6.10.2) READ, and the source\n    program:\n    a. Can't parse largest negative number.\n    b. Can't parse polar numbers with @.\n    c. Can't parse rectangular numbers with i.\n    d. Can't parse ratios with /.\n    e. Can't parse numbers with embedded #.\n    f. Can't parse exactness with #E and #I.\n    g. Can't parse inexact numbers with mantissas where the digit string\n       before the decimal point would overflow if read as an exact number,\n    h. On Intel, SPARC, and SGI, the source program can't contain exact\n       integer constants \u003c-536870912 or \u003e536870911.  On Intel and SPARC, the\n       compiler will generate incorrect C code without warning.  On SGI, the\n       compiler might signal an exception or might generate incorrect C code\n       without warning.  On Alpha, the source program can't contain exact\n       integer constants \u003c-2305843009213693952 or \u003e2305843009213693951.  The\n       compiler will generate incorrect C code without warning.\n 8. (6.5.6) STRING-\u003eNUMBER doesn't accept the optional radix argument.\n 9. APPLY and CALL-WITH-CURRENT-CONTINUATION don't accept continuations or\n    foreign procedures as their first argument.\n10. (6.2) EQV? might return #T when given two procedures that can never be\n    called.\n    (BEGIN (DEFINE (F X) (LAMBDA () X)) (EQV? (F 1) (F 2))) ==\u003e #T\n    EQV? might return #T when given two fictitious pairs or degenerate vectors.\n    (EQV? (CONS #T #T) (CONS #T #T)) ==\u003e #T\n    (EQV? (VECTOR #T) (VECTOR #T)) ==\u003e #T\n11. (6.5.5) =, \u003c, \u003e, \u003c=, \u003e= might not be transitive.\n12. (6.5.6) STRING-\u003eNUMBER, READ, DISPLAY, and WRITE don't obey write/read\n    invariance for inexact numbers.\n13. (APPLY (LAMBDA X X) y) ==\u003e y without checking that y is a list and without\n    copying y.  Furthermore, because of the way LIST is defined, (APPLY LIST X)\n    doesn't copy X.\n14. (6.10.1) Closing a port that has already been closed yields undefined\n    behaviour rather than having no effect.\n\n\t\t\t\t  EXTENSIONS\n\nStalin extends R4RS in a number of ways:\n\n 1. New syntax: PRIMITIVE-PROCEDURE and FOREIGN-PROCEDURE.\n 2. New procedures: LIST-LENGTH, SUBLIST, SUB, LIST-APPEND, LIST-REVERSE, REF,\n    LIST-SET!, REF!, LIST-FILL!, FILL!, LIST-COPY, STRING-\u003eUNINTERNED-SYMBOL,\n    STRING-REVERSE, \u003c\u003c, \u003e\u003e, BITWISE-NOT, BITWISE-AND, BITWISE-OR,\n    MAKE-DISPLACED-VECTOR, SUBVECTOR, VECTOR-APPEND, VECTOR-REVERSE,\n    VECTOR-COPY, PANIC, POINTER?, INTEGER-\u003eSTRING, INTEGER-\u003eINPUT-PORT,\n    INTEGER-\u003eOUTPUT-PORT, and INTEGER-\u003ePOINTER.\n 3. New data type: pointer.  ZERO? can be used to check for null pointers\n    (as well as null strings and null ports).  INTEGER-\u003ePOINTER can be used to\n    convert an integer address to a pointer.  INTEGER-\u003eSTRING,\n    INTEGER-\u003eINPUT-PORT, and INTEGER-\u003eOUTPUT-PORT can be used to convert an\n    integer address to a string, input port, or output-port, respectively.\n 4. New variable: ARGV is bound to a vector of strings containing the\n    command line arguments.\n 5. If the last expression executed by the program evaluates to an integer,\n    then its value is returned as the status code of the program.  Otherwise,\n    the status code zero is returned.\n 6. Vectors are self evaluating.\n 7. DO iterator list can be empty.\n 8. Bodies can be empty.\n 9. The commands of DO and the expressions of COND, CASE, BEGIN, and DO are\n    considered bodies.\n10. Bodies can have definitions intermixed with expressions.\n11. Definitions are executed in order and can reference variables defined by\n    previous definitions.\n12. Any body with just definitions treated like BEGIN.\n13. Binding can be just a variable in LET, LET*, and LETREC.\n14. DEFINE can take a single argument.\n15. (EQV? \"\" \"\") ==\u003e #T\n    (EQV? #() #()) ==\u003e #T\n16. The procedures LENGTH, APPEND, REVERSE, and COPY are generic.\n17. EOF objects, input ports, and output ports are disjoint from each other\n    and all other data types.\n18. All EOF objects are EQ?.\n\nA future version of this document will describe all of the above extensions in\ngreater detail.\n\n\t\t\t\t INSTALLATION\n\nThe Stalin compiler is written in Scheme and can compile itself.  (While I\nhave run Stalin under other Scheme implementations such as Scheme-\u003eC, SCM, and\nGambit-C, this requires some modification of the Stalin source code.)  To\ncompile and use Stalin, you must have a C compiler installed.\n\nTo install Stalin, do:\n\n% uncompress stalin-0.11.tar.Z\n% tar xf stalin-0.11.tar\n% cd stalin-0.11\n% ./build\n\nTo test Stalin, do:\n\n% cd benchmarks\n% ./compile-and-run-stalin-benchmarks\n\nwhich will compile and run some sample programs including the Gabriel\nbenchmarks.\n\nIf you wish to compare the performance of Stalin against Scheme-\u003eC, Gambit-C,\nBigloo, and Chez (assuming that you have these systems installed) you can do:\n\n% ./benchmark\n\nThis will compile all of the example with each of the Scheme compilers, run\neach example three times, and automatically produce a file `results.tex' with\nabsolute CPU times for each benchmark and compiler as well as ratios of the\nCPU times used by Stalin vs. the other compilers.\n\nYou might wish to put the executable `stalin' in your standard directory of\nexecutables.  You might also wish to put the man page `stalin.man' in your\nstandard directory of man pages.  And you might wish to copy the directory\n`include' to `/usr/local/stalin/include'.  If you do the latter then you need\nnot specify the -I option when using Stalin.\n\nStalin comes with an experimental Emacs interface.  To use this interface\nyou first need to compile the program pp.sc.  This program must be compiled\nwith Scheme-\u003eC (which is not included in the Stalin distribution).  Compile\nthis program with the following commands:\n\n% scc -o pp pp.sc\n% rm pp.c\n\nand then put `pp' in your path.  The Emacs interface is in the file\n`stalin.el'.  Read the instructions at the beginning of that file for an\nexplanation of how to use that interface.\n\nStalin also comes with an experimental FPI to OpenGL.  This interface assumes\nthat you have the files `GL/gl.h', `GL/glu.h', and `GL/glut.h' in your C\ncompiler include path.  To install this interface, do:\n\n% ./build-gl-fpi\n\nPlease note that the OpenGL interface requires Mark Kilgard's GLUT which\ndoesn't come with OpenGL by default.  GLUT can be obtained from:\n\nhttp://reality.sgi.com/mjk_asd/glut3/glut3.html\n\nSince Stalin is now self-hosting, this distribution comes with pre-generated\nC code.  The initial installation is done simply by compiling this C code.\nSince the C code generated by Stalin varies depending on architectural\nparameters, this distribution comes with two pre-generated versions: the file\n`stalin-32.c' for 32-bit architectures and the file `stalin-Alpha.c' for the\nDEC/Alpha.  The `build' script automatically determines the architecture that\nit is running on and copies the appropriate file to `stalin.c' and then\ncompiles this file.  If you wish to rebuild Stalin from the Scheme sources\n(given a running Stalin compiler), you can touch or modify the file `stalin.sc'\nand then do:\n\n% make\n\nwhich will first generate `stalin.c' from `stalin.sc' and then generate\n`stalin' from `stalin.c'.  This will automatically make a version that is\nappropriate for the architecture that you are running on.  If you wish to\ncross-generate C code for a different architecture, then do either:\n\n% make stalin-32.c\n\nor:\n\n% make stalin-Alpha.c\n\n\t\t\t\t    USAGE\n\nSee the man page for how to invoke Stalin.\n\nThe Stalin distribution comes with a number of examples in the benchmarks\ndirectory.  The first example is a simple \"Hello World\" program in the file\n`hello.sc'.  To compile and run it do:\n\n% ./make-hello\n% ./hello\n\nThe second example is a version of the \"Hello World\" program that uses Xlib in\nthe file `xhello.sc'.  To compile and run it, first set your DISPLAY\nenvironment variable appropriately and then do:\n\n% ./make-xhello\n% ./xhello\n\nthen click on the window to exit.  The third example illustrates how to use\nthe application framework that is included in QobiScheme.  It is in the file\n`define-application-example.sc'.  To compile and run it, first set your DISPLAY\nenvironment variable appropriately and then do:\n\n% ./make-define-application-example\n% ./define-application-example\n\nThis program illustrates simple buttons (\"Quit\"), on/off buttons (\"Flag\"),\nradio buttons (\"Line\" and \"Ellipse\"), mode buttons (\"A/B/C\"),\nincrement/decrement buttons (\"-K\" and \"+K\"), keystroke accelerators (c-X c-C\nand c-H), the builtin help facility, the type-in buffer with a few Emacs-like\nkey bindings, mouse-clickable regions, and rubber-banding (click on the\ndisplay pane to draw lines and ellipses).\n\n\t\t\t FOREIGN PROCEDURE INTERFACE\n\nStalin has a rudimentary foreign procedure interface.  The syntax\n\n   (FOREIGN-PROCEDURE (\u003carg type\u003e ...) \u003creturn type\u003e \u003cname\u003e)\n\nreturns a procedure.  \u003carg type\u003e must be one of CHAR, SIGNED-CHAR,\nUNSIGNED-CHAR, SHORT, UNSIGNED-SHORT, INT, UNSIGNED, LONG, UNSIGNED-LONG,\nFLOAT, DOUBLE, LONG-DOUBLE, CHAR*, FILE*, or VOID*.  \u003creturn type\u003e must be one\nof CHAR, SIGNED-CHAR, UNSIGNED-CHAR, SHORT, UNSIGNED-SHORT, INT, UNSIGNED,\nLONG, UNSIGNED-LONG, FLOAT, DOUBLE, LONG-DOUBLE, CHAR*, INPUT-PORT,\nOUTPUT-PORT, VOID*, VOID, or NO-RETURN.  \u003cname\u003e must be a string that\nnames the entry point.  Calling that procedure calls the named entry point.\nForeign procedure are first-class objects and can be passed as arguments to\nScheme procedures, returned as results, and stored in and accessed from\nvariables, pairs, vectors, and structures.  PROCEDURE? returns #T when given a\nforeign procedure as its argument.\n\n                 \u003ctype\u003e         C              Scheme\n\t\t -------------------------------------------------------\n                 CHAR           char           character\n                 SIGNED-CHAR    signed char    character\n                 UNSIGNED-CHAR  unsigned char  character\n                 SHORT          short          exact integer\n                 UNSIGNED-SHORT unsigned short exact integer\n                 INT            int            exact integer\n                 UNSIGNED       unsigned       exact integer\n                 LONG           long           exact integer\n                 UNSIGNED-LONG  unsigned long  exact integer\n                 FLOAT          float          inexact real\n                 DOUBLE         double         inexact real\n                 LONG-DOUBLE    long double    inexact real\n                 CHAR*          char*          string\n                 FILE*          FILE*          input port or output port\n                 INPUT-PORT     FILE*          input port\n                 OUTPUT-PORT    FILE*          output port\n                 VOID           void           unspecified\n                 NO-RETURN      void           unspecified\n                 VOID*          void*          pointer\n\nWhen a foreign procedure is created, the entry point must take the given\nnumber of types and have its argument and return types declared to correspond\nto the above mapping from \u003ctype\u003e to C.  A foreign procedure must be called with\nthe correct number of arguments of the correct types as specified by the above\nmapping from \u003ctype\u003e to Scheme.  No automatic type conversion is done on entry\nto or exit from the foreign procedure.  If -Ot is not specified, a run time\nerror will be generated if a foreign procedure is called with the wrong number\nof arguments or arguments of the wrong type.  Such type checking is eliminated\nif the compiler can prove that it is redundant or if the -Ot option is\nspecified.  The foreign procedure returns a Scheme value of the type specified\nby the above mapping from \u003ctype\u003e to Scheme unless the \u003creturn type\u003e is VOID or\nNO-RETURN.  If the \u003creturn type\u003e is VOID, the returned value is unspecified.\nIf the \u003creturn type\u003e is NO-RETURN then the procedure doesn't return.  As an\nexample, the expression\n   ((FOREIGN-PROCEDURE (CHAR*) INT \"atoi\") (VECTOR-REF ARGV 1))\nparses the first command line argument into an exact integer.\n\nStalin introduces a new object type called `pointer'.  Pointers are first class\nobjects and can be passed as arguments to Scheme procedures, returned as\nresults, and stored in and accessed from variables, pairs, vectors, and\nstructures.  Pointers are disjoint from all other Scheme types.  The only\nprimitive procedures that are defined on pointers, however, are POINTER? and\nZERO?.  POINTER? takes a single argument.  It returns #T if that argument is a\npointer and #F otherwise.  If ZERO? is given a pointer as its argument it\nreturns #T if the pointer is NULL and #F otherwise.  Pointers, however, can be\npassed into and out of foreign procedures as values of the C type void*.\n\nZERO? can also be given a string or a port as its argument.  It returns #T if\nthe string or port is NULL and #F otherwise.  Note that null strings are\ndistinct from empty strings.  Null strings and ports are never created by\nordinary Scheme procedures.  They can only be created by foreign procedures and\nthe Scheme procedures INTEGER-\u003eSTRING, INTEGER-\u003eINPUT-PORT, and\nINTEGER-\u003eOUTPUT-PORT.\n\nA foreign procedure invocation should not access a CHAR* or FILE* value that\nwas passed as an argument to a different invocation of the same or different\nforeign procedure as that value might have been reclaimed in the interim.\n\n\t\t\t\t PORTABILITY\n\nStalin should run under Solaris 1 and 2 on Sun/SPARCs (in 32-bit mode),\nIRIX 4, 5, and 6 on SGI/MIPs (in 32-bit mode), Linux on Intel/x86s (both with\nlibc5 and glibc) and DEC/Alphas, and OSF/1 V3 and V4 on DEC/Alphas though it\nhas only been extensively tested on Linux on Intel/x86s and DEC/Alphas.\n\n\t\t\t\t FUTURE PLANS\n\nStalin currently provides only a minimal set of features, coinciding mostly\nwith those specified in R4RS.  Future plans include several language\nextensions: macros, displaced strings, an object system with inheritance and\ngeneric procedures, weak pointers and finalization, hash tables, a condition\nsystem, a module system, separate compilation, and a debugger.  Additional\ncompile-time optimizations are planned, as well improving the speed of the\ncompiler.\n\n\t\t\t\tCOMMUNICATION\n\nBug mail should be addressed to Bug-Stalin@AI.MIT.EDU and not to me personally.\nPlease include the version number (0.11) in the message.  Periodic\nannouncements of bug fixes, enhancements, and new releases will be made to\nInfo-Stalin@AI.MIT.EDU.  Send mail to Info-Stalin-Request@AI.MIT.EDU to be\nadded to the Info-Stalin@AI.MIT.EDU mailing list.\n\n\t\t\t\tHOW TO OBTAIN\n\nThe current release of Stalin is available by anonymous FTP from\nftp://ftp.ecn.nec.com/qobi/stalin.tar.Z.\n\n\t\t\t       ACKNOWLEDGEMENTS\n\nRob Browning \u003crlb@cs.utexas.edu\u003e, Jeffrey B. Siegal \u003cjbs@quiotix.com\u003e,\nBengt Kleberg \u003cbengt@softwell.se\u003e, and Sven Hartrumpf\n\u003cSven.Hartrumpf@FernUni-Hagen.de\u003e contributed portions of the code and\ndocumentation.\n\n\t\t\t\t  CONDITIONS\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdspearson%2Fstalin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdspearson%2Fstalin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdspearson%2Fstalin/lists"}