pax_global_header00006660000000000000000000000064124701544060014515gustar00rootroot0000000000000052 comment=9cd92b219ad97869d9da19ee4ea25ba1a40aea98 xmlrpc-1.15/000077500000000000000000000000001247015440600127505ustar00rootroot00000000000000xmlrpc-1.15/.gitignore000066400000000000000000000000171247015440600147360ustar00rootroot00000000000000.project ebin/ xmlrpc-1.15/LICENSE000066400000000000000000000023671247015440600137650ustar00rootroot00000000000000Copyright (C) 2003 Joakim Grebenö . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. xmlrpc-1.15/Makefile000066400000000000000000000016311247015440600144110ustar00rootroot00000000000000ifeq ($(DEBUG),true) DEBUG_FLAGS = -DDEBUG else DEBUG_FLAGS = endif XMLRPC_SOURCE_ROOT=. XMLRPC_INCLUDE_DIR=$(XMLRPC_SOURCE_ROOT)/include SOURCE_DIR=src EBIN_DIR=ebin INCLUDE_DIR=include INCLUDES=$(wildcard $(INCLUDE_DIR)/*.hrl) SOURCES=$(wildcard $(SOURCE_DIR)/*.erl) TARGETS=$(patsubst $(SOURCE_DIR)/%.erl, $(EBIN_DIR)/%.beam,$(SOURCES)) #other args: +native +"{hipe,[o3,verbose]}" -Ddebug=true +debug_info +no_strict_record_tests ERLC_OPTS=-I $(XMLRPC_INCLUDE_DIR) -I $(INCLUDE_DIR) -o $(EBIN_DIR) $(DEBUG_FLAGS) -DTEST -Wall +debug_info ERL_CALL=erl -pa $(EBIN_DIR) all: $(EBIN_DIR) $(TARGETS) $(EBIN_DIR): mkdir -p $@ $(EBIN_DIR)/%.beam: $(SOURCE_DIR)/%.erl $(INCLUDES) erlc $(ERLC_OPTS) $< run-tests: all $(ERL_CALL) \ -eval 'eunit:test("ebin", [verbose])' \ -s init stop dialyze: $(TARGETS) dialyzer -c $? clean: rm -f ebin/*.beam $(TARGETS) rm -f build-stamp install-stamp distclean: clean xmlrpc-1.15/README000066400000000000000000000016141247015440600136320ustar00rootroot00000000000000This is an HTTP 1.1 compliant XML-RPC library for Erlang. It is designed to make it easy to write XML-RPC Erlang clients and/or servers. The library is compliant with the XML-RPC specification published by http://www.xmlrpc.org/. Prior to using this library you need a recent installation of Erlang (Erlang/OTP R12). In order to compile the library run make on top level. You are now ready to try the client and server examples in the examples/ directory. Do not forget to read doc/xmlrpc.3 (or xmlrpc.txt, xmlrpc.ps, xmlrpc.pdf) for a detailed API description. Get the latest version of this library at http://github.com/rds13/xmlrpc/ . This library is a hack over http://ejabberd.jabber.ru/files/contributions/xmlrpc-1.13-ipr2.tgz to add support for custom HTTP headers, https transport and case insensitive HTTP header support. Custom HTTP headers allow to send cookies between client and server. xmlrpc-1.15/examples/000077500000000000000000000000001247015440600145665ustar00rootroot00000000000000xmlrpc-1.15/examples/BankClient.java000066400000000000000000000026131247015440600174450ustar00rootroot00000000000000import org.apache.xmlrpc.*; import java.util.*; public class BankClient { public static void main(String[] args) { if (args.length < 2) { System.err.println("Usage: BankClient deposit Account Amount"); System.err.println(" BankClient withdraw Account Amount"); System.err.println(" BankClient balance Account"); System.exit(-1); } if (!ask(3020, args)) if (!ask(3030, args)) System.err.println("No bank server available"); } private static boolean ask(int port, String[] args) { try { // This is obviously not a unique tag. String tag = new String(Long.toString(System.currentTimeMillis())); XmlRpcClient xmlrpc = new XmlRpcClient("http://localhost:"+port+"/"); Vector params = new Vector(); params.addElement(tag); params.addElement(new String(args[1])); if (args[0].equals("deposit")) { params.addElement(new Integer(Integer.parseInt(args[2]))); System.out.println(xmlrpc.execute("deposit", params)); return true; } if (args[0].equals("withdraw")) { params.addElement(new Integer(Integer.parseInt(args[2]))); System.out.println(xmlrpc.execute("withdraw", params)); return true; } if (args[0].equals("balance")) { System.out.println(xmlrpc.execute("balance", params)); return true; } } catch (Exception e) { System.err.println(e); } return false; } } xmlrpc-1.15/examples/DateClient.java000066400000000000000000000023441247015440600174500ustar00rootroot00000000000000import org.apache.xmlrpc.*; import java.util.*; public class DateClient { public static void main(String[] args) { try { XmlRpcClient xmlrpc = new XmlRpcClient("http://localhost:4567/"); // Login Vector login_params = new Vector(); login_params.addElement(new String("Slarti")); login_params.addElement(new String("Bartfast")); System.out.println(xmlrpc.execute("login", login_params)); // Call 'days_since' function Hashtable ymd = new Hashtable(); ymd.put("y", new Integer(2001)); ymd.put("m", new Integer(12)); ymd.put("d", new Integer(20)); Hashtable calc = new Hashtable(); calc.put("days_since", ymd); Vector calc_params = new Vector(); calc_params.add(calc); System.out.println(xmlrpc.execute("calc", calc_params)); // Call 'days_since', 'day_of_week' and 'is_leap_year' functions calc.put("day_of_week", ymd); calc.put("is_leap_year", new Integer(2000)); Vector calc_params2 = new Vector(); calc_params2.addElement(calc); System.out.println(xmlrpc.execute("calc", calc_params2)); // Logout System.out.println(xmlrpc.execute("logout", new Vector())); } catch (Exception e) { System.err.println(e); } } } xmlrpc-1.15/examples/EchoClient.java000066400000000000000000000007371247015440600174550ustar00rootroot00000000000000import org.apache.xmlrpc.*; import java.util.*; public class EchoClient { public static void main(String[] args) { try { XmlRpcClient xmlrpc = new XmlRpcClient("http://localhost:4567/"); Vector params = new Vector(); params.addElement(new Double(42.5)); params.addElement(new String("foo")); params.addElement(new Integer(7)); System.out.println(xmlrpc.execute("echo", params)); } catch (Exception e) { System.err.println(e); } } } xmlrpc-1.15/examples/FibClient.java000066400000000000000000000010041247015440600172630ustar00rootroot00000000000000import org.apache.xmlrpc.*; import java.util.*; public class FibClient { public static void main(String[] args) { try { if (args.length != 1) { System.err.println("Usage: FibClient N"); System.exit(-1); } XmlRpcClient xmlrpc = new XmlRpcClient("http://localhost:4567/"); Vector params = new Vector(); params.addElement(new Integer(Integer.parseInt(args[0]))); System.out.println(xmlrpc.execute("fib", params)); } catch (Exception e) { System.err.println(e); } } } xmlrpc-1.15/examples/Makefile000066400000000000000000000012711247015440600162270ustar00rootroot00000000000000# Update the APACHE_XMLRPC_PATH variable to point at your Apache # XML-RPC installation. This is only necessary if you intend to # compile the Java clients. APACHE_XMLRPC_PATH=../../apache/xmlrpc/bin/xmlrpc-1.1.jar # Do not change anything below this line. ERLC=erlc ERLC_FLAGS=-W MODULES=date_server echo_server fib_server validator EBIN_FILES=$(MODULES:%=%.beam) JAVAC=javac JAVAC_FLAGS=-classpath $(APACHE_XMLRPC_PATH):. JAVA_FILES=FibClient EchoClient DateClient BankClient CLASS_FILES=$(JAVA_FILES:%=%.class) all: $(EBIN_FILES) java_clients: $(CLASS_FILES) %.beam: %.erl $(ERLC) $(ERLC_FLAGS) $< %.class: %.java $(JAVAC) $(JAVAC_FLAGS) $< clean: rm -f $(EBIN_FILES) $(CLASS_FILES) xmlrpc-1.15/examples/README000066400000000000000000000141751247015440600154560ustar00rootroot00000000000000This directory contains five example Erlang XML-RPC servers. Four of them are desribed in this README file. The fifth server is an example of robust banking system and is described in a separate tutorial (robust_banking.txt). The servers are small and silly but together they utilize a majority of the functionality provided by the library. The first example (fib_server.erl) calculates Fibonacci values and is a non-keepalive server. The second example (echo_server.erl) echoes back any incoming parameters and is a non-keepalive server. The third example (date_server.erl) calculates calendar values for given dates and is a keepalive server which uses the state variable to provide login state and different timeout settings. The fourth example (validator.erl) is a validation server which can be used to validate the library using the http://validator.xmlrpc.org/ service. Run make to compile the servers. You need to replace "../../xmerl/ebin" below to point at your installation of the xmerl package. If you intend to verify inter-operability with the example Java clients you need to replace "../../apache/xmlrpc/bin/xmlrpc-1.1.jar" below to point at your installation of the Apache XML-RPC library. Get it at http://www.apache.org/. You furthermore need a recent installation of Java/JDK. Get it at http://java.sun.com/. Run 'make java_clients' to compile the Java clients. Example 1: fib_server.erl ------------------------- $ erl -pa ../ebin -pa ../../xmerl/ebin Erlang (BEAM) emulator version 5.1.2.b2 [source] Eshell V5.1.2.b2 (abort with ^G) 1> {ok, Pid} = xmlrpc:start_link({fib_server, handler}). {ok,<0.30.0>} 2> xmlrpc:call({127, 0, 0, 1}, 4567, "/", {call, foo, []}). {ok,{response,{fault,-1,"Unknown call: {call,foo,[]}"}}} 3> xmlrpc:call({127, 0, 0, 1}, 4567, "/", {call, fib, [0]}). {ok,{response,[1]}} 4> xmlrpc:call({127, 0, 0, 1}, 4567, "/", {call, fib, [4]}). {ok,{response,[5]}} Nothing fancy. Uses a new HTTP connection for each call and handles unknown method calls gracefully. FibClient.java could as well has been used to call the Fibonacci server: $ java -classpath ../../apache/xmlrpc/bin/xmlrpc-1.1.jar:. FibClient 0 1 $ java -classpath ../../apache/xmlrpc/bin/xmlrpc-1.1.jar:. FibClient 4 5 Stop the Fibonacci server: 5> xmlrpc:stop(Pid). stop Example 2: echo_server.erl -------------------------- $ erl -pa ../ebin -pa ../../xmerl/ebin Erlang (BEAM) emulator version 5.1.2.b2 [source] Eshell V5.1.2.b2 (abort with ^G) 1> {ok, Pid} = xmlrpc:start_link({echo_server, handler}). {ok,<0.30.0>} 2> xmlrpc:call({127, 0, 0, 1}, 4567, "/", {call, foo, []}). {ok,{response,{fault,-1,"Unknown call: {call,foo,[]}"}}} 3> xmlrpc:call({127, 0, 0, 1}, 4567, "/", {call, echo, [42.0]}). {ok,{response,[{array, [42.0000]}]}} 4> xmlrpc:call({127, 0, 0, 1}, 4567, "/", {call, echo, [2.6, {array, [5, "foo"]}, {struct, [{baz, 1}, {bar, {base64, "SDOMCVN=-kmDC*="}}]}]}). {ok,{response,[{array,[2.60000, {array,[5,"foo"]}, {struct,[{baz,1},{bar,{base64,"SDOMCVN=-kmDC*="}}]}]}]}} The parameters are converted from Erlang to XML format before being sent to the server. When the parameters arrive at the server they are converted back to Erlang format. The server handler echoes the parameters back as a response to the client, i.e. in the process converting the parameters back to XML format. The response arrives at the client which finally convert the parameters back to Erlang format. Nothing fancy. Uses a new HTTP connection for each call and handles unknown method calls gracefully. EchoClient.java could as well has been used to call the echo server: $ java -classpath ../../apache/xmlrpc/bin/xmlrpc-1.1.jar:. EchoClient [42.5, foo, 7] Stop the echo server: 5> xmlrpc:stop(Pid). stop Example 3: date_server.erl -------------------------- $ erl -pa ../ebin -pa ../../xmerl/ebin Erlang (BEAM) emulator version 5.1.2.b2 [source] Eshell V5.1.2.b2 (abort with ^G) 1> xmlrpc:start_link(4567, 1000, 300000, {date_server, handler}, {false, 0}). {ok,<0.30.0>} 2> xmlrpc:call({127, 0, 0, 1}, 4567, "/", {call, calc, [{struct, [{is_leap_year, 1492}]}]}, true, 300000). {ok,#Port<0.32>,{response,{fault,-3,"Not authenticated"}}} 3> xmlrpc:call({127, 0, 0, 1}, 4567, "/", {call, login, ["Foo", "Bar"]}, true, 300000). {ok,#Port<0.40>,{response,{fault,-1,"Invalid authentication"}}} 4> {ok, S, _} = xmlrpc:call({127, 0, 0, 1}, 4567, "/", {call, login, ["Slarti", "Bartfast"]}, true, 300000). {ok,#Port<0.42>,{response,["ok"]}} 5> xmlrpc:call(S, "/", {call, login, ["Slarti", "Bartfast"]}, true, 300000). {ok,#Port<0.42>,{response,{fault,-2,"Already authenticated"}}} 6> xmlrpc:call(S, "/", {call, foo, []}, true, 300000). {ok,#Port<0.42>,{response,{fault,-4,"Unknown call: {call,foo,[]}"}}} 7> xmlrpc:call(S, "/", {call, calc, [{struct, [{is_leap_year, 1492}]}]}, true, 300000). {ok,#Port<0.42>,{response,[{array,[3,{struct,[{is_leap_year,true}]}]}]}} 8> xmlrpc:call(S, "/", {call, calc, [{struct, [{is_leap_year, 2010}]}]}, true, 300000). {ok,#Port<0.42>,{response,[{array,[4,{struct,[{is_leap_year,false}]}]}]}} 9> xmlrpc:call(S, "/", {call, calc, [{struct, [{is_leap_year, 2010}, {days_since, {struct, [{y, 2002}, {m, 12}, {d, 10}]}}]}]}, true, 300000). {ok,#Port<0.42>, {response,[{array,[5,{struct,[{is_leap_year,false},{days_since,731559}]}]}]}} 10> xmlrpc:call(S, "/", {call, logout, []}). {ok,{response,["ok"]}} 11> xmlrpc:call(S, "/", {call, calc, [{struct, [{is_leap_year, 2010}]}]}, true, 300000). {error,#Port<0.42>,closed} DateClient.java could as well has been used to call the date server: $ java -classpath ../../apache/xmlrpc/bin/xmlrpc-1.1.jar:. DateClient ok [1, {days_since=731204}] [2, {days_since=731204, day_of_week=Thursday, is_leap_year=true}] ok Stop the date server: 12> xmlrpc:stop(Pid). stop Example 4: validator.erl -------------------------- $ erl -pa ../ebin -pa ../../xmerl/ebin Erlang (BEAM) emulator version 5.1.2.b2 [source] Eshell V5.1.2.b2 (abort with ^G) 1> {ok, Pid} = xmlrpc:start_link({validator, handler}). {ok,<0.30.0>} If your computer is connected to the Internet you can now verify that the library is compliant with the validation service at http://validator.xmlrpc.org/. Stop the validator server: 2> xmlrpc:stop(Pid). stop xmlrpc-1.15/examples/date_server.erl000066400000000000000000000044061247015440600176010ustar00rootroot00000000000000-module(date_server). -export([handler/2]). %% %% A server which calculates date value(s) such as: %% %% * Calculates the number of days since year 0 for a given date. %% * Calculates if a given date is a leap year. %% * Calculates the day of the week for a given day. %% %% In order to perform the calculation a client must login with %% username "Slarti" and password "Bartfast". After login the HTTP/1.1 %% keepalive timeout is set to infinity. The server returns a session %% counter for each call using the state variable. %% handler({false, N}, {call, login, ["Slarti", "Bartfast"]}) -> {true, infinity, {true, N+1}, {response, ["ok"]}}; handler({false, N}, {call, login, [_, _]}) -> {false, {response, {fault, -1, "Invalid authentication"}}}; handler({true, N}, {call, login, [_, _]}) -> {true, infinity, {true, N+1}, {response, {fault, -2, "Already authenticated"}}}; handler({true, N}, {call, logout, []}) -> {false, {response, ["ok"]}}; handler({true, N}, {call, calc, [{struct, Elements}]}) -> {true, infinity, {true, N+1}, {response, [{array, [N, {struct, calc(Elements)}]}]}}; handler({false, N}, {call, calc, Params}) -> {false, {response, {fault, -3, "Not authenticated"}}}; handler({Status, N}, Payload) -> FaultString = lists:flatten(io_lib:format("Unknown call: ~p", [Payload])), {true, 300000, {Status, N+1}, {response, {fault, -4, FaultString}}}. calc([]) -> []; calc([{days_since, {struct, Elements}}|Rest]) -> {Y, M, D} = extract_date(Elements), [{days_since, calendar:date_to_gregorian_days({Y, M, D})}| calc(Rest)]; calc([{is_leap_year, Y}|Rest]) -> [{is_leap_year, calendar:is_leap_year(Y)}|calc(Rest)]; calc([{day_of_week, {struct, Elements}}|Rest]) -> {Y, M, D} = extract_date(Elements), [{day_of_week, day(calendar:day_of_the_week(Y, M, D))}|calc(Rest)]. extract_date(Elements) -> extract_date(Elements, 0, 0, 0). extract_date([], Y, M, D) -> {Y, M, D}; extract_date([{y, Y}|Rest], _, M, D) -> extract_date(Rest, Y, M, D); extract_date([{m, M}|Rest], Y, _, D) -> extract_date(Rest, Y, M, D); extract_date([{d, D}|Rest], Y, M, _) -> extract_date(Rest, Y, M, D). day(1) -> "Monday"; day(2) -> "Tuesday"; day(3) -> "Wednesday"; day(4) -> "Thursday"; day(5) -> "Friday"; day(6) -> "Saturday"; day(7) -> "Sunday". xmlrpc-1.15/examples/echo_server.erl000066400000000000000000000005241247015440600175770ustar00rootroot00000000000000-module(echo_server). -export([handler/2]). %% %% A server which echoes back any incoming parameters. %% handler(_, {call, echo, Params}) -> {false, {response, [{array, Params}]}}; handler(_, Payload) -> FaultString = lists:flatten(io_lib:format("Unknown call: ~p", [Payload])), {false, {response, {fault, -1, FaultString}}}. xmlrpc-1.15/examples/fib_server.erl000066400000000000000000000006201247015440600174160ustar00rootroot00000000000000-module(fib_server). -export([handler/2]). %% %% A server which calculates Fibonacci values. %% handler(_State, {call, fib, [N]}) when integer(N) -> {false, {response, [fib(N)]}}; handler(_State, Payload) -> FaultString = lists:flatten(io_lib:format("Unknown call: ~p", [Payload])), {false, {response, {fault, -1, FaultString}}}. fib(0) -> 1; fib(1) -> 1; fib(N) -> fib(N-1)+fib(N-2). xmlrpc-1.15/examples/reply.hrl000066400000000000000000000000351247015440600164260ustar00rootroot00000000000000 -record(reply, {tag, val}). xmlrpc-1.15/examples/robust_bank_client.erl000066400000000000000000000015151247015440600211430ustar00rootroot00000000000000-module(robust_bank_client). -export([deposit/2, withdraw/2, balance/1]). deposit(Who, X) -> robust_xmlrpc(deposit, [Who, X]). withdraw(Who, X) -> robust_xmlrpc(withdraw, [Who, X]). balance(Who) -> robust_xmlrpc(balance, [Who]). robust_xmlrpc(F, A) -> Tag = mk_tag(), case call(3020, Tag, F, A) of {error, Reason} -> call(3030, Tag, F, A); Result -> Result end. mk_tag() -> {MegaSecs, Secs, MicroSecs} = erlang:now(), lists:concat([atom_to_list(node()), ".", integer_to_list(MegaSecs), ".", integer_to_list(Secs), ".", integer_to_list(MicroSecs)]). call(Port, Tag, F, A) -> case xmlrpc:call("localhost", Port, "/", {call, F, [Tag|A]}, false, 10000) of {error, Reason} -> {error, Reason}; {ok, Result} -> xmlrpc:call("localhost", Port, "/", {call, delete_tag, [Tag]}), Result end. xmlrpc-1.15/examples/robust_bank_server.erl000066400000000000000000000027671247015440600212050ustar00rootroot00000000000000-module(robust_bank_server). -export([start/1, stop/1]). -export([handler/2]). % internal -include("reply.hrl"). start(Port) -> mnesia:start(), xmlrpc:start_link(Port, 100, 60*1000, {?MODULE, handler}, undefined). stop(Pid) -> mnesia:stop(), xmlrpc:stop(Pid). handler(_, {call, deposit, [Tag, Who, X]}) -> {false, {response, [lookup(Tag, deposit, [Who, X])]}}; handler(_, {call, withdraw, [Tag, Who, X]}) -> case lookup(Tag, withdraw, [Who, X]) of ok -> {false, {response, ["ok"]}}; {error, Reason} -> FaultString = lists:flatten(io_lib:format("~p", [Reason])), {false, {response, {fault, -1, FaultString}}} end; handler(_, {call, balance, [Tag, Who]}) -> case lookup(Tag, balance, [Who]) of {ok, Result} -> {false, {response, [Result]}}; {error, Reason} -> FaultString = lists:flatten(io_lib:format("~p", [Reason])), {false, {response, {fault, -2, FaultString}}} end; handler(_, {call, delete_tag, [Tag]}) -> mnesia:transaction(fun() -> mnesia:delete({reply, Tag}) end), {false, {response, ["ok"]}}. lookup(Tag, F, A) -> Fun = fun() -> case mnesia:read({reply, Tag}) of [] -> Val = get_val(F, A), mnesia:write(#reply{tag = Tag, val = Val}), Val; [Reply] -> Reply#reply.val end end, {atomic, Result} = mnesia:transaction(Fun), Result. get_val(deposit, [Who, X]) -> (bank:deposit(Who, X))(); get_val(withdraw, [Who, X]) -> (bank:withdraw(Who, X))(); get_val(balance, [Who]) -> (bank:balance(Who))(). xmlrpc-1.15/examples/robust_banking.txt000066400000000000000000000077341247015440600203510ustar00rootroot00000000000000This is a companion to Joe Armstrong's tutorial on how to build a fault-tolerant banking server in Erlang: http://www.sics.se/~joe/tutorials/robust_server/robust_server.html You *should* read Joe's tutorial before you go any further. You have been warned! 1 A fault-tolerant banking server using XML-RPC ----------------------------------------------- It is easy to update Joe's banking server with XML-RPC support. Just replace the robust_bank_server.erl and robust_bank_client.erl modules with the drop-in replacements found in this directory. Do that. The original modules look like this: http://www.sics.se/~joe/tutorials/robust_server/robust_bank_server.erl http://www.sics.se/~joe/tutorials/robust_server/robust_bank_client.erl They are actually larger than the XML-RPC ditto. There is also a Java application (BankClient.java) which can be used to access the banking server. More on that below. 1.1 Initializing the data-base ------------------------------ This assumes that there are two nodes called one@enfield and two@enfield. To initialize the system open two terminal windows (on enfield) and proceed as follows: Note: You *must* update the paths to the xmerl and xmlrpc packages. ** In terminal 1: $ erl -pa xmlrpc-1.11/ebin -pa xmerl-0.18/ebin -sname one -mnesia dir '"one"' Erlang (BEAM) emulator version 5.2 [source] [hipe] Eshell V5.2 (abort with ^G) ** In terminal 2: $ erl -pa xmlrpc-1.11/ebin -pa xmerl-0.18/ebin -sname two -mnesia dir '"two"' Erlang (BEAM) emulator version 5.2 [source] [hipe] Eshell V5.2 (abort with ^G) (two@enfield)1> robust_bank_manager:create_schema(). ok (two@enfield)2> mnesia:start(). ok ** In terminal 1: (one@enfield)1> mnesia:start(). ok (one@enfield)2> robust_bank_manager:create_table(). 1.2. Now we are ready to run everything --------------------------------------- We are now ready to start the banking server on the two nodes: ** In terminal 1: (one@enfield)3> robust_bank_server:start(3020). {ok,<0.102.0>} ** In terminal 2: (two@enfield)3> robust_bank_server:start(3030). {ok,<0.102.0>} The XML-RPC based banking server has now been started. We open a third terminal window and start an Erlang node to be used as a client: ** In terminal 3: $ erl -pa xmlrpc-1.11/ebin -pa xmerl-0.18/ebin Erlang (BEAM) emulator version 5.2 [source] [hipe] Eshell V5.2 (abort with ^G) 1> robust_bank_client:deposit("joe", 7). {response,[7]} 2> robust_bank_client:balance("joe"). {response,[7]} Both servers are running - server one replies. Kill server one redo the query: 3> robust_bank_client:balance("joe"). {response,[7]} This time server 2 replies (we killed server one, remember). Make a deposit. We make a deposit of 10 units: 4> robust_bank_client:deposit("joe", 10). {response,[17]} Only server two is running - so the transaction takes place on server two. Restart server one and query the balance: 5> robust_bank_client:balance("joe"). {response,[17]} Server one replies with 17 units. Well done server one. When server one was restarted - the two servers synced their data and the changes made to server two were propagated to server one. Kill server two and query the balance: 6> robust_bank_client:balance("joe"). {response,[17]} Server one replied. 1.3 Lets try the Java client ----------------------------- $ java -classpath apache/xmlrpc/bin/xmlrpc-1.1.jar:. BankClient deposit joe 22 39 $ java -classpath apache/xmlrpc/bin/xmlrpc-1.1.jar:. BankClient withdraw joe 2 ok $ java -classpath apache/xmlrpc/bin/xmlrpc-1.1.jar:. BankClient balance joe 37 $ java -classpath apache/xmlrpc/bin/xmlrpc-1.1.jar:. BankClient withdraw joe 2000 org.apache.xmlrpc.XmlRpcException: not_enough_money java.io.IOException: Connection refused No bank server available etc. 2 Summing up ------------ The intention here was not to make the ultimate fault-tolerant server, but rather to illustrate how to make a simple functioning server, with no detail omitted. A production server could be based on this simple design, but would involve a slightly less simplistic approach. xmlrpc-1.15/examples/validator.erl000066400000000000000000000043141247015440600172610ustar00rootroot00000000000000-module(validator). -export([handler/2]). -record(e, {lt = 0, gt = 0, amp = 0, apos = 0, quot = 0}). handler(_, {call, 'validator1.arrayOfStructsTest', [{array, Array}]}) -> {false, {response, [sum_array(Array)]}}; handler(_, {call, 'validator1.countTheEntities', [String]}) -> {false, {response, [count(String, #e{})]}}; handler(_, {call, 'validator1.easyStructTest', [{struct, Elements}]})-> {false, {response, [sum_struct(Elements)]}}; handler(_, {call, 'validator1.echoStructTest', [Struct]}) -> {false, {response, [Struct]}}; handler(_, {call, 'validator1.manyTypesTest', Params}) -> {false, {response, [{array, Params}]}}; handler(_, {call, 'validator1.moderateSizeArrayCheck', [{array, Values}]}) -> {false, {response, [hd(Values)++hd(lists:reverse(Values))]}}; handler(_, {call, 'validator1.nestedStructTest', [{struct, Years}]}) -> {value, {_, {struct, Months}}} = lists:keysearch('2000', 1, Years), {value, {_, {struct, Days}}} = lists:keysearch('04', 1, Months), {value, {_, {struct, Elements}}} = lists:keysearch('01', 1, Days), {false, {response, [sum_struct(Elements)]}}; handler(_, {call, 'validator1.simpleStructReturnTest', [N]}) -> Elements = [{times10, N*10}, {times100, N*100}, {times1000, N*1000}], {false, {response, [{struct, Elements}]}}. sum_array([]) -> 0; sum_array([{struct, Elements}|Rest]) -> {value, {_, N}} = lists:keysearch('curly', 1, Elements), N+sum_array(Rest). count([], E) -> {struct, [{ctLeftAngleBrackets, E#e.lt}, {ctRightAngleBrackets, E#e.gt}, {ctAmpersands, E#e.amp}, {ctApostrophes, E#e.apos}, {ctQuotes, E#e.quot}]}; count([$<|Rest], #e{lt = LT} = E) -> count(Rest, E#e{lt = LT+1}); count([$>|Rest], #e{gt = GT} = E) -> count(Rest, E#e{gt = GT+1}); count([$&|Rest], #e{amp = AMP} = E) -> count(Rest, E#e{amp = AMP+1}); count([$'|Rest], #e{apos = APOS} = E) -> count(Rest, E#e{apos = APOS+1}); count([$"|Rest], #e{quot = QUOT} = E) -> count(Rest, E#e{quot = QUOT+1}); count([_|Rest], E) -> count(Rest, E). sum_struct([]) -> 0; sum_struct([{moe, N}|Rest]) -> N+sum_struct(Rest); sum_struct([{larry, N}|Rest]) -> N+sum_struct(Rest); sum_struct([{curly, N}|Rest]) -> N+sum_struct(Rest); sum_struct([_|Rest]) -> sum_struct(Rest). xmlrpc-1.15/include/000077500000000000000000000000001247015440600143735ustar00rootroot00000000000000xmlrpc-1.15/include/xmlrpc.hrl000066400000000000000000000030741247015440600164130ustar00rootroot00000000000000%% Copyright (C) 2003 Joakim Grebenö . %% All rights reserved. %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions %% are met: %% %% 1. Redistributions of source code must retain the above copyright %% notice, this list of conditions and the following disclaimer. %% 2. 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. %% %% THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. -record(header, { %% int() content_length, %% string() content_type, %% string() user_agent, %% close | undefined connection, %% string() authorization, %% string() xforwardedfor, %% list() cookies }). xmlrpc-1.15/rebar000077500000000000000000003303421247015440600137760ustar00rootroot00000000000000#!/usr/bin/env escript %%! -noshell -noinput PK@;+ getopt.beamXkpuc J .$J-)|, P"hQ$HN,I .$1Z**:vN5LӇ[m'Q}tN3Ihѯ3m3.E0nSΜs=ssKNx(m:m獮3[e?g֫\lFc3[,Wu>0;!kۨ/fn4jR`ŨI5*O,v@sNbxYa(90n ijŽ Ȃ *]=UQݡ B jL!,+(AUȈ:F"c]Ka$|$nԢ="qR2n("$97RFzHzwձJOyk-=0߾=|罰dU>eE,δ,U].'U%˒*qVqUJIe8P|?\j2% S|pHUYz#NA"|z?rD L#bW2EYU3$gQ`yMYs7J#PVLuN NeI=IG_syptkSp1ReQF&IM3)! B)X,fe] I*, Q4D+J{6fc[q![o %ғ,%ꢴʤHӉÞaiSY񓀪JOj.4IktpU«ɊUe H6jc(K8`sdWCͩvj8 H,`> +?$U<&8픳*1Ī Kcp1NP/$Rrz6vsʯ‹tX@%!JV#*=%QtAT^>2R`w;KrTm5$Qb07 q$r ׳La?3~f+uX_Hg[J,Fy]>2-Ɣ b"(8| [x38.O$Z"EGqPnJSӑ4"#yVDY׹U?[U"4HQy%tZIєVXECj!ci ^ӄvD2oQt eF zLZQ:$z(&17QQJ%iݓ18TRta|0ZG@'4''ĭc™xGo(WjnEo|LkZV}+O;';-&˙XV*xS݇QĹbޔMN`CÈ͵ׯ#ItH3%µ6l߂rUm"\9@nw ̠;h Y|V:[<v| @]nPȓo]>Б=O<ߛSOw9?;bK(XZcE)_{659LQE-b3i5-p*>$32NG# sZU~CrJD kX^RҚ|wdȞׅ{XDgiF6F1ٔ(u( y8 F[Y٢ȩH Uf1/cfEV1QRpbæTdP<-}CU)E녘!_]m%0\AJ&as: UՖDR6UɄ= 0YŞS4 mL$rAUaDei@<:eJN$ H;2 mФ1ddS_d(-(]OrR0ɽܗT _ sJ-X!E5ē㉾d!퇙PTJ=Geuh,hM8x:-mG-H!!NnWbY8.b{mPF<6e8N%;,Fu0 2Gň.7bp`nodkWgOE8 ד'@AA $Zp:0Ơ9Z5wܳ^95sZ5Um68m9ze=D)N ;G6rZĶ"dq3DKc$Bc@+'_-cM,$,+ u+sǶ)"(PRP4(iXU`ޅ܍,A/B-@b]d ĠkeyW (sq|5#: U`fq0[c$fv F81If\w2/'{)| w5;E&mƘjŐeI~%MlfK{7݂M((mPA|ijėbKۖŨNF8vxUF,H|"k&x0E\ ǠVƑUW +*YEq@Q4 /="UQaR1¢g$d;}t̵[ *p(j?[Og)",|$fJuq'if*l6̯N[O>W6]1r1NxpL'ǹwƹ1@ڭrNM55*80;?i<>7..kʊ'O8렞6ޛЛ^ \p.#pNCcg|8 Yȇޑ`0#op=WGo, |܃Ӂnqrx`"Apw0 dJ4\?rƻ7%=TnZ切Y4΄~4<5uc3l|0*ea弐C|-4U#ׄNb4F3==ڐ_V[le1943V!Rb1l<Uy`nQ}렚[V"[wƝǭw`fϳSpRDR385`Tݬmb9ȐAdiqyY ,#Xu9%s 풮' c[!~#@[$ '+3YQ+bflfHJ/f.ojI-͂<(/& Iϵ-u-j@^@uz^:o뙬 uޠǟZjDnXW!'3+m;YRY3ϑ}E{>'7 /k8w~yjuW|ub7ժ!.ۉG]Ϭ3\u7~^K~t__2޳oHnц^*;z$ʢ?>piM oڼܨVR^]*>~Fq/sq][~2g^y:lԖ ?;p^^Hkcvpƣ;>Xs/>rb] }rAî#;g¯?X|ÓŨe(fJNjWljA eӉnPn/{f=er;TU-d'2 b; ?G}sj}~q\K ̑:T)g(9,t+rZM&jnw&\g$d|H9Fڇp:3<Q%3j,roHK4匘UήTA\< hV| )Ȍj|X0VqF=bL'3JT֭NetHtq PwK)1ӭ$Q5]TZH7ԥh];Z-޴J6PK@F8{ G rebar.appVMo0 WrzJ˰a"0dδ1>)64͇$"ߣ)zj-k_Tovw=];nV+s |LR5sn$ V|-7q} 5޼F0.>--޻hxơH cL0uK$=wP>h5@x"C] >VcVIwPyAKƱVދXA&@{N94J`c}GW*=,`㍠Х i9y,D2~0^zv൹j}p?mna']DLGVU5@g= !9a}, ;;E[wNZmc,pOݻ3~ZKW/]<;idԾEθ ;^fk/4Dӏhlxr{UX8g`T.VpoٖG A 5,)?) >)4p&B |vk>3 h 9{4p012b[ά PK@Fel_} rebar.beamX xն4I'}Q ) M_h'}-Ni6ęy9Y{*RUAQsV9y(GkOVfctebXej_0 "oDU(j^p^CnOo8y*9C[8Ӽ{xOZ!ҺxG|h EPݚ^y9Ok ,U;n_ yu5>xar<@zjF^'P'o BnA9x-j/1J/YԠ{;Um۫A Nx"3hY]À1LBb!`pvAJFErT|+JIan6@.g|TJt(r<!%e>(U[)Xs:Ȯ1;g" 0Kd!q Q8Yv5kerzeByzXnod僐|Z<LɅ \wQQႏzTF8p[a .prE#E8Z|\6lRnX` C; qCN$C;xےGx+A*9iʕCT+,tB~ORt&%+kN§* c>]g,l A>WO+<™`"y0?9,WV, bVtUYJ!JN7! RHX!eKQm>hR(< oQtg*6өӡ݊.;2t*fmhVvAeSJ<_2[}K7ohNL_ٗjd\KS{3XL<{l]H|vjΏݺhpgOߵsڽ\\ڵo͖g^q铆3ogk-MCvuaNʋ%W}ʎ{tykՍ%ޞ?7I˯sGWe߳uƇI"O2ZNlĆXG*ֳ)J6][G4\Zkӷ6 Lb觧8v?ߔaPh`.=,}&LdYf߱/7'Ώ'/^%sN) ' _JeL/I'/RTg㏝olI?Q qRh?d3q=o|<2/l}ڇ.lIѶ4[ x"jn=wUO;?];=w<`jO~xT̏Q'fxCicQҎe?{` Ou_ܺyOFl鿯Qz/uCxWq}ե> !,K/VOץ]+Vc\Unk >BoKw+8[ulKq]sSԥ26-Y[u[ş:>4ݻNwiu7[xVÉ6Nz~̲LyG=ωg}qL@~7|j<;ŋy1|mݬumրظ_vy{C5LرVʺG%|rQ͕'[yY(ڲ=#O+|hwԮIq se>{sչ]B lzU,xGvoMwG%JF"GwV£^/Uxt'(ެܩVE2Gwq'+wa[ "<' IkC 偗n|բϻmm%^>NW!}M𻠄j'F_mRZnSvIpw;q{wbw>ֶ0tb٥yeب,sfyjf-s*0ӆƒz[X7d;rdXhN\$S|vL84|;V(xQ9*JK3$ 62_Ӻ]j| Itto,vɏ6PK@X<rebar_abnfc_compiler.beammU{lEٻn{w{kŤm(!QH Q!bըH":sJo~f2ۻzM+hWsUm6L5-)9gbZ^5}.a32 ,15n}c2/I^$eK74+7UU(j{zE4yͲ ,弣2jVv6_YZn{JճePS*q:8˕1騞T6U].,ɒ+ n!F o0 McK[g$IfwH[sћfn4)aaTP<#R$`PDBUPT@]C)0i%[> jGnFZD *E>IIt(O!DQ_$A6W"#F CHOH\5u~ڍ<C(.8Il*'@*=IU +xFWIRA.H~ Ո\?H<^<rЅ*ˠФq v'n.[nE)v'^1fa,L{87+7;,DO,6{ ( 45@aL(.a#qGKz򿺰Rl؈_ Qt"[Mš8N5X+QlWu0$ E܋|,Mjd̏1g4 Mwcp!|F0iq:CZxˁ6}]j]/Yӧ;z`D'*kɡg<76IIw\pCB~3DžW>{%0g.}uG֥MO|/2sxiQ^lyJ`;GGzpn+n<򙏶;&pN8l~ܔDOoyx61y{[?" #EOrOtubR>@w*>|B=؏gRPH}zS3i_n^>01[LmdFD3[zEm_O{{)J u',k)\ i))ds1x-/`ԴrJɨPnt53X&ԺĪXLmZۤ S1Ypn^J΁;mRNêirmYA4 7e+e^}_`䝂jEVz lj,lKƐVjb9k(FJe*`i&PK@!t rebar_app_utils.beameWp߽wllr܅#A6 $X.wrݛݽD֩ )3XeVGtc)ֱNiŎmV6 }{׭o(3a#eˡ(JQ/NeDJ')vF_l,$Ra58*gx,ChJڼ)u׵A9d-Urr̐}H[FԸLQ\ M(mrA(;HxZ/awBNɊ 3ز u znED(н/R'|&=K"f}m[C$GM1l)" EJB@($:zOry^lSr B.^O\R)n"iJKH"')"u1 |Ԏp~yV'N{|8_ %S{l(̐!~fW#uAbX IBȀ".YL09H\  ޖ옕$+d `QgLR$+-KVJa1PPb @Rн@2@s@J瀸 SHd!//nQp"\pYtEtRw/epGh~[gWD۩eW{hVh֛+}lx݇+rJZ ^UZ'Ay^ `Zq X]b )JU\ *$C(\C3$]-yMاey C6!.QEދ$ɤg6Eq;iǟ>FA![H{8f[uP`? p-lK,flj La(E2,w1CZ#˥`fBup14SkiN/-3}EjuK VMrM85ׂVDA/ &L#0i2ۇQ-qXb-a[xk#{ `aa<"=MlA+nms6rJp^hU~]PX;Z BHdA( V[ arєnX'l@6ݒoD.dYr,y/2,ײ_Ti@uY8|Y  YYY,_H@ K"h%' ,"Kg񜅃fŷId>۞~9r}>sX&pMC]ʦƏ|}څgm9Ҟ7/ӟ]|܇|s۶L>ڗ{T+zCo]H{Իk_zGYrJĭC!yW\SO>w~pЮ>v_;W7.5 +˾ >;ZC |}9Oztwꥧ]zo} E?x˔6]OW)ixouyek/:4;qy/=ųgpɖjO&&o?LM^YNO6W_[_؇oiT?ȡkXs9nڳkZ^o8xSUwjo}Wuoߢ|S/_^^YwktgZ6ZJݚ2|\YvFtRrU\(< O=32XbP3t#ݖHDr&X*{.M֬۸'/ 4, 4554ܔMl c(!&1@X`thL 1ƀ}Uc &|n>̾Aңӣ^"&AYRV5ZY3K8Њ٪U(ME]Q9/,,jVR QQ leՂ>^5%:_(jeQBy-Ɓ%XCsBf"4Ra*^斴2eU32 e5C}*TmXsTP#vU,i,k7 2ujTA^ʢ=5䕢e1{% jD8gnaZU΂R-M (! P'X-\USM^Д\;bzN+5-[o~(X16k{to^7JPj*e_n ZnjB-jydklIWTq9WYE=sʘՊf.@Պ jZ]\Ж.Q,(,T-VU(mt\0.>H:j2 vJTnOu\x _E#_ $ R$*2H[|aS.\ |O~sDЕ@NK o`B|by k@sy|ts9?8:@st _&7Q^ a"=!w8bO3`hk'i>r$[In-m $ٵhᇁO 9sߢcm*ۏ\%m EBJ!?]M89$]DqّveeF`6$~q95*J{iPLFfHDF&.AjB=$!d#f؅ ٴ^v*"k43׬ a0imk\ln}+n7LOW`m o *^b ߆=q7tS KQQS235ݦ>2BvxcI8%۸?J8{8dVdp$863`<@w#G'Av5t|(#F<*,„.';Tm}+2c Elqnsx¹NS+q>,y;\*XxJ{PǬ;,m:_?boNVΏr׿bk?[#v'x[p}o~gzoW#ǒ }k{_wJ/ovwO<3t,nN.Ϟo5>=go8zvR?>x{/߾MK/OMqkCGH-~xG~8B>ٻGw-ut;olTj̫>_?#G/~m׳=M_wor+giS!bJZ֙}Nw]k =xNєY8&w8>qoSc͎ {v8x#7›u<*eP3C&ym ~3f5b܀^j2Ai 2eW(Ux#V_@T`R&ƳsebM뗶ǒv` މei` !;ÚaBRDCoo(PҖ P)^%p_ nӖA/ftZ0OPApìrYэesIDi?v FL PK@0G rebar_asn1_compiler.beammU]lU3wvghpwfLBG w)˰&άS &&@ JHw;k$gs󝟹{C n؛ύwУxdxEwhu≑"O.IeKOC/tbfZbu"u"1*QH+Yq#E$ "̺U 2:e+$9[3Ĉ繞jaq XPc +!U~nݪw6\+N]C+֛2O nϔC'e$u5zFQ"t"SYGE/oU9u0La@ :ڎuuZx &NATNeOpP`}b4(h?H훂dp 7W5P5F@D}/a}AQm˟ XIA&Fz3д:,}{!P.+s.3**&O)z Cʮ2vXV.ŗ!Dkw;hN B* E:%6.Yyvqwi&=2gfrS4ȕPK@x rebar_base_compiler.beamuWkl&u)uZIT$-ڢnk˲4v3,ȦezP!<03RslHtX@t,ۿE4P`X~Ε;u s={L-{jpd!=f޳q78Zɭ]3Wub:i|v9`:|m]pJ)2+ص.^n^sEsUuX"׼:[gU\dՊpw6B9Wɻ^j;]onkz^JkUR]u0|5SZ;^enbw/j$G-_5EˡoVKaӶjaǬWv-W{~/*&,Nbf!X@vy.7̆)kP[ɋ~Z Ǿ*,@nf]m;e v)~ql mFM l[18xrԨc]lU)D'@5/8-Ѧn=kg;[޸]49.-km-u/ȋ$>u}>K2pB(B2(*$ucQ"VU=j6\c°@a|Nyh'IŠH NIc2uunIE!ivAv3WCl:Etc}xة(/qh!A42-F3/(?f4RwRiE>4 E Z6 /NEtl1398Lem, W$4Ďɡkb%UHzF/4A鄦5h$\s^dtv}$ 0 #atV~̋3TX[2U 4xxlѾ3\qa B!s&gG|6NA% *0[0AUq "#0B[dқoUH0FPX" |^a^hIN%R!ɨ9DHkDQvK^3dOHB [UgZE ? 2HB@@! nj]@a@@{̆:+46ywxnh9Ff</2,|o[jԨfN'įy~8;7O[k]ޔꑛM;O3_cɏ4~d@#\zXqJI{pN6V~~'y{_} hu}u`܅/V_瞏p?٩cG߻gpZvD{IGhsCQhLc5xY*<P7|E]qkEMnϾ~?ݯZ tcM{g5 E7snZ;שAnx5\sͪQ oU+TEu4jE>]I O/^̭.IݓĤ>=MLstH8 gۅ.-Yv''QuUU(D$4Ez]]=BIEO3|||3 g|w4 CQBX$8C|ڧ$ cD-\zB e3qZe!Y(xDut.|pTA!pk,X"91![HlI;/l~ݺ |\mj 4֦rz'ԾC3.$_KT*D]BoKhrScWmTZAo0.?t*n@S]VD3Z2,7 _?x:yګRo*}+ŠA 1FY<ٝX1f)0h8uLQ / `jrz\NF)h{nsL7,/R\`ah*{A˦RP3ҚˇZa'NX/`JԹY#ۓKŒ2BXvo)Kr"ns.PK@ЙQx rebar_config.beam]V]lԥDZJqT'ˢ~lK.\QTcqdJe)T AX<t] (0 S ꧵@0=\U'=;97!!TIxfmٱ-7^]3hvme1oe]jDr@ܱl1z&ZN<׋k:Avۆ3=p\CXseeSB(L }Acf`u䂈r5i95=3QF4r&έ"\Nܱ-k)+x)TK$`XtюtdžUlx xW~4_L`&qQd_(v'B1Gb6tWF:k` 'GR22x1eejRJ:i 0xAE+QC## $D+R7"D) ݀u^x'`,] (oS4_V>`uuj6d,ݭmŭ[J)!wj{ ]MM쐻(i s() Q@{B8'[U K_s%Z6I)CXYA%وjL*T{zai}Iœ:'5)h[ehk%'%%"+ʺI͉)IC%pLMQr)n1@+tyU wP#i,*'N1 @NԤI 4*I-TSV>'N 9'ɚ49S姠[0]yCa |5UH#W$h9TZN+ Y}#t;<)鼤&aZ#@Th4u'{(<[j=dG3<"q ꆷ٫_Yĉg! Dbx)nlOxbAyR)84'^6D\TeQ΂ڙ4מe1ɉy衮) )SNH9|\"I")N,RxKoU4,XJPDf9}5{O`8_ A*-2 !A+V0BwV{}z7X"`1D_5g)n Od>yy$S,F;b?={r,f,x `gHNl|1}i)axy%OebG#u(fTO~7x酫kWgo|zMxw񗩲c3}E{lw Vұ||Ͽӱ?/c;;W6o'_[3.l"tmS0}U2)6˴ϰqlgi)<3F:ƑOUx'pooeفa:Vҋ%}XmY8 \l_ƻVUJs^~F}.QkC3Rl$ !m7]{3š~–<[g0xv} ߐR!PK@"$0!rebar_core.beamY xT՝;ǵ;\hMt1QsZGP9-im))$~ӻ5+%KofՐ1(W=PdL:c/}[Ŝ%G0ʦKUDVzҹk'r#)B1-2|m"IgӃ\/p2%R՛‹\_?X 7-tI$4R+џ'YgvXj{Åڱs9NvI$GD8v$jҽCe䠘>gr=0eK0p= m%u5e\b0m{LGRUX JUgH\PUdX~:H%P!-chQb"i'&>"SHE,MRt*IپLNݚɦzԸ[sxr'tmXJrVÎSs_6Q.s X*r[5NG.βdc_30ꢚ$c%Ѥpf (DĆ^r xZ!㩋.< [7SSuz|fe8'$Y:4YD]gM=k@Tl6*z+4Mf@LXbb-̣0>*v$y#"0ƫ@FE`6CSȀ(3X%RpXU =LvVuttjӅ}<"X; 6t*I>5Ac)OVI$gb0$FX-v`)dѭlw31 rDeN}*T|r(E>HHxEzx14tUg֦6ԩYӂ fZܠs|CeuzEA3܀ݙA ZfQ*5c E@}fM cUB :!s(NsuᶛEr"U*IQ1 n:&Ej+haxZsaaAffF\s)Da-&0m /le zR#q΂zl0ϳu~e"~6ޅ_L/(K8/RTK*h9.2􆘈 3*tjYu'oT%8~|TBcPtRt",a:h 0PYc!E/ uRwkYO,6/CmH^URS'Zo%-K uS9o6B'rEn|dn kQqhw? uN"lg&ԿJ-i;4u2 ZRL.t@;6^QG'!&, QϺBQ/ě7.@\QEoZLhaP>O~ViB=[xX{Q.T(kǾH#lx }[&G2 #3Fm I_ǡ!߁KtNL:Y+(4 #7QAH Xb٨fyTqu1W5JwWǢFOCQװdՠ`N]C. 륍q˰YGFGF.):rݪMagU0":c}^| e?*( &opA\f0rԈNnEND!kQcݴƺA;)CaYίhWI#Y+3"^Y&/y[hWҫK@ N{%phW d5P 7 !G(^DtYq]5R>75Xs*~@7 g' !j"aY5;hx[v> MF_#Gqub+QKvлL#HA{nx =c: W;=1e;fwPRPY)f h3+zs:H;B-(y/2ԑI2#, ½B2&<ՑCAWRѦ{;zI$^o$ҷ6S jqr3, IoGL)}LzB|>I@ u:LG>(LGBQiTaOvg; 0o7znW'pe$?#Ԭc,mdOk6[{^K]m!t[# 9qUy"e"&oExV7bU&N\$7q*a5}YofMX(0o)vy݊=[mI5hYFL&>uܕOL϶}=}!%lJnc1bn{^>pJ#/VhNaŦFKؼ?AURc̹|qtyz9,U*R1}%PԯA8vvʣ2WȻbLZ#?Đ84V@7N0nTGX\%rJa{bnuma p^TKXƱ=:IznH#ͺ Z|0$>8#73n6F}#nHG|7xZ{ FM P?eNZ]uʒ ̩'@P#Ef?Fj½'S$wu~oi߃xw-~*ƿEB}og(>P|Fۊ:DiX.vN%P ة8 8;ȟCTt\K1b#tDzlLjM/![Fԏ+s1=r@t`ޣ6a0 b= #:FX|1Q'aLv9[Ꚋ1MΧcrnbD\9ɜ+|E-b9?QғK/t/sYiZ]4mrRƅ|_鲡eۥr22&444_/rW|p\Ivn+\q'Үmvd]6\ 9-˜ym׺9a.]]\4H}k4oFƨ&osُ1^' z}g?`˿6xYK|Wm>smG+Ӂ=?#mod}_jzvѢǿ+d??<?O]uhzk}og/qo4M[82]mZs˯Cc>YnnS Neҗ?v=G֭<U?iwڬeÊ'_{ i^ˡ7{ߟz2wٮU3=-U[ʌWn{|U]/-Ƈֿ)VbC/;pˏ6r;b7N _ŝ9H+O=~//8so쑪{ǯ{V{)'=N_/q J,Iz]s'y~>99f% ͩcTa9Ĕ\/$PsuWJOns$*5rri y<&CETa,t4H31% SSpsL1s3EARq,XW 6ـfl "||+&7}ZlaSrR&@¸o 8f1<5=*6MŁ*iQ\2Q8%xK=%P a,E(%pNS'HNx VJ3-saZ*tK ($y "yD1G\se(]ܰxl[͝-?i܋K$w)x%O+"4F+EQsN]i=rH 9xKŘ]/ID"<&%qGp@Hュwk128гLsj= H$}_.⮉r, 9@hjhSqXQ(6^3Vbճ^-p& ~f "O;AL9E=-E.V`R .Գ6l&Oam $ll }0DԱúyKE uaa;i!+UvxDF0d[}^4֋ƺg鶌3֋ O%B3{^Rw.<@Xi^d_^؇~ɽJQz VacF# A +m 6hͣnCFfH17?:|]|C/Cman,ȷG6>GLAM<)](">}4k1 6&Q;V`o/@чѡAQαOevlQ.q;@`ҵ\}nuϥɗsS}_+b~OVN<#{57j[[9s6δrfr'TY7_ֹ՛éj$'k5c>߬u);]7{[;>Uϻ6K֢;;Fw=kNuϾ$|A-Jmg'WV[w!򃗞_vU>_ʱ{ǿ8.ëw|G踴cjo:o\$]ڿ_=+sW;w~:|v_ynW05o?[}빎~;}*T+uuW.OAogw軯5S*B~*{~3{Է5D#_1SͫO6w_lnv?2zʖoʭx7sqHM|ޢ;%jv{V]@l>ǻW{;ޖP݊|PYiWOmm?I#rґA=k.~qٻ⟧̎rDK)58I/<1=y#Ҧ(OeQB(W*HJ$drŢ[SfY\kZ̆ywGlpk)t"e-斶D3CPSTQqCc ʜF*L!b\2ey-LQ;t>-rb/8aM=$ =h8jS ?{u-= 2PK@6h=)rebar_deps.beamY{ՙ'< „ L&Iy b$bVcKB'Sm-ۖn荖^ (wmwKh4/<;Cha<4|3b@`õ| }N 5T񦲕W\)jDPsta&4&fJS9\)B1ߝ3| ç{:;WUJG\ZK/*Y^.Uk =^e.[a^{廽JsraZ<Zu=cW,z=JMmR˱Y^[^/5O=О_22KZ_٩RfV[^O4jR| 0 *P)sl7)P@ـo T~,T]U`4flȽ}e/Wl6[5B8 !'RCVզ]R tI\)o챙BU]3lJT%[ͲZvFtJ\ Z廪P_ZTsIxX!slۂ*pV@yy'RyzP$0g*Vfz˕}|#ГT:OXiC|`.ٰq8i${3^hˆM"hN'{+Ӆ} tt``#6og=yK޴SGвk@֎^SxWZJ V?4>ftii ː,"Ld02ep$~;oJPYe>ŒHZ0=,`#Ђa#ԙns)!% kn-Gs} U1F- .& iP&WPc: E>ʒX  Zu-K!<| ,8`;Z%]ɤbC+]}6l1aa&6LQ6Ҭl͸z6iGaP|qcaP8̥}lb 6eP<,M}@DI4nB/v%ĮTb)Gy(n+a ?,?VThݛW%OoLWxuGhjod\?6 S--Sʆ*k cM[mBnSvN7,'m2!Ck(g@`%ZB妦M }_Kb LPó-X!xV vCCVIaiu>h<ѬUgCyv, cbs!wq8փc8 6 3p!|2#fF|ĴR#3 9Ҏ1SmO ?`n6ņ~Z%b<Ǥ05AXZG +h糐Aͯj}P4~`P$z Q:Gp|orFv ǥ 5@I. G:"I Ib (!fR$!|^ m =4«ѥn$^ixrP\`#dfs 7ILߖ[%6;b7c#q#爭cdyԉcnM-BNft#q*dQfnOZ2).F.n~\L‰CPchʻkHj7 I:wyS6ށXae| M=lR֔Ƈ)cLX#ăbb EPIq /i2[`6C࣑ߙ.fT./)DZ@9>S7/g!K@.wiK_[7*f>lrQ\\!j$8L|] Sl2J2'ED H3M3w+49ܒpW4 w-9b'NjqU.WRL 3Af$L؅~egYbb keM3$L7r--˱cE\SIjI`d޽9+N8Ցqyr1N |UH AU&!JG\GNA5Z_8 !2nIM" HG~*&4E-64h^Hu|3&I'ТF:&&pI1 ' nÃU11i)!i#DշM呖3QjBN.@:l" N6 \7ndԱ O]S-d\] ߧżMI,h774T$rY:.R<6P,;]B ,Pߋ!k{FBy jj>&UĿډUQOa;C/b && cĂM0qC2c &ٸ_uB0Z,kdH? b8cSe.+6BAoFjT#QAl<(q;-?MIeHB6]oˆ,ahEjȜJC+,1㭳x,QYRGuJM"-vKըgꔦfC^$*$h_R5b/qohxLC0G$~ާ!4~cK{vB{BW5~SR -e5mU7h^G]QT~M5atWr锿59C6"42URBfT.j iu a'0buܐdȼ-͋2_Myѷ0/Ѧy8n+NdkdӈF)1Y@h}oϵG?<}?/mN@ĝ fr2: a%|wtp7uַq \ H%UW( ʇZo,Y&I`8c]M1wSw +)$#>aqa.d)$9`检f>?f턙{ fU0s7`c[X2NcK1ٱF \ (ecoΛ8= Xx\G ^ODžaQSj{rR' RsO@H4?F3~F㟦=iP܇lއlއLާz nFEǯR:Y\>Câ6qLGl;l0FZ fΟϳEp}^\q/`ؼ:)P'!3taƪ EFx X#.|_-g 翢/Bt~l_~|?6ҏ#$ABn5xz0l""@S&L\g?C ~߽;dn;d0n y{D0.EL:=J9h BHE\WBwTPhjZcwt>BI6_ͩ[cd?HǐǎERƩ4?TW)`Thx2bqB9QLQ.nU-sdbI0%';qI¹'s׊~@tYε:8K4?$H2$"IWPDZJwn3U>gig&uϱx=1(~z ck9Qԁ ˄9XkS0[X̎'30?_Glq~.(:ct~X爧XV׋7uE-)o<N_1OӀ|yoaݠx0o#3i^ N7Mߒ:nн~~P@%qbȞv8EMf 󝚎cMHߓ?B>yaPmPb/vB?%IЋBoA/AK-_j14h|j/ g2=/_^ 7N*xnNJqlu/3a_t- D E cp8#HP')^@^н%3%b)f!U=hA:DY*#+!L_Ha2$g`w^ i9hXPO/@6´$Oσvzߖ~;nj|a٭QR i:K8u{ӚszbwVK 5<9V:ikG7^;fidc@2'OZZkR\V˓9~f4D~/Xm9ݧb7%g99%˟{rʟ(cC _}0y?6%Ź9rO@{p $Vͯaj$xy3:nM:"׀5m"ԗuVeYp@߳nvWmWWT0 c{<.A̓IPjԔ3zxg*44}E"[BĞkPRbBE tP"qDHFupJmRF5jE^}JJNSpHQ%PPHPK@,EUTrebar_edoc.beamMTKoFriQG d'ʣaL؉9BQܕDK2/` CS=@{Ho=E@R447ffWC>8\06w672 1b/Dq-,CQ2QC?o"bN%GsCmG HM nwW]$`okykkt`S}2; 6%/!uV q:H~ ֹG47&PJ ^ GAєͅ%Ў뀮>kU's}OuE9!x|؋5bRBUZjkzQqZyoJo"Ro!"tyG4w3\)+2~ SK/"m@o׿;G=+Ke=u3e ӫxMY \| "#=v(:mPxq ńYڞ=@W 9M"i_;~;bMAKPK@(ϔ rebar_erlc_compiler.beamY pf^[ GR; e-EQp4dYZۊdؕ"  !BJڹ;(vzG[9:c:uzCt='gs+kM=l% TqAh|^1҆U̦x9_4,鑼eWY4o,Gtf\p6&UHVԺr{ݐ-RSMZme$_6浽Q4*FdybFLVВ3+nոܲ 1\R]4G% ٶ-hfrـ';2Ūa7B[4j1L:Kqû̗|*dW-4yfpl31_f&n99oŪͷe,Wl B£Es8Sd%3xΗFL%ok;([ ~] 4ѓj#') lWH')/zRS"'>+ԓ:D!229בIN1kyڟ z ׎! A(:q֧j<u="U}[zUP&B:L1]"GT6]v=(FX&N iRniԩoRH)`3_W"!= .M z'NZӥD׎$th S_O9SjtzCybiIi 0}>m"WQ!։"p]n>2yTYl_%瑂bEir[-dƃ0oyqދ*yIc!weһuekܟA!t{v/IUV>U|{$~sZPf5hQuNH*t)DQz%=DFJDRVf ʢP B tqϦJK11I$5e~6>1Wu-Hr-kjʠ&=A P== t6>LEp48ԯf]#^=:Bۅr.2vpc!! X(l(˻5)F·,/DndDyvU:81UY0# Ʈn񫗰 HYA7G% ]omH):<G˪@>жuT P]Rq-mmyzIox(_4QPhBN2k#xrP1NM*CT@Z%E%(>SSŸ׎#A(m!(2|6Ŝ( \QS;qYN`($㐓gԼS]lV lMdUA'],߀ ?]͚F&ЉP]L#4YIr7"<] sFގP?wn wc8.Rr SL1s;OC$/ tS؃7[WW6zBߔxRI%8#(Z \D Q-#%e"oC7k:n \!`)!`%@@(/D{W!rm uQ~d^z5Ԙf,,[>v7 BHW!{}L+[Q ]bH7EN`z3z?bɹQ ߆g 8RRE-cZ)rwQWX N C:.tD$n(A6ָ10鋫բ @=>z e84ƴv Ym-Thy[AQ^QSq%׬9z6Gޠ-T-N%ףDy:(8Gv$Ht$ݵ(ݽt[@߶}[ѡ;H36&Qި +5P'7uvt*4JDjE7GTgKPNnANƐ*/cr[an'n˛ ?n[zQ\$aܦ׮sv{Q;v2& ? nQ΀Xqe%bضɋaj^<ed&icDҁIZD2>r0b)!Kv,4ullzNlB^IGr>_V>6r`ŷ~EWDZZ _9+68ԥŚT jS;>M8#MmMR4kEyvFWgUp !.ĦŻX!D e`kl,B[q=ju=ܥ…eX5.]B6 N6^F6."oeGꢲo] smkqjݨx ]OY_j1Ph;(,wrh"]w4nXQV"6A[7KrVSS݁mji;خ:$w|7>v q eIp/>vֿ+ %cOa@ý}>^{;O›sUE)8*#q=FuA!WA?32L v2 qaTP=0uDBoހQ%H}#7Bm<@N)!ͺQuncK'GDcGn p(?X{[p=cxcW jp-}]YR,X.ISQv&kbg蜡ךDZg, ^*&yeeQ8Y{NB۹>jk/aϹeOS><ݨ1\"4_2*`Rk3axO+.b4`H>>01< Chp1gb\yƘ${ Ӄq1B$^N鴾yOtp~G\E|ckS,_\S,qWVp_yhrӛ\9Y] |N5tvN'wFƥp9mܕq}.=.]} C^DإW\yFbba؉PtGsu|p zVVK)6>qӿm ”~S4'x AxGBQqyz68v#k~Aw?<:9U wPytG9pw&6tfrNA?t_~,9uka_7O ~mp'{?{;K_>c|5oOD-[+ 7 >yrysy1||+FNszN~z0fg9K1Ro}s{19 ~NI?.}hT,Zp:Ҙ''H;쒳(¼O7?ڳs۷o.`/{g?99hxM 'ł5%㿜)yuL^.'(-׮Ho^.QZ{^mqO_g1&KL-Tz Bh\]ԟ]~S!pEDVX#*E1ӞQ3mVQn,V {]&jŊ-6t[9vZv#[k?MwV3/ݶwI-K-b``pL*.R PK@X. rebar_erlydtl_compiler.beamuW lwgI$/1!!P8&-(?e\Krľ:IihMTnӴcuS+ih 6iH0M/5ћ{ );ەir](j} FF1rV> E5^Gasz6c3U2~˫LN5|=W&ڰI( ʦr %?^L)kC0V,XU]Q4b^5-s3|I!feK&XIvr3uSc#jvį0,xgH7 F }5GbQr4_>Z夦akzLxY%gNxIX^ieORځY2Ur$1XД*9(yhVUNO^KϐhPRY#C.ZnƐ",P 9k1zPq4tr6"u}=g#O&bh"S͌ qG}>R;-KѪPԼ2G܊aGͬ~?T ^Nmt-0p]D }/I$_3XyyW&$ ؏E{(qHLG#qs%N9q_}͖h6}(( 4+%^B6ȩԟv2ӧ[pAT.!0yyV N./>x6ʳMh/!gB$k5v"א*!/«BDxf5M(shvWqq E!3Lh#F:n LR]B6RF'Mן7K?7$yLկ=t/^&:Q_'NE OvS‘˾>_zmtcu\Ms.Xpn>52xqq˷|r?}ԍ s?xӊ¿'5b?6{9=Cs=uy濷=+ף/Os/?3: oma}3m^|oZ8*ta%={ dC=vt2׏8rNH8 Ygs> ԃp|XT9vӲ 2G2Qh7OفjDٻw]6ko}$O7Y*dq7R2jBWղRNQ3J|AQ{7tgnLRRfe$ #P C( טօהҔ4%=wvsswsw}(B7gǧ]P(%.n-װ#g^0%*yYwD5`mn5JgpKuK²Y7Rh:mʦjLYeðZJաۆaö-gTEn5F%F+iv!U7Z%yF$jQbngoݪ`[]еe󎇗,KBs԰FXZK(_Q7()dh 7Cb0~^Xj˺f#u+ta$Lh~2Q).T{X}_UK 䂚VbxB@!& `2X#AwesTADBs*YA%'"}M!!ߥ8A Hy9JhB%YBB *@餇<,`$`uC7#Nzʔ3 (d6e *Ġ9&H1O#ĊH>(H򉐔簔%cXN Q rk2'Ej^ |v]hI,hr.9+ XNZiMژ\S֔fSkȾg;)^DŔ#k=`r(Df2 aq&5wM?qJ Q %+ȷS…DFlESGF0xA W(/9,2w; h,qB! #.,> qQaJ$Ɠh,''J1 nD"'x +!Ta RF'q!"Pd/kAYLpb?U20݇eI8q_L&' yДmN~ة*x`":tQ(Jf|FDyi$UPΆBLa2Y8I0):d4l0Gy>ɾs|răq``B:8FB`z az<'݁߁Qg~[ 0I`>P;w9 Zؽ yӷcr)깟ёg~Kɥ߽'z} ϓqob-MO7/WnU'^K_խ‹gsޚh7]ѧ_l?Wת+~—D5օ>zgᅳ}r/o_z[?}᝗&~o }?ǫcم2;\!3`-j:,QFQNPrF ay.Pkɲg֐^(NY6ͦQbX+Qdܱ\| cщ!poӳǎ>^C]ӕdzca;@ّ#,ƻfèv,CCkDcynЉi5E|\ҧ8_Cwt&4j5jE!z; W@%ePK@4rebar_eunit.beamXkpUmY7m_V^B)1-v+J2@nKmYDI!a. &0a`ϟ[TVQU[[߹ݲeKs=|i{tbdH2(]KW͛vkYY.6Brޛ) wy(6A\^7*UcyW:T,a(ЫƵ55 897|V׈\ǵBsä,5tVqn\,ek8,B '@{vfI{wK{!mnMe߂\}Ƥ236av0rG\M78*v%Drl2E"5'% `$ey6|_ʎ=iX_j8ʄ&?ѪV p|4mO'. r@8~٤mail t`AT>@^L'*OQ-4֫3]CQ%ig$t*V/2x;,U~K|A_F6FP-n4@ FeH\aBT=vBCNlx6IQg2,Mvm;:v5;~0mGB59!vTEFl2RY1Qx%Xn MY8M1!1ۆ?k4Fc4]Þenf`}bH쁩=mZ졆LyvtQ5}_\Ci$ł1~5-v1b?SR+2nL]u!ܢh=QrQ3Qn#@|7P@rCm8zuCbB׎>Bp4ō@qoܷ cYcʁ1#RqL4'G!Mʢĉ!hw@ȫm, \SRBdqYLhlG܄H!I1[mqr8yدa"qSʠ V-08[AHG/U6+įj97ШuvjwЩw?kv.nWFkC =N=**7O>b7R`j$5vB$L@ C7q'ड8'h=D;Q4lqgj{JI ޽ *{>dX$f8.;a3sRTsES0t ݶѨiQKji8_c˲aT6=e-ڶư^B9Ƙ"%fզ6i Gͧ ړG7FF(\DJ+5$fR ~CsD(' O.iߕM1"ZX-&Ga2j_ȧ Pd`3X=jR#*MWKaF|aqU|Wu2|3h8nޘ1E! ߌal<g(\Ng&d\BLWP^݊54k-|3B}J>+O/V M)~dt ԕYpP=ߪ?n9^1zеQEC·ur0%13ь˾"o:LlF!QutimYҊ-k5qx *o q O=:(N8K3 z \.?H:lc鯬~vhkGޓphT}]H*Jʹ3:>R8 A= c?Icq5FpS;~47J'U 59 h\W6Kr ){4)eFSdZʟϥsҧa'zҲ}J¹p=L[Ј8Ƃqx<كacɯFψmƟ5lH@T'd+*#58|_Ŀ)V4Jw [SK(gup)eiGU~$p-LoQ}YldC "E{{ sO_S/+Ry)fʇ_8%8 /%nI ߣ' | jH<@XlŁyͯWP|ϰfƆ6Y56j?XOĘZ/r'.Z&:a2qTLZQA?7=)#nޘ/ɤdߒW&o@_$/7LGO|O9m{F;a߲$wRo&+8^Ua;vw q !!g@<>>PGi'cXV>nB`KN@R-$4->&'0sp ^|;/aS$!%KfcEiTwhDcj&ϰHW|J^05 }߿_0d3~_K/ ǡV Ta!#Q"!H A@ۺ!HDMV-VV\ZQֵhm'DqAT[p?\<缜eܹ7#zNT9) X8R+PR4d:'A*jPpIE(u*NN}j?,T1Vb((t*Πp:e.TqJWJ8҃a w TtLt*L1sdu /o2,_ $?,B&tQPT_THBH)!Abp:p! OtzD^%*[8* (׀<\0vPst92]  8V'SR<߼^C}KwNM7kw׽S\DoqxC5DQ5nn#c'Yzf9AQ/jZu^.袋u3mwǦe?IsbFWersX[ةz!纭]\45;]t}䔘|vTuϒ<+$}xM7뻯Rj̵kۂK9N_p9?*RV2ֱxt}ݿD cɓn>YWaf$`-}.6-ouW1dk2(y_7÷ھ{&dΏ8wu֜ ]wyZkdz}r|F%iƒMk ݓ,x1nNu2UK=W[_݉sݐUeڸev#}>ca[avOO~[skwvaZ@mӜf[uֆ߿p?U``Ue)dogz}h[<|˿V`\ŌE~+.ݵ೬?Jaë vMU̙mڐ;670s嫭Y ;Mpm-4<9oD/f Jq4">wY蟈kǣǣC-ɻ[2(!!L;5p-.;y?DRkuɇ B} _fGD#= ?(8%1\"2c|Ya7v4%M#0\?A61C`ch8óFzqI;Ln;Tp; [QrIb° )HQ`Fm3"I'hӱ/)~0Q~Q]LJ~gy?Ync7&ttk\]diꏱd1 }졏KJdfCЩst*`=.|(I0Fh2'_#<)D;p"xA\ >ѷp|wNUw = {>:` eAG'{$NKYVN9)OtW,qt:뢣#Y \8O.j$f̱u9'Em뢃A>. Ԑg:u"S/R'a22/~ON%&M?uyxC/?\ҼW  cw^z-ܞNC >_ }/>5<|3^\oym?W_s?z5oD.>yڅ{hKCo'W6~ﮃN27"c6=􋷮&V̱4Z><ɫU~7G_w'Z?y;_3YQnmwyf"Ɍ58:y,c9bse>cjơ>kS? =cw[f`G/X"6l,^iU#J]@UY%2jJvZ6#GO.bW/ݵ 'DzdlU-'ӟ陷9Q H-XgogіWppޔݲ_d z( h"rJ9.g94!NȂai界eFJ‹`酈K8 譽w{W|h`bN -AfLT4e `*{-w<>>wv?] @^)٨)) %c"+0 u2&AUCڗ"Ǥ~KqII՜Kl4f8zjrzW1o0.qȜE$SLfa2"iq Z)iM5A1@-ZcJC~('K^d?`C`fC^DQu4Ec^c-a4StEeq^f 3 z 9$QDT:w0Fۉ2tOH4Dg贺XpNEcia] XEaúKac,:}/$@7nK`A #&+ 3fG(4·b_`6Wk60zњujCWbZ4eG;gg_PCӪSug+~cg8Ѯn_=;:0{mRqnUxb~@wv|>([(uN(8HG[] gڟj;unc'[&}'6}HCg&5 hgRzMsL?ޘt>{o 41I]oF?ȪNP B@NͤR8 LJF$d0K23 $Y 6:Zm(y}@uW@FȲkjN[z&B5y5UU~#5)%MQ_"G̹U%y1&%I*70aa 2KgP 5ǨgV!@cTPK@01prebar_log.beamMToEͮl\u4Un$$;wu$$+>Sz@ n4#ޛ{y/!8sV5+r?-$;F>s [^R{ߐ  R(ω{3tq+p:؀(piV!U[ۀva#-#Α R$=M{UE*}Wd~BҦZ`LC:!-i>ZaøyJNN3:Māw $|t%-3hoI s=::Jn^()*H蠖0ͼ Ef_2og:Cg2Js`.m45h M˃Pwf*yQ̨s%Sle5%K]SuA8W&leclqZ6e*$-2HL ,OQl;X6W MpFj  H A$b>a@? |i H&k 0^y9ԓXҦ ?UU֏I)V7/=-}e?g_|gA+[TPۍqQHiQA(_E{҇_/~akW7:Ħ mH9H΃Ji,H$N丼v}`Ү_:sЋ@ 8(VZo94g^/V)]gy}^7X[Q[8+(9?8 DAʆᩕ4KV`tx5fq?:-ڝ^:Eh8za0+V~B!ZH\PK@gD rebar_neotoma_compiler.beamuW lb}& I8@p|q 8&4|hժ}vwݙ4*P1L0A?VR 샯kJ54ӄN6" Jl|a.[#{q߃F)DZ(ʨUEOhB&.[aZ"kҊf m_ ;cu%]zvgw2H#]lZ]^cJuMwssZVQ 0  opm+a(SH/yyUř(QFXhcD#?nGXG1JpFLm+qF`DG;cZr^i^aHo"{1#~JPp<8AYOhֻѬ0C y͋t%OY OA1sP4 =1wk mV8;9?r0"FPP@eHgHc+-2\rYu*[c\yFf fuHNE]"~>ŋ|)Ot P)x\[ mdE+pl . Sry@ų^}\+x.UwrM6]{EEzVLx3<[Ks:"`:m20q#17p3|u?8AW[=bvQ˯~tr跿sX ZҭgB\jw_O֕7Z3ovuLl~rko/RA=WN <×<7@9pg_1>a>7oepط^ v/qU/<|ݓ}o,q蓦z;o׼ճ?Կo8o||g#׎fr՞'rt.xsf|5G?:1^#?Z8|*gxέuyHvl#BۇGdg$/oιm;o:ɹ#Imj=;/{'xz0>0:Y(J--ZI'|MټnhQ$ n~vl+8VA+R [ S͸)),˴*nV2-gΊTCϨ悳f`hvL)`AIfZ5Xo"oyC۝X6mhjʫ$阄!g4Csr-gj9ǟ4HOk]Y;kogI!;\bnV;b;U”UG7s庙4TieUҡlG~ԬftՔMF&mf4Ndyՙ-!ղ+ 6 r=7eV0̃ !30+ڑjE\eδe+HOBִ2NYf6I8r,5S8Z.2,YiP_\.Ma#Q9 J@urQFs4RTY?QLNmi nh) KՌ)Hd1%/hVIiYjQiFЊ""z%M.Г/sX!HP$IˀA$u<0+!t"7)?,UJ@S$%J *xre |AP/Hhx ! Lⱬ lj1ا!b4Bkc|:gS:@_E5j+ GA4lN.&̹H9 o) 1l "&rXP$P>^-c|3[hH jB%0 pثbF*FA1/N+lƶK#䵐 k øY 1\;d#z C|0@I\C5Z8% nDb|H䝐MDb(&txt^J zb|7|,9~aF0Yϯwʛ'j/N/5`u%z/N[&y7<<=l緃ux$7\=RC.Ϗ[<ç KUѺ䙦 U?QcyJIwz>9 E<-֒zXAf})݇Zc{wk/, W}}ffh$7s.!x̓MwIͪ(7 \3g)ܵHg)VϥBFP2?x`dϮ,Kv[p.{%GƆRuGu{fܚi EReέ=$8zV.O7jTPY@,Ximc,\F]"l32zd2gcGaӚ|ĽFyRC_PK@ցeU$ rebar_port_compiler.beamt9 xUUNSMK9Bt']NBNB8IQt+I'} DPEOb՝quX?GWq\w/FGw^6_Um #hnmZєK'&a+ŬɆ3l.M'3񄚵҉CY f7T_WsvCKg kPMDRyx/]h&|DҬ}Gj$%(&<'PsjQ 557 B] LD7ԾxJլiC%bu4I&+2$̭q-ɂHBS-jEщx/1E#ywP4;uȩHR-TGsjJS|6!(/.Ӓzi֬:f5T5Mx$"d:1vMSCy\22S{4)d21492iX<+˦j_X_چG"Yk:Ct x)&R@?܋GzjͦZ"}L~Up*L k:8)-H C,d= 1\: x)DU1Q"ptNlN YK4Suʊ΅icZNM1 E\AZCʼVr`VD]Pk<M T D [!tx<7zzc#xa-F5Kn, 8rcIFNpӘ@- 7 5!МI(ڴ.L0=8=^`@3_J垳M$SC- r!6ѣ *0s)ՙ8ŪXhv=Yt6cYbiӤ\RMقH,퇦daLW2KbI[aꆥEOBY \c+S8WD%/ȜJի1b3'n+E+9VE"B.$SET^u;ق.-CvX|GkimB<EJ /|$EE {BGpB2YqA5ÍQ3  x{g10b!P8bbP)~'!˺_u . -Ed:U$7t|1c r23VV Nꁭ lMR5q.qaHvbfP!#"LM?iA+˗>0{Մ-vp4GK H˗'cy'v'j/e2w8,gŔ fjQ.Y=3VN%!H>Rfd 1ӚP#J Z+1.rP &NtUr +W0`S3! (0H#Y~LʣJiT$W6'S4,?8FC3vA)R甠*q*a.0,%sD*L@س MtNjp[d팠r% l16N`jx2t"JXT܉Qكyؼ6àv `p(Н"E%'W"lPb㥱 `C?ј[%,?7@k$ X~LA%tXЀz1޲ ,* GIUa%6EmD+6J^ (W"Exq_@7J+|e]2΋pꉏ Y8l> <,__LT8,+ė'{x%m/k$ Y^0gk@x/Ե†'hD?eLjhbn@F~UzˏT izRX,Z)Pɋ<0,YG0${OOsj ɭ$)q)~)M#`h&} s TvԃUd B--PhX}P_m9]o-Ktgl'zN& TD?lWr g6`8⃮(cuzi ɟSGZٶiQW-aVTBdwLiB(|R]Cȋz KF_b9S* .ض C\ۡC 1Yz%&$+X~:1[6!;*bYUjtY.7$ٶA3p0tp^c3CV=eNż <уV(BK-*J _EW' ? ց1w =B+,OVAݺ5I'CHfCJEõͶz:89Pp9X?W!~:2qn3/Q +v ra2|ς?3ĵ!3,",% 9)h۳w;OU ld1zfq/ S,8 W[mC i~*A: euG44 {*I XT N]mtѼBH61 tÁu)qd*IE[LMY^ F2q8OX~@o?>bG\mSCJ !_ ȶ{'V) $x/iTjx,R l3hb= YdUDqY3 p˲|N&"a6Fd`B5Y3Í2F6&l2]$6L6~!#z_&Qs9IC(7c(HL?}GƱmw+ula+ ~׷`waCXW 5@MXg@MȬ6\j\tr gigFHXk6KF&W !vu&Wc.ĝI&6 !#w%$kXZfd; ݅>$o}C$6.G~q9 |23- T7֑=P{s7~c7@2Z{Hxn\Gn7AP|T/b */@Bއ%2GntMO[ ]ne[+맢_ܡ0ƫ%v+7]Wv Ϻ;KGP z;_Gn#n#sOUq^yBp(@ŗ:[?d;NQw٥w nv%g>3D,Mf L`X`J0l0` /10J`§˜F3a0f.1D;Q<tUR{L L8> Ð) -8_Du&)9—P`(&4/6[Lzu>sJv5 c _n/2Oqdɟl( ~s!R8@yQo)۾Rxl>q3)?&7ᑦɿ9Eܞ=pSE9]}cG h̛y~hå˺m5;۵sw~32/l,i]r߽RS䇏)ֿڞYH>r~-s}zJimҢ?~)}k+u'^.[{b|冫 ~˻o΁+_PCE?8{G2,|0}>KoX/b'_ncsi/0:ӷ}{q|]  {_z\vߡɲoį#.7mVݖoZ~/_;}_uGk /*5Ƴ2Yrs̾Ou?U#Y|vSÑڷ~ְ}Ȥ˦t/??|2oE7n <З [~wQΊ铷[dͤO~zsx_?/8rue=,lWT'SMe6 Ƙ8؋[s-ᮥ+ZI5ߢ@zLj'5ҕmxNZ(,.u+|yA킅Iun R){Ī+h|lbxפIUDoivkǛ`#6>=!m _Z6/JMJ,//*O-I-K-b``pL*.R PK@ rebar_protobuffs_compiler.beamuV}lg9ؾNk˱9]28utmZ>{K;BѺ„DmH/`STU(B1-TLCt?P:1r@Xz|}C(f̸V !oE.m˵r)ZݨvSB-F5NlZ 㳖YnZutnۖ٢VE ҡU\:/Uu%m n--Y?S1J<-MM,g 5΢֚upTk:WTRMSL!] 3Ȧ7u]{,@Q䫪jf ]c>]-U|Qv:%l Ӱfؤ=E[VB^ݖ;K--C7-h;@7̲յ73o ȤT̘4KmdTwʫq : C?gu1qAJ J2X9D`d,&CXU9$(,~ 𽈙W*L9""!}7Efuk  "Л̫\;s'bR(!<p ̺/&a! V'ʈ >m7n8iwmwLe$uL$/L"lk lC,O J>49( Dr!XpzD bA| A Oq" 6\6}lTtopG@vym1GK6x}&=nOG^<ދyצ6\;p4v;C^ u?S[ 6m/}O?mۯ-=6ƻ_xOGNv_?_^Z8oo͛_jw_y~NZꨥvyc^*k] OoZ~󹡗?{sn? |~vݻNMpf{{YxkH=? J ͈^ӞNgo=ypzF=>Ox7.o׵nW^qI+_ݎgIy/KKsfl6,kXC 7ӨT%tX  "Y64]C SG*lٓsQ׸<6.,MwjDac(hDf|b4ԬiE(j3c]W:Q;ԨJ԰hX /OKj;IHyZK#^Rg,{٩Xu!9vItiYB3EǥCPK@_"O| rebar_rel_utils.beameW}lS9~8y:hxbIl4n~ N{|llbEҭkU1ER::&ֱ&kI@ڦu؆k߀"s9wn݁PHucfu1CH1lɨ{>>X;pM8jjA܀bHq!NOd)=9TpizfhRI8u&7;@0wtpq/y)~^R +W%ȡ4Oc5DI`9JT Iܹ'q.E,ϭ\MM%yA½f]M^?nG(x ѲҫbpVa'&@ywA3r"DHegNҜo?@2'"7qBX+'"q>O*P'"T.ݲ@X@0X`^ ˪ī)YR# '.L0XJE!ŨɈXT?ĩ.EąNT!TTy*.rhFH`@eb#l.I p IN55U9wNLqBWA ?E@Bpt闥ʼnAqģF8J8&nP 2դ"Ij ȠZ$BQVɾ1Y`Q(f "P Si`.=^"|xvoA@8TF .v}bӵAXe,~%*C9e1T0Ƭc:YH DNHE{jxjpJ5A̯2miٳjZ bXXåL8VS?>ׇzc~];r/ѳ_:Y+oo{|[I,o[+?? %?>zg3Z&|wϞk_M}47>| ڸwScK?s[?>=fM?6~KgVMu37;>C.lzas?}<|Kz]]gwcO>l7]ō.5uyz'Wى?_:r} \zvSߺ:j~3q?;++3֬,8' 9"|.T&|喽7~ #[[i,:9xRC]eV.ufɁ8uxgR G\!czf714ckz8 uwDݠ v?:Gse*cH#wx' z]Ӛ45h A,Y}3R^;#[l ZY01=Sz`L!!r ;l;pPK@$prebar_reltool.beamY tוYcYc<2`a@Je,2ϒea`;cil Ku$4kCpR/4M4$OK9mْ%f% eMBH7Og3gszs}~7m[70̜P%;0&jt5״?fT]ɫ3X!LJSŵ@rPTh./dSnurUQ"mئ꺦(ɔ(1ͥAXSJfЖҵvm<)Uɔ`|$h& 5՘ćJCj|86pq-S~inR5=+%JΘgu-r1 aJ!*Œ빤)jڐ|@ &Kt-K%sy{^3>)`$uԈQҟRs6LN'lJ*rı%[r%BQB4GTA-)d*lVNӛ6QLiJʖVxSb eA?WH]`-F(lAIL=@|Mff \^/v1fz!3Mn%˹wksZW$2Ij8 hz\-IYC8Ied&_FɌ:IYPxlBdGma0Ӓb]u;s( vzl 0O5=OqEOufb^̩Dq0?WLq2Glslft޳Y ]MĴ,9P@qj<0f75M8-Hwt)DJKZ0Kȶ}Exq gQ>p8Dg3~OhD,e&‘ûI|ð|$WYm$R@VLU˒RgUׯC_e7DyOX -dwt&N`+dypwP^65~a=6v ,&f⡰ k⠀]Z6a˯ᨣ+Eݨz˯wc+T H.KHc$~e@1N#1"[f5cAL@~X(,Òs68nZ0gv ʍV3nFr<V L3 K;$AB ߼U Jr0",cX#,HM0|~fIr4f7 ],0q΋ӊA~Z |ۨT?6_d~PB8NgCb#ˇ`e"2GryѴzp&)@(o$8݊'z `䭊Z n4_)BM„{nJQo$3!dABB Qo3 )1l_i8PU ؉.8Wp&Ǭg;Ba9uRu/9P%<8.w<"w=hXDyp7C3ZRnM!mn#m$mS,L[!DIj$WuhR/)Y2^yhMFѣQ ږ$'L;H$mn+"\6 rhzЦFpG^χq4B{nuV#ˈ7hxpLO$*8ex> LB@ ;_Hߡz@zd@";Ir@(paApw _M2A(/Uf7l{V 1-l^hTs/y51Zפ,9d^8{{, &I<+p %0y|hOgh0``tnbv:/2+`HgMs`T(1<:'X2¸V:_ c Y cG|wz~=m3@|%_c5Ol06н[ –XZ-F،Rf[(NN ?-1vS9a/,Tعʉn ?{,ykN QCTg%%wd^9@Y[tv:';-GjK1 /8jA I|:~fmIisG|нg]㮜h7N>3tkO߽`ۑ(7iƚw\s&z~nq|?//EM#Ǿϵ`Ծ;>%e?Th4[zgսM/qw}ž#z w7={6= }1CxǛ U߼x݋^Ug nU;~r'~IMn}xi?W+^sf{k?MU=/Wίa;߻Z?%7vI_Fg?]oG/+?ޑ3(鹕ןY-cPsAȝ'a%}}ѿKm?8>5\wױ_=y''/?XمJcOyݧ~AKOj=DT?o̻#v-Njh-[k5Cwϧj5IP.[j4SmtNz[%}b0=Ior+QZy>Ly(\xȈL~o`;^Ƿ/nfv}%删8ܱ\!VQP>pj2C$lr'3T!&!XK$G}Kk#2̔7lXkX UJmX{gat0+}&0c ԭk"2.LCbBb7洂W۴T!;ة ҵ}j<7ݯù!-[o\7AcZsyBPK@-Drebar_require_vsn.beameTMlEٱŨEkiu$Iܨbw]wv74CS "R!r 3P qB@BF{7{3;;.leRm\a6FIC5Jx%]57L$eSZh.a[4&:=9ZVhqE"TVs\ҫV(AԳ=ڢemP' 51*c-<0ڰ;=ֵ>rKITD{d(1:=4N l2C!%! D"ij2ܭ ֧d A o%0J (@ĢR "+"{[?JX*OᢜHTwᵇ JdQA>$C$b#$<`/~LqEGzXAa~'#3,Uo|*Q:viX-b`0@(ä3~! Y?a} 3~^}>Z0\_W?6C'OwΊk٦r:5sO~9lwׅ[wߋ|;u|Rso' "_O<͗?~4V7^ Vo-Unv˝ƕg,Bk/#PemZ6s]3o<tN, K;]tVKV/}<cRS'l 0,FNt0Y:iۈtDV.6jiY%U22K93&wVk ]m]<-v=@-X5zjR㪤NAFޱMG: U!GWluv?=|({r _PK@ <rebar_subdirs.beam]U]hUwvgInn52t"ZN~6mR*7?mhӄ7dgg֙HJ) ł>"e)/R-T/R轓I[;;strA٣W񛫦GkP&e *Y3dKoTڮq_Ս[KԨ1m$MN r=Zm˩`af/;ٴirnzu]pgsFզ]25}IUizulWbkaWq yzEcɵ;T LJO :]O'.ݦgX.rfE8<7W8<d˞A/lY׫lpӯ{FLW?PK@\J]rebar_templater.beamY tי[à #0`3lc[L<4 nS?_BpӰ&r&|A&r٦anX%]gB|:<'{:;pYAancri AħG-:yQ^xѽފE|&< =Z3 5qMZ=].tQI4;+ l[9=2/'*p(ŠMwɪ]85=^ETEd̀m/΄ ׶buE@KӰDH3WE Pg:x8[^9xMZ` =18T*U(ݼ¬f˦4Z!A=PgA4U*S7H{Bvq+U.q $ ᔖ怖@m`^1p·MEu>Du v8C44x*Hu]E!_c W^HVՠbS{xq![x!ZB()/j^"9 (y@*Akn1!EH@ր~kp3WsIc%E#] iEAOZH1]ujT@p׳u]U i-ׄKW[*"Vřڧ'}I[ Jaj܄(7*q3/65X(>:4Yk-Cu:QR/ť=תHD )>Ѩbz 6J?h4Bx/.W*@R eq6\A' RYW?"$4wY-Ӗ(eG 4VkJ{V&]Dw h4s!q'$N«vhRZנU8[ R'=E|]WbƅtWBvSa*ޑ#K,}| EV,dkMԜ`(uM7jq$,#uŋQ` *q҃tIrNi#Byqk8۠dB Z5|&(˨3x#7yc690/nEt7q+i"1]cQ8RzZviŋ^9:p<@$JPM"C\/n=rlf4/@8ۈM9!G 4ro)JBD^+q n_iHy+醂"1üePC6"@P~DP\P%N,ܝ;}g)$8&rkV^Vw2ިoǟNjȀx%;Mxq],'&JN%F|?y/c3=(pDpztu6^-!wHq%_ҋ]M *ׇBh`Q Og=l>+)QpWПcCP>0O:Y\tz~F&Ua2 CM80mA,RTrf‡YjiAG:Nɝ#ln=iN=A=p4À/4z@?~a8fUaIܵSS`R?P 3w_0՚Jcr *d{^Qx~6{)\!ƾULo6rʡ=D10,`ߟ>w[>^ãHA\W_V%!YCQMbc2F 0f0~*s(3~5.˓3/o^c4S7/6T2]C {<FM?kb4gt~y[0d6)|.O۩Ͻp4v^\Y/tlOw͜T٩򷯬TS#;FWؽ˗ϝ>{Z_}FNO{bHzPyWϬn4{|/mG?6T]ꥣ{i7Va'+|6w;K ~+]nWO=u?^g#o.ם}?sU~Bvm䬳bW^lOˑI-Z_SgݱO9ƫ5_?{=U=[][^?4OM晇~\q#ؿtzd#_*{KC?~j;͎tXwS|/ #0`l`5zP)}Vska`4]ӗ=F5gd2&T#ơ+e?dJ|[[WB_p&NYt0aoM&#(e(Lg39 Fo0HƸIB.t  x& .|Zpz$dS[8X8+'m8jG>Ҽ;=,  ZN.} ?>S/,\0[& a /Y!9°9>LH9q(#Su8aL2]Pm<0YDžf:Zz ͧ?af7)­_h0f ^` fZBbFIBݦkc Kd,@ AY -5f8s((pkqw{.JAs$Z@ABP1@cf dw2s cǔ~}h4G22l ٥2 iCN[β˟X4ߖp#7?b̄||\& )y7?\M_N=Qt {ru{=uz{cKV,/z}ݫ=C>ѓPĒ7C{>ڋ;驒M]oHǞhBxrSeoz?s_?}ku/Omx:?{k5;##CG?-=-ܴsڟ>7}m_xzC OH[يwvOncm_i=ҋwLE C= ?\ușKe5E[SV9JW̑yvV:~WfXAb/i]VNtbgxg9 =Uܞ1 mQ!R܉0]A-i,oSZ\NwDMv,)5hi K|œD:&Ũt2& ƓRl/mw FC#TnwMH5\;#Zױ~k|ScCS ڴYiX{mmZ|T)扬#U9D9n1 ]:%=:ד2˩::U]N-mZT PK@*Lrebar_utils.beamY{tՙ[c5rw&t-;c)b'qLb'X-i! KSe K6](p iiOZrv9@pvΆE lK)}d e4~w~;QzlmegݶQ`0M}T3e;N\^ޜTc, zlWiyKqv)iy]jkted8fHtМ첩{}ruvE]hLF2*4 zTKkfce93r休!@JQBMgS2yݜe(ۥ=@P2L;i鶝+fZǎ|8($ڝ4}bgy *G}՘O}cDZ^F}@YEc_ҲM>"0Lڹ^CG k}z7%9ZOQ8 `2s%;&s%.euZZO׏);zK9g멲uX ٹݛLeԄuIT_dkꓺ `QDbpC`7x&Ky-RM_;i'uDw;3uȗy=>Y2I@\yAh0J\Z9ehFMյZHC97rE~m|X4 U(j eB4~ۄl:>s}id)ؓ.Q םJCϺ BPGK8 u%TkZ%qG\[.J ]k3C_ 2]BW-|ЗSE{ڨ U}[0ɧ(Gf > E9t h9+zVa/D:"G #EljU6V@(㘿VLPzΫʝ٨/#)%qG{1Þ:2R}"/>-^YLr= {Vd/Մ#գȾ65_!+o#½^>(Y>Q2ˋJM*iopjBTLUFԄ"M NK(Q\y6{#hIgT}2l>vRB(&շ'Մ*#`AX:ѫ""D] "HR$HA ~P@AY Jj *7~Uby-nle7 3Hb è\P HeƫH_}l V+lg(T)Hx0sqs,0"]3 0$%*1$Ƣ<Lj^PϏDL*hP#~-B)APO]"Ճy|PY~A #zEd,2\%Aը|/`tdD=$/ @րyM$O@$%7(R(aizJX|FXU&R@ؒ ^gc)oZ֬X,43aa:SMjgز $+QFT +,on0,e٪GR #9.bv9`\<h=Dd>XO*yB;&W@p8 5uBt> a|Q6@4^M%s<04(`ꈰ.,#>aO:}6 _,td*&%| PN9Y8ʼn0jyΚʵ]8Z|uʨ _ݐw#6ݔ) o \wDP TIGd D8 <(u$"܅5PP1E w>h'7 qVaTLƘhLLjkA =mB{>:Supd! J ;?qohzcXr\a0ۀׂۢ{ƚU䈃G& _C|La=oߛaA#M/I7!CwL~8#c^/̇bb rb 5ai,mܔ#4)&J[- vCK x `0 v'0&pw `8Xw,<p Tj0^ $G EI0 ߈pOne"%$CNZG=-qJ O: cb,t٨^[ctP_凱uoThaaIqj0P`~AK?ݍDB/5{B Wb#&6, #!CN!KÕE 0'#Q%MQV_M|r>(;.̠mn×B :K<=q[^-PKc5P,t?5,ri%@Ky;57ZB1 P+݋6aWqhEs3@17DHTʉs_O=@ Gn.-[]>:í0P|x]Ac.(\-c iz3J chlTf8Շr|*\_\_?sϦcjc7k(G`s&<="}-t: i\9<ysK zn\ExS8^\rY4ᙡ1SgM9}~c#۷vo(}sqmWgďJO"խ]o?|읪C]nXOVЙԶm|7>Wǣʽw~oz޾rg򮿼oׯO4k ʻ~x˛=֟xdG/^-27:|]E[}vܟ'?F'U?{=g?xwk7_ISϿ³_yW;#ޙfy}g^'CԾ~;~|~U狷O?FCo>>twrC-/~wynԟ ?Ο晗rͿh>=<'wvC=h{|F Ks~ ϝ䓾o_~롃 }fS]?B&#w {(/ՋFuyws]/v;yUw~rt}| cKSLCm㙖݁Z٬'͐IL"B=_z|sz]9{2k!:_rPmtΜ`8}4WD`b*_NifZrE=%N3Mz7'6MYڙl] 5S ~Gl0߳erG{[G$1 ʅCM0U֬@?Pg{֪5&j59` e/teڰ~}v 䴘i`0q=e[-3 +kZ[,3UuZPK@i rebar_xref.beamXlWėK$sӴΏs$vڴg;.I@c8g8}ݹm ?!-VBbL 6ImMڐƴilCLZA sT[{{Թ!m%R񹸩U:E}={EWj0LE7=:gf\銾PUog/+zT]1JP[lV-VЊj2%#{IszUiƈ& BIWoRyҠnjAkflx13@KeTTjM+UiE)S͖cU5np M7lU35C-4Ki4VJN;jU_lV͛%+Am0 /P UTWU]fiëT*EȐ骒_m[yTrY̖V_h`U oZ&@Z %c •bxJZ#@Vm,irMJQͪeVM3R/\h)E_i YCyu?.[Be*T*9gw\9BM^Lwg簨VlZ,u^ W%I#1<Р꺦Mn/oShcӔSWK% F]WoS]3$8$pL ܽA  ;I t< rrDl !>'(ˈ{A 9˺(WdDy M bi=O_NS)񭔥&iXK,[X+\r Mfy9a+~/3H^:k-EJ2ӆ&H"> d: {ȪL[\d&7 V*Frfq^ӮS~/`O3m xͽ+ϞEKӈ|cz}^ۑoۑ''o YDǶi,P{(q<)P(Aҭԡ](ևƁX." p2٤[]pw uˠ 3IR}0m S^i80o3@yA_ NyQnűy%{> Oז{`tq d>Ht8v818$rB" Q>P&kjRR  F l ?,tgI p { % $SaOVN/`vrI0(nP2(s,Jn%"twbB ;=C^uggF iHfd&j'>1t !EڍP2dZ я=|@Noi஀H|}$l2a#!!D3k&$%q~9a0 lp;kA\' A9b+|$ I"`UgQ;eCb=-$x ^a&aO@$'2~NZP:N$Hq@D<&a1O Not?Hoj7(9$ pW!f@SG"lw؟1" q` %;;W$;QQ:je0aG0̌EHwI5 8eO;OR 'A):ƙ^#H$F<(BE$&oֳ,E5_J>2L'겯}򑈲&NB >a>-sSt.:! Iғ6}N9@iqdfAE97wӠ~wH<سP{IlJ3{Uqӈvp σ%\c6w1&l2  _w$n#XQ6T ,I?o7"Ig"/Ș#g#L "y3@M3o$:#}θ;y K.a.#]3q ?81ḬkG\~;'Nd&|v~ׂL] gЕkTg%G9#k2ehxْ1 [Wt= <}f_fw"OGyK|ߜ#c+A3μ2m@ǜr㸎:V =\+cUO@rOy|C鵵L{K^mFX X3k*EZ̈́WuRs*搥u[˵Z ^W X^Kа4fC0/&3ٙsDJF"#Ț%U7u!2868yY9FŧpJ_׉ZVQ9%?=99dΐ^悮!_˚njC_8Ci9I/PK@c8ppriv/templates/basicnif.cTMo@+FTlDWˇ(ŒUש(%V+XU]kY.7 yo<!"6 qy-+UX<64I*2vDD#e|-Ko!U2 ~3#:l6R(a=FI.P˧е ay?fLH6֛q[ﮔ!"zϘj)%t*Q: !L^9mZNI}f{6Dt:9n3QO+ \ШϵU Z5mGMc[ߴĊD Y  !EB7ngV{͉c8Senһ#&pt[Isaݡ&Q]2B\L?@7wx\n=~PbKx'6wyGjYYni Ȣ>ܗmJeVfv+ۅ FPK@zpriv/templates/basicnif.erlSKO0 WDR)cp C<`=jtc4+#$Enx]*@5VvMHw`t<93?YD:JQIm8j"He㋫IΔOf! WA;.U#+,hP5UZbZrLJQ)D&S6H!$bRv tR֒}L7Qq |i*3GeуyYK}WL,I ޿k1'bDVH\'Ir`-0ci|hQ?N[ԛcη^i^x*PĶheW$njV2X$bPK@"'priv/templates/simplefsm.erlS]k0}We} 62_DB^5HE%VZsOϽ9 U@y I Kj 3{\ б7x#{_o4{,oB!vk" G>:54WYf_@1h`Ch?vOYr $0joߕ=isF +! B`.ݩuY YYKMkJ9;Hsi}ryrC3 |uE|V9K,i)U2GNy?(X?RSkwVJsQG,veSP*:f;J Alt3Fb2)tIݑa9Awwf?`J5'k&dɥ#3xy[vef^^fPS ֜s?CH [[^7\EEcR\ dp#j; 52~MS0if]I[K.90Tqsn,pѪ${" _pr FkLP}z#%%!a)'u WL`Vr(1y 9(&),+Y7*zSh~hC>ju(&0kfSCAs%yfoa:&Y/eoЧ>6ZaU>VLvtڅ՚.P4$qL(gc,u3FeQCK19Q4V5{JY꺗O@~wd1nnZ#1;WJ}3򈕦@ԨFbP)hwc`-ͭʙU#&ϼ52o2"ֽ9[^9QrPM3ڧx*, ̠vg7>X>l:SZɢ<2QԦ.I@}Eiojuר}f'qN4Pe c\ʬZqiB_A|[[pllP^vXc3:' "P'=lWhl&gJ$HLv>)hJ{~#8`@~a@ ^%;ˀ+!=-En/dnK܉sBl!Y"0>n r4*N׳qknߐCZ3%mB-|gl)l3ݓoRI7b$}Sow*b5Kg5ߋaI}c;Ҵ7L-WrAf3 CNVQ/{rv4JeE bmPK@vD(priv/templates/simplenode.reltool.configSn0#Hm@Vjogd,k6ʿw77opw_- UO -?VD=#zxE; \?dֽT7=4hЉ}8!1 NC NU}X%&'8Vk̵2WQt]'ѰFEIa8=-`v;2prv$#}i~$N!MD%ڧmSp{m;I va|ޚI{%,3dpOZ:.TL'p)9kGq&2_ Z8qq6sSŃ1Cf[3+t{NiIؓE$$  x;LgU{{zm+;ZJ{RϘ ՛LwV0.'\!ҴMO. WƷ~Na aڙLoKw6& 4,J4JUh1FxFUJzwF/׻§T \p}k*f pk5ubЛas,?3]<3y~d'FVc\ywhWNf[IL6Y@ǜ}Z _[άh[?]`FיO.}9pJΟ{@  H_Qa@|a5?Udc!uCY7[j'Z`%#QUniD~i?=+|ieqկo=CiP"|0f8a"e4whW7FE=զz˷!ӿwpAKyJ? RưMbFn* mHzNIF 8j4_9*\WB_Az7XWJ^JA~~i(^~JxhX-"jp&Qx2/9x]=#VU)Z8pd dW>rzH >tRfTV?dgz0q"cL:Ԡٙp'֨Ji0 dLcȦaζ?4!H#RwRleH1^+o΋|4ԴY/ئUK5k{0iM6Уt Y?PK@8&M$priv/templates/simplenode.sys.config}0> I#! b!$`M 8p #9%1 }/amRyG*c*en@@z3+IΉٖ|2e?KDm)oQ'>=XWP6͟׾SV`az'c|~eX#L;cٚ7PK@d(A"priv/templates/simplenode.templateu E cnLiZC@7dr30_AݝҔqZdcG'gl,Cɢ VkV`nĘፍ%hC7yKײL8pCڪ#ER@7c'B-B xŭD0&8qEuCt1 bPK@[eQ5!priv/templates/simplenode.vm.argsEKo0SҪ UV}ܐlJF~ס䋽;z!~E`SHCSӍ'D``L (VSHy8W$=rI  ޤM1t #bBN48jֆP ;Nuw(Np+Ն.6]2n=2X%m!ݎU܂%Y8qo>n7V849vcʰ DVUw"% b9p};r[^60c{m5~lPK@NE,priv/templates/simplenode.windows.runner.cmd}T]o0}ϯ䊪$+}DԽ0mRd XM6 o8tluu1j -c،XNFtrJ@:Y:yųU[BٹZScc@H 窤b>`fnǐ* YT 6bxxa' qg74LvyrWuhƝN(g|[޵3]\Tc4pgU-F_/}dPK@.Z/priv/templates/simplenode.windows.start_erl.cmdTMk0W i]_Z˶GQq*jKF Gd'4tFyoFvjյR~i4d'@fO胠Ԓ-M)!8U2H=7%l&gU*8#^.TV#,JMj%d9_0.Jمyz%Uj+!Qz:ATK5XTf4>ňp0NKmyZ]XNJSYy̏h 'i.] ebn̝5Υ1w;7-*S ]~莠aBDZhlt_\n t=KfmT4hFJKGeJZ:˿Ei`Vku|xSS=ApԼ30 :@:+T Op5tja?!rNҎMft]6AjjFt&$>>[͚{([u"]NUPK@Z`JV!priv/templates/simplesrv.template.K,LLI-Q..*LQPʭ,N-*K-R.I-I,Ig@uzE9J djZ PPK@;+ getopt.beamPK@[- x )mustache.beamPK@F8{ G rebar.appPK@Fel_} rebar.beamPK@X<-rebar_abnfc_compiler.beamPK@!t #3rebar_app_utils.beamPK@fF# 4<rebar_appups.beamPK@0G Grebar_asn1_compiler.beamPK@x Lrebar_base_compiler.beamPK@#20Urebar_cleaner.beamPK@ЙQx Xrebar_config.beamPK@"$0!_rebar_core.beamPK@2  )srebar_ct.beamPK@6h=)mrebar_deps.beamPK@,EUTrrebar_edoc.beamPK@(ϔ rebar_erlc_compiler.beamPK@X. |rebar_erlydtl_compiler.beamPK@bd rebar_escripter.beamPK@4Ӿrebar_eunit.beamPK@ rebar_file_utils.beamPK@6_arebar_lfe_compiler.beamPK@01prebar_log.beamPK@gD  rebar_neotoma_compiler.beamPK@*%`  rebar_otp_app.beamPK@ցeU$ rebar_port_compiler.beamPK@ $rebar_protobuffs_compiler.beamPK@_"O| rebar_rel_utils.beamPK@$p#rebar_reltool.beamPK@-DP3rebar_require_vsn.beamPK@ <,7rebar_subdirs.beamPK@\J];rebar_templater.beamPK@~SI yLrebar_upgrade.beamPK@*LWrebar_utils.beamPK@i 0grebar_xref.beamPK@c8pvrpriv/templates/basicnif.cPK@ztpriv/templates/basicnif.erlPK@+R vpriv/templates/basicnif.templatePK@Ȫ8Iwpriv/templates/ctsuite.erlPK@}OP_|priv/templates/ctsuite.templatePK@v %}priv/templates/simpleapp.app.srcPK@yE\!}priv/templates/simpleapp.templatePK@k t~priv/templates/simpleapp_app.erlPK@O Npriv/templates/simpleapp_sup.erlPK@"'priv/templates/simplefsm.erlPK@DrFS!jpriv/templates/simplefsm.templatePK@8[npriv/templates/simplemod.erlPK@6V!priv/templates/simplemod.templatePK@+]I;D"priv/templates/simplemod_tests.erlPK@DV^$priv/templates/simplenode.erl.scriptPK@,?",priv/templates/simplenode.nodetoolPK@vD(priv/templates/simplenode.reltool.configPK@f({  priv/templates/simplenode.runnerPK@8&M$=priv/templates/simplenode.sys.configPK@d(A"+priv/templates/simplenode.templatePK@[eQ5!/priv/templates/simplenode.vm.argsPK@NE,priv/templates/simplenode.windows.runner.cmdPK@.Z/2priv/templates/simplenode.windows.start_erl.cmdPK@ø[3priv/templates/simplesrv.erlPK@Z`JV!ȟpriv/templates/simplesrv.templatePK;;NQxmlrpc-1.15/src/000077500000000000000000000000001247015440600135375ustar00rootroot00000000000000xmlrpc-1.15/src/beam_util.erl000066400000000000000000000040041247015440600162020ustar00rootroot00000000000000%% Copyright (C) 2009 Romuald du Song . %% All rights reserved. %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions %% are met: %% %% 1. Redistributions of source code must retain the above copyright %% notice, this list of conditions and the following disclaimer. %% 2. 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. %% %% THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. -module(beam_util). -export([module_export_list/1, filter_arity/3]). %% Module = string() %% Function = atom() module_export_list( Module ) -> {_Module, _Binary, Filename} = code:get_object_code(Module), case beam_lib:info( Filename ) of {error, beam_lib, _} -> false; [ _ , _ , _ ] -> case beam_lib:chunks( Filename, [exports]) of {ok, {_, [{exports, Exports}]}} -> Exports; {error, beam_lib, Er} -> false end end. %% Module = string() %% Arity = integer() %% Exports = list() filter_arity( Function, Arity, Exports) -> case lists:filter( fun( EFName ) -> {Function, Arity} == EFName end, Exports ) of [{_, _}] -> true; [] -> false end. xmlrpc-1.15/src/log.hrl000066400000000000000000000031771247015440600150370ustar00rootroot00000000000000%% Copyright (C) 2003 Joakim Grebenö . %% All rights reserved. %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions %% are met: %% %% 1. Redistributions of source code must retain the above copyright %% notice, this list of conditions and the following disclaimer. %% 2. 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. %% %% THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. -define(INFO_LOG(Reason), error_logger:info_report({?MODULE, ?LINE, Reason})). -define(ERROR_LOG(Reason), error_logger:error_report({?MODULE, ?LINE, Reason})). -ifdef(DEBUG). -define(DEBUG_LOG(Reason), error_logger:info_report({debug, ?MODULE, ?LINE, Reason})). -else. -define(DEBUG_LOG(Reason), ok). -endif. xmlrpc-1.15/src/tcp_serv.erl000066400000000000000000000110701247015440600160670ustar00rootroot00000000000000%% Copyright (C) 2003 Joakim Grebenö . %% All rights reserved. %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions %% are met: %% %% 1. Redistributions of source code must retain the above copyright %% notice, this list of conditions and the following disclaimer. %% 2. 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. %% %% THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. -module(tcp_serv). -vsn("1.13"). -author('jocke@gleipnir.com'). -export([start_link/1, start_link/2, stop/1, stop/2]). -export([init/2, start_session/3]). -export([system_continue/3, system_terminate/4]). -include("log.hrl"). -record(state, { %% int() max_sessions, %% {M, F, A} %% M = F = atom() %% A = [term()] session_handler, %% [pid()] session_list, %% socket() listen_socket, %% pid() parent, %% term() debug_info }). %% Exported: start_link/{1,2} start_link(Args) -> start_link(Args, 60000). start_link(Args, Timeout) -> Pid = proc_lib:spawn_link(?MODULE, init, [self(), Args]), receive {Pid, started} -> {ok, Pid}; {Pid, Reason} -> {error, Reason} after Timeout -> {error, timeout} end. %% Exported: stop/{1,2} stop(Pid) -> stop(Pid, 15000). stop(Pid, Timeout) -> Pid ! {self(), stop}, receive {Pid, Reply} -> Reply after Timeout -> {error, timeout} end. %% Exported: init/2 init(Parent, [Port, MaxSessions, OptionList, SessionHandler]) -> process_flag(trap_exit, true), case gen_tcp:listen(Port, OptionList) of {ok, ListenSocket} -> self() ! start_session, Parent ! {self(), started}, loop(#state{max_sessions = MaxSessions, session_handler = SessionHandler, session_list = [], listen_socket = ListenSocket, parent = Parent}); Reason -> Parent ! {self(), {not_started, Reason}} end. loop(#state{session_list = SessionList, listen_socket = ListenSocket, parent = Parent} = State) -> receive {From, stop} -> cleanup(State), From ! {self(), ok}; start_session when length(SessionList) > State#state.max_sessions -> timer:sleep(5000), self() ! start_session, loop(State); start_session -> A = [self(), State#state.session_handler, ListenSocket], Pid = proc_lib:spawn_link(?MODULE, start_session, A), loop(State#state{session_list = [Pid|SessionList]}); {'EXIT', Parent, Reason} -> cleanup(State), exit(Reason); {'EXIT', Pid, Reason} -> case lists:member(Pid, SessionList) of true -> PurgedSessionList = lists:delete(Pid, SessionList), loop(State#state{session_list = PurgedSessionList}); false -> ?ERROR_LOG({ignoring, {'EXIT', Pid, Reason}}), loop(State) end; {system, From, Request} -> sys:handle_system_msg(Request, From, Parent, ?MODULE, State#state.debug_info, State); UnknownMessage -> ?ERROR_LOG({unknown_message, UnknownMessage}), loop(State) end. cleanup(State) -> gen_tcp:close(State#state.listen_socket). %% Exported: start_session/3 start_session(Parent, {M, F, A}, ListenSocket) -> case gen_tcp:accept(ListenSocket) of {ok, Socket} -> Parent ! start_session, case apply(M, F, [Socket|A]) of ok -> gen_tcp:close(Socket); {error, closed} -> ok; {error, Reason} -> ?ERROR_LOG({M, F, Reason}), gen_tcp:close(Socket) end; {error, _Reason} -> timer:sleep(5000), Parent ! start_session end. %% Exported: system_continue/3 system_continue(Parent, DebugInfo, State) -> loop(State#state{parent = Parent, debug_info = DebugInfo}). %% Exported: system_terminate/3 system_terminate(Reason, _Parent, _DebugInfo, State) -> cleanup(State), exit(Reason). xmlrpc-1.15/src/url_util.erl000066400000000000000000000030611247015440600161020ustar00rootroot00000000000000%% Author: Romuald du Song %% Created: 9 oct. 2009 %% Description: %% Hacked from Joe Armtrong http://www.erlang.org/examples/small_examples/urlget.erl -module(url_util). %% %% Include files %% %% %% Exported Functions %% -export([parse/1]). %% %% API Functions %% %%---------------------------------------------------------------------- %% parse(URL) -> {http, Site, Port, File} | %% {file, File} | {error,Why} %% (primitive) parse([$h,$t,$t,$p,$:,$/,$/|T]) -> parse_http(T, http); parse([$h,$t,$t,$p,$s,$:,$/,$/|T]) -> parse_http(T, https); parse([$f,$t,$p,$:,$/,$/|_T]) -> {error, no_ftp}; parse([$f,$i,$l,$e,$:,$/,$/|F]) -> {file, F}; parse(_X) -> {error, unknown_url_type}. %% %% Local Functions %% parse_http(X, Protocol) -> case string:chr(X, $/) of 0 -> %% not terminated by "/" (sigh) %% try again parse_http(X ++ "/", Protocol); N -> %% The Host is up to the first "/" %% The file is everything else Host = string:substr(X, 1, N-1), File = string:substr(X, N, length(X)), %% Now check to see if the host name contains a colon %% i.e. there is an explicit port address in the hostname case string:chr(Host, $:) of 0 -> %% no colon Port = 80, {Protocol, Host, Port, File}; M -> Site = string:substr(Host,1,M-1), case (catch list_to_integer( string:substr(Host, M+1, length(Host)))) of {'EXIT', _} -> {Protocol, Site, 80, File}; Port -> {Protocol, Site, Port, File} end end end. xmlrpc-1.15/src/xmlrpc.app.src000066400000000000000000000002261247015440600163340ustar00rootroot00000000000000{application, xmlrpc, [ {description, "XML-RPC server"}, {vsn, "1.15"}, {registered, []}, {applications, [kernel, stdlib]}, {env, []} ]}. xmlrpc-1.15/src/xmlrpc.erl000066400000000000000000000241001247015440600155450ustar00rootroot00000000000000%% Hacked by Romuald du Song %% %% Copyright (C) 2003 Joakim Grebenö . %% All rights reserved. %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions %% are met: %% %% 1. Redistributions of source code must retain the above copyright %% notice, this list of conditions and the following disclaimer. %% 2. 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. %% %% THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. -module(xmlrpc). -author('jocke@gleipnir.com'). -export([call/3, call/4, call/5, call/6, call/7, call/8, call2/7]). -export([start_link/1, start_link/5, start_link/6, stop/1]). -ifdef(TEST). -export([parse_response/3, open_socket/3]). -endif. -include("log.hrl"). -include("xmlrpc.hrl"). %% Exported: call/{3,4,5,6,7,8} call(Socket, URI, Payload) -> call2(Socket, URI, Payload, false, 60000, "", [{ssl, false}, {header, false}]). call(Host, Port, URI, Payload, Options) when is_number(Port) -> call(Host, Port, URI, Payload, false, 60000, "", Options); call(Socket, URI, Payload, KeepAlive, Timeout) -> call2(Socket, URI, Payload, KeepAlive, Timeout, "", [{ssl, false}, {header, false}]). call(Host, Port, URI, Payload) when is_number(Port) -> call(Host, Port, URI, Payload, false, 60000, "", [{ssl, false}, {header, false}]); call(Socket, URI, Payload, Options) -> call2(Socket, URI, Payload, false, 60000, "", Options). call(Host, Port, URI, Payload, KeepAlive, Timeout) when is_number(Port) -> call(Host, Port, URI, Payload, KeepAlive, Timeout, "", [{ssl, false}, {header, false}]); call(Socket, URI, Payload, KeepAlive, Timeout, Options) -> call2(Socket, URI, Payload, KeepAlive, Timeout, "", Options). call(Host, Port, URI, Payload, KeepAlive, Timeout, Options) when is_number(Port) -> call(Host, Port, URI, Payload, KeepAlive, Timeout, "", Options); call(Socket, URI, Payload, KeepAlive, Timeout, ExtraHeader, Options) -> call2(Socket, URI, Payload, KeepAlive, Timeout, ExtraHeader, Options). call(Host, Port, URI, Payload, KeepAlive, Timeout, ExtraHeaders, Options) when is_number(Port) -> case open_socket(Host, Port, Options) of {ok, Socket} -> call2(Socket, URI, Payload, KeepAlive, Timeout, ExtraHeaders, Options); {error, Reason} when KeepAlive == false -> {error, Reason}; {error, Reason} -> {error, undefined, Reason} end. open_socket(Host, Port, Options) -> case fetch_comm_module(Options) of ssl -> %% Start ssl application application:start(ssl), %% Always seed ssl:seed("wheredoyouthinkitcanbefound"), %% new ssl implementation does not seem to work as of R13B01 %%{ok, SslSocket} = ssl:connect(Host, Port, [{ssl_imp, new}, {active, false}, {verify, verify_none}]), ssl:connect(Host, Port, [{verify, 0}, {active, false}]); _ -> gen_tcp:connect(Host, Port, [{active, false}]) end. call2(Socket, URI, Payload, KeepAlive, Timeout, ExtraHeader, Options) -> ?DEBUG_LOG({decoded_call, Payload}), case xmlrpc_encode:payload(Payload) of {ok, EncodedPayload} -> ?DEBUG_LOG({encoded_call, EncodedPayload}), case send(Socket, URI, KeepAlive, EncodedPayload, ExtraHeader, Options) of ok -> case parse_response(Socket, Timeout, Options) of {ok, Header} -> handle_payload(Socket, KeepAlive, Timeout, Options, Header); {error, Reason} when KeepAlive == false -> comm_close(Options, Socket), {error, Reason}; {error, Reason} -> {error, Socket, Reason} end; {error, Reason} when KeepAlive == false -> comm_close(Options, Socket), {error, Reason}; {error, Reason} -> {error, Socket, Reason} end; {error, Reason} when KeepAlive == false -> comm_close(Options, Socket), {error, Reason}; {error, Reason} -> {error, Socket, Reason} end. send(Socket, URI, false, Payload, ExtraHeader, SslOption) -> send(Socket, URI, lists:flatten(["Connection: close\r\n" | ExtraHeader]), Payload, SslOption); send(Socket, URI, true, Payload, ExtraHeader, SslOption) -> send(Socket, URI, ExtraHeader, Payload, SslOption). send(Socket, URI, Header, Payload, SslOption) -> Request = ["POST ", URI, " HTTP/1.1\r\n", "Content-Length: ", integer_to_list(lists:flatlength(Payload)), "\r\n", "User-Agent: Erlang XML-RPC Client 1.13\r\n", "Content-Type: text/xml\r\n", Header, "\r\n", Payload], M = fetch_comm_module(SslOption), apply(M, send, [Socket, Request]). parse_response(Socket, Timeout, SslOption) -> M = fetch_comm_module(SslOption), S = fetch_sets_module(SslOption), apply(S, setopts, [Socket, [{packet, line}]]), case apply(M, recv, [Socket, 0, Timeout]) of {ok, "HTTP/1.1 200 OK\r\n"} -> parse_header(Socket, Timeout, SslOption); {ok, StatusLine} -> {error, StatusLine}; {error, Reason} -> {error, Reason} end. fetch_comm_module(Options) -> case lists:keysearch(ssl, 1, Options) of {value, {ssl, true}} -> ssl; _ -> gen_tcp end. has_header_option(Options) -> case lists:keysearch(header, 1, Options) of {value, {_, true}} -> true; _ -> false end. fetch_sets_module(Options) -> case lists:keysearch(ssl, 1, Options) of {value, {ssl, true}} -> ssl; _ -> inet end. comm_close(Options, Socket) -> M = fetch_comm_module(Options), apply(M, close, [ Socket ]). parse_header(Socket, Timeout, SslOption) -> parse_header(Socket, Timeout, SslOption, #header{}). parse_header(Socket, Timeout, SslOption, Header) -> M = fetch_comm_module(SslOption), case apply(M, recv, [Socket, 0, Timeout]) of {ok, "\r\n"} when Header#header.content_length == undefined -> {error, missing_content_length}; {ok, "\r\n"} -> {ok, Header}; {ok, HeaderField} -> case string:tokens(string:to_lower(HeaderField), " \r\n") of ["content-length:", ContentLength] -> case catch list_to_integer(ContentLength) of badarg -> {error, {invalid_content_length, ContentLength}}; Value -> parse_header(Socket, Timeout, SslOption, Header#header{content_length = Value}) end; ["connection:", "close"] -> parse_header(Socket, Timeout, SslOption, Header#header{connection = close}); ["x-forwarded-for:", XForwardedFor] -> parse_header(Socket, Timeout, SslOption, Header#header{xforwardedfor = XForwardedFor}); ["authorization:", Authorization] -> parse_header(Socket, Timeout, SslOption, Header#header{authorization = Authorization}); ["cookie:", Cookie] -> Cookies = [ Cookie | Header#header.cookies ], parse_header(Socket, Timeout, SslOption, Header#header{cookies = Cookies}); _ -> parse_header(Socket, Timeout, SslOption, Header) end; {error, Reason} -> {error, Reason} end. handle_payload(Socket, KeepAlive, Timeout, Options, Header) -> case get_payload(Socket, Timeout, Options, Header#header.content_length) of {ok, Payload} -> ?DEBUG_LOG({encoded_response, Payload}), case xmlrpc_decode:payload(Payload) of {ok, {response, DecodedPayload}} when KeepAlive == false -> ?DEBUG_LOG({decoded_response, DecodedPayload}), comm_close(Options, Socket), case has_header_option(Options) of true -> {ok, {response, DecodedPayload, Header}}; _ -> {ok, {response, DecodedPayload}} end; {ok, {response, DecodedPayload}} when KeepAlive == true, Header#header.connection == close -> ?DEBUG_LOG({decoded_response, DecodedPayload}), comm_close(Options, Socket), case has_header_option(Options) of true -> {ok, Socket, {response, DecodedPayload, Header}}; _ -> {ok, Socket, {response, DecodedPayload}} end; {ok, {response, DecodedPayload}} -> ?DEBUG_LOG({decoded_response, DecodedPayload}), case has_header_option(Options) of true -> {ok, Socket, {response, DecodedPayload, Header}}; _ -> {ok, Socket, {response, DecodedPayload}} end; {error, Reason} when KeepAlive == false -> comm_close(Options, Socket), {error, Reason}; {error, Reason} when KeepAlive == true, Header#header.connection == close -> comm_close(Options, Socket), {error, Socket, Reason}; {error, Reason} -> {error, Socket, Reason} end; {error, Reason} when KeepAlive == false -> gen_tcp:close(Socket), {error, Reason}; {error, Reason} when KeepAlive == true, Header#header.connection == close -> comm_close(Options, Socket), {error, Socket, Reason}; {error, Reason} -> {error, Socket, Reason} end. get_payload(Socket, Timeout, SslOption, ContentLength) -> M = fetch_comm_module(SslOption), apply(fetch_sets_module(SslOption), setopts, [Socket, [{packet, raw}]]), apply(M, recv, [Socket, ContentLength, Timeout]). %% Exported: start_link/{1,5,6} start_link(Handler) -> start_link(4567, 1000, 60000, Handler, undefined). start_link(Port, MaxSessions, Timeout, Handler, State) -> start_link(all, Port, MaxSessions, Timeout, Handler, State). start_link(IP, Port, MaxSessions, Timeout, Handler, State) -> OptionList = [{active, false}, {reuseaddr, true}] ++ ip(IP), SessionHandler = {xmlrpc_http, handler, [Timeout, Handler, State]}, tcp_serv:start_link([Port, MaxSessions, OptionList, SessionHandler]). ip(all) -> []; ip(IP) when is_tuple(IP) -> [{ip, IP}]. %% Exported: stop/1 stop(Pid) -> tcp_serv:stop(Pid). xmlrpc-1.15/src/xmlrpc_decode.erl000066400000000000000000000202761247015440600170620ustar00rootroot00000000000000%% Copyright (C) 2003 Joakim Grebenö . %% All rights reserved. %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions %% are met: %% %% 1. Redistributions of source code must retain the above copyright %% notice, this list of conditions and the following disclaimer. %% 2. 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. %% %% THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. -module(xmlrpc_decode). -author('jocke@gleipnir.com'). -export([payload/1]). -include_lib("xmerl/include/xmerl.hrl"). payload(Payload) -> case catch xmerl_scan:string(Payload, [{encoding, latin1}]) of {'EXIT', Reason} -> {error, Reason}; {E, _} -> case catch decode_element(E) of {'EXIT', Reason} -> {error, Reason}; Result -> Result end end. decode_element(#xmlElement{name = methodCall} = MethodCall) when is_record(MethodCall, xmlElement) -> {MethodName, Rest} = match_element([methodName], MethodCall#xmlElement.content), TextValue = get_text_value(MethodName#xmlElement.content), case match_element(normal, [params], Rest) of {error, {missing_element, _}} -> {ok, {call, list_to_atom(TextValue), []}}; {Params, _} -> DecodedParams = decode_params(Params#xmlElement.content), {ok, {call, list_to_atom(TextValue), DecodedParams}} end; decode_element(#xmlElement{name = methodResponse} = MethodResponse) when is_record(MethodResponse, xmlElement) -> case match_element([fault, params], MethodResponse#xmlElement.content) of {Fault, _} when Fault#xmlElement.name == fault -> {Value, _} = match_element([value], Fault#xmlElement.content), case decode(Value#xmlElement.content) of {struct, [{faultCode, Code}, {faultString, String}]} when is_integer(Code) -> case xmlrpc_util:is_string(String) of yes -> {ok, {response, {fault, Code, String}}}; no -> {error, {bad_string, String}} end; {struct, [{faultString, String}, {faultCode, Code}]} when is_integer(Code) -> %% This case has been found in java xmlrpc case xmlrpc_util:is_string(String) of yes -> {ok, {response, {fault, Code, String}}}; no -> {error, {bad_string, String}} end; _ -> {error, {bad_element, MethodResponse}} end; {Params, _} -> case decode_params(Params#xmlElement.content) of [DecodedParam] -> {ok, {response, [DecodedParam]}}; DecodedParams -> {error, {to_many_params, DecodedParams}} end end; decode_element(E) -> {error, {bad_element, E}}. match_element(NameList, Content) -> match_element(throw, NameList, Content). match_element(Type, NameList, []) -> return(Type, {error, {missing_element, NameList}}); match_element(Type, NameList, [E|Rest]) when is_record(E, xmlElement) -> case lists:member(E#xmlElement.name, NameList) of true -> {E, Rest}; false -> return(Type, {error, {unexpected_element, E#xmlElement.name}}) end; match_element(Type, NameList, [T|Rest]) when is_record(T, xmlText) -> case only_whitespace(T#xmlText.value) of yes -> match_element(Type, NameList, Rest); no -> return(Type, {error, {unexpected_text, T#xmlText.value, NameList}}) end. return(throw, Result) -> throw(Result); return(normal, Result) -> Result. only_whitespace([]) -> yes; only_whitespace([$ |Rest]) -> only_whitespace(Rest); only_whitespace([$\n|Rest]) -> only_whitespace(Rest); only_whitespace([$\t|Rest]) -> only_whitespace(Rest); only_whitespace(_) -> no. get_text_value([]) -> []; get_text_value([T|Rest]) when is_record(T, xmlText) -> T#xmlText.value++get_text_value(Rest); get_text_value(_) -> throw({error, missing_text}). decode_params([]) -> []; decode_params(Content) -> case match_element(normal, [param], Content) of {error, {missing_element, _}} -> []; {Param, Rest} -> {Value, _} = match_element([value], Param#xmlElement.content), [decode(Value#xmlElement.content)|decode_params(Rest)] end. decode(Content) when is_list(Content) -> case get_value(Content) of {text_value, TextValue} -> TextValue; E -> decode(E) end; decode(String) when is_record(String, xmlText) -> String#xmlText.value; decode(Struct) when Struct#xmlElement.name == struct -> {struct, decode_members(Struct#xmlElement.content)}; decode(Array) when Array#xmlElement.name == array -> {Data, _} = match_element([data], Array#xmlElement.content), {array, decode_values(Data#xmlElement.content)}; decode(Int) when Int#xmlElement.name == int; Int#xmlElement.name == i4 -> TextValue = get_text_value(Int#xmlElement.content), make_integer(TextValue); decode(Boolean) when Boolean#xmlElement.name == boolean -> case get_text_value(Boolean#xmlElement.content) of "1" -> true; "0" -> false; TextValue -> throw({error, {invalid_boolean, TextValue}}) end; decode(String) when String#xmlElement.name == string -> get_text_value(String#xmlElement.content); decode(Double) when Double#xmlElement.name == double -> TextValue = get_text_value(Double#xmlElement.content), make_double(TextValue); decode(Date) when Date#xmlElement.name == 'dateTime.iso8601' -> TextValue = get_text_value(Date#xmlElement.content), % {date, ensure_iso8601_date(TextValue)}; % FIXME {date, TextValue}; decode(Base64) when Base64#xmlElement.name == base64 -> TextValue = get_text_value(Base64#xmlElement.content), % {base64, ensure_base64(TextValue)}; % FIXME {base64, TextValue}; decode(Value) -> throw({error, {bad_value, Value}}). get_value(Content) -> case any_element(Content) of false -> {text_value, get_text_value(Content)}; true -> get_element(Content) end. any_element([]) -> false; any_element([E|_]) when is_record(E, xmlElement) -> true; any_element([_|Rest]) -> any_element(Rest). get_element([]) -> throw({error, missing_element}); get_element([E|_]) when is_record(E, xmlElement) -> E; get_element([T|Rest]) when is_record(T, xmlText) -> case only_whitespace(T#xmlText.value) of yes -> get_element(Rest); no -> throw({error, {unexpected_text, T#xmlText.value}}) end. decode_members(Content) -> case match_element(normal, [member], Content) of {error, {missing_element, _}} -> []; {Member, Rest} -> {Name, Rest2} = match_element([name], Member#xmlElement.content), TextValue = get_text_value(Name#xmlElement.content), {Value, _} = match_element([value], Rest2), [{list_to_atom(TextValue), decode(Value#xmlElement.content)}|decode_members(Rest)] end. decode_values([]) -> []; decode_values(Content) -> case match_element(normal, [value], Content) of {error, {missing_element, _}} -> []; {Value, Rest} -> [decode(Value#xmlElement.content)|decode_values(Rest)] end. make_integer(Integer) -> case catch list_to_integer(Integer) of {'EXIT', _Reason} -> throw({error, {not_integer, Integer}}); Value -> Value end. make_double(Double) -> case catch list_to_float(Double) of {'EXIT', _} -> case catch list_to_integer(Double) of {'EXIT', _} -> throw({error, {not_double, Double}}); Value -> float(Value) end; Value -> Value end. % FIXME %ensure_iso8601_date(Date) -> % case xmlrpc_util:is_iso8601_date(Date) of % no -> throw({error, {not_iso8601_date, Date}}); % yes -> Date % end. % %ensure_base64(Base64) -> % case xmlrpc_util:is_base64(Base64) of % no -> throw({error, {not_base64, Base64}}); % yes -> Base64 % end. xmlrpc-1.15/src/xmlrpc_encode.erl000066400000000000000000000127111247015440600170670ustar00rootroot00000000000000%% Copyright (C) 2003 Joakim Grebenö . %% All rights reserved. %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions %% are met: %% %% 1. Redistributions of source code must retain the above copyright %% notice, this list of conditions and the following disclaimer. %% 2. 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. %% %% THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. -module(xmlrpc_encode). -author('jocke@gleipnir.com'). -export([payload/1]). %% Exported: payload/1 payload({call, Name, Params}) when is_atom(Name), is_list(Params) -> case encode_params(Params) of {error, Reason} -> {error, Reason}; EncodedParams -> EncodedPayload = ["", atom_to_list(Name), "", EncodedParams, ""], {ok, EncodedPayload} end; payload({response, {fault, Code, String}}) when is_integer(Code) -> case xmlrpc_util:is_string(String) of yes -> EncodedPayload = ["" "faultCode", integer_to_list(Code), "" "faultString", escape_string(String), "", ""], {ok, EncodedPayload}; no -> {error, {bad_string, String}} end; payload({response, []} = _Payload) -> {ok, [""]}; payload({response, [Param]} = _Payload) -> case encode_params([Param]) of {error, Reason} -> {error, Reason}; EncodedParam -> {ok, ["", EncodedParam, ""]} end; payload(Payload) -> {error, {bad_payload, Payload}}. encode_params(Params) -> encode_params(Params, []). encode_params([], []) -> []; encode_params([], Acc) -> ["", Acc, ""]; encode_params([Param|Rest], Acc) -> case encode(Param) of {error, Reason} -> {error, Reason}; EncodedParam -> NewAcc = Acc++["", EncodedParam, ""], encode_params(Rest, NewAcc) end. encode({struct, Struct}) -> case encode_members(Struct) of {error, Reason} -> {error, Reason}; Members -> ["", Members, ""] end; encode({array, Array}) when is_list(Array) -> case encode_values(Array)of {error, Reason} -> {error, Reason}; Values -> ["", Values, ""] end; encode(Integer) when is_integer(Integer) -> ["", integer_to_list(Integer), ""]; encode(true) -> "1"; % duh! encode(false) -> "0"; % duh! encode(Double) when is_float(Double) -> ["", io_lib:format("~p", [Double]), ""]; encode({date, Date}) -> case xmlrpc_util:is_iso8601_date(Date) of yes -> ["", Date, ""]; no -> {error, {bad_date, Date}} end; encode({base64, Base64}) -> case xmlrpc_util:is_base64(Base64) of yes -> ["", Base64, ""]; no -> {error, {bad_base64, Base64}} end; encode(Value) -> case xmlrpc_util:is_string(Value) of yes -> ["", escape_string(Value), ""]; no -> {error, {bad_value, Value}} end. escape_string([]) -> []; escape_string([$<|Rest]) -> ["<", escape_string(Rest)]; escape_string([$>|Rest]) -> [">", escape_string(Rest)]; escape_string([$&|Rest]) -> ["&", escape_string(Rest)]; escape_string([C|Rest]) -> [C|escape_string(Rest)]. encode_members(Struct) -> encode_members(Struct, []). encode_members([], Acc) -> Acc; encode_members([{Name, Value}|Rest], Acc) when is_atom(Name) -> case encode(Value) of {error, Reason} -> {error, Reason}; EncodedValue -> NewAcc = Acc++["", atom_to_list(Name), "", EncodedValue, ""], encode_members(Rest, NewAcc) end; encode_members([{Name, _Value}|_Rest], _Acc) -> {error, {invalid_name, Name}}; encode_members(UnknownMember, _Acc) -> {error, {unknown_member, UnknownMember}}. encode_values(Array) -> encode_values(Array, []). encode_values([], Acc) -> Acc; encode_values([Value|Rest], Acc) -> case encode(Value) of {error, Reason} -> {error, Reason}; EncodedValue -> NewAcc = Acc++["", EncodedValue, ""], encode_values(Rest, NewAcc) end; encode_values([{Name, _Value}|_Rest], _Acc) -> {error, {invalid_name, Name}}; encode_values(UnknownMember, _Acc) -> {error, {unknown_member, UnknownMember}}. xmlrpc-1.15/src/xmlrpc_http.erl000066400000000000000000000211351247015440600166110ustar00rootroot00000000000000%% Copyright (C) 2003 Joakim Grebenö . %% All rights reserved. %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions %% are met: %% %% 1. Redistributions of source code must retain the above copyright %% notice, this list of conditions and the following disclaimer. %% 2. 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. %% %% THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. -module(xmlrpc_http). -author('jocke@gleipnir.com'). -export([handler/4]). -include("log.hrl"). -include("xmlrpc.hrl"). %% Exported: handler/4 handler(Socket, Timeout, Handler, State) -> case parse_request(Socket, Timeout) of {ok, Header} -> ?DEBUG_LOG({header, Header}), handle_payload(Socket, Timeout, Handler, State, Header); {status, StatusCode} -> send(Socket, StatusCode), handler(Socket, Timeout, Handler, State); {error, Reason} -> {error, Reason} end. parse_request(Socket, Timeout) -> inet:setopts(Socket, [{packet, line}]), case gen_tcp:recv(Socket, 0, Timeout) of {ok, RequestLine} -> case string:tokens(RequestLine, " \r\n") of ["POST", _, "HTTP/1.0"] -> ?DEBUG_LOG({http_version, "1.0"}), parse_header(Socket, Timeout, #header{connection = close}); ["POST", _, "HTTP/1.1"] -> ?DEBUG_LOG({http_version, "1.1"}), parse_header(Socket, Timeout); [_Method, _, "HTTP/1.1"] -> {status, 501}; ["POST", _, _HTTPVersion] -> {status, 505}; _ -> {status, 400} end; {error, Reason} -> {error, Reason} end. parse_header(Socket, Timeout) -> parse_header(Socket, Timeout, #header{}). parse_header(Socket, Timeout, Header) -> case gen_tcp:recv(Socket, 0, Timeout) of {ok, "\r\n"} when Header#header.content_length == undefined -> {status, 411}; {ok, "\r\n"} when Header#header.content_type == undefined -> {status, 400}; {ok, "\r\n"} when Header#header.user_agent == undefined -> {status, 400}; {ok, "\r\n"} -> {ok, Header}; {ok, HeaderField} -> case split_header_field(HeaderField) of {"content-length:", ContentLength} -> case catch list_to_integer(ContentLength) of {'EXIT', {badarg,_}} -> {status, 400}; N -> parse_header(Socket, Timeout, Header#header{content_length = N}) end; {"content-type:", "text/xml"} -> parse_header(Socket, Timeout, Header#header{content_type = "text/xml"}); {"content-type:", "text/xml; charset=utf-8"} -> parse_header(Socket, Timeout, Header#header{content_type = "text/xml; charset=utf-8"}); {"content-type:", _ContentType} -> {status, 415}; {"user-agent:", UserAgent} -> parse_header(Socket, Timeout, Header#header{user_agent = UserAgent}); {"connection:", "close"} -> parse_header(Socket, Timeout, Header#header{connection = close}); {"connection:", [_,$e,$e,$p,$-,_,$l,$i,$v,$e]} -> parse_header(Socket, Timeout, Header#header{connection = undefined}); {"authorization:", Authorization} -> parse_header(Socket, Timeout, Header#header{authorization = Authorization}); {"x-forwarded-for:", XForwardedFor} -> parse_header(Socket, Timeout, Header#header{xforwardedfor = XForwardedFor}); {"cookie:", Cookie} -> Cookies = [ Cookie | Header#header.cookies ], parse_header(Socket, Timeout, Header#header{cookies = Cookies}); _ -> ?DEBUG_LOG({skipped_header, HeaderField}), parse_header(Socket, Timeout, Header) end; {error, Reason} -> {error, Reason} end. split_header_field(HeaderField) -> split_header_field(HeaderField, []). split_header_field([], Name) -> {Name, ""}; split_header_field([$ |Rest], Name) -> {string:to_lower(lists:reverse(Name)), Rest -- "\r\n"}; split_header_field([C|Rest], Name) -> split_header_field(Rest, [C|Name]). handle_payload(Socket, Timeout, Handler, State, #header{connection = Connection} = Header) -> case get_payload(Socket, Timeout, Header#header.content_length) of {ok, Payload} -> ?DEBUG_LOG({encoded_call, Payload}), case xmlrpc_decode:payload(Payload) of {ok, DecodedPayload} -> ?DEBUG_LOG({decoded_call, DecodedPayload}), eval_payload(Socket, Timeout, Handler, State, Connection, DecodedPayload, Header); {error, Reason} when Connection == close -> ?ERROR_LOG({xmlrpc_decode, payload, Payload, Reason}), send(Socket, 400); {error, Reason} -> ?ERROR_LOG({xmlrpc_decode, payload, Payload, Reason}), send(Socket, 400), handler(Socket, Timeout, Handler, State) end; {error, Reason} -> {error, Reason} end. get_payload(Socket, Timeout, ContentLength) -> inet:setopts(Socket, [{packet, raw}]), gen_tcp:recv(Socket, ContentLength, Timeout). %% Check whether module has defined new function %% M:F(State, Payload, Header) has_newcall(M, F) -> erlang:function_exported(M, F, 3). %% Handle module call do_call({M, F} = _Handler, State, Payload, Header) -> case has_newcall(M, F) of true -> M:F(State, Payload, Header); false -> M:F(State, Payload) end. eval_payload(Socket, Timeout, {M, F} = Handler, State, Connection, Payload, Header) -> case catch do_call(Handler, State, Payload, Header) of {'EXIT', Reason} when Connection == close -> ?ERROR_LOG({M, F, {'EXIT', Reason}}), send(Socket, 500, "Connection: close\r\n"); {'EXIT', Reason} -> ?ERROR_LOG({M, F, {'EXIT', Reason}}), send(Socket, 500), handler(Socket, Timeout, Handler, State); {error, Reason} when Connection == close -> ?ERROR_LOG({M, F, Reason}), send(Socket, 500, "Connection: close\r\n"); {error, Reason} -> ?ERROR_LOG({M, F, Reason}), send(Socket, 500), handler(Socket, Timeout, Handler, State); {false, ResponsePayload} -> encode_send(Socket, 200, "Connection: close\r\n", ResponsePayload); {false, ResponsePayload, ExtraHeaders} -> encode_send(Socket, 200, [ExtraHeaders, "Connection: close\r\n"], ResponsePayload); {true, _NewTimeout, _NewState, ResponsePayload} when Connection == close -> encode_send(Socket, 200, "Connection: close\r\n", ResponsePayload); {true, NewTimeout, NewState, ResponsePayload} -> encode_send(Socket, 200, "", ResponsePayload), handler(Socket, NewTimeout, Handler, NewState); {true, _NewTimeout, _NewState, ResponsePayload, ExtraHeaders} when Connection == close -> encode_send(Socket, 200, [ExtraHeaders, "Connection: close\r\n"], ResponsePayload); {true, NewTimeout, NewState, ResponsePayload, ExtraHeaders} -> encode_send(Socket, 200, ExtraHeaders, ResponsePayload), handler(Socket, NewTimeout, Handler, NewState) end. encode_send(Socket, StatusCode, ExtraHeader, Payload) -> ?DEBUG_LOG({decoded_response, Payload}), case xmlrpc_encode:payload(Payload) of {ok, EncodedPayload} -> ?DEBUG_LOG({encoded_response, lists:flatten(EncodedPayload)}), send(Socket, StatusCode, ExtraHeader, EncodedPayload); {error, Reason} -> ?ERROR_LOG({xmlrpc_encode, payload, Payload, Reason}), send(Socket, 500) end. send(Socket, StatusCode) -> send(Socket, StatusCode, "", ""). send(Socket, StatusCode, ExtraHeader) -> send(Socket, StatusCode, ExtraHeader, ""). send(Socket, StatusCode, ExtraHeader, Payload) -> Response = ["HTTP/1.1 ", integer_to_list(StatusCode), " ", reason_phrase(StatusCode), "\r\n", "Content-Length: ", integer_to_list(lists:flatlength(Payload)), "\r\n", "Server: Erlang/1.13\r\n", "Content-Type: text/xml\r\n", ExtraHeader, "\r\n", Payload], gen_tcp:send(Socket, Response). reason_phrase(200) -> "OK"; reason_phrase(400) -> "Bad Request"; reason_phrase(411) -> "Length required"; reason_phrase(415) -> "Unsupported Media Type"; reason_phrase(500) -> "Internal Server Error"; reason_phrase(501) -> "Not Implemented"; reason_phrase(505) -> "HTTP Version not supported". xmlrpc-1.15/src/xmlrpc_tests.erl000066400000000000000000000117741247015440600170040ustar00rootroot00000000000000%% Copyright (C) 2009 Romuald du Song . %% All rights reserved. %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions %% are met: %% %% 1. Redistributions of source code must retain the above copyright %% notice, this list of conditions and the following disclaimer. %% 2. 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. %% %% THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. -module(xmlrpc_tests). -export([handler/2,start/0]). -include_lib("eunit/include/eunit.hrl"). -define(setup(F), {setup, fun start/0, fun stop/1, F}). start_stop_test_() -> {"The server can be started, stopped", ?setup(fun is_alive/1)}. variables_types_test_() -> [{"A simple int value is be a valid parameter type", ?setup(fun handle_int_call/0)}, {"A simple float value is a valid parameter type", ?setup(fun handle_float_call/0)}, {"A complex struct value is a valid parameter type", ?setup(fun handle_struct_call/0)} ]. timeout_call_test_() -> [{"A timeout call time can be made", ?setup(fun handle_timeout_call/0)}]. header_insensitive_test_() -> [{"A HTTP header can be specified in lowcase", ?setup(fun handle_lowcase_header/0)}]. is_alive(Pid) -> [?_assert(erlang:is_process_alive(Pid))]. handle_int_call() -> ?_assert(xmlrpc:call(localhost, 4567, "/", {call, echo, [42]}) =:= {ok,{response,[{array, [42]}]}}). handle_float_call() -> ?_assert(xmlrpc:call(localhost, 4567, "/", {call, echo, [42.0]}) =:= {ok,{response,[{array, [42.0000]}]}}). handle_struct_call() -> ?_assert(xmlrpc:call({127, 0, 0, 1}, 4567, "/", {call, echo, [2.6, {array, [5, "foo"]}, {struct, [{baz, 1}, {bar, {base64, "aXMgdGhpcyBiaW5hcnkgPw=="}}] }]}) =:= {ok,{response,[{array,[2.60000, {array,[5,"foo"]}, {struct, [{baz,1}, {bar,{base64,"aXMgdGhpcyBiaW5hcnkgPw=="}}] }]}]}}). handle_timeout_call() -> ?_assert(xmlrpc:call(localhost, 4567, "/", {call, echo, [42]}, true, 10000) =:= {ok,{response,[{array, [42]}]}}). -ifdef(TEST). handle_lowcase_header() -> Options = [{ssl, false}], ParseResult = case xmlrpc:open_socket(localhost, 4567, Options) of {ok, Socket} -> Payload = ["", "", "echo", "", "43", "", ""], Request = [ "POST / HTTP/1.1\r\n", "user-agent: Dart/1.8 (dart:io)\r\n", "content-type: text/xml; charset=utf-8\r\n", "content-length: ",integer_to_list(lists:flatlength(Payload)),"\r\n", "X-Forwarded-For: 192.46.45.211\r\n", "Connection: close\r\n", "\r\n", Payload], gen_tcp:send(Socket, Request), case xmlrpc:parse_response(Socket, 1000, Options) of {ok, Header} -> { ok, Header }; {error, Reason } -> { error, Reason } end; {error, Reason} -> {error, Reason} end, ?assertMatch({ok, _Header}, ParseResult). -endif. %% setup functions %% start local XMLRPC echo server for tests start() -> {ok, Pid} = xmlrpc:start_link({?MODULE, handler}), Pid. stop(Pid) -> xmlrpc:stop(Pid). handler(_, {call, echo, Params}) -> {false, {response, [{array, Params}]}}; handler(_, Payload) -> FaultString = lists:flatten(io_lib:format("Unknown call: ~p", [Payload])), {false, {response, {fault, -1, FaultString}}}. xmlrpc-1.15/src/xmlrpc_util.erl000066400000000000000000000031351247015440600166070ustar00rootroot00000000000000%% Copyright (C) 2003 Joakim Grebenö . %% All rights reserved. %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions %% are met: %% %% 1. Redistributions of source code must retain the above copyright %% notice, this list of conditions and the following disclaimer. %% 2. 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. %% %% THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. -module(xmlrpc_util). -author('jocke@gleipnir.com'). -export([is_string/1, is_iso8601_date/1, is_base64/1]). is_string([C|Rest]) when C >= 0, C =< 255 -> is_string(Rest); is_string([]) -> yes; is_string(_) -> no. is_iso8601_date(_) -> yes. % FIXME is_base64(_) -> yes. % FIXME xmlrpc-1.15/xmlrpc.pub000066400000000000000000000006761247015440600147760ustar00rootroot00000000000000{author,"Joakim Grebenö","jocke@gleipnir.com","030107"}. {name,"xmlrpc"}. {vsn,{1, 15}}. {summary,"An XML-RPC client/server library"}. {keywords,["XML","XML-RPC","RPC"]}. {needs,[{"xmerl",{0,18}}]}. {abstract, "This is an HTTP 1.1 compliant XML-RPC library for Erlang. It is designed to make it easy to write XML-RPC Erlang clients and/or servers. The library is compliant with the XML-RPC specification published by http://www.xmlrpc.org/."}.