Browse files

migrate text files to markdown, remove unneeded Makefiles

  • Loading branch information...
1 parent 58c159e commit a7d03360095d0d5b7a8695d724dfd6b1afc89fdb @ericbmerritt ericbmerritt committed Oct 6, 2011
Showing with 564 additions and 141 deletions.
  1. +30 −0 LICENSE.md
  2. +0 −31 LICENSE.txt
  3. +0 −14 Makefile
  4. +534 −0 README.md
  5. +0 −18 README.txt
  6. +0 −2 RELEASE.txt
  7. +0 −41 examples/Makefile
  8. +0 −35 src/Makefile
View
30 LICENSE.md
@@ -0,0 +1,30 @@
+BSD License
+===========
+
+Copyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+* Neither the name of Francesca Gangemi, Corrado Santoro may be used
+ to endorse or promote products derived from this software without
+ specific prior written permission.
+
+
+THIS SOFTWARE IS PROVIDED BY Francesca Gangemi AND Corrado Santoro ``AS
+IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
View
31 LICENSE.txt
@@ -1,31 +0,0 @@
-
-
- Copyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of Francesca Gangemi, Corrado Santoro may be used
- to endorse or promote products derived from this software without
- specific prior written permission.
-
-
- THIS SOFTWARE IS PROVIDED BY Francesca Gangemi AND Corrado Santoro ``AS
- IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
-
------------------------- END OF LICENSE -------------------------------------
View
14 Makefile
@@ -1,14 +0,0 @@
-#
-# Makefile
-#
-# $Id$
-#
-
-
-all:
- @[ -d ebin ] || mkdir ebin
- (cd src; make; cd ../examples; make; cd ..)
-
-clean:
- (cd src; make clean; cd ../examples; make clean; cd ..)
-
View
534 README.md
@@ -0,0 +1,534 @@
+ERESYE - ERlang Expert SYstem Engine
+========================================
+
+Introduction
+------------
+
+This article describe how to write a simple Artificial Intelligence
+application with Erlang, by using a *rule production system*.
+
+To reach this objective, we will exploit the **ERESYE** tool, an
+Erlang Inference Engine that allows rule-based systems to be written
+directly in Erlang.
+
+As it is widely known, a rule-based system is composed by a
+**knowledge base**, which stores a set of *facts* representing the
+'universe of discourse' of a given application, and a set of
+**production rules**, which are used to infer knowledge and/or reason
+about the knowledge. A rule is activated when one or more facts match
+the template(s) given in the rule declaration: in such a case, the
+body of the rule contains a code that is thus executed
+
+In ERESYE, *facts* are expressed by means of Erlang tuples or records,
+while rules are written using standard Erlang function clauses, whose
+declaration reports, in the clause head, the facts or fact templates
+that have to be matched for the rule to be activated and executed.
+
+For more information about ERESYE please refer to the paper docs directory.
+
+For more information about rule-based inference engines and expert
+systems, you can refer to the book: *S. Russell and
+P. Norvig. **Artificial Intelligence: A Modern Approach/2E.** Prentice
+Hall, 2003.*
+
+To write an AI application with ERESYE the following steps have to be
+performed:
+
+1. Indentify your universe of discourse and determine the facts that
+ have to be used to represent such a world;
+
+2. Indentify the rules that you need and write them by using, e.g.
+ first-order-logic predicates or even natural language;
+
+3. Implement the system by writing your rules as Erlang function
+ clauses, according to the modality required by ERESYE.
+
+
+The Application: the Domain of Relatives
+----------------------------------------
+
+We will design a system able to derive new knowledge using some
+inference rules and starting from a small set; as a sample
+application, we chose the domain of relatives: we will start from some
+base concepts, such as *parent*, *male* and *female*, and then, by
+means of a proper set of rules, we will derive the concepts of
+*mother*, *father*, *sister*, *brother*, *grandmother* and
+*grandfather*.
+
+According to the list above, we will first derive the facts that will be
+used to represent our concepts. Given the set of relationships above, they
+will be represented by means of the following facts:
+
+<table border="1" align="center">
+<thead>
+ <tr>
+ <td>#</td>
+ <td>Concept</td>
+ <td>Fact / Erlang tuple</td>
+ </tr>
+</thead>
+<tbody>
+ <tr>
+ <td>1</td>
+ <td>X is male</td>
+ <td><tt>{male, X}</tt></td>
+ </tr>
+ <tr>
+ <td>2</td>
+ <td>X is female</td>
+ <td><tt>{female, X}</tt></td>
+ </tr>
+ <tr>
+ <td>3</td>
+ <td>X is Y's parent</td>
+ <td><tt>{parent, X, Y}</tt></td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>X is Y's mother</td>
+ <td><tt>{mother, X, Y}</tt></td>
+ </tr>
+ <tr>
+ <td>5</td>
+ <td>X is Y's father</td>
+ <td><tt>{father, X, Y}</tt></td>
+ </tr>
+ <tr>
+ <td>6</td>
+ <td>X is Y's sister</td>
+ <td><tt>{sister, X, Y}</tt></td>
+ </tr>
+ <tr>
+ <td>7</td>
+ <td>X is Y's brother</td>
+ <td><tt>{brother, X, Y}</tt></td>
+ </tr>
+ <tr>
+ <td>8</td>
+ <td>X is Y's grandmother</td>
+ <td><tt>{grandmother, X, Y}</tt></td>
+ </tr>
+ <tr>
+ <td>9</td>
+ <td>X is Y's grandfather</td>
+ <td><tt>{grandfather, X, Y}</tt></td>
+ </tr>
+</tbody>
+</table>
+
+Concepts 1, 2 and 3 will be used as a base to derive the other ones.
+
+Deriving new concepts by means of rules
+---------------------------------------
+
+#### Concept: mother
+
+The rule to derive the concept of mother is quite
+straightforward:
+
+ if X is female and X is Y's parent then X is Y's mother.
+
+From the point of view of ERESYE, since knowledge is stored in the
+*knowledge base* of the engine, the rule above is translated into the
+following one: *if the facts {female, X} and {parent, X, Y} are
+*asserted* in the knowledge base, then we assert the fact {mother, X,
+Y}.
+
+The rule *mother* can be thus written as follows:
+
+ %%
+ %% if (X is female) and (X is Y's parent) then (X is Y's mother)
+ %%
+ mother (Engine, {female, X}, {parent, X, Y}) ->
+ eresye:assert (Engine, {mother, X, Y}).
+
+
+#### Concept: father
+
+This concept can be easily derived by means of the following rule:
+
+ %%
+ %% if (X is male) and (X is Y's parent) then (X is Y's father)
+ %%
+ father (Engine, {male, X}, {parent, X, Y}) ->
+ eresye:assert (Engine, {father, X, Y}).
+
+
+#### Concept: sister
+
+ This concept can be expressed by the following rule:
+
+ if Y and Z have the same parent and Z is female, then Z
+ is the Y's sister.
+
+The ERESYE rule used to map this concept is:
+
+ %%
+ %% if (Y and Z have the same parent X) and (Z is female)
+ %% then (Z is Y's sister)
+ %%
+ sister (Engine, {parent, X, Y}, {parent, X, Z}, {female, Z}) when Y =/= Z ->
+ eresye:assert (Engine, {sister, Z, Y}).
+
+
+Please note the guard, which is needed to ensure that when Y and Z are
+bound to the same value, the rule is not activated (indeed this is
+possible since the same fact can match both the first and second
+'parent' pattern).
+
+#### Concept: brother
+
+Given the previous one, this concept is now quite simple to
+implement:
+
+
+ %%
+ %% if (Y and Z have the same parent X) and (Z is male)
+ %% then (Z is Y's brother)
+ %%
+ brother (Engine, {parent, X, Y}, {parent, X, Z}, {male, Z}) when Y =/= Z ->
+ eresye:assert (Engine, {brother, Z, Y}).
+
+
+#### Concepts: grandmother and grandfather
+
+The former concept can be expressed by means of the rule:
+
+ if X is Y's mother and Y is Z's parent, then X is Z's
+ grandmother.</u>* The latter concept is now obvious.
+
+Both can be implemented using the following ERESYE rules:
+
+ %%
+ %% if (X is Y's mother) and (Y is Z's parent)
+ %% then (X is Z's grandmother)
+ %%
+ grandmother (Engine, {mother, X, Y}, {parent, Y, Z}) ->
+ eresye:assert (Engine, {grandmother, X, Z}).
+
+ %%
+ %% if (X is Y's father) and (Y is Z's parent)
+ %% then (X is Z's grandfather)
+ %%
+ grandfather (Engine, {father, X, Y}, {parent, Y, Z}) ->
+ eresye:assert (Engine, {grandfather, X, Z}).
+
+
+Instantiating the Engine and Populating the Knowledge Base
+----------------------------------------------------------
+
+After writing the rules, we need to:
+
+- instantiate the engine;
+- add the rules above to the engine;
+- populate the knowledge base with a set of initial facts.
+
+We do this in the function *start* below:
+
+ start () ->
+ eresye:start (relatives),
+ lists:foreach (fun (X) ->
+ eresye:add_rule (relatives, {?MODULE, X})
+ end,
+ [mother, father, brother, sister,
+ grandfather, grandmother]),
+
+ eresye:assert (relatives,
+ [{male, bob}, {male, corrado}, {male, mark}, {male, caesar},
+ {female, alice}, {female, sara}, {female, jane}, {female, anna},
+ {parent, jane, bob}, {parent, corrado, bob},
+ {parent, jane, mark}, {parent, corrado, mark},
+ {parent, jane, alice}, {parent, corrado, alice},
+ {parent, bob, caesar}, {parent, bob, anna},
+ {parent, sara, casear}, {parent, sara, anna}]),
+ ok.
+
+As the listing reports, creating a new ERESYE engine implies to call
+the function *eresye:start/1*, giving the name of the engine to be
+created
+
+Then, we have to add the rules to the engine by using the function
+*eresye:add_rule/2*: it takes two arguments, the name of the engine
+and a tuple representing the function in the form *{Module,
+FuncName}*; obviously the function *Module:FuncName* must be
+exported. Function *add_rule* has to be called for each rule that has
+to be added; for this reason, the code above has an iteration over the
+list of rules written before.
+
+Finally, we populate the inference engine with a set of sample facts
+by giving them, in a list, to the function *eresye:assert/2*. To test
+our rules, we considered the relationships in the Figure below and
+assert only the facts for *male*, *female* and *parent*.
+
+Testing the application
+-----------------------
+
+The final complete code of our AI application is thus the following:
+
+
+ %%%
+ %%% relatives.erl
+ %%%
+ -module (relatives).
+ -compile ([export_all]).
+
+ %%
+ %% if (X is female) and (X is Y's parent) then (X is Y's mother)
+ %%
+ mother (Engine, {female, X}, {parent, X, Y}) ->
+ eresye:assert (Engine, {mother, X, Y}).
+
+
+ %%
+ %% if (X is male) and (X is Y's parent) then (X is Y's father)
+ %%
+ father (Engine, {male, X}, {parent, X, Y}) ->
+ eresye:assert (Engine, {father, X, Y}).
+
+
+
+ %%
+ %% if (Y and Z have the same parent X) and (Z is female)
+ %% then (Z is Y's sister)
+ %%
+ sister (Engine, {parent, X, Y}, {parent, X, Z}, {female, Z}) when Y =/= Z ->
+ eresye:assert (Engine, {sister, Z, Y}).
+
+
+
+ %%
+ %% if (Y and Z have the same parent X) and (Z is male)
+ %% then (Z is Y's brother)
+ %%
+ brother (Engine, {parent, X, Y}, {parent, X, Z}, {male, Z}) when Y =/= Z ->
+ eresye:assert (Engine, {brother, Z, Y}).
+
+
+ %%
+ %% if (X is Y's father) and (Y is Z's parent)
+ %% then (X is Z's grandfather)
+ %%
+ grandfather (Engine, {father, X, Y}, {parent, Y, Z}) ->
+ eresye:assert (Engine, {grandfather, X, Z}).
+
+
+ %%
+ %% if (X is Y's mother) and (Y is Z's parent)
+ %% then (X is Z's grandmother)
+ %%
+ grandmother (Engine, {mother, X, Y}, {parent, Y, Z}) ->
+ eresye:assert (Engine, {grandmother, X, Z}).
+
+ start () ->
+ eresye:start (relatives),
+ lists:foreach (fun (X) ->
+ eresye:add_rule (relatives, {?MODULE, X})
+ end,
+ [mother, father,
+ brother, sister,
+ grandfather, grandmother]),
+
+ eresye:assert (relatives,
+ [{male, bob},
+ {male, corrado},
+ {male, mark},
+ {male, caesar},
+ {female, alice},
+ {female, sara},
+ {female, jane},
+ {female, anna},
+ {parent, jane, bob},
+ {parent, corrado, bob},
+ {parent, jane, mark},
+ {parent, corrado, mark},
+ {parent, jane, alice},
+ {parent, corrado, alice},
+ {parent, bob, caesar},
+ {parent, bob, anna},
+ {parent, sara, casear},
+ {parent, sara, anna}]),
+ ok.
+
+Now it's time to test our application:
+
+
+ Erlang (BEAM) emulator version 5.5 [source] [async-threads:0] [hipe]
+
+ Eshell V5.5 (abort with ^G)
+ 1> c(relatives).
+ {ok,relatives}
+ 2> relatives:start().
+ ok
+ 3>
+
+Following the call to function *relatives:start/0*, the engine is
+created and populated; if no errors occurred, the rules should have
+been processed and the new facts derived. To check this, we can use
+the function *eresye:get_kb/1*, which returns the list of facts
+asserted into the knowledge base of a given engine:
+
+
+ 4> eresye:get_kb(relatives).
+ [{brother,bob,mark},
+ {sister,alice,bob},
+ {sister,alice,mark},
+ {brother,bob,alice},
+ {brother,mark,alice},
+ {grandmother,jane,caesar},
+ {grandfather,corrado,caesar},
+ {grandmother,jane,anna},
+ {grandfather,corrado,anna},
+ {sister,anna,caesar},
+ {brother,caesar,anna},
+ {sister,anna,casear},
+ {mother,sara,anna},
+ {mother,sara,casear},
+ {parent,sara,anna},
+ {father,bob,anna},
+ {parent,sara,casear},
+ {father,bob,caesar},
+ {parent,bob,anna},
+ {father,corrado,alice},
+ {parent,bob,caesar},
+ {mother,jane,alice},
+ {parent,corrado,alice},
+ {father,corrado,mark},
+ {parent,jane,alice},
+ {mother,jane,mark},
+ {parent,corrado|...},
+ {brother|...},
+ {...}|...]
+ 5>
+
+The presence of facts representing concepts like *father*, *sister*,
+etc., proves that the rules seems to be working as expected.
+
+We can however query the knowledge base using specific fact templates.
+For example, if we want to know who are Alice's brothers, we can use
+the function *eresye:query_kb/2* as follows:
+
+
+ 6> eresye:query_kb(relatives, {brother, '_', alice}).
+ [{brother,bob,alice},{brother,mark,alice}]
+ 7>
+
+The facts returned conform to the relationships depicted in the figure
+above, thus proving that the rules written are really working.
+
+As the example shows, function *eresye:query_kb/2* takes the engine
+name as the first argument, while, for the second parameter, a tuple
+has to be specified, representing the fact template to be matched; in
+such a tuple, the atom *'_'* plays the role of a wildcard. However, to
+specify a more complex matching, a *fun* can be used as a tuple
+element; this *fun* has to return a boolean value which indicates if
+the element matches the template. For example, to select both Alice's
+and Anna's brothers, we can use the following function call:
+
+
+ 7> eresye:query_kb(relatives, {brother, '_', fun (X) -> (X == alice) or (X == anna) end}).
+ [{brother,bob,alice},{brother,mark,alice},{brother,caesar,anna}]
+ 8>
+
+Deriving new concepts by means of rules
+---------------------------------------
+
+#### Concept: 'mother'
+
+The rule to derive the concept of mother is quite straightforward:
+
+ if X is female and X is Y's parent then X is Y's mother.
+
+From the point of view of ERESYE, since knowledge is stored in the
+*knowledge base* of the engine, the rule above is translated into the
+following one: *<u>if the facts *{female, X}* and *{parent, X, Y}* are
+**asserted** in the knowledge base, then we assert the fact *{mother,
+X, Y}*.</u>*
+
+The rule *mother* can be thus written as follows:
+
+
+ %%
+ %% if (X is female) and (X is Y's parent) then (X is Y's mother)
+ %%
+ mother (Engine, {female, X}, {parent, X, Y}) ->
+ eresye:assert (Engine, {mother, X, Y}).
+
+#### Concept: 'father'
+
+This concept can be easily derived by means of the following rule:
+
+ %%
+ %% if (X is male) and (X is Y's parent) then (X is Y's father)
+ %%
+ father (Engine, {male, X}, {parent, X, Y}) ->
+ eresye:assert (Engine, {father, X, Y}).
+
+
+#### Concept: 'sister'
+
+This concept can be expressed by the following rule:
+
+ if Y and Z have the same parent and Z is female, then Z is the Y's
+ sister.
+
+The ERESYE rule used to map this concept is:
+
+ %%
+ %% if (Y and Z have the same parent X) and (Z is female)
+ %% then (Z is Y's sister)
+ %%
+ sister (Engine, {parent, X, Y}, {parent, X, Z}, {female, Z}) when Y =/= Z ->
+ eresye:assert (Engine, {sister, Z, Y}).
+
+Please note the guard, which is needed to ensure that when Y and Z are
+bound to the same value, the rule is not activated (indeed this is possible
+since the same fact can match both the first and second
+'parent' pattern).
+
+#### Concept: 'brother'
+
+ Given the previous one, this concept is now quite simple to
+implement:
+
+ %%
+ %% if (Y and Z have the same parent X) and (Z is male)
+ %% then (Z is Y's brother)
+ %%
+ brother (Engine, {parent, X, Y}, {parent, X, Z}, {male, Z}) when Y =/= Z ->
+ eresye:assert (Engine, {brother, Z, Y}).
+
+
+#### Concepts: 'grandmother' and 'grandfather'
+
+The former concept can be expressed by means of the rule:
+
+ if X is Y's mother and Y is Z's parent, then X is Z's grandmother.
+
+The latter concept is now obvious. Both can be implemented using the
+following ERESYE rules:
+
+ %%
+ %% if (X is Y's mother) and (Y is Z's parent)
+ %% then (X is Z's grandmother)
+ %%
+ grandmother (Engine, {mother, X, Y}, {parent, Y, Z}) ->
+ eresye:assert (Engine, {grandmother, X, Z}).
+
+ %%
+ %% if (X is Y's father) and (Y is Z's parent)
+ %% then (X is Z's grandfather)
+ %%
+ grandfather (Engine, {father, X, Y}, {parent, Y, Z}) ->
+ eresye:assert (Engine, {grandfather, X, Z}).
+
+
+Conclusions
+-----------
+
+This HowTo not only shows how to use the ERESYE engine to write an AI
+application, but also highlights the versatility of the Erlang language:
+the characteristics of functional and symbolic programming, together with
+the possibility of performing *introspection* of function declaration,
+can be successfully exploited for application domains which are completely
+new for Erlang but can surely be very interesting.
+
View
18 README.txt
@@ -1,18 +0,0 @@
-
-This is ERESYE relase 1.2.5.
-----------------------------
-
-Directories contain the following material:
-
- doc/ --> some papers on ERESYE architecture and usage
- src/ --> ERESYE source code
- ebin/ --> ERESYE beam files
- include/ --> ERESYE include files
- examples/ --> Some examples
-
-
-If you want to run examples, go to "examples" and don't forget to run the
-emulator by adding "../ebin" in the Erlang path, i.e.:
-
- $ erl -pa ../ebin
-
View
2 RELEASE.txt
@@ -1,2 +0,0 @@
-THIS IS ERESYE RELEASE 1.2.5
-============================
View
41 examples/Makefile
@@ -1,41 +0,0 @@
-#
-# Makefile
-#
-
-EBIN=./
-#ERLC=erlc
-BEAM=erlc -b beam -I ../include -pa $(EBIN)
-YRL=erlc -W
-FIND=find
-
-.SUFFIXES: .erl .beam
-
-OBJS=\
-sample \
-auto \
-cannibals \
-sieve \
-phil \
-prodcons \
-wine_sample \
-journal_sample \
-relatives
-
-ERL_OBJS=$(foreach file, $(OBJS), $(EBIN)/$(file).beam)
-
-OTHER_OBJS=
-FIND=find
-
-all: $(ERL_OBJS) $(OTHER_OBJS)
-
-$(EBIN)/%.beam: %.erl
- $(BEAM) $<
-
-clean:
- @(cd $(EBIN); $(RM) -f *.beam)
-
-clearbak:
- @$(FIND) . -type f -name \*~ -exec rm {} \;
-
-run:
- erl -pa $(EBIN)
View
35 src/Makefile
@@ -1,35 +0,0 @@
-#
-# Makefile
-#
-
-EBIN=../ebin/
-#ERLC=erlc
-BEAM=erlc -b beam -I ../include -o $(EBIN)
-YRL=erlc -W
-FIND=find
-
-.SUFFIXES: .erl .beam
-
-OBJS=\
-eresye \
-eresye_agenda \
-eresye_tree_list \
-eresye_ontology \
-eresye_ontology_resolver
-
-ERL_OBJS=$(foreach file, $(OBJS), $(EBIN)/$(file).beam)
-
-OTHER_OBJS=
-FIND=find
-
-all: $(ERL_OBJS) $(OTHER_OBJS)
-
-$(EBIN)/%.beam: %.erl
- $(BEAM) $<
-
-clean:
- @(cd $(EBIN); $(RM) -f *.beam)
-
-clearbak:
- @$(FIND) . -type f -name \*~ -exec rm {} \;
-

0 comments on commit a7d0336

Please sign in to comment.