From raimo+erlang-questions@REDACTED Mon Aug 3 13:30:22 2015 From: raimo+erlang-questions@REDACTED (Raimo Niskanen) Date: Mon, 3 Aug 2015 13:30:22 +0200 Subject: [erlang-questions] Is this proper way to convert a latin string to utf8 string In-Reply-To: <61ad39.1b5a.14ecbd84a49.Coremail.jusfeel@163.com> References: <254a8012.24490.14eca7d5390.Coremail.jusfeel@163.com> <61ad39.1b5a.14ecbd84a49.Coremail.jusfeel@163.com> Message-ID: <20150803113022.GA6395@erix.ericsson.se> On Mon, Jul 27, 2015 at 03:30:26AM +0800, ?? wrote: > I think my questions is wrong. It is not a latin1 encoded string. It is actually utf8 encoded string but be read by Erlang into [232,191,153] represented by a latin - charlist. > > A simple list_to_binary will give me back the UTF8 already. It's just I need a list to accommodate other part of the program. > > I am using a web framework(Chicagoboss). I posted the data into Erlang in Chinese in utf8 encoded string from a web form. It is read by Erlang as [232,191,153]. This is just one single Chinese character. But erlang read it as [232,191,153]. So I want to consume via ajax later on on the client side. > > But because this piece of information is in a blob of long json data and it is needed to be converted to binary before sending down the wire. So in order to make this piece of information to be correctly converted as one part of the whole assembled json, it needs to turn to a utf8 list first like this: > > asn1rt:utf8_binary_to_list(list_to_binary([232,191,153])), 1> unicode:characters_to_list(list_to_binary([232,191,153])). [36825] / Raimo > > this will give me [36825] which represent the same Chinese character as <<232,191,153>>. You can test this by > io:format("~ts~n",[[36825]]). and io:format("~ts~n",[<<232,191,153>>]). They all output the same character: ? > > then later, asn1rt:utf8_list_to_binary will convert all the json data together to binary. > > > > > -- > Hao > > > > ? 2015-07-27 00:14:16?"Jesper Louis Andersen" ??? > > > > On Sun, Jul 26, 2015 at 3:11 PM, ?? wrote: > > Hi, > Does anyone know if this is a proper way to convert latin string to utf-8 string? > > > {ok, S} = asn1rt:utf8_binary_to_list(list_to_binary([232,191,153])). > io:format("~ts~n",[S]). > > Use the `unicode` module for character conversion: > > > 1> unicode:characters_to_binary([232,191,153], latin1, utf8). > <<195,168,194,191,194,153>> > 2> io:format("~ts~n", [v(1)]). > > > It prints as three characters: > > > LATIN SMALL LETTER E WITH GRAVE > INVERTED QUESTION MARK > (unbound 0x0099 part of the Latin-1 supplement range) > > > I don't know if this is correct for you. > > > What are you trying to do generally? That is, what is the problem you are having. Perhaps we can give better help if we know your situation. > > > -- > > J. > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -- / Raimo Niskanen, Erlang/OTP, Ericsson AB From roger@REDACTED Mon Aug 3 14:58:00 2015 From: roger@REDACTED (Roger Lipscombe) Date: Mon, 3 Aug 2015 13:58:00 +0100 Subject: [erlang-questions] Disabling a parse transform on a per-file basis? Message-ID: It turns out that you can deadlock lager (2.0.3) if you attempt to use lager:log (or lager:debug, etc.) from inside a lager backend. I have the lager parse transform enabled in rebar.config for every module in the application. Is there a way to *remove* it for specific modules? Then, if anyone attempts to use it in one of our lager backends, they'll get a compile error, rather than a deadlock in production. From roger@REDACTED Mon Aug 3 17:12:31 2015 From: roger@REDACTED (Roger Lipscombe) Date: Mon, 3 Aug 2015 16:12:31 +0100 Subject: [erlang-questions] Character encodings and lager Message-ID: I'm tracking down a crash in one of our custom lager backends. The relevant piece of code is, cut down, something like the following: Message = lager_msg:message(Msg), JSON = mochijson2:encode({struct, [{"msg", list_to_binary(Message)}]}). When I call it with the following... lager:log(info, self(), "~p", [<<178, 179>>]). ...it crashes with an exception: {ucs,{bad_utf8_character_code}} Now, I know that's not a valid UTF8 character code: it's superscript-2 and superscript-3, as encoded in Latin1. Cutting this down further, I get: Message = [60,60,178,179,62,62]. mochijson2:encode({struct, [{"msg", list_to_binary(Message)}]}). ** exception exit: {ucs,{bad_utf8_character_code}} So, my question would -- usually -- be: "how do I convert the Latin1 string to UTF8?". However, the binary isn't supposed to contain anything outside the 32-127 ASCII range. In fact, it should be an uppercase hexadecimal string: [A-F0-9] in ASCII. Note: In the original crash, the string was sent from an embedded device, and it appears to have garbage in it because of some kind of corruption in configuration NVRAM. So, I have an actual *binary*, which usually only contains valid hex characters (in ASCII), but occasionally has bytes outside this range. How do I get that into mochijson2, via lager, without anything crashing? I tried the following: mochijson2:encode({struct, [{"msg", unicode:characters_to_binary(Message)}]}). ...which works, but am I going to get burnt if I start using UTF-8 in my logging once we move to Erlang 17 or 18? How do others deal with this kind of thing in Erlang? Regards, Roger. From mononcqc@REDACTED Mon Aug 3 17:52:58 2015 From: mononcqc@REDACTED (Fred Hebert) Date: Mon, 3 Aug 2015 11:52:58 -0400 Subject: [erlang-questions] Character encodings and lager In-Reply-To: References: Message-ID: <20150803155255.GA52021@fhebert-ltm1> On 08/03, Roger Lipscombe wrote: > Message = [60,60,178,179,62,62]. > mochijson2:encode({struct, [{"msg", list_to_binary(Message)}]}). >** exception exit: {ucs,{bad_utf8_character_code}} > >So, my question would -- usually -- be: "how do I convert the Latin1 >string to UTF8?". > unicode:characters_to_binary(List, latin1, utf8) should do it: http://www.erlang.org/doc/man/unicode.html#characters_to_binary-3 >However, the binary isn't supposed to contain anything outside the >32-127 ASCII range. In fact, it should be an uppercase hexadecimal >string: [A-F0-9] in ASCII. > Ah, well those are supposed to be the same in latin1 and utf8. SOmething else is breaking your data. The thing you generated a failure on above in the example is: 2> [60,60,178,179,62,62]. "<>" Which, well, isn't very much hexadecimal as it uses the superscript 2 and 3 (? and ?) instead of anything else, and also includes < and >. >Note: In the original crash, the string was sent from an embedded >device, and it appears to have garbage in it because of some kind of >corruption in configuration NVRAM. > Yeah that's a problem alright. >So, I have an actual *binary*, which usually only contains valid hex >characters (in ASCII), but occasionally has bytes outside this range. >How do I get that into mochijson2, via lager, without anything >crashing? > Avoid putting garbage into the program, and the program will stop choking on the garbage. The conversion of latin1 to unicode will only work as long as the sequence of garbage generated is perceived to be valid latin1. >I tried the following: > > mochijson2:encode({struct, [{"msg", >unicode:characters_to_binary(Message)}]}). > >...which works, but am I going to get burnt if I start using UTF-8 in >my logging once we move to Erlang 17 or 18? > Use the form I put in earlier: characters_to_binary(Data, InEncoding, OutEncoding) -> Result If you specify the InEncoding, you can, along with your upgrade from 17 to 18, change the InEncoding from latin1 to utf8 and possibly remove the text entirely. But the underlying problem is that you will *never* have a happy good time if what you're trying to do is convert unknown encodings into a known one. There is just no good solid way to do it. Text encoding is one place where it pays off to be very strict in what you accept so the rest of your system is much simpler. >How do others deal with this kind of thing in Erlang? > I crash on bad corrupted input because nothing good will come out of trying to make that kind of garbage edible to my programs. Regards, Fred. From luis.rascao@REDACTED Tue Aug 4 00:40:32 2015 From: luis.rascao@REDACTED (=?UTF-8?B?THVpcyBSYXNjw6Nv?=) Date: Mon, 3 Aug 2015 23:40:32 +0100 Subject: [erlang-questions] rebar eunit test pass but fail on cover test In-Reply-To: <3119103.jZzUViM4mz@debian> References: <3119103.jZzUViM4mz@debian> Message-ID: Hi, This appears to be a bug in OTP's cover.erl, i isolated your code to the following simple module: -module(t). -compile([export_all]). pad(A, L) -> P = << <<"#">> || _ <- lists:seq(1, L) >>, <>. test() -> pad(<<"hi">>, 2). i then issue the following commands in an erl shell: 1> c(t, [debug_info]). {ok,t} 2> t:test(). <<"hi##">> %% no problem here 3> cover:start(). {ok,<0.39.0>} 4> cover:compile_beam("t.beam"). {ok,t} 5> t:test(). ** exception error: bad argument in function t:'-pad/2-lbc$^0/2-0-'/2 (t.erl, line 5) in call from t:pad/2 (t.erl, line 5) Cover manipulates the original .beam abstract code, inserts it's hooks for code coverage statistics and then compiles the manipulated abstract code and loads it, rebar then runs the eunit test. A closer look at the abstract code before and after the manipulation shows the following: before: [{match,5, {var,5,'P'}, {bc,5, {bin,5, [{bin_element,5, * {string,5,"#"},* default,default}]} after: {match,5, {var,5,'P'}, {bc,5, {bin,5, [{bin_element,5, *{block,0,[{string,5,"#"}]},* default,default}]}, if i hack cover.erl and remove the *{block* instruction the test succeeds, could this really be a Cover or am i missing something? On Thu, Jul 16, 2015 at 9:49 PM, ruanbeihong wrote: > Hi everyone, > > I'm learning erlang for a while. Currently I'm using rebar > to manage building and test work. I find the cover test > provided in rebar (eunit?) quite convenient. > > But recently I come across a strange situation: when running > test without '{cover_enabled, true}.' in rebar.conf, it > works find and passed my test, but with it will result in a > fail of test. And the crush info is IMO not quite useful. > > So I ask here for someone might come across same problem and > to see if this is a bug. > > My code is at https://github.com/jamesruan/z85 > commit: 6e0fc13667 > simply git clone it and run: > rebar eunit > or > rebar -C rebar.conf eunit > The first will success in my environment ( > Erlang/OTP 18 [erts-7.0] [source] [64-bit] [smp:4:4] [async- > threads:10] [kernel-poll:false]) > But the second will fail. > > Thanks, > > James Ruan > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -- PGP fingerprint: F708 E141 AE8D 2D38 E1BC DF3D 1719 3EA0 647D 7260 -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael.eugene.turner@REDACTED Wed Aug 5 09:27:48 2015 From: michael.eugene.turner@REDACTED (Michael Turner) Date: Wed, 5 Aug 2015 16:27:48 +0900 Subject: [erlang-questions] 16-bit Erlang: crazy? Or just stupid? Message-ID: Comments invited. https://docs.google.com/document/d/10GfPfpqQKzV6Ws7MULPBue6VoAaZF-vGHTQ4UFAXtSw/edit Regards, Michael Turner Executive Director Project Persephone K-1 bldg 3F 7-2-6 Nishishinjuku Shinjuku-ku Tokyo 160-0023 Tel: +81 (3) 6890-1140 Fax: +81 (3) 6890-1158 Mobile: +81 (90) 5203-8682 turner@REDACTED http://www.projectpersephone.org/ "Love does not consist in gazing at each other, but in looking outward together in the same direction." -- Antoine de Saint-Exup?ry -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael.eugene.turner@REDACTED Thu Aug 6 08:40:48 2015 From: michael.eugene.turner@REDACTED (Michael Turner) Date: Thu, 6 Aug 2015 15:40:48 +0900 Subject: [erlang-questions] 16-bit Erlang: crazy? Or just stupid? In-Reply-To: References: Message-ID: I screwed up the access settings in Google Docs. You should all be able to read it now. Sorry for the stupid, crazy service failure. Regards, Michael Turner Executive Director Project Persephone K-1 bldg 3F 7-2-6 Nishishinjuku Shinjuku-ku Tokyo 160-0023 Tel: +81 (3) 6890-1140 Fax: +81 (3) 6890-1158 Mobile: +81 (90) 5203-8682 turner@REDACTED http://www.projectpersephone.org/ "Love does not consist in gazing at each other, but in looking outward together in the same direction." -- Antoine de Saint-Exup?ry On Wed, Aug 5, 2015 at 4:27 PM, Michael Turner < michael.eugene.turner@REDACTED> wrote: > > Comments invited. > > > https://docs.google.com/document/d/10GfPfpqQKzV6Ws7MULPBue6VoAaZF-vGHTQ4UFAXtSw/edit > > Regards, > Michael Turner > Executive Director > Project Persephone > K-1 bldg 3F > 7-2-6 Nishishinjuku > Shinjuku-ku Tokyo 160-0023 > Tel: +81 (3) 6890-1140 > Fax: +81 (3) 6890-1158 > Mobile: +81 (90) 5203-8682 > turner@REDACTED > http://www.projectpersephone.org/ > > "Love does not consist in gazing at each other, but in looking outward > together in the same direction." -- Antoine de Saint-Exup?ry > -------------- next part -------------- An HTML attachment was scrubbed... URL: From dmitrii.bushmelev@REDACTED Thu Aug 6 09:46:44 2015 From: dmitrii.bushmelev@REDACTED (Dmitry Bushmelev) Date: Thu, 6 Aug 2015 09:46:44 +0200 Subject: [erlang-questions] http error on request using httpc:request Message-ID: <03091E52-2C70-4CBC-A4B6-E1C0907F53FE@gmail.com> Hi. If I am making request using curl or browser, response is successful: $ curl -v http://www.fotbolldirekt.se/epfootball/feed/ * Trying 188.95.225.175... * Connected to www.fotbolldirekt.se (188.95.225.175) port 80 (#0) > GET /epfootball/feed/ HTTP/1.1 > User-Agent: curl/7.37.1 > Host: www.fotbolldirekt.se > Accept: */* > < HTTP/1.1 200 OK ? but if I am using httpc I am getting 500: > httpc:request(get, {"http://blogg.vk.se/fotbollsbloggen/feed/", []}, [], []). {ok,{{"HTTP/1.0",500,"Server Error"}, [{"cache-control","no-cache"}, {"connection","close"}, {"content-type","text/html"}], "

500 Server Error

\nAn internal server error occured.\n\n?}} Erlang 17.4, problem reproduces on ubuntu 14.04 and OSX 10.10. Do someone knows how to fix that? Thanks. From aschultz@REDACTED Thu Aug 6 12:41:22 2015 From: aschultz@REDACTED (Andreas Schultz) Date: Thu, 6 Aug 2015 12:41:22 +0200 (CEST) Subject: [erlang-questions] output to standard_error crashes sometimes on R18 Message-ID: <619163438.2710789.1438857682456.JavaMail.zimbra@tpip.net> Hi, Since I upgraded to 18.0.2, my Erlang application Linux sometimes crash with egain in standard error. The crash is triggered by something like this: io:format(standard_error, "started ~s~n", [application]). The actual crash looks like this: ** Generic server standard_error_sup terminating ** Last message in was {'EXIT',<0.28.0>,eagain} ** When Server state == {state,standard_error,undefined,<0.28.0>,{local,standard_error_sup}} ** Reason for termination == ** eagain 2015-08-06 09:14:41 =CRASH REPORT==== crasher: initial call: supervisor_bridge:standard_error/1 pid: <0.27.0> registered_name: standard_error_sup exception exit: {eagain,[{gen_server,terminate,7,[{file,"gen_server.erl"},{line,826}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]} ancestors: [kernel_sup,<0.10.0>] messages: [] links: [<0.11.0>] dictionary: [] trap_exit: true status: running heap_size: 376 stack_size: 27 reductions: 155 neighbours: 2015-08-06 09:14:41 =SUPERVISOR REPORT==== Supervisor: {local,kernel_sup} Context: child_terminated Reason: eagain Offender: [{pid,<0.27.0>},{id,standard_error},{mfargs,{standard_error,start_link,[]}},{restart_type,temporary},{shutdown,2000},{child_type,supervisor}] I have straced erl and it does get an EAGAIN on fd 2: 14209 09:14:41.170429 writev(2, [{"started gen_listener_tcp\n", 25}], 1 14209 09:14:41.170446 <... writev resumed> ) = -1 EAGAIN (Resource temporarily unavailable) So whats going on here??? After some searching I found a nice explanation about duped fd's and file status flags here: http://stackoverflow.com/a/9677130 (a quick test program verifies that this indeed happens on Linux). So according to that, setting any of the stdio file descriptors to non-blocking, would set all of them to non-blocking. And sure enough, strace shows this: 14170 09:14:39.787004 fcntl(1, F_SETFL, O_RDWR|O_NONBLOCK|O_LARGEFILE) = 0 (pid 14170 is the main erl process, pid 14209 one of the threads in erl) I have stopped digging through this at that point. Clearly, the standard_error process or the underlying port driver should handle the EAGAIN gracefully, but fail to do so. Andreas From radek@REDACTED Fri Aug 7 11:17:51 2015 From: radek@REDACTED (Radoslaw Gruchalski) Date: Fri, 7 Aug 2015 09:17:51 +0000 (UTC) Subject: [erlang-questions] http error on request using httpc:request In-Reply-To: <03091E52-2C70-4CBC-A4B6-E1C0907F53FE@gmail.com> References: <03091E52-2C70-4CBC-A4B6-E1C0907F53FE@gmail.com> Message-ID: Any reason why the address is different in those examples? Sent from Outlook On Fri, Aug 7, 2015 at 2:11 AM -0700, "Dmitry Bushmelev" wrote: Hi. If I am making request using curl or browser, response is successful: $ curl -v http://www.fotbolldirekt.se/epfootball/feed/ * Trying 188.95.225.175... * Connected to www.fotbolldirekt.se (188.95.225.175) port 80 (#0) > GET /epfootball/feed/ HTTP/1.1 > User-Agent: curl/7.37.1 > Host: www.fotbolldirekt.se > Accept: */* > < HTTP/1.1 200 OK ? but if I am using httpc I am getting 500: > httpc:request(get, {"http://blogg.vk.se/fotbollsbloggen/feed/", []}, [], []). {ok,{{"HTTP/1.0",500,"Server Error"}, [{"cache-control","no-cache"}, {"connection","close"}, {"content-type","text/html"}], "500 Server Error An internal server error occured. ?}} Erlang 17.4, problem reproduces on ubuntu 14.04 and OSX 10.10. Do someone knows how to fix that? Thanks. _______________________________________________ erlang-questions mailing list erlang-questions@REDACTED http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- An HTML attachment was scrubbed... URL: From jesper.louis.andersen@REDACTED Fri Aug 7 11:35:47 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Fri, 7 Aug 2015 11:35:47 +0200 Subject: [erlang-questions] 16-bit Erlang: crazy? Or just stupid? In-Reply-To: References: Message-ID: In principle, with enough work, this is possible, though in a modern world I think the 16 bit address space ends up being too small. The 32 bit address space is quite viable however, and that experiment has been done, see the halfword-emulator for Erlang. The idea is to run Processes in a 32bit space, but keep ETS tables and other things in a 64 bit space. The end result is less memory pressure for processes, smaller pointers in many cases and so on. I'm somewhat hesitant to say we would win much by having smaller data paths down to 16 bit. It doesn't look like this is the primary limitation of modern CPU architectures: power, memory bandwidth, and a tiny issue width is. On Thu, Aug 6, 2015 at 8:40 AM, Michael Turner < michael.eugene.turner@REDACTED> wrote: > I screwed up the access settings in Google Docs. You should all be able to > read it now. Sorry for the stupid, crazy service failure. > > Regards, > Michael Turner > Executive Director > Project Persephone > K-1 bldg 3F > 7-2-6 Nishishinjuku > Shinjuku-ku Tokyo 160-0023 > Tel: +81 (3) 6890-1140 > Fax: +81 (3) 6890-1158 > Mobile: +81 (90) 5203-8682 > turner@REDACTED > http://www.projectpersephone.org/ > > "Love does not consist in gazing at each other, but in looking outward > together in the same direction." -- Antoine de Saint-Exup?ry > > On Wed, Aug 5, 2015 at 4:27 PM, Michael Turner < > michael.eugene.turner@REDACTED> wrote: > >> >> Comments invited. >> >> >> https://docs.google.com/document/d/10GfPfpqQKzV6Ws7MULPBue6VoAaZF-vGHTQ4UFAXtSw/edit >> >> Regards, >> Michael Turner >> Executive Director >> Project Persephone >> K-1 bldg 3F >> 7-2-6 Nishishinjuku >> Shinjuku-ku Tokyo 160-0023 >> Tel: +81 (3) 6890-1140 >> Fax: +81 (3) 6890-1158 >> Mobile: +81 (90) 5203-8682 >> turner@REDACTED >> http://www.projectpersephone.org/ >> >> "Love does not consist in gazing at each other, but in looking outward >> together in the same direction." -- Antoine de Saint-Exup?ry >> > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From eric.pailleau@REDACTED Fri Aug 7 11:42:06 2015 From: eric.pailleau@REDACTED (=?ISO-8859-1?Q?=C9ric_Pailleau?=) Date: Fri, 07 Aug 2015 11:42:06 +0200 Subject: [erlang-questions] Fwd: Re: http error on request using httpc:request In-Reply-To: <21e56750-cb0a-436e-97d1-2db0f5fdf676@email.android.com> Message-ID: ---------- Message transf?r? ---------- De?: ?ric Pailleau Date?: 7 ao?t 2015 11:32 Objet?: Re: [erlang-questions] http error on request using httpc:request ??: Dmitry Bushmelev Cc?: > Hello, > Use {autoredirect, true}. > Regards > > Le?6 ao?t 2015 09:46, Dmitry Bushmelev a ?crit?: > > > > Hi. > > If I am making request using curl or browser, response is successful: > > > > $ curl -v http://www.fotbolldirekt.se/epfootball/feed/ > > * Trying 188.95.225.175... > > * Connected to www.fotbolldirekt.se (188.95.225.175) port 80 (#0) > > > GET /epfootball/feed/ HTTP/1.1 > > > User-Agent: curl/7.37.1 > > > Host: www.fotbolldirekt.se > > > Accept: */* > > > > > < HTTP/1.1 200 OK > > ? > > > > but if I am using httpc I am getting 500: > > > > > httpc:request(get, {"http://blogg.vk.se/fotbollsbloggen/feed/", []}, [], []). > > {ok,{{"HTTP/1.0",500,"Server Error"}, > > ???? [{"cache-control","no-cache"}, > > ????? {"connection","close"}, > > ????? {"content-type","text/html"}], > > ???? "

500 Server Error

\nAn internal server error occured.\n\n?}} > > > > Erlang 17.4, problem reproduces on ubuntu 14.04 and OSX 10.10. > > > > Do someone knows how to fix that? > > Thanks. > > _______________________________________________ > > erlang-questions mailing list > > erlang-questions@REDACTED > > http://erlang.org/mailman/listinfo/erlang-questions From jj@REDACTED Fri Aug 7 11:46:28 2015 From: jj@REDACTED (Giovanni Giorgi) Date: Fri, 7 Aug 2015 11:46:28 +0200 Subject: [erlang-questions] 16-bit Erlang: crazy? Or just stupid? In-Reply-To: References: Message-ID: <58C6BA8B-8C15-4090-BEF0-5DC85464D622@gioorgi.com> Agree with Jesper. Lowering the data size could bring some benefit if you are able to "pack" data in a 64bit address, but it will bring even worst performance... x86 modern architecture is built with more efficient 64bit-opcode. Simply put the chip are "reversed" to work better with a 32,64bit address opcode and end up eating more cycle if you force them to push 16bit op-code. (they must "shift out", the unwanted bits). Also: + Arduino ATM-Mega chip is a 8bit chip which provide easily 32bit adressing without problem. +I have a RasberryPI ARM 4x-core for 45? with 32bit in it.... ...there are not any more embedded 16bit chip nowedays... Think twice before doing it. On 07/ago/2015, at 11:35, Jesper Louis Andersen wrote: > In principle, with enough work, this is possible, though in a modern world I think the 16 bit address space ends up being too small. The 32 bit address space is quite viable however, and that experiment has been done, see the halfword-emulator for Erlang. > > The idea is to run Processes in a 32bit space, but keep ETS tables and other things in a 64 bit space. The end result is less memory pressure for processes, smaller pointers in many cases and so on. > > I'm somewhat hesitant to say we would win much by having smaller data paths down to 16 bit. It doesn't look like this is the primary limitation of modern CPU architectures: power, memory bandwidth, and a tiny issue width is. > > > On Thu, Aug 6, 2015 at 8:40 AM, Michael Turner wrote: > I screwed up the access settings in Google Docs. You should all be able to read it now. Sorry for the stupid, crazy service failure. > > Regards, > Michael Turner > Executive Director > Project Persephone > K-1 bldg 3F > 7-2-6 Nishishinjuku > Shinjuku-ku Tokyo 160-0023 > Tel: +81 (3) 6890-1140 > Fax: +81 (3) 6890-1158 > Mobile: +81 (90) 5203-8682 > turner@REDACTED > http://www.projectpersephone.org/ > > "Love does not consist in gazing at each other, but in looking outward together in the same direction." -- Antoine de Saint-Exup?ry > > On Wed, Aug 5, 2015 at 4:27 PM, Michael Turner wrote: > > Comments invited. > > https://docs.google.com/document/d/10GfPfpqQKzV6Ws7MULPBue6VoAaZF-vGHTQ4UFAXtSw/edit > > Regards, > Michael Turner > Executive Director > Project Persephone > K-1 bldg 3F > 7-2-6 Nishishinjuku > Shinjuku-ku Tokyo 160-0023 > Tel: +81 (3) 6890-1140 > Fax: +81 (3) 6890-1158 > Mobile: +81 (90) 5203-8682 > turner@REDACTED > http://www.projectpersephone.org/ > > "Love does not consist in gazing at each other, but in looking outward together in the same direction." -- Antoine de Saint-Exup?ry > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > > > > -- > J. > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -- [ [ [ Giovanni ``Daitan`` Giorgi ] ] ] jj@REDACTED -------------- next part -------------- An HTML attachment was scrubbed... URL: From garazdawi@REDACTED Fri Aug 7 18:58:50 2015 From: garazdawi@REDACTED (Lukas Larsson) Date: Fri, 7 Aug 2015 18:58:50 +0200 Subject: [erlang-questions] output to standard_error crashes sometimes on R18 In-Reply-To: <619163438.2710789.1438857682456.JavaMail.zimbra@tpip.net> References: <619163438.2710789.1438857682456.JavaMail.zimbra@tpip.net> Message-ID: <50F2A23D-EB3E-4D09-A50E-01930B61BDE7@gmail.com> Hello, Many thanks for the detailed analysis. I've gotten the similar reports from a couple of places. I'll take a look at it when I get back from summer vacation. Lukas > On 6 aug 2015, at 12:41, Andreas Schultz wrote: > > Hi, > > Since I upgraded to 18.0.2, my Erlang application Linux sometimes crash > with egain in standard error. The crash is triggered by something like this: > > io:format(standard_error, "started ~s~n", [application]). > > The actual crash looks like this: > > ** Generic server standard_error_sup terminating > ** Last message in was {'EXIT',<0.28.0>,eagain} > ** When Server state == {state,standard_error,undefined,<0.28.0>,{local,standard_error_sup}} > ** Reason for termination == > ** eagain > 2015-08-06 09:14:41 =CRASH REPORT==== > crasher: > initial call: supervisor_bridge:standard_error/1 > pid: <0.27.0> > registered_name: standard_error_sup > exception exit: {eagain,[{gen_server,terminate,7,[{file,"gen_server.erl"},{line,826}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]} > ancestors: [kernel_sup,<0.10.0>] > messages: [] > links: [<0.11.0>] > dictionary: [] > trap_exit: true > status: running > heap_size: 376 > stack_size: 27 > reductions: 155 > neighbours: > 2015-08-06 09:14:41 =SUPERVISOR REPORT==== > Supervisor: {local,kernel_sup} > Context: child_terminated > Reason: eagain > Offender: [{pid,<0.27.0>},{id,standard_error},{mfargs,{standard_error,start_link,[]}},{restart_type,temporary},{shutdown,2000},{child_type,supervisor}] > > I have straced erl and it does get an EAGAIN on fd 2: > > 14209 09:14:41.170429 writev(2, [{"started gen_listener_tcp\n", 25}], 1 > 14209 09:14:41.170446 <... writev resumed> ) = -1 EAGAIN (Resource temporarily unavailable) > > So whats going on here??? > > After some searching I found a nice explanation about duped fd's and file status flags > here: http://stackoverflow.com/a/9677130 (a quick test program verifies that this indeed > happens on Linux). > > So according to that, setting any of the stdio file descriptors to non-blocking, would > set all of them to non-blocking. And sure enough, strace shows this: > > 14170 09:14:39.787004 fcntl(1, F_SETFL, O_RDWR|O_NONBLOCK|O_LARGEFILE) = 0 > > (pid 14170 is the main erl process, pid 14209 one of the threads in erl) > > I have stopped digging through this at that point. Clearly, the standard_error > process or the underlying port driver should handle the EAGAIN gracefully, but > fail to do so. > > Andreas > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From charles@REDACTED Fri Aug 7 18:19:35 2015 From: charles@REDACTED (Charles Weitzer) Date: Fri, 7 Aug 2015 16:19:35 +0000 Subject: [erlang-questions] Hiring Senior Software Engineer - Machine Learning Group Message-ID: Voleon Capital Management LP is a startup quantitative hedge fund located in Berkeley, California. We would like to hire a senior software engineer as soon as possible. Voleon's founders previously worked together at one of the most successful quantitative hedge funds in the world. Our CEO has a PhD in Computer Science from Stanford and has been CEO and founder of a successful Internet infrastructure startup. Our Chief Investment Officer has a PhD in Statistics from Berkeley. Voleon's team includes PhD's from leading departments in statistics, computer science, and mathematics. We have made several unpublished advances in the field of machine learning and in other areas as well. Here is our formal job description: ********************************************************** * Senior Software Engineer * Technology-driven investment firm employing cutting-edge statistical machine learning techniques seeks an exceptionally capable software engineer. You will architect and implement new production trading systems, machine learning infrastructure, data integration pipelines, and large-scale storage systems. The firm researches and deploys systematic trading strategies designed to generate attractive returns without being dependent on the performance of the overall market. Join a team of under 30 people that includes a Berkeley statistics professor as well as over ten PhD's from Berkeley, Chicago, CMU, Princeton, Stanford, and UCLA, led by the founder and CEO of a successful Internet infrastructure technology firm. The firm's offices are walking distance from BART and the UC Berkeley campus in downtown Berkeley, California. We have a casual and collegial office environment, catered meals, and competitive benefits packages. We seek candidates with a proven track record of writing correct, well-designed software, solving hard problems, and delivering complex projects on time. You should preferably have experience designing and implementing fault-tolerant distributed systems. Experience with building large-scale data infrastructure, stream processing systems, or latency-sensitive programs is a bonus. We are growing rapidly. Willingness to take initiative and a gritty determination to productize are essential. Required experience: - developing with C/C++/Python/Go in a Linux environment with a focus on performance, concurrency, and correctness. - deep experience with at least one functional programming language (Erlang, Haskell, Scala, etc.) - working in TCP/IP networking, multi-threading, and server development. - working with common Internet protocols (IP, TCP/UDP, SSL/TLS, HTTP, SNMP, etc.). - architecting and designing highly available systems. - architecting and designing large-scale data management infrastructure. - working in large codebases and building modular, manageable code. Preferred experience: - debugging and performance profiling, including the use of tools such as strace, valgrind, gdb, tcpdump, etc. - working with build and test automation tools. - working with well-defined change management processes. - diagnosing RDBMS performance problems, exploiting indexing, using EXPLAIN PLAN, optimizing at the code layer, etc. - working with messaging queues (RabbitMQ, Redis, etc.) as well as distributed caching systems. Interest in financial applications is essential, but experience in finance is not a primary factor in our hiring. Benefits and compensation are highly competitive. ********************************************************** The above job description is just a starting point in terms of possible duties and seniority. We can be very flexible for the right person. Please send your CV/questions to Charles@REDACTED. Please reference "Erlang.org" in the subject line of your email. -------------- next part -------------- An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Sat Aug 8 13:03:05 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Sat, 8 Aug 2015 13:03:05 +0200 Subject: [erlang-questions] syntax errror on : Message-ID: <55C5E1E9.8090804@home.nl> Hello, I try to find a solution for this etude : http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 So far I have this : %% @author Roelof Wobben %% @doc Function to calculate the area of a rectangle %% @reference from
Introducing Erlang, %% O'Reilly Media, Inc., 2012. %% @copyright 2012 by R.WObben %% @version 0.1 -module(geom51). -export([area/0]). %% @doc ask the user for which shape the area %% must be calculated. %% Choices are : %% c or a C for a circle %% e or a E for a ellipse %% t or a T for a triangle -spec(area() -> char() ). area() -> io:format("Which shape must the area be calculated?~n"), io:format(" R. Rectangle ~n"), io:format(" T. Triangle~n"), io:format(" E. Ellipse~n"), Answer = io:get_line("Your choice? "), Value = hd(Answer), char_to_shape(Value). %% @doc convert the choice to a Shape and send the %5 data to the dimension function %% when the choice is a : %% r or a R then the shape will be a rectangle %% t or a T then the shape will be a triangle %% e or a E then the shape will be a ellipse -spec(char_to_shape(char() ) -> atom() ). char_to_shape(Char) -> case Char of $R -> get_dimension(rectangle); $T -> triangle; $E -> ellipse; $r -> rectangle; $t -> triangle; $e -> ellipse; _Else -> "Wrong Shape" end. -spec(get_dimension( atom() ) -> number() ) . %% @doc Calculates the area of a shape, given the %% shape and two of the dimensions. Returns the product %% of its arguments for a rectangle, one half the %% product of the arguments for a triangle, and %% math:pi times the product of the arguments for %% an ellipse. get_dimension(Shape)-> case Shape of rectangle -> Answer1 = io:get_line("What is the length of the rectangle? "), {Test, _} = string:to_float(Answer1), case Test of error -> Test2 = string:to_integer(Answer1), case Test2 of error -> io:write("the input schould be a number"); _Else -> Test2 = Test end end end but now I see these error message : geom51.erl:72: syntax error before: geom51.erl:42: function get_dimension/1 undefined geom51.erl:51: spec for undefined function geom51:get_dimension/1 geom51.erl:72: syntax error before: geom51.erl:42: function get_dimension/1 undefined geom51.erl:51: spec for undefined function geom51:get_dimension/1 anyone who knows how to solve this one ? Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From essen@REDACTED Sat Aug 8 13:07:08 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Sat, 08 Aug 2015 13:07:08 +0200 Subject: [erlang-questions] syntax errror on : In-Reply-To: <55C5E1E9.8090804@home.nl> References: <55C5E1E9.8090804@home.nl> Message-ID: <55C5E2DC.80605@ninenines.eu> You forgot the dot at the end of the very last function. On 08/08/2015 01:03 PM, Roelof Wobben wrote: > Hello, > > I try to find a solution for this etude : > http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 > > So far I have this : > > %% @author Roelof Wobben > %% @doc Function to calculate the area of a rectangle > %% @reference from "http://shop.oreilly.com/product/0636920025818.do" >Introducing Erlang, > %% O'Reilly Media, Inc., 2012. > %% @copyright 2012 by R.WObben > %% @version 0.1 > > -module(geom51). > > -export([area/0]). > > %% @doc ask the user for which shape the area > %% must be calculated. > %% Choices are : > %% c or a C for a circle > %% e or a E for a ellipse > %% t or a T for a triangle > > -spec(area() -> char() ). > > area() -> > io:format("Which shape must the area be calculated?~n"), > io:format(" R. Rectangle ~n"), > io:format(" T. Triangle~n"), > io:format(" E. Ellipse~n"), > Answer = io:get_line("Your choice? "), > > Value = hd(Answer), > char_to_shape(Value). > > %% @doc convert the choice to a Shape and send the > %5 data to the dimension function > %% when the choice is a : > %% r or a R then the shape will be a rectangle > %% t or a T then the shape will be a triangle > %% e or a E then the shape will be a ellipse > > -spec(char_to_shape(char() ) -> atom() ). > > char_to_shape(Char) -> > case Char of > $R -> get_dimension(rectangle); > $T -> triangle; > $E -> ellipse; > $r -> rectangle; > $t -> triangle; > $e -> ellipse; > _Else -> "Wrong Shape" > end. > > -spec(get_dimension( atom() ) -> number() ) . > > %% @doc Calculates the area of a shape, given the > %% shape and two of the dimensions. Returns the product > %% of its arguments for a rectangle, one half the > %% product of the arguments for a triangle, and > %% math:pi times the product of the arguments for > %% an ellipse. > > get_dimension(Shape)-> > case Shape of > rectangle -> > Answer1 = io:get_line("What is the length of the > rectangle? "), > {Test, _} = string:to_float(Answer1), > case Test of > error -> Test2 = string:to_integer(Answer1), > case Test2 of > error -> io:write("the input schould be a > number"); > _Else -> Test2 = Test > end > end > end > > > but now I see these error message : > > geom51.erl:72: syntax error before: > geom51.erl:42: function get_dimension/1 undefined > geom51.erl:51: spec for undefined function geom51:get_dimension/1 > > geom51.erl:72: syntax error before: > geom51.erl:42: function get_dimension/1 undefined > geom51.erl:51: spec for undefined function geom51:get_dimension/1 > > anyone who knows how to solve this one ? > > Roelof > > > > > > > > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From erlang@REDACTED Sat Aug 8 17:39:39 2015 From: erlang@REDACTED (Joe Armstrong) Date: Sat, 8 Aug 2015 17:39:39 +0200 Subject: [erlang-questions] syntax errror on : In-Reply-To: <55C5E1E9.8090804@home.nl> References: <55C5E1E9.8090804@home.nl> Message-ID: On Sat, Aug 8, 2015 at 1:03 PM, Roelof Wobben wrote: > Hello, > > I try to find a solution for this etude : > http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 > > So far I have this : > > %% @author Roelof Wobben > %% @doc Function to calculate the area of a rectangle > %% @reference from "http://shop.oreilly.com/product/0636920025818.do" >Introducing Erlang, > %% O'Reilly Media, Inc., 2012. > %% @copyright 2012 by R.WObben > %% @version 0.1 > > -module(geom51). > > -export([area/0]). > > %% @doc ask the user for which shape the area > %% must be calculated. > %% Choices are : > %% c or a C for a circle > %% e or a E for a ellipse > %% t or a T for a triangle > > -spec(area() -> char() ). > > area() -> > io:format("Which shape must the area be calculated?~n"), > io:format(" R. Rectangle ~n"), > io:format(" T. Triangle~n"), > io:format(" E. Ellipse~n"), > Answer = io:get_line("Your choice? "), > > Value = hd(Answer), > char_to_shape(Value). > > %% @doc convert the choice to a Shape and send the > %5 data to the dimension function > %% when the choice is a : > %% r or a R then the shape will be a rectangle > %% t or a T then the shape will be a triangle > %% e or a E then the shape will be a ellipse > > -spec(char_to_shape(char() ) -> atom() ). > > char_to_shape(Char) -> > case Char of > $R -> get_dimension(rectangle); > $T -> triangle; > $E -> ellipse; > $r -> rectangle; > $t -> triangle; > $e -> ellipse; > _Else -> "Wrong Shape" > end. Just a quick comment on this function: char_to_shape can return a string (ie "Wrong Shape") and NOT a shape (atom) so you violate your own spec. A better solution is to omit the final clause and write char_to_shape(Char) -> case Char of $R -> get_dimension(rectangle); $T -> triangle; $E -> ellipse; $r -> rectangle; $t -> triangle; $e -> ellipse end. Now the function will generate an exception if called with an incorrect argument. Returning a string is just about the worse thing you could do since some other function somewhere else will have to deal with this. This is an example of the "let it crash" philosophy. Crashing is no big deal in Erlang - in single threaded languages crashing is a big deal - if you crash you lose *everything*. In Erlang you can have millions of processes, if a few crash who cares? In Erlang we let processes watch each other, if one process crashes some other process is supposed to observe this and try to fix the error. In Erlang we assume we'll never get things right and that programs will crash so we don't really bother to program defensively - but we do make sure errors are detected and logged and faulty computations restarted. This leads to a very clean and simple programming style since you don't have to add the additional clauses to catch errors - just leave them out. This make life easy for the programmer since it's in writing these extra clause the programmer is "out of spec" ie what should I do in the error case. Return a string? (as you did) print a message - but who will deal with the string, who will read the message? The refactored code is actually easier to read and write since there is no nasty edge case. So there you are - two new principles: "Let it crash" "Let some other process fix the error" Cheers /Joe > > -spec(get_dimension( atom() ) -> number() ) . > > %% @doc Calculates the area of a shape, given the > %% shape and two of the dimensions. Returns the product > %% of its arguments for a rectangle, one half the > %% product of the arguments for a triangle, and > %% math:pi times the product of the arguments for > %% an ellipse. > > get_dimension(Shape)-> > case Shape of > rectangle -> > Answer1 = io:get_line("What is the length of the rectangle? "), > {Test, _} = string:to_float(Answer1), > case Test of > error -> Test2 = string:to_integer(Answer1), > case Test2 of > error -> io:write("the input schould be a > number"); > _Else -> Test2 = Test > end > end > end > > > but now I see these error message : > > geom51.erl:72: syntax error before: > geom51.erl:42: function get_dimension/1 undefined > geom51.erl:51: spec for undefined function geom51:get_dimension/1 > > geom51.erl:72: syntax error before: > geom51.erl:42: function get_dimension/1 undefined > geom51.erl:51: spec for undefined function geom51:get_dimension/1 > > anyone who knows how to solve this one ? > > Roelof > > > > > > > > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From r.wobben@REDACTED Sat Aug 8 17:22:45 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Sat, 8 Aug 2015 17:22:45 +0200 Subject: [erlang-questions] syntax errror on : In-Reply-To: <55C5E2DC.80605@ninenines.eu> References: <55C5E1E9.8090804@home.nl> <55C5E2DC.80605@ninenines.eu> Message-ID: <55C61EC5.5050509@home.nl> Hmm, still some stupid faults, When I do R and then 2 I see this output: What is the length of the rectangle? 2 ** exception error: no match of right hand side value "2\n" in function geom51:get_dimension/1 (geom51.erl, line 69) When I do R and then 2.0 I see this : What is the length of the rectangle? 2.0 ** exception error: no case clause matching 2.0 in function geom51:get_dimension/1 (geom51.erl, line 65) What is the length of the rectangle? 2.0 ** exception error: no case clause matching 2.0 in function geom51:get_dimension/1 (geom51.erl, line 65) Which is wierd the string:to_integer schould do the trick. Roelof Op 8-8-2015 om 13:07 schreef Lo?c Hoguin: > You forgot the dot at the end of the very last function. > > On 08/08/2015 01:03 PM, Roelof Wobben wrote: >> Hello, >> >> I try to find a solution for this etude : >> http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 >> >> So far I have this : >> >> %% @author Roelof Wobben >> %% @doc Function to calculate the area of a rectangle >> %% @reference from > "http://shop.oreilly.com/product/0636920025818.do" >Introducing >> Erlang, >> %% O'Reilly Media, Inc., 2012. >> %% @copyright 2012 by R.WObben >> %% @version 0.1 >> >> -module(geom51). >> >> -export([area/0]). >> >> %% @doc ask the user for which shape the area >> %% must be calculated. >> %% Choices are : >> %% c or a C for a circle >> %% e or a E for a ellipse >> %% t or a T for a triangle >> >> -spec(area() -> char() ). >> >> area() -> >> io:format("Which shape must the area be calculated?~n"), >> io:format(" R. Rectangle ~n"), >> io:format(" T. Triangle~n"), >> io:format(" E. Ellipse~n"), >> Answer = io:get_line("Your choice? "), >> >> Value = hd(Answer), >> char_to_shape(Value). >> >> %% @doc convert the choice to a Shape and send the >> %5 data to the dimension function >> %% when the choice is a : >> %% r or a R then the shape will be a rectangle >> %% t or a T then the shape will be a triangle >> %% e or a E then the shape will be a ellipse >> >> -spec(char_to_shape(char() ) -> atom() ). >> >> char_to_shape(Char) -> >> case Char of >> $R -> get_dimension(rectangle); >> $T -> triangle; >> $E -> ellipse; >> $r -> rectangle; >> $t -> triangle; >> $e -> ellipse; >> _Else -> "Wrong Shape" >> end. >> >> -spec(get_dimension( atom() ) -> number() ) . >> >> %% @doc Calculates the area of a shape, given the >> %% shape and two of the dimensions. Returns the product >> %% of its arguments for a rectangle, one half the >> %% product of the arguments for a triangle, and >> %% math:pi times the product of the arguments for >> %% an ellipse. >> >> get_dimension(Shape)-> >> case Shape of >> rectangle -> >> Answer1 = io:get_line("What is the length of the >> rectangle? "), >> {Test, _} = string:to_float(Answer1), >> case Test of >> error -> Test2 = string:to_integer(Answer1), >> case Test2 of >> error -> io:write("the input schould be a >> number"); >> _Else -> Test2 = Test >> end >> end >> end >> >> >> but now I see these error message : >> >> geom51.erl:72: syntax error before: >> geom51.erl:42: function get_dimension/1 undefined >> geom51.erl:51: spec for undefined function geom51:get_dimension/1 >> >> geom51.erl:72: syntax error before: >> geom51.erl:42: function get_dimension/1 undefined >> geom51.erl:51: spec for undefined function geom51:get_dimension/1 >> >> anyone who knows how to solve this one ? >> >> Roelof >> >> >> >> >> >> >> >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast >> antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From r.wobben@REDACTED Sat Aug 8 18:59:27 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Sat, 8 Aug 2015 18:59:27 +0200 Subject: [erlang-questions] syntax errror on : In-Reply-To: References: <55C5E1E9.8090804@home.nl> <55C623DD.9070101@home.nl> Message-ID: <55C6356F.2050704@home.nl> Op 8-8-2015 om 18:24 schreef Joe Armstrong: > On Sat, Aug 8, 2015 at 5:44 PM, Roelof Wobben wrote: >> Op 8-8-2015 om 17:39 schreef Joe Armstrong: >> >>> On Sat, Aug 8, 2015 at 1:03 PM, Roelof Wobben wrote: >>>> Hello, >>>> >>>> I try to find a solution for this etude : >>>> http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 >>>> >>>> So far I have this : >>>> >>>> %% @author Roelof Wobben >>>> %% @doc Function to calculate the area of a rectangle >>>> %% @reference from >>> "http://shop.oreilly.com/product/0636920025818.do" >Introducing >>>> Erlang, >>>> %% O'Reilly Media, Inc., 2012. >>>> %% @copyright 2012 by R.WObben >>>> %% @version 0.1 >>>> >>>> -module(geom51). >>>> >>>> -export([area/0]). >>>> >>>> %% @doc ask the user for which shape the area >>>> %% must be calculated. >>>> %% Choices are : >>>> %% c or a C for a circle >>>> %% e or a E for a ellipse >>>> %% t or a T for a triangle >>>> >>>> -spec(area() -> char() ). >>>> >>>> area() -> >>>> io:format("Which shape must the area be calculated?~n"), >>>> io:format(" R. Rectangle ~n"), >>>> io:format(" T. Triangle~n"), >>>> io:format(" E. Ellipse~n"), >>>> Answer = io:get_line("Your choice? "), >>>> >>>> Value = hd(Answer), >>>> char_to_shape(Value). >>>> >>>> %% @doc convert the choice to a Shape and send the >>>> %5 data to the dimension function >>>> %% when the choice is a : >>>> %% r or a R then the shape will be a rectangle >>>> %% t or a T then the shape will be a triangle >>>> %% e or a E then the shape will be a ellipse >>>> >>>> -spec(char_to_shape(char() ) -> atom() ). >>>> >>>> char_to_shape(Char) -> >>>> case Char of >>>> $R -> get_dimension(rectangle); >>>> $T -> triangle; >>>> $E -> ellipse; >>>> $r -> rectangle; >>>> $t -> triangle; >>>> $e -> ellipse; >>>> _Else -> "Wrong Shape" >>>> end. >>> Just a quick comment on this function: >>> >>> char_to_shape can return a string (ie "Wrong Shape") and NOT a shape >>> (atom) >>> so you violate your own spec. >>> >>> A better solution is to omit the final clause and write >>> >>> char_to_shape(Char) -> >>> case Char of >>> $R -> get_dimension(rectangle); >>> $T -> triangle; >>> $E -> ellipse; >>> $r -> rectangle; >>> $t -> triangle; >>> $e -> ellipse >>> end. >>> >>> Now the function will generate an exception if called with an incorrect >>> argument. Returning a string is just about the worse thing you could do >>> since some other function somewhere else will have to deal with this. >>> >>> This is an example of the "let it crash" philosophy. Crashing is no big >>> deal in >>> Erlang - in single threaded languages crashing is a big deal - if you >>> crash >>> you lose *everything*. In Erlang you can have millions of processes, >>> if a few crash who cares? In Erlang we let processes watch each other, >>> if one process >>> crashes some other process is supposed to observe this and try to fix the >>> error. >>> >>> In Erlang we assume we'll never get things right and that programs will >>> crash >>> so we don't really bother to program defensively - but we do make sure >>> errors are detected and logged and faulty computations restarted. >>> >>> This leads to a very clean and simple programming style since you don't >>> have to add the additional clauses to catch errors - just leave them out. >>> This make life easy for the programmer since it's in writing these extra >>> clause the programmer is "out of spec" ie what should I do in the error >>> case. >>> Return a string? (as you did) print a message - but who will deal with the >>> string, who will read the message? >>> >>> The refactored code is actually easier to read and write since there is no >>> nasty edge case. >>> >>> So there you are - two new principles: >>> >>> "Let it crash" >>> "Let some other process fix the error" >>> >>> Cheers >>> >>> /Joe >>> >>> >>>> -spec(get_dimension( atom() ) -> number() ) . >>>> >>>> %% @doc Calculates the area of a shape, given the >>>> %% shape and two of the dimensions. Returns the product >>>> %% of its arguments for a rectangle, one half the >>>> %% product of the arguments for a triangle, and >>>> %% math:pi times the product of the arguments for >>>> %% an ellipse. >>>> >>>> get_dimension(Shape)-> >>>> case Shape of >>>> rectangle -> >>>> Answer1 = io:get_line("What is the length of the rectangle? >>>> "), >>>> {Test, _} = string:to_float(Answer1), >>>> case Test of >>>> error -> Test2 = string:to_integer(Answer1), >>>> case Test2 of >>>> error -> io:write("the input schould be a >>>> number"); >>>> _Else -> Test2 = Test >>>> end >>>> end >>>> end >>>> >>>> >>>> but now I see these error message : >>>> >>>> geom51.erl:72: syntax error before: >>>> geom51.erl:42: function get_dimension/1 undefined >>>> geom51.erl:51: spec for undefined function geom51:get_dimension/1 >>>> >>>> geom51.erl:72: syntax error before: >>>> geom51.erl:42: function get_dimension/1 undefined >>>> geom51.erl:51: spec for undefined function geom51:get_dimension/1 >>>> >>>> anyone who knows how to solve this one ? >>>> >>>> Roelof >>>> >>>> >>>> >>>> >>>> >>>> >>>> >>>> >>>> >>>> --- >>>> Dit e-mailbericht is gecontroleerd op virussen met Avast >>>> antivirussoftware. >>>> https://www.avast.com/antivirus >>>> >>>> _______________________________________________ >>>> erlang-questions mailing list >>>> erlang-questions@REDACTED >>>> http://erlang.org/mailman/listinfo/erlang-questions >> >> Correct but the exercise I stated that let it chrash is not handy when >> dealing with user input. >> As I understand the exercise well I have to write error messages on wrong >> input even as it against the erlang principle let it crash > You can do both. You could write shape_to_char as I suggested and > enclose the call > in a catch or try statement > > case (catch shape_to_char(X)) of > {'EXIT', _} -> > io:format("invalid input"); > Shape -> > ... > end > > or > > try shape_to_char(X) of > Shape -> > ... > catch > exit:Why -> > ... > end. > > The problem with your code is the name of the function and its type signature. > > What you wrote should have been called: > > shape_to_char_or_error(X) -> > <> ... > > with type: > > -spec (shape_to_char_or_error(char()) -> atom() | string() > > which mixes error handling with normal behaviour. I think it's better > to write it with the simpler type signature and then enclose the code in > a try-catch or catch construct - it's just prettier that way. > > Have fun > > /Joe > > > > > >> >> Roelof >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >> https://www.avast.com/antivirus >> Thanks, Im at chapter 5 of introducing erlang and the try catch was not mentioned/explained. For testing if the input of the dimensions is a integer or a float can that be in one clause or schould I write two. The input is a string and I need the integer / float to calculate the area later. That function I already wrote in a earlier exercise. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From r.wobben@REDACTED Sat Aug 8 20:19:11 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Sat, 8 Aug 2015 20:19:11 +0200 Subject: [erlang-questions] syntax errror on : In-Reply-To: <55C6356F.2050704@home.nl> References: <55C5E1E9.8090804@home.nl> <55C623DD.9070101@home.nl> <55C6356F.2050704@home.nl> Message-ID: <55C6481F.7070407@home.nl> Op 8-8-2015 om 18:59 schreef Roelof Wobben: > Op 8-8-2015 om 18:24 schreef Joe Armstrong: >> On Sat, Aug 8, 2015 at 5:44 PM, Roelof Wobben wrote: >>> Op 8-8-2015 om 17:39 schreef Joe Armstrong: >>> >>>> On Sat, Aug 8, 2015 at 1:03 PM, Roelof Wobben >>>> wrote: >>>>> Hello, >>>>> >>>>> I try to find a solution for this etude : >>>>> http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 >>>>> >>>>> >>>>> So far I have this : >>>>> >>>>> %% @author Roelof Wobben >>>>> %% @doc Function to calculate the area of a rectangle >>>>> %% @reference from >>>> "http://shop.oreilly.com/product/0636920025818.do" >Introducing >>>>> Erlang, >>>>> %% O'Reilly Media, Inc., 2012. >>>>> %% @copyright 2012 by R.WObben >>>>> %% @version 0.1 >>>>> >>>>> -module(geom51). >>>>> >>>>> -export([area/0]). >>>>> >>>>> %% @doc ask the user for which shape the area >>>>> %% must be calculated. >>>>> %% Choices are : >>>>> %% c or a C for a circle >>>>> %% e or a E for a ellipse >>>>> %% t or a T for a triangle >>>>> >>>>> -spec(area() -> char() ). >>>>> >>>>> area() -> >>>>> io:format("Which shape must the area be calculated?~n"), >>>>> io:format(" R. Rectangle ~n"), >>>>> io:format(" T. Triangle~n"), >>>>> io:format(" E. Ellipse~n"), >>>>> Answer = io:get_line("Your choice? "), >>>>> >>>>> Value = hd(Answer), >>>>> char_to_shape(Value). >>>>> >>>>> %% @doc convert the choice to a Shape and send the >>>>> %5 data to the dimension function >>>>> %% when the choice is a : >>>>> %% r or a R then the shape will be a rectangle >>>>> %% t or a T then the shape will be a triangle >>>>> %% e or a E then the shape will be a ellipse >>>>> >>>>> -spec(char_to_shape(char() ) -> atom() ). >>>>> >>>>> char_to_shape(Char) -> >>>>> case Char of >>>>> $R -> get_dimension(rectangle); >>>>> $T -> triangle; >>>>> $E -> ellipse; >>>>> $r -> rectangle; >>>>> $t -> triangle; >>>>> $e -> ellipse; >>>>> _Else -> "Wrong Shape" >>>>> end. >>>> Just a quick comment on this function: >>>> >>>> char_to_shape can return a string (ie "Wrong Shape") and NOT a shape >>>> (atom) >>>> so you violate your own spec. >>>> >>>> A better solution is to omit the final clause and write >>>> >>>> char_to_shape(Char) -> >>>> case Char of >>>> $R -> get_dimension(rectangle); >>>> $T -> triangle; >>>> $E -> ellipse; >>>> $r -> rectangle; >>>> $t -> triangle; >>>> $e -> ellipse >>>> end. >>>> >>>> Now the function will generate an exception if called with an >>>> incorrect >>>> argument. Returning a string is just about the worse thing you >>>> could do >>>> since some other function somewhere else will have to deal with this. >>>> >>>> This is an example of the "let it crash" philosophy. Crashing is no >>>> big >>>> deal in >>>> Erlang - in single threaded languages crashing is a big deal - if you >>>> crash >>>> you lose *everything*. In Erlang you can have millions of processes, >>>> if a few crash who cares? In Erlang we let processes watch each other, >>>> if one process >>>> crashes some other process is supposed to observe this and try to >>>> fix the >>>> error. >>>> >>>> In Erlang we assume we'll never get things right and that programs >>>> will >>>> crash >>>> so we don't really bother to program defensively - but we do make sure >>>> errors are detected and logged and faulty computations restarted. >>>> >>>> This leads to a very clean and simple programming style since you >>>> don't >>>> have to add the additional clauses to catch errors - just leave >>>> them out. >>>> This make life easy for the programmer since it's in writing these >>>> extra >>>> clause the programmer is "out of spec" ie what should I do in the >>>> error >>>> case. >>>> Return a string? (as you did) print a message - but who will deal >>>> with the >>>> string, who will read the message? >>>> >>>> The refactored code is actually easier to read and write since >>>> there is no >>>> nasty edge case. >>>> >>>> So there you are - two new principles: >>>> >>>> "Let it crash" >>>> "Let some other process fix the error" >>>> >>>> Cheers >>>> >>>> /Joe >>>> >>>> >>>>> -spec(get_dimension( atom() ) -> number() ) . >>>>> >>>>> %% @doc Calculates the area of a shape, given the >>>>> %% shape and two of the dimensions. Returns the product >>>>> %% of its arguments for a rectangle, one half the >>>>> %% product of the arguments for a triangle, and >>>>> %% math:pi times the product of the arguments for >>>>> %% an ellipse. >>>>> >>>>> get_dimension(Shape)-> >>>>> case Shape of >>>>> rectangle -> >>>>> Answer1 = io:get_line("What is the length of the >>>>> rectangle? >>>>> "), >>>>> {Test, _} = string:to_float(Answer1), >>>>> case Test of >>>>> error -> Test2 = >>>>> string:to_integer(Answer1), >>>>> case Test2 of >>>>> error -> io:write("the input >>>>> schould be a >>>>> number"); >>>>> _Else -> Test2 = Test >>>>> end >>>>> end >>>>> end >>>>> >>>>> >>>>> but now I see these error message : >>>>> >>>>> geom51.erl:72: syntax error before: >>>>> geom51.erl:42: function get_dimension/1 undefined >>>>> geom51.erl:51: spec for undefined function geom51:get_dimension/1 >>>>> >>>>> geom51.erl:72: syntax error before: >>>>> geom51.erl:42: function get_dimension/1 undefined >>>>> geom51.erl:51: spec for undefined function geom51:get_dimension/1 >>>>> >>>>> anyone who knows how to solve this one ? >>>>> >>>>> Roelof >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> --- >>>>> Dit e-mailbericht is gecontroleerd op virussen met Avast >>>>> antivirussoftware. >>>>> https://www.avast.com/antivirus >>>>> >>>>> _______________________________________________ >>>>> erlang-questions mailing list >>>>> erlang-questions@REDACTED >>>>> http://erlang.org/mailman/listinfo/erlang-questions >>> >>> Correct but the exercise I stated that let it chrash is not handy when >>> dealing with user input. >>> As I understand the exercise well I have to write error messages on >>> wrong >>> input even as it against the erlang principle let it crash >> You can do both. You could write shape_to_char as I suggested and >> enclose the call >> in a catch or try statement >> >> case (catch shape_to_char(X)) of >> {'EXIT', _} -> >> io:format("invalid input"); >> Shape -> >> ... >> end >> >> or >> >> try shape_to_char(X) of >> Shape -> >> ... >> catch >> exit:Why -> >> ... >> end. >> >> The problem with your code is the name of the function and its type >> signature. >> >> What you wrote should have been called: >> >> shape_to_char_or_error(X) -> >> <> ... >> >> with type: >> >> -spec (shape_to_char_or_error(char()) -> atom() | string() >> >> which mixes error handling with normal behaviour. I think it's better >> to write it with the simpler type signature and then enclose the code in >> a try-catch or catch construct - it's just prettier that way. >> >> Have fun >> >> /Joe >> >> >> >> >> >>> >>> Roelof >>> >>> >>> --- >>> Dit e-mailbericht is gecontroleerd op virussen met Avast >>> antivirussoftware. >>> https://www.avast.com/antivirus >>> > > Thanks, > > Im at chapter 5 of introducing erlang and the try catch was not > mentioned/explained. > For testing if the input of the dimensions is a integer or a float can > that be in one clause or schould I write two. > The input is a string and I need the integer / float to calculate the > area later. That function I already wrote in a earlier exercise. > > Roelof > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast > antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > I tried it yoiur way like this : char_to_shape(Char) -> try shape_to_char(X) of Shape -> case Shape of $R -> rectangle; $T -> triangle; $E -> ellipse; $r -> rectangle; $t -> triangle; $e -> ellipse end, catch exit:"Wrong Shape", end. but now I see this error message : c(geom51). geom51.erl:52: syntax error before: 'end' geom51.erl:29: function char_to_shape/1 undefined geom51.erl:38: spec for undefined function geom51:char_to_shape/1 --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From g@REDACTED Sat Aug 8 20:24:42 2015 From: g@REDACTED (Garrett Smith) Date: Sat, 8 Aug 2015 13:24:42 -0500 Subject: [erlang-questions] syntax errror on : In-Reply-To: <55C6481F.7070407@home.nl> References: <55C5E1E9.8090804@home.nl> <55C623DD.9070101@home.nl> <55C6356F.2050704@home.nl> <55C6481F.7070407@home.nl> Message-ID: This is actually Joe's way: On Sat, Aug 8, 2015 at 1:19 PM, Roelof Wobben wrote: > char_to_shape(Char) -> >> case Char of >> $R -> get_dimension(rectangle); >> $T -> triangle; >> $E -> ellipse; >> $r -> rectangle; >> $t -> triangle; >> $e -> ellipse >> end. > > I think your immediate problem is just reading a bit more carefully. Oh, and try not to use the list as a compiler :) -------------- next part -------------- An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Sat Aug 8 20:27:03 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Sat, 8 Aug 2015 20:27:03 +0200 Subject: [erlang-questions] syntax errror on : In-Reply-To: References: <55C5E1E9.8090804@home.nl> <55C623DD.9070101@home.nl> <55C6356F.2050704@home.nl> <55C6481F.7070407@home.nl> Message-ID: <55C649F7.5000101@home.nl> An HTML attachment was scrubbed... URL: From g@REDACTED Sat Aug 8 20:30:41 2015 From: g@REDACTED (Garrett Smith) Date: Sat, 8 Aug 2015 13:30:41 -0500 Subject: [erlang-questions] syntax errror on : In-Reply-To: <55C649F7.5000101@home.nl> References: <55C5E1E9.8090804@home.nl> <55C623DD.9070101@home.nl> <55C6356F.2050704@home.nl> <55C6481F.7070407@home.nl> <55C649F7.5000101@home.nl> Message-ID: So it's me who needs to read more carefully - touche! Your syntax error is in terminating two clauses with commas - commas separate expressions. Delete them. Out of curiosity, what's wrong with the bad match error? Who's saying you need to map that to some string? On Sat, Aug 8, 2015 at 1:27 PM, Roelof Wobben wrote: > Op 8-8-2015 om 20:24 schreef Garrett Smith: > > This is actually Joe's way: > > On Sat, Aug 8, 2015 at 1:19 PM, Roelof Wobben wrote: > >> char_to_shape(Char) -> >>> case Char of >>> $R -> get_dimension(rectangle); >>> $T -> triangle; >>> $E -> ellipse; >>> $r -> rectangle; >>> $t -> triangle; >>> $e -> ellipse >>> end. >> >> > I think your immediate problem is just reading a bit more carefully. Oh, > and try not to use the list as a compiler :) > > > That was Joe first way. > > Later he explained thet try catch because the exercise needs to give error > messages. > > Roelof > > > > ------------------------------ > [image: Avast logo] > > Dit e-mailbericht is gecontroleerd op virussen met Avast > antivirussoftware. > www.avast.com > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From g@REDACTED Sun Aug 9 00:07:51 2015 From: g@REDACTED (Garrett Smith) Date: Sat, 8 Aug 2015 17:07:51 -0500 Subject: [erlang-questions] Refactoring in anger Message-ID: We've had an ongoing thread on how to handle some problems idiomatically in Erlang: http://erlang.org/pipermail/erlang-questions/2015-August/085382.html The OP's questions are coming out of an exercise here: http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 This in turn points to a proposed solution here: http://chimera.labs.oreilly.com/books/1234000000726/apa.html#_literal_geom_erl_literal_9 Upon reading this solution, I became so enraged [1] that I rewrote the module and want to make a number of points. Here's my rewrite: https://gist.github.com/gar1t/7bb80d728f804554ac32 The tone of my points below is *very preachy* which is going to annoy some people here. I apologize in advance - but hey, ranters gotta rant. # Clarity of "what's going on" Compare my area/0 to the original area/0. Which is easier to see "what's going on"? I'm not boasting here but rather making the most important point I can about programming: take the time to be clear in your intent! If you're actually clear - in your brain - making the code reflect your understanding *is not that hard*. If your code is not clear, chances are your brain is not clear. Maybe the original code works, maybe it doesn't. I can't tell from looking at that function, at all. I have to dig around various implementation details and hold a bunch of information in my brain to understand what the author is maybe trying to do. At some point I can't keep it all straight and have to run the thing and observe its behavior. *Now* I'm thinking, what happens to the pour schlep who has to modify this code. In the real world, this causes fear, and loathing, and tests - lots and lots of tests! We don't have to live this way. # Separation of concerns (in this case IO vs calculations) The original calculate/3 mixes user facing behavior (print error messages) with a calculation. If your function returns a mishmash of completely unrelated values (e.g. the result of io:format and also the result of an area calculation) *it's a mess*. In the rewrite I've added print_area/0, which is responsible for displaying results to the user. area/0 returns an area or raises an exception. print_area/0 handles both the result and any error. # Handling invalid input The original thread here involves a discussion on how to handle bad input to a function. My rewrite does one of two things on this front: - If input is from a user, there's an explicit exception raised on bad input that can be used by an error handler to inform the user - If input is not from a user but rather internal, I don't handle bad input at all, but let Erlang crash with a function or case clause error The first case address the user experience. We could let exceptions just propagate and upset users with arcane Erlang messages. Or we can handle errors politely with intelligible messages. The original ask_erl.erl handles invalid input by passing atoms like 'error' and 'unknown' along a call chain. This is tedious and finally culminates in the original calculate/3 - a monster mishmash function of error handling, IO, and calculation. My rewrite raises an exception for those functions that take user provided input. I prefer exceptions in this case as they keep return values on the happy path, which makes code easier to read. I don't care about handling internal errors, as long as they manifest in an obvious way. # Avoid variable assignment/binding inside case expressions Just don't do this: case Shape of rectangle -> Numbers = get_dimensions("width", "height"); triangle -> Numbers = get_dimensions("base", "height"); ellipse -> Numbers = get_dimensions("major axis", "minor axis") end Now that you're not allowed to do that, what? Hey, a function! Numbers = get_dimensions(Shape) Every time, all the time. # Consider not using case expressions at all Think of a function as a named case expression with a well defined scope. You'll find that having to name the function forces you to think about "what's going on" there. It will help your reader (often that means you, later on) to understand your intention. My rewrite doesn't use a single case expression. Is it somehow worse? It's better! # If it looks confusing, it's bad! Erlang is not C, or bash, or Perl, or Ruby. It's possible to write really easy-to-read code in Erlang. People who complain about Erlang syntax are probably complain about terrible code in Erlang. Terrible code in any language is worth complaining about - but it's unrelated to syntax. It's easy to spot bad code in Erlang: - Long functions - Excessive nesting (more than two levels is a train wreck, and IMO more than one is bad) I hate nesting so much that I'll go to the trouble of writing to_number/1 as a list of "try" attempts (see rewrite). Some people call this monadic, which I like because it sounds super cool. - Variable assignment/binding inside case and if expressions (see above) - Functions that are a litany of imperative style instructions, like this: get_number(Prompt) -> Str = io:get_line("Enter " ++ Prompt ++ " > "), {Test, _} = string:to_float(Str), case Test of error -> {N, _} = string:to_integer(Str); _ -> N = Test end, N. This fails the "long functions" test - but lines per function is just a proxy. The real problem here is that it takes too much effort to read and understand. Really, this is an imperative pattern applied naively to Erlang. No! Try this: number_from_user(Prompt) -> to_positive_number(prompt_user(["Enter ", Prompt, " > "])). Where's the rest of the code? It's there, inside the other functions. But *this* function doesn't make you deal with that detail because it wants you to understand what *it* is doing. Okay, so I've been pretty critical here of this online training resource, which some will consider bad form. So let's turn this into something nice and kind! The subject of this email is "refactoring in anger", which turns out to be something I routinely do with my own code. It's hard to write the perfect code in one pass. So I tend to just "get it to work" and then examine what seems to be working very carefully - and then change it so that it becomes *super obvious* what's going on. This state can take a few passes and still might have warts. Okay, no sweat - it's just code. Nothing to get angry about. Calm down and fix it. Over time, when you practice this pattern of refactoring, you'll start writing things clearly the first time. That's because you'll start *thinking* more clearly the first time. Now that's positive and nice and kind right? Garrett --- [1] Of course I'm joking here, but only partly. The original solution is presented to learners - and it's full of bad practices, so that makes me cranky. I suppose it's good to have teaching material for Erlang in any form - at least it serves as a point of discussion, even if contentious. From felixgallo@REDACTED Sun Aug 9 02:36:06 2015 From: felixgallo@REDACTED (Felix Gallo) Date: Sat, 8 Aug 2015 17:36:06 -0700 Subject: [erlang-questions] Refactoring in anger In-Reply-To: References: Message-ID: Eshell V7.0 (abort with ^G) 1> c(geom). {ok,geom} 2> c(ask_area). {ok,ask_area} 3> ask_area:print_area(). R)ectangle, T)riangle, or E)llipse > T ** exception error: no function clause matching ask_area:error_msg({badmatch,["Enter ","base"," > "]}) (ask_area.erl, line 69) in function ask_area:print_area/0 (ask_area.erl, line 9) glass houses, etc. F. On Sat, Aug 8, 2015 at 3:07 PM, Garrett Smith wrote: > We've had an ongoing thread on how to handle some problems > idiomatically in Erlang: > > http://erlang.org/pipermail/erlang-questions/2015-August/085382.html > > The OP's questions are coming out of an exercise here: > > http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 > > This in turn points to a proposed solution here: > > > http://chimera.labs.oreilly.com/books/1234000000726/apa.html#_literal_geom_erl_literal_9 > > Upon reading this solution, I became so enraged [1] that I rewrote the > module and want to make a number of points. > > Here's my rewrite: > > https://gist.github.com/gar1t/7bb80d728f804554ac32 > > The tone of my points below is *very preachy* which is going to annoy > some people here. I apologize in advance - but hey, ranters gotta > rant. > > # Clarity of "what's going on" > > Compare my area/0 to the original area/0. Which is easier to see > "what's going on"? I'm not boasting here but rather making the most > important point I can about programming: take the time to be clear in > your intent! If you're actually clear - in your brain - making the > code reflect your understanding *is not that hard*. If your code is > not clear, chances are your brain is not clear. > > Maybe the original code works, maybe it doesn't. I can't tell from > looking at that function, at all. I have to dig around various > implementation details and hold a bunch of information in my brain to > understand what the author is maybe trying to do. At some point I > can't keep it all straight and have to run the thing and observe its > behavior. *Now* I'm thinking, what happens to the pour schlep who has > to modify this code. In the real world, this causes fear, and > loathing, and tests - lots and lots of tests! > > We don't have to live this way. > > # Separation of concerns (in this case IO vs calculations) > > The original calculate/3 mixes user facing behavior (print error > messages) with a calculation. If your function returns a mishmash of > completely unrelated values (e.g. the result of io:format and also the > result of an area calculation) *it's a mess*. > > In the rewrite I've added print_area/0, which is responsible for > displaying results to the user. area/0 returns an area or raises an > exception. print_area/0 handles both the result and any error. > > # Handling invalid input > > The original thread here involves a discussion on how to handle bad > input to a function. My rewrite does one of two things on this front: > > - If input is from a user, there's an explicit exception raised on bad > input that can be used by an error handler to inform the user > > - If input is not from a user but rather internal, I don't handle bad > input at all, but let Erlang crash with a function or case clause > error > > The first case address the user experience. We could let exceptions > just propagate and upset users with arcane Erlang messages. Or we can > handle errors politely with intelligible messages. > > The original ask_erl.erl handles invalid input by passing atoms like > 'error' and 'unknown' along a call chain. This is tedious and finally > culminates in the original calculate/3 - a monster mishmash function > of error handling, IO, and calculation. > > My rewrite raises an exception for those functions that take user > provided input. I prefer exceptions in this case as they keep return > values on the happy path, which makes code easier to read. > > I don't care about handling internal errors, as long as they manifest > in an obvious way. > > # Avoid variable assignment/binding inside case expressions > > Just don't do this: > > case Shape of > rectangle -> Numbers = get_dimensions("width", "height"); > triangle -> Numbers = get_dimensions("base", "height"); > ellipse -> Numbers = get_dimensions("major axis", "minor axis") > end > > Now that you're not allowed to do that, what? Hey, a function! > > Numbers = get_dimensions(Shape) > > Every time, all the time. > > # Consider not using case expressions at all > > Think of a function as a named case expression with a well defined scope. > > You'll find that having to name the function forces you to think about > "what's going on" there. It will help your reader (often that means > you, later on) to understand your intention. > > My rewrite doesn't use a single case expression. Is it somehow worse? > It's better! > > # If it looks confusing, it's bad! > > Erlang is not C, or bash, or Perl, or Ruby. It's possible to write > really easy-to-read code in Erlang. People who complain about Erlang > syntax are probably complain about terrible code in Erlang. Terrible > code in any language is worth complaining about - but it's unrelated > to syntax. > > It's easy to spot bad code in Erlang: > > - Long functions > > - Excessive nesting (more than two levels is a train wreck, and IMO > more than one is bad) > > I hate nesting so much that I'll go to the trouble of writing > to_number/1 as a list of "try" attempts (see rewrite). Some people > call this monadic, which I like because it sounds super cool. > > - Variable assignment/binding inside case and if expressions (see above) > > - Functions that are a litany of imperative style instructions, like this: > > get_number(Prompt) -> > Str = io:get_line("Enter " ++ Prompt ++ " > "), > {Test, _} = string:to_float(Str), > case Test of > error -> {N, _} = string:to_integer(Str); > _ -> N = Test > end, > N. > > This fails the "long functions" test - but lines per function is just > a proxy. The real problem here is that it takes too much effort to > read and understand. Really, this is an imperative pattern applied > naively to Erlang. No! > > Try this: > > number_from_user(Prompt) -> > to_positive_number(prompt_user(["Enter ", Prompt, " > "])). > > Where's the rest of the code? It's there, inside the other functions. > But *this* function doesn't make you deal with that detail because it > wants you to understand what *it* is doing. > > Okay, so I've been pretty critical here of this online training > resource, which some will consider bad form. So let's turn this into > something nice and kind! > > The subject of this email is "refactoring in anger", which turns out > to be something I routinely do with my own code. It's hard to write > the perfect code in one pass. So I tend to just "get it to work" and > then examine what seems to be working very carefully - and then change > it so that it becomes *super obvious* what's going on. This state can > take a few passes and still might have warts. Okay, no sweat - it's > just code. Nothing to get angry about. Calm down and fix it. > > Over time, when you practice this pattern of refactoring, you'll start > writing things clearly the first time. That's because you'll start > *thinking* more clearly the first time. > > Now that's positive and nice and kind right? > > Garrett > > --- > > [1] Of course I'm joking here, but only partly. The original solution > is presented to learners - and it's full of bad practices, so that > makes me cranky. I suppose it's good to have teaching material for > Erlang in any form - at least it serves as a point of discussion, even > if contentious. > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From felixgallo@REDACTED Sun Aug 9 04:06:58 2015 From: felixgallo@REDACTED (Felix Gallo) Date: Sat, 8 Aug 2015 19:06:58 -0700 Subject: [erlang-questions] Refactoring in anger In-Reply-To: References: Message-ID: Nevertheless, if you're going to level a thundering, public j'accuse at someone who has clearly gone to great effort to provide a beginner experience for erlang newbies, without (apparently) first contacting him privately and suggesting improvements in a constructively critical manner, please have the decency to run the code that you have etched into your stone tablets *before* you hold them aloft and, with fiery mane ablaze in the evening sun, present them as the replacement for the gentleman's work. There are many "problems" with the etudes code. I'm not sure that introducing a complex exception handling workflow is one of them, to be frank, pedagogically, at the moment that the student is trying to understand pattern matching and function headers. Could be. But I think we can say it's a matter of taste. And that's what really rubs me the wrong way about Garrett's post. Being 'very preachy', even when volubly disclaimed, is still pretty tasteless. But being 'very preachy' and then slapping up code you haven't even run once, directly in opposition to your preaching's core point: that's hypocritical, and super tasteless. And I enjoy my rich dark ironic comedy as much as the next guy, but come on. F. On Sat, Aug 8, 2015 at 6:19 PM, Leandro Ostera wrote: > Just a minor typo: Line 48 should is trying to reassign the Prompt > variable. > > But +1 on the rest. > > On Sun, Aug 9, 2015 at 2:36 AM, Felix Gallo wrote: > >> Eshell V7.0 (abort with ^G) >> 1> c(geom). >> {ok,geom} >> 2> c(ask_area). >> {ok,ask_area} >> 3> ask_area:print_area(). >> R)ectangle, T)riangle, or E)llipse > T >> ** exception error: no function clause matching >> ask_area:error_msg({badmatch,["Enter ","base"," > "]}) (ask_area.erl, line >> 69) >> in function ask_area:print_area/0 (ask_area.erl, line 9) >> >> >> glass houses, etc. >> >> F. >> >> On Sat, Aug 8, 2015 at 3:07 PM, Garrett Smith wrote: >> >>> We've had an ongoing thread on how to handle some problems >>> idiomatically in Erlang: >>> >>> http://erlang.org/pipermail/erlang-questions/2015-August/085382.html >>> >>> The OP's questions are coming out of an exercise here: >>> >>> http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 >>> >>> This in turn points to a proposed solution here: >>> >>> >>> http://chimera.labs.oreilly.com/books/1234000000726/apa.html#_literal_geom_erl_literal_9 >>> >>> Upon reading this solution, I became so enraged [1] that I rewrote the >>> module and want to make a number of points. >>> >>> Here's my rewrite: >>> >>> https://gist.github.com/gar1t/7bb80d728f804554ac32 >>> >>> The tone of my points below is *very preachy* which is going to annoy >>> some people here. I apologize in advance - but hey, ranters gotta >>> rant. >>> >>> # Clarity of "what's going on" >>> >>> Compare my area/0 to the original area/0. Which is easier to see >>> "what's going on"? I'm not boasting here but rather making the most >>> important point I can about programming: take the time to be clear in >>> your intent! If you're actually clear - in your brain - making the >>> code reflect your understanding *is not that hard*. If your code is >>> not clear, chances are your brain is not clear. >>> >>> Maybe the original code works, maybe it doesn't. I can't tell from >>> looking at that function, at all. I have to dig around various >>> implementation details and hold a bunch of information in my brain to >>> understand what the author is maybe trying to do. At some point I >>> can't keep it all straight and have to run the thing and observe its >>> behavior. *Now* I'm thinking, what happens to the pour schlep who has >>> to modify this code. In the real world, this causes fear, and >>> loathing, and tests - lots and lots of tests! >>> >>> We don't have to live this way. >>> >>> # Separation of concerns (in this case IO vs calculations) >>> >>> The original calculate/3 mixes user facing behavior (print error >>> messages) with a calculation. If your function returns a mishmash of >>> completely unrelated values (e.g. the result of io:format and also the >>> result of an area calculation) *it's a mess*. >>> >>> In the rewrite I've added print_area/0, which is responsible for >>> displaying results to the user. area/0 returns an area or raises an >>> exception. print_area/0 handles both the result and any error. >>> >>> # Handling invalid input >>> >>> The original thread here involves a discussion on how to handle bad >>> input to a function. My rewrite does one of two things on this front: >>> >>> - If input is from a user, there's an explicit exception raised on bad >>> input that can be used by an error handler to inform the user >>> >>> - If input is not from a user but rather internal, I don't handle bad >>> input at all, but let Erlang crash with a function or case clause >>> error >>> >>> The first case address the user experience. We could let exceptions >>> just propagate and upset users with arcane Erlang messages. Or we can >>> handle errors politely with intelligible messages. >>> >>> The original ask_erl.erl handles invalid input by passing atoms like >>> 'error' and 'unknown' along a call chain. This is tedious and finally >>> culminates in the original calculate/3 - a monster mishmash function >>> of error handling, IO, and calculation. >>> >>> My rewrite raises an exception for those functions that take user >>> provided input. I prefer exceptions in this case as they keep return >>> values on the happy path, which makes code easier to read. >>> >>> I don't care about handling internal errors, as long as they manifest >>> in an obvious way. >>> >>> # Avoid variable assignment/binding inside case expressions >>> >>> Just don't do this: >>> >>> case Shape of >>> rectangle -> Numbers = get_dimensions("width", "height"); >>> triangle -> Numbers = get_dimensions("base", "height"); >>> ellipse -> Numbers = get_dimensions("major axis", "minor axis") >>> end >>> >>> Now that you're not allowed to do that, what? Hey, a function! >>> >>> Numbers = get_dimensions(Shape) >>> >>> Every time, all the time. >>> >>> # Consider not using case expressions at all >>> >>> Think of a function as a named case expression with a well defined scope. >>> >>> You'll find that having to name the function forces you to think about >>> "what's going on" there. It will help your reader (often that means >>> you, later on) to understand your intention. >>> >>> My rewrite doesn't use a single case expression. Is it somehow worse? >>> It's better! >>> >>> # If it looks confusing, it's bad! >>> >>> Erlang is not C, or bash, or Perl, or Ruby. It's possible to write >>> really easy-to-read code in Erlang. People who complain about Erlang >>> syntax are probably complain about terrible code in Erlang. Terrible >>> code in any language is worth complaining about - but it's unrelated >>> to syntax. >>> >>> It's easy to spot bad code in Erlang: >>> >>> - Long functions >>> >>> - Excessive nesting (more than two levels is a train wreck, and IMO >>> more than one is bad) >>> >>> I hate nesting so much that I'll go to the trouble of writing >>> to_number/1 as a list of "try" attempts (see rewrite). Some people >>> call this monadic, which I like because it sounds super cool. >>> >>> - Variable assignment/binding inside case and if expressions (see above) >>> >>> - Functions that are a litany of imperative style instructions, like >>> this: >>> >>> get_number(Prompt) -> >>> Str = io:get_line("Enter " ++ Prompt ++ " > "), >>> {Test, _} = string:to_float(Str), >>> case Test of >>> error -> {N, _} = string:to_integer(Str); >>> _ -> N = Test >>> end, >>> N. >>> >>> This fails the "long functions" test - but lines per function is just >>> a proxy. The real problem here is that it takes too much effort to >>> read and understand. Really, this is an imperative pattern applied >>> naively to Erlang. No! >>> >>> Try this: >>> >>> number_from_user(Prompt) -> >>> to_positive_number(prompt_user(["Enter ", Prompt, " > "])). >>> >>> Where's the rest of the code? It's there, inside the other functions. >>> But *this* function doesn't make you deal with that detail because it >>> wants you to understand what *it* is doing. >>> >>> Okay, so I've been pretty critical here of this online training >>> resource, which some will consider bad form. So let's turn this into >>> something nice and kind! >>> >>> The subject of this email is "refactoring in anger", which turns out >>> to be something I routinely do with my own code. It's hard to write >>> the perfect code in one pass. So I tend to just "get it to work" and >>> then examine what seems to be working very carefully - and then change >>> it so that it becomes *super obvious* what's going on. This state can >>> take a few passes and still might have warts. Okay, no sweat - it's >>> just code. Nothing to get angry about. Calm down and fix it. >>> >>> Over time, when you practice this pattern of refactoring, you'll start >>> writing things clearly the first time. That's because you'll start >>> *thinking* more clearly the first time. >>> >>> Now that's positive and nice and kind right? >>> >>> Garrett >>> >>> --- >>> >>> [1] Of course I'm joking here, but only partly. The original solution >>> is presented to learners - and it's full of bad practices, so that >>> makes me cranky. I suppose it's good to have teaching material for >>> Erlang in any form - at least it serves as a point of discussion, even >>> if contentious. >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >>> >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From g@REDACTED Sun Aug 9 04:54:46 2015 From: g@REDACTED (Garrett Smith) Date: Sat, 8 Aug 2015 21:54:46 -0500 Subject: [erlang-questions] Refactoring in anger In-Reply-To: References: Message-ID: Aye, this was an untested change I made after posting the original. Change reverted. On Sat, Aug 8, 2015 at 8:19 PM, Leandro Ostera wrote: > Just a minor typo: Line 48 should is trying to reassign the Prompt variable. > > But +1 on the rest. > > On Sun, Aug 9, 2015 at 2:36 AM, Felix Gallo wrote: >> >> Eshell V7.0 (abort with ^G) >> 1> c(geom). >> {ok,geom} >> 2> c(ask_area). >> {ok,ask_area} >> 3> ask_area:print_area(). >> R)ectangle, T)riangle, or E)llipse > T >> ** exception error: no function clause matching >> ask_area:error_msg({badmatch,["Enter ","base"," > "]}) (ask_area.erl, line >> 69) >> in function ask_area:print_area/0 (ask_area.erl, line 9) >> >> >> glass houses, etc. >> >> F. >> >> On Sat, Aug 8, 2015 at 3:07 PM, Garrett Smith wrote: >>> >>> We've had an ongoing thread on how to handle some problems >>> idiomatically in Erlang: >>> >>> http://erlang.org/pipermail/erlang-questions/2015-August/085382.html >>> >>> The OP's questions are coming out of an exercise here: >>> >>> http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 >>> >>> This in turn points to a proposed solution here: >>> >>> >>> http://chimera.labs.oreilly.com/books/1234000000726/apa.html#_literal_geom_erl_literal_9 >>> >>> Upon reading this solution, I became so enraged [1] that I rewrote the >>> module and want to make a number of points. >>> >>> Here's my rewrite: >>> >>> https://gist.github.com/gar1t/7bb80d728f804554ac32 >>> >>> The tone of my points below is *very preachy* which is going to annoy >>> some people here. I apologize in advance - but hey, ranters gotta >>> rant. >>> >>> # Clarity of "what's going on" >>> >>> Compare my area/0 to the original area/0. Which is easier to see >>> "what's going on"? I'm not boasting here but rather making the most >>> important point I can about programming: take the time to be clear in >>> your intent! If you're actually clear - in your brain - making the >>> code reflect your understanding *is not that hard*. If your code is >>> not clear, chances are your brain is not clear. >>> >>> Maybe the original code works, maybe it doesn't. I can't tell from >>> looking at that function, at all. I have to dig around various >>> implementation details and hold a bunch of information in my brain to >>> understand what the author is maybe trying to do. At some point I >>> can't keep it all straight and have to run the thing and observe its >>> behavior. *Now* I'm thinking, what happens to the pour schlep who has >>> to modify this code. In the real world, this causes fear, and >>> loathing, and tests - lots and lots of tests! >>> >>> We don't have to live this way. >>> >>> # Separation of concerns (in this case IO vs calculations) >>> >>> The original calculate/3 mixes user facing behavior (print error >>> messages) with a calculation. If your function returns a mishmash of >>> completely unrelated values (e.g. the result of io:format and also the >>> result of an area calculation) *it's a mess*. >>> >>> In the rewrite I've added print_area/0, which is responsible for >>> displaying results to the user. area/0 returns an area or raises an >>> exception. print_area/0 handles both the result and any error. >>> >>> # Handling invalid input >>> >>> The original thread here involves a discussion on how to handle bad >>> input to a function. My rewrite does one of two things on this front: >>> >>> - If input is from a user, there's an explicit exception raised on bad >>> input that can be used by an error handler to inform the user >>> >>> - If input is not from a user but rather internal, I don't handle bad >>> input at all, but let Erlang crash with a function or case clause >>> error >>> >>> The first case address the user experience. We could let exceptions >>> just propagate and upset users with arcane Erlang messages. Or we can >>> handle errors politely with intelligible messages. >>> >>> The original ask_erl.erl handles invalid input by passing atoms like >>> 'error' and 'unknown' along a call chain. This is tedious and finally >>> culminates in the original calculate/3 - a monster mishmash function >>> of error handling, IO, and calculation. >>> >>> My rewrite raises an exception for those functions that take user >>> provided input. I prefer exceptions in this case as they keep return >>> values on the happy path, which makes code easier to read. >>> >>> I don't care about handling internal errors, as long as they manifest >>> in an obvious way. >>> >>> # Avoid variable assignment/binding inside case expressions >>> >>> Just don't do this: >>> >>> case Shape of >>> rectangle -> Numbers = get_dimensions("width", "height"); >>> triangle -> Numbers = get_dimensions("base", "height"); >>> ellipse -> Numbers = get_dimensions("major axis", "minor axis") >>> end >>> >>> Now that you're not allowed to do that, what? Hey, a function! >>> >>> Numbers = get_dimensions(Shape) >>> >>> Every time, all the time. >>> >>> # Consider not using case expressions at all >>> >>> Think of a function as a named case expression with a well defined scope. >>> >>> You'll find that having to name the function forces you to think about >>> "what's going on" there. It will help your reader (often that means >>> you, later on) to understand your intention. >>> >>> My rewrite doesn't use a single case expression. Is it somehow worse? >>> It's better! >>> >>> # If it looks confusing, it's bad! >>> >>> Erlang is not C, or bash, or Perl, or Ruby. It's possible to write >>> really easy-to-read code in Erlang. People who complain about Erlang >>> syntax are probably complain about terrible code in Erlang. Terrible >>> code in any language is worth complaining about - but it's unrelated >>> to syntax. >>> >>> It's easy to spot bad code in Erlang: >>> >>> - Long functions >>> >>> - Excessive nesting (more than two levels is a train wreck, and IMO >>> more than one is bad) >>> >>> I hate nesting so much that I'll go to the trouble of writing >>> to_number/1 as a list of "try" attempts (see rewrite). Some people >>> call this monadic, which I like because it sounds super cool. >>> >>> - Variable assignment/binding inside case and if expressions (see above) >>> >>> - Functions that are a litany of imperative style instructions, like >>> this: >>> >>> get_number(Prompt) -> >>> Str = io:get_line("Enter " ++ Prompt ++ " > "), >>> {Test, _} = string:to_float(Str), >>> case Test of >>> error -> {N, _} = string:to_integer(Str); >>> _ -> N = Test >>> end, >>> N. >>> >>> This fails the "long functions" test - but lines per function is just >>> a proxy. The real problem here is that it takes too much effort to >>> read and understand. Really, this is an imperative pattern applied >>> naively to Erlang. No! >>> >>> Try this: >>> >>> number_from_user(Prompt) -> >>> to_positive_number(prompt_user(["Enter ", Prompt, " > "])). >>> >>> Where's the rest of the code? It's there, inside the other functions. >>> But *this* function doesn't make you deal with that detail because it >>> wants you to understand what *it* is doing. >>> >>> Okay, so I've been pretty critical here of this online training >>> resource, which some will consider bad form. So let's turn this into >>> something nice and kind! >>> >>> The subject of this email is "refactoring in anger", which turns out >>> to be something I routinely do with my own code. It's hard to write >>> the perfect code in one pass. So I tend to just "get it to work" and >>> then examine what seems to be working very carefully - and then change >>> it so that it becomes *super obvious* what's going on. This state can >>> take a few passes and still might have warts. Okay, no sweat - it's >>> just code. Nothing to get angry about. Calm down and fix it. >>> >>> Over time, when you practice this pattern of refactoring, you'll start >>> writing things clearly the first time. That's because you'll start >>> *thinking* more clearly the first time. >>> >>> Now that's positive and nice and kind right? >>> >>> Garrett >>> >>> --- >>> >>> [1] Of course I'm joking here, but only partly. The original solution >>> is presented to learners - and it's full of bad practices, so that >>> makes me cranky. I suppose it's good to have teaching material for >>> Erlang in any form - at least it serves as a point of discussion, even >>> if contentious. >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >> >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> > From g@REDACTED Sun Aug 9 05:21:50 2015 From: g@REDACTED (Garrett Smith) Date: Sat, 8 Aug 2015 22:21:50 -0500 Subject: [erlang-questions] Refactoring in anger In-Reply-To: References: Message-ID: I of course ran it, it worked. I made a minor untested change after the post, it broke trivially, it's fixed. You can check the gist change history if that sort of thing makes the slightest difference in your economy. I'm happy to submit broken code as it's consistent with my thesis of refactoring. In this case, yeah, not much to fix, but flawed nonetheless. "It's just code... calm down and fix it." I'm sure this talented community will see other actual ways to improve the code and make constructive improvements. In that critique we can learn to be better Erlang programmers. The differences I've articulated between the two modules are not a matter of taste. They're a matter of cogency. Naturally the critique is not perfect, but hopefully you can see past jots and tittles to the process of improving code with well reasoned patterns and principles. On Sat, Aug 8, 2015 at 9:06 PM, Felix Gallo wrote: > Nevertheless, if you're going to level a thundering, public j'accuse at > someone who has clearly gone to great effort to provide a beginner > experience for erlang newbies, without (apparently) first contacting him > privately and suggesting improvements in a constructively critical manner, > please have the decency to run the code that you have etched into your stone > tablets *before* you hold them aloft and, with fiery mane ablaze in the > evening sun, present them as the replacement for the gentleman's work. > > There are many "problems" with the etudes code. I'm not sure that > introducing a complex exception handling workflow is one of them, to be > frank, pedagogically, at the moment that the student is trying to understand > pattern matching and function headers. Could be. But I think we can say > it's a matter of taste. > > And that's what really rubs me the wrong way about Garrett's post. Being > 'very preachy', even when volubly disclaimed, is still pretty tasteless. > But being 'very preachy' and then slapping up code you haven't even run > once, directly in opposition to your preaching's core point: that's > hypocritical, and super tasteless. And I enjoy my rich dark ironic comedy > as much as the next guy, but come on. > > F. > > On Sat, Aug 8, 2015 at 6:19 PM, Leandro Ostera wrote: >> >> Just a minor typo: Line 48 should is trying to reassign the Prompt >> variable. >> >> But +1 on the rest. >> >> On Sun, Aug 9, 2015 at 2:36 AM, Felix Gallo wrote: >>> >>> Eshell V7.0 (abort with ^G) >>> 1> c(geom). >>> {ok,geom} >>> 2> c(ask_area). >>> {ok,ask_area} >>> 3> ask_area:print_area(). >>> R)ectangle, T)riangle, or E)llipse > T >>> ** exception error: no function clause matching >>> ask_area:error_msg({badmatch,["Enter ","base"," > "]}) (ask_area.erl, line >>> 69) >>> in function ask_area:print_area/0 (ask_area.erl, line 9) >>> >>> >>> glass houses, etc. >>> >>> F. >>> >>> On Sat, Aug 8, 2015 at 3:07 PM, Garrett Smith wrote: >>>> >>>> We've had an ongoing thread on how to handle some problems >>>> idiomatically in Erlang: >>>> >>>> http://erlang.org/pipermail/erlang-questions/2015-August/085382.html >>>> >>>> The OP's questions are coming out of an exercise here: >>>> >>>> http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 >>>> >>>> This in turn points to a proposed solution here: >>>> >>>> >>>> http://chimera.labs.oreilly.com/books/1234000000726/apa.html#_literal_geom_erl_literal_9 >>>> >>>> Upon reading this solution, I became so enraged [1] that I rewrote the >>>> module and want to make a number of points. >>>> >>>> Here's my rewrite: >>>> >>>> https://gist.github.com/gar1t/7bb80d728f804554ac32 >>>> >>>> The tone of my points below is *very preachy* which is going to annoy >>>> some people here. I apologize in advance - but hey, ranters gotta >>>> rant. >>>> >>>> # Clarity of "what's going on" >>>> >>>> Compare my area/0 to the original area/0. Which is easier to see >>>> "what's going on"? I'm not boasting here but rather making the most >>>> important point I can about programming: take the time to be clear in >>>> your intent! If you're actually clear - in your brain - making the >>>> code reflect your understanding *is not that hard*. If your code is >>>> not clear, chances are your brain is not clear. >>>> >>>> Maybe the original code works, maybe it doesn't. I can't tell from >>>> looking at that function, at all. I have to dig around various >>>> implementation details and hold a bunch of information in my brain to >>>> understand what the author is maybe trying to do. At some point I >>>> can't keep it all straight and have to run the thing and observe its >>>> behavior. *Now* I'm thinking, what happens to the pour schlep who has >>>> to modify this code. In the real world, this causes fear, and >>>> loathing, and tests - lots and lots of tests! >>>> >>>> We don't have to live this way. >>>> >>>> # Separation of concerns (in this case IO vs calculations) >>>> >>>> The original calculate/3 mixes user facing behavior (print error >>>> messages) with a calculation. If your function returns a mishmash of >>>> completely unrelated values (e.g. the result of io:format and also the >>>> result of an area calculation) *it's a mess*. >>>> >>>> In the rewrite I've added print_area/0, which is responsible for >>>> displaying results to the user. area/0 returns an area or raises an >>>> exception. print_area/0 handles both the result and any error. >>>> >>>> # Handling invalid input >>>> >>>> The original thread here involves a discussion on how to handle bad >>>> input to a function. My rewrite does one of two things on this front: >>>> >>>> - If input is from a user, there's an explicit exception raised on bad >>>> input that can be used by an error handler to inform the user >>>> >>>> - If input is not from a user but rather internal, I don't handle bad >>>> input at all, but let Erlang crash with a function or case clause >>>> error >>>> >>>> The first case address the user experience. We could let exceptions >>>> just propagate and upset users with arcane Erlang messages. Or we can >>>> handle errors politely with intelligible messages. >>>> >>>> The original ask_erl.erl handles invalid input by passing atoms like >>>> 'error' and 'unknown' along a call chain. This is tedious and finally >>>> culminates in the original calculate/3 - a monster mishmash function >>>> of error handling, IO, and calculation. >>>> >>>> My rewrite raises an exception for those functions that take user >>>> provided input. I prefer exceptions in this case as they keep return >>>> values on the happy path, which makes code easier to read. >>>> >>>> I don't care about handling internal errors, as long as they manifest >>>> in an obvious way. >>>> >>>> # Avoid variable assignment/binding inside case expressions >>>> >>>> Just don't do this: >>>> >>>> case Shape of >>>> rectangle -> Numbers = get_dimensions("width", "height"); >>>> triangle -> Numbers = get_dimensions("base", "height"); >>>> ellipse -> Numbers = get_dimensions("major axis", "minor axis") >>>> end >>>> >>>> Now that you're not allowed to do that, what? Hey, a function! >>>> >>>> Numbers = get_dimensions(Shape) >>>> >>>> Every time, all the time. >>>> >>>> # Consider not using case expressions at all >>>> >>>> Think of a function as a named case expression with a well defined >>>> scope. >>>> >>>> You'll find that having to name the function forces you to think about >>>> "what's going on" there. It will help your reader (often that means >>>> you, later on) to understand your intention. >>>> >>>> My rewrite doesn't use a single case expression. Is it somehow worse? >>>> It's better! >>>> >>>> # If it looks confusing, it's bad! >>>> >>>> Erlang is not C, or bash, or Perl, or Ruby. It's possible to write >>>> really easy-to-read code in Erlang. People who complain about Erlang >>>> syntax are probably complain about terrible code in Erlang. Terrible >>>> code in any language is worth complaining about - but it's unrelated >>>> to syntax. >>>> >>>> It's easy to spot bad code in Erlang: >>>> >>>> - Long functions >>>> >>>> - Excessive nesting (more than two levels is a train wreck, and IMO >>>> more than one is bad) >>>> >>>> I hate nesting so much that I'll go to the trouble of writing >>>> to_number/1 as a list of "try" attempts (see rewrite). Some people >>>> call this monadic, which I like because it sounds super cool. >>>> >>>> - Variable assignment/binding inside case and if expressions (see above) >>>> >>>> - Functions that are a litany of imperative style instructions, like >>>> this: >>>> >>>> get_number(Prompt) -> >>>> Str = io:get_line("Enter " ++ Prompt ++ " > "), >>>> {Test, _} = string:to_float(Str), >>>> case Test of >>>> error -> {N, _} = string:to_integer(Str); >>>> _ -> N = Test >>>> end, >>>> N. >>>> >>>> This fails the "long functions" test - but lines per function is just >>>> a proxy. The real problem here is that it takes too much effort to >>>> read and understand. Really, this is an imperative pattern applied >>>> naively to Erlang. No! >>>> >>>> Try this: >>>> >>>> number_from_user(Prompt) -> >>>> to_positive_number(prompt_user(["Enter ", Prompt, " > "])). >>>> >>>> Where's the rest of the code? It's there, inside the other functions. >>>> But *this* function doesn't make you deal with that detail because it >>>> wants you to understand what *it* is doing. >>>> >>>> Okay, so I've been pretty critical here of this online training >>>> resource, which some will consider bad form. So let's turn this into >>>> something nice and kind! >>>> >>>> The subject of this email is "refactoring in anger", which turns out >>>> to be something I routinely do with my own code. It's hard to write >>>> the perfect code in one pass. So I tend to just "get it to work" and >>>> then examine what seems to be working very carefully - and then change >>>> it so that it becomes *super obvious* what's going on. This state can >>>> take a few passes and still might have warts. Okay, no sweat - it's >>>> just code. Nothing to get angry about. Calm down and fix it. >>>> >>>> Over time, when you practice this pattern of refactoring, you'll start >>>> writing things clearly the first time. That's because you'll start >>>> *thinking* more clearly the first time. >>>> >>>> Now that's positive and nice and kind right? >>>> >>>> Garrett >>>> >>>> --- >>>> >>>> [1] Of course I'm joking here, but only partly. The original solution >>>> is presented to learners - and it's full of bad practices, so that >>>> makes me cranky. I suppose it's good to have teaching material for >>>> Erlang in any form - at least it serves as a point of discussion, even >>>> if contentious. >>>> _______________________________________________ >>>> erlang-questions mailing list >>>> erlang-questions@REDACTED >>>> http://erlang.org/mailman/listinfo/erlang-questions >>> >>> >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >>> >> > From jdavid.eisenberg@REDACTED Sun Aug 9 08:25:33 2015 From: jdavid.eisenberg@REDACTED (J David Eisenberg) Date: Sat, 8 Aug 2015 23:25:33 -0700 Subject: [erlang-questions] Refactoring in anger (Felix Gallo) Message-ID: Felix Gallo wrote: > Nevertheless, if you're going to level a thundering, public j'accuse at > someone who has clearly gone to great effort to provide a beginner > experience for erlang newbies, without (apparently) first contacting him > privately and suggesting improvements in a constructively critical manner, > please have the decency to run the code that you have etched into your > stone tablets *before* you hold them aloft and, with fiery mane ablaze in > the evening sun, present them as the replacement for the gentleman's work. > > There are many "problems" with the etudes code. I'm not sure that > introducing a complex exception handling workflow is one of them, to be > frank, pedagogically, at the moment that the student is trying to > understand pattern matching and function headers. Could be. But I think > we can say it's a matter of taste. > > And that's what really rubs me the wrong way about Garrett's post. Being > 'very preachy', even when volubly disclaimed, is still pretty tasteless. > But being 'very preachy' and then slapping up code you haven't even run > once, directly in opposition to your preaching's core point: that's > hypocritical, and super tasteless. And I enjoy my rich dark ironic comedy > as much as the next guy, but come on. > > F. Author of Etudes here. There I was at Pepe's Tacos in Las Vegas, waiting for my meal, and I decided to read the Erlang questions mail list and see what's going on. As the story unfolded, I started cackling with laughter, until I realized that half the people in the restaurant were staring at me like "What the hell is wrong with this crazy white guy laughing at his phone?" So no, I'm not even remotely offended. Especially because I write in the preface: "I was learning Erlang as I was creating the solutions to the ?tudes, following the philosophy that 'the first way that works is the right way.' Therefore, don?t be surprised if you see some fairly na?ve code that an expert Erlang programmer would never write." Since the book is open source, if anyone would like to add a better solution with a discussion of why it's better, I would be perfectly happy to see that. Modulo the anger, of course :) > On Sat, Aug 8, 2015 at 6:19 PM, Leandro Ostera wrote: > > > Just a minor typo: Line 48 should is trying to reassign the Prompt > > variable. > > > > But +1 on the rest. > > > > On Sun, Aug 9, 2015 at 2:36 AM, Felix Gallo wrote: > > > >> Eshell V7.0 (abort with ^G) > >> 1> c(geom). > >> {ok,geom} > >> 2> c(ask_area). > >> {ok,ask_area} > >> 3> ask_area:print_area(). > >> R)ectangle, T)riangle, or E)llipse > T > >> ** exception error: no function clause matching > >> ask_area:error_msg({badmatch,["Enter ","base"," > "]}) (ask_area.erl, line > >> 69) > >> in function ask_area:print_area/0 (ask_area.erl, line 9) > >> > >> > >> glass houses, etc. > >> > >> F. > >> > >> On Sat, Aug 8, 2015 at 3:07 PM, Garrett Smith wrote: > >> > >>> We've had an ongoing thread on how to handle some problems > >>> idiomatically in Erlang: > >>> > >>> http://erlang.org/pipermail/erlang-questions/2015-August/085382.html > >>> > >>> The OP's questions are coming out of an exercise here: > >>> > >>> http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 > >>> > >>> This in turn points to a proposed solution here: > >>> > >>> > >>> http://chimera.labs.oreilly.com/books/1234000000726/apa.html#_literal_geom_erl_literal_9 > >>> > >>> Upon reading this solution, I became so enraged [1] that I rewrote the > >>> module and want to make a number of points. > >>> > >>> Here's my rewrite: > >>> > >>> https://gist.github.com/gar1t/7bb80d728f804554ac32 > >>> > >>> The tone of my points below is *very preachy* which is going to annoy > >>> some people here. I apologize in advance - but hey, ranters gotta > >>> rant. > >>> > >>> # Clarity of "what's going on" > >>> > >>> Compare my area/0 to the original area/0. Which is easier to see > >>> "what's going on"? I'm not boasting here but rather making the most > >>> important point I can about programming: take the time to be clear in > >>> your intent! If you're actually clear - in your brain - making the > >>> code reflect your understanding *is not that hard*. If your code is > >>> not clear, chances are your brain is not clear. > >>> > >>> Maybe the original code works, maybe it doesn't. I can't tell from > >>> looking at that function, at all. I have to dig around various > >>> implementation details and hold a bunch of information in my brain to > >>> understand what the author is maybe trying to do. At some point I > >>> can't keep it all straight and have to run the thing and observe its > >>> behavior. *Now* I'm thinking, what happens to the pour schlep who has > >>> to modify this code. In the real world, this causes fear, and > >>> loathing, and tests - lots and lots of tests! > >>> > >>> We don't have to live this way. > >>> > >>> # Separation of concerns (in this case IO vs calculations) > >>> > >>> The original calculate/3 mixes user facing behavior (print error > >>> messages) with a calculation. If your function returns a mishmash of > >>> completely unrelated values (e.g. the result of io:format and also the > >>> result of an area calculation) *it's a mess*. > >>> > >>> In the rewrite I've added print_area/0, which is responsible for > >>> displaying results to the user. area/0 returns an area or raises an > >>> exception. print_area/0 handles both the result and any error. > >>> > >>> # Handling invalid input > >>> > >>> The original thread here involves a discussion on how to handle bad > >>> input to a function. My rewrite does one of two things on this front: > >>> > >>> - If input is from a user, there's an explicit exception raised on bad > >>> input that can be used by an error handler to inform the user > >>> > >>> - If input is not from a user but rather internal, I don't handle bad > >>> input at all, but let Erlang crash with a function or case clause > >>> error > >>> > >>> The first case address the user experience. We could let exceptions > >>> just propagate and upset users with arcane Erlang messages. Or we can > >>> handle errors politely with intelligible messages. > >>> > >>> The original ask_erl.erl handles invalid input by passing atoms like > >>> 'error' and 'unknown' along a call chain. This is tedious and finally > >>> culminates in the original calculate/3 - a monster mishmash function > >>> of error handling, IO, and calculation. > >>> > >>> My rewrite raises an exception for those functions that take user > >>> provided input. I prefer exceptions in this case as they keep return > >>> values on the happy path, which makes code easier to read. > >>> > >>> I don't care about handling internal errors, as long as they manifest > >>> in an obvious way. > >>> > >>> # Avoid variable assignment/binding inside case expressions > >>> > >>> Just don't do this: > >>> > >>> case Shape of > >>> rectangle -> Numbers = get_dimensions("width", "height"); > >>> triangle -> Numbers = get_dimensions("base", "height"); > >>> ellipse -> Numbers = get_dimensions("major axis", "minor axis") > >>> end > >>> > >>> Now that you're not allowed to do that, what? Hey, a function! > >>> > >>> Numbers = get_dimensions(Shape) > >>> > >>> Every time, all the time. > >>> > >>> # Consider not using case expressions at all > >>> > >>> Think of a function as a named case expression with a well defined scope. > >>> > >>> You'll find that having to name the function forces you to think about > >>> "what's going on" there. It will help your reader (often that means > >>> you, later on) to understand your intention. > >>> > >>> My rewrite doesn't use a single case expression. Is it somehow worse? > >>> It's better! > >>> > >>> # If it looks confusing, it's bad! > >>> > >>> Erlang is not C, or bash, or Perl, or Ruby. It's possible to write > >>> really easy-to-read code in Erlang. People who complain about Erlang > >>> syntax are probably complain about terrible code in Erlang. Terrible > >>> code in any language is worth complaining about - but it's unrelated > >>> to syntax. > >>> > >>> It's easy to spot bad code in Erlang: > >>> > >>> - Long functions > >>> > >>> - Excessive nesting (more than two levels is a train wreck, and IMO > >>> more than one is bad) > >>> > >>> I hate nesting so much that I'll go to the trouble of writing > >>> to_number/1 as a list of "try" attempts (see rewrite). Some people > >>> call this monadic, which I like because it sounds super cool. > >>> > >>> - Variable assignment/binding inside case and if expressions (see above) > >>> > >>> - Functions that are a litany of imperative style instructions, like > >>> this: > >>> > >>> get_number(Prompt) -> > >>> Str = io:get_line("Enter " ++ Prompt ++ " > "), > >>> {Test, _} = string:to_float(Str), > >>> case Test of > >>> error -> {N, _} = string:to_integer(Str); > >>> _ -> N = Test > >>> end, > >>> N. > >>> > >>> This fails the "long functions" test - but lines per function is just > >>> a proxy. The real problem here is that it takes too much effort to > >>> read and understand. Really, this is an imperative pattern applied > >>> naively to Erlang. No! > >>> > >>> Try this: > >>> > >>> number_from_user(Prompt) -> > >>> to_positive_number(prompt_user(["Enter ", Prompt, " > "])). > >>> > >>> Where's the rest of the code? It's there, inside the other functions. > >>> But *this* function doesn't make you deal with that detail because it > >>> wants you to understand what *it* is doing. > >>> > >>> Okay, so I've been pretty critical here of this online training > >>> resource, which some will consider bad form. So let's turn this into > >>> something nice and kind! > >>> > >>> The subject of this email is "refactoring in anger", which turns out > >>> to be something I routinely do with my own code. It's hard to write > >>> the perfect code in one pass. So I tend to just "get it to work" and > >>> then examine what seems to be working very carefully - and then change > >>> it so that it becomes *super obvious* what's going on. This state can > >>> take a few passes and still might have warts. Okay, no sweat - it's > >>> just code. Nothing to get angry about. Calm down and fix it. > >>> > >>> Over time, when you practice this pattern of refactoring, you'll start > >>> writing things clearly the first time. That's because you'll start > >>> *thinking* more clearly the first time. > >>> > >>> Now that's positive and nice and kind right? > >>> > >>> Garrett > >>> > >>> --- > >>> > >>> [1] Of course I'm joking here, but only partly. The original solution > >>> is presented to learners - and it's full of bad practices, so that > >>> makes me cranky. I suppose it's good to have teaching material for > >>> Erlang in any form - at least it serves as a point of discussion, even > >>> if contentious. From r.wobben@REDACTED Sun Aug 9 10:31:44 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Sun, 9 Aug 2015 10:31:44 +0200 Subject: [erlang-questions] Refactoring in anger (Felix Gallo) In-Reply-To: References: Message-ID: <55C70FF0.9070700@home.nl> Op 9-8-2015 om 8:25 schreef J David Eisenberg: > Felix Gallo wrote: > >> Nevertheless, if you're going to level a thundering, public j'accuse at >> someone who has clearly gone to great effort to provide a beginner >> experience for erlang newbies, without (apparently) first contacting him >> privately and suggesting improvements in a constructively critical manner, >> please have the decency to run the code that you have etched into your >> stone tablets *before* you hold them aloft and, with fiery mane ablaze in >> the evening sun, present them as the replacement for the gentleman's work. >> >> There are many "problems" with the etudes code. I'm not sure that >> introducing a complex exception handling workflow is one of them, to be >> frank, pedagogically, at the moment that the student is trying to >> understand pattern matching and function headers. Could be. But I think >> we can say it's a matter of taste. >> >> And that's what really rubs me the wrong way about Garrett's post. Being >> 'very preachy', even when volubly disclaimed, is still pretty tasteless. >> But being 'very preachy' and then slapping up code you haven't even run >> once, directly in opposition to your preaching's core point: that's >> hypocritical, and super tasteless. And I enjoy my rich dark ironic comedy >> as much as the next guy, but come on. >> >> F. > Author of Etudes here. > > There I was at Pepe's Tacos in Las Vegas, waiting for my meal, and I decided > to read the Erlang questions mail list and see what's going on. As the story > unfolded, I started cackling with laughter, until I realized that half > the people > in the restaurant were staring at me like "What the hell is wrong with this > crazy white guy laughing at his phone?" > > So no, I'm not even remotely offended. Especially because I write in > the preface: > "I was learning Erlang as I was creating the solutions to the ?tudes, > following the philosophy that 'the first way that works is the right way.' > Therefore, don?t be surprised if you see some fairly na?ve code that an expert > Erlang programmer would never write." > > Since the book is open source, if anyone would like to add a better > solution with > a discussion of why it's better, I would be perfectly happy to see that. Modulo > the anger, of course :) > >> On Sat, Aug 8, 2015 at 6:19 PM, Leandro Ostera wrote: >> >>> Just a minor typo: Line 48 should is trying to reassign the Prompt >>> variable. >>> >>> But +1 on the rest. >>> >>> On Sun, Aug 9, 2015 at 2:36 AM, Felix Gallo wrote: >>> >>>> Eshell V7.0 (abort with ^G) >>>> 1> c(geom). >>>> {ok,geom} >>>> 2> c(ask_area). >>>> {ok,ask_area} >>>> 3> ask_area:print_area(). >>>> R)ectangle, T)riangle, or E)llipse > T >>>> ** exception error: no function clause matching >>>> ask_area:error_msg({badmatch,["Enter ","base"," > "]}) (ask_area.erl, line >>>> 69) >>>> in function ask_area:print_area/0 (ask_area.erl, line 9) >>>> >>>> >>>> glass houses, etc. >>>> >>>> F. >>>> >>>> On Sat, Aug 8, 2015 at 3:07 PM, Garrett Smith wrote: >>>> >>>>> We've had an ongoing thread on how to handle some problems >>>>> idiomatically in Erlang: >>>>> >>>>> http://erlang.org/pipermail/erlang-questions/2015-August/085382.html >>>>> >>>>> The OP's questions are coming out of an exercise here: >>>>> >>>>> http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 >>>>> >>>>> This in turn points to a proposed solution here: >>>>> >>>>> >>>>> http://chimera.labs.oreilly.com/books/1234000000726/apa.html#_literal_geom_erl_literal_9 >>>>> >>>>> Upon reading this solution, I became so enraged [1] that I rewrote the >>>>> module and want to make a number of points. >>>>> >>>>> Here's my rewrite: >>>>> >>>>> https://gist.github.com/gar1t/7bb80d728f804554ac32 >>>>> >>>>> The tone of my points below is *very preachy* which is going to annoy >>>>> some people here. I apologize in advance - but hey, ranters gotta >>>>> rant. >>>>> >>>>> # Clarity of "what's going on" >>>>> >>>>> Compare my area/0 to the original area/0. Which is easier to see >>>>> "what's going on"? I'm not boasting here but rather making the most >>>>> important point I can about programming: take the time to be clear in >>>>> your intent! If you're actually clear - in your brain - making the >>>>> code reflect your understanding *is not that hard*. If your code is >>>>> not clear, chances are your brain is not clear. >>>>> >>>>> Maybe the original code works, maybe it doesn't. I can't tell from >>>>> looking at that function, at all. I have to dig around various >>>>> implementation details and hold a bunch of information in my brain to >>>>> understand what the author is maybe trying to do. At some point I >>>>> can't keep it all straight and have to run the thing and observe its >>>>> behavior. *Now* I'm thinking, what happens to the pour schlep who has >>>>> to modify this code. In the real world, this causes fear, and >>>>> loathing, and tests - lots and lots of tests! >>>>> >>>>> We don't have to live this way. >>>>> >>>>> # Separation of concerns (in this case IO vs calculations) >>>>> >>>>> The original calculate/3 mixes user facing behavior (print error >>>>> messages) with a calculation. If your function returns a mishmash of >>>>> completely unrelated values (e.g. the result of io:format and also the >>>>> result of an area calculation) *it's a mess*. >>>>> >>>>> In the rewrite I've added print_area/0, which is responsible for >>>>> displaying results to the user. area/0 returns an area or raises an >>>>> exception. print_area/0 handles both the result and any error. >>>>> >>>>> # Handling invalid input >>>>> >>>>> The original thread here involves a discussion on how to handle bad >>>>> input to a function. My rewrite does one of two things on this front: >>>>> >>>>> - If input is from a user, there's an explicit exception raised on bad >>>>> input that can be used by an error handler to inform the user >>>>> >>>>> - If input is not from a user but rather internal, I don't handle bad >>>>> input at all, but let Erlang crash with a function or case clause >>>>> error >>>>> >>>>> The first case address the user experience. We could let exceptions >>>>> just propagate and upset users with arcane Erlang messages. Or we can >>>>> handle errors politely with intelligible messages. >>>>> >>>>> The original ask_erl.erl handles invalid input by passing atoms like >>>>> 'error' and 'unknown' along a call chain. This is tedious and finally >>>>> culminates in the original calculate/3 - a monster mishmash function >>>>> of error handling, IO, and calculation. >>>>> >>>>> My rewrite raises an exception for those functions that take user >>>>> provided input. I prefer exceptions in this case as they keep return >>>>> values on the happy path, which makes code easier to read. >>>>> >>>>> I don't care about handling internal errors, as long as they manifest >>>>> in an obvious way. >>>>> >>>>> # Avoid variable assignment/binding inside case expressions >>>>> >>>>> Just don't do this: >>>>> >>>>> case Shape of >>>>> rectangle -> Numbers = get_dimensions("width", "height"); >>>>> triangle -> Numbers = get_dimensions("base", "height"); >>>>> ellipse -> Numbers = get_dimensions("major axis", "minor axis") >>>>> end >>>>> >>>>> Now that you're not allowed to do that, what? Hey, a function! >>>>> >>>>> Numbers = get_dimensions(Shape) >>>>> >>>>> Every time, all the time. >>>>> >>>>> # Consider not using case expressions at all >>>>> >>>>> Think of a function as a named case expression with a well defined scope. >>>>> >>>>> You'll find that having to name the function forces you to think about >>>>> "what's going on" there. It will help your reader (often that means >>>>> you, later on) to understand your intention. >>>>> >>>>> My rewrite doesn't use a single case expression. Is it somehow worse? >>>>> It's better! >>>>> >>>>> # If it looks confusing, it's bad! >>>>> >>>>> Erlang is not C, or bash, or Perl, or Ruby. It's possible to write >>>>> really easy-to-read code in Erlang. People who complain about Erlang >>>>> syntax are probably complain about terrible code in Erlang. Terrible >>>>> code in any language is worth complaining about - but it's unrelated >>>>> to syntax. >>>>> >>>>> It's easy to spot bad code in Erlang: >>>>> >>>>> - Long functions >>>>> >>>>> - Excessive nesting (more than two levels is a train wreck, and IMO >>>>> more than one is bad) >>>>> >>>>> I hate nesting so much that I'll go to the trouble of writing >>>>> to_number/1 as a list of "try" attempts (see rewrite). Some people >>>>> call this monadic, which I like because it sounds super cool. >>>>> >>>>> - Variable assignment/binding inside case and if expressions (see above) >>>>> >>>>> - Functions that are a litany of imperative style instructions, like >>>>> this: >>>>> >>>>> get_number(Prompt) -> >>>>> Str = io:get_line("Enter " ++ Prompt ++ " > "), >>>>> {Test, _} = string:to_float(Str), >>>>> case Test of >>>>> error -> {N, _} = string:to_integer(Str); >>>>> _ -> N = Test >>>>> end, >>>>> N. >>>>> >>>>> This fails the "long functions" test - but lines per function is just >>>>> a proxy. The real problem here is that it takes too much effort to >>>>> read and understand. Really, this is an imperative pattern applied >>>>> naively to Erlang. No! >>>>> >>>>> Try this: >>>>> >>>>> number_from_user(Prompt) -> >>>>> to_positive_number(prompt_user(["Enter ", Prompt, " > "])). >>>>> >>>>> Where's the rest of the code? It's there, inside the other functions. >>>>> But *this* function doesn't make you deal with that detail because it >>>>> wants you to understand what *it* is doing. >>>>> >>>>> Okay, so I've been pretty critical here of this online training >>>>> resource, which some will consider bad form. So let's turn this into >>>>> something nice and kind! >>>>> >>>>> The subject of this email is "refactoring in anger", which turns out >>>>> to be something I routinely do with my own code. It's hard to write >>>>> the perfect code in one pass. So I tend to just "get it to work" and >>>>> then examine what seems to be working very carefully - and then change >>>>> it so that it becomes *super obvious* what's going on. This state can >>>>> take a few passes and still might have warts. Okay, no sweat - it's >>>>> just code. Nothing to get angry about. Calm down and fix it. >>>>> >>>>> Over time, when you practice this pattern of refactoring, you'll start >>>>> writing things clearly the first time. That's because you'll start >>>>> *thinking* more clearly the first time. >>>>> >>>>> Now that's positive and nice and kind right? >>>>> >>>>> Garrett >>>>> >>>>> --- >>>>> >>>>> [1] Of course I'm joking here, but only partly. The original solution >>>>> is presented to learners - and it's full of bad practices, so that >>>>> makes me cranky. I suppose it's good to have teaching material for >>>>> Erlang in any form - at least it serves as a point of discussion, even >>>>> if contentious. > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions I was the person who was looking for help because I was more then 1 week busy with this exercise. I understand the solution presented by Garret. The only things I miss are the documentation of the functions. (spec and explanations). Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From r.wobben@REDACTED Sun Aug 9 10:39:56 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Sun, 9 Aug 2015 10:39:56 +0200 Subject: [erlang-questions] Refactoring in anger (Felix Gallo) In-Reply-To: <55C70FF0.9070700@home.nl> References: <55C70FF0.9070700@home.nl> Message-ID: <55C711DC.6070601@home.nl> Op 9-8-2015 om 10:31 schreef Roelof Wobben: > Op 9-8-2015 om 8:25 schreef J David Eisenberg: >> Felix Gallo wrote: >> >>> Nevertheless, if you're going to level a thundering, public j'accuse at >>> someone who has clearly gone to great effort to provide a beginner >>> experience for erlang newbies, without (apparently) first contacting >>> him >>> privately and suggesting improvements in a constructively critical >>> manner, >>> please have the decency to run the code that you have etched into your >>> stone tablets *before* you hold them aloft and, with fiery mane >>> ablaze in >>> the evening sun, present them as the replacement for the gentleman's >>> work. >>> >>> There are many "problems" with the etudes code. I'm not sure that >>> introducing a complex exception handling workflow is one of them, to be >>> frank, pedagogically, at the moment that the student is trying to >>> understand pattern matching and function headers. Could be. But I >>> think >>> we can say it's a matter of taste. >>> >>> And that's what really rubs me the wrong way about Garrett's post. >>> Being >>> 'very preachy', even when volubly disclaimed, is still pretty >>> tasteless. >>> But being 'very preachy' and then slapping up code you haven't even run >>> once, directly in opposition to your preaching's core point: that's >>> hypocritical, and super tasteless. And I enjoy my rich dark ironic >>> comedy >>> as much as the next guy, but come on. >>> >>> F. >> Author of Etudes here. >> >> There I was at Pepe's Tacos in Las Vegas, waiting for my meal, and I >> decided >> to read the Erlang questions mail list and see what's going on. As >> the story >> unfolded, I started cackling with laughter, until I realized that half >> the people >> in the restaurant were staring at me like "What the hell is wrong >> with this >> crazy white guy laughing at his phone?" >> >> So no, I'm not even remotely offended. Especially because I write in >> the preface: >> "I was learning Erlang as I was creating the solutions to the ?tudes, >> following the philosophy that 'the first way that works is the right >> way.' >> Therefore, don?t be surprised if you see some fairly na?ve code that >> an expert >> Erlang programmer would never write." >> >> Since the book is open source, if anyone would like to add a better >> solution with >> a discussion of why it's better, I would be perfectly happy to see >> that. Modulo >> the anger, of course :) >> >>> On Sat, Aug 8, 2015 at 6:19 PM, Leandro Ostera >>> wrote: >>> >>>> Just a minor typo: Line 48 should is trying to reassign the Prompt >>>> variable. >>>> >>>> But +1 on the rest. >>>> >>>> On Sun, Aug 9, 2015 at 2:36 AM, Felix Gallo >>>> wrote: >>>> >>>>> Eshell V7.0 (abort with ^G) >>>>> 1> c(geom). >>>>> {ok,geom} >>>>> 2> c(ask_area). >>>>> {ok,ask_area} >>>>> 3> ask_area:print_area(). >>>>> R)ectangle, T)riangle, or E)llipse > T >>>>> ** exception error: no function clause matching >>>>> ask_area:error_msg({badmatch,["Enter ","base"," > "]}) >>>>> (ask_area.erl, line >>>>> 69) >>>>> in function ask_area:print_area/0 (ask_area.erl, line 9) >>>>> >>>>> >>>>> glass houses, etc. >>>>> >>>>> F. >>>>> >>>>> On Sat, Aug 8, 2015 at 3:07 PM, Garrett Smith wrote: >>>>> >>>>>> We've had an ongoing thread on how to handle some problems >>>>>> idiomatically in Erlang: >>>>>> >>>>>> http://erlang.org/pipermail/erlang-questions/2015-August/085382.html >>>>>> >>>>>> The OP's questions are coming out of an exercise here: >>>>>> >>>>>> http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 >>>>>> >>>>>> >>>>>> This in turn points to a proposed solution here: >>>>>> >>>>>> >>>>>> http://chimera.labs.oreilly.com/books/1234000000726/apa.html#_literal_geom_erl_literal_9 >>>>>> >>>>>> >>>>>> Upon reading this solution, I became so enraged [1] that I >>>>>> rewrote the >>>>>> module and want to make a number of points. >>>>>> >>>>>> Here's my rewrite: >>>>>> >>>>>> https://gist.github.com/gar1t/7bb80d728f804554ac32 >>>>>> >>>>>> The tone of my points below is *very preachy* which is going to >>>>>> annoy >>>>>> some people here. I apologize in advance - but hey, ranters gotta >>>>>> rant. >>>>>> >>>>>> # Clarity of "what's going on" >>>>>> >>>>>> Compare my area/0 to the original area/0. Which is easier to see >>>>>> "what's going on"? I'm not boasting here but rather making the most >>>>>> important point I can about programming: take the time to be >>>>>> clear in >>>>>> your intent! If you're actually clear - in your brain - making the >>>>>> code reflect your understanding *is not that hard*. If your code is >>>>>> not clear, chances are your brain is not clear. >>>>>> >>>>>> Maybe the original code works, maybe it doesn't. I can't tell from >>>>>> looking at that function, at all. I have to dig around various >>>>>> implementation details and hold a bunch of information in my >>>>>> brain to >>>>>> understand what the author is maybe trying to do. At some point I >>>>>> can't keep it all straight and have to run the thing and observe its >>>>>> behavior. *Now* I'm thinking, what happens to the pour schlep who >>>>>> has >>>>>> to modify this code. In the real world, this causes fear, and >>>>>> loathing, and tests - lots and lots of tests! >>>>>> >>>>>> We don't have to live this way. >>>>>> >>>>>> # Separation of concerns (in this case IO vs calculations) >>>>>> >>>>>> The original calculate/3 mixes user facing behavior (print error >>>>>> messages) with a calculation. If your function returns a mishmash of >>>>>> completely unrelated values (e.g. the result of io:format and >>>>>> also the >>>>>> result of an area calculation) *it's a mess*. >>>>>> >>>>>> In the rewrite I've added print_area/0, which is responsible for >>>>>> displaying results to the user. area/0 returns an area or raises an >>>>>> exception. print_area/0 handles both the result and any error. >>>>>> >>>>>> # Handling invalid input >>>>>> >>>>>> The original thread here involves a discussion on how to handle bad >>>>>> input to a function. My rewrite does one of two things on this >>>>>> front: >>>>>> >>>>>> - If input is from a user, there's an explicit exception raised >>>>>> on bad >>>>>> input that can be used by an error handler to inform the user >>>>>> >>>>>> - If input is not from a user but rather internal, I don't handle >>>>>> bad >>>>>> input at all, but let Erlang crash with a function or case clause >>>>>> error >>>>>> >>>>>> The first case address the user experience. We could let exceptions >>>>>> just propagate and upset users with arcane Erlang messages. Or we >>>>>> can >>>>>> handle errors politely with intelligible messages. >>>>>> >>>>>> The original ask_erl.erl handles invalid input by passing atoms like >>>>>> 'error' and 'unknown' along a call chain. This is tedious and >>>>>> finally >>>>>> culminates in the original calculate/3 - a monster mishmash function >>>>>> of error handling, IO, and calculation. >>>>>> >>>>>> My rewrite raises an exception for those functions that take user >>>>>> provided input. I prefer exceptions in this case as they keep return >>>>>> values on the happy path, which makes code easier to read. >>>>>> >>>>>> I don't care about handling internal errors, as long as they >>>>>> manifest >>>>>> in an obvious way. >>>>>> >>>>>> # Avoid variable assignment/binding inside case expressions >>>>>> >>>>>> Just don't do this: >>>>>> >>>>>> case Shape of >>>>>> rectangle -> Numbers = get_dimensions("width", "height"); >>>>>> triangle -> Numbers = get_dimensions("base", "height"); >>>>>> ellipse -> Numbers = get_dimensions("major axis", "minor >>>>>> axis") >>>>>> end >>>>>> >>>>>> Now that you're not allowed to do that, what? Hey, a function! >>>>>> >>>>>> Numbers = get_dimensions(Shape) >>>>>> >>>>>> Every time, all the time. >>>>>> >>>>>> # Consider not using case expressions at all >>>>>> >>>>>> Think of a function as a named case expression with a well >>>>>> defined scope. >>>>>> >>>>>> You'll find that having to name the function forces you to think >>>>>> about >>>>>> "what's going on" there. It will help your reader (often that means >>>>>> you, later on) to understand your intention. >>>>>> >>>>>> My rewrite doesn't use a single case expression. Is it somehow >>>>>> worse? >>>>>> It's better! >>>>>> >>>>>> # If it looks confusing, it's bad! >>>>>> >>>>>> Erlang is not C, or bash, or Perl, or Ruby. It's possible to write >>>>>> really easy-to-read code in Erlang. People who complain about Erlang >>>>>> syntax are probably complain about terrible code in Erlang. Terrible >>>>>> code in any language is worth complaining about - but it's unrelated >>>>>> to syntax. >>>>>> >>>>>> It's easy to spot bad code in Erlang: >>>>>> >>>>>> - Long functions >>>>>> >>>>>> - Excessive nesting (more than two levels is a train wreck, and IMO >>>>>> more than one is bad) >>>>>> >>>>>> I hate nesting so much that I'll go to the trouble of writing >>>>>> to_number/1 as a list of "try" attempts (see rewrite). Some people >>>>>> call this monadic, which I like because it sounds super cool. >>>>>> >>>>>> - Variable assignment/binding inside case and if expressions (see >>>>>> above) >>>>>> >>>>>> - Functions that are a litany of imperative style instructions, like >>>>>> this: >>>>>> >>>>>> get_number(Prompt) -> >>>>>> Str = io:get_line("Enter " ++ Prompt ++ " > "), >>>>>> {Test, _} = string:to_float(Str), >>>>>> case Test of >>>>>> error -> {N, _} = string:to_integer(Str); >>>>>> _ -> N = Test >>>>>> end, >>>>>> N. >>>>>> >>>>>> This fails the "long functions" test - but lines per function is >>>>>> just >>>>>> a proxy. The real problem here is that it takes too much effort to >>>>>> read and understand. Really, this is an imperative pattern applied >>>>>> naively to Erlang. No! >>>>>> >>>>>> Try this: >>>>>> >>>>>> number_from_user(Prompt) -> >>>>>> to_positive_number(prompt_user(["Enter ", Prompt, " > "])). >>>>>> >>>>>> Where's the rest of the code? It's there, inside the other >>>>>> functions. >>>>>> But *this* function doesn't make you deal with that detail >>>>>> because it >>>>>> wants you to understand what *it* is doing. >>>>>> >>>>>> Okay, so I've been pretty critical here of this online training >>>>>> resource, which some will consider bad form. So let's turn this into >>>>>> something nice and kind! >>>>>> >>>>>> The subject of this email is "refactoring in anger", which turns out >>>>>> to be something I routinely do with my own code. It's hard to write >>>>>> the perfect code in one pass. So I tend to just "get it to work" and >>>>>> then examine what seems to be working very carefully - and then >>>>>> change >>>>>> it so that it becomes *super obvious* what's going on. This state >>>>>> can >>>>>> take a few passes and still might have warts. Okay, no sweat - it's >>>>>> just code. Nothing to get angry about. Calm down and fix it. >>>>>> >>>>>> Over time, when you practice this pattern of refactoring, you'll >>>>>> start >>>>>> writing things clearly the first time. That's because you'll start >>>>>> *thinking* more clearly the first time. >>>>>> >>>>>> Now that's positive and nice and kind right? >>>>>> >>>>>> Garrett >>>>>> >>>>>> --- >>>>>> >>>>>> [1] Of course I'm joking here, but only partly. The original >>>>>> solution >>>>>> is presented to learners - and it's full of bad practices, so that >>>>>> makes me cranky. I suppose it's good to have teaching material for >>>>>> Erlang in any form - at least it serves as a point of discussion, >>>>>> even >>>>>> if contentious. >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > I was the person who was looking for help because I was more then 1 > week busy with this exercise. > I understand the solution presented by Garret. The only things I miss > are the documentation of the functions. (spec and explanations). > > Roelof > > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast > antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions I found two problems. one that area/0 is not found. That could be easily solved by adding area/0 to export. Second one that area/3 cannot be found. Somehow that one is not imported. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From jesper.louis.andersen@REDACTED Sun Aug 9 10:48:08 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Sun, 9 Aug 2015 10:48:08 +0200 Subject: [erlang-questions] Refactoring in anger In-Reply-To: References: Message-ID: On Sun, Aug 9, 2015 at 12:07 AM, Garrett Smith wrote: > The original calculate/3 mixes user facing behavior (print error > messages) with a calculation. If your function returns a mishmash of > completely unrelated values (e.g. the result of io:format and also the > result of an area calculation) *it's a mess*. > Another point to make could be the area/0 function: area() -> Answer = io:get_line("R)ectangle, T)riangle, or E)llipse > "), Shape = char_to_shape(hd(Answer)), case Shape of rectangle -> Numbers = get_dimensions("width", "height"); triangle -> Numbers = get_dimensions("base", "height"); ellipse -> Numbers = get_dimensions("major axis", "minor axis"); unknown -> Numbers = {error, "Unknown shape " ++ [hd(Answer)]} end, Area = calculate(Shape, element(1, Numbers), element(2, Numbers)), Area. First, projecting out of Answer with hd/1 can be solved by just pattern matching the first character out of the list. Of course, an empty list would fail here, but input parsing is hard and Barbie wants to go shopping. Second, you don't need to project out of numbers and bind it in every variant if you use the return value of the case expression to match the dimensions. Third, in addition to separating side-effects from computation, it is often smart to let errors return structural data which can be handled by a machine easily. And then provide a function which can interpret the machine-readable structure into human-readable form. Garrett omits the input that were failing. I like to keep it around in the error term[0]. Finally, it should be obvious the answer we wish to return is the area: area() -> [A | _] = io:get_line("R)ectangle, T)riangle, or E)llipse > "), {X, Y} = case char_to_shape(A) of rectangle -> get_dimensions("width", "height"); triangle -> get_dimensions("base", "height"); ellipse -> get_dimensions("major axis", "minor axis"); unknown -> exit({unknown, A}) end, calculate(Shape, X, Y). Lifting the case-expr to the top level as Garrett is doing is probably next up on the todo list. In general, Erlang likes to match data in structure rather than projecting components out of structure. I'd suggest you master both styles eventually in code, but matching can often avoid the scourge of boolean blindness in code. [0] Caveat: think about when it is being garbage collected and how large that term is. -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From tavaresbm@REDACTED Sun Aug 9 12:12:36 2015 From: tavaresbm@REDACTED (Bruno Matos Tavares) Date: Sun, 9 Aug 2015 11:12:36 +0100 Subject: [erlang-questions] Build/release 18.0 with enable-native-libs doesn't work Message-ID: Hi, I?m trying to build Erlang on Amazon Linux AMI 2015.03 (HVM) (c3.4xlarge) without success. After some research I?ve bumped into this post https://groups.google.com/forum/#!searchin/erlang-programming/enable-native-libs/erlang-programming/qFJmWtUQHuA/EBHC750-4UYJ but the recipe doesn?t work either. ./configure --prefix=/usr/local \ --disable-debug \ --enable-silent-rules \ --enable-m64-build \ --enable-threads \ --enable-smp-support \ --enable-kernel-poll \ --enable-hipe \ --enable-native-libs \ --with-ssl=/usr/bin \ --without-docs \ --without-wx \ --without-javac \ --without-odbc make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe' Makefile:72: warning: overriding recipe for target `clean' /home/ec2-user/tmp/tmp_1/otp_src_18.0/make/otp_subdir.mk:29: warning: ignoring old recipe for target `clean' === Entering application hipe make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/rtl' ERLC ../ebin/hipe_rtl.beam hipe_rtl.erl: internal error in native_compile; crash reason: undef in function hipe:compile/4 called as hipe:compile(hipe_rtl,[], <<70,79,82,49,0,0,235,184,66,69,65,77,65,116,111,109,0,0,12,228,0,0,1,36,8, 104,105,112,101,95,114,116,108,6,109,107,95,114,116,108,3,114,116,108,7,114, 116,108,95,102,117,110,10,114,116,108,95,112,97,114,97,109,115,14,114,116, 108,95,105,115,95,99,108,111,115,117,114,101,11,114,116,108,95,105,115,95, 108,101,97,102,8,114,116,108,95,99,111,100,101,15,114,116,108,95,99,111,100, 101,95,117,112,100,97,116,101,6,101,114,108,97,110,103,10,115,101,116,101, 108,101,109,101,110,116,5,101,114,114,111,114,8,114,116,108,95,100,97,116, [..] 57,201,58,201,59,201,60,201,69,201,70,201,71,201,72,201,73,201,74,201,75, 201,76,201,77,201,142,201,117,201,87,201,199,201,202,201,207,201,208,201, 211,201,213,201,214,201,215,201,217,201,218,201,219,201,227,201,228,201,225, 201,232,201,235,201,236,201,240,201,242,201,247,233,2,233,6,233,10,233,12, 233,22,233,23,233,25,233,28,233,30,41,199,0,0>>, []) in call from compile:native_compile_1/1 (compile.erl, line 1361) in call from compile:'-internal_comp/4-anonymous-1-'/2 (compile.erl, line 295) in call from compile:fold_comp/3 (compile.erl, line 321) in call from compile:internal_comp/4 (compile.erl, line 305) in call from compile:'-do_compile/2-anonymous-0-'/2 (compile.erl, line 155) make[3]: *** [../ebin/hipe_rtl.beam] Error 1 make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/rtl' make[2]: *** [opt] Error 2 make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe' make[1]: *** [opt] Error 2 make[1]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' make: *** [libs] Error 2 However when I just use ?enable-native-libs? it does ?make?. Is it something wrong with my config or some limitation on AWS Linux that I?m not aware of. Thank you, Bruno. full log (configure + make): [ec2-user@REDACTED tmp_1]$ cat output.log Ignoring the --cache-file argument since it can cause the system to be erroneously configured Disabling caching checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu checking for gcc... gcc checking for C compiler default output file name... a.out checking whether the C compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ANSI C... none needed checking for g++... g++ checking whether we are using the GNU C++ compiler... yes checking whether g++ accepts -g... yes checking for ld... ld checking for GNU make... yes (make) checking for a BSD-compatible install... /usr/bin/install -c checking whether ln -s works... yes checking for ranlib... ranlib checking ERTS version... 7.0 checking OTP release... 18 checking OTP version... 18.0 configure: creating ./config.status config.status: creating Makefile config.status: creating make/output.mk config.status: creating make/emd2exml configure: configuring in lib configure: running /bin/sh '/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/configure' --prefix=/usr/local '--prefix=/usr/local' '--disable-debug' '--enable-silent-rules' '--enable-m64-build' '--enable-threads' '--enable-smp-support' '--enable-kernel-poll' '--enable-hipe' '--enable-native-libs' '--with-ssl=/usr/bin' '--without-docs' '--without-wx' '--without-javac' '--without-odbc' --cache-file=/dev/null --srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib configure: creating ./config.status configure: configuring in snmp/. configure: running /bin/sh '/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/./configure' --prefix=/usr/local '--prefix=/usr/local' '--disable-debug' '--enable-silent-rules' '--enable-m64-build' '--enable-threads' '--enable-smp-support' '--enable-kernel-poll' '--enable-hipe' '--enable-native-libs' '--with-ssl=/usr/bin' '--without-docs' '--without-wx' '--without-javac' '--without-odbc' '--cache-file=/dev/null' '--srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' --cache-file=/dev/null --srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/. checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu checking for perl... perl configure: creating ./config.status config.status: creating mibs/Makefile configure: configuring in common_test/. configure: running /bin/sh '/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/common_test/./configure' --prefix=/usr/local '--prefix=/usr/local' '--disable-debug' '--enable-silent-rules' '--enable-m64-build' '--enable-threads' '--enable-smp-support' '--enable-kernel-poll' '--enable-hipe' '--enable-native-libs' '--with-ssl=/usr/bin' '--without-docs' '--without-wx' '--without-javac' '--without-odbc' '--cache-file=/dev/null' '--srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' --cache-file=/dev/null --srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/common_test/. checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu configure: creating ./config.status config.status: creating priv/x86_64-unknown-linux-gnu/Makefile configure: configuring in erl_interface/. configure: running /bin/sh '/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/./configure' --prefix=/usr/local '--prefix=/usr/local' '--disable-debug' '--enable-silent-rules' '--enable-m64-build' '--enable-threads' '--enable-smp-support' '--enable-kernel-poll' '--enable-hipe' '--enable-native-libs' '--with-ssl=/usr/bin' '--without-docs' '--without-wx' '--without-javac' '--without-odbc' '--cache-file=/dev/null' '--srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' --cache-file=/dev/null --srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/. checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu checking for gcc... gcc checking for C compiler default output file name... a.out checking whether the C compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ANSI C... none needed checking how to run the C preprocessor... gcc -E checking for ranlib... ranlib checking for ld.sh... no checking for ld... ld checking for egrep... grep -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for short... yes checking size of short... 2 checking for int... yes checking size of int... 4 checking for long... yes checking size of long... 8 checking for void *... yes checking size of void *... 8 checking for long long... yes checking size of long long... 8 checking for ar... ar checking for a BSD-compatible install... /usr/bin/install -c checking how to create a directory including parents... /usr/bin/install -c -d checking for gethostbyname in -lnsl... yes checking for getpeername in -lsocket... no checking for ANSI C header files... (cached) yes checking for sys/wait.h that is POSIX.1 compatible... yes checking arpa/inet.h usability... yes checking arpa/inet.h presence... yes checking for arpa/inet.h... yes checking fcntl.h usability... yes checking fcntl.h presence... yes checking for fcntl.h... yes checking limits.h usability... yes checking limits.h presence... yes checking for limits.h... yes checking malloc.h usability... yes checking malloc.h presence... yes checking for malloc.h... yes checking netdb.h usability... yes checking netdb.h presence... yes checking for netdb.h... yes checking netinet/in.h usability... yes checking netinet/in.h presence... yes checking for netinet/in.h... yes checking stddef.h usability... yes checking stddef.h presence... yes checking for stddef.h... yes checking for stdlib.h... (cached) yes checking for string.h... (cached) yes checking sys/param.h usability... yes checking sys/param.h presence... yes checking for sys/param.h... yes checking sys/socket.h usability... yes checking sys/socket.h presence... yes checking for sys/socket.h... yes checking sys/select.h usability... yes checking sys/select.h presence... yes checking for sys/select.h... yes checking sys/time.h usability... yes checking sys/time.h presence... yes checking for sys/time.h... yes checking for unistd.h... (cached) yes checking for sys/types.h... (cached) yes checking for uid_t in sys/types.h... yes checking for pid_t... yes checking for size_t... yes checking whether time.h and sys/time.h may both be included... yes checking for socklen_t usability... yes checking for working alloca.h... yes checking for alloca... yes checking whether gcc needs -traditional... no checking for working memcmp... yes checking for dup2... yes checking for gethostbyaddr... yes checking for gethostbyname... yes checking for gethostbyaddr_r... yes checking for gethostbyname_r... yes checking for gethostname... yes checking for writev... yes checking for gethrtime... no checking for gettimeofday... yes checking for inet_ntoa... yes checking for memchr... yes checking for memmove... yes checking for memset... yes checking for select... yes checking for socket... yes checking for strchr... yes checking for strerror... yes checking for strrchr... yes checking for strstr... yes checking for uname... yes checking for res_gethostbyname... no checking for res_gethostbyname in -lresolv... yes checking for clock_gettime... yes checking for mixed cygwin or msys and native VC++ environment... no checking for mixed cygwin and native MinGW environment... no checking if we mix cygwin with any native compiler... no checking if we mix msys with another native compiler... no checking for native win32 threads... no checking for pthread_create in -lpthread... yes checking for getconf... getconf checking for Native POSIX Thread Library... yes checking nptl/pthread.h usability... no checking nptl/pthread.h presence... no checking for nptl/pthread.h... no checking pthread.h usability... yes checking pthread.h presence... yes checking for pthread.h... yes checking pthread/mit/pthread.h usability... no checking pthread/mit/pthread.h presence... no checking for pthread/mit/pthread.h... no checking if we can add -Werror=return-type to WERRORFLAGS (via CFLAGS)... yes configure: creating ./config.status config.status: creating src/x86_64-unknown-linux-gnu/Makefile config.status: creating src/x86_64-unknown-linux-gnu/eidefs.mk config.status: creating src/x86_64-unknown-linux-gnu/config.h configure: configuring in gs/. configure: running /bin/sh '/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/./configure' --prefix=/usr/local '--prefix=/usr/local' '--disable-debug' '--enable-silent-rules' '--enable-m64-build' '--enable-threads' '--enable-smp-support' '--enable-kernel-poll' '--enable-hipe' '--enable-native-libs' '--with-ssl=/usr/bin' '--without-docs' '--without-wx' '--without-javac' '--without-odbc' '--cache-file=/dev/null' '--srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' --cache-file=/dev/null --srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/. checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu checking for prebuilt tcl/tk in tcl/binaries/x86_64_linux-gnu.tar.gz... not found configure: creating ./config.status config.status: creating tcl/x86_64-unknown-linux-gnu/Makefile config.status: creating tcl/win32/Makefile configure: configuring in megaco/. configure: running /bin/sh '/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/./configure' --prefix=/usr/local '--prefix=/usr/local' '--disable-debug' '--enable-silent-rules' '--enable-m64-build' '--enable-threads' '--enable-smp-support' '--enable-kernel-poll' '--enable-hipe' '--enable-native-libs' '--with-ssl=/usr/bin' '--without-docs' '--without-wx' '--without-javac' '--without-odbc' '--cache-file=/dev/null' '--srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' --cache-file=/dev/null --srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/. checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu checking for gcc... gcc checking for C compiler default output file name... a.out checking whether the C compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ANSI C... none needed checking for flex... flex checking for yywrap in -lfl... no checking for yywrap in -ll... no checking lex output file root... lex.yy checking whether yytext is a pointer... no checking for reentrant capable flex... yes checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)... yes checking for usable Dynamic Erlang Driver configuration... yes checking for perl... perl configure: creating ./config.status config.status: creating examples/meas/Makefile configure: creating ./config.status config.status: creating examples/meas/Makefile config.status: creating src/flex/x86_64-unknown-linux-gnu/Makefile configure: configuring in odbc/. configure: running /bin/sh '/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/odbc/./configure' --prefix=/usr/local '--prefix=/usr/local' '--disable-debug' '--enable-silent-rules' '--enable-m64-build' '--enable-threads' '--enable-smp-support' '--enable-kernel-poll' '--enable-hipe' '--enable-native-libs' '--with-ssl=/usr/bin' '--without-docs' '--without-wx' '--without-javac' '--without-odbc' '--cache-file=/dev/null' '--srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' --cache-file=/dev/null --srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/odbc/. checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu configure: creating ./config.status config.status: creating c_src/x86_64-unknown-linux-gnu/Makefile configure: configuring in wx/. configure: running /bin/sh '/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/wx/./configure' --prefix=/usr/local '--prefix=/usr/local' '--disable-debug' '--enable-silent-rules' '--enable-m64-build' '--enable-threads' '--enable-smp-support' '--enable-kernel-poll' '--enable-hipe' '--enable-native-libs' '--with-ssl=/usr/bin' '--without-docs' '--without-wx' '--without-javac' '--without-odbc' '--cache-file=/dev/null' '--srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' --cache-file=/dev/null --srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/wx/. checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu checking for gcc... gcc checking for C compiler default output file name... a.out checking whether the C compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ANSI C... none needed checking for g++... g++ checking whether we are using the GNU C++ compiler... yes checking whether g++ accepts -g... yes checking for ranlib... ranlib checking how to run the C preprocessor... gcc -E configure: Building for linux-gnu checking for mixed cygwin or msys and native VC++ environment... no checking for mixed cygwin and native MinGW environment... no checking if we mix cygwin with any native compiler... no checking if we mix msys with another native compiler... no checking for egrep... grep -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for void *... yes checking size of void *... 8 checking GL/gl.h usability... no checking GL/gl.h presence... no checking for GL/gl.h... no checking OpenGL/gl.h usability... no checking OpenGL/gl.h presence... no checking for OpenGL/gl.h... no configure: Checking for OpenGL headers in /usr/X11R6 checking GL/gl.h usability... no checking GL/gl.h presence... no checking for GL/gl.h... no configure: Checking for OpenGL headers in /usr/local checking GL/gl.h usability... no checking GL/gl.h presence... no checking for GL/gl.h... no configure: WARNING: No OpenGL headers found, wx will NOT be usable checking GL/glu.h usability... no checking GL/glu.h presence... no checking for GL/glu.h... no checking OpenGL/glu.h usability... no checking OpenGL/glu.h presence... no checking for OpenGL/glu.h... no configure: WARNING: No GLU headers found, wx will NOT be usable /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/wx/./configure: line 5201: wx-config: command not found checking for debug build of wxWidgets... checking for wx-config... no checking for standard build of wxWidgets... checking for wx-config... (cached) no configure: WARNING: wxWidgets must be installed on your system. Please check that wx-config is in path, the directory where wxWidgets libraries are installed (returned by 'wx-config --libs' or 'wx-config --static --libs' command) is in LD_LIBRARY_PATH or equivalent variable and wxWidgets version is 2.8.4 or above. checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)... yes checking if we can add -Werror=return-type to CXXFLAGS (via CFLAGS)... yes configure: creating x86_64-unknown-linux-gnu/config.status config.status: creating config.mk config.status: creating c_src/Makefile configure: configuring in erts configure: running /bin/sh '/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/configure' --prefix=/usr/local '--prefix=/usr/local' '--disable-debug' '--enable-silent-rules' '--enable-m64-build' '--enable-threads' '--enable-smp-support' '--enable-kernel-poll' '--enable-hipe' '--enable-native-libs' '--with-ssl=/usr/bin' '--without-docs' '--without-wx' '--without-javac' '--without-odbc' --cache-file=/dev/null --srcdir=/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu checking for gcc... gcc checking for C compiler default output file name... a.out checking whether the C compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ANSI C... none needed checking for library containing strerror... none required checking OTP release... 18 checking OTP version... 18.0 checking for gcc... (cached) gcc checking whether we are using the GNU C compiler... (cached) yes checking whether gcc accepts -g... (cached) yes checking for gcc option to accept ANSI C... (cached) none needed checking for mixed cygwin or msys and native VC++ environment... no checking for mixed cygwin and native MinGW environment... no checking if we mix cygwin with any native compiler... no checking if we mix msys with another native compiler... no checking for getconf... getconf checking for large file support CFLAGS... none checking for large file support LDFLAGS... none checking for large file support LIBS... none checking if we can add -Werror=return-type to WERRORFLAGS (via CFLAGS)... yes checking how to run the C preprocessor... gcc -E checking for egrep... grep -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for void *... yes checking size of void *... 8 checking whether compilation mode forces ARCH adjustment... no configure: Adjusting LDFLAGS to use -m64 checking if VM has to be linked with Carbon framework... no checking if we are building a halfword emulator (32bit heap on 64bit machine)... no checking how to run the C preprocessor... gcc -E checking for ranlib... ranlib checking for bison... no checking for byacc... no checking for perl5... no checking for perl... /usr/bin/perl checking whether ln -s works... yes checking for ar... ar checking for rm... /bin/rm checking for mkdir... /bin/mkdir checking for xsltproc... xsltproc checking for fop... no configure: WARNING: No 'fop' command found: going to generate placeholder PDF files checking for xmllint... xmllint checking for a BSD-compatible install... /usr/bin/install -c checking how to create a directory including parents... /usr/bin/install -c -d checking for extra flags needed to export symbols... -Wl,-export-dynamic checking for sin in -lm... yes checking for dlopen in -ldl... yes checking for main in -linet... no checking for openpty in -lutil... yes checking for native win32 threads... no checking for pthread_create in -lpthread... yes checking for getconf... (cached) getconf checking for Native POSIX Thread Library... yes checking nptl/pthread.h usability... no checking nptl/pthread.h presence... no checking for nptl/pthread.h... no checking pthread.h usability... yes checking pthread.h presence... yes checking for pthread.h... yes checking pthread/mit/pthread.h usability... no checking pthread/mit/pthread.h presence... no checking for pthread/mit/pthread.h... no checking for kstat_open in -lkstat... no checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... yes checking for clock_gettime() with high resolution monotonic clock type... CLOCK_BOOTTIME checking for clock_getres... yes checking for clock_get_attributes... no checking for gethrtime... no checking for mach clock_get_time() with monotonic clock type... no checking for clock_gettime in -lrt... yes checking if SIGUSR1 and SIGUSR2 can be used... yes checking if sigaltstack can be used... yes checking for pthread.h... (cached) yes checking for pthread/mit/pthread.h... (cached) no checking sched.h usability... yes checking sched.h presence... yes checking for sched.h... yes checking sys/time.h usability... yes checking sys/time.h presence... yes checking for sys/time.h... yes checking for pthread_spin_lock... yes checking for sched_yield... yes checking whether sched_yield() returns an int... yes checking for pthread_yield... yes checking whether pthread_yield() returns an int... yes checking for pthread_rwlock_init... yes checking for pthread_rwlockattr_setkind_np... yes checking for PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP... yes checking for pthread_attr_setguardsize... yes checking whether pthread_cond_timedwait() can use the monotonic clock CLOCK_BOOTTIME for timeout... yes checking for Linux futexes... yes checking for pthread_setname_np... linux checking for pthread_getname_np... normal checking for short... yes checking size of short... 2 checking for int... yes checking size of int... 4 checking for long... yes checking size of long... 8 checking for long long... yes checking size of long long... 8 checking for __int128_t... yes checking size of __int128_t... 16 checking for a working __sync_synchronize()... yes checking for 32-bit __sync_add_and_fetch()... yes checking for 64-bit __sync_add_and_fetch()... yes checking for 128-bit __sync_add_and_fetch()... no checking for 32-bit __sync_fetch_and_and()... yes checking for 64-bit __sync_fetch_and_and()... yes checking for 128-bit __sync_fetch_and_and()... no checking for 32-bit __sync_fetch_and_or()... yes checking for 64-bit __sync_fetch_and_or()... yes checking for 128-bit __sync_fetch_and_or()... no checking for 32-bit __sync_val_compare_and_swap()... yes checking for 64-bit __sync_val_compare_and_swap()... yes checking for 128-bit __sync_val_compare_and_swap()... no checking for 32-bit __atomic_store_n()... yes checking for 64-bit __atomic_store_n()... yes checking for 128-bit __atomic_store_n()... no checking for 32-bit __atomic_load_n()... yes checking for 64-bit __atomic_load_n()... yes checking for 128-bit __atomic_load_n()... no checking for 32-bit __atomic_add_fetch()... yes checking for 64-bit __atomic_add_fetch()... yes checking for 128-bit __atomic_add_fetch()... no checking for 32-bit __atomic_fetch_and()... yes checking for 64-bit __atomic_fetch_and()... yes checking for 128-bit __atomic_fetch_and()... no checking for 32-bit __atomic_fetch_or()... yes checking for 64-bit __atomic_fetch_or()... yes checking for 128-bit __atomic_fetch_or()... no checking for 32-bit __atomic_compare_exchange_n()... yes checking for 64-bit __atomic_compare_exchange_n()... yes checking for 128-bit __atomic_compare_exchange_n()... no checking for a usable libatomic_ops implementation... no checking whether default stack size should be modified... no checking for void *... (cached) yes checking size of void *... (cached) 8 checking for int... (cached) yes checking size of int... (cached) 4 checking for long... (cached) yes checking size of long... (cached) 8 checking for long long... (cached) yes checking size of long long... (cached) 8 checking for __int64... no checking size of __int64... 0 checking for __int128_t... (cached) yes checking size of __int128_t... (cached) 16 checking whether byte ordering is bigendian... no checking whether double word ordering is middle-endian... no checking for gcc double word cmpxchg asm support... yes checking whether an emulator with smp support should be built... yes; enabled by user checking for posix_fadvise... yes checking for closefrom... no checking linux/falloc.h usability... yes checking linux/falloc.h presence... yes checking for linux/falloc.h... yes checking whether fallocate() works... yes checking whether posix_fallocate() works... yes checking whether the emulator should use threads... yes; thread support required and therefore forced checking whether lock checking should be enabled... no checking whether lock counters should be enabled... no checking whether dirty schedulers should be enabled... no checking whether dlopen() needs to be called before first call to dlerror()... no checking whether the child waiter thread should be enabled... yes on SMP build, but not on non-SMP build checking for kstat_open in -lkstat... (cached) no checking for tgetent in -ltinfo... yes checking for wcwidth... yes checking for zlib 1.2.5 or higher... yes checking for connect... yes checking for gethostbyname... yes checking for gethostbyname_r... yes checking for working posix_openpt implementation... yes checking if netdb.h requires netinet/in.h to be previously included... yes checking for socklen_t... yes checking for h_errno declaration in netdb.h... yes checking for dirent.h that defines DIR... yes checking for library containing opendir... none required checking for ANSI C header files... (cached) yes checking for sys/wait.h that is POSIX.1 compatible... yes checking whether time.h and sys/time.h may both be included... yes checking fcntl.h usability... yes checking fcntl.h presence... yes checking for fcntl.h... yes checking limits.h usability... yes checking limits.h presence... yes checking for limits.h... yes checking for unistd.h... (cached) yes checking syslog.h usability... yes checking syslog.h presence... yes checking for syslog.h... yes checking dlfcn.h usability... yes checking dlfcn.h presence... yes checking for dlfcn.h... yes checking ieeefp.h usability... no checking ieeefp.h presence... no checking for ieeefp.h... no checking for sys/types.h... (cached) yes checking sys/stropts.h usability... no checking sys/stropts.h presence... no checking for sys/stropts.h... no checking sys/sysctl.h usability... yes checking sys/sysctl.h presence... yes checking for sys/sysctl.h... yes checking sys/ioctl.h usability... yes checking sys/ioctl.h presence... yes checking for sys/ioctl.h... yes checking for sys/time.h... (cached) yes checking sys/uio.h usability... yes checking sys/uio.h presence... yes checking for sys/uio.h... yes checking sys/socket.h usability... yes checking sys/socket.h presence... yes checking for sys/socket.h... yes checking sys/sockio.h usability... no checking sys/sockio.h presence... no checking for sys/sockio.h... no checking sys/socketio.h usability... no checking sys/socketio.h presence... no checking for sys/socketio.h... no checking net/errno.h usability... no checking net/errno.h presence... no checking for net/errno.h... no checking malloc.h usability... yes checking malloc.h presence... yes checking for malloc.h... yes checking arpa/nameser.h usability... yes checking arpa/nameser.h presence... yes checking for arpa/nameser.h... yes checking libdlpi.h usability... no checking libdlpi.h presence... no checking for libdlpi.h... no checking pty.h usability... yes checking pty.h presence... yes checking for pty.h... yes checking util.h usability... no checking util.h presence... no checking for util.h... no checking utmp.h usability... yes checking utmp.h presence... yes checking for utmp.h... yes checking langinfo.h usability... yes checking langinfo.h presence... yes checking for langinfo.h... yes checking poll.h usability... yes checking poll.h presence... yes checking for poll.h... yes checking sdkddkver.h usability... no checking sdkddkver.h presence... no checking for sdkddkver.h... no checking for struct ifreq.ifr_hwaddr... yes checking for struct ifreq.ifr_enaddr... no checking for dlpi_open in -ldlpi... no configure: Extending the search to include /lib checking for dlpi_open in -ldlpi... no checking sys/resource.h usability... yes checking sys/resource.h presence... yes checking for sys/resource.h... yes checking whether getrlimit is declared... yes checking whether setrlimit is declared... yes checking whether RLIMIT_STACK is declared... yes checking sys/event.h usability... no checking sys/event.h presence... no checking for sys/event.h... no checking sys/epoll.h usability... yes checking sys/epoll.h presence... yes checking for sys/epoll.h... yes checking sys/devpoll.h usability... no checking sys/devpoll.h presence... no checking for sys/devpoll.h... no checking sys/timerfd.h usability... yes checking sys/timerfd.h presence... yes checking for sys/timerfd.h... yes checking for netinet/sctp.h... no checking for sched.h... (cached) yes checking setns.h usability... no checking setns.h presence... no checking for setns.h... no checking for setns... yes checking valgrind/valgrind.h usability... no checking valgrind/valgrind.h presence... no checking for valgrind/valgrind.h... no checking for SO_BSDCOMPAT declaration... yes checking for INADDR_LOOPBACK in netinet/in.h... yes checking for sys_errlist declaration in stdio.h or errno.h... yes checking if windows.h includes winsock2.h... no checking for an ANSI C-conforming const... yes checking return type of signal handlers... void checking for off_t... yes checking for pid_t... yes checking for size_t... yes checking whether struct tm is in sys/time.h or time.h... time.h checking whether struct sockaddr has sa_len field... no checking for struct exception (and matherr function)... yes checking for char... yes checking size of char... 1 checking for short... (cached) yes checking size of short... (cached) 2 checking for int... (cached) yes checking size of int... (cached) 4 checking for long... (cached) yes checking size of long... (cached) 8 checking for void *... (cached) yes checking size of void *... (cached) 8 checking for long long... (cached) yes checking size of long long... (cached) 8 checking for size_t... (cached) yes checking size of size_t... 8 checking for off_t... (cached) yes checking size of off_t... 8 checking for time_t... yes checking size of time_t... 8 checking if we should add -fno-tree-copyrename to CFLAGS for computed gotos to work properly... yes checking for broken gcc-4.3.0 compiler... no checking whether byte ordering is bigendian... (cached) no checking whether double word ordering is middle-endian... (cached) no checking for fdatasync... yes checking for library containing fdatasync... none required checking for sendfile... yes checking windows.h usability... no checking windows.h presence... no checking for windows.h... no checking winsock2.h usability... no checking winsock2.h presence... no checking for winsock2.h... no checking for ws2tcpip.h... no checking for getaddrinfo... yes checking whether getaddrinfo accepts enough flags... yes checking for getnameinfo... yes checking for getipnodebyname... no checking for getipnodebyaddr... no checking for gethostbyname2... yes checking for ieee_handler... no checking for fpsetmask... no checking for finite... yes checking for isnan... yes checking for isinf... yes checking for res_gethostbyname... no checking for dlopen... yes checking for pread... yes checking for pwrite... yes checking for memmove... yes checking for strerror... yes checking for strerror_r... yes checking for strncasecmp... yes checking for gethrtime... (cached) no checking for localtime_r... yes checking for gmtime_r... yes checking for inet_pton... yes checking for memcpy... yes checking for mallopt... yes checking for sbrk... yes checking for _sbrk... no checking for __sbrk... yes checking for brk... yes checking for _brk... no checking for __brk... no checking for flockfile... yes checking for fstat... yes checking for strlcpy... no checking for strlcat... no checking for setsid... yes checking for posix2time... no checking for time2posix... no checking for setlocale... yes checking for nl_langinfo... yes checking for poll... yes checking for mlockall... yes checking for ppoll... yes checking for isfinite... yes checking for posix_memalign... yes checking for writev... yes checking for mmap... yes checking for mremap... yes checking whether posix2time is declared... no checking whether time2posix is declared... no checking if vfork is known to hang multithreaded applications... no checking for unistd.h... (cached) yes checking vfork.h usability... no checking vfork.h presence... no checking for vfork.h... no checking for fork... yes checking for vfork... yes checking for working fork... yes checking for working vfork... (cached) yes checking for vprintf... yes checking for _doprnt... no checking for conflicting declaration of fread... yes checking for putc_unlocked... yes checking for fwrite_unlocked... yes checking for openpty... yes checking net/if_dl.h usability... no checking net/if_dl.h presence... no checking for net/if_dl.h... no checking ifaddrs.h usability... yes checking ifaddrs.h presence... yes checking for ifaddrs.h... yes checking netpacket/packet.h usability... yes checking netpacket/packet.h presence... yes checking for netpacket/packet.h... yes checking for getifaddrs... yes checking whether in6addr_any is declared... yes checking whether in6addr_loopback is declared... yes checking whether IN6ADDR_ANY_INIT is declared... yes checking whether IN6ADDR_LOOPBACK_INIT is declared... yes checking whether IPV6_V6ONLY is declared... yes checking for sched_getaffinity/sched_setaffinity... yes checking for pset functionality... no checking for processor_bind functionality... no checking for cpuset_getaffinity/cpuset_setaffinity... no checking for 'end' symbol... yes checking for '_end' symbol... yes checking if __after_morecore_hook can track malloc()s core memory use... no checking types of sbrk()s return value and argument... void *,intptr_t checking types of brk()s return value and argument... int,void * checking if sbrk()/brk() wrappers can track malloc()s core memory use... no checking for IP version 6 support... yes checking for multicast support... yes checking for clock_gettime() with wall clock type... CLOCK_REALTIME checking for clock_getres... (cached) yes checking for clock_get_attributes... (cached) no checking for gettimeofday... yes checking for mach clock_get_time() with wall clock type... no checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... (cached) yes checking for clock_gettime() with monotonic clock type... CLOCK_BOOTTIME checking for clock_getres... (cached) yes checking for clock_get_attributes... (cached) no checking for gethrtime... (cached) no checking for mach clock_get_time() with monotonic clock type... (cached) no checking for clock_gettime in -lrt... (cached) yes checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... (cached) yes checking for clock_gettime() with high resolution monotonic clock type... (cached) CLOCK_BOOTTIME checking for clock_getres... (cached) yes checking for clock_get_attributes... (cached) no checking for gethrtime... (cached) no checking for mach clock_get_time() with monotonic clock type... (cached) no checking for clock_gettime in -lrt... (cached) yes checking if gethrvtime works and how to use it... not working checking if clock_gettime can be used to get process CPU time... yes checking for m4... m4 configure: Floating point exceptions disabled by default on Linux checking whether to redefine FD_SETSIZE... no checking for working poll()... yes checking whether epoll is level triggered... yes checking whether kernel poll support should be enabled... yes; epoll checking whether putenv() stores a copy of the key-value pair... no checking for ld... gcc checking for compiler flags for loadable drivers... -m64 -g -O2 -I/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/x86_64-unknown-linux-gnu -fno-tree-copyrename -D_GNU_SOURCE -fPIC checking for linker for loadable drivers... gcc checking for linker flags for loadable drivers... -m64 -shared -Wl,-Bsymbolic checking for 'runtime library path' linker flag... -Wl,-R checking for a compiler that handles jumptables... gcc checking for static ZLib to be used by SSL in standard locations... no checking for OpenSSL kerberos 5 support... yes checking for krb5.h in standard locations... found in /usr/include checking for ssl runtime library path to use... /usr/bin/lib:/usr/local/lib64:/usr/sfw/lib64:/usr/lib64:/opt/local/lib64:/usr/pkg/lib64:/usr/local/openssl/lib64:/usr/lib/openssl/lib64:/usr/openssl/lib64:/usr/local/ssl/lib64:/usr/lib/ssl/lib64:/usr/ssl/lib64://lib64:/usr/local/lib:/usr/sfw/lib:/usr/lib:/opt/local/lib:/usr/pkg/lib:/usr/local/openssl/lib:/usr/lib/openssl/lib:/usr/openssl/lib:/usr/local/ssl/lib:/usr/lib/ssl/lib:/usr/ssl/lib://lib checking for kstat_open in -lkstat... (cached) no checking for kvm_open in -lkvm... no checking for c++... c++ checking for log2... yes configure: creating ./config.status config.status: creating emulator/x86_64-unknown-linux-gnu/Makefile config.status: creating epmd/src/x86_64-unknown-linux-gnu/Makefile config.status: creating etc/common/x86_64-unknown-linux-gnu/Makefile config.status: creating include/internal/x86_64-unknown-linux-gnu/ethread.mk config.status: creating include/internal/x86_64-unknown-linux-gnu/erts_internal.mk config.status: creating lib_src/x86_64-unknown-linux-gnu/Makefile config.status: creating Makefile config.status: creating ../make/x86_64-unknown-linux-gnu/otp.mk config.status: creating ../make/x86_64-unknown-linux-gnu/otp_ded.mk config.status: creating ../make/x86_64-unknown-linux-gnu/ose_lm.mk config.status: creating ../lib/ic/c_src/x86_64-unknown-linux-gnu/Makefile config.status: creating ../lib/os_mon/c_src/x86_64-unknown-linux-gnu/Makefile config.status: creating ../lib/crypto/c_src/x86_64-unknown-linux-gnu/Makefile config.status: creating ../lib/orber/c_src/x86_64-unknown-linux-gnu/Makefile config.status: creating ../lib/runtime_tools/c_src/x86_64-unknown-linux-gnu/Makefile config.status: creating ../lib/tools/c_src/x86_64-unknown-linux-gnu/Makefile config.status: creating x86_64-unknown-linux-gnu/config.h config.status: creating include/internal/x86_64-unknown-linux-gnu/ethread_header_config.h config.status: creating include/x86_64-unknown-linux-gnu/erl_int_sizes_config.h config.status: creating include/x86_64-unknown-linux-gnu/erl_native_features_config.h ********************************************************************* ********************** APPLICATIONS DISABLED ********************** ********************************************************************* jinterface : Java compiler disabled by user odbc : odbc disabled by user. odbc : User gave --without-odbc option wx : User gave --without-wx option ********************************************************************* ********************************************************************* ********************** APPLICATIONS INFORMATION ******************* ********************************************************************* wx : wxWidgets not found, wx will NOT be usable ********************************************************************* ********************************************************************* ********************** DOCUMENTATION INFORMATION ****************** ********************************************************************* documentation : fop is missing. Using fakefop to generate placeholder PDF files. ********************************************************************* MAKE depend make[1]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' MAKE generate make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' GEN x86_64-unknown-linux-gnu/gen_git_version.mk M4 x86_64-unknown-linux-gnu/opt/plain/hipe_x86_asm.h M4 x86_64-unknown-linux-gnu/opt/plain/hipe_amd64_asm.h M4 x86_64-unknown-linux-gnu/opt/plain/hipe_sparc_asm.h M4 x86_64-unknown-linux-gnu/opt/plain/hipe_ppc_asm.h M4 x86_64-unknown-linux-gnu/opt/plain/hipe_arm_asm.h GEN x86_64-unknown-linux-gnu/opt/plain/erl_alloc_types.h GEN x86_64-unknown-linux-gnu/opt/plain/OPCODES-GENERATED GEN x86_64-unknown-linux-gnu/TABLES-GENERATED CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_mkliterals.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/hipe_mkliterals GEN x86_64-unknown-linux-gnu/opt/plain/hipe_literals.h GEN x86_64-unknown-linux-gnu/erl_version.h GEN x86_64-unknown-linux-gnu/opt/plain/driver_tab.c GEN x86_64-unknown-linux-gnu/opt/plain/GENERATED GEN x86_64-unknown-linux-gnu/preload.c make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' make[1]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' make[1]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' MAKE depend make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' GEN x86_64-unknown-linux-gnu/opt/plain/depend.mk make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' MAKE depend make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' GEN obj/x86_64-unknown-linux-gnu/opt/depend.mk make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' make[4]: Nothing to be done for `depend'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' GEN x86_64-unknown-linux-gnu/gen_git_version.mk make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' GEN x86_64-unknown-linux-gnu/gen_git_version.mk make[2]: Nothing to be done for `depend'. make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' make[1]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' make[1]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' MAKE depend make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' make[2]: Nothing to be done for `depend'. make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' make[1]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' MAKE emulator make[1]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' MAKE opt make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' M4 x86_64-unknown-linux-gnu/opt/smp/hipe_x86_asm.h M4 x86_64-unknown-linux-gnu/opt/smp/hipe_amd64_asm.h M4 x86_64-unknown-linux-gnu/opt/smp/hipe_sparc_asm.h M4 x86_64-unknown-linux-gnu/opt/smp/hipe_ppc_asm.h M4 x86_64-unknown-linux-gnu/opt/smp/hipe_arm_asm.h GEN x86_64-unknown-linux-gnu/opt/smp/erl_alloc_types.h GEN x86_64-unknown-linux-gnu/opt/smp/OPCODES-GENERATED CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_mkliterals.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/hipe_mkliterals.smp GEN x86_64-unknown-linux-gnu/opt/smp/hipe_literals.h GEN x86_64-unknown-linux-gnu/opt/smp/driver_tab.c GEN x86_64-unknown-linux-gnu/opt/smp/GENERATED GEN x86_64-unknown-linux-gnu/opt/smp/depend.mk make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' MAKE depend make[5]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' make[5]: Nothing to be done for `depend'. make[5]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' GEN x86_64-unknown-linux-gnu/gen_git_version.mk make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' GEN x86_64-unknown-linux-gnu/gen_git_version.mk CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_main.o CC obj/x86_64-unknown-linux-gnu/opt/smp/preload.o EMU_CC obj/x86_64-unknown-linux-gnu/opt/smp/beam_emu.o CC obj/x86_64-unknown-linux-gnu/opt/smp/beam_opcodes.o CC obj/x86_64-unknown-linux-gnu/opt/smp/beam_load.o CC obj/x86_64-unknown-linux-gnu/opt/smp/beam_bif_load.o CC obj/x86_64-unknown-linux-gnu/opt/smp/beam_debug.o CC obj/x86_64-unknown-linux-gnu/opt/smp/beam_bp.o CC obj/x86_64-unknown-linux-gnu/opt/smp/beam_catches.o CC obj/x86_64-unknown-linux-gnu/opt/smp/code_ix.o CC obj/x86_64-unknown-linux-gnu/opt/smp/beam_ranges.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_pbifs.o CC obj/x86_64-unknown-linux-gnu/opt/smp/benchmark.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_alloc.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_mtrace.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_alloc_util.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_goodfit_alloc.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bestfit_alloc.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_afit_alloc.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_instrument.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_init.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_atom_table.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_table.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_ddll.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_guard.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_info.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_op.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_os.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_lists.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_trace.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_unique.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_wrap.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_trace.o CC obj/x86_64-unknown-linux-gnu/opt/smp/copy.o CC obj/x86_64-unknown-linux-gnu/opt/smp/utils.o CC obj/x86_64-unknown-linux-gnu/opt/smp/bif.o CC obj/x86_64-unknown-linux-gnu/opt/smp/io.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_printf_term.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_debug.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_md5.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_message.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_process.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_process_dict.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_process_lock.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_port_task.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_arith.o CC obj/x86_64-unknown-linux-gnu/opt/smp/time.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_time_sup.o CC obj/x86_64-unknown-linux-gnu/opt/smp/external.o CC obj/x86_64-unknown-linux-gnu/opt/smp/dist.o CC obj/x86_64-unknown-linux-gnu/opt/smp/binary.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_db.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_db_util.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_db_hash.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_db_tree.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_thr_progress.o CC obj/x86_64-unknown-linux-gnu/opt/smp/big.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hash.o CC obj/x86_64-unknown-linux-gnu/opt/smp/index.o CC obj/x86_64-unknown-linux-gnu/opt/smp/atom.o CC obj/x86_64-unknown-linux-gnu/opt/smp/module.o CC obj/x86_64-unknown-linux-gnu/opt/smp/export.o CC obj/x86_64-unknown-linux-gnu/opt/smp/register.o CC obj/x86_64-unknown-linux-gnu/opt/smp/break.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_async.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_lock_check.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_gc.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_lock_count.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_posix_str.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bits.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_math.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_fun.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_port.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_term.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_node_tables.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_monitors.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_process_dump.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_hl_timer.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_cpu_topology.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_drv_thread.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_chksum.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_re.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_unicode.o CC obj/x86_64-unknown-linux-gnu/opt/smp/packet_parser.o CC obj/x86_64-unknown-linux-gnu/opt/smp/safe_hash.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_zlib.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_nif.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_bif_binary.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_ao_firstfit_alloc.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_thr_queue.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_sched_spec_pre_alloc.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_ptab.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_map.o CC obj/x86_64-unknown-linux-gnu/opt/smp/sys.o CC obj/x86_64-unknown-linux-gnu/opt/smp/driver_tab.o CC obj/x86_64-unknown-linux-gnu/opt/smp/unix_efile.o CC obj/x86_64-unknown-linux-gnu/opt/smp/gzio.o CC obj/x86_64-unknown-linux-gnu/opt/smp/elib_memmove.o CC obj/x86_64-unknown-linux-gnu/opt/smp/sys_float.o CC obj/x86_64-unknown-linux-gnu/opt/smp/sys_time.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_poll.kp.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_check_io.kp.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_poll.nkp.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_check_io.nkp.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_mseg.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_mmap.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_unix_sys_ddll.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_mtrace_sys_wrap.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_sys_common_misc.o CC obj/x86_64-unknown-linux-gnu/opt/smp/erl_os_monotonic_time_extender.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_bif0.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_bif1.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_bif2.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_debug.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_gc.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_mode_switch.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_native_bif.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_stack.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_amd64.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_amd64_glue.o M4 x86_64-unknown-linux-gnu/opt/smp/hipe_amd64_bifs.S CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_amd64_bifs.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_x86_signal.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_x86_stack.o CC obj/x86_64-unknown-linux-gnu/opt/smp/hipe_bif64.o CC obj/x86_64-unknown-linux-gnu/opt/smp/efile_drv.o CC obj/x86_64-unknown-linux-gnu/opt/smp/inet_drv.o CC obj/x86_64-unknown-linux-gnu/opt/smp/zlib_drv.o CC obj/x86_64-unknown-linux-gnu/opt/smp/ram_file_drv.o CC obj/x86_64-unknown-linux-gnu/opt/smp/ttsl_drv.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_latin_1_table.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_compile.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_config.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_dfa_exec.o GEN /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/pcre_exec_loop_break_cases.inc CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_exec.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_fullinfo.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_get.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_globals.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_maketables.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_newline.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_ord2utf8.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_refcount.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_study.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_tables.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_valid_utf8.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_version.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_byte_order.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_jit_compile.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_string_utils.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_ucd.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/pcre_xclass.o AR /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator/pcre/obj/x86_64-unknown-linux-gnu/opt/libepcre.a make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' MAKE opt make[5]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' CC obj/x86_64-unknown-linux-gnu/opt/r/ethr_aux.o CC obj/x86_64-unknown-linux-gnu/opt/r/ethr_atomics.o CC obj/x86_64-unknown-linux-gnu/opt/r/ethr_mutex.o CC obj/x86_64-unknown-linux-gnu/opt/r/ethr_cbf.o CC obj/x86_64-unknown-linux-gnu/opt/r/ethread.o CC obj/x86_64-unknown-linux-gnu/opt/r/ethr_event.o AR ../lib/internal/x86_64-unknown-linux-gnu/libethread.a RANLIB ../lib/internal/x86_64-unknown-linux-gnu/libethread.a CC obj/x86_64-unknown-linux-gnu/opt/erl_memory_trace_parser.o AR ../lib/x86_64-unknown-linux-gnu/liberts.a RANLIB ../lib/x86_64-unknown-linux-gnu/liberts.a CC obj/x86_64-unknown-linux-gnu/opt/r/erl_memory_trace_parser.o AR ../lib/x86_64-unknown-linux-gnu/liberts_r.a RANLIB ../lib/x86_64-unknown-linux-gnu/liberts_r.a CC obj/x86_64-unknown-linux-gnu/opt/erl_printf_format.o CC obj/x86_64-unknown-linux-gnu/opt/erl_printf.o CC obj/x86_64-unknown-linux-gnu/opt/erl_misc_utils.o AR ../lib/internal/x86_64-unknown-linux-gnu/liberts_internal.a RANLIB ../lib/internal/x86_64-unknown-linux-gnu/liberts_internal.a CC obj/x86_64-unknown-linux-gnu/opt/r/erl_printf_format.o CC obj/x86_64-unknown-linux-gnu/opt/r/erl_printf.o CC obj/x86_64-unknown-linux-gnu/opt/r/erl_misc_utils.o AR ../lib/internal/x86_64-unknown-linux-gnu/liberts_internal_r.a RANLIB ../lib/internal/x86_64-unknown-linux-gnu/liberts_internal_r.a GEN obj/x86_64-unknown-linux-gnu/opt/MADE make[5]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/beam.smp LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/child_setup make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' MAKE opt make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' GEN x86_64-unknown-linux-gnu/gen_git_version.mk CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_main.o CC obj/x86_64-unknown-linux-gnu/opt/plain/preload.o EMU_CC obj/x86_64-unknown-linux-gnu/opt/plain/beam_emu.o CC obj/x86_64-unknown-linux-gnu/opt/plain/beam_opcodes.o CC obj/x86_64-unknown-linux-gnu/opt/plain/beam_load.o CC obj/x86_64-unknown-linux-gnu/opt/plain/beam_bif_load.o CC obj/x86_64-unknown-linux-gnu/opt/plain/beam_debug.o CC obj/x86_64-unknown-linux-gnu/opt/plain/beam_bp.o CC obj/x86_64-unknown-linux-gnu/opt/plain/beam_catches.o CC obj/x86_64-unknown-linux-gnu/opt/plain/code_ix.o CC obj/x86_64-unknown-linux-gnu/opt/plain/beam_ranges.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_pbifs.o CC obj/x86_64-unknown-linux-gnu/opt/plain/benchmark.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_alloc.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_mtrace.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_alloc_util.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_goodfit_alloc.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bestfit_alloc.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_afit_alloc.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_instrument.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_init.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_atom_table.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_table.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_ddll.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_guard.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_info.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_op.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_os.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_lists.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_trace.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_unique.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_wrap.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_trace.o CC obj/x86_64-unknown-linux-gnu/opt/plain/copy.o CC obj/x86_64-unknown-linux-gnu/opt/plain/utils.o CC obj/x86_64-unknown-linux-gnu/opt/plain/bif.o CC obj/x86_64-unknown-linux-gnu/opt/plain/io.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_printf_term.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_debug.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_md5.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_message.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_process.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_process_dict.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_process_lock.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_port_task.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_arith.o CC obj/x86_64-unknown-linux-gnu/opt/plain/time.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_time_sup.o CC obj/x86_64-unknown-linux-gnu/opt/plain/external.o CC obj/x86_64-unknown-linux-gnu/opt/plain/dist.o CC obj/x86_64-unknown-linux-gnu/opt/plain/binary.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_db.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_db_util.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_db_hash.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_db_tree.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_thr_progress.o CC obj/x86_64-unknown-linux-gnu/opt/plain/big.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hash.o CC obj/x86_64-unknown-linux-gnu/opt/plain/index.o CC obj/x86_64-unknown-linux-gnu/opt/plain/atom.o CC obj/x86_64-unknown-linux-gnu/opt/plain/module.o CC obj/x86_64-unknown-linux-gnu/opt/plain/export.o CC obj/x86_64-unknown-linux-gnu/opt/plain/register.o CC obj/x86_64-unknown-linux-gnu/opt/plain/break.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_async.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_lock_check.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_gc.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_lock_count.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_posix_str.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bits.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_math.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_fun.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_port.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_term.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_node_tables.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_monitors.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_process_dump.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_hl_timer.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_cpu_topology.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_drv_thread.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_chksum.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_re.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_unicode.o CC obj/x86_64-unknown-linux-gnu/opt/plain/packet_parser.o CC obj/x86_64-unknown-linux-gnu/opt/plain/safe_hash.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_zlib.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_nif.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_bif_binary.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_ao_firstfit_alloc.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_thr_queue.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_sched_spec_pre_alloc.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_ptab.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_map.o CC obj/x86_64-unknown-linux-gnu/opt/plain/sys.o CC obj/x86_64-unknown-linux-gnu/opt/plain/driver_tab.o CC obj/x86_64-unknown-linux-gnu/opt/plain/unix_efile.o CC obj/x86_64-unknown-linux-gnu/opt/plain/gzio.o CC obj/x86_64-unknown-linux-gnu/opt/plain/elib_memmove.o CC obj/x86_64-unknown-linux-gnu/opt/plain/sys_float.o CC obj/x86_64-unknown-linux-gnu/opt/plain/sys_time.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_poll.kp.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_check_io.kp.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_poll.nkp.o sys/common/erl_poll.c: In function ?check_fd_events?: sys/common/erl_poll.c:2252:6: warning: variable ?timeout? set but not used [-Wunused-but-set-variable] int timeout; ^ CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_check_io.nkp.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_mseg.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_mmap.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_unix_sys_ddll.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_mtrace_sys_wrap.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_sys_common_misc.o CC obj/x86_64-unknown-linux-gnu/opt/plain/erl_os_monotonic_time_extender.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_bif0.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_bif1.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_bif2.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_debug.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_gc.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_mode_switch.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_native_bif.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_stack.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_amd64.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_amd64_glue.o M4 x86_64-unknown-linux-gnu/opt/plain/hipe_amd64_bifs.S CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_amd64_bifs.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_x86_signal.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_x86_stack.o CC obj/x86_64-unknown-linux-gnu/opt/plain/hipe_bif64.o CC obj/x86_64-unknown-linux-gnu/opt/plain/efile_drv.o CC obj/x86_64-unknown-linux-gnu/opt/plain/inet_drv.o CC obj/x86_64-unknown-linux-gnu/opt/plain/zlib_drv.o CC obj/x86_64-unknown-linux-gnu/opt/plain/ram_file_drv.o CC obj/x86_64-unknown-linux-gnu/opt/plain/ttsl_drv.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/emulator' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/etc' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/etc/common' MAKE opt make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/etc/common' CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/inet_gethost.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/inet_gethost CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/heart.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/heart CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/erlexec.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/erlexec CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/typer.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/typer CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/dialyzer.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/dialyzer CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/erlc.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/erlc CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/escript.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/escript CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/ct_run.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/ct_run CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/safe_string.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/run_erl.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/run_erl_common.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/run_erl CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/to_erl.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/to_erl_common.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/to_erl CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/dyn_erl.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/dyn_erl VSN Install VSN erl.src make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/etc/common' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/etc/common' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/etc/unix' GEN etp-commands make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/etc/unix' make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/etc' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/epmd' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/epmd/src' MAKE opt make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/epmd/src' CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/epmd.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/epmd_cli.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/obj/x86_64-unknown-linux-gnu/epmd_srv.o LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/bin/x86_64-unknown-linux-gnu/epmd make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/epmd/src' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/epmd/src' make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/epmd' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' MAKE opt make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' make[3]: Nothing to be done for `all'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/lib_src' (cd preloaded/src && make ../ebin/erts.app) make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/preloaded/src' VSN ../ebin/erts.app make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts/preloaded/src' make[1]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/erts' MAKE secondary_bootstrap_build make[1]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe' Makefile:72: warning: overriding recipe for target `clean' /home/ec2-user/tmp/tmp_1/otp_src_18.0/make/otp_subdir.mk:29: warning: ignoring old recipe for target `clean' === Entering application hipe make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/rtl' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/main' VSN hipe.hrl make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/main' ERLC ../boot_ebin/hipe_rtl.beam ERLC ../boot_ebin/hipe_rtl_cfg.beam ERLC ../boot_ebin/hipe_rtl_liveness.beam GEN hipe_literals.hrl ERLC ../boot_ebin/hipe_icode2rtl.beam ERLC ../boot_ebin/hipe_rtl_mk_switch.beam ERLC ../boot_ebin/hipe_rtl_primops.beam ERLC ../boot_ebin/hipe_rtl_varmap.beam ERLC ../boot_ebin/hipe_rtl_exceptions.beam ERLC ../boot_ebin/hipe_rtl_binary_match.beam ERLC ../boot_ebin/hipe_rtl_binary_construct.beam ERLC ../boot_ebin/hipe_rtl_arith_32.beam ERLC ../boot_ebin/hipe_rtl_arith_64.beam ERLC ../boot_ebin/hipe_rtl_ssa.beam ERLC ../boot_ebin/hipe_rtl_ssa_const_prop.beam ERLC ../boot_ebin/hipe_rtl_cleanup_const.beam ERLC ../boot_ebin/hipe_rtl_symbolic.beam ERLC ../boot_ebin/hipe_rtl_lcm.beam ERLC ../boot_ebin/hipe_rtl_ssapre.beam ERLC ../boot_ebin/hipe_rtl_binary.beam ERLC ../boot_ebin/hipe_rtl_ssa_avail_expr.beam ERLC ../boot_ebin/hipe_rtl_arch.beam ERLC ../boot_ebin/hipe_tagscheme.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/rtl' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/misc' ERLC ../boot_ebin/hipe_consttab.beam ERLC ../boot_ebin/hipe_gensym.beam ERLC ../boot_ebin/hipe_data_pp.beam ERLC ../boot_ebin/hipe_pack_constants.beam ERLC ../boot_ebin/hipe_sdi.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/misc' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/main' ERLC ../boot_ebin/hipe_main.beam ERLC ../boot_ebin/hipe.beam ../../compiler/src/beam_disasm.hrl:35: Warning: record function has field(s) without type information VSN ../boot_ebin/hipe.app VSN ../boot_ebin/hipe.appup make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/main' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/cerl' ERLC ../boot_ebin/cerl_cconv.beam ERLC ../boot_ebin/cerl_closurean.beam ERLC ../boot_ebin/cerl_hipeify.beam ERLC ../boot_ebin/cerl_lib.beam ERLC ../boot_ebin/cerl_messagean.beam ERLC ../boot_ebin/cerl_pmatch.beam ERLC ../boot_ebin/cerl_prettypr.beam ERLC ../boot_ebin/cerl_to_icode.beam ERLC ../boot_ebin/cerl_typean.beam ERLC ../boot_ebin/erl_bif_types.beam ERLC ../boot_ebin/erl_types.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/cerl' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/icode' ERLC ../boot_ebin/hipe_beam_to_icode.beam ERLC ../boot_ebin/hipe_icode.beam ERLC ../boot_ebin/hipe_icode_bincomp.beam ERLC ../boot_ebin/hipe_icode_callgraph.beam ERLC ../boot_ebin/hipe_icode_cfg.beam ../flow/cfg.inc:178: Warning: missing specification for function params/1 ../flow/cfg.inc:182: Warning: missing specification for function params_update/2 ERLC ../boot_ebin/hipe_icode_coordinator.beam ERLC ../boot_ebin/hipe_icode_fp.beam ERLC ../boot_ebin/hipe_icode_exceptions.beam ERLC ../boot_ebin/hipe_icode_inline_bifs.beam ERLC ../boot_ebin/hipe_icode_instruction_counter.beam ERLC ../boot_ebin/hipe_icode_liveness.beam ERLC ../boot_ebin/hipe_icode_pp.beam ERLC ../boot_ebin/hipe_icode_primops.beam ERLC ../boot_ebin/hipe_icode_range.beam ERLC ../boot_ebin/hipe_icode_split_arith.beam ERLC ../boot_ebin/hipe_icode_ssa.beam ERLC ../boot_ebin/hipe_icode_ssa_const_prop.beam ERLC ../boot_ebin/hipe_icode_ssa_copy_prop.beam ERLC ../boot_ebin/hipe_icode_ssa_struct_reuse.beam ERLC ../boot_ebin/hipe_icode_type.beam ERLC ../boot_ebin/hipe_icode_heap_test.beam ERLC ../boot_ebin/hipe_icode_ebb.beam ERLC ../boot_ebin/hipe_icode_mulret.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/icode' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/flow' ERLC ../boot_ebin/hipe_bb.beam ERLC ../boot_ebin/hipe_dominators.beam ERLC ../boot_ebin/hipe_gen_cfg.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/flow' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/util' ERLC ../boot_ebin/hipe_timing.beam ERLC ../boot_ebin/hipe_dot.beam ERLC ../boot_ebin/hipe_digraph.beam ERLC ../boot_ebin/hipe_vectors.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/util' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/doc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/regalloc' ERLC ../boot_ebin/hipe_ig.beam ERLC ../boot_ebin/hipe_ig_moves.beam ERLC ../boot_ebin/hipe_moves.beam ERLC ../boot_ebin/hipe_node_sets.beam ERLC ../boot_ebin/hipe_spillcost.beam ERLC ../boot_ebin/hipe_reg_worklists.beam ERLC ../boot_ebin/hipe_adj_list.beam ERLC ../boot_ebin/hipe_temp_map.beam ERLC ../boot_ebin/hipe_optimistic_regalloc.beam ERLC ../boot_ebin/hipe_coalescing_regalloc.beam ERLC ../boot_ebin/hipe_graph_coloring_regalloc.beam ERLC ../boot_ebin/hipe_regalloc_loop.beam ERLC ../boot_ebin/hipe_ls_regalloc.beam ERLC ../boot_ebin/hipe_ppc_specific.beam ERLC ../boot_ebin/hipe_ppc_specific_fp.beam ERLC ../boot_ebin/hipe_sparc_specific.beam ERLC ../boot_ebin/hipe_sparc_specific_fp.beam ERLC ../boot_ebin/hipe_arm_specific.beam ERLC ../boot_ebin/hipe_x86_specific.beam ERLC ../boot_ebin/hipe_x86_specific_x87.beam ERLC ../boot_ebin/hipe_amd64_specific.beam ERLC ../boot_ebin/hipe_amd64_specific_sse2.beam ERLC ../boot_ebin/hipe_amd64_specific_x87.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/regalloc' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/sparc' ERLC ../boot_ebin/hipe_rtl_to_sparc.beam ERLC ../boot_ebin/hipe_sparc.beam ERLC ../boot_ebin/hipe_sparc_assemble.beam ERLC ../boot_ebin/hipe_sparc_cfg.beam ERLC ../boot_ebin/hipe_sparc_defuse.beam ERLC ../boot_ebin/hipe_sparc_encode.beam ERLC ../boot_ebin/hipe_sparc_finalise.beam ERLC ../boot_ebin/hipe_sparc_frame.beam ERLC ../boot_ebin/hipe_sparc_liveness_all.beam ERLC ../boot_ebin/hipe_sparc_liveness_fpr.beam ERLC ../boot_ebin/hipe_sparc_liveness_gpr.beam ERLC ../boot_ebin/hipe_sparc_main.beam ERLC ../boot_ebin/hipe_sparc_pp.beam ERLC ../boot_ebin/hipe_sparc_ra.beam ERLC ../boot_ebin/hipe_sparc_ra_finalise.beam ERLC ../boot_ebin/hipe_sparc_ra_ls.beam ERLC ../boot_ebin/hipe_sparc_ra_naive.beam ERLC ../boot_ebin/hipe_sparc_ra_postconditions.beam ERLC ../boot_ebin/hipe_sparc_ra_postconditions_fp.beam ERLC ../boot_ebin/hipe_sparc_registers.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/sparc' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/ppc' ERLC ../boot_ebin/hipe_ppc.beam ERLC ../boot_ebin/hipe_ppc_assemble.beam ERLC ../boot_ebin/hipe_ppc_cfg.beam ERLC ../boot_ebin/hipe_ppc_defuse.beam ERLC ../boot_ebin/hipe_ppc_encode.beam ERLC ../boot_ebin/hipe_ppc_finalise.beam ERLC ../boot_ebin/hipe_ppc_frame.beam ERLC ../boot_ebin/hipe_ppc_liveness_all.beam ERLC ../boot_ebin/hipe_ppc_liveness_fpr.beam ERLC ../boot_ebin/hipe_ppc_liveness_gpr.beam ERLC ../boot_ebin/hipe_ppc_main.beam ERLC ../boot_ebin/hipe_ppc_pp.beam ERLC ../boot_ebin/hipe_ppc_ra.beam ERLC ../boot_ebin/hipe_ppc_ra_finalise.beam ERLC ../boot_ebin/hipe_ppc_ra_ls.beam ERLC ../boot_ebin/hipe_ppc_ra_naive.beam ERLC ../boot_ebin/hipe_ppc_ra_postconditions.beam ERLC ../boot_ebin/hipe_ppc_ra_postconditions_fp.beam ERLC ../boot_ebin/hipe_ppc_registers.beam ERLC ../boot_ebin/hipe_rtl_to_ppc.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/ppc' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/x86' ERLC ../boot_ebin/hipe_rtl_to_x86.beam ERLC ../boot_ebin/hipe_x86.beam ERLC ../boot_ebin/hipe_x86_assemble.beam ERLC ../boot_ebin/hipe_x86_cfg.beam ERLC ../boot_ebin/hipe_x86_defuse.beam ERLC ../boot_ebin/hipe_x86_encode.beam ERLC ../boot_ebin/hipe_x86_frame.beam ERLC ../boot_ebin/hipe_x86_liveness.beam ERLC ../boot_ebin/hipe_x86_main.beam ERLC ../boot_ebin/hipe_x86_postpass.beam ERLC ../boot_ebin/hipe_x86_pp.beam ERLC ../boot_ebin/hipe_x86_ra.beam ERLC ../boot_ebin/hipe_x86_ra_finalise.beam ERLC ../boot_ebin/hipe_x86_ra_ls.beam ERLC ../boot_ebin/hipe_x86_ra_naive.beam ERLC ../boot_ebin/hipe_x86_ra_postconditions.beam ERLC ../boot_ebin/hipe_x86_ra_x87_ls.beam ERLC ../boot_ebin/hipe_x86_registers.beam ERLC ../boot_ebin/hipe_x86_spill_restore.beam ERLC ../boot_ebin/hipe_x86_x87.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/x86' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/amd64' ERLC ../boot_ebin/hipe_amd64_assemble.beam ERLC ../boot_ebin/hipe_amd64_defuse.beam ERLC ../boot_ebin/hipe_amd64_encode.beam ERLC ../boot_ebin/hipe_amd64_frame.beam ERLC ../boot_ebin/hipe_amd64_liveness.beam ERLC ../boot_ebin/hipe_amd64_main.beam ERLC ../boot_ebin/hipe_amd64_pp.beam ERLC ../boot_ebin/hipe_amd64_ra.beam ERLC ../boot_ebin/hipe_amd64_ra_finalise.beam ERLC ../boot_ebin/hipe_amd64_ra_ls.beam ERLC ../boot_ebin/hipe_amd64_ra_naive.beam ERLC ../boot_ebin/hipe_amd64_ra_postconditions.beam ERLC ../boot_ebin/hipe_amd64_ra_sse2_postconditions.beam ERLC ../boot_ebin/hipe_amd64_ra_x87_ls.beam ERLC ../boot_ebin/hipe_amd64_registers.beam ERLC ../boot_ebin/hipe_amd64_spill_restore.beam ERLC ../boot_ebin/hipe_amd64_x87.beam ERLC ../boot_ebin/hipe_rtl_to_amd64.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/amd64' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/arm' ERLC ../boot_ebin/hipe_arm.beam ERLC ../boot_ebin/hipe_arm_assemble.beam ERLC ../boot_ebin/hipe_arm_cfg.beam ERLC ../boot_ebin/hipe_arm_defuse.beam ERLC ../boot_ebin/hipe_arm_encode.beam ERLC ../boot_ebin/hipe_arm_finalise.beam ERLC ../boot_ebin/hipe_arm_frame.beam ERLC ../boot_ebin/hipe_arm_liveness_gpr.beam ERLC ../boot_ebin/hipe_arm_main.beam ERLC ../boot_ebin/hipe_arm_pp.beam ERLC ../boot_ebin/hipe_arm_ra.beam ERLC ../boot_ebin/hipe_arm_ra_finalise.beam ERLC ../boot_ebin/hipe_arm_ra_ls.beam ERLC ../boot_ebin/hipe_arm_ra_naive.beam ERLC ../boot_ebin/hipe_arm_ra_postconditions.beam ERLC ../boot_ebin/hipe_arm_registers.beam ERLC ../boot_ebin/hipe_rtl_to_arm.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/arm' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/opt' ERLC ../boot_ebin/hipe_spillmin.beam ERLC ../boot_ebin/hipe_spillmin_color.beam ERLC ../boot_ebin/hipe_spillmin_scan.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/opt' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/tools' ERLC ../boot_ebin/hipe_profile.beam ERLC ../boot_ebin/hipe_jit.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/tools' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/llvm' ERLC ../boot_ebin/hipe_rtl_to_llvm.beam ERLC ../boot_ebin/hipe_llvm.beam ERLC ../boot_ebin/elf_format.beam ERLC ../boot_ebin/hipe_llvm_main.beam ERLC ../boot_ebin/hipe_llvm_merge.beam ERLC ../boot_ebin/hipe_llvm_liveness.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/llvm' === Leaving application hipe make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/parsetools' === Entering application parsetools make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/parsetools/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/parsetools/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/parsetools/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/parsetools/doc/src' === Leaving application parsetools make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/parsetools' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/asn1/src' make[2]: Nothing to be done for `opt'. make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/asn1/src' make[1]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' MAKE secondary_bootstrap_copy cp: cannot stat ?lib/hipe/ebin/*.beam?: No such file or directory MAKE tertiary_bootstrap_build make[1]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp' === Entering application snmp make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/compile' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/compile' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/mibs' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/mibs' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/compile' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/compile' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/app' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/app' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/misc' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/misc' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/agent' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/agent' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/manager' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/manager' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/examples' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/examples/ex1' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/examples/ex1' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/examples/ex2' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/examples/ex2' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/examples' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/priv/conf' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/priv/conf/agent' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/priv/conf/agent' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/priv/conf/manager' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/priv/conf/manager' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/priv/conf' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/doc/src' === Leaving application snmp make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl' === Entering application sasl make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl/doc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl/examples/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl/examples/src' === Leaving application sasl make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl' === Skipping subdir jinterface, reason: Java compiler disabled by user === make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic' === Entering application ic make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/c_src' MAKE opt make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/c_src' CC ../priv/obj/x86_64-unknown-linux-gnu/ic.o CC ../priv/obj/x86_64-unknown-linux-gnu/ic_tmo.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_version.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_long.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_ulong.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_double.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_char.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_string.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_atom.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_pid.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_port.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_ref.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_term.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_tuple_header.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_list_header.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_longlong.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_ulonglong.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_wchar.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_encode_wstring.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_decode_longlong.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_decode_ulonglong.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_decode_wchar.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_decode_wstring.o CC ../priv/obj/x86_64-unknown-linux-gnu/oe_ei_code_erlang_binary.o AR ../priv/lib/x86_64-unknown-linux-gnu/libic.a RANLIB ../priv/lib/x86_64-unknown-linux-gnu/libic.a make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/c_src' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/c_src' === Skipping subdir java_src, reason: Java compiler disabled by user === make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/doc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/examples/pre_post_condition' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/examples/pre_post_condition' === Leaving application ic make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools' === Entering application syntax_tools make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools/examples' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools/examples' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools/doc/src' === Leaving application syntax_tools make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools' make[1]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' MAKE tertiary_bootstrap_copy MAKE libs make[1]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/stdlib' === Entering application stdlib make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/stdlib/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/stdlib/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/stdlib/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/stdlib/doc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/stdlib/examples' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/stdlib/examples' === Leaving application stdlib make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/stdlib' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl' === Entering application sasl make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl/doc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl/examples/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl/examples/src' === Leaving application sasl make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/sasl' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/kernel' === Entering application kernel make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/kernel/src' ERLC ../ebin/hipe_unified_loader.beam make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/kernel/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/kernel/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/kernel/doc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/kernel/examples' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/kernel/examples' === Leaving application kernel make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/kernel' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/compiler' === Entering application compiler make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/compiler/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/compiler/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/compiler/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/compiler/doc/src' === Leaving application compiler make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/compiler' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools' === Entering application tools make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/c_src' MAKE opt make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/c_src' CC ../obj/x86_64-unknown-linux-gnu/opt/emem/erl_memory.o CC ../obj/x86_64-unknown-linux-gnu/opt/emem/erl_memory_trace_block_table.o LD ../bin/x86_64-unknown-linux-gnu/emem make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/c_src' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/c_src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/doc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/examples' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/examples' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/priv' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/priv' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/emacs' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools/emacs' === Leaving application tools make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/tools' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/test_server' === Entering application test_server make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/test_server/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/test_server/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/test_server/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/test_server/doc/src' === Leaving application test_server make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/test_server' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/common_test' === Entering application common_test make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/common_test/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/common_test/doc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/common_test/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/common_test/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/common_test/priv' MAKE opt make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/common_test/priv' make[4]: Nothing to be done for `debug'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/common_test/priv' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/common_test/priv' === Leaving application common_test make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/common_test' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/runtime_tools' === Entering application runtime_tools make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/runtime_tools/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/runtime_tools/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/runtime_tools/c_src' MAKE opt make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/runtime_tools/c_src' CC ../priv/obj/x86_64-unknown-linux-gnu/trace_ip_drv.o LD ../priv/lib/x86_64-unknown-linux-gnu/trace_ip_drv.so CC ../priv/obj/x86_64-unknown-linux-gnu/trace_file_drv.o LD ../priv/lib/x86_64-unknown-linux-gnu/trace_file_drv.so CC ../priv/obj/x86_64-unknown-linux-gnu/dyntrace.o LD ../priv/lib/x86_64-unknown-linux-gnu/dyntrace.so make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/runtime_tools/c_src' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/runtime_tools/c_src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/runtime_tools/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/runtime_tools/doc/src' === Leaving application runtime_tools make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/runtime_tools' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets' === Entering application inets make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src/inets_app' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src/inets_app' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src/http_lib' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src/http_lib' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src/http_client' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src/http_client' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src/http_server' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src/http_server' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src/ftp' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src/ftp' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src/tftp' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src/tftp' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/examples' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/examples/server_root' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/examples/server_root' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/examples/httpd_load_test' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/examples/httpd_load_test' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/examples' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/priv' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/priv' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets/doc/src' === Leaving application inets make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/inets' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/parsetools' === Entering application parsetools make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/parsetools/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/parsetools/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/parsetools/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/parsetools/doc/src' === Leaving application parsetools make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/parsetools' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/xmerl' === Entering application xmerl make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/xmerl/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/xmerl/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/xmerl/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/xmerl/doc/src' === Leaving application xmerl make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/xmerl' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/edoc' === Entering application edoc make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/edoc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/edoc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/edoc/include' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/edoc/include' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/edoc/priv' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/edoc/priv' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/edoc/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/edoc/doc/src' === Leaving application edoc make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/edoc' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen' === Entering application erl_docgen make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/bin' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/bin' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/css' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/css' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/dtd' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/dtd' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/dtd_html_entities' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/dtd_html_entities' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/dtd_man_entities' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/dtd_man_entities' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/images' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/images' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/js/flipmenu' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/js/flipmenu' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/xsl' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv/xsl' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/priv' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen/doc/src' === Leaving application erl_docgen make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_docgen' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp' === Entering application snmp make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/compile' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/compile' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/mibs' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/mibs' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/compile' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/compile' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/app' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/app' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/misc' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/misc' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/agent' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/agent' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/manager' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src/manager' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/examples' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/examples/ex1' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/examples/ex1' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/examples/ex2' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/examples/ex2' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/examples' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/priv/conf' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/priv/conf/agent' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/priv/conf/agent' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/priv/conf/manager' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/priv/conf/manager' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/priv/conf' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp/doc/src' === Leaving application snmp make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/snmp' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/otp_mibs' === Entering application otp_mibs make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/otp_mibs/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/otp_mibs/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/otp_mibs/mibs' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/otp_mibs/mibs' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/otp_mibs/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/otp_mibs/doc/src' === Leaving application otp_mibs make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/otp_mibs' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface' === Entering application erl_interface make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/src' MAKE opt make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/src' CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/ei_connect.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/ei_resolve.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/eirecv.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/send.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/send_exit.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/send_reg.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_atom.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_big.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_bignum.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_binary.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_boolean.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_char.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_double.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_fun.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_intlist.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_list_header.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_long.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_pid.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_port.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_ref.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_skip.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_string.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_trace.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_tuple_header.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_ulong.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_version.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_longlong.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_ulonglong.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_atom.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_big.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_bignum.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_binary.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_boolean.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_char.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_double.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_fun.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_list_header.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_long.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_pid.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_port.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_ref.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_string.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_trace.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_tuple_header.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_ulong.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_version.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_longlong.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_ulonglong.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/epmd_port.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/epmd_publish.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/epmd_unpublish.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/ei_decode_term.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/ei_format.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/ei_locking.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/ei_malloc.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/ei_portio.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/ei_printterm.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/ei_pthreads.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/ei_trace.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/ei_x_encode.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/eimd5.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/get_type.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/show_msg.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/ei_compat.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/hash_dohash.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/hash_foreach.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/hash_freetab.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/hash_insert.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/hash_isprime.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/hash_lookup.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/hash_newtab.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/hash_remove.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/hash_resize.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/hash_rlookup.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_close.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_delete.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_dirty.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_dump.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_free.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_get.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_getf.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_geti.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_getp.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_gets.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_make.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_open.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_purge.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_resize.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_restore.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_set.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_setf.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_seti.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_setp.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_sets.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_stat.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/reg_tabstat.o AR /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj/x86_64-unknown-linux-gnu/libei_st.a RANLIB /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj/x86_64-unknown-linux-gnu/libei_st.a CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/decode_term.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/encode_term.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/erl_connect.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/erl_error.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/erl_eterm.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/erl_fix_alloc.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/erl_format.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/erl_malloc.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/erl_marshal.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/erl_resolve.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/erl_timeout.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/global_names.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/global_register.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/global_unregister.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.st/x86_64-unknown-linux-gnu/global_whereis.o AR /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj/x86_64-unknown-linux-gnu/liberl_interface_st.a RANLIB /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj/x86_64-unknown-linux-gnu/liberl_interface_st.a CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/ei_connect.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/ei_resolve.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/eirecv.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/send.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/send_exit.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/send_reg.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_atom.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_big.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_bignum.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_binary.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_boolean.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_char.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_double.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_fun.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_intlist.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_list_header.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_long.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_pid.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_port.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_ref.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_skip.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_string.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_trace.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_tuple_header.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_ulong.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_version.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_longlong.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_ulonglong.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_atom.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_big.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_bignum.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_binary.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_boolean.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_char.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_double.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_fun.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_list_header.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_long.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_pid.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_port.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_ref.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_string.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_trace.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_tuple_header.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_ulong.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_version.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_longlong.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_ulonglong.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/epmd_port.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/epmd_publish.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/epmd_unpublish.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/ei_decode_term.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/ei_format.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/ei_locking.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/ei_malloc.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/ei_portio.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/ei_printterm.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/ei_pthreads.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/ei_trace.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/ei_x_encode.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/eimd5.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/get_type.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/show_msg.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/ei_compat.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/hash_dohash.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/hash_foreach.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/hash_freetab.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/hash_insert.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/hash_isprime.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/hash_lookup.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/hash_newtab.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/hash_remove.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/hash_resize.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/hash_rlookup.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_close.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_delete.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_dirty.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_dump.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_free.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_get.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_getf.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_geti.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_getp.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_gets.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_make.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_open.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_purge.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_resize.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_restore.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_set.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_setf.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_seti.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_setp.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_sets.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_stat.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/reg_tabstat.o AR /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj/x86_64-unknown-linux-gnu/libei.a RANLIB /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj/x86_64-unknown-linux-gnu/libei.a CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/decode_term.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/encode_term.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/erl_connect.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/erl_error.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/erl_eterm.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/erl_fix_alloc.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/erl_format.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/erl_malloc.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/erl_marshal.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/erl_resolve.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/erl_timeout.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/global_names.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/global_register.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/global_unregister.o CC /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj.mt/x86_64-unknown-linux-gnu/global_whereis.o AR /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj/x86_64-unknown-linux-gnu/liberl_interface.a RANLIB /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/obj/x86_64-unknown-linux-gnu/liberl_interface.a LD /home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/bin/x86_64-unknown-linux-gnu/erl_call make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/src' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface/doc/src' === Leaving application erl_interface make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/erl_interface' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/asn1' === Entering application asn1 make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/asn1/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/asn1/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/asn1/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/asn1/doc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/asn1/c_src' CC ../priv/obj/x86_64-unknown-linux-gnu/asn1_erl_nif.o LD ../priv/lib/x86_64-unknown-linux-gnu/asn1rt_nif.so make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/asn1/c_src' === Leaving application asn1 make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/asn1' === Skipping subdir jinterface, reason: Java compiler disabled by user === make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/debugger' === Entering application debugger make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/debugger/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/debugger/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/debugger/priv' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/debugger/priv' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/debugger/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/debugger/doc/src' === Leaving application debugger make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/debugger' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/reltool' === Entering application reltool make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/reltool/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/reltool/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/reltool/examples' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/reltool/examples' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/reltool/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/reltool/doc/src' === Leaving application reltool make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/reltool' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs' === Entering application gs make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/tcl' MAKE opt make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/tcl' make[4]: Nothing to be done for `debug'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/tcl' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/tcl' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/contribs' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/contribs/bonk' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/contribs/bonk' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/contribs/cols' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/contribs/cols' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/contribs/mandel' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/contribs/mandel' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/contribs/othello' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/contribs/othello' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/contribs' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/examples' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/examples' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs/doc/src' === Leaving application gs make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/gs' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic' === Entering application ic make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/c_src' MAKE opt make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/c_src' make[4]: Nothing to be done for `debug'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/c_src' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/c_src' === Skipping subdir java_src, reason: Java compiler disabled by user === make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/doc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/examples/pre_post_condition' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic/examples/pre_post_condition' === Leaving application ic make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ic' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/mnesia' === Entering application mnesia make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/mnesia/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/mnesia/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/mnesia/include' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/mnesia/include' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/mnesia/examples' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/mnesia/examples' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/mnesia/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/mnesia/doc/src' === Leaving application mnesia make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/mnesia' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/crypto' === Entering application crypto make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/crypto/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/crypto/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/crypto/c_src' MAKE opt make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/crypto/c_src' CC ../priv/obj/x86_64-unknown-linux-gnu/crypto.o LD ../priv/lib/x86_64-unknown-linux-gnu/crypto.so CC ../priv/obj/x86_64-unknown-linux-gnu/crypto_callback.o /usr/bin/install -c -d ../priv/lib/x86_64-unknown-linux-gnu gcc -m64 -shared -Wl,-Bsymbolic -o ../priv/lib/x86_64-unknown-linux-gnu/crypto_callback.so ../priv/obj/x86_64-unknown-linux-gnu/crypto_callback.o make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/crypto/c_src' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/crypto/c_src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/crypto/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/crypto/doc/src' === Leaving application crypto make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/crypto' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber' === Entering application orber make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/COSS/CosNaming' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/COSS/CosNaming' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/java_src' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/java_src/Orber' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/java_src/Orber' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/java_src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/c_src' MAKE opt make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/c_src' mkdir -p ../priv/obj/x86_64-unknown-linux-gnu make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/c_src' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/c_src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/examples' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/examples/Stack' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/examples/Stack' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/examples' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/doc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/priv' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber/priv' === Leaving application orber make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/orber' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/os_mon' === Entering application os_mon make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/os_mon/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/os_mon/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/os_mon/c_src' MAKE opt make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/os_mon/c_src' CC ../priv/obj/x86_64-unknown-linux-gnu/memsup.o LD ../priv/bin/x86_64-unknown-linux-gnu/memsup CC ../priv/obj/x86_64-unknown-linux-gnu/cpu_sup.o LD ../priv/bin/x86_64-unknown-linux-gnu/cpu_sup make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/os_mon/c_src' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/os_mon/c_src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/os_mon/mibs' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/os_mon/mibs' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/os_mon/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/os_mon/doc/src' === Leaving application os_mon make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/os_mon' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools' === Entering application syntax_tools make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools/examples' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools/examples' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools/doc/src' === Leaving application syntax_tools make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/syntax_tools' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/public_key' === Entering application public_key make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/public_key/asn1' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/public_key/asn1' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/public_key/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/public_key/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/public_key/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/public_key/doc/src' === Leaving application public_key make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/public_key' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssl' === Entering application ssl make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssl/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssl/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssl/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssl/doc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssl/examples/certs' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssl/examples/certs' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssl/examples/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssl/examples/src' === Leaving application ssl make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssl' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/observer' === Entering application observer make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/observer/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/observer/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/observer/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/observer/doc/src' === Leaving application observer make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/observer' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/diameter' === Entering application diameter make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/diameter/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/diameter/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/diameter/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/diameter/doc/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/diameter/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/diameter/doc/src' === Leaving application diameter make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/diameter' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosTransactions' === Entering application cosTransactions make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosTransactions/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosTransactions/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosTransactions/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosTransactions/doc/src' === Leaving application cosTransactions make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosTransactions' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosEvent' === Entering application cosEvent make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosEvent/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosEvent/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosEvent/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosEvent/doc/src' === Leaving application cosEvent make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosEvent' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosTime' === Entering application cosTime make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosTime/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosTime/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosTime/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosTime/doc/src' === Leaving application cosTime make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosTime' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosNotification' === Entering application cosNotification make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosNotification/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosNotification/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosNotification/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosNotification/doc/src' === Leaving application cosNotification make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosNotification' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosProperty' === Entering application cosProperty make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosProperty/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosProperty/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosProperty/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosProperty/doc/src' === Leaving application cosProperty make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosProperty' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosFileTransfer' === Entering application cosFileTransfer make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosFileTransfer/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosFileTransfer/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosFileTransfer/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosFileTransfer/doc/src' === Leaving application cosFileTransfer make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosFileTransfer' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosEventDomain' === Entering application cosEventDomain make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosEventDomain/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosEventDomain/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosEventDomain/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosEventDomain/doc/src' === Leaving application cosEventDomain make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/cosEventDomain' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/et' === Entering application et make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/et/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/et/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/et/examples' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/et/examples' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/et/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/et/doc/src' === Leaving application et make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/et' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco' === Entering application megaco make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/app' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/app' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/engine' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/engine' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/text' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/text' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/flex' MAKE opt make[5]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/flex' ERLC ../../ebin/megaco_flex_scanner.beam ERLC ../../ebin/megaco_flex_scanner_handler.beam GEN megaco_flex_scanner_drv.flex LEX megaco_flex_scanner_drv.c GEN megaco_flex_scanner_drv_mt.flex LEX megaco_flex_scanner_drv_mt.c CC ../../priv/obj/x86_64-unknown-linux-gnu/megaco_flex_scanner_drv.o LD ../../priv/lib/x86_64-unknown-linux-gnu/megaco_flex_scanner_drv.so CC ../../priv/obj/x86_64-unknown-linux-gnu/megaco_flex_scanner_drv_mt.o LD ../../priv/lib/x86_64-unknown-linux-gnu/megaco_flex_scanner_drv_mt.so make[5]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/flex' make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/flex' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/binary' GEN prebuild.skip make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/binary' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/tcp' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/tcp' make[4]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/udp' make[4]: Nothing to be done for `opt'. make[4]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src/udp' make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/examples/simple' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/examples/simple' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/examples/meas' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/examples/meas' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco/doc/src' === Leaving application megaco make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/megaco' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/webtool' === Entering application webtool make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/webtool/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/webtool/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/webtool/priv' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/webtool/priv' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/webtool/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/webtool/doc/src' === Leaving application webtool make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/webtool' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eunit' === Entering application eunit make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eunit/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eunit/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eunit/examples' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eunit/examples' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eunit/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eunit/doc/src' === Leaving application eunit make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eunit' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssh' === Entering application ssh make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssh/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssh/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssh/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssh/doc/src' === Leaving application ssh make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/ssh' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/typer' === Entering application typer make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/typer/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/typer/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/typer/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/typer/doc/src' === Leaving application typer make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/typer' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/percept' === Entering application percept make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/percept/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/percept/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/percept/priv' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/percept/priv' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/percept/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/percept/doc/src' === Leaving application percept make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/percept' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eldap' === Entering application eldap make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eldap/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eldap/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eldap/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eldap/doc/src' === Leaving application eldap make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/eldap' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/dialyzer' === Entering application dialyzer make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/dialyzer/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/dialyzer/src' make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/dialyzer/doc/src' make[3]: Nothing to be done for `opt'. make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/dialyzer/doc/src' === Leaving application dialyzer make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/dialyzer' make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe' Makefile:72: warning: overriding recipe for target `clean' /home/ec2-user/tmp/tmp_1/otp_src_18.0/make/otp_subdir.mk:29: warning: ignoring old recipe for target `clean' === Entering application hipe make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/rtl' ERLC ../ebin/hipe_rtl.beam hipe_rtl.erl: internal error in native_compile; crash reason: undef in function hipe:compile/4 called as hipe:compile(hipe_rtl,[], <<70,79,82,49,0,0,235,184,66,69,65,77,65,116,111,109,0,0,12,228,0,0,1,36,8, 104,105,112,101,95,114,116,108,6,109,107,95,114,116,108,3,114,116,108,7,114, 116,108,95,102,117,110,10,114,116,108,95,112,97,114,97,109,115,14,114,116, 108,95,105,115,95,99,108,111,115,117,114,101,11,114,116,108,95,105,115,95, 108,101,97,102,8,114,116,108,95,99,111,100,101,15,114,116,108,95,99,111,100, 101,95,117,112,100,97,116,101,6,101,114,108,97,110,103,10,115,101,116,101, 108,101,109,101,110,116,5,101,114,114,111,114,8,114,116,108,95,100,97,116, 97,15,114,116,108,95,108,97,98,101,108,95,114,97,110,103,101,8,114,116,108, 95,105,110,102,111,15,114,116,108,95,105,110,102,111,95,117,112,100,97,116, 101,7,109,107,95,109,111,118,101,9,114,116,108,95,102,112,114,101,103,4,116, 114,117,101,4,109,111,118,101,8,109,111,118,101,95,100,115,116,15,109,111, 118,101,95,100,115,116,95,117,112,100,97,116,101,8,109,111,118,101,95,115, 114,99,15,109,111,118,101,95,115,114,99,95,117,112,100,97,116,101,12,109, 107,95,109,117,108,116,105,109,111,118,101,6,108,101,110,103,116,104,9,109, 117,108,116,105,109,111,118,101,7,100,115,116,108,105,115,116,7,115,114,99, 108,105,115,116,4,101,120,105,116,17,109,117,108,116,105,109,111,118,101,95, 100,115,116,108,105,115,116,17,109,117,108,116,105,109,111,118,101,95,115, 114,99,108,105,115,116,6,109,107,95,112,104,105,3,112,104,105,7,112,104,105, 95,100,115,116,6,112,104,105,95,105,100,7,112,104,105,95,97,114,103,5,108, 105,115,116,115,7,107,101,121,102,105,110,100,5,102,97,108,115,101,4,112, 114,101,100,11,112,104,105,95,97,114,103,108,105,115,116,18,112,104,105,95, 97,114,103,108,105,115,116,95,117,112,100,97,116,101,6,105,115,95,112,104, 105,14,112,104,105,95,101,110,116,101,114,95,112,114,101,100,9,107,101,121, 100,101,108,101,116,101,15,112,104,105,95,114,101,109,111,118,101,95,112, 114,101,100,16,112,104,105,95,97,114,103,118,97,114,95,115,117,98,115,116, 17,112,104,105,95,114,101,100,105,114,101,99,116,95,112,114,101,100,6,109, 107,95,97,108,117,3,97,108,117,7,97,108,117,95,100,115,116,14,97,108,117,95, 100,115,116,95,117,112,100,97,116,101,8,97,108,117,95,115,114,99,49,15,97, 108,117,95,115,114,99,49,95,117,112,100,97,116,101,8,97,108,117,95,115,114, 99,50,15,97,108,117,95,115,114,99,50,95,117,112,100,97,116,101,6,97,108,117, 95,111,112,7,109,107,95,108,111,97,100,4,108,111,97,100,4,119,111,114,100,8, 117,110,115,105,103,110,101,100,8,108,111,97,100,95,100,115,116,15,108,111, 97,100,95,100,115,116,95,117,112,100,97,116,101,8,108,111,97,100,95,115,114, 99,11,108,111,97,100,95,111,102,102,115,101,116,9,108,111,97,100,95,115,105, 122,101,9,108,111,97,100,95,115,105,103,110,12,109,107,95,108,111,97,100,95, 97,116,111,109,9,108,111,97,100,95,97,116,111,109,13,108,111,97,100,95,97, 116,111,109,95,100,115,116,20,108,111,97,100,95,97,116,111,109,95,100,115, 116,95,117,112,100,97,116,101,14,108,111,97,100,95,97,116,111,109,95,97,116, 111,109,18,109,107,95,108,111,97,100,95,119,111,114,100,95,105,110,100,101, 120,15,108,111,97,100,95,119,111,114,100,95,105,110,100,101,120,19,108,111, 97,100,95,119,111,114,100,95,105,110,100,101,120,95,100,115,116,26,108,111, 97,100,95,119,111,114,100,95,105,110,100,101,120,95,100,115,116,95,117,112, 100,97,116,101,13,109,107,95,103,111,116,111,95,105,110,100,101,120,10,103, 111,116,111,95,105,110,100,101,120,16,103,111,116,111,95,105,110,100,101, 120,95,105,110,100,101,120,17,103,111,116,111,95,105,110,100,101,120,95,108, 97,98,101,108,115,15,109,107,95,108,111,97,100,95,97,100,100,114,101,115, 115,12,108,111,97,100,95,97,100,100,114,101,115,115,16,108,111,97,100,95,97, 100,100,114,101,115,115,95,100,115,116,23,108,111,97,100,95,97,100,100,114, 101,115,115,95,100,115,116,95,117,112,100,97,116,101,17,108,111,97,100,95, 97,100,100,114,101,115,115,95,97,100,100,114,24,108,111,97,100,95,97,100, 100,114,101,115,115,95,97,100,100,114,95,117,112,100,97,116,101,17,108,111, 97,100,95,97,100,100,114,101,115,115,95,116,121,112,101,8,109,107,95,115, 116,111,114,101,5,115,116,111,114,101,10,115,116,111,114,101,95,98,97,115, 101,12,115,116,111,114,101,95,111,102,102,115,101,116,9,115,116,111,114,101, 95,115,114,99,10,115,116,111,114,101,95,115,105,122,101,8,109,107,95,108,97, 98,101,108,5,108,97,98,101,108,12,109,107,95,110,101,119,95,108,97,98,101, 108,11,104,105,112,101,95,103,101,110,115,121,109,14,103,101,116,95,110,101, 120,116,95,108,97,98,101,108,10,108,97,98,101,108,95,110,97,109,101,8,105, 115,95,108,97,98,101,108,9,109,107,95,98,114,97,110,99,104,6,98,114,97,110, 99,104,11,98,114,97,110,99,104,95,115,114,99,49,11,98,114,97,110,99,104,95, 115,114,99,50,11,98,114,97,110,99,104,95,99,111,110,100,17,98,114,97,110,99, 104,95,116,114,117,101,95,108,97,98,101,108,18,98,114,97,110,99,104,95,102, 97,108,115,101,95,108,97,98,101,108,11,98,114,97,110,99,104,95,112,114,101, 100,7,109,107,95,97,108,117,98,4,97,108,117,98,8,97,108,117,98,95,100,115, 116,9,97,108,117,98,95,115,114,99,49,7,97,108,117,98,95,111,112,9,97,108, 117,98,95,115,114,99,50,9,97,108,117,98,95,99,111,110,100,15,97,108,117,98, 95,116,114,117,101,95,108,97,98,101,108,16,97,108,117,98,95,102,97,108,115, 101,95,108,97,98,101,108,9,97,108,117,98,95,112,114,101,100,9,109,107,95, 115,119,105,116,99,104,6,115,119,105,116,99,104,16,109,107,95,115,111,114, 116,101,100,95,115,119,105,116,99,104,10,115,119,105,116,99,104,95,115,114, 99,13,115,119,105,116,99,104,95,108,97,98,101,108,115,17,115,119,105,116,99, 104,95,115,111,114,116,95,111,114,100,101,114,7,109,107,95,103,111,116,111, 4,103,111,116,111,10,103,111,116,111,95,108,97,98,101,108,7,105,115,95,103, 111,116,111,7,109,107,95,99,97,108,108,6,114,101,109,111,116,101,10,110,111, 116,95,114,101,109,111,116,101,4,99,97,108,108,11,99,97,108,108,95,110,111, 114,109,97,108,18,99,97,108,108,95,110,111,114,109,97,108,95,117,112,100,97, 116,101,12,99,97,108,108,95,100,115,116,108,105,115,116,19,99,97,108,108,95, 100,115,116,108,105,115,116,95,117,112,100,97,116,101,8,99,97,108,108,95, 102,117,110,12,99,97,108,108,95,97,114,103,108,105,115,116,17,99,97,108,108, 95,99,111,110,116,105,110,117,97,116,105,111,110,9,99,97,108,108,95,102,97, 105,108,9,99,97,108,108,95,116,121,112,101,16,99,97,108,108,95,102,97,105, 108,95,117,112,100,97,116,101,7,105,115,95,99,97,108,108,13,99,97,108,108, 95,105,115,95,107,110,111,119,110,26,99,97,108,108,95,111,114,95,101,110, 116,101,114,95,102,117,110,95,105,115,95,107,110,111,119,110,7,114,116,108, 95,114,101,103,7,114,116,108,95,118,97,114,8,109,107,95,101,110,116,101,114, 5,101,110,116,101,114,9,101,110,116,101,114,95,102,117,110,13,101,110,116, 101,114,95,97,114,103,108,105,115,116,10,101,110,116,101,114,95,116,121,112, 101,14,101,110,116,101,114,95,105,115,95,107,110,111,119,110,9,109,107,95, 114,101,116,117,114,110,6,114,101,116,117,114,110,14,114,101,116,117,114, 110,95,118,97,114,108,105,115,116,9,109,107,95,103,99,116,101,115,116,7,114, 116,108,95,105,109,109,6,103,99,116,101,115,116,12,103,99,116,101,115,116, 95,119,111,114,100,115,11,109,107,95,102,105,120,110,117,109,111,112,8,102, 105,120,110,117,109,111,112,12,102,105,120,110,117,109,111,112,95,100,115, 116,19,102,105,120,110,117,109,111,112,95,100,115,116,95,117,112,100,97,116, 101,12,102,105,120,110,117,109,111,112,95,115,114,99,13,102,105,120,110,117, 109,111,112,95,116,121,112,101,10,109,107,95,99,111,109,109,101,110,116,7, 99,111,109,109,101,110,116,12,99,111,109,109,101,110,116,95,116,101,120,116, 10,105,115,95,99,111,109,109,101,110,116,8,109,107,95,102,108,111,97,100,5, 102,108,111,97,100,9,102,108,111,97,100,95,100,115,116,16,102,108,111,97, 100,95,100,115,116,95,117,112,100,97,116,101,9,102,108,111,97,100,95,115, 114,99,12,102,108,111,97,100,95,111,102,102,115,101,116,9,109,107,95,102, 115,116,111,114,101,6,102,115,116,111,114,101,11,102,115,116,111,114,101,95, 98,97,115,101,13,102,115,116,111,114,101,95,111,102,102,115,101,116,10,102, 115,116,111,114,101,95,115,114,99,5,109,107,95,102,112,13,104,105,112,101, 95,114,116,108,95,97,114,99,104,18,109,107,95,102,112,95,99,104,101,99,107, 95,114,101,115,117,108,116,2,102,112,6,102,112,95,100,115,116,13,102,112,95, 100,115,116,95,117,112,100,97,116,101,7,102,112,95,115,114,99,49,7,102,112, 95,115,114,99,50,5,102,112,95,111,112,10,109,107,95,102,112,95,117,110,111, 112,7,102,112,95,117,110,111,112,11,102,112,95,117,110,111,112,95,100,115, 116,18,102,112,95,117,110,111,112,95,100,115,116,95,117,112,100,97,116,101, 11,102,112,95,117,110,111,112,95,115,114,99,10,102,112,95,117,110,111,112, 95,111,112,8,109,107,95,102,109,111,118,101,5,102,109,111,118,101,9,102,109, 111,118,101,95,100,115,116,16,102,109,111,118,101,95,100,115,116,95,117,112, 100,97,116,101,9,102,109,111,118,101,95,115,114,99,16,102,109,111,118,101, 95,115,114,99,95,117,112,100,97,116,101,8,109,107,95,102,99,111,110,118,5, 102,99,111,110,118,9,102,99,111,110,118,95,100,115,116,16,102,99,111,110, 118,95,100,115,116,95,117,112,100,97,116,101,9,102,99,111,110,118,95,115, 114,99,6,109,107,95,114,101,103,13,109,107,95,114,101,103,95,103,99,115,97, 102,101,10,109,107,95,110,101,119,95,114,101,103,12,103,101,116,95,110,101, 120,116,95,118,97,114,17,109,107,95,110,101,119,95,114,101,103,95,103,99, 115,97,102,101,9,114,101,103,95,105,110,100,101,120,13,114,101,103,95,105, 115,95,103,99,115,97,102,101,6,105,115,95,114,101,103,6,109,107,95,118,97, 114,4,108,105,118,101,10,109,107,95,110,101,119,95,118,97,114,9,118,97,114, 95,105,110,100,101,120,12,118,97,114,95,108,105,118,101,110,101,115,115,19, 118,97,114,95,108,105,118,101,110,101,115,115,95,117,112,100,97,116,101,6, 105,115,95,118,97,114,8,109,107,95,102,112,114,101,103,12,109,107,95,110, 101,119,95,102,112,114,101,103,11,102,112,114,101,103,95,105,110,100,101, 120,8,105,115,95,102,112,114,101,103,6,109,107,95,105,109,109,9,105,109,109, 95,118,97,108,117,101,6,105,115,95,105,109,109,14,109,107,95,99,111,110,115, 116,95,108,97,98,101,108,13,114,116,108,95,99,111,110,115,116,95,108,98,108, 17,99,111,110,115,116,95,108,97,98,101,108,95,108,97,98,101,108,14,105,115, 95,99,111,110,115,116,95,108,97,98,101,108,4,117,115,101,115,4,97,114,103, 115,9,99,97,108,108,95,117,115,101,100,2,43,43,11,114,101,116,117,114,110, 95,117,115,101,100,13,116,97,105,108,99,97,108,108,95,117,115,101,100,7,100, 101,102,105,110,101,115,12,99,97,108,108,95,100,101,102,105,110,101,100,26, 114,101,109,111,118,101,95,105,109,109,115,95,97,110,100,95,99,111,110,115, 116,95,108,98,108,115,10,115,117,98,115,116,95,117,115,101,115,15,115,117, 98,115,116,95,117,115,101,115,95,108,108,118,109,7,114,101,118,101,114,115, 101,15,115,117,98,115,116,95,108,105,115,116,95,108,108,118,109,11,115,117, 98,115,116,49,95,108,108,118,109,13,115,117,98,115,116,95,100,101,102,105, 110,101,115,10,115,117,98,115,116,95,108,105,115,116,6,115,117,98,115,116, 49,7,105,115,95,115,97,102,101,11,105,115,95,115,104,105,102,116,95,111,112, 3,115,108,108,3,115,114,108,3,115,114,97,12,114,101,100,105,114,101,99,116, 95,106,109,112,2,112,112,11,115,116,97,110,100,97,114,100,95,105,111,8,112, 112,95,98,108,111,99,107,2,105,111,6,102,111,114,109,97,116,12,104,105,112, 101,95,100,97,116,97,95,112,112,9,112,112,95,105,110,115,116,114,115,2,111, 107,8,112,112,95,105,110,115,116,114,5,117,110,116,97,103,3,116,97,103,7,99, 108,111,115,117,114,101,8,99,111,110,115,116,97,110,116,5,105,110,116,51,50, 5,105,110,116,49,54,4,98,121,116,101,6,115,105,103,110,101,100,7,112,112,95, 97,114,103,115,11,112,112,95,112,104,105,95,97,114,103,115,6,112,112,95,114, 101,103,14,105,115,95,112,114,101,99,111,108,111,117,114,101,100,8,114,101, 103,95,110,97,109,101,6,112,112,95,118,97,114,4,100,101,97,100,6,112,112,95, 97,114,103,16,112,112,95,115,119,105,116,99,104,95,108,97,98,101,108,115,1, 43,11,109,111,100,117,108,101,95,105,110,102,111,15,103,101,116,95,109,111, 100,117,108,101,95,105,110,102,111,26,45,114,101,100,105,114,101,99,116,95, 106,109,112,47,51,45,108,99,36,94,48,47,49,45,48,45,15,102,117,110,99,116, 105,111,110,95,99,108,97,117,115,101,24,45,115,117,98,115,116,95,108,105, 115,116,47,50,45,108,99,36,94,48,47,49,45,48,45,18,45,97,114,103,115,47,49, 45,108,99,36,94,48,47,49,45,48,45,31,45,112,104,105,95,114,101,100,105,114, 101,99,116,95,112,114,101,100,47,51,45,108,99,36,94,48,47,49,45,48,45,30,45, 112,104,105,95,97,114,103,118,97,114,95,115,117,98,115,116,47,50,45,108,99, 36,94,48,47,49,45,48,45,67,111,100,101,0,0,92,59,0,0,0,16,0,0,0,0,0,0,0,153, 0,0,3,101,0,0,0,216,1,16,153,16,2,18,34,128,1,32,16,176,128,70,160,131,71, 50,71,3,71,19,71,35,71,51,71,67,71,83,71,99,71,115,71,2,64,131,3,19,1,48, 153,32,2,18,66,16,1,64,57,53,3,58,53,3,160,66,3,0,19,66,3,16,35,43,53,19,50, 64,35,3,19,1,80,153,48,2,18,82,16,1,96,57,85,3,58,85,3,160,66,3,0,19,66,3, 32,35,43,85,19,50,64,35,3,19,1,112,153,64,2,18,98,16,1,128,57,117,3,58,117, 3,160,66,3,0,19,66,3,48,35,43,117,19,50,64,35,3,19,1,144,153,80,2,18,114,16, 1,160,57,149,3,58,149,3,160,66,3,0,19,66,3,64,35,43,149,19,50,64,35,3,19,1, 176,153,96,2,18,130,16,1,192,57,181,3,58,181,3,160,66,3,0,19,66,3,80,35,43, 181,19,50,64,35,3,19,1,208,153,112,2,18,146,32,1,224,57,245,3,58,245,3,160, 66,3,0,35,43,245,35,50,64,19,35,64,3,19,64,97,3,153,112,78,48,0,1,240,64,71, 0,3,153,112,7,16,16,1,8,16,153,128,2,18,210,16,1,8,17,57,13,16,3,58,13,16,3, 160,66,3,0,19,66,3,96,35,43,13,16,19,50,64,35,3,19,1,8,18,153,144,2,18,226, 16,1,8,19,57,13,18,3,58,13,18,3,160,66,3,0,19,66,3,128,35,43,13,18,19,50,64, 35,3,19,1,8,20,153,160,2,18,242,16,1,8,21,57,13,20,3,58,13,20,3,160,66,3,0, 19,66,3,144,35,43,13,20,19,50,64,35,3,19,1,8,22,153,176,2,18,10,16,32,1,8, 23,57,13,24,3,58,13,24,3,160,66,3,0,35,43,13,24,35,50,64,19,35,64,3,19,64, 161,3,153,176,78,48,0,1,8,24,64,71,0,3,153,176,7,16,16,1,8,25,153,192,2,18, 10,17,32,1,8,26,12,32,32,64,19,4,64,3,20,57,13,27,3,58,13,27,3,32,66,3,0,35, 43,13,27,35,10,18,64,10,19,3,61,13,29,1,8,27,57,13,28,4,58,13,28,4,32,66,4, 0,3,43,13,28,3,10,18,64,10,19,3,61,13,29,1,8,28,16,64,0,70,48,3,71,10,20,71, 20,71,4,18,32,19,1,8,29,153,192,72,3,1,8,30,153,208,2,18,10,21,16,1,8,31,57, 13,30,3,58,13,30,3,48,66,3,0,19,66,3,16,35,43,13,30,19,10,20,64,35,3,19,1,8, 32,153,224,2,18,10,22,32,1,8,33,12,32,32,64,19,4,64,3,20,57,13,34,19,58,13, 34,19,32,66,19,0,35,43,13,34,35,10,18,64,10,19,3,61,13,36,1,8,34,57,13,35, 20,58,13,35,20,48,66,20,0,3,43,13,35,3,10,20,64,20,19,64,4,35,64,33,3,153, 224,8,48,0,32,1,8,35,64,71,16,3,153,224,7,16,16,1,8,36,153,224,72,3,1,8,37, 153,240,2,18,10,23,16,1,8,38,57,13,37,3,58,13,37,3,48,66,3,0,19,66,3,32,35, 43,13,37,19,10,20,64,35,3,19,1,8,39,153,8,16,2,18,10,24,32,1,8,40,12,32,32, 64,19,4,64,3,20,57,13,41,19,58,13,41,19,32,66,19,0,35,43,13,41,35,10,18,64, 10,19,3,61,13,43,1,8,41,57,13,42,20,58,13,42,20,48,66,20,0,3,43,13,42,3,10, 20,64,20,19,64,4,35,64,49,3,153,8,16,8,48,0,32,1,8,42,64,71,16,3,153,8,16,7, 16,16,1,8,43,153,8,16,72,3,1,8,44,153,8,17,2,18,10,25,32,1,8,45,14,32,32, 153,8,18,124,5,32,32,3,35,153,8,18,124,5,48,32,19,51,64,19,4,64,3,20,43,13, 46,35,51,16,64,0,70,48,3,71,10,27,71,20,71,4,18,32,19,1,8,46,16,224,32,70, 32,3,71,10,28,71,20,70,32,35,71,10,29,71,19,70,48,51,71,71,32,71,3,71,35,70, 48,3,71,18,71,10,25,71,51,153,8,19,7,16,48,1,8,47,153,8,20,2,18,10,31,16,1, 8,48,57,13,47,3,58,13,47,3,48,66,3,0,19,66,3,16,35,43,13,47,19,10,27,64,35, 3,19,1,8,49,153,8,21,2,18,10,32,16,1,8,50,57,13,49,3,58,13,49,3,48,66,3,0, 19,66,3,32,35,43,13,49,19,10,27,64,35,3,19,1,8,51,153,8,22,2,18,10,33,16,1, 8,52,16,80,16,70,64,19,71,10,34,71,3,71,3,71,2,64,19,3,19,1,8,53,153,8,23,2, 18,10,35,16,1,8,54,57,13,53,3,58,13,53,3,64,66,3,0,19,66,3,16,35,43,13,53, 19,10,34,64,35,3,19,1,8,55,153,8,24,2,18,10,36,16,1,8,56,57,13,55,3,58,13, 55,3,64,66,3,0,19,66,3,32,35,43,13,55,19,10,34,64,35,3,19,1,8,57,153,8,25,2, 18,10,37,32,1,8,58,57,13,61,3,58,13,61,3,64,66,3,0,35,66,3,48,51,43,13,61, 35,10,34,12,32,64,64,3,20,64,51,35,64,19,3,64,17,19,64,3,4,153,8,26,7,48,64, 57,13,59,3,58,13,60,3,32,66,3,16,3,18,32,19,1,8,59,43,13,60,3,10,40,16,176, 0,70,32,3,71,10,41,71,4,70,48,19,71,71,48,71,20,71,3,70,48,3,71,18,71,10,37, 71,19,153,8,27,7,16,48,1,8,60,153,8,26,74,3,1,8,61,16,32,16,70,16,19,71,3, 153,8,28,74,19,1,8,62,153,8,28,2,18,10,42,16,1,8,63,57,13,62,3,58,13,62,3, 64,66,3,0,19,66,3,48,35,43,13,62,19,10,34,64,35,3,19,1,8,64,153,8,29,2,18, 10,43,32,1,8,65,57,13,66,3,58,13,66,3,64,66,3,0,35,43,13,66,35,10,34,64,19, 35,64,3,19,64,65,3,153,8,29,78,48,0,1,8,66,64,71,64,3,153,8,29,7,16,16,1,8, 67,153,8,30,2,18,10,44,16,1,8,68,57,13,69,3,58,13,69,3,64,66,3,0,19,43,13, 69,19,10,34,64,10,19,3,19,1,8,69,64,10,40,3,19,1,8,70,153,8,31,2,18,10,45, 48,1,8,71,57,13,72,3,58,13,72,3,64,66,3,0,51,66,3,48,67,43,13,72,51,10,34, 12,48,80,64,3,36,64,35,4,64,67,35,64,19,3,64,17,19,64,3,20,153,8,32,7,48,80, 16,80,16,70,32,51,71,20,71,4,69,51,3,35,64,36,19,64,65,3,153,8,32,8,48,0,48, 1,8,72,16,32,16,70,16,19,71,3,153,8,28,74,19,1,8,73,153,8,33,2,18,10,47,32, 1,8,74,57,13,85,3,58,13,85,3,64,66,3,0,35,66,3,16,51,66,3,48,67,43,13,85,35, 10,34,12,48,80,17,4,64,3,20,64,67,35,64,19,3,64,17,19,64,51,36,153,8,34,7, 48,80,56,13,84,3,65,3,19,35,52,13,81,35,57,13,83,19,58,13,83,19,32,66,19,16, 20,57,13,75,36,58,13,75,36,32,66,36,0,19,43,13,75,19,10,18,64,10,19,3,61,13, 76,1,8,75,64,10,40,3,1,8,76,64,3,4,57,13,77,20,58,13,77,20,32,66,20,0,19,43, 13,77,19,10,18,64,10,19,3,61,13,78,1,8,77,64,10,40,3,1,8,78,48,13,82,4,59,4, 13,82,23,64,10,19,13,79,10,40,13,80,1,8,79,43,13,82,3,10,19,64,20,19,64,36, 3,5,32,45,114,48,1,8,80,43,13,82,3,10,40,64,20,19,64,36,3,5,32,13,26,48,1,8, 81,64,20,19,64,3,35,64,65,3,153,8,35,8,48,0,48,1,8,82,16,48,16,70,32,19,71, 4,71,3,153,8,36,74,19,1,8,83,153,8,37,72,19,1,8,84,153,8,38,74,3,1,8,85,16, 32,16,70,16,19,71,3,153,8,28,74,19,1,8,86,153,8,39,2,18,10,48,32,1,8,87,12, 16,32,64,3,4,57,13,88,3,58,13,88,3,64,66,3,0,35,66,3,48,51,43,13,88,35,10, 34,64,51,3,153,8,40,4,32,109,97,57,13,89,4,58,13,89,4,64,66,4,0,19,43,13,89, 19,10,34,64,4,19,64,3,35,64,65,3,153,8,41,8,48,0,16,1,8,88,16,32,0,70,16,19, 71,4,153,8,28,74,19,1,8,89,64,71,64,3,153,8,41,7,16,16,1,8,90,153,8,42,2,18, 10,49,48,1,8,91,13,16,80,48,70,32,51,71,19,71,35,69,51,2,19,64,3,4,57,13,92, 3,58,13,92,3,64,66,3,0,35,66,3,48,51,43,13,92,35,10,34,64,51,3,153,8,43,4, 32,109,92,57,13,93,4,58,13,93,4,64,66,4,0,19,43,13,93,19,10,34,64,4,19,64,3, 35,64,65,3,153,8,44,8,48,0,16,1,8,92,16,32,0,70,16,19,71,4,153,8,28,74,19,1, 8,93,64,71,64,3,153,8,44,7,16,16,1,8,94,153,8,45,2,18,10,50,64,1,8,95,16,96, 64,70,80,67,71,10,51,71,3,71,19,71,35,71,51,64,67,3,19,1,8,96,153,8,46,2,18, 10,52,16,1,8,97,57,13,96,3,58,13,96,3,80,66,3,0,19,66,3,16,35,43,13,96,19, 10,51,64,35,3,19,1,8,98,153,8,47,2,18,10,53,32,1,8,99,57,13,100,3,58,13,100, 3,80,66,3,0,35,43,13,100,35,10,51,64,19,35,64,3,19,64,33,3,153,8,47,78,48,0, 1,8,100,64,71,80,3,153,8,47,7,16,16,1,8,101,153,8,48,2,18,10,54,16,1,8,102, 57,13,101,3,58,13,101,3,80,66,3,0,19,66,3,32,35,43,13,101,19,10,51,64,35,3, 19,1,8,103,153,8,49,2,18,10,55,32,1,8,104,57,13,105,3,58,13,105,3,80,66,3,0, 35,43,13,105,35,10,51,64,19,35,64,3,19,64,49,3,153,8,49,78,48,0,1,8,105,64, 71,80,3,153,8,49,7,16,16,1,8,106,153,8,50,2,18,10,56,16,1,8,107,57,13,106,3, 58,13,106,3,80,66,3,0,19,66,3,64,35,43,13,106,19,10,51,64,35,3,19,1,8,108, 153,8,51,2,18,10,57,32,1,8,109,57,13,110,3,58,13,110,3,80,66,3,0,35,43,13, 110,35,10,51,64,19,35,64,3,19,64,81,3,153,8,51,78,48,0,1,8,110,64,71,80,3, 153,8,51,7,16,16,1,8,111,153,8,52,2,18,10,58,16,1,8,112,57,13,111,3,58,13, 111,3,80,66,3,0,19,66,3,48,35,43,13,111,19,10,51,64,35,3,19,1,8,113,153,8, 53,2,18,10,59,48,1,8,114,16,112,48,70,96,51,71,10,60,71,3,71,19,71,35,71,10, 61,71,10,62,64,51,3,19,1,8,115,153,8,54,2,18,10,59,80,1,8,116,16,112,80,70, 96,83,71,10,60,71,3,71,19,71,35,71,51,71,67,64,83,3,19,1,8,117,153,8,55,2, 18,10,63,16,1,8,118,57,13,117,3,58,13,117,3,96,66,3,0,19,66,3,16,35,43,13, 117,19,10,60,64,35,3,19,1,8,119,153,8,56,2,18,10,64,32,1,8,120,57,13,121,3, 58,13,121,3,96,66,3,0,35,43,13,121,35,10,60,64,19,35,64,3,19,64,33,3,153,8, 56,78,48,0,1,8,121,64,71,96,3,153,8,56,7,16,16,1,8,122,153,8,57,2,18,10,65, 16,1,8,123,57,13,122,3,58,13,122,3,96,66,3,0,19,66,3,32,35,43,13,122,19,10, 60,64,35,3,19,1,8,124,153,8,58,2,18,10,66,16,1,8,125,57,13,124,3,58,13,124, 3,96,66,3,0,19,66,3,48,35,43,13,124,19,10,60,64,35,3,19,1,8,126,153,8,59,2, 18,10,67,16,1,8,127,57,13,126,3,58,13,126,3,96,66,3,0,19,66,3,64,35,43,13, 126,19,10,60,64,35,3,19,1,8,128,153,8,60,2,18,10,68,16,1,8,129,57,13,128,3, 58,13,128,3,96,66,3,0,19,66,3,80,35,43,13,128,19,10,60,64,35,3,19,1,8,130, 153,8,61,2,18,10,69,32,1,8,131,16,64,32,70,48,35,71,10,70,71,3,71,19,64,35, 3,19,1,8,132,153,8,62,2,18,10,71,16,1,8,133,57,13,132,3,58,13,132,3,48,66,3, 0,19,66,3,16,35,43,13,132,19,10,70,64,35,3,19,1,8,134,153,8,63,2,18,10,72, 32,1,8,135,57,13,136,3,58,13,136,3,48,66,3,0,35,43,13,136,35,10,70,64,19,35, 64,3,19,64,33,3,153,8,63,78,48,0,1,8,136,64,71,112,3,153,8,63,7,16,16,1,8, 137,153,8,64,2,18,10,73,16,1,8,138,57,13,137,3,58,13,137,3,48,66,3,0,19,66, 3,32,35,43,13,137,19,10,70,64,35,3,19,1,8,139,153,8,65,2,18,10,74,48,1,8, 140,16,80,48,70,64,51,71,10,75,71,3,71,19,71,35,64,51,3,19,1,8,141,153,8,66, 2,18,10,76,16,1,8,142,57,13,141,3,58,13,141,3,64,66,3,0,19,66,3,16,35,43,13, 141,19,10,75,64,35,3,19,1,8,143,153,8,67,2,18,10,77,32,1,8,144,57,13,145,3, 58,13,145,3,64,66,3,0,35,43,13,145,35,10,75,64,19,35,64,3,19,64,33,3,153,8, 67,78,48,0,1,8,145,64,71,128,3,153,8,67,7,16,16,1,8,146,153,8,68,2,18,10,78, 48,1,8,147,16,80,48,70,64,51,71,10,79,71,3,71,19,71,35,64,51,3,19,1,8,148, 153,8,69,2,18,10,80,16,1,8,149,57,13,148,3,58,13,148,3,64,66,3,0,19,66,3,32, 35,43,13,148,19,10,79,64,35,3,19,1,8,150,153,8,70,2,18,10,81,16,1,8,151,57, 13,150,3,58,13,150,3,64,66,3,0,19,66,3,48,35,43,13,150,19,10,79,64,35,3,19, 1,8,152,153,8,71,2,18,10,82,48,1,8,153,16,80,48,70,64,51,71,10,83,71,3,71, 19,71,35,64,51,3,19,1,8,154,153,8,72,2,18,10,84,16,1,8,155,57,13,154,3,58, 13,154,3,64,66,3,0,19,66,3,16,35,43,13,154,19,10,83,64,35,3,19,1,8,156,153, 8,73,2,18,10,85,32,1,8,157,57,13,158,3,58,13,158,3,64,66,3,0,35,43,13,158, 35,10,83,64,19,35,64,3,19,64,33,3,153,8,73,78,48,0,1,8,158,64,71,144,3,153, 8,73,7,16,16,1,8,159,153,8,74,2,18,10,86,16,1,8,160,57,13,159,3,58,13,159,3, 64,66,3,0,19,66,3,32,35,43,13,159,19,10,83,64,35,3,19,1,8,161,153,8,75,2,18, 10,87,32,1,8,162,57,13,163,3,58,13,163,3,64,66,3,0,35,43,13,163,35,10,83,64, 19,35,64,3,19,64,49,3,153,8,76,78,48,0,1,8,163,64,71,144,3,153,8,76,7,16,16, 1,8,164,153,8,77,2,18,10,88,16,1,8,165,57,13,164,3,58,13,164,3,64,66,3,0,19, 66,3,48,35,43,13,164,19,10,83,64,35,3,19,1,8,166,153,8,78,2,18,10,89,48,1,8, 167,16,96,48,70,80,51,71,10,90,71,3,71,19,71,35,71,10,61,64,51,3,19,1,8,168, 153,8,79,2,18,10,89,64,1,8,169,16,96,64,70,80,67,71,10,90,71,3,71,19,71,35, 71,51,64,67,3,19,1,8,170,153,8,80,2,18,10,91,16,1,8,171,57,13,170,3,58,13, 170,3,80,66,3,0,19,66,3,16,35,43,13,170,19,10,90,64,35,3,19,1,8,172,153,8, 81,2,18,10,92,16,1,8,173,57,13,172,3,58,13,172,3,80,66,3,0,19,66,3,32,35,43, 13,172,19,10,90,64,35,3,19,1,8,174,153,8,82,2,18,10,93,16,1,8,175,57,13,174, 3,58,13,174,3,80,66,3,0,19,66,3,48,35,43,13,174,19,10,90,64,35,3,19,1,8,176, 153,8,83,2,18,10,94,16,1,8,177,57,13,176,3,58,13,176,3,80,66,3,0,19,66,3,64, 35,43,13,176,19,10,90,64,35,3,19,1,8,178,153,8,84,2,18,10,95,16,1,8,179,16, 48,16,70,32,19,71,10,96,71,3,64,19,3,19,1,8,180,153,8,85,2,18,10,97,0,1,8, 181,12,0,0,64,50,3,153,8,85,7,16,96,16,48,16,70,32,19,71,10,96,71,3,64,19,3, 18,0,19,1,8,182,153,8,86,2,18,10,100,16,1,8,183,57,13,182,3,58,13,182,3,32, 66,3,0,19,66,3,16,35,43,13,182,19,10,96,64,35,3,19,1,8,184,153,8,87,2,18,10, 101,16,1,8,185,57,13,186,3,58,13,186,3,32,66,3,0,19,43,13,186,19,10,96,64, 10,19,3,19,1,8,186,64,10,40,3,19,1,8,187,153,8,88,2,18,10,102,80,1,8,188,16, 128,80,70,112,83,71,10,103,71,3,71,35,71,19,71,51,71,67,71,71,160,64,83,3, 19,1,8,189,153,8,89,2,18,10,102,96,1,8,190,16,128,96,70,112,99,71,10,103,71, 3,71,35,71,19,71,51,71,67,71,83,64,99,3,19,1,8,191,153,8,90,2,18,10,104,16, 1,8,192,57,13,191,3,58,13,191,3,112,66,3,0,19,66,3,16,35,43,13,191,19,10, 103,64,35,3,19,1,8,193,153,8,91,2,18,10,105,16,1,8,194,57,13,193,3,58,13, 193,3,112,66,3,0,19,66,3,32,35,43,13,193,19,10,103,64,35,3,19,1,8,195,153,8, 92,2,18,10,106,16,1,8,196,57,13,195,3,58,13,195,3,112,66,3,0,19,66,3,48,35, 43,13,195,19,10,103,64,35,3,19,1,8,197,153,8,93,2,18,10,107,16,1,8,198,57, 13,197,3,58,13,197,3,112,66,3,0,19,66,3,64,35,43,13,197,19,10,103,64,35,3, 19,1,8,199,153,8,94,2,18,10,108,16,1,8,200,57,13,199,3,58,13,199,3,112,66,3, 0,19,66,3,80,35,43,13,199,19,10,103,64,35,3,19,1,8,201,153,8,95,2,18,10,109, 16,1,8,202,57,13,201,3,58,13,201,3,112,66,3,0,19,66,3,96,35,43,13,201,19,10, 103,64,35,3,19,1,8,203,153,8,96,2,18,10,110,112,1,8,204,16,160,112,70,144, 115,71,10,111,71,3,71,19,71,35,71,51,71,67,71,83,71,99,71,71,160,64,115,3, 19,1,8,205,153,8,97,2,18,10,110,128,1,8,206,16,160,128,70,144,131,71,10,111, 71,3,71,19,71,35,71,51,71,67,71,83,71,99,71,115,64,131,3,19,1,8,207,153,8, 98,2,18,10,112,16,1,8,208,57,13,207,3,58,13,207,3,144,66,3,0,19,66,3,16,35, 43,13,207,19,10,111,64,35,3,19,1,8,209,153,8,99,2,18,10,113,16,1,8,210,57, 13,209,3,58,13,209,3,144,66,3,0,19,66,3,32,35,43,13,209,19,10,111,64,35,3, 19,1,8,211,153,8,100,2,18,10,114,16,1,8,212,57,13,211,3,58,13,211,3,144,66, 3,0,19,66,3,48,35,43,13,211,19,10,111,64,35,3,19,1,8,213,153,8,101,2,18,10, 115,16,1,8,214,57,13,213,3,58,13,213,3,144,66,3,0,19,66,3,64,35,43,13,213, 19,10,111,64,35,3,19,1,8,215,153,8,102,2,18,10,116,16,1,8,216,57,13,215,3, 58,13,215,3,144,66,3,0,19,66,3,80,35,43,13,215,19,10,111,64,35,3,19,1,8,217, 153,8,103,2,18,10,117,16,1,8,218,57,13,217,3,58,13,217,3,144,66,3,0,19,66,3, 96,35,43,13,217,19,10,111,64,35,3,19,1,8,219,153,8,104,2,18,10,118,16,1,8, 220,57,13,219,3,58,13,219,3,144,66,3,0,19,66,3,112,35,43,13,219,19,10,111, 64,35,3,19,1,8,221,153,8,105,2,18,10,119,16,1,8,222,57,13,221,3,58,13,221,3, 144,66,3,0,19,66,3,128,35,43,13,221,19,10,111,64,35,3,19,1,8,223,153,8,106, 2,18,10,120,32,1,8,224,16,80,32,70,64,35,71,10,121,71,3,71,19,71,2,64,35,3, 19,1,8,225,153,8,107,2,18,10,122,48,1,8,226,16,80,48,70,64,51,71,10,121,71, 3,71,19,71,35,64,51,3,19,1,8,227,153,8,108,2,18,10,123,16,1,8,228,57,13,227, 3,58,13,227,3,64,66,3,0,19,66,3,16,35,43,13,227,19,10,121,64,35,3,19,1,8, 229,153,8,109,2,18,10,124,16,1,8,230,57,13,229,3,58,13,229,3,64,66,3,0,19, 66,3,32,35,43,13,229,19,10,121,64,35,3,19,1,8,231,153,8,110,2,18,10,125,16, 1,8,232,57,13,231,3,58,13,231,3,64,66,3,0,19,66,3,48,35,43,13,231,19,10,121, 64,35,3,19,1,8,233,153,8,111,2,18,10,126,16,1,8,234,16,48,16,70,32,19,71,10, 127,71,3,64,19,3,19,1,8,235,153,8,112,2,18,10,128,16,1,8,236,57,13,235,3,58, 13,235,3,32,66,3,0,19,66,3,16,35,43,13,235,19,10,127,64,35,3,19,1,8,237,153, 8,113,2,18,10,129,16,1,8,238,57,13,239,3,58,13,239,3,32,66,3,0,19,43,13,239, 19,10,127,64,10,19,3,19,1,8,239,64,10,40,3,19,1,8,240,153,8,114,2,18,10,130, 112,1,8,241,12,112,112,64,99,4,64,83,20,64,67,36,64,51,52,64,35,68,64,19,84, 64,3,100,48,13,243,99,59,99,13,243,23,64,10,131,13,242,10,132,13,242,1,8, 242,16,144,0,70,128,3,71,10,133,71,100,71,84,71,68,71,4,71,52,71,36,71,20, 18,112,19,1,8,243,153,8,115,74,99,1,8,244,153,8,116,2,18,10,130,96,1,8,245, 12,96,96,64,83,4,64,67,20,64,51,36,64,35,52,64,19,68,64,3,84,48,13,247,83, 59,83,13,247,23,64,10,131,13,246,10,132,13,246,1,8,246,16,144,0,70,128,3,71, 10,133,71,84,71,68,71,52,71,4,71,36,71,20,71,2,18,96,19,1,8,247,153,8,117, 74,83,1,8,248,153,8,118,2,18,10,134,16,1,8,249,57,13,248,3,58,13,248,3,128, 66,3,0,19,66,3,112,35,43,13,248,19,10,133,64,35,3,19,1,8,250,153,8,119,2,18, 10,135,32,1,8,251,57,13,252,3,58,13,252,3,128,66,3,0,35,43,13,252,35,10,133, 64,19,35,64,3,19,64,129,3,153,8,120,78,48,0,1,8,252,64,71,176,3,153,8,120,7, 16,16,1,8,253,153,8,121,2,18,10,136,16,1,8,254,57,13,253,3,58,13,253,3,128, 66,3,0,19,66,3,16,35,43,13,253,19,10,133,64,35,3,19,1,8,255,153,8,122,2,18, 10,137,32,1,40,0,57,45,1,3,58,45,1,3,128,66,3,0,35,43,45,1,35,10,133,64,19, 35,64,3,19,64,33,3,153,8,122,78,48,0,1,40,1,64,71,176,3,153,8,122,7,16,16,1, 40,2,153,8,123,2,18,10,138,16,1,40,3,57,45,2,3,58,45,2,3,128,66,3,0,19,66,3, 32,35,43,45,2,19,10,133,64,35,3,19,1,40,4,153,8,124,2,18,10,139,16,1,40,5, 57,45,4,3,58,45,4,3,128,66,3,0,19,66,3,48,35,43,45,4,19,10,133,64,35,3,19,1, 40,6,153,8,125,2,18,10,140,16,1,40,7,57,45,6,3,58,45,6,3,128,66,3,0,19,66,3, 80,35,43,45,6,19,10,133,64,35,3,19,1,40,8,153,8,126,2,18,10,141,16,1,40,9, 57,45,8,3,58,45,8,3,128,66,3,0,19,66,3,96,35,43,45,8,19,10,133,64,35,3,19,1, 40,10,153,8,127,2,18,10,142,16,1,40,11,57,45,10,3,58,45,10,3,128,66,3,0,19, 66,3,64,35,43,45,10,19,10,133,64,35,3,19,1,40,12,153,8,128,2,18,10,143,32,1, 40,13,57,45,14,3,58,45,14,3,128,66,3,0,35,43,45,14,35,10,133,64,19,35,64,3, 19,64,113,3,153,8,128,78,48,0,1,40,14,64,71,176,3,153,8,128,7,16,16,1,40,15, 153,8,129,2,18,10,144,16,1,40,16,57,45,17,3,58,45,17,3,128,66,3,0,19,43,45, 17,19,10,133,64,10,19,3,19,1,40,17,64,10,40,3,19,1,40,18,153,8,130,2,18,10, 145,16,1,40,19,57,45,20,3,58,45,20,3,128,66,3,0,19,66,3,32,35,43,45,20,19, 10,133,64,35,3,6,16,45,22,1,40,20,16,32,16,70,16,19,71,3,153,8,123,74,19,1, 40,21,153,8,131,2,18,10,146,16,1,40,22,48,45,23,3,64,10,19,3,19,1,40,23,12, 16,16,64,3,4,57,45,24,3,58,45,24,3,48,66,3,0,19,44,45,29,19,10,147,1,40,24, 57,45,29,4,58,45,25,4,48,66,4,0,3,44,45,29,3,10,148,1,40,25,57,45,29,4,60,4, 45,29,23,64,32,45,26,48,45,27,1,40,26,66,4,0,3,66,4,16,19,48,45,29,3,45,45, 29,19,40,45,29,19,1,61,45,28,1,40,27,66,4,0,3,66,4,16,19,66,4,32,35,48,45, 29,3,48,45,29,19,45,45,29,35,40,45,29,35,1,1,40,28,64,10,19,3,18,16,19,1,40, 29,64,10,40,3,18,16,19,1,40,30,153,8,132,2,18,10,149,48,1,40,31,12,48,48,64, 35,4,64,19,20,64,3,36,48,45,33,35,59,35,45,33,23,64,10,131,45,32,10,132,45, 32,1,40,32,16,80,0,70,64,3,71,10,150,71,36,71,20,71,4,18,48,19,1,40,33,153, 8,133,74,35,1,40,34,153,8,134,2,18,10,151,16,1,40,35,57,45,34,3,58,45,34,3, 64,66,3,0,19,66,3,16,35,43,45,34,19,10,150,64,35,3,19,1,40,36,153,8,135,2, 18,10,152,16,1,40,37,57,45,36,3,58,45,36,3,64,66,3,0,19,66,3,32,35,43,45,36, 19,10,150,64,35,3,19,1,40,38,153,8,136,2,18,10,153,16,1,40,39,57,45,38,3,58, 45,38,3,64,66,3,0,19,66,3,48,35,43,45,38,19,10,150,64,35,3,19,1,40,40,153,8, 137,2,18,10,154,16,1,40,41,57,45,42,3,58,45,42,3,64,66,3,0,19,66,3,16,35,43, 45,42,19,10,150,64,35,3,6,16,45,22,1,40,42,16,32,16,70,16,19,71,3,153,8,134, 74,19,1,40,43,153,8,138,2,18,10,155,16,1,40,44,16,48,16,70,32,19,71,10,156, 71,3,64,19,3,19,1,40,45,153,8,139,2,18,10,157,16,1,40,46,57,45,45,3,58,45, 45,3,32,66,3,0,19,66,3,16,35,43,45,45,19,10,156,64,35,3,19,1,40,47,153,8, 140,2,18,10,158,16,1,40,48,45,45,49,3,16,96,16,70,32,19,71,10,159,71,3,70, 32,3,71,10,160,71,19,19,1,40,49,16,48,16,70,32,19,71,10,160,71,3,64,19,3,19, 1,40,50,153,8,141,2,18,10,161,16,1,40,51,57,45,50,3,58,45,50,3,32,66,3,0,19, 66,3,16,35,43,45,50,19,10,160,64,35,3,19,1,40,52,153,8,142,2,18,10,162,48,1, 40,53,16,80,48,70,64,51,71,10,163,71,3,71,19,71,35,64,51,3,19,1,40,54,153,8, 143,2,18,10,164,16,1,40,55,57,45,54,3,58,45,54,3,64,66,3,0,19,66,3,16,35,43, 45,54,19,10,163,64,35,3,19,1,40,56,153,8,144,2,18,10,165,32,1,40,57,57,45, 58,3,58,45,58,3,64,66,3,0,35,43,45,58,35,10,163,64,19,35,64,3,19,64,33,3, 153,8,144,78,48,0,1,40,58,64,71,192,3,153,8,144,7,16,16,1,40,59,153,8,145,2, 18,10,166,16,1,40,60,57,45,59,3,58,45,59,3,64,66,3,0,19,66,3,32,35,43,45,59, 19,10,163,64,35,3,19,1,40,61,153,8,146,2,18,10,167,16,1,40,62,57,45,61,3,58, 45,61,3,64,66,3,0,19,66,3,48,35,43,45,61,19,10,163,64,35,3,19,1,40,63,153,8, 147,2,18,10,168,16,1,40,64,16,48,16,70,32,19,71,10,169,71,3,64,19,3,19,1,40, 65,153,8,148,2,18,10,170,16,1,40,66,57,45,65,3,58,45,65,3,32,66,3,0,19,66,3, 16,35,43,45,65,19,10,169,64,35,3,19,1,40,67,153,8,149,2,18,10,171,16,1,40, 68,57,45,69,3,58,45,69,3,32,66,3,0,19,43,45,69,19,10,169,64,10,19,3,19,1,40, 69,64,10,40,3,19,1,40,70,153,8,150,2,18,10,172,48,1,40,71,16,80,48,70,64,51, 71,10,173,71,3,71,19,71,35,64,51,3,19,1,40,72,153,8,151,2,18,10,174,16,1,40, 73,57,45,72,3,58,45,72,3,64,66,3,0,19,66,3,16,35,43,45,72,19,10,173,64,35,3, 19,1,40,74,153,8,152,2,18,10,175,32,1,40,75,57,45,76,3,58,45,76,3,64,66,3,0, 35,43,45,76,35,10,173,64,19,35,64,3,19,64,33,3,153,8,152,78,48,0,1,40,76,64, 71,208,3,153,8,152,7,16,16,1,40,77,153,8,153,2,18,10,176,16,1,40,78,57,45, 77,3,58,45,77,3,64,66,3,0,19,66,3,32,35,43,45,77,19,10,173,64,35,3,19,1,40, 79,153,8,154,2,18,10,177,16,1,40,80,57,45,79,3,58,45,79,3,64,66,3,0,19,66,3, 48,35,43,45,79,19,10,173,64,35,3,19,1,40,81,153,8,155,2,18,10,178,48,1,40, 82,16,80,48,70,64,51,71,10,179,71,3,71,19,71,35,64,51,3,19,1,40,83,153,8, 156,2,18,10,180,16,1,40,84,57,45,83,3,58,45,83,3,64,66,3,0,19,66,3,16,35,43, 45,83,19,10,179,64,35,3,19,1,40,85,153,8,157,2,18,10,181,16,1,40,86,57,45, 85,3,58,45,85,3,64,66,3,0,19,66,3,32,35,43,45,85,19,10,179,64,35,3,19,1,40, 87,153,8,158,2,18,10,182,16,1,40,88,57,45,87,3,58,45,87,3,64,66,3,0,19,66,3, 48,35,43,45,87,19,10,179,64,35,3,19,1,40,89,153,8,159,2,18,10,183,64,1,40, 90,12,64,64,64,51,4,64,35,20,64,19,36,64,3,52,153,8,160,7,16,112,16,128,16, 70,80,19,71,10,186,71,52,71,36,71,20,71,4,69,19,3,3,18,64,19,1,40,91,153,8, 161,2,18,10,187,16,1,40,92,57,45,91,3,58,45,91,3,80,66,3,0,19,66,3,16,35,43, 45,91,19,10,186,64,35,3,19,1,40,93,153,8,162,2,18,10,188,32,1,40,94,57,45, 95,3,58,45,95,3,80,66,3,0,35,43,45,95,35,10,186,64,19,35,64,3,19,64,33,3, 153,8,162,78,48,0,1,40,95,64,71,224,3,153,8,162,7,16,16,1,40,96,153,8,163,2, 18,10,189,16,1,40,97,57,45,96,3,58,45,96,3,80,66,3,0,19,66,3,32,35,43,45,96, 19,10,186,64,35,3,19,1,40,98,153,8,164,2,18,10,190,16,1,40,99,57,45,98,3,58, 45,98,3,80,66,3,0,19,66,3,64,35,43,45,98,19,10,186,64,35,3,19,1,40,100,153, 8,165,2,18,10,191,16,1,40,101,57,45,100,3,58,45,100,3,80,66,3,0,19,66,3,48, 35,43,45,100,19,10,186,64,35,3,19,1,40,102,153,8,166,2,18,10,192,48,1,40, 103,16,80,48,70,64,51,71,10,193,71,3,71,19,71,35,64,51,3,19,1,40,104,153,8, 167,2,18,10,194,16,1,40,105,57,45,104,3,58,45,104,3,64,66,3,0,19,66,3,16,35, 43,45,104,19,10,193,64,35,3,19,1,40,106,153,8,168,2,18,10,195,32,1,40,107, 57,45,108,3,58,45,108,3,64,66,3,0,35,43,45,108,35,10,193,64,19,35,64,3,19, 64,33,3,153,8,168,78,48,0,1,40,108,64,71,240,3,153,8,168,7,16,16,1,40,109, 153,8,169,2,18,10,196,16,1,40,110,57,45,109,3,58,45,109,3,64,66,3,0,19,66,3, 32,35,43,45,109,19,10,193,64,35,3,19,1,40,111,153,8,170,2,18,10,197,16,1,40, 112,57,45,111,3,58,45,111,3,64,66,3,0,19,66,3,48,35,43,45,111,19,10,193,64, 35,3,19,1,40,113,153,8,171,2,18,10,198,32,1,40,114,12,32,32,64,19,4,64,3,20, 57,45,115,3,58,45,115,3,32,66,3,0,35,44,45,116,35,10,18,1,40,115,64,10,40,3, 61,45,119,1,40,116,57,45,117,4,58,45,117,4,32,66,4,0,3,44,45,118,3,10,18,1, 40,117,64,10,40,3,61,45,119,1,40,118,16,64,0,70,48,3,71,10,199,71,20,71,4, 18,32,19,1,40,119,153,8,171,72,3,1,40,120,153,8,172,2,18,10,200,16,1,40,121, 57,45,120,3,58,45,120,3,48,66,3,0,19,66,3,16,35,43,45,120,19,10,199,64,35,3, 19,1,40,122,153,8,173,2,18,10,201,32,1,40,123,12,32,32,64,19,4,64,3,20,57, 45,124,19,58,45,124,19,32,66,19,0,35,44,45,125,35,10,18,1,40,124,64,10,40,3, 61,45,127,1,40,125,57,45,126,20,58,45,126,20,48,66,20,0,3,43,45,126,3,10, 199,64,20,19,64,4,35,64,33,3,153,8,173,8,48,0,32,1,40,126,64,71,8,16,3,153, 8,173,7,16,16,1,40,127,153,8,173,72,3,1,40,128,153,8,174,2,18,10,202,16,1, 40,129,57,45,128,3,58,45,128,3,48,66,3,0,19,66,3,32,35,43,45,128,19,10,199, 64,35,3,19,1,40,130,153,8,175,2,18,10,203,32,1,40,131,12,32,32,64,19,4,64,3, 20,57,45,132,19,58,45,132,19,32,66,19,0,35,44,45,133,35,10,18,1,40,132,64, 10,40,3,61,45,135,1,40,133,57,45,134,20,58,45,134,20,48,66,20,0,3,43,45,134, 3,10,199,64,20,19,64,4,35,64,49,3,153,8,175,8,48,0,32,1,40,134,64,71,8,16,3, 153,8,175,7,16,16,1,40,135,153,8,175,72,3,1,40,136,153,8,176,2,18,10,204,32, 1,40,137,16,64,32,70,48,35,71,10,205,71,3,71,19,64,35,3,19,1,40,138,153,8, 177,2,18,10,206,16,1,40,139,57,45,138,3,58,45,138,3,48,66,3,0,19,66,3,16,35, 43,45,138,19,10,205,64,35,3,19,1,40,140,153,8,178,2,18,10,207,32,1,40,141, 57,45,142,3,58,45,142,3,48,66,3,0,35,43,45,142,35,10,205,64,19,35,64,3,19, 64,33,3,153,8,178,78,48,0,1,40,142,64,71,8,17,3,153,8,178,7,16,16,1,40,143, 153,8,179,2,18,10,208,16,1,40,144,57,45,143,3,58,45,143,3,48,66,3,0,19,66,3, 32,35,43,45,143,19,10,205,64,35,3,19,1,40,145,153,8,180,2,18,10,209,32,1,40, 146,45,45,145,3,40,45,145,3,1,16,64,32,70,48,35,71,10,147,71,3,71,19,64,35, 3,19,1,40,147,153,8,181,2,18,10,209,16,1,40,148,64,10,40,19,6,32,45,146,1, 40,149,153,8,182,2,18,10,210,16,1,40,150,64,10,19,19,6,32,45,146,1,40,151, 153,8,183,2,18,10,211,0,1,40,152,12,0,0,64,50,3,153,8,183,7,16,128,64,10,40, 19,5,32,45,146,0,1,40,153,153,8,184,2,18,10,213,0,1,40,154,12,0,0,64,50,3, 153,8,184,7,16,128,64,10,19,19,5,32,45,146,0,1,40,155,153,8,185,2,18,10,214, 16,1,40,156,57,45,155,3,58,45,155,3,48,66,3,0,19,66,3,16,35,43,45,155,19,10, 147,64,35,3,19,1,40,157,153,8,186,2,18,10,215,16,1,40,158,57,45,157,3,58,45, 157,3,48,66,3,0,19,66,3,32,35,43,45,157,19,10,147,64,35,3,19,1,40,159,153,8, 187,2,18,10,216,16,1,40,160,57,45,161,3,58,45,161,3,48,66,3,0,19,43,45,161, 19,10,147,64,10,19,3,19,1,40,161,64,10,40,3,19,1,40,162,153,8,188,2,18,10, 217,16,1,40,163,45,45,162,3,40,45,162,3,1,16,64,16,70,48,19,71,10,148,71,3, 71,10,218,64,19,3,19,1,40,164,153,8,189,2,18,10,217,32,1,40,165,45,45,164,3, 40,45,164,3,1,16,64,32,70,48,35,71,10,148,71,3,71,19,64,35,3,19,1,40,166, 153,8,190,2,18,10,219,0,1,40,167,12,0,0,64,50,3,153,8,190,7,16,128,5,16,45, 163,0,1,40,168,153,8,191,2,18,10,220,16,1,40,169,57,45,168,3,58,45,168,3,48, 66,3,0,19,66,3,16,35,43,45,168,19,10,148,64,35,3,19,1,40,170,153,8,192,2,18, 10,221,16,1,40,171,57,45,170,3,58,45,170,3,48,66,3,0,19,66,3,32,35,43,45, 170,19,10,148,64,35,3,19,1,40,172,153,8,193,2,18,10,222,32,1,40,173,57,45, 174,3,58,45,174,3,48,66,3,0,35,43,45,174,35,10,148,64,19,35,64,3,19,64,49,3, 153,8,193,78,48,0,1,40,174,64,71,8,18,3,153,8,193,7,16,16,1,40,175,153,8, 194,2,18,10,223,16,1,40,176,57,45,177,3,58,45,177,3,48,66,3,0,19,43,45,177, 19,10,148,64,10,19,3,19,1,40,177,64,10,40,3,19,1,40,178,153,8,195,2,18,10, 224,16,1,40,179,45,45,178,3,40,45,178,3,1,16,48,16,70,32,19,71,10,18,71,3, 64,19,3,19,1,40,180,153,8,196,2,18,10,225,0,1,40,181,12,0,0,64,50,3,153,8, 196,7,16,128,5,16,45,179,0,1,40,182,153,8,197,2,18,10,226,16,1,40,183,57,45, 182,3,58,45,182,3,32,66,3,0,19,66,3,16,35,43,45,182,19,10,18,64,35,3,19,1, 40,184,153,8,198,2,18,10,227,16,1,40,185,57,45,186,3,58,45,186,3,32,66,3,0, 19,43,45,186,19,10,18,64,10,19,3,19,1,40,186,64,10,40,3,19,1,40,187,153,8, 199,2,18,10,228,16,1,40,188,16,48,16,70,32,19,71,10,159,71,3,64,19,3,19,1, 40,189,153,8,200,2,18,10,229,16,1,40,190,57,45,189,3,58,45,189,3,32,66,3,0, 19,66,3,16,35,43,45,189,19,10,159,64,35,3,19,1,40,191,153,8,201,2,18,10,230, 16,1,40,192,57,45,193,3,58,45,193,3,32,66,3,0,19,43,45,193,19,10,159,64,10, 19,3,19,1,40,193,64,10,40,3,19,1,40,194,153,8,202,2,18,10,231,16,1,40,195, 16,48,16,70,32,19,71,10,232,71,3,64,19,3,19,1,40,196,153,8,203,2,18,10,233, 16,1,40,197,57,45,196,3,58,45,196,3,32,66,3,0,19,66,3,16,35,43,45,196,19,10, 232,64,35,3,19,1,40,198,153,8,204,2,18,10,234,16,1,40,199,57,45,200,3,58,45, 200,3,32,66,3,0,19,43,45,200,19,10,232,64,10,19,3,19,1,40,200,64,10,40,3,19, 1,40,201,153,8,205,2,18,10,235,16,1,40,202,12,0,16,153,8,206,4,16,45,204,5, 16,45,245,0,1,40,203,153,8,207,2,18,10,236,16,1,40,204,57,45,228,3,60,3,45, 228,23,8,16,48,45,205,144,45,207,96,45,208,128,45,209,32,45,210,112,45,212, 64,45,214,80,45,223,1,40,205,66,3,0,19,66,3,32,35,48,45,228,19,59,19,45,228, 23,160,10,205,45,217,10,199,45,217,10,20,45,217,10,27,45,206,10,70,45,219,1, 40,206,64,35,3,19,1,40,207,66,3,0,19,66,3,32,35,66,3,64,51,43,45,228,19,10, 111,61,45,213,1,40,208,66,3,0,19,66,3,32,35,66,3,48,51,43,45,228,19,10,60, 61,45,213,1,40,209,66,3,0,19,66,3,32,35,66,3,48,51,43,45,228,19,10,133,12, 48,64,64,51,4,64,3,20,64,35,36,153,8,208,7,0,144,64,3,19,64,4,3,17,4,153,8, 208,7,32,160,64,3,19,64,20,3,64,19,20,153,8,209,4,16,45,19,48,45,226,3,59,3, 45,226,23,64,10,40,45,221,10,19,45,222,1,40,210,66,3,0,19,66,3,16,35,48,45, 228,19,59,19,45,228,23,160,10,160,45,217,10,127,45,219,10,96,45,219,10,169, 45,219,10,156,45,211,1,40,211,12,16,48,64,35,4,153,8,210,7,0,176,64,3,19,64, 4,3,153,8,210,8,32,160,16,1,40,212,66,3,0,19,66,3,16,35,66,3,32,51,43,45, 228,19,10,103,1,40,213,16,64,64,69,51,2,19,69,35,19,3,19,1,40,214,66,3,0,19, 66,3,16,35,66,3,32,51,66,3,48,67,48,45,228,19,59,19,45,228,23,8,20,10,179, 45,224,10,173,45,215,10,163,45,216,10,193,45,216,10,121,45,217,10,34,45,218, 10,79,45,219,10,75,45,219,10,83,45,219,10,150,45,220,1,40,215,16,64,80,69, 67,2,19,69,51,19,3,19,1,40,216,16,32,64,69,51,2,3,19,1,40,217,16,32,48,69, 35,2,3,19,1,40,218,64,67,3,6,16,109,87,1,40,219,64,2,3,19,1,40,220,12,48,64, 64,51,4,64,3,20,64,35,36,153,8,211,7,0,192,64,3,19,64,4,3,17,4,153,8,211,7, 32,160,64,3,19,64,20,3,64,19,20,153,8,212,4,16,45,41,48,45,227,3,59,3,45, 227,23,64,10,40,45,221,10,19,45,222,1,40,221,16,32,0,69,36,20,3,18,48,19,1, 40,222,64,20,3,18,48,19,1,40,223,66,3,0,19,66,3,16,35,66,3,32,51,66,3,48,67, 66,3,64,83,48,45,228,19,59,19,45,228,23,96,10,90,45,224,10,186,45,225,10,51, 45,225,1,40,224,16,96,80,69,67,2,3,69,51,3,19,69,35,19,3,19,1,40,225,16,64, 96,69,83,2,19,69,51,19,3,19,1,40,226,153,8,209,74,3,1,40,227,153,8,212,74,3, 1,40,228,153,8,213,74,3,1,40,229,153,8,214,2,18,10,241,16,1,40,230,14,16,16, 57,45,243,3,60,3,45,243,23,8,16,112,45,231,32,45,232,96,45,233,128,45,234, 144,45,235,64,45,236,48,45,237,80,45,239,1,40,231,66,3,0,19,43,45,243,19,10, 103,61,45,241,1,40,232,66,3,0,19,48,45,243,19,59,19,45,243,23,160,10,127,45, 241,10,156,45,241,10,96,45,241,10,169,45,241,10,160,45,241,1,40,233,66,3,0, 19,66,3,16,35,43,45,243,19,10,60,61,45,240,1,40,234,66,3,0,19,66,3,16,35,43, 45,243,19,10,133,64,35,4,153,8,215,7,0,208,64,3,19,64,4,3,17,4,153,8,215,7, 32,160,61,45,242,1,40,235,66,3,0,19,66,3,16,35,43,45,243,19,10,111,61,45, 240,1,40,236,66,3,0,19,66,3,16,35,48,45,243,19,59,19,45,243,23,8,20,10,34, 45,240,10,75,45,240,10,173,45,240,10,83,45,240,10,163,45,240,10,193,45,240, 10,79,45,241,10,121,45,241,10,179,45,241,10,150,45,241,1,40,237,66,3,0,19, 66,3,16,35,48,45,243,19,59,19,45,243,23,160,10,70,45,240,10,205,45,240,10, 199,45,240,10,20,45,240,10,27,45,238,1,40,238,64,35,3,61,45,242,1,40,239,66, 3,0,19,66,3,16,35,48,45,243,19,59,19,45,243,23,96,10,186,45,240,10,51,45, 240,10,90,45,241,1,40,240,16,32,48,69,35,2,3,61,45,242,1,40,241,64,2,3,1,40, 242,5,16,45,245,16,1,40,243,153,8,216,74,3,1,40,244,153,8,217,2,18,10,243, 16,1,40,245,56,45,249,3,12,32,16,65,3,19,4,64,19,20,57,45,246,19,58,45,246, 19,32,66,19,0,3,44,45,247,3,10,159,1,40,246,57,45,248,20,58,45,248,20,32,66, 20,0,3,43,45,248,3,10,232,1,40,247,64,4,3,5,16,45,245,32,1,40,248,64,4,3, 136,16,16,153,8,218,4,16,45,245,16,32,16,69,4,3,3,18,16,19,1,40,249,52,45, 244,3,19,1,40,250,153,8,219,2,18,10,244,32,1,40,251,57,77,44,19,60,19,77,44, 23,8,16,48,45,252,144,77,1,96,77,2,128,77,3,32,77,6,112,77,9,64,77,10,80,77, 24,1,40,252,66,19,0,35,66,19,32,51,48,77,44,35,59,35,77,44,23,160,10,70,77, 12,10,27,45,253,10,20,45,254,10,199,45,255,10,205,77,0,1,40,253,12,16,64,64, 19,4,64,51,19,153,8,220,4,32,77,156,64,4,19,64,3,35,64,49,3,153,8,221,8,48, 0,16,1,40,254,12,16,64,64,19,4,64,51,19,153,8,222,4,32,77,160,64,3,19,64,4, 3,5,32,13,40,16,1,40,255,12,16,64,64,19,4,64,51,19,153,8,223,4,32,77,160,64, 3,19,64,4,3,5,32,45,131,16,1,72,0,12,16,64,64,19,4,64,51,19,153,8,224,4,32, 77,160,64,4,19,64,3,35,64,49,3,153,8,225,8,48,0,16,1,72,1,66,19,0,35,66,19, 32,51,66,19,64,67,43,77,44,35,10,111,12,48,80,64,19,4,64,51,19,64,3,20,64, 67,36,153,8,226,4,32,77,160,64,4,19,64,3,35,136,16,32,64,49,3,153,8,227,7, 48,0,64,3,35,64,20,19,64,4,3,64,35,20,136,16,16,153,8,228,4,32,77,160,58,77, 31,4,144,64,4,19,64,3,35,64,81,3,153,8,229,8,48,0,16,1,72,2,66,19,0,35,66, 19,32,51,66,19,48,67,43,77,44,35,10,60,12,48,80,64,19,4,64,51,19,64,3,20,64, 67,36,153,8,230,4,32,77,160,64,4,19,64,3,35,136,16,32,64,49,3,153,8,231,7, 48,0,64,3,35,64,20,19,64,4,3,64,35,20,136,16,16,153,8,232,4,32,77,160,58,77, 32,4,96,64,4,19,64,3,35,64,65,3,153,8,233,8,48,0,16,1,72,3,66,19,0,35,66,19, 32,51,66,19,48,67,43,77,44,35,10,133,12,64,80,64,3,20,64,19,3,64,3,4,64,67, 36,64,51,52,153,8,234,4,16,45,19,48,77,34,3,59,3,77,34,23,64,10,19,77,4,10, 40,77,5,1,72,4,64,36,19,64,20,3,64,4,52,136,48,16,153,8,235,4,32,77,156,64, 4,19,64,3,35,64,65,3,153,8,236,8,48,0,16,1,72,5,64,52,19,17,36,17,52,64,20, 3,153,8,237,4,32,77,160,64,4,19,64,3,35,17,4,64,49,3,153,8,238,7,48,0,57,77, 33,3,58,77,33,3,128,66,3,0,19,66,3,48,35,43,77,33,19,10,133,64,3,52,64,35, 19,64,20,3,136,48,16,153,8,239,4,32,77,156,64,4,19,64,3,35,64,65,3,153,8, 236,8,48,0,16,1,72,6,66,19,0,35,66,19,16,51,48,77,44,35,59,35,77,44,23,160, 10,127,77,12,10,96,77,12,10,169,77,12,10,156,77,7,10,160,77,8,1,72,7,12,0, 64,64,51,19,153,8,240,4,32,77,156,16,48,16,70,32,19,71,10,156,71,3,64,19,3, 18,0,19,1,72,8,12,0,64,64,51,19,153,8,241,4,32,77,160,16,48,16,70,32,19,71, 10,160,71,3,64,19,3,18,0,19,1,72,9,66,19,0,35,66,19,16,51,66,19,32,67,43,77, 44,35,10,103,12,48,80,64,19,4,64,51,19,64,3,20,64,67,36,153,8,242,4,32,77, 160,64,4,19,64,3,35,136,16,32,64,33,3,153,8,243,7,48,0,64,3,35,64,20,19,64, 4,3,64,35,20,136,16,16,153,8,244,4,32,77,160,58,77,35,4,112,64,4,19,64,3,35, 64,49,3,153,8,245,8,48,0,16,1,72,10,66,19,0,35,66,19,16,51,66,19,32,67,66, 19,48,83,48,77,44,35,59,35,77,44,23,8,20,10,34,77,11,10,79,77,12,10,75,77, 12,10,83,77,12,10,179,77,13,10,150,77,17,10,173,77,20,10,193,77,21,10,163, 77,22,10,121,77,23,1,72,11,64,19,35,64,3,19,64,35,3,6,32,13,87,1,72,12,64, 19,3,19,1,72,13,12,64,96,64,19,4,64,51,20,64,3,36,64,67,52,56,77,15,3,65,3, 35,99,57,77,14,35,58,77,14,35,32,66,35,0,115,66,35,16,131,43,77,14,83,115, 64,131,3,61,77,16,1,72,14,64,83,19,64,99,3,153,8,246,4,32,77,160,61,77,16,1, 72,15,52,77,40,3,64,83,3,1,72,16,64,4,19,64,3,35,136,16,48,64,65,3,153,8, 247,7,48,0,64,3,35,64,4,19,64,20,3,64,35,4,153,8,248,4,32,77,160,57,77,36,4, 58,77,36,4,64,66,4,0,19,43,77,36,19,10,179,64,4,19,64,3,35,136,16,32,64,33, 3,153,8,249,7,48,0,64,3,35,64,20,19,64,4,3,64,35,20,136,16,16,153,8,250,4, 32,77,160,64,4,19,64,3,35,64,49,3,153,8,251,8,48,0,16,1,72,17,12,64,80,64,3, 20,64,19,3,64,3,4,64,67,36,64,51,52,153,8,252,4,16,45,41,48,77,38,3,59,3,77, 38,23,64,10,19,77,18,10,40,77,19,1,72,18,64,36,19,64,20,3,64,4,52,136,48,16, 153,8,253,4,32,77,156,64,4,19,64,3,35,64,49,3,153,8,254,8,48,0,16,1,72,19, 64,52,19,17,36,17,52,64,20,3,153,8,255,4,32,77,160,64,4,19,64,3,35,17,4,64, 33,3,153,40,0,7,48,0,57,77,37,3,58,77,37,3,64,66,3,0,19,66,3,32,35,43,77,37, 19,10,150,64,3,52,64,35,19,64,20,3,136,48,16,153,40,1,4,32,77,156,64,4,19, 64,3,35,64,49,3,153,8,254,8,48,0,16,1,72,20,12,48,96,64,19,4,64,67,19,64,3, 20,64,83,36,153,40,2,4,32,77,160,64,4,19,64,3,35,136,16,32,64,49,3,153,40,3, 7,48,0,64,3,35,64,20,19,64,4,3,64,35,20,136,16,16,153,40,4,4,32,77,160,57, 77,39,4,58,77,39,4,64,66,4,0,19,43,77,39,19,10,173,64,4,19,64,3,35,64,65,3, 153,40,5,8,48,0,16,1,72,21,12,16,80,64,19,4,64,67,19,153,40,6,4,32,77,160, 64,4,19,64,3,35,64,49,3,153,40,7,8,48,0,16,1,72,22,12,16,80,64,19,4,64,67, 19,153,40,8,4,32,77,160,64,4,19,64,3,35,64,49,3,153,40,9,8,48,0,16,1,72,23, 12,16,64,64,19,4,64,51,19,153,40,10,4,32,77,160,64,4,19,64,3,35,64,33,3,153, 40,11,8,48,0,16,1,72,24,66,19,0,35,66,19,16,51,66,19,32,67,66,19,48,83,66, 19,64,99,48,77,44,35,59,35,77,44,23,96,10,90,77,25,10,186,77,29,10,51,77,30, 1,72,25,12,64,96,64,19,4,64,51,20,64,3,36,64,67,52,56,77,27,3,65,3,35,99,57, 77,26,35,58,77,26,35,32,66,35,0,115,66,35,16,131,43,77,26,83,115,64,131,3, 61,77,28,1,72,26,64,83,19,64,99,3,153,8,246,4,32,77,160,61,77,28,1,72,27,52, 77,40,3,64,83,3,1,72,28,64,4,19,64,3,35,136,16,48,64,65,3,153,40,12,7,48,0, 64,3,35,64,4,19,64,20,3,64,35,4,153,40,13,4,32,77,160,57,77,41,4,58,77,41,4, 80,66,4,0,19,43,77,41,19,10,90,64,4,19,64,3,35,136,16,32,64,33,3,153,40,14, 7,48,0,64,3,35,64,20,19,64,4,3,64,35,20,136,16,16,153,40,15,4,32,77,160,64, 4,19,64,3,35,64,49,3,153,40,16,8,48,0,16,1,72,29,12,48,112,64,19,4,64,67,19, 64,3,20,64,99,36,153,40,17,4,32,77,160,64,4,19,64,3,35,136,16,32,64,49,3, 153,40,18,7,48,0,64,3,35,64,20,19,64,4,3,64,35,20,136,16,16,153,40,19,4,32, 77,160,57,77,42,4,58,77,42,4,80,66,4,0,19,43,77,42,19,10,186,64,4,19,64,3, 35,64,81,3,153,40,20,8,48,0,16,1,72,30,12,48,112,64,19,4,64,67,19,64,3,20, 64,99,36,153,40,21,4,32,77,160,64,4,19,64,3,35,136,16,32,64,49,3,153,8,49,7, 48,0,64,3,35,64,20,19,64,4,3,64,35,20,136,16,16,153,40,22,4,32,77,160,57,77, 43,4,58,77,43,4,80,66,4,0,19,43,77,43,19,10,51,64,4,19,64,3,35,64,81,3,153, 8,51,8,48,0,16,1,72,31,64,71,8,19,3,153,8,229,7,16,16,1,72,32,64,71,96,3, 153,8,233,7,16,16,1,72,33,16,32,16,70,16,19,71,3,153,8,124,74,19,1,72,34, 153,8,234,74,3,1,72,35,64,71,8,20,3,153,8,245,7,16,16,1,72,36,64,71,8,21,3, 153,8,249,7,16,16,1,72,37,16,32,16,70,16,19,71,3,153,8,135,74,19,1,72,38, 153,8,252,74,3,1,72,39,64,71,208,3,153,40,5,7,16,16,1,72,40,16,48,96,70,32, 35,71,36,71,83,153,40,23,74,35,1,72,41,64,71,8,22,3,153,40,14,7,16,16,1,72, 42,64,71,224,3,153,40,20,7,16,16,1,72,43,64,71,80,3,153,8,51,7,16,16,1,72, 44,153,40,24,74,19,1,72,45,153,40,25,2,18,10,245,32,1,72,46,57,77,121,19,60, 19,77,121,23,8,16,48,77,47,144,77,52,96,77,53,128,77,54,32,77,57,112,77,60, 64,77,61,80,77,72,1,72,47,66,19,0,35,66,19,32,51,48,77,121,35,59,35,77,121, 23,160,10,70,77,63,10,27,77,48,10,205,77,49,10,199,77,50,10,20,77,51,1,72, 48,12,32,64,64,3,4,64,51,3,64,19,20,153,40,26,7,16,224,64,3,19,64,2,35,64,4, 3,136,16,16,153,40,26,4,48,77,123,57,77,76,3,58,77,76,3,32,66,3,0,35,64,4, 19,64,49,3,153,8,221,8,48,0,16,1,72,49,12,16,64,64,19,4,64,2,35,64,51,19, 153,40,27,4,48,77,127,57,77,77,3,58,77,77,3,32,66,3,0,35,64,4,19,64,49,3, 153,8,225,8,48,0,16,1,72,50,12,16,64,64,19,4,64,2,35,64,51,19,153,40,27,4, 48,77,127,57,77,78,3,58,77,78,3,32,66,3,0,19,64,4,3,5,32,45,131,16,1,72,51, 12,16,64,64,19,4,64,2,35,64,51,19,153,40,27,4,48,77,127,57,77,79,3,58,77,79, 3,32,66,3,0,19,64,4,3,5,32,13,40,16,1,72,52,66,19,0,35,66,19,32,51,66,19,64, 67,43,77,121,35,10,111,12,32,80,64,19,4,64,2,35,64,67,19,64,51,20,153,40,27, 4,48,77,127,57,77,82,3,58,77,82,3,32,66,3,0,51,66,3,16,3,64,20,19,64,2,35, 64,51,20,153,40,27,4,48,77,127,57,77,81,3,58,77,81,3,32,66,3,0,35,64,4,19, 136,16,16,64,49,3,153,8,227,7,48,0,58,77,80,3,144,64,3,19,64,4,35,64,81,3, 153,8,229,8,48,0,16,1,72,53,66,19,0,35,66,19,32,51,66,19,48,67,43,77,121,35, 10,60,12,32,80,64,19,4,64,2,35,64,51,19,64,67,20,153,40,27,4,48,77,127,57, 77,85,3,58,77,85,3,32,66,3,0,51,66,3,16,3,64,20,19,64,2,35,64,51,20,153,40, 27,4,48,77,127,57,77,84,3,58,77,84,3,32,66,3,0,51,64,4,19,64,20,35,64,49,3, 64,51,20,136,16,16,153,8,231,7,48,0,58,77,83,3,96,64,3,19,64,4,35,64,65,3, 153,8,233,8,48,0,16,1,72,54,66,19,0,35,66,19,32,51,66,19,48,67,43,77,121,35, 10,133,12,64,80,64,3,20,64,19,3,64,3,4,64,67,36,64,51,52,153,40,28,4,16,45, 19,48,77,90,3,59,3,77,90,23,64,10,19,77,55,10,40,77,56,1,72,55,64,36,3,17, 36,17,52,153,40,26,7,16,224,64,3,19,64,2,35,64,20,3,17,20,153,40,26,4,48,77, 123,57,77,86,3,58,77,86,3,32,66,3,0,35,64,4,19,64,65,3,153,8,236,8,48,0,64, 1,72,56,64,52,19,64,2,35,64,20,3,17,20,17,52,153,40,27,4,48,77,127,57,77,89, 3,58,77,89,3,32,66,3,0,52,66,3,16,35,64,36,3,64,35,36,153,40,26,7,16,224,64, 3,19,64,2,35,64,36,3,17,36,153,40,26,4,48,77,123,57,77,88,3,58,77,88,3,32, 66,3,0,51,64,4,19,64,52,35,64,49,3,64,51,52,136,48,16,153,8,238,7,48,0,57, 77,87,3,58,77,87,3,128,66,3,0,19,43,77,87,19,10,133,64,3,19,64,4,35,64,65,3, 153,8,236,8,48,0,16,1,72,57,66,19,0,35,66,19,16,51,48,77,121,35,59,35,77, 121,23,160,10,127,77,63,10,96,77,63,10,169,77,63,10,156,77,58,10,160,77,59, 1,72,58,12,16,64,64,3,4,64,51,3,153,40,26,7,16,224,64,3,19,64,2,35,64,4,3, 136,16,0,153,40,26,4,48,77,123,57,77,91,3,58,77,91,3,32,16,48,16,66,3,0,19, 70,32,3,71,10,156,71,19,18,0,19,1,72,59,12,0,64,64,2,35,64,51,19,153,40,27, 4,48,77,127,57,77,92,3,58,77,92,3,32,16,48,16,66,3,0,19,70,32,3,71,10,160, 71,19,18,0,19,1,72,60,66,19,0,35,66,19,16,51,66,19,32,67,43,77,121,35,10, 103,12,32,80,64,19,4,64,2,35,64,67,19,64,51,20,153,40,27,4,48,77,127,57,77, 95,3,58,77,95,3,32,66,3,0,51,66,3,16,3,64,20,19,64,2,35,64,51,20,153,40,27, 4,48,77,127,57,77,94,3,58,77,94,3,32,66,3,0,35,64,4,19,136,16,16,64,33,3, 153,8,243,7,48,0,58,77,93,3,112,64,3,19,64,4,35,64,49,3,153,8,245,8,48,0,16, 1,72,61,66,19,0,35,66,19,16,51,66,19,32,67,66,19,48,83,48,77,121,35,59,35, 77,121,23,8,20,10,34,77,62,10,79,77,63,10,75,77,63,10,83,77,63,10,150,77,64, 10,179,77,67,10,173,77,68,10,163,77,69,10,193,77,70,10,121,77,71,1,72,62,64, 19,35,64,3,19,64,35,3,6,32,13,87,1,72,63,64,19,3,19,1,72,64,12,64,80,64,3, 20,64,19,3,64,3,4,64,67,36,64,51,52,153,40,29,4,16,45,41,48,77,100,3,59,3, 77,100,23,64,10,19,77,65,10,40,77,66,1,72,65,64,36,3,17,36,17,52,153,40,26, 7,16,224,64,3,19,64,2,35,64,20,3,17,20,153,40,26,4,48,77,123,57,77,96,3,58, 77,96,3,32,66,3,0,35,64,4,19,64,49,3,153,8,254,8,48,0,64,1,72,66,64,52,19, 64,2,35,64,20,3,17,20,17,52,153,40,27,4,48,77,127,57,77,99,3,58,77,99,3,32, 66,3,0,52,66,3,16,35,64,36,3,64,35,36,153,40,26,7,16,224,64,3,19,64,2,35,64, 36,3,17,36,153,40,26,4,48,77,123,57,77,98,3,58,77,98,3,32,66,3,0,51,64,4,19, 64,52,35,64,33,3,64,51,52,136,48,16,153,40,0,7,48,0,57,77,97,3,58,77,97,3, 64,66,3,0,19,43,77,97,19,10,150,64,3,19,64,4,35,64,49,3,153,8,254,8,48,0,16, 1,72,67,12,48,96,64,19,4,64,2,35,64,83,19,64,67,20,64,51,36,153,40,27,4,48, 77,127,57,77,104,3,58,77,104,3,32,66,3,0,51,66,3,16,3,64,36,19,64,2,35,64, 51,36,153,40,27,4,48,77,127,57,77,103,3,58,77,103,3,32,66,3,0,51,66,3,16,3, 64,20,19,64,2,35,64,51,20,153,40,27,4,48,77,127,57,77,102,3,58,77,102,3,32, 66,3,0,51,64,4,19,64,36,35,64,65,3,64,51,36,136,16,32,153,8,247,7,48,0,57, 77,101,3,58,77,101,3,64,66,3,0,19,43,77,101,19,10,179,64,3,19,64,4,35,136, 16,16,64,33,3,153,8,249,7,48,0,64,3,19,64,4,35,64,49,3,153,8,251,8,48,0,16, 1,72,68,12,32,96,64,19,4,64,2,35,64,67,19,64,83,20,153,40,27,4,48,77,127,57, 77,107,3,58,77,107,3,32,66,3,0,51,66,3,16,3,64,20,19,64,2,35,64,51,20,153, 40,27,4,48,77,127,57,77,106,3,58,77,106,3,32,66,3,0,51,64,4,19,64,20,35,64, 49,3,64,51,20,136,16,16,153,40,3,7,48,0,57,77,105,3,58,77,105,3,64,66,3,0, 19,43,77,105,19,10,173,64,3,19,64,4,35,64,65,3,153,40,5,8,48,0,16,1,72,69, 12,16,80,64,19,4,64,2,35,64,67,19,153,40,27,4,48,77,127,57,77,108,3,58,77, 108,3,32,66,3,0,35,64,4,19,64,49,3,153,40,9,8,48,0,16,1,72,70,12,16,80,64, 19,4,64,2,35,64,67,19,153,40,27,4,48,77,127,57,77,109,3,58,77,109,3,32,66,3, 0,35,64,4,19,64,49,3,153,40,7,8,48,0,16,1,72,71,12,16,64,64,19,4,64,2,35,64, 51,19,153,40,27,4,48,77,127,57,77,110,3,58,77,110,3,32,66,3,0,35,64,4,19,64, 33,3,153,40,11,8,48,0,16,1,72,72,66,19,0,35,66,19,16,51,66,19,32,67,66,19, 48,83,66,19,64,99,48,77,121,35,59,35,77,121,23,96,10,90,77,73,10,51,77,74, 10,186,77,75,1,72,73,12,48,96,64,19,4,64,2,35,64,83,19,64,67,20,64,51,36, 153,40,27,4,48,77,127,57,77,114,3,58,77,114,3,32,66,3,0,51,66,3,16,3,64,36, 19,64,2,35,64,51,36,153,40,27,4,48,77,127,57,77,113,3,58,77,113,3,32,66,3,0, 51,66,3,16,3,64,20,19,64,2,35,64,51,20,153,40,27,4,48,77,127,57,77,112,3,58, 77,112,3,32,66,3,0,51,64,4,19,64,36,35,64,65,3,64,51,36,136,16,32,153,40,12, 7,48,0,57,77,111,3,58,77,111,3,80,66,3,0,19,43,77,111,19,10,90,64,3,19,64,4, 35,136,16,16,64,33,3,153,40,14,7,48,0,64,3,19,64,4,35,64,49,3,153,40,16,8, 48,0,16,1,72,74,12,32,112,64,19,4,64,2,35,64,99,19,64,67,20,153,40,27,4,48, 77,127,57,77,117,3,58,77,117,3,32,66,3,0,51,66,3,16,3,64,20,19,64,2,35,64, 51,20,153,40,27,4,48,77,127,57,77,116,3,58,77,116,3,32,66,3,0,35,64,4,19, 136,16,16,64,49,3,153,8,49,7,48,0,57,77,115,3,58,77,115,3,80,66,3,0,19,43, 77,115,19,10,51,64,3,19,64,4,35,64,81,3,153,8,51,8,48,0,16,1,72,75,12,32, 112,64,19,4,64,2,35,64,99,19,64,67,20,153,40,27,4,48,77,127,57,77,120,3,58, 77,120,3,32,66,3,0,51,66,3,16,3,64,20,19,64,2,35,64,51,20,153,40,27,4,48,77, 127,57,77,119,3,58,77,119,3,32,66,3,0,35,64,4,19,136,16,16,64,49,3,153,40, 18,7,48,0,57,77,118,3,58,77,118,3,80,66,3,0,19,43,77,118,19,10,186,64,3,19, 64,4,35,64,81,3,153,40,20,8,48,0,16,1,72,76,153,40,30,72,3,1,72,77,153,40, 31,72,3,1,72,78,153,40,32,72,3,1,72,79,153,40,33,72,3,1,72,80,64,71,8,19,3, 153,8,229,7,16,16,1,72,81,153,40,34,72,3,1,72,82,153,40,35,72,3,1,72,83,64, 71,96,3,153,8,233,7,16,16,1,72,84,153,40,36,72,3,1,72,85,153,40,37,72,3,1, 72,86,153,40,38,72,3,1,72,87,64,71,176,3,153,8,236,7,16,16,1,72,88,153,40, 39,72,3,1,72,89,153,40,40,72,3,1,72,90,153,40,28,74,3,1,72,91,153,40,41,72, 3,1,72,92,153,40,42,72,3,1,72,93,64,71,8,20,3,153,8,245,7,16,16,1,72,94,153, 40,43,72,3,1,72,95,153,40,44,72,3,1,72,96,153,40,45,72,3,1,72,97,64,71,8,23, 3,153,8,254,7,16,16,1,72,98,153,40,46,72,3,1,72,99,153,40,47,72,3,1,72,100, 153,40,29,74,3,1,72,101,64,71,8,21,3,153,8,249,7,16,16,1,72,102,153,40,48, 72,3,1,72,103,153,40,49,72,3,1,72,104,153,40,50,72,3,1,72,105,64,71,208,3, 153,40,5,7,16,16,1,72,106,153,40,51,72,3,1,72,107,153,40,52,72,3,1,72,108, 153,40,53,72,3,1,72,109,153,40,54,72,3,1,72,110,153,40,55,72,3,1,72,111,64, 71,8,22,3,153,40,14,7,16,16,1,72,112,153,40,56,72,3,1,72,113,153,40,57,72,3, 1,72,114,153,40,58,72,3,1,72,115,64,71,80,3,153,8,51,7,16,16,1,72,116,153, 40,59,72,3,1,72,117,153,40,60,72,3,1,72,118,64,71,224,3,153,40,20,7,16,16,1, 72,119,153,40,61,72,3,1,72,120,153,40,62,72,3,1,72,121,153,40,63,74,19,1,72, 122,153,40,64,2,18,10,247,48,1,72,123,56,77,124,19,12,32,48,65,19,19,20,64, 35,4,64,2,35,153,40,27,4,48,77,127,57,77,125,3,58,77,125,3,32,16,32,16,66,3, 0,19,66,3,16,3,69,19,4,35,64,20,19,5,48,77,123,32,1,72,124,52,77,122,19,16, 48,48,70,32,19,71,35,71,3,64,19,3,19,1,72,125,153,40,65,72,3,1,72,126,153, 40,66,2,18,10,248,48,1,72,127,56,77,129,3,65,3,51,67,57,77,128,51,58,77,128, 51,32,66,51,0,83,66,51,16,99,43,77,128,19,83,12,16,112,64,67,19,64,35,3,64, 99,4,153,40,67,7,32,160,16,48,16,70,32,19,71,4,71,3,64,19,3,18,16,19,1,72, 128,16,32,80,69,51,35,35,64,67,3,6,48,77,127,1,72,129,52,77,126,3,16,48,48, 70,32,3,71,19,71,35,19,1,72,130,153,40,68,2,18,10,249,32,1,72,131,57,77,154, 19,60,19,77,154,23,8,16,112,77,132,32,77,133,96,77,134,128,77,135,144,77, 136,80,77,137,48,77,140,64,77,146,1,72,132,66,19,0,35,43,77,154,35,10,103, 61,77,147,1,72,133,66,19,0,35,48,77,154,35,59,35,77,154,23,160,10,127,77, 147,10,156,77,147,10,96,77,147,10,169,77,147,10,160,77,147,1,72,134,66,19,0, 35,66,19,16,51,43,77,154,35,10,60,12,16,64,64,19,4,64,51,19,153,40,69,4,32, 77,160,64,4,19,64,3,35,64,33,3,153,8,56,8,48,0,16,1,72,135,66,19,0,35,66,19, 16,51,43,77,154,35,10,133,12,16,64,64,19,4,64,51,19,153,40,70,4,32,77,156, 64,4,19,64,3,35,64,33,3,153,8,122,8,48,0,16,1,72,136,66,19,0,35,66,19,16,51, 43,77,154,35,10,111,12,16,64,64,19,4,64,51,19,153,40,71,4,32,77,160,64,4,19, 64,3,35,64,33,3,153,40,72,8,48,0,16,1,72,137,66,19,0,35,66,19,16,51,48,77, 154,35,59,35,77,154,23,96,10,90,77,147,10,186,77,138,10,51,77,139,1,72,138, 12,16,64,64,19,4,64,51,19,153,40,73,4,32,77,160,64,4,19,64,3,35,64,33,3,153, 8,162,8,48,0,16,1,72,139,12,16,64,64,19,4,64,51,19,153,40,74,4,32,77,160,64, 4,19,64,3,35,64,33,3,153,8,47,8,48,0,16,1,72,140,66,19,0,35,66,19,16,51,48, 77,154,35,59,35,77,154,23,160,10,27,77,141,10,20,77,142,10,70,77,143,10,199, 77,144,10,205,77,145,1,72,141,12,16,64,64,19,4,64,51,19,153,40,75,4,32,77, 156,64,4,19,64,3,35,64,33,3,153,40,76,8,48,0,16,1,72,142,12,16,64,64,19,4, 64,51,19,153,40,77,4,32,77,160,64,3,19,64,4,3,5,32,13,33,16,1,72,143,12,16, 64,64,19,4,64,51,19,153,40,78,4,32,77,160,64,4,19,64,3,35,64,33,3,153,8,63, 8,48,0,16,1,72,144,12,16,64,64,19,4,64,51,19,153,40,79,4,32,77,160,64,3,19, 64,4,3,5,32,45,123,16,1,72,145,12,16,64,64,19,4,64,51,19,153,40,80,4,32,77, 160,64,4,19,64,3,35,64,33,3,153,8,178,8,48,0,16,1,72,146,66,19,0,35,66,19, 16,51,48,77,154,35,59,35,77,154,23,8,20,10,79,77,147,10,121,77,147,10,179, 77,147,10,150,77,147,10,34,77,148,10,75,77,149,10,83,77,150,10,193,77,151, 10,173,77,152,10,163,77,153,1,72,147,64,19,3,19,1,72,148,12,16,64,64,19,4, 64,51,19,153,40,81,4,32,77,160,64,4,19,64,3,35,64,33,3,153,40,82,8,48,0,16, 1,72,149,12,16,64,64,19,4,64,51,19,153,40,83,4,32,77,160,64,4,19,64,3,35,64, 33,3,153,8,67,8,48,0,16,1,72,150,12,16,64,64,19,4,64,51,19,153,40,84,4,32, 77,160,64,4,19,64,3,35,64,33,3,153,8,73,8,48,0,16,1,72,151,12,16,64,64,19,4, 64,51,19,153,40,85,4,32,77,160,64,4,19,64,3,35,64,33,3,153,8,168,8,48,0,16, 1,72,152,12,16,64,64,19,4,64,51,19,153,40,86,4,32,77,160,64,4,19,64,3,35,64, 33,3,153,8,152,8,48,0,16,1,72,153,12,16,64,64,19,4,64,51,19,153,40,87,4,32, 77,160,64,4,19,64,3,35,64,33,3,153,8,144,8,48,0,16,1,72,154,153,40,88,74,19, 1,72,155,153,40,89,2,18,10,250,32,1,72,156,56,77,157,19,12,32,32,65,19,19, 20,64,3,4,153,40,90,4,32,77,160,64,3,35,64,4,19,64,20,3,64,35,20,136,16,16, 153,40,90,4,32,109,83,16,32,16,69,4,3,3,18,16,19,1,72,157,52,77,158,19,64,2, 3,19,1,72,158,16,32,32,70,16,35,71,19,153,40,90,74,35,1,72,159,153,40,23,2, 18,10,251,32,1,72,160,56,77,162,3,65,3,35,51,57,77,161,35,58,77,161,35,32, 66,35,0,67,66,35,16,83,43,77,161,19,67,64,83,3,19,1,72,161,64,51,3,6,32,77, 160,1,72,162,52,77,159,3,64,19,3,19,1,72,163,153,40,91,2,18,10,252,16,1,72, 164,57,77,175,3,60,3,77,175,23,8,16,96,77,165,128,77,166,112,77,167,144,77, 168,64,77,169,48,77,170,32,77,171,80,77,172,1,72,165,66,3,0,19,43,77,175,19, 10,60,61,77,173,1,72,166,66,3,0,19,43,77,175,19,10,133,61,77,174,1,72,167, 66,3,0,19,43,77,175,19,10,103,61,77,174,1,72,168,66,3,0,19,43,77,175,19,10, 111,61,77,174,1,72,169,66,3,0,19,48,77,175,19,59,19,77,175,23,8,20,10,34,77, 173,10,75,77,173,10,173,77,173,10,83,77,173,10,163,77,173,10,79,77,174,10, 121,77,174,10,179,77,174,10,193,77,174,10,150,77,174,1,72,170,66,3,0,19,48, 77,175,19,59,19,77,175,23,160,10,70,77,173,10,205,77,173,10,199,77,173,10, 20,77,173,10,27,77,173,1,72,171,66,3,0,19,48,77,175,19,59,19,77,175,23,160, 10,96,77,173,10,127,77,174,10,156,77,174,10,169,77,174,10,160,77,174,1,72, 172,66,3,0,19,48,77,175,19,59,19,77,175,23,96,10,51,77,173,10,90,77,174,10, 186,77,174,1,72,173,64,10,19,3,19,1,72,174,64,10,40,3,19,1,72,175,153,40,92, 74,3,1,72,176,153,40,93,2,18,10,253,16,1,72,177,48,77,179,3,59,3,77,179,23, 96,10,254,77,178,10,255,77,178,42,0,77,178,1,72,178,64,10,19,3,19,1,72,179, 64,10,40,3,19,1,72,180,153,40,94,2,18,42,1,48,1,72,181,57,77,195,3,60,3,77, 195,23,160,144,77,182,128,77,184,112,77,186,64,77,189,32,77,194,1,72,182,66, 3,0,51,66,3,96,67,43,77,195,51,10,111,12,32,80,64,35,4,64,19,20,43,77,183, 67,19,64,3,19,64,113,3,153,40,95,7,48,0,1,72,183,57,77,196,3,58,77,196,3, 144,66,3,0,19,66,3,112,35,43,77,196,19,10,111,43,77,188,35,20,64,3,19,64,4, 35,64,129,3,153,40,96,8,48,0,32,1,72,184,66,3,0,51,66,3,80,67,43,77,195,51, 10,133,12,32,80,64,35,4,64,19,20,43,77,185,67,19,64,3,19,64,97,3,153,40,97, 7,48,0,1,72,185,57,77,197,3,58,77,197,3,128,66,3,0,19,66,3,96,35,43,77,197, 19,10,133,43,77,188,35,20,64,3,19,64,4,35,64,113,3,153,8,128,8,48,0,32,1,72, 186,66,3,0,51,66,3,64,67,43,77,195,51,10,103,12,32,80,64,35,4,64,19,20,43, 77,187,67,19,64,3,19,64,81,3,153,40,98,7,48,0,1,72,187,57,77,198,3,58,77, 198,3,112,66,3,0,19,66,3,80,35,43,77,198,19,10,103,43,77,188,35,20,64,3,19, 64,4,35,64,97,3,153,40,99,8,48,0,32,1,72,188,18,32,19,1,72,189,66,3,0,51,66, 3,32,67,43,77,195,51,10,121,14,64,80,64,3,52,56,77,192,67,65,67,51,36,64,35, 4,64,19,20,43,77,190,51,19,64,35,3,61,77,191,1,72,190,64,51,3,1,72,191,64,3, 51,64,4,19,64,20,35,64,36,3,64,51,36,17,4,17,20,153,40,100,4,48,109,77,16, 32,16,69,36,3,3,61,77,193,1,72,192,52,77,199,67,64,2,3,1,72,193,64,52,19,64, 3,35,64,49,3,153,40,101,8,48,0,64,1,72,194,66,3,0,51,66,3,16,67,43,77,195, 51,10,127,43,77,195,67,19,16,48,48,70,32,3,71,10,127,71,35,19,1,72,195,19,1, 72,196,16,32,16,70,16,19,71,3,153,8,104,74,19,1,72,197,16,32,16,70,16,19,71, 3,153,8,126,74,19,1,72,198,16,32,16,70,16,19,71,3,153,8,94,74,19,1,72,199, 16,32,80,70,16,19,71,67,153,40,102,74,19,1,72,200,153,40,103,2,18,42,2,16,1, 72,201,64,3,19,64,42,3,3,6,32,77,205,1,72,202,153,40,104,2,18,42,4,16,1,72, 203,64,3,19,64,42,3,3,6,32,77,214,1,72,204,153,40,105,2,18,42,2,32,1,72,205, 57,77,212,19,58,77,212,19,160,66,19,0,35,66,19,16,51,66,19,32,67,66,19,48, 83,66,19,64,99,66,19,80,115,66,19,96,131,66,19,144,147,43,77,212,35,50,13, 112,32,160,64,3,100,64,147,84,64,131,68,64,115,52,64,99,36,64,83,20,64,67,4, 69,51,2,35,64,71,8,24,19,153,40,106,7,48,240,64,4,19,17,4,64,100,3,153,40, 107,4,32,109,33,64,71,8,25,19,64,2,35,64,100,3,153,40,108,7,48,240,48,77, 210,20,59,20,77,210,23,64,10,19,77,206,10,40,77,207,1,72,206,64,71,8,26,19, 64,2,35,17,20,64,100,3,153,40,109,7,48,240,1,72,207,48,77,211,36,59,36,77, 211,23,64,10,19,77,208,10,40,77,209,1,72,208,64,71,8,27,19,64,2,35,17,20,17, 36,64,100,3,153,40,110,7,48,240,1,72,209,16,32,0,69,84,2,35,64,71,8,28,19, 64,100,3,64,52,84,136,64,48,153,40,111,7,48,240,64,71,8,29,19,64,2,35,64,36, 3,153,40,112,7,48,240,64,50,35,64,4,19,64,2,51,136,16,32,64,20,3,153,40,113, 7,64,8,16,64,71,8,30,19,64,2,35,64,20,3,153,40,114,7,48,240,64,4,19,64,20,3, 5,32,77,214,32,1,72,210,153,40,115,74,20,1,72,211,153,40,116,74,36,1,72,212, 16,32,32,70,16,35,71,19,153,32,74,35,1,72,213,153,40,117,2,18,42,8,32,1,72, 214,56,77,217,19,14,64,32,65,19,35,51,104,52,77,215,64,35,19,64,3,4,64,51, 20,64,19,36,153,40,118,4,32,77,219,105,52,61,77,216,1,72,215,106,52,16,32,0, 69,36,2,19,64,71,8,31,3,153,40,119,7,32,8,17,1,72,216,64,20,19,64,4,3,5,32, 77,214,64,1,72,217,52,77,213,19,64,42,9,3,19,1,72,218,153,40,120,2,18,42,10, 32,1,72,219,57,109,31,19,60,19,109,31,23,8,16,32,77,220,48,77,226,64,77,232, 128,77,255,80,109,10,96,109,18,112,109,24,144,109,25,1,72,220,66,19,0,35,66, 19,16,51,48,109,31,35,59,35,109,31,23,160,10,96,77,221,10,127,77,222,10,169, 77,223,10,156,77,224,10,160,77,225,1,72,221,16,32,64,69,51,2,35,64,71,8,32, 19,153,40,121,78,48,240,1,72,222,16,32,64,69,51,2,35,64,71,8,33,19,153,40, 122,78,48,240,1,72,223,16,32,64,69,51,2,35,64,71,8,34,19,153,40,123,78,48, 240,1,72,224,12,32,64,64,2,35,64,71,8,35,19,64,51,4,64,3,20,153,40,124,7,48, 240,64,4,19,136,16,16,64,4,3,153,40,125,4,32,109,33,64,71,8,36,19,64,2,35, 64,4,3,153,40,126,8,48,240,16,1,72,225,12,32,64,64,2,35,64,71,8,37,19,64,51, 4,64,3,20,153,40,127,7,48,240,64,4,19,136,16,16,64,4,3,153,40,128,4,32,109, 55,64,71,8,36,19,64,2,35,64,4,3,153,40,129,8,48,240,16,1,72,226,66,19,0,35, 66,19,16,51,66,19,32,67,48,109,31,35,59,35,109,31,23,160,10,205,77,227,10, 199,77,228,10,70,77,229,10,27,77,230,10,20,77,231,1,72,227,12,48,80,64,2,35, 64,71,8,38,19,64,51,4,64,67,20,64,3,36,153,40,130,7,48,240,64,4,19,136,16, 32,64,20,3,153,40,131,4,32,109,55,64,71,8,39,19,64,2,35,64,20,3,153,40,132, 7,48,240,64,4,19,136,16,16,64,4,3,153,40,133,4,32,109,55,64,71,8,40,19,64,2, 35,64,4,3,153,40,134,8,48,240,16,1,72,228,12,48,80,64,2,35,64,71,8,38,19,64, 51,4,64,67,20,64,3,36,153,40,135,7,48,240,64,4,19,136,16,32,64,20,3,153,40, 136,4,32,109,55,64,71,8,41,19,64,2,35,64,20,3,153,40,137,7,48,240,64,4,19, 136,16,16,64,4,3,153,40,138,4,32,109,55,64,71,8,40,19,64,2,35,64,4,3,153,40, 139,8,48,240,16,1,72,229,12,48,80,64,2,35,64,71,8,38,19,64,51,4,64,67,20,64, 3,36,153,40,140,7,48,240,64,4,19,136,16,32,64,20,3,153,40,141,4,32,109,55, 16,32,0,69,4,2,35,64,71,8,42,19,64,20,3,153,40,142,8,48,240,32,1,72,230,12, 48,80,64,2,35,64,71,8,38,19,64,51,4,64,67,20,64,3,36,153,40,143,7,48,240,64, 4,19,136,16,32,64,20,3,153,40,144,4,32,109,33,64,71,8,43,19,64,2,35,64,20,3, 153,40,145,7,48,240,64,4,19,136,16,16,64,4,3,153,40,146,4,32,109,33,64,71,8, 40,19,64,2,35,64,4,3,153,40,147,8,48,240,16,1,72,231,12,48,80,64,2,35,64,71, 8,38,19,64,51,4,64,67,20,64,3,36,153,40,148,7,48,240,64,4,19,136,16,32,64, 20,3,153,40,149,4,32,109,55,64,71,8,41,19,64,2,35,64,20,3,153,40,150,7,48, 240,64,4,19,136,16,16,64,4,3,153,40,151,4,32,109,55,64,71,8,40,19,64,2,35, 64,4,3,153,40,152,8,48,240,16,1,72,232,66,19,0,35,66,19,16,51,66,19,32,67, 66,19,48,83,48,109,31,35,59,35,109,31,23,8,20,10,179,77,233,10,193,77,234, 10,163,77,235,10,75,77,239,10,173,77,240,10,83,77,241,10,150,77,245,10,34, 77,252,10,121,77,253,10,79,77,254,1,72,233,12,64,96,64,2,35,64,71,8,44,19, 64,51,4,64,67,20,64,83,36,64,3,52,153,40,153,7,48,240,64,4,19,136,16,48,64, 36,3,153,40,154,4,32,109,55,64,71,8,45,19,64,2,35,64,36,3,153,40,155,7,48, 240,64,4,19,136,16,32,64,20,3,153,40,156,4,32,109,55,64,71,8,46,19,64,2,35, 64,20,3,153,40,157,7,48,240,64,4,19,136,16,16,64,4,3,153,40,158,4,32,109,55, 64,71,8,40,19,64,2,35,64,4,3,153,40,159,8,48,240,16,1,72,234,12,64,96,64,2, 35,64,71,8,38,19,64,51,4,64,83,20,64,67,36,64,3,52,153,40,160,7,48,240,64,4, 19,136,16,48,64,36,3,153,40,161,4,32,109,55,64,71,8,41,19,64,2,35,64,36,3, 153,40,162,7,48,240,16,32,0,69,4,2,35,64,71,8,47,19,136,16,32,64,20,3,153, 40,163,7,48,240,64,4,19,136,16,16,64,4,3,153,40,164,4,32,109,55,64,71,8,40, 19,64,2,35,64,4,3,153,40,165,8,48,240,16,1,72,235,12,64,96,64,2,35,64,71,8, 38,19,64,51,4,64,83,20,64,67,36,64,3,52,153,40,166,7,48,240,64,4,19,17,4,64, 52,3,153,40,167,4,32,109,55,64,71,8,41,19,64,2,35,64,52,3,153,40,168,7,48, 240,48,109,26,20,59,20,109,26,23,64,42,11,77,236,42,12,77,237,1,72,236,64, 71,8,48,19,64,2,35,17,20,64,52,3,153,40,169,7,48,240,61,77,238,1,72,237,64, 71,8,49,19,64,2,35,17,20,64,52,3,153,40,170,7,48,240,1,72,238,64,36,19,136, 48,16,64,4,3,153,40,171,4,32,109,55,64,71,8,36,19,64,2,35,64,4,3,153,40,172, 8,48,240,16,1,72,239,12,64,96,64,2,35,64,71,8,38,19,64,51,4,64,83,20,64,67, 36,64,3,52,153,40,173,7,48,240,64,4,19,136,16,48,64,36,3,153,40,174,4,32, 109,55,16,64,0,69,4,2,51,69,20,51,35,64,71,8,50,19,64,36,3,153,40,175,8,48, 240,48,1,72,240,12,64,96,64,2,35,64,71,8,38,19,64,51,4,64,67,20,64,83,36,64, 3,52,153,40,176,7,48,240,64,4,19,136,16,48,64,36,3,153,40,177,4,32,109,55, 64,71,8,51,19,64,2,35,64,36,3,153,40,178,7,48,240,64,4,19,136,16,32,64,20,3, 153,40,179,4,32,109,55,64,71,8,45,19,64,2,35,64,20,3,153,40,180,7,48,240,64, 4,19,136,16,16,64,4,3,153,40,181,4,32,109,55,64,71,8,52,19,64,2,35,64,4,3, 153,40,182,8,48,240,16,1,72,241,12,64,96,64,2,35,64,71,8,38,19,64,51,4,64,3, 20,64,83,36,64,67,52,153,40,183,7,48,240,64,4,19,17,4,64,20,3,153,40,184,4, 32,109,55,48,77,244,36,59,36,77,244,23,64,42,13,77,242,42,14,77,243,1,72, 242,16,32,0,69,52,2,35,64,71,8,53,19,64,20,3,153,40,185,8,48,240,64,1,72, 243,16,32,0,69,52,2,35,64,71,8,54,19,64,20,3,153,40,186,8,48,240,64,1,72, 244,16,64,0,69,36,2,51,69,52,51,35,64,71,8,55,19,64,20,3,153,40,187,8,48, 240,64,1,72,245,12,64,80,64,19,4,64,2,35,64,71,8,38,19,64,51,20,64,67,36,64, 3,52,153,40,188,7,48,240,64,4,3,17,4,153,40,189,4,16,45,41,48,109,28,3,59,3, 109,28,23,64,10,19,77,246,10,40,77,250,1,72,246,48,77,247,20,16,32,0,69,20, 2,35,64,71,8,24,19,17,20,64,52,3,153,40,190,7,48,240,61,77,251,1,72,247,57, 109,27,20,60,20,109,27,23,64,32,77,248,48,77,249,1,72,248,66,20,0,3,66,20, 16,19,48,109,27,3,45,109,27,19,40,109,27,19,1,16,32,16,69,3,2,35,64,71,8,24, 19,17,20,64,52,3,153,40,191,7,48,240,61,77,251,1,72,249,66,20,0,3,66,20,16, 19,66,20,32,35,48,109,27,3,48,109,27,19,45,109,27,35,40,109,27,35,1,16,64, 32,69,19,2,51,69,3,51,35,64,71,8,56,19,17,20,64,52,3,153,40,192,7,48,240,61, 77,251,1,72,250,64,71,8,57,19,64,2,35,64,52,3,153,40,193,7,48,240,64,20,19, 17,20,64,52,3,153,40,194,4,32,109,55,64,71,8,58,19,64,2,35,64,52,3,153,40, 195,7,48,240,1,72,251,64,36,19,136,48,16,64,4,3,153,40,196,4,32,109,33,64, 71,8,36,19,64,2,35,64,4,3,153,40,197,8,48,240,16,1,72,252,12,48,96,64,2,35, 64,71,8,38,19,64,51,4,64,83,20,64,3,36,153,40,198,7,48,240,64,4,19,136,16, 32,64,20,3,153,40,199,4,32,109,55,64,71,8,59,19,64,2,35,64,20,3,153,40,200, 7,48,240,64,4,19,136,16,16,64,4,3,153,40,201,4,32,109,37,64,71,8,36,19,64,2, 35,64,4,3,153,40,202,8,48,240,16,1,72,253,12,48,80,64,2,35,64,71,8,60,19,64, 51,4,64,67,20,64,3,36,153,40,203,7,48,240,64,4,19,136,16,32,64,20,3,153,40, 204,4,32,109,55,64,71,8,61,19,64,2,35,64,20,3,153,40,205,7,48,240,64,4,19, 64,17,35,136,16,16,64,4,3,153,40,206,4,48,109,67,64,71,8,62,19,64,2,35,64,4, 3,153,40,207,8,48,240,16,1,72,254,12,48,80,64,2,35,64,71,8,38,19,64,67,4,64, 51,20,64,3,36,153,40,208,7,48,240,16,64,0,69,4,2,51,69,20,51,35,64,71,8,63, 19,64,36,3,153,40,209,8,48,240,48,1,72,255,66,19,0,35,66,19,16,51,66,19,32, 67,66,19,48,83,66,19,80,99,66,19,96,115,43,109,31,35,10,133,12,112,128,64, 19,20,64,2,35,64,71,8,38,19,64,51,4,64,67,36,64,83,52,64,99,68,64,115,84,64, 3,100,153,40,210,7,48,240,64,4,19,17,4,64,100,3,153,40,211,4,32,109,33,64, 71,8,41,19,64,2,35,64,100,3,153,40,212,7,48,240,64,20,3,17,20,153,40,213,4, 16,45,19,48,109,30,3,59,3,109,30,23,64,10,19,109,0,10,40,109,4,1,104,0,48, 109,1,36,16,32,0,69,36,2,35,64,71,8,24,19,17,36,64,100,3,153,40,214,7,48, 240,61,109,5,1,104,1,57,109,29,36,60,36,109,29,23,64,32,109,2,48,109,3,1, 104,2,66,36,0,3,66,36,16,19,48,109,29,3,45,109,29,19,40,109,29,19,1,16,32, 16,69,3,2,35,64,71,8,24,19,17,36,64,100,3,153,40,215,7,48,240,61,109,5,1, 104,3,66,36,0,3,66,36,16,19,66,36,32,35,48,109,29,3,48,109,29,19,45,109,29, 35,40,109,29,35,1,16,64,32,69,19,2,51,69,3,51,35,64,71,8,56,19,17,36,64,100, 3,153,40,216,7,48,240,61,109,5,1,104,4,64,71,8,57,19,64,2,35,64,100,3,153, 40,217,7,48,240,64,36,19,17,36,64,100,3,153,40,218,4,32,109,55,64,71,8,58, 19,64,2,35,64,100,3,153,40,219,7,48,240,1,104,5,64,52,19,17,52,64,100,3,153, 40,220,4,32,109,33,64,71,8,64,19,64,2,35,64,100,3,153,40,221,7,48,240,52, 109,6,68,61,109,7,1,104,6,16,32,0,69,68,2,35,64,71,8,65,19,17,68,64,100,3, 153,40,222,7,48,240,1,104,7,52,109,8,84,61,109,9,1,104,8,16,32,0,69,84,2,35, 64,71,8,66,19,17,68,17,84,64,100,3,153,40,223,7,48,240,1,104,9,64,71,8,40, 19,64,2,35,64,100,3,153,40,224,8,48,240,112,1,104,10,66,19,0,35,66,19,16,51, 66,19,32,67,66,19,48,83,66,19,64,99,48,109,31,35,59,35,109,31,23,96,10,90, 109,11,10,186,109,16,10,51,109,17,1,104,11,12,80,112,64,2,35,64,71,8,44,19, 64,51,4,64,67,20,64,83,36,64,99,52,64,3,68,153,40,225,7,48,240,64,4,19,17,4, 64,68,3,153,40,226,4,32,109,55,64,71,8,45,19,64,2,35,64,68,3,153,40,227,7, 48,240,64,20,19,17,20,64,68,3,153,40,228,4,32,109,55,64,71,8,46,19,64,2,35, 64,68,3,153,40,229,7,48,240,64,36,19,17,36,64,68,3,153,40,230,4,32,109,55, 48,109,15,52,59,52,109,15,23,96,42,15,109,12,42,16,109,13,42,17,109,14,1, 104,12,64,71,8,67,19,64,2,35,17,52,64,68,3,153,40,231,7,48,240,61,109,15,1, 104,13,64,71,8,68,19,64,2,35,17,52,64,68,3,153,40,232,7,48,240,61,109,15,1, 104,14,64,71,8,69,19,64,2,35,17,52,64,68,3,153,40,233,7,48,240,1,104,15,64, 71,8,40,19,64,2,35,64,68,3,153,40,234,8,48,240,80,1,104,16,12,80,112,64,2, 35,64,71,8,38,19,64,51,4,64,67,20,64,83,36,64,99,52,64,3,68,153,40,235,7,48, 240,64,4,19,136,16,64,64,52,3,153,40,236,4,32,109,55,64,71,8,41,19,64,2,35, 64,52,3,153,40,237,7,48,240,64,4,19,136,16,48,64,36,3,153,40,238,4,32,109, 55,16,32,0,69,4,2,35,64,71,8,47,19,136,16,32,64,20,3,153,40,239,7,48,240,64, 4,19,136,16,16,64,4,3,153,40,240,4,32,109,55,64,71,8,40,19,64,2,35,64,4,3, 153,40,241,8,48,240,16,1,104,17,12,80,112,64,2,35,64,71,8,38,19,64,51,4,64, 67,20,64,83,36,64,99,52,64,3,68,153,40,242,7,48,240,64,4,19,136,16,64,64,52, 3,153,40,243,4,32,109,55,64,71,8,41,19,64,2,35,64,52,3,153,40,244,7,48,240, 64,4,19,136,16,48,64,36,3,153,40,245,4,32,109,55,16,32,0,69,4,2,35,64,71,8, 47,19,136,16,32,64,20,3,153,40,246,7,48,240,64,4,19,136,16,16,64,4,3,153,40, 247,4,32,109,55,64,71,8,40,19,64,2,35,64,4,3,153,40,248,8,48,240,16,1,104, 18,66,19,0,35,66,19,16,51,66,19,32,67,66,19,48,83,66,19,64,99,66,19,80,115, 43,109,31,35,10,60,12,96,128,64,2,35,64,71,8,38,19,64,51,4,64,67,20,64,83, 36,64,115,52,64,99,68,64,3,84,153,40,249,7,48,240,64,4,19,17,4,64,84,3,153, 40,250,4,32,109,55,64,71,8,70,19,64,2,35,64,84,3,153,40,251,7,48,240,64,20, 19,17,20,64,84,3,153,40,252,4,32,109,55,64,71,8,45,19,64,2,35,64,84,3,153, 40,253,7,48,240,64,36,19,17,36,64,84,3,153,40,254,4,32,109,55,64,71,8,71,19, 64,2,35,64,84,3,153,40,255,7,48,240,43,109,19,52,42,18,64,71,8,72,19,64,2, 35,17,52,64,84,3,153,72,0,7,48,240,1,104,19,48,109,23,68,59,68,109,23,23,96, 42,15,109,20,42,16,109,21,42,17,109,22,1,104,20,64,71,8,67,19,64,2,35,17,52, 17,68,64,84,3,153,72,1,7,48,240,61,109,23,1,104,21,64,71,8,68,19,64,2,35,17, 52,17,68,64,84,3,153,72,2,7,48,240,61,109,23,1,104,22,64,71,8,69,19,64,2,35, 17,52,17,68,64,84,3,153,72,3,7,48,240,1,104,23,64,71,8,40,19,64,2,35,64,84, 3,153,72,4,8,48,240,96,1,104,24,66,19,0,35,66,19,16,51,66,19,32,67,66,19,48, 83,66,19,64,99,66,19,80,115,66,19,96,131,43,109,31,35,10,103,12,112,144,64, 2,35,64,71,8,73,19,64,51,4,64,83,20,64,67,36,64,115,52,64,131,68,64,99,84, 64,3,100,153,72,5,7,48,240,64,4,19,136,16,96,64,84,3,153,72,6,4,32,109,55, 16,32,0,69,4,2,35,64,71,8,47,19,136,16,80,64,68,3,153,72,7,7,48,240,64,4,19, 136,16,64,64,52,3,153,72,8,4,32,109,55,16,96,0,69,4,2,51,69,20,51,51,69,36, 51,35,64,71,8,74,19,64,52,3,153,72,9,8,48,240,64,1,104,25,66,19,0,35,66,19, 16,51,66,19,32,67,66,19,48,83,66,19,64,99,66,19,80,115,66,19,96,131,66,19, 112,147,66,19,128,163,43,109,31,35,10,111,12,144,176,64,2,35,64,71,8,38,19, 64,51,4,64,67,20,64,83,36,64,99,52,64,115,68,64,147,84,64,163,100,64,131, 116,64,3,132,153,72,10,7,48,240,64,4,19,136,16,128,64,116,3,153,72,11,4,32, 109,55,64,71,8,41,19,64,2,35,64,116,3,153,72,12,7,48,240,64,4,19,136,16,112, 64,100,3,153,72,13,4,32,109,55,16,32,0,69,4,2,35,64,71,8,47,19,136,16,96,64, 84,3,153,72,14,7,48,240,64,4,19,136,16,80,64,68,3,153,72,15,4,32,109,55,64, 71,8,75,19,64,2,35,64,68,3,153,72,16,7,48,240,16,32,0,69,4,2,35,64,71,8,47, 19,136,16,64,64,52,3,153,72,17,7,48,240,16,96,0,69,4,2,51,69,20,51,51,69,36, 51,35,64,71,8,76,19,64,52,3,153,72,18,8,48,240,64,1,104,26,153,72,19,74,20, 1,104,27,153,72,20,74,20,1,104,28,153,40,189,74,3,1,104,29,153,72,21,74,36, 1,104,30,153,40,213,74,3,1,104,31,16,112,32,70,32,35,71,71,8,77,71,19,70,48, 3,71,18,71,42,10,71,35,153,72,22,7,16,48,1,104,32,153,72,23,2,18,42,19,32,1, 104,33,56,109,35,19,65,19,35,51,52,109,34,51,64,35,19,6,32,109,55,1,104,34, 12,32,64,64,35,19,64,3,4,64,51,20,153,72,24,4,32,109,55,64,71,8,78,19,64,2, 35,64,4,3,153,72,25,7,48,240,64,20,19,64,4,3,5,32,109,33,32,1,104,35,52,109, 32,19,64,42,9,3,19,1,104,36,153,72,26,2,18,42,20,32,1,104,37,56,109,39,19, 65,19,35,51,57,109,40,35,58,109,40,35,32,66,35,0,67,66,35,16,83,52,109,38, 51,13,32,32,96,64,3,20,64,83,4,69,67,2,35,64,71,8,79,19,153,72,27,7,48,240, 64,4,19,136,16,16,64,4,3,153,72,28,4,32,109,55,64,71,8,80,19,64,2,35,64,4,3, 153,72,29,8,48,240,16,1,104,38,13,48,32,96,64,3,36,64,51,20,64,83,4,69,67,2, 35,64,71,8,79,19,153,72,30,7,48,240,64,4,19,136,16,32,64,20,3,153,72,31,4, 32,109,55,64,71,8,81,19,64,2,35,64,20,3,153,72,32,7,48,240,64,4,19,64,20,3, 5,32,109,37,32,1,104,39,52,109,40,19,64,42,9,3,19,1,104,40,6,32,109,33,1, 104,41,153,72,33,2,18,42,21,32,1,104,42,12,32,32,64,3,20,64,19,3,64,3,4,153, 72,34,7,16,8,18,48,109,46,3,59,3,109,46,23,64,10,19,109,43,10,40,109,44,1, 104,43,57,109,45,4,58,109,45,4,48,66,4,0,3,66,4,16,19,43,109,45,3,10,147, 136,16,16,64,19,3,153,72,35,7,16,8,19,16,32,16,69,3,2,35,64,71,8,82,19,64,4, 3,153,72,35,8,48,240,16,1,104,44,57,109,45,4,58,109,45,4,48,66,4,0,3,66,4, 16,19,43,109,45,3,10,147,16,32,32,69,19,2,35,64,71,8,83,19,64,20,3,153,72, 36,8,48,240,32,1,104,45,16,32,0,70,16,19,71,4,153,8,185,74,19,1,104,46,153, 72,34,74,3,1,104,47,153,72,37,2,18,42,24,32,1,104,48,12,32,32,64,3,20,64,19, 3,64,3,4,153,72,38,7,16,8,18,48,109,53,3,59,3,109,53,23,64,10,19,109,49,10, 40,109,50,1,104,49,57,109,52,4,58,109,52,4,48,66,4,0,3,66,4,16,19,43,109,52, 3,10,148,136,16,16,64,19,3,153,72,35,7,16,8,19,16,32,16,69,3,2,35,64,71,8, 82,19,64,4,3,153,72,35,8,48,240,16,1,104,50,57,109,52,4,58,109,52,4,48,66,4, 0,3,66,4,16,19,66,4,32,35,43,109,52,3,10,148,16,32,48,64,35,4,69,19,2,35,64, 71,8,84,19,64,20,3,153,72,39,7,48,240,43,109,51,4,42,25,64,71,8,85,19,64,2, 35,64,20,3,153,72,40,8,48,240,32,1,104,51,64,42,9,3,18,32,19,1,104,52,16,32, 0,70,16,19,71,4,153,8,191,74,19,1,104,53,153,72,38,74,3,1,104,54,153,72,41, 2,18,42,26,32,1,104,55,12,32,32,64,19,4,64,3,20,57,109,56,19,58,109,56,19, 48,66,19,0,35,44,109,61,35,10,148,1,104,56,57,109,65,4,58,109,57,4,48,66,4, 0,3,44,109,60,3,10,147,1,104,57,57,109,65,4,58,109,58,4,32,66,4,0,3,43,109, 58,3,10,159,57,109,62,4,58,109,62,4,32,66,4,0,3,66,4,16,19,43,109,62,3,10, 159,16,32,32,69,19,2,35,64,71,8,86,19,64,20,3,153,72,42,8,48,240,32,1,104, 58,57,109,65,4,58,109,59,4,32,66,4,0,3,43,109,59,3,10,18,57,109,63,4,58,109, 63,4,32,66,4,0,3,66,4,16,19,43,109,63,3,10,18,16,32,32,69,19,2,35,64,71,8, 87,19,64,20,3,153,72,43,8,48,240,32,1,104,59,57,109,65,4,58,109,65,4,32,66, 4,0,3,43,109,65,3,10,232,57,109,64,4,58,109,64,4,32,66,4,0,3,66,4,16,19,43, 109,64,3,10,232,16,32,32,69,19,2,35,64,71,8,88,19,64,20,3,153,72,44,8,48, 240,32,1,104,60,64,4,19,64,20,3,5,32,109,42,32,1,104,61,64,4,19,64,20,3,5, 32,109,48,32,1,104,62,16,32,0,70,16,19,71,4,153,8,200,74,19,1,104,63,16,32, 0,70,16,19,71,4,153,8,197,74,19,1,104,64,16,32,0,70,16,19,71,4,153,8,203,74, 19,1,104,65,16,112,0,70,32,19,71,71,8,89,71,4,70,48,3,71,18,71,42,26,71,19, 153,72,45,7,16,48,1,104,66,153,72,46,2,18,42,27,48,1,104,67,56,109,71,19,65, 19,51,67,52,109,68,67,16,32,64,69,51,2,35,64,71,8,90,19,153,72,47,78,48,240, 1,104,68,13,48,32,80,64,35,36,64,3,20,64,67,4,69,51,2,35,64,71,8,91,19,153, 72,48,7,48,240,43,109,69,36,81,64,71,8,92,19,64,2,35,17,36,64,20,3,153,72, 49,7,48,240,64,1,3,61,109,70,1,104,69,153,72,50,125,5,0,8,20,36,17,3,1,104, 70,64,4,19,64,3,35,64,20,3,5,48,109,67,48,1,104,71,52,109,66,19,64,42,9,3, 19,1,104,72,153,0,2,18,42,29,0,1,104,73,64,18,3,153,0,78,16,8,21,1,104,74, 153,0,2,18,42,29,16,1,104,75,64,3,19,64,18,3,153,0,78,32,8,22,1,104,76,153, 40,102,2,18,42,31,48,1,104,77,56,109,80,3,12,48,48,65,3,51,36,64,19,4,64,35, 20,43,109,78,51,35,64,19,3,61,109,79,1,104,78,64,51,3,1,104,79,64,3,51,64,4, 19,64,20,35,64,36,3,64,51,36,136,32,16,153,40,100,4,48,109,77,16,32,16,69,4, 3,3,18,16,19,1,104,80,52,109,81,3,19,1,104,81,16,32,16,69,3,2,19,64,42,32,3, 153,40,102,7,32,8,23,1,104,82,153,40,90,2,18,42,33,32,1,104,83,56,109,84,3, 12,32,32,65,3,35,20,64,19,3,64,35,19,64,3,4,153,40,90,4,32,77,160,64,3,35, 64,4,19,64,20,3,64,35,20,136,16,16,153,40,90,4,32,109,83,16,32,16,69,4,3,3, 18,16,19,1,104,84,52,109,85,3,19,1,104,85,16,32,16,69,3,2,19,64,42,32,3,153, 40,90,7,32,8,23,1,104,86,153,72,51,2,18,42,34,16,1,104,87,56,109,89,3,65,3, 19,35,57,109,88,19,58,109,88,19,32,12,16,48,66,19,16,4,64,35,3,153,72,51,4, 16,109,87,16,32,16,69,4,3,3,18,16,19,1,104,88,64,35,3,6,16,109,87,1,104,89, 52,109,90,3,19,1,104,90,16,32,16,70,16,19,71,3,153,72,51,74,19,1,104,91,153, 8,43,2,18,42,35,32,1,104,92,56,109,94,3,65,3,35,51,57,109,93,35,58,109,93, 35,32,12,48,64,66,35,0,67,66,35,16,36,64,19,3,64,67,19,64,3,4,64,51,20,153, 8,43,4,32,77,160,64,3,35,64,4,19,64,20,3,64,35,20,136,16,32,153,8,43,4,32, 109,92,16,80,16,70,32,19,71,4,71,20,69,19,3,3,18,32,19,1,104,93,64,51,3,6, 32,109,92,1,104,94,52,109,95,3,19,1,104,95,16,32,16,69,3,2,19,64,42,32,3, 153,8,43,7,32,8,23,1,104,96,153,8,40,2,18,42,36,32,1,104,97,56,109,99,3,65, 3,35,51,57,109,98,35,58,109,98,35,32,12,48,64,66,35,0,36,66,35,16,83,64,19, 3,64,83,19,64,3,4,64,51,20,153,8,40,4,32,77,160,64,3,35,64,4,19,64,20,3,64, 35,20,136,16,32,153,8,40,4,32,109,97,16,80,16,70,32,19,71,20,71,4,69,19,3,3, 18,32,19,1,104,98,64,51,3,6,32,109,97,1,104,99,52,109,100,3,19,1,104,100,16, 32,16,69,3,2,19,64,42,32,3,153,8,40,7,32,8,23,3,0,83,116,114,84,0,0,0,0,73, 109,112,84,0,0,1,36,0,0,0,24,0,0,0,10,0,0,0,11,0,0,0,3,0,0,0,10,0,0,0,12,0, 0,0,1,0,0,0,10,0,0,0,26,0,0,0,1,0,0,0,10,0,0,0,30,0,0,0,1,0,0,0,38,0,0,0,39, 0,0,0,3,0,0,0,38,0,0,0,46,0,0,0,3,0,0,0,98,0,0,0,99,0,0,0,1,0,0,0,184,0,0,0, 185,0,0,0,1,0,0,0,98,0,0,0,212,0,0,0,1,0,0,0,184,0,0,0,237,0,0,0,0,0,0,0,10, 0,0,0,238,0,0,0,2,0,0,0,184,0,0,0,239,0,0,0,0,0,0,0,184,0,0,0,240,0,0,0,0,0, 0,0,184,0,0,0,242,0,0,0,0,0,0,0,38,0,0,0,246,0,0,0,1,0,0,1,5,0,0,1,6,0,0,0, 3,0,0,1,7,0,0,1,2,0,0,0,4,0,0,1,5,0,0,1,6,0,0,0,2,0,0,0,184,0,0,1,22,0,0,0, 1,0,0,0,184,0,0,1,23,0,0,0,1,0,0,0,10,0,0,1,28,0,0,0,2,0,0,0,10,0,0,1,30,0, 0,0,1,0,0,0,10,0,0,1,30,0,0,0,2,0,0,0,10,0,0,0,12,0,0,0,2,69,120,112,84,0,0, 9,4,0,0,0,192,0,0,1,29,0,0,0,1,0,0,3,75,0,0,1,29,0,0,0,0,0,0,3,73,0,0,1,26, 0,0,0,2,0,0,3,55,0,0,1,24,0,0,0,2,0,0,3,48,0,0,1,21,0,0,0,2,0,0,3,42,0,0,1, 10,0,0,0,2,0,0,2,219,0,0,1,2,0,0,0,2,0,0,2,205,0,0,1,4,0,0,0,1,0,0,2,203,0, 0,1,2,0,0,0,1,0,0,2,201,0,0,1,1,0,0,0,3,0,0,2,181,0,0,0,253,0,0,0,1,0,0,2, 177,0,0,0,252,0,0,0,1,0,0,2,164,0,0,0,249,0,0,0,2,0,0,2,131,0,0,0,245,0,0,0, 2,0,0,2,46,0,0,0,244,0,0,0,2,0,0,1,251,0,0,0,241,0,0,0,1,0,0,1,230,0,0,0, 236,0,0,0,1,0,0,1,204,0,0,0,235,0,0,0,1,0,0,1,202,0,0,0,234,0,0,0,1,0,0,1, 199,0,0,0,233,0,0,0,1,0,0,1,197,0,0,0,231,0,0,0,1,0,0,1,195,0,0,0,230,0,0,0, 1,0,0,1,192,0,0,0,229,0,0,0,1,0,0,1,190,0,0,0,228,0,0,0,1,0,0,1,188,0,0,0, 227,0,0,0,1,0,0,1,185,0,0,0,226,0,0,0,1,0,0,1,183,0,0,0,225,0,0,0,0,0,0,1, 181,0,0,0,223,0,0,0,1,0,0,1,176,0,0,0,222,0,0,0,2,0,0,1,173,0,0,0,221,0,0,0, 1,0,0,1,171,0,0,0,220,0,0,0,1,0,0,1,169,0,0,0,219,0,0,0,0,0,0,1,167,0,0,0, 217,0,0,0,2,0,0,1,165,0,0,0,217,0,0,0,1,0,0,1,163,0,0,0,216,0,0,0,1,0,0,1, 160,0,0,0,215,0,0,0,1,0,0,1,158,0,0,0,214,0,0,0,1,0,0,1,156,0,0,0,213,0,0,0, 0,0,0,1,154,0,0,0,211,0,0,0,0,0,0,1,152,0,0,0,210,0,0,0,1,0,0,1,150,0,0,0, 209,0,0,0,1,0,0,1,148,0,0,0,208,0,0,0,1,0,0,1,144,0,0,0,207,0,0,0,2,0,0,1, 141,0,0,0,206,0,0,0,1,0,0,1,139,0,0,0,204,0,0,0,2,0,0,1,137,0,0,0,202,0,0,0, 1,0,0,1,129,0,0,0,200,0,0,0,1,0,0,1,121,0,0,0,198,0,0,0,2,0,0,1,114,0,0,0, 197,0,0,0,1,0,0,1,112,0,0,0,196,0,0,0,1,0,0,1,110,0,0,0,195,0,0,0,2,0,0,1, 107,0,0,0,194,0,0,0,1,0,0,1,105,0,0,0,192,0,0,0,3,0,0,1,103,0,0,0,191,0,0,0, 1,0,0,1,101,0,0,0,190,0,0,0,1,0,0,1,99,0,0,0,189,0,0,0,1,0,0,1,97,0,0,0,188, 0,0,0,2,0,0,1,94,0,0,0,187,0,0,0,1,0,0,1,92,0,0,0,183,0,0,0,4,0,0,1,90,0,0, 0,182,0,0,0,1,0,0,1,88,0,0,0,181,0,0,0,1,0,0,1,86,0,0,0,180,0,0,0,1,0,0,1, 84,0,0,0,178,0,0,0,3,0,0,1,82,0,0,0,177,0,0,0,1,0,0,1,80,0,0,0,176,0,0,0,1, 0,0,1,78,0,0,0,175,0,0,0,2,0,0,1,75,0,0,0,174,0,0,0,1,0,0,1,73,0,0,0,172,0, 0,0,3,0,0,1,71,0,0,0,171,0,0,0,1,0,0,1,68,0,0,0,170,0,0,0,1,0,0,1,66,0,0,0, 168,0,0,0,1,0,0,1,64,0,0,0,167,0,0,0,1,0,0,1,62,0,0,0,166,0,0,0,1,0,0,1,60, 0,0,0,165,0,0,0,2,0,0,1,57,0,0,0,164,0,0,0,1,0,0,1,55,0,0,0,162,0,0,0,3,0,0, 1,53,0,0,0,161,0,0,0,1,0,0,1,51,0,0,0,158,0,0,0,1,0,0,1,48,0,0,0,157,0,0,0, 1,0,0,1,46,0,0,0,155,0,0,0,1,0,0,1,44,0,0,0,153,0,0,0,1,0,0,1,39,0,0,0,152, 0,0,0,1,0,0,1,37,0,0,0,151,0,0,0,1,0,0,1,35,0,0,0,149,0,0,0,3,0,0,1,31,0,0, 0,144,0,0,0,1,0,0,1,16,0,0,0,143,0,0,0,2,0,0,1,13,0,0,0,142,0,0,0,1,0,0,1, 11,0,0,0,141,0,0,0,1,0,0,1,9,0,0,0,140,0,0,0,1,0,0,1,7,0,0,0,139,0,0,0,1,0, 0,1,5,0,0,0,138,0,0,0,1,0,0,1,3,0,0,0,137,0,0,0,2,0,0,1,0,0,0,0,136,0,0,0,1, 0,0,0,254,0,0,0,135,0,0,0,2,0,0,0,251,0,0,0,134,0,0,0,1,0,0,0,249,0,0,0,130, 0,0,0,6,0,0,0,245,0,0,0,130,0,0,0,7,0,0,0,241,0,0,0,129,0,0,0,1,0,0,0,238,0, 0,0,128,0,0,0,1,0,0,0,236,0,0,0,126,0,0,0,1,0,0,0,234,0,0,0,125,0,0,0,1,0,0, 0,232,0,0,0,124,0,0,0,1,0,0,0,230,0,0,0,123,0,0,0,1,0,0,0,228,0,0,0,122,0,0, 0,3,0,0,0,226,0,0,0,120,0,0,0,2,0,0,0,224,0,0,0,119,0,0,0,1,0,0,0,222,0,0,0, 118,0,0,0,1,0,0,0,220,0,0,0,117,0,0,0,1,0,0,0,218,0,0,0,116,0,0,0,1,0,0,0, 216,0,0,0,115,0,0,0,1,0,0,0,214,0,0,0,114,0,0,0,1,0,0,0,212,0,0,0,113,0,0,0, 1,0,0,0,210,0,0,0,112,0,0,0,1,0,0,0,208,0,0,0,110,0,0,0,8,0,0,0,206,0,0,0, 110,0,0,0,7,0,0,0,204,0,0,0,109,0,0,0,1,0,0,0,202,0,0,0,108,0,0,0,1,0,0,0, 200,0,0,0,107,0,0,0,1,0,0,0,198,0,0,0,106,0,0,0,1,0,0,0,196,0,0,0,105,0,0,0, 1,0,0,0,194,0,0,0,104,0,0,0,1,0,0,0,192,0,0,0,102,0,0,0,6,0,0,0,190,0,0,0, 102,0,0,0,5,0,0,0,188,0,0,0,101,0,0,0,1,0,0,0,185,0,0,0,100,0,0,0,1,0,0,0, 183,0,0,0,97,0,0,0,0,0,0,0,181,0,0,0,95,0,0,0,1,0,0,0,179,0,0,0,94,0,0,0,1, 0,0,0,177,0,0,0,93,0,0,0,1,0,0,0,175,0,0,0,92,0,0,0,1,0,0,0,173,0,0,0,91,0, 0,0,1,0,0,0,171,0,0,0,89,0,0,0,4,0,0,0,169,0,0,0,89,0,0,0,3,0,0,0,167,0,0,0, 88,0,0,0,1,0,0,0,165,0,0,0,87,0,0,0,2,0,0,0,162,0,0,0,86,0,0,0,1,0,0,0,160, 0,0,0,85,0,0,0,2,0,0,0,157,0,0,0,84,0,0,0,1,0,0,0,155,0,0,0,82,0,0,0,3,0,0, 0,153,0,0,0,81,0,0,0,1,0,0,0,151,0,0,0,80,0,0,0,1,0,0,0,149,0,0,0,78,0,0,0, 3,0,0,0,147,0,0,0,77,0,0,0,2,0,0,0,144,0,0,0,76,0,0,0,1,0,0,0,142,0,0,0,74, 0,0,0,3,0,0,0,140,0,0,0,73,0,0,0,1,0,0,0,138,0,0,0,72,0,0,0,2,0,0,0,135,0,0, 0,71,0,0,0,1,0,0,0,133,0,0,0,69,0,0,0,2,0,0,0,131,0,0,0,68,0,0,0,1,0,0,0, 129,0,0,0,67,0,0,0,1,0,0,0,127,0,0,0,66,0,0,0,1,0,0,0,125,0,0,0,65,0,0,0,1, 0,0,0,123,0,0,0,64,0,0,0,2,0,0,0,120,0,0,0,63,0,0,0,1,0,0,0,118,0,0,0,59,0, 0,0,5,0,0,0,116,0,0,0,59,0,0,0,3,0,0,0,114,0,0,0,58,0,0,0,1,0,0,0,112,0,0,0, 57,0,0,0,2,0,0,0,109,0,0,0,56,0,0,0,1,0,0,0,107,0,0,0,55,0,0,0,2,0,0,0,104, 0,0,0,54,0,0,0,1,0,0,0,102,0,0,0,53,0,0,0,2,0,0,0,99,0,0,0,52,0,0,0,1,0,0,0, 97,0,0,0,50,0,0,0,4,0,0,0,95,0,0,0,49,0,0,0,3,0,0,0,91,0,0,0,47,0,0,0,2,0,0, 0,74,0,0,0,45,0,0,0,3,0,0,0,71,0,0,0,44,0,0,0,1,0,0,0,68,0,0,0,43,0,0,0,2,0, 0,0,65,0,0,0,42,0,0,0,1,0,0,0,63,0,0,0,37,0,0,0,2,0,0,0,58,0,0,0,36,0,0,0,1, 0,0,0,56,0,0,0,35,0,0,0,1,0,0,0,54,0,0,0,33,0,0,0,1,0,0,0,52,0,0,0,32,0,0,0, 1,0,0,0,50,0,0,0,31,0,0,0,1,0,0,0,48,0,0,0,25,0,0,0,2,0,0,0,45,0,0,0,23,0,0, 0,1,0,0,0,38,0,0,0,21,0,0,0,1,0,0,0,31,0,0,0,17,0,0,0,2,0,0,0,26,0,0,0,16,0, 0,0,2,0,0,0,23,0,0,0,15,0,0,0,1,0,0,0,21,0,0,0,14,0,0,0,1,0,0,0,19,0,0,0,13, 0,0,0,1,0,0,0,17,0,0,0,9,0,0,0,2,0,0,0,14,0,0,0,8,0,0,0,1,0,0,0,12,0,0,0,7, 0,0,0,1,0,0,0,10,0,0,0,6,0,0,0,1,0,0,0,8,0,0,0,5,0,0,0,1,0,0,0,6,0,0,0,4,0, 0,0,1,0,0,0,4,0,0,0,2,0,0,0,8,0,0,0,2,76,105,116,84,0,0,2,239,0,0,6,246,120, 156,125,84,75,79,219,64,16,222,242,78,120,149,82,160,133,170,93,212,3,54,37, 72,165,82,15,64,233,1,84,169,82,14,85,31,39,20,69,27,123,157,88,113,118,163, 245,58,166,170,240,133,63,218,159,210,217,113,214,33,181,193,23,207,124,223, 236,236,55,15,155,16,210,34,132,108,221,245,102,124,82,235,48,95,113,79,42, 223,39,179,74,71,64,108,151,136,185,129,28,113,60,210,39,27,126,24,4,92,113, 161,41,83,161,14,121,12,196,46,16,219,191,250,66,166,130,126,235,133,116, 168,184,207,61,30,199,82,85,223,52,236,133,213,4,139,146,106,9,145,100,62, 48,123,37,166,102,152,54,211,114,0,244,126,137,94,71,58,5,187,29,10,159,223, 64,208,235,82,208,74,158,195,7,32,54,245,212,239,190,124,254,75,236,83,161, 198,99,81,132,117,255,207,44,5,225,141,72,6,114,8,236,78,137,157,15,198,101, 60,47,81,51,129,57,242,178,132,47,6,195,118,34,30,204,55,158,76,21,229,73, 49,170,78,9,115,110,143,152,170,46,13,38,208,1,230,69,137,89,232,40,38,188, 94,53,23,196,90,170,7,148,60,66,193,26,113,163,99,17,22,104,54,75,29,236, 125,159,44,184,180,113,145,9,240,214,193,91,62,59,163,151,145,140,19,197, 235,118,11,1,106,114,22,208,32,17,158,14,165,48,196,83,32,86,128,248,42,2, 121,74,179,212,96,27,128,173,30,95,49,205,126,240,238,0,174,155,128,151,210, 231,247,64,188,233,240,240,16,14,82,120,213,173,148,102,150,158,162,148,103, 224,173,81,120,186,82,75,10,240,68,160,65,225,226,108,56,13,41,174,19,37,28, 91,159,59,205,118,61,205,99,109,216,37,128,230,12,4,246,42,216,53,122,222, 192,241,25,96,1,128,25,60,153,135,157,55,40,246,178,79,54,141,109,22,191,45, 164,115,144,197,7,238,253,176,79,38,172,6,246,188,201,124,13,206,60,56,79, 222,89,180,53,206,148,135,67,209,182,49,249,6,195,210,105,214,117,172,224, 49,56,134,222,2,244,198,156,159,124,87,70,3,189,106,102,195,235,108,216,162, 185,18,236,159,169,5,175,199,30,180,144,40,212,67,60,189,246,242,217,230, 212,26,80,117,67,153,92,247,250,110,131,33,251,36,183,25,13,46,13,150,230, 216,110,185,198,90,1,107,201,28,131,127,141,99,183,195,180,34,78,67,237,245, 232,100,44,244,220,30,188,168,227,7,211,39,91,102,198,121,97,69,81,120,45, 94,228,22,115,210,61,46,204,42,20,249,3,22,70,52,95,15,192,150,1,91,164,141, 80,232,15,39,83,238,251,143,69,123,26,157,223,154,23,163,2,189,197,168,90, 69,21,141,56,236,10,238,23,62,60,97,128,21,80,240,95,185,133,14,234,100,199, 39,129,75,121,20,243,98,69,177,74,56,128,191,190,62,217,125,52,120,15,34, 118,18,145,255,203,191,255,108,210,80,196,90,37,248,145,217,54,29,21,171, 245,39,75,209,65,189,183,246,174,219,163,201,226,198,22,84,216,17,52,71,104, 98,249,142,207,153,239,22,209,69,72,128,38,238,230,85,222,75,92,67,248,119, 160,40,166,186,54,50,103,81,77,115,172,102,19,156,245,58,157,122,254,1,131, 212,181,219,0,76,111,99,84,0,0,1,36,0,0,0,24,0,0,1,36,0,0,0,2,0,0,3,97,0,0, 1,35,0,0,0,2,0,0,3,92,0,0,1,34,0,0,0,1,0,0,3,87,0,0,1,33,0,0,0,2,0,0,3,83,0, 0,1,31,0,0,0,3,0,0,3,77,0,0,1,27,0,0,0,3,0,0,3,67,0,0,1,20,0,0,0,2,0,0,3,37, 0,0,1,19,0,0,0,2,0,0,3,33,0,0,1,8,0,0,0,2,0,0,2,214,0,0,0,251,0,0,0,2,0,0,2, 160,0,0,0,250,0,0,0,2,0,0,2,156,0,0,0,248,0,0,0,3,0,0,2,127,0,0,0,247,0,0,0, 3,0,0,2,123,0,0,0,243,0,0,0,1,0,0,1,245,0,0,0,224,0,0,0,1,0,0,1,179,0,0,0, 209,0,0,0,2,0,0,1,146,0,0,0,203,0,0,0,2,0,0,1,131,0,0,0,201,0,0,0,2,0,0,1, 123,0,0,0,154,0,0,0,1,0,0,1,41,0,0,0,146,0,0,0,1,0,0,1,22,0,0,0,145,0,0,0,1, 0,0,1,19,0,0,0,48,0,0,0,2,0,0,0,87,0,0,0,24,0,0,0,2,0,0,0,40,0,0,0,22,0,0,0, 2,0,0,0,33,65,116,116,114,0,0,0,40,131,108,0,0,0,1,104,2,100,0,3,118,115, 110,108,0,0,0,1,110,16,0,208,99,240,96,14,196,132,132,153,187,39,109,19,43, 204,164,106,106,67,73,110,102,0,0,1,35,131,108,0,0,0,4,104,2,100,0,7,111, 112,116,105,111,110,115,108,0,0,0,6,104,2,100,0,6,111,117,116,100,105,114, 107,0,58,47,104,111,109,101,47,101,99,50,45,117,115,101,114,47,116,109,112, 47,116,109,112,95,49,47,111,116,112,95,115,114,99,95,49,56,46,48,47,108,105, 98,47,104,105,112,101,47,114,116,108,47,46,46,47,101,98,105,110,100,0,18, 119,97,114,110,95,101,120,112,111,114,116,101,100,95,118,97,114,115,100,0, 18,119,97,114,110,95,117,110,117,115,101,100,95,105,109,112,111,114,116,100, 0,6,105,110,108,105,110,101,100,0,6,110,97,116,105,118,101,100,0,10,100,101, 98,117,103,95,105,110,102,111,106,104,2,100,0,7,118,101,114,115,105,111,110, 107,0,3,54,46,48,104,2,100,0,4,116,105,109,101,104,6,98,0,0,7,223,97,8,97,9, 97,9,97,49,97,10,104,2,100,0,6,115,111,117,114,99,101,107,0,63,47,104,111, 109,101,47,101,99,50,45,117,115,101,114,47,116,109,112,47,116,109,112,95,49, 47,111,116,112,95,115,114,99,95,49,56,46,48,47,108,105,98,47,104,105,112, 101,47,114,116,108,47,104,105,112,101,95,114,116,108,46,101,114,108,106,0, 65,98,115,116,0,0,110,53,131,80,0,2,89,172,120,156,204,189,121,156,21,197, 213,62,126,153,187,12,51,44,178,9,136,168,184,160,128,160,66,20,17,183,32, 138,33,34,162,34,174,100,114,153,190,179,115,103,156,133,85,17,21,69,5,212, 160,198,184,38,26,53,121,93,80,113,1,53,46,32,138,138,138,138,68,5,92,16,23, 18,87,92,99,226,242,235,234,238,219,93,231,156,167,170,175,111,222,239,231, 243,227,15,157,91,93,231,212,115,158,115,170,186,186,186,186,78,77,137,147, 216,174,57,59,189,34,59,165,165,181,57,91,217,90,49,109,104,67,34,209,110, 120,77,202,73,148,101,91,91,155,107,167,180,181,230,178,237,156,68,170,170, 182,33,87,83,82,159,232,88,83,219,148,171,104,110,109,216,39,215,220,144, 109,199,106,254,214,73,100,166,54,58,109,13,57,39,209,190,80,211,162,173, 203,62,251,236,59,53,91,155,223,87,213,221,167,70,106,156,226,194,217,199, 85,218,156,171,108,108,118,106,92,192,29,43,27,167,54,85,180,228,154,167, 229,154,91,92,180,137,100,77,210,45,245,43,84,84,213,230,26,28,79,72,149, 166,178,173,141,83,3,21,101,77,5,169,226,234,167,155,179,249,234,92,113,117, 83,173,51,155,114,117,16,185,119,169,38,169,144,7,70,152,76,232,166,106,58, 21,122,99,63,219,178,84,208,96,193,134,182,124,109,99,94,181,80,34,132,218, 242,78,174,170,54,159,115,184,80,178,169,214,169,171,251,175,16,5,220,253, 255,4,141,239,130,255,59,48,117,192,211,251,135,158,118,18,29,60,247,54,54, 181,186,13,16,13,251,211,102,217,37,15,66,157,16,104,109,107,106,200,253,12, 1,191,20,130,60,64,3,217,81,3,217,66,116,168,90,13,181,45,173,170,77,191,55, 182,185,209,85,161,93,214,13,132,13,29,168,53,212,213,27,6,178,205,149,53, 181,173,185,202,214,182,102,234,138,17,58,39,25,226,10,117,41,59,213,25,190, 63,47,77,102,155,167,242,178,210,166,198,233,185,230,166,74,161,161,169,169, 82,106,40,111,107,112,7,188,150,38,5,139,43,159,49,98,56,178,105,164,102, 147,63,180,77,205,54,17,83,70,114,226,244,43,38,63,186,151,182,203,55,230, 43,242,185,234,138,218,124,107,174,58,215,76,93,122,176,57,86,221,75,165, 109,249,250,124,227,244,188,16,49,52,71,180,37,185,182,100,115,174,154,151, 101,170,154,42,64,113,186,165,169,182,161,129,66,61,4,216,82,135,67,241,80, 141,205,78,30,155,173,57,55,166,56,165,135,22,44,81,78,207,207,4,138,14,211, 20,117,246,20,121,192,132,166,195,140,206,57,204,204,214,97,113,206,97,178, 58,71,135,21,56,138,213,40,25,202,78,49,222,113,167,176,154,149,174,135,114, 51,154,26,155,61,203,58,120,247,153,169,245,170,122,182,189,250,81,234,254, 85,81,213,150,119,111,172,238,175,114,245,203,141,250,236,212,22,191,160, 179,42,168,109,169,168,108,104,108,113,187,166,95,216,33,40,108,200,101,171, 252,146,246,170,164,178,209,9,42,108,87,248,89,209,214,228,100,93,20,37,97, 37,247,103,86,171,228,2,206,53,84,120,183,3,77,83,109,190,170,81,171,164, 126,134,154,56,21,45,196,192,165,158,77,174,129,83,27,167,21,154,85,127,86, 56,45,173,65,3,222,207,150,230,74,255,103,71,85,215,237,237,181,145,64,215, 240,183,146,82,65,225,87,213,202,93,241,168,92,241,217,84,83,235,255,40,117, 255,138,26,203,168,95,181,142,118,41,219,92,237,183,210,33,248,165,233,113, 41,13,245,116,86,151,115,110,4,52,87,52,53,231,156,172,55,67,216,78,21,54, 231,60,8,94,105,73,161,253,108,67,91,54,229,53,226,254,165,25,171,126,185, 96,135,6,108,22,126,82,191,4,165,195,104,165,97,164,82,70,149,54,54,5,1,224, 34,109,169,169,173,106,13,75,20,229,13,141,217,0,103,248,43,237,233,87,127, 106,152,188,159,161,3,58,120,63,27,171,170,90,114,65,133,50,191,66,237,172, 28,253,93,157,143,92,230,21,169,174,228,163,235,20,254,142,218,233,28,149, 121,21,189,194,110,5,217,233,106,78,80,235,222,200,103,248,144,187,179,210, 72,79,39,87,164,186,177,181,81,175,221,37,42,8,138,253,8,209,138,189,200,14, 122,209,118,33,98,199,105,206,181,180,4,74,244,162,168,189,174,164,88,253, 223,47,239,45,202,137,131,168,152,26,79,10,241,94,95,209,210,218,232,246, 221,36,253,233,133,75,185,247,119,197,148,108,75,129,108,191,32,234,31,254, 111,221,63,129,76,228,32,165,211,51,55,242,79,62,55,61,40,74,120,34,126,63, 207,103,167,22,68,212,240,17,137,148,185,34,83,220,81,160,178,198,15,25,237, 119,198,11,18,255,135,22,202,90,201,48,90,82,217,152,15,58,92,215,160,164, 181,185,45,167,183,214,45,40,175,202,54,180,144,11,5,21,94,223,10,227,218, 141,252,41,217,82,242,171,125,161,223,76,137,252,86,230,253,140,16,150,122, 191,11,29,36,188,58,76,255,29,97,221,206,251,205,145,118,241,74,5,78,95,56, 66,169,232,106,153,94,219,234,210,229,197,66,23,245,219,29,17,221,233,112, 80,156,244,29,231,253,136,156,219,41,40,208,99,181,107,161,146,43,95,225, 118,135,92,115,196,132,10,239,32,6,188,72,215,32,149,186,14,141,46,171,202, 149,217,134,6,223,123,225,47,143,196,246,234,207,232,150,211,209,251,73,6, 218,238,122,17,9,114,191,50,25,53,187,122,69,46,145,173,181,249,182,172,154, 114,6,156,248,205,100,107,27,244,223,81,191,232,224,253,206,55,54,79,205,22, 194,66,43,33,173,118,9,85,145,98,101,178,103,86,216,9,188,241,218,231,186, 204,31,187,67,51,59,249,191,9,244,114,191,44,194,164,252,216,156,115,231, 192,249,194,221,215,251,81,49,45,219,28,73,169,74,213,149,173,185,194,239, 142,254,15,111,236,10,124,88,174,8,111,156,58,213,213,95,32,217,255,229,206, 162,102,20,26,87,232,245,58,202,128,170,104,12,47,171,162,195,118,240,59,26, 24,170,228,192,173,52,104,99,77,135,42,62,186,148,87,177,225,165,83,149,28, 95,210,74,77,147,63,62,169,217,101,8,161,212,253,161,245,47,255,87,208,159, 210,85,77,97,95,43,247,20,84,180,229,221,130,0,136,255,43,82,21,150,132,72, 202,11,37,5,45,30,31,209,172,160,172,138,206,35,130,223,161,188,87,221,13, 195,105,133,234,234,111,189,186,247,59,172,174,110,218,174,91,233,143,146,2, 122,53,124,170,130,68,97,94,16,86,45,115,255,210,111,57,29,213,239,134,218, 105,185,188,186,175,248,221,71,47,34,17,219,65,97,172,157,145,111,155,90,96, 166,99,225,103,132,52,42,210,188,84,40,138,98,213,155,69,230,170,163,123, 164,251,195,141,203,150,108,85,46,242,130,178,67,85,242,236,232,26,21,20,42, 134,246,133,154,202,154,189,153,111,104,95,39,239,119,11,209,92,184,193,84, 53,133,186,213,253,196,255,89,112,47,211,163,224,214,78,157,26,205,180,194, 31,101,238,95,46,191,13,109,129,246,206,94,231,201,187,61,74,27,222,186,106, 37,122,121,103,175,23,177,202,41,183,151,7,190,72,185,207,198,133,78,217, 210,54,69,13,103,170,192,159,180,248,5,254,90,66,80,86,90,248,229,27,234, 142,240,181,205,238,83,113,69,221,212,192,97,106,208,137,152,40,105,106,138, 254,240,39,115,77,77,21,83,26,26,43,235,3,124,193,116,144,142,103,97,108, 178,226,66,143,39,197,157,252,46,72,202,186,105,29,138,92,216,14,170,232, 197,103,58,228,106,15,50,121,35,151,250,128,89,25,169,208,93,143,95,58,171, 117,137,168,205,171,117,75,127,254,234,254,12,187,152,250,161,98,37,252,17, 206,202,187,105,179,114,58,189,242,167,222,129,59,252,41,57,120,220,108,36, 79,35,254,157,61,242,123,69,67,195,180,169,226,17,70,201,157,233,198,172,47, 231,117,177,80,88,155,38,36,128,216,116,178,244,153,116,91,85,146,101,112, 221,107,58,121,252,116,37,147,238,205,9,214,156,65,106,206,80,83,25,159,17, 88,123,38,169,61,51,184,179,248,207,139,80,96,22,17,152,229,199,180,122,150, 132,181,103,147,218,179,221,191,213,131,37,172,122,22,169,122,150,251,183, 122,218,132,85,207,38,85,207,14,198,85,243,146,238,92,82,127,174,122,108, 137,158,92,149,95,132,196,185,68,226,92,247,111,245,24,235,185,41,95,219, 224,149,213,213,164,221,56,117,189,80,169,166,45,170,104,158,246,116,238, 199,128,91,35,83,217,144,117,163,199,187,174,10,219,43,205,73,23,111,32,145, 28,227,251,81,43,42,29,213,92,61,46,112,152,94,60,58,114,139,86,156,26,23, 144,175,151,141,14,88,214,203,142,12,232,212,202,218,79,202,54,159,80,160, 77,43,47,31,167,248,241,174,212,213,133,139,42,65,176,170,58,23,68,241,218, 30,18,120,1,33,240,130,40,94,11,173,92,16,152,94,148,176,30,194,154,130,144, 168,162,148,132,161,167,105,240,137,66,226,23,18,241,11,181,112,44,136,95, 88,224,180,40,113,214,175,52,37,161,95,139,210,163,119,55,29,137,23,5,72, 195,124,162,97,62,239,44,5,29,243,245,104,40,74,15,233,68,84,19,137,31,217, 81,46,210,87,174,80,79,185,8,197,220,69,81,204,181,131,8,47,34,8,47,146,49, 119,145,31,115,117,133,152,70,151,4,216,139,217,194,26,194,123,49,194,123, 113,28,222,139,9,222,139,113,152,95,28,133,57,194,77,46,11,236,151,128,53, 64,132,255,18,132,255,146,56,252,151,16,252,151,24,99,252,146,40,198,145,9, 228,178,48,97,1,95,177,68,248,23,32,252,11,226,240,47,32,248,23,224,190,181, 32,232,91,8,121,116,77,192,94,72,150,85,17,230,133,8,243,194,56,204,11,9, 230,133,96,84,91,24,140,106,8,112,116,77,0,94,132,22,126,17,238,69,225,106, 120,65,171,43,154,60,161,181,129,21,5,13,69,42,34,43,23,1,233,56,195,23,17, 195,23,1,195,163,54,165,117,151,146,5,108,100,214,165,200,29,151,198,161, 186,148,160,186,20,220,37,46,13,238,18,200,29,209,53,1,120,49,90,98,71,184, 23,35,220,139,227,112,47,38,184,23,155,7,243,197,124,48,23,70,240,26,194, 148,43,201,123,1,100,195,149,200,134,43,227,108,184,146,216,112,101,97,142, 166,65,83,101,99,221,50,4,59,186,38,0,95,133,222,92,32,220,87,137,174,112, 149,236,10,87,133,13,161,174,112,21,144,142,51,252,42,98,248,85,192,240,168, 77,254,194,5,239,246,0,123,51,178,59,209,167,19,247,81,70,33,74,137,9,118, 118,167,16,142,146,73,58,224,73,131,213,73,169,117,160,184,74,37,141,77,197, 232,25,198,45,220,153,224,78,169,71,176,112,222,77,149,237,28,41,219,217,4, 156,214,49,0,167,149,32,112,169,103,88,108,37,245,224,24,87,169,60,90,116, 142,171,218,65,91,137,142,171,219,174,137,211,186,11,161,53,227,175,181,135, 175,245,169,174,93,34,93,187,24,73,147,149,0,35,172,18,102,132,86,178,50,66, 171,218,25,161,117,37,35,253,104,160,169,197,100,197,71,169,212,212,47,210, 212,79,173,18,249,107,227,113,245,224,19,62,215,101,122,182,103,245,162,157, 33,150,74,29,245,117,120,89,121,215,168,242,174,106,189,41,91,219,64,4,248, 80,197,4,186,249,107,243,68,36,120,158,206,238,202,185,221,141,112,91,26,44, 117,135,131,56,109,103,183,168,157,221,148,169,185,25,173,92,223,238,68,95, 218,91,186,199,219,203,178,187,71,218,118,55,57,129,214,49,59,129,214,67,27, 201,178,123,80,100,222,226,94,120,91,161,218,246,136,180,237,97,26,175,88, 29,183,87,241,6,251,147,6,219,23,150,224,12,108,244,143,244,245,55,181,201, 234,180,248,219,110,108,117,32,19,123,50,38,212,234,161,1,213,158,145,182, 61,77,168,88,29,136,138,214,201,248,239,49,56,174,189,24,46,245,230,192,224, 161,189,34,125,123,153,112,177,58,192,67,3,72,131,37,85,77,134,27,239,128, 72,211,0,83,107,180,142,97,40,166,149,224,253,75,234,17,55,222,129,180,207, 6,139,204,6,15,14,140,244,13,52,97,103,117,160,7,105,29,23,58,71,53,136,222, 183,252,55,86,6,80,131,34,101,174,88,74,189,249,138,171,20,196,76,92,53,228, 230,189,41,50,255,69,160,97,136,219,59,210,230,138,165,189,183,133,92,223, 96,122,63,82,239,115,13,218,6,71,218,92,161,180,119,255,227,218,134,16,109, 229,209,222,8,3,119,67,34,157,174,104,218,123,139,17,91,203,83,24,87,43,227, 191,224,230,0,233,198,97,223,8,131,189,209,166,81,37,149,82,27,25,184,182, 125,41,121,133,177,39,45,149,237,27,41,219,215,20,185,172,14,140,92,90,199, 24,71,180,90,74,237,219,40,162,82,117,158,27,184,31,221,103,173,191,211,49, 120,116,191,72,233,126,38,67,105,157,148,82,24,91,9,141,253,67,9,186,178, 240,157,146,97,156,29,26,105,28,106,130,70,235,164,194,237,180,90,171,195, 72,171,219,177,215,85,6,90,134,69,122,135,153,218,166,117,76,157,129,213, 242,26,229,16,127,65,227,210,114,239,249,69,164,237,23,38,92,172,14,24,148, 246,167,142,8,55,205,25,26,141,246,222,42,73,243,204,150,213,11,118,224,241, 198,15,160,143,156,77,53,181,6,31,28,16,169,59,192,100,43,173,83,82,11,30, 28,104,149,194,52,142,163,26,78,199,105,127,87,135,97,164,25,30,105,116,197, 74,131,173,31,92,227,129,116,232,10,111,73,224,30,127,96,164,240,64,227,45, 137,86,50,14,37,180,26,30,149,88,123,106,184,225,232,71,80,62,252,29,71,6, 71,141,136,212,141,48,53,73,235,4,163,189,124,154,160,213,202,130,29,82,83, 102,134,15,17,35,192,43,214,107,225,114,135,59,247,247,46,138,149,159,155, 244,237,167,104,197,231,38,177,226,227,138,36,143,164,75,246,170,232,68,183, 107,213,249,164,164,212,166,152,172,203,145,119,45,180,34,168,153,246,158, 65,189,109,196,234,9,18,214,9,247,71,136,85,172,160,245,186,255,231,141,156, 24,12,21,218,210,213,77,100,60,66,11,85,162,141,66,79,229,228,21,39,28,68, 143,160,89,174,224,221,76,54,14,35,71,222,140,150,28,111,214,44,194,75,111, 55,19,80,55,75,139,110,14,28,2,86,28,195,75,2,238,159,213,38,211,0,174,117, 193,241,207,34,252,92,209,118,199,178,130,204,248,220,116,175,161,208,51,81, 104,252,153,24,240,103,24,26,162,142,57,52,180,214,216,194,230,159,5,202,88, 114,69,187,156,92,221,54,201,226,45,100,123,56,162,239,22,228,244,91,98,113, 221,66,112,221,34,35,241,150,48,18,5,65,225,37,1,247,214,130,211,93,101,86, 167,223,42,156,126,43,119,250,173,62,49,225,160,195,156,126,43,49,224,86, 232,116,81,199,236,116,173,53,230,244,91,5,202,88,114,69,187,156,92,221,54, 201,226,93,14,255,8,0,81,120,151,160,208,149,43,117,227,136,111,179,80,197, 110,75,254,235,212,232,147,145,202,172,175,103,137,210,235,62,100,122,127, 187,82,135,142,60,148,144,184,132,24,179,68,221,205,114,249,234,214,26,65, 225,146,168,249,186,255,189,134,2,82,31,40,53,249,238,80,34,212,118,183,154, 124,55,183,229,180,48,149,215,152,154,123,100,213,123,10,241,163,109,13,9, 241,223,75,170,222,235,254,157,155,81,27,61,213,250,223,211,120,151,228,55, 74,247,234,159,149,178,11,196,201,84,211,210,80,83,166,197,189,245,231,171, 189,194,250,68,87,167,182,170,42,215,156,203,183,246,203,54,215,182,214,230, 90,128,28,253,172,103,41,157,195,22,184,94,170,123,171,24,29,193,252,150, 235,8,35,171,240,81,144,214,117,238,151,179,109,212,93,238,39,109,221,143, 241,222,175,5,119,113,74,0,224,251,9,96,209,241,30,192,159,218,160,222,247, 0,26,118,31,224,246,226,225,225,1,2,245,1,108,239,3,154,127,192,24,76,46,11, 67,30,116,18,189,133,33,214,1,249,65,49,154,60,200,7,100,183,160,220,191,83, 69,67,9,127,245,247,160,208,80,28,37,15,18,74,30,196,148,112,0,210,238,101, 248,155,40,100,240,50,228,192,101,197,161,93,70,208,46,195,177,182,140,196, 154,112,32,185,44,12,89,78,28,24,104,183,58,112,185,112,224,114,238,192,229, 62,127,228,94,192,29,184,92,104,40,142,146,229,132,146,229,152,18,14,64,218, 189,82,251,120,13,89,185,82,240,232,74,36,39,101,155,241,150,190,149,250,19, 55,130,189,146,192,94,41,167,103,129,250,226,132,131,7,242,255,149,108,248, 194,69,219,143,185,18,81,180,74,255,164,15,113,180,10,49,177,42,98,2,59,112, 21,1,180,74,50,177,202,252,20,16,94,18,96,159,10,190,27,140,123,8,120,74,68, 175,43,153,156,80,83,203,138,200,99,0,143,221,167,128,124,156,217,79,17,179, 159,146,102,63,101,157,159,63,173,125,81,137,236,122,26,249,226,233,56,80, 79,19,80,79,139,192,82,37,99,29,228,137,194,21,1,116,181,218,127,238,239,36, 55,236,247,91,45,148,173,246,41,212,186,86,73,67,165,119,129,213,106,119,74, 88,163,125,117,46,159,107,206,250,43,21,171,233,196,98,181,112,178,146,173, 16,202,232,236,113,53,33,99,53,253,78,213,140,25,112,240,140,254,197,43,162, 224,25,1,240,25,25,133,110,81,106,66,115,206,161,51,69,95,193,179,4,249,179, 129,223,167,54,182,6,87,117,75,158,85,11,252,174,9,45,188,180,180,62,55,179, 170,54,31,189,39,44,180,252,108,208,178,42,43,13,190,197,246,202,179,237,88, 187,76,163,149,177,103,117,47,243,25,247,115,114,170,252,156,109,170,188, 134,84,93,99,158,42,175,145,83,229,53,166,169,242,154,200,111,38,37,218,44, 121,77,125,162,231,73,222,17,3,253,92,179,250,169,15,35,114,149,185,150,150, 198,102,221,234,53,145,99,153,190,18,97,66,83,192,185,38,27,68,64,16,101,26, 97,207,3,91,159,23,97,245,60,143,251,231,11,119,49,217,165,163,75,50,162,95, 228,95,109,163,168,126,17,141,65,47,198,141,65,47,18,26,94,196,27,121,95, 180,111,228,37,151,5,248,181,134,143,91,144,13,107,5,133,174,116,187,9,172, 64,77,46,194,246,208,29,98,173,208,16,71,195,90,66,195,90,76,3,111,90,218, 250,146,19,125,76,143,250,217,75,200,71,47,249,224,234,208,179,237,75,134, 103,219,151,133,19,94,86,177,134,84,188,28,117,100,129,247,21,240,189,63, 242,203,43,98,144,122,69,142,152,175,104,227,150,94,77,155,182,81,55,173, 211,107,174,43,238,70,190,142,216,182,78,115,148,55,62,53,230,91,194,90,81, 207,92,39,194,106,29,192,186,46,192,74,70,186,117,108,112,23,237,131,193, 221,45,45,115,7,119,39,215,144,107,205,9,230,214,25,134,247,117,108,120,23, 45,89,135,247,117,209,13,81,186,249,85,116,130,3,242,243,171,130,168,87,165, 159,95,37,119,70,182,94,183,94,175,185,158,116,24,98,221,122,198,235,122,98, 237,122,200,235,122,43,175,235,13,188,174,103,188,138,150,172,188,174,47, 240,74,38,0,127,215,171,252,157,88,137,186,253,107,218,29,52,136,208,215, 116,13,175,185,127,186,226,250,51,193,107,240,21,204,235,52,174,95,23,238, 122,221,109,183,98,92,97,83,160,86,234,71,54,43,83,109,18,253,111,232,53, 222,112,194,55,28,33,121,111,16,242,222,136,158,81,4,113,111,4,196,17,222, 54,80,252,27,244,101,74,191,129,13,164,129,13,182,181,220,13,78,244,2,233, 127,43,31,142,77,220,101,27,193,13,126,163,156,55,108,12,198,103,88,88,135, 166,78,27,121,213,240,115,111,225,204,141,142,120,63,183,177,128,153,193, 221,4,224,110,146,112,55,133,235,231,176,20,2,222,196,235,22,94,51,10,188, 155,36,222,77,116,86,163,33,126,91,246,137,183,117,201,183,249,220,233,109, 253,6,71,111,36,239,232,245,222,41,238,70,242,14,49,235,29,124,199,127,135, 223,241,193,224,250,174,147,232,18,140,32,174,84,133,247,209,45,30,93,223, 21,140,189,43,71,87,183,40,125,162,210,1,135,215,45,122,213,45,98,120,13,30, 220,182,208,64,216,34,218,221,82,24,43,117,71,111,33,140,108,81,179,109,133, 99,40,146,246,33,178,66,182,64,67,158,17,139,135,4,116,218,97,90,199,239,45, 225,248,77,67,230,61,189,210,123,197,133,204,123,164,229,247,112,200,188,23, 59,73,124,31,127,212,141,34,230,125,113,151,123,159,207,135,221,130,210,227, 26,28,78,157,42,118,97,68,247,105,118,39,249,64,175,252,65,232,80,189,59, 126,64,93,246,129,112,217,7,184,233,15,180,166,245,91,218,7,20,193,135,186, 204,135,166,80,254,144,130,248,80,222,49,62,36,94,249,208,28,182,31,162,176, 253,176,48,153,97,133,94,220,225,80,198,144,128,78,164,210,14,221,26,202,31, 42,215,139,64,222,170,87,217,90,204,179,206,86,210,234,86,28,198,91,99,195, 248,51,39,58,0,12,197,238,103,170,48,165,235,252,76,222,31,220,162,212,137, 193,198,94,173,172,228,184,38,80,107,24,94,253,253,220,173,24,126,226,131, 12,254,156,24,172,170,179,197,191,207,29,243,94,14,33,28,110,68,214,164,125, 27,138,18,15,182,40,107,194,202,216,162,91,30,6,90,30,134,220,179,77,63,146, 13,249,103,27,226,114,91,196,37,14,158,109,4,212,54,201,229,54,199,184,126, 28,94,18,96,191,0,7,134,32,204,95,136,190,246,133,154,198,54,180,177,34,235, 250,241,23,64,62,206,236,47,136,217,95,72,179,245,70,165,125,95,146,19,241, 144,101,95,34,111,124,25,7,235,75,2,235,75,16,156,95,6,193,137,252,17,93,19, 128,191,66,103,246,33,220,95,9,143,124,37,61,242,21,219,227,193,61,242,21, 144,143,51,253,43,98,250,87,192,116,189,85,105,225,215,228,252,65,100,218, 215,200,37,95,199,225,250,154,224,250,26,244,218,175,163,94,43,92,18,93,19, 128,191,65,39,36,34,220,223,8,151,124,35,93,242,77,140,75,190,1,242,113,166, 127,67,76,255,6,152,254,141,213,37,223,58,209,105,143,200,176,111,145,67, 190,141,67,245,45,65,245,173,24,129,191,245,70,96,228,140,194,21,1,244,7, 253,220,73,132,244,7,49,111,251,65,222,251,84,209,137,116,195,144,91,148,57, 206,255,146,7,60,137,253,64,44,209,64,168,170,233,255,166,53,174,56,165,182, 146,243,194,246,109,121,181,59,223,91,16,23,148,252,168,31,190,137,40,249, 81,128,252,81,130,252,81,130,252,145,128,212,74,83,39,6,223,19,208,178,234, 124,97,190,171,195,255,9,60,167,151,36,10,133,36,162,74,232,71,20,32,164,74, 200,67,181,170,207,238,6,94,145,97,66,1,132,233,174,49,175,72,145,80,148, 176,182,99,90,147,47,48,86,148,138,240,195,12,77,129,79,110,177,226,213,121, 41,94,157,7,97,82,146,36,167,178,130,56,41,73,130,78,174,196,66,151,192,94, 94,66,220,173,234,115,151,36,141,243,146,232,146,128,155,66,7,139,33,212,41, 62,230,42,209,118,227,88,129,109,90,82,146,18,210,177,70,167,136,209,41,105, 116,202,54,43,41,73,147,51,113,145,89,105,228,140,116,44,174,52,193,149,150, 33,158,118,76,187,78,163,75,2,110,166,224,140,152,93,167,37,25,225,140,12, 119,70,198,126,251,43,201,8,233,88,163,201,25,241,74,134,27,157,177,221,252, 74,74,249,137,196,200,178,82,228,143,210,88,104,165,4,90,41,28,53,74,181,91, 143,244,138,126,85,64,111,239,36,186,105,208,173,190,105,47,124,211,158,251, 198,45,40,115,121,162,247,65,234,158,246,66,65,44,7,237,9,7,237,33,7,172, 101,105,105,25,61,36,26,25,88,134,92,84,22,11,175,140,192,43,3,163,114,89, 48,42,35,247,68,215,4,228,114,122,142,53,130,92,142,32,151,199,66,46,39,144, 203,193,157,160,60,186,19,8,200,209,53,1,185,139,195,143,218,70,168,187,136, 72,234,34,38,20,170,40,53,74,125,62,135,86,14,212,85,254,189,30,50,180,11, 49,180,139,28,102,11,13,23,37,236,253,141,49,74,42,186,202,35,198,17,23,93, 145,117,93,185,117,216,141,93,9,192,174,210,186,174,230,59,103,120,73,0,239, 102,60,94,19,225,239,38,124,217,141,143,10,221,98,110,159,221,132,116,113, 230,119,35,230,119,147,230,119,179,222,67,187,131,243,222,145,133,221,145, 135,186,23,7,177,59,129,216,29,132,80,247,40,132,132,143,162,107,2,252,246, 134,115,233,145,1,219,243,71,26,37,205,187,155,91,148,62,162,240,197,168,94, 56,214,251,64,20,118,194,158,166,207,87,17,21,61,9,21,61,165,183,122,90,186, 162,16,142,190,110,213,196,3,3,138,83,16,126,5,174,43,8,140,149,124,247,50, 29,247,143,8,239,133,200,234,133,201,194,113,211,139,192,237,37,201,234,101, 238,217,189,140,61,187,119,204,233,184,200,150,222,162,127,247,230,253,187, 119,76,255,238,45,164,127,14,21,189,9,21,189,37,21,189,173,189,124,7,39,177, 61,183,57,56,236,24,153,187,3,114,221,14,63,7,239,14,4,239,14,40,84,119,40, 132,42,114,159,118,81,24,211,7,24,19,28,88,141,140,233,131,140,233,243,115, 140,233,67,140,233,131,186,77,31,173,219,8,99,180,139,194,152,190,50,79,6, 50,162,175,24,189,250,162,161,170,111,161,37,86,152,25,231,159,227,0,7,176, 157,192,25,19,136,134,157,8,13,59,33,159,238,100,29,126,164,2,193,227,78, 161,1,69,41,40,124,177,76,53,132,214,74,186,119,166,41,72,44,125,96,103,68, 213,206,130,42,28,49,59,19,160,59,35,170,118,182,133,255,206,150,240,223,5, 102,81,65,38,236,130,76,216,165,72,19,118,33,38,236,130,156,181,139,45,232, 119,177,4,125,63,156,241,5,217,208,15,217,208,175,72,27,250,17,27,250,193, 120,233,167,199,139,176,66,191,42,204,216,19,37,168,65,70,236,41,122,239, 158,114,238,177,167,154,231,4,135,120,232,101,19,213,153,29,176,227,238,5, 15,19,65,68,236,69,136,216,75,222,62,246,178,76,59,132,112,120,214,136,38, 237,67,47,78,188,112,32,154,46,238,91,41,57,30,0,211,253,32,146,7,32,138,6, 0,138,112,172,12,32,48,7,72,138,6,152,39,27,225,37,1,127,160,237,12,127,100, 197,64,49,211,80,103,43,141,27,197,74,172,83,141,129,82,188,104,26,6,18,26, 6,74,26,6,90,39,26,131,112,26,38,100,233,32,228,175,65,69,3,29,68,128,14,2, 81,57,40,136,74,228,177,232,154,48,97,111,107,198,40,100,201,222,194,103, 174,142,14,227,92,29,163,124,21,236,146,226,111,148,131,55,21,151,12,214,43, 15,166,122,138,38,103,48,33,103,48,32,103,176,6,67,114,48,4,167,197,66,198, 15,65,110,28,82,52,210,33,4,233,16,48,58,12,137,70,7,225,198,232,154,48,97, 127,146,193,11,33,223,95,140,202,42,203,231,17,193,49,47,90,153,124,127,163, 74,147,218,226,171,246,150,171,132,228,196,36,48,84,221,212,127,213,30,87, 237,189,231,66,14,60,128,36,44,67,214,31,32,208,28,0,208,28,0,209,28,224, 240,215,92,158,176,191,130,23,118,134,16,232,112,252,158,106,4,61,127,7,69, 199,8,162,199,21,8,79,225,41,180,59,162,0,186,40,113,190,164,61,194,49,191, 170,18,194,96,193,117,132,253,85,149,132,207,23,69,71,68,139,162,194,135,7, 177,44,115,200,139,7,161,222,119,144,78,44,238,118,7,17,100,7,1,98,15,10, 136,69,221,46,186,38,64,143,84,137,208,66,208,214,97,115,164,24,54,93,225, 118,39,178,2,181,21,207,111,11,141,150,35,133,120,188,237,35,137,237,35,129, 237,164,89,105,227,193,14,207,238,135,204,59,24,185,230,224,120,120,7,19, 120,7,195,184,59,216,250,178,67,191,42,192,31,226,36,186,235,224,173,46,58, 68,184,232,16,238,162,67,226,223,118,28,34,20,196,179,112,8,97,225,16,200, 194,33,113,175,59,14,165,105,25,145,133,135,34,47,29,26,143,239,80,130,239, 80,57,180,28,234,24,95,17,134,151,4,224,195,220,217,110,8,216,234,153,195, 132,103,14,227,158,57,44,230,29,225,97,66,58,222,236,195,136,217,135,73,179, 245,70,165,125,135,179,36,152,200,178,195,145,71,14,143,135,118,56,129,118, 56,24,108,15,183,188,129,138,174,9,208,71,145,68,157,8,242,81,66,157,43,147, 26,175,206,186,132,15,110,71,209,67,51,145,53,71,17,107,148,58,117,116,38, 110,66,66,30,227,240,100,162,8,246,24,52,125,25,67,26,30,163,217,142,234, 250,118,5,31,65,73,217,14,222,135,178,213,185,124,203,204,169,252,90,231, 106,119,240,201,231,102,180,86,208,243,67,245,58,234,48,126,244,209,66,201, 209,44,53,42,50,239,104,68,253,209,241,212,31,77,80,28,13,168,63,58,162,94, 120,62,186,38,64,255,202,209,211,183,250,29,152,66,254,21,130,252,171,240, 156,88,240,121,164,186,138,190,176,44,25,43,144,141,53,124,97,169,46,152, 190,176,44,57,142,230,152,69,60,31,167,10,245,157,81,74,136,239,138,86,101, 116,87,116,161,214,48,94,54,49,216,231,164,149,165,199,24,190,228,46,153,64, 44,153,160,163,85,149,201,62,136,9,0,214,4,1,107,2,128,53,1,192,154,80,128, 165,10,189,35,179,91,189,226,49,135,191,147,240,254,161,184,61,158,166,232, 69,116,30,47,112,31,15,112,31,47,112,31,15,112,31,15,112,31,175,227,214,10, 213,222,124,20,126,39,56,52,229,0,234,50,39,16,47,156,224,136,205,172,94, 153,105,147,57,16,47,100,27,208,196,13,219,204,113,219,195,64,219,195,138, 19,103,73,12,116,37,19,131,135,24,161,228,68,162,228,68,153,222,160,160,229, 196,144,252,162,212,180,107,98,194,202,73,50,170,38,242,68,207,40,174,38,34, 231,78,36,206,197,227,225,68,130,106,34,112,238,68,199,184,73,91,187,38,96, 159,20,101,148,142,219,167,93,114,146,152,239,184,210,37,71,52,179,18,235, 132,231,36,41,94,132,249,39,17,243,79,2,230,159,100,157,243,76,226,57,183, 145,121,147,144,115,38,21,129,110,18,65,55,9,68,255,36,199,184,93,91,187,38, 96,159,76,156,99,221,177,93,114,178,112,206,201,194,57,39,199,56,231,100,41, 94,132,249,39,19,243,79,6,230,159,108,117,206,41,60,253,57,50,239,20,228, 156,83,138,64,119,10,65,119,10,24,215,84,217,104,183,12,57,39,186,38,96,159, 138,115,180,35,240,167,34,240,167,22,1,254,84,2,254,84,227,192,232,94,41,85, 3,227,184,41,13,200,10,114,89,24,114,154,147,232,45,12,177,198,218,105,34, 214,78,19,177,118,154,255,252,62,81,59,112,145,6,219,105,82,190,8,70,78,35, 140,156,102,100,132,52,47,109,62,61,234,89,36,65,61,178,246,116,228,189,211, 139,192,122,58,193,122,186,249,142,228,94,106,239,221,145,12,254,163,215, 133,49,103,56,137,29,164,49,86,15,158,33,60,120,134,240,160,91,210,222,165, 144,76,251,168,11,207,144,10,138,160,229,12,66,203,25,102,90,40,0,105,247, 228,104,224,240,62,127,133,222,155,140,188,55,185,8,152,147,9,204,201,124, 34,48,57,152,8,8,103,5,23,148,78,114,24,119,73,165,182,176,30,165,70,246, 102,210,170,56,168,146,110,203,187,230,41,173,29,9,0,247,82,73,238,76,81, 148,207,137,162,106,81,148,172,206,181,201,106,173,178,90,171,172,214,64, 181,57,110,181,6,166,205,81,213,90,101,181,86,81,173,125,227,180,92,179,59, 77,159,206,47,116,204,55,182,86,20,46,2,87,87,249,159,134,40,214,178,165, 200,205,85,170,176,84,247,67,149,35,94,239,86,129,73,124,149,152,196,87,129, 73,124,85,112,31,224,101,124,98,95,101,123,78,170,38,86,87,71,38,169,170, 100,59,114,181,196,94,13,176,87,11,236,213,0,123,53,192,94,13,176,87,227, 135,169,106,235,195,84,141,230,24,148,245,185,164,70,24,87,35,141,171,1,198, 213,8,227,106,128,113,53,192,184,26,96,92,13,122,226,170,49,63,113,213,42, 79,133,174,65,227,67,45,241,166,250,240,159,189,165,173,117,204,239,243,133, 176,152,208,214,218,30,214,132,56,253,30,205,43,49,60,170,193,150,135,129, 150,241,163,154,20,231,211,169,218,130,71,144,120,29,17,175,51,222,190,235, 108,79,122,66,137,233,6,82,103,125,210,19,106,232,0,95,103,122,210,171,247, 191,250,156,98,222,6,81,143,34,170,94,139,40,124,199,169,39,128,234,101,68, 213,59,198,237,15,225,37,1,183,193,255,230,115,74,236,182,135,6,49,39,112, 69,219,141,98,5,214,93,15,13,66,58,214,104,114,126,159,146,225,70,235,109, 74,235,166,22,238,165,230,135,238,169,200,27,83,99,129,209,197,210,169,160, 139,78,181,60,114,71,215,4,228,188,147,232,18,66,182,122,36,47,60,146,231, 30,201,199,60,210,229,133,116,172,225,121,98,120,30,24,174,55,42,237,107, 244,79,13,152,98,250,6,183,164,17,57,164,49,22,87,35,193,213,40,6,189,70, 211,71,184,225,21,1,181,73,139,30,195,170,64,19,2,219,20,11,182,137,128,109, 2,195,108,147,101,77,32,186,38,32,159,169,69,143,125,69,224,76,17,61,103, 242,232,57,51,38,122,206,20,210,177,134,211,41,234,153,192,240,51,173,209, 211,172,79,142,177,75,154,145,75,154,99,145,53,19,100,205,224,214,213,108, 89,9,136,174,9,200,45,133,17,54,110,29,160,5,1,111,137,5,78,78,176,83,245, 13,55,205,22,251,42,64,139,117,21,160,213,73,244,100,70,88,163,171,85,68,87, 43,143,174,214,184,37,128,86,33,30,203,5,125,204,104,53,114,209,106,127,254, 111,43,244,162,216,167,255,54,228,179,182,88,156,244,209,167,205,60,71,105, 139,121,246,111,179,63,251,79,115,18,189,184,33,86,191,77,19,126,155,198, 253,54,45,246,193,127,154,144,143,37,100,26,33,100,154,153,144,105,49,79, 253,211,11,3,132,249,153,127,58,242,217,244,88,136,244,169,116,58,159,16,78, 55,61,241,79,143,14,85,34,72,207,246,95,52,249,25,194,176,55,206,22,222,112, 133,248,190,174,179,29,251,199,3,234,122,148,134,12,127,127,120,54,177,77, 53,210,34,26,49,110,195,18,194,96,15,183,14,82,82,49,199,237,111,138,10,63, 107,89,192,8,220,17,56,71,21,146,29,129,115,36,35,115,194,198,88,105,250, 184,102,39,135,79,248,47,57,199,161,217,218,144,165,231,16,75,207,145,52, 157,99,161,73,8,3,154,206,137,144,23,165,66,75,244,70,181,20,44,149,92,207, 85,27,60,60,59,205,91,110,230,34,130,230,18,130,112,31,153,75,0,206,149,4, 205,117,140,123,110,194,75,2,242,185,106,199,90,8,217,58,126,157,43,122,140, 43,220,110,44,47,24,143,7,174,115,133,96,17,54,159,75,108,62,87,218,28,52, 40,237,58,207,73,116,10,236,178,125,96,113,30,242,198,121,69,32,59,143,32, 59,15,70,220,121,142,237,227,10,253,170,128,127,190,147,232,65,224,91,61, 115,190,240,204,249,220,51,231,155,61,115,190,16,44,194,254,243,137,253,231, 67,251,207,55,57,103,158,22,116,110,39,171,104,84,29,10,59,104,30,114,208, 188,34,0,206,35,0,231,153,250,243,60,173,63,11,23,105,23,133,13,11,252,229, 55,245,33,14,70,190,64,168,115,69,210,227,252,173,44,200,42,247,178,150,59, 25,217,180,128,216,180,160,176,51,198,208,134,196,188,176,240,229,144,101, 214,181,16,65,91,24,11,109,33,129,182,16,65,91,168,65,19,220,104,23,5,236, 69,133,15,166,226,231,88,139,68,79,88,196,123,194,34,127,150,67,28,65,59, 196,165,122,245,75,253,14,17,99,254,165,196,252,75,145,249,151,146,118,165, 149,151,169,131,175,91,180,128,226,219,163,46,67,158,185,44,128,6,119,71, 169,139,104,119,212,229,130,254,203,77,187,163,46,183,236,142,186,218,239,2, 106,145,29,191,26,184,90,188,26,184,26,102,191,83,197,201,49,109,121,94,179, 112,160,40,45,238,232,62,12,182,214,230,219,178,10,7,187,214,101,76,182,182, 193,116,253,15,78,162,219,248,198,230,169,89,91,13,237,139,51,146,130,175, 228,26,189,226,53,65,69,228,167,107,37,139,215,134,27,5,17,199,215,170,5, 149,122,238,164,235,100,197,235,220,254,171,94,215,152,85,93,231,171,98,57, 222,74,110,8,222,133,248,254,64,1,124,3,81,115,3,204,237,229,21,91,210,187, 73,37,201,42,234,212,27,2,63,23,135,64,30,108,234,21,107,199,204,198,43,17, 31,212,220,16,120,14,138,223,72,196,111,116,107,84,26,34,229,70,30,135,69, 169,235,82,229,134,167,69,165,12,95,164,246,143,68,237,31,221,168,206,123, 81,109,82,252,71,24,247,104,12,186,73,235,209,112,123,158,151,134,152,108, 207,187,9,247,232,155,100,143,190,9,247,232,155,44,61,250,166,152,30,125, 147,165,191,222,172,87,188,217,210,95,255,44,187,209,159,173,253,245,207, 176,191,222,34,43,222,18,219,95,111,193,253,245,54,173,191,226,61,135,183, 17,53,183,225,254,122,91,76,127,21,74,120,127,189,205,210,95,37,2,208,95, 111,139,233,175,66,137,232,175,183,217,250,235,95,136,248,95,44,253,245,47, 197,244,215,191,18,117,127,141,233,175,127,5,193,137,58,213,237,78,162,131, 114,102,133,223,75,241,180,235,118,116,115,191,93,11,3,60,239,184,157,32, 190,61,118,40,184,221,52,20,136,25,129,169,166,48,239,14,183,162,102,158, 117,122,118,135,152,158,185,210,237,70,179,130,237,221,105,18,106,26,205, 213,238,212,101,239,84,202,98,57,187,147,112,118,103,44,103,119,154,17,73, 54,84,90,96,143,13,91,98,210,146,187,144,183,239,138,69,126,23,65,126,23, 238,244,90,130,97,228,87,114,89,192,95,226,36,186,235,240,173,222,92,34,188, 185,132,123,115,73,124,58,210,146,37,66,67,44,17,36,89,177,146,65,68,240, 182,165,181,119,187,191,61,107,221,66,236,168,187,145,163,238,142,197,119, 55,193,119,183,28,88,239,246,7,86,228,160,240,146,128,123,143,147,216,174,0, 215,234,152,123,132,99,238,225,142,81,5,99,176,63,238,17,130,177,246,222,67, 236,189,71,218,27,52,39,109,186,183,208,95,108,217,209,74,238,69,110,184,55, 22,22,201,9,173,234,163,91,212,189,214,244,104,244,178,128,191,180,208,95, 138,200,143,86,178,84,184,101,41,119,203,210,248,252,104,37,75,133,134,88, 34,150,18,34,150,98,34,120,219,210,218,251,220,7,113,207,90,125,168,196,30, 187,15,121,236,190,88,160,247,17,160,247,89,110,232,247,177,27,58,242,157, 172,35,76,82,217,175,253,62,229,222,201,177,41,247,35,83,238,143,53,133,228, 186,86,245,173,147,137,251,241,100,66,152,132,235,9,179,30,40,152,101,62, 186,0,37,199,86,114,49,102,145,188,216,94,125,62,99,123,192,49,31,89,16,93, 19,144,85,58,108,17,92,214,254,36,210,97,43,29,180,63,61,232,191,140,84,108, 225,206,244,160,16,143,101,128,164,193,86,50,198,24,37,173,75,139,151,185, 190,12,99,207,106,233,50,97,233,50,110,233,178,56,75,151,9,241,88,75,73,10, 109,15,174,45,132,151,217,173,93,238,175,111,121,207,150,112,125,107,57,10, 200,229,1,72,184,190,181,220,176,190,245,144,136,187,135,76,235,91,15,89, 214,183,30,118,18,157,60,255,184,176,189,92,165,184,35,61,44,90,123,88,177, 139,50,64,149,60,162,87,123,36,122,186,10,119,170,62,66,208,61,162,77,80,68, 43,143,120,173,16,233,191,17,233,191,57,137,62,158,116,99,115,144,35,82,77, 28,10,198,8,125,127,11,231,36,130,137,199,172,154,48,45,143,137,6,30,43,52, 16,58,58,124,88,127,156,152,241,56,49,227,113,63,112,212,79,161,242,241,64, 37,138,167,39,164,183,159,40,4,12,136,132,39,12,193,180,66,86,93,129,179, 235,250,245,87,18,83,72,10,241,18,149,57,221,53,5,228,179,83,151,140,150,60, 41,33,60,105,177,228,201,16,30,211,179,74,214,93,101,51,229,41,98,10,201, 194,93,242,148,111,138,139,94,152,242,148,197,148,167,37,132,167,45,166,60, 109,50,101,181,172,187,218,102,202,51,58,192,103,124,128,170,86,146,233,125, 54,212,27,230,136,242,203,200,139,241,103,221,174,119,44,47,24,195,11,70,5, 64,212,127,82,132,74,146,252,89,213,53,6,184,215,82,221,127,33,60,38,70,184, 220,21,14,242,109,66,249,81,30,243,37,141,77,65,65,201,97,135,138,42,170,64, 75,218,89,242,108,54,129,156,249,156,161,135,173,1,156,71,89,158,11,45,173, 225,20,175,97,20,39,137,161,36,201,181,170,107,100,105,141,100,73,8,219,88, 90,195,89,90,35,88,90,131,88,90,131,89,122,222,192,210,11,162,225,23,76,55, 181,23,181,148,144,193,63,49,164,191,238,159,109,224,141,230,120,63,200,235, 34,236,95,151,139,186,175,227,69,221,215,45,11,179,122,154,210,146,55,44,11, 179,27,164,101,27,172,11,179,27,224,194,236,70,89,113,99,236,194,236,70,188, 48,251,166,203,172,71,89,24,112,98,210,244,38,209,243,166,124,22,126,211, 178,168,42,132,209,131,218,155,49,139,170,66,137,152,162,191,233,152,207,28, 124,203,125,116,8,239,241,248,214,254,22,154,169,189,165,83,131,231,147,111, 17,96,111,73,106,222,50,47,139,132,151,4,224,183,221,121,105,52,41,177,77, 163,223,22,131,202,219,252,237,240,219,230,117,145,183,133,96,188,197,111, 19,139,223,150,22,191,109,90,24,121,199,157,124,250,86,89,87,70,222,65,174, 120,39,30,24,73,160,90,130,19,168,122,197,150,165,145,119,172,75,35,155,157, 68,15,98,128,213,53,155,133,107,92,249,118,71,177,130,216,181,145,205,66,67, 60,21,155,9,21,155,49,21,188,113,105,239,187,110,13,223,94,243,51,247,187, 200,91,239,198,67,124,151,64,124,23,244,232,119,45,15,221,209,53,1,122,139, 147,232,236,131,182,79,230,183,8,165,91,20,185,240,25,71,79,206,90,242,30, 120,198,33,153,88,85,141,104,188,17,205,188,231,53,67,196,223,39,226,239, 255,188,135,156,247,205,15,57,31,249,155,70,155,115,173,109,205,6,26,62,18, 250,92,161,210,73,217,102,61,34,169,119,63,242,126,41,149,102,247,126,68,44, 82,42,213,180,154,69,32,105,73,162,255,216,245,164,223,78,69,32,140,77,248, 24,129,252,184,8,144,31,19,144,31,99,144,31,19,144,130,45,114,89,152,240, 137,147,216,158,154,96,29,50,62,17,67,134,171,160,221,9,172,64,245,90,230, 32,58,100,124,34,52,20,65,198,39,132,140,79,48,25,188,117,105,241,151,126, 200,85,87,182,230,10,254,226,147,160,47,5,137,174,80,250,100,23,77,75,52, 245,165,95,187,146,188,146,170,186,109,246,26,105,195,241,235,94,207,248, 248,204,108,136,6,211,234,100,206,22,59,40,149,126,182,118,170,156,142,235, 128,24,23,95,137,202,42,221,228,9,185,106,12,253,171,34,160,147,68,148,74, 34,128,142,218,144,254,251,218,213,232,183,224,29,165,111,216,100,138,82,81, 42,209,88,112,36,27,165,146,144,224,190,22,238,195,23,5,244,111,156,68,119, 29,186,181,171,137,164,148,74,156,158,183,247,141,191,189,45,104,14,117,180, 111,132,124,17,20,144,172,148,74,74,82,64,91,150,150,254,224,36,58,184,177, 86,85,59,35,223,54,181,177,9,63,236,136,156,143,37,50,11,99,137,204,194,168, 138,44,103,148,255,168,160,4,237,154,159,24,126,36,54,170,44,138,236,67,204, 66,174,197,226,132,217,22,233,66,86,198,162,132,197,188,226,71,203,147,194, 79,174,198,130,117,230,79,114,127,66,196,252,196,136,193,206,255,137,192, 251,73,18,243,147,99,252,44,55,188,196,97,39,19,110,228,235,176,109,145,159, 76,240,200,87,226,36,242,85,65,210,244,93,110,50,33,68,139,177,220,23,43,88, 238,181,64,45,143,26,149,246,181,211,221,98,250,14,33,217,14,184,69,137,22, 1,142,60,41,43,25,22,114,94,17,254,18,33,186,36,96,151,232,110,137,249,22, 33,89,34,220,82,194,221,82,226,144,67,170,169,91,164,104,81,150,147,147,157, 147,50,251,103,212,168,180,207,173,213,41,180,207,248,136,144,68,25,52,149, 108,17,232,72,22,77,37,195,123,179,87,102,120,74,208,174,9,232,101,238,20, 66,109,11,108,156,58,213,157,98,99,220,101,66,161,74,107,55,49,55,3,207,139, 213,213,210,64,161,217,34,146,87,207,83,216,234,42,196,141,72,216,229,222, 171,57,175,137,10,37,135,129,151,35,116,229,197,160,35,41,244,148,136,64,87, 30,161,19,244,68,215,4,240,14,254,148,141,240,205,230,133,201,14,8,118,135, 8,54,122,97,166,174,163,181,197,100,71,129,174,163,97,109,81,93,48,189,48, 75,246,244,215,20,171,140,169,149,147,61,249,109,54,89,72,249,197,138,232, 109,86,21,201,212,202,154,225,61,131,115,83,28,227,93,54,73,210,127,37,101, 242,177,16,73,113,194,45,2,160,233,46,43,133,229,105,206,196,64,73,108,47, 247,57,161,202,154,121,55,137,18,142,41,185,136,22,28,196,36,205,88,82,166, 25,75,154,211,140,37,141,105,198,146,189,213,187,226,98,114,239,38,69,114, 177,36,79,46,150,140,73,46,150,236,45,164,227,205,38,41,197,146,50,165,88, 210,154,82,44,185,67,232,16,227,13,22,165,17,83,114,113,200,72,242,48,37, 192,67,109,7,243,221,53,188,36,0,247,9,29,18,119,107,237,35,28,210,135,59, 164,143,99,61,188,32,217,71,72,199,155,77,210,140,41,33,110,182,222,168,180, 111,71,53,233,137,203,192,155,220,17,249,100,199,120,112,59,18,112,59,194, 30,188,163,99,57,149,158,92,21,224,251,170,169,79,145,57,120,147,125,133, 127,250,114,255,244,141,61,149,62,217,87,40,136,103,161,47,97,161,47,100, 161,111,204,169,244,201,221,252,37,143,42,115,106,146,228,110,226,38,225,10, 241,228,28,170,76,38,231,80,165,44,53,137,102,244,238,238,175,170,240,32, 117,124,155,216,157,24,233,74,240,252,8,94,153,41,233,134,20,7,28,237,238, 216,242,102,72,21,188,39,236,110,158,100,238,161,190,238,143,73,155,145,220, 3,113,179,7,225,6,7,192,30,4,217,30,128,155,61,28,99,222,12,237,154,128,221, 223,73,116,171,42,46,113,70,178,191,136,255,254,236,205,176,42,176,38,206, 72,246,23,226,69,88,223,159,88,223,31,88,79,218,149,86,238,169,158,0,98,83, 103,36,247,68,238,217,179,8,128,123,18,128,123,194,216,219,211,58,74,237, 105,27,165,246,114,18,61,170,138,77,158,145,220,75,184,105,47,238,166,189, 252,17,221,109,16,123,105,47,33,93,4,9,36,225,154,215,132,36,65,111,88,218, 57,192,157,125,87,217,19,103,36,81,186,53,37,24,11,143,36,90,83,18,188,115, 15,48,223,221,195,75,2,242,64,39,209,181,170,168,212,25,73,145,98,77,9,83, 191,12,140,185,189,15,20,210,69,24,78,82,171,41,41,110,184,222,170,180,112, 63,245,134,201,189,109,52,193,124,78,201,253,84,161,158,207,73,9,240,231,10, 183,136,159,117,168,202,232,89,135,133,90,195,200,46,162,198,124,139,186,54, 148,121,124,168,43,93,213,228,183,141,140,30,74,140,30,42,103,153,67,45,207, 28,66,152,159,6,230,149,153,78,42,148,226,244,208,46,175,4,159,84,136,91,30, 6,90,30,70,222,204,37,135,5,244,4,25,49,146,195,136,158,97,238,240,231,101, 196,104,110,85,251,229,43,107,248,213,110,158,131,43,42,107,114,149,234,53, 92,75,91,67,171,232,3,195,204,235,94,42,119,88,149,121,33,50,185,63,234,179, 251,135,30,196,97,75,242,153,169,218,220,131,251,155,31,143,194,75,2,234,1, 234,78,16,191,248,120,128,232,171,174,96,201,152,38,86,98,125,56,58,64,138, 199,152,124,0,49,249,0,105,178,222,164,180,109,184,123,19,172,106,50,159,10, 152,28,142,252,48,60,6,212,112,2,106,56,232,12,195,29,227,153,128,218,53,1, 247,64,39,209,57,128,107,245,197,129,194,23,7,10,95,28,24,51,112,30,40,197, 99,204,62,144,152,125,32,48,251,64,235,176,57,34,116,6,62,100,47,57,2,57,99, 68,12,42,146,217,45,57,2,140,15,35,28,227,17,123,218,53,1,247,160,208,25, 214,3,246,146,7,9,103,28,36,156,113,80,140,51,14,146,226,49,102,147,180,113, 74,68,152,125,144,213,25,35,213,35,86,147,233,112,198,228,72,228,138,145,49, 152,72,58,55,175,54,29,229,71,154,142,102,12,175,8,152,191,244,87,123,93, 164,109,121,195,235,178,228,47,197,35,218,47,229,253,246,151,114,29,239,151, 65,163,200,212,81,126,172,170,70,205,143,103,163,136,189,163,228,224,52,202, 114,71,149,194,108,14,50,202,178,138,39,132,25,211,163,10,76,11,66,143,80, 15,101,190,97,230,187,211,17,136,146,35,40,37,56,4,142,32,192,142,144,148, 28,97,190,69,133,151,4,232,209,234,145,44,2,109,237,142,163,69,119,28,45, 186,227,232,152,251,212,104,41,94,140,241,163,137,241,163,165,241,163,173, 55,171,35,53,215,24,39,251,71,34,215,28,89,12,186,35,9,186,35,101,192,29, 105,158,237,135,151,4,232,163,52,215,196,77,247,143,18,174,57,74,184,230, 168,152,145,242,40,41,94,140,241,36,137,155,146,227,198,31,101,29,45,199, 168,199,176,192,74,211,144,57,6,121,102,76,49,224,72,178,54,37,194,122,243, 24,227,184,57,198,52,110,142,11,222,126,76,109,156,102,112,198,56,225,12,87, 166,221,41,188,224,84,191,213,36,217,86,151,28,71,16,143,115,162,172,178, 225,252,91,84,81,9,215,170,154,192,231,38,126,195,117,255,175,91,56,149,237, 159,78,122,171,140,138,32,159,9,228,25,209,4,239,209,62,103,197,137,178,136, 11,216,149,190,59,86,173,231,43,92,230,1,250,88,20,107,199,234,246,224,72, 59,150,128,58,86,218,115,172,121,120,62,214,56,60,143,87,235,249,5,192,214, 17,96,188,8,186,241,236,235,21,85,64,198,102,186,161,51,57,158,88,48,30,197, 133,168,98,142,11,173,49,54,206,140,23,32,227,217,21,13,115,118,199,91,199, 255,227,66,191,27,71,255,227,144,223,143,139,71,118,28,65,118,156,12,198, 227,204,99,255,113,198,177,127,66,232,247,184,145,127,130,240,251,4,238,247, 9,108,224,103,126,39,217,5,85,101,233,119,81,197,236,119,173,49,230,247,9,2, 100,60,187,162,97,206,238,4,235,205,101,82,48,86,87,54,230,167,97,250,38,9, 250,38,241,177,122,82,52,86,243,248,152,164,44,80,202,205,227,28,201,93,166, 4,120,228,78,50,142,115,82,148,25,63,201,52,206,157,172,226,93,225,50,143, 115,39,35,123,78,214,237,193,30,33,201,200,148,0,183,231,100,243,56,119,178, 113,156,59,69,197,123,1,176,53,222,79,17,14,59,133,125,35,173,10,172,115, 208,83,132,116,188,217,36,203,153,18,226,102,159,98,29,128,78,13,29,98,28, 128,80,14,51,37,23,135,140,164,48,83,2,60,74,78,53,15,64,167,26,7,160,211, 66,135,196,13,64,34,87,153,146,165,14,57,45,102,230,121,154,144,142,55,155, 228,41,83,66,220,236,211,200,200,144,98,201,162,146,181,33,130,154,18,119, 38,169,22,43,131,225,204,179,69,180,71,242,178,40,233,116,109,222,201,205, 128,117,73,226,147,100,157,191,205,167,186,178,162,37,91,149,195,80,130,45, 92,10,74,128,10,96,234,166,42,57,21,122,107,63,11,106,202,9,19,97,121,165, 97,34,172,18,46,80,214,230,10,84,213,230,115,14,23,42,124,217,88,87,247,115, 16,217,8,33,45,212,153,97,213,25,97,185,87,74,167,52,54,54,228,178,121,244, 13,100,82,37,56,241,190,248,168,198,17,44,242,178,40,137,228,248,182,169, 172,168,253,216,150,163,43,79,84,62,244,180,132,99,126,120,155,36,169,86, 148,132,101,71,126,161,13,237,139,82,85,68,191,40,213,129,104,223,148,38,27, 162,111,74,233,120,49,149,135,13,234,58,36,241,138,18,137,66,185,208,238, 212,160,221,162,196,117,103,82,29,17,99,192,45,249,200,45,112,64,20,95,245, 40,9,143,50,242,225,183,79,61,201,169,162,169,22,174,205,71,140,234,213,195, 15,105,5,204,70,39,209,201,215,229,26,169,108,196,104,27,5,218,70,51,90,146, 105,69,85,52,161,109,4,104,27,11,187,251,0,216,38,127,81,79,229,68,87,188, 162,140,232,201,38,132,136,164,83,81,106,8,34,90,147,190,253,17,146,166,124, 232,234,90,199,48,31,250,52,237,68,1,189,134,151,13,157,23,154,189,115,166, 147,232,26,25,92,240,16,180,251,76,100,55,201,166,162,180,25,237,62,147,217, 45,36,141,118,159,25,107,247,153,200,238,51,45,126,86,73,92,148,189,94,199, 197,1,137,146,184,40,57,125,124,192,183,86,146,199,69,137,200,241,65,21,142, 85,133,104,86,161,93,20,192,91,220,222,228,1,111,177,246,38,148,200,69,201, 198,131,39,185,92,148,136,97,116,106,161,163,147,48,130,94,23,118,180,58, 133,35,62,240,190,221,86,100,64,107,100,0,220,183,219,234,224,125,187,109,2, 93,155,105,223,110,155,182,111,87,76,52,166,203,57,79,16,142,120,206,67,242, 117,40,233,104,34,17,95,183,125,67,237,180,92,62,215,210,194,47,164,212,5, 140,206,56,13,210,97,22,59,233,176,160,15,167,14,211,205,243,141,233,198, 249,134,123,101,187,124,99,222,237,207,213,21,177,211,161,255,3,174,126,6, 226,148,147,203,58,152,112,16,196,51,253,225,206,37,23,247,194,153,34,238, 102,6,247,52,195,4,104,38,105,122,166,125,2,52,83,78,128,102,138,9,208,76, 60,1,154,105,154,0,205,164,1,131,199,8,1,83,14,112,5,112,128,181,89,17,107, 112,58,57,75,220,197,103,201,233,164,91,212,126,92,224,116,19,155,179,8,204, 89,118,54,103,73,54,103,9,54,103,97,54,103,153,216,156,197,187,31,98,83,192, 148,108,22,218,45,74,156,116,6,200,23,112,202,236,104,226,163,28,3,39,0,179, 209,4,96,54,105,126,118,232,91,84,147,78,0,132,164,113,2,48,59,118,2,48,59, 152,0,32,211,206,114,7,34,87,200,118,175,63,11,57,239,172,98,186,194,89,4, 198,89,200,121,103,217,238,245,103,89,238,245,103,187,237,41,224,5,127,98, 236,103,35,236,103,23,131,157,100,77,82,34,48,114,206,166,145,35,44,160,215, 133,17,115,156,68,119,221,8,235,90,200,28,209,245,85,34,165,19,90,27,38,101, 155,89,169,214,38,90,18,153,131,149,20,67,203,28,66,203,28,3,45,115,98,58, 212,57,78,225,224,47,60,193,57,7,185,237,156,8,31,156,224,156,99,152,224, 204,21,94,153,107,154,224,204,181,77,112,206,35,19,156,50,5,133,174,82,11, 178,72,130,31,37,239,199,63,214,141,166,39,160,145,98,39,40,134,182,201,237, 254,60,243,237,254,60,227,4,229,60,52,65,1,62,158,23,44,143,55,25,159,193, 231,9,199,204,179,207,0,72,62,30,85,217,118,207,154,39,239,89,243,196,61, 107,30,190,103,205,51,221,179,230,73,159,160,94,34,128,202,129,111,158,121, 14,112,129,171,49,184,221,248,236,193,27,206,5,232,134,115,1,105,248,2,205, 5,168,46,189,229,8,89,227,45,231,130,216,91,206,5,150,91,206,133,222,126, 137,152,7,204,11,17,251,23,22,199,254,133,4,202,133,136,253,11,109,183,157, 11,45,183,157,249,218,235,41,60,118,205,71,200,231,235,200,225,232,53,223, 48,122,93,36,224,93,100,26,189,46,178,141,94,151,200,199,51,253,228,12,65, 226,37,68,181,43,157,158,150,109,8,224,17,70,22,58,133,99,56,176,39,23,10,3, 84,158,166,73,158,50,216,199,22,114,120,200,199,36,87,148,167,209,131,103, 104,70,162,94,228,242,227,54,80,225,73,97,224,139,16,184,69,197,128,91,68, 192,45,66,224,22,105,224,4,65,218,69,1,252,82,255,214,25,210,205,195,239,82, 132,250,210,8,53,12,190,75,13,193,119,153,128,118,153,41,248,46,179,5,223, 239,72,240,117,82,80,212,118,248,214,138,134,41,13,230,16,252,29,105,224, 119,133,132,88,146,147,43,156,68,103,239,219,114,79,165,49,47,89,242,10,97, 206,21,214,116,106,234,50,2,139,124,126,5,1,123,5,200,222,165,55,38,109,184, 82,157,139,30,25,96,51,227,74,4,245,202,226,161,94,73,160,94,137,160,94,105, 201,179,166,95,20,102,92,229,186,194,251,236,156,185,130,135,233,85,200,134, 171,184,13,48,88,175,50,4,235,239,5,208,223,155,130,245,247,150,15,208,111, 113,235,185,26,13,15,20,183,136,70,110,81,167,248,161,123,241,173,164,201, 91,157,68,31,117,175,157,150,83,189,176,165,34,155,119,34,59,91,138,144,78, 101,155,171,91,68,235,183,250,173,3,59,238,8,68,176,29,119,8,77,119,72,59, 252,170,122,122,148,164,74,143,50,86,213,217,145,41,68,233,72,146,119,185, 130,238,56,86,71,212,6,223,193,220,69,204,37,105,73,148,92,123,87,206,219, 81,47,128,222,229,1,253,223,232,26,102,210,165,142,220,200,215,250,194,60, 172,150,32,195,150,168,6,26,218,166,64,203,150,16,52,36,207,136,18,12,115, 214,75,211,150,72,211,138,85,38,109,91,34,108,91,194,109,67,169,73,146,119, 187,191,166,52,103,243,149,53,208,186,187,9,32,146,165,68,137,118,240,69, 177,125,119,75,251,138,87,39,45,188,91,88,120,55,183,240,30,100,225,61,14, 57,16,158,109,89,186,87,111,66,37,8,25,229,246,34,237,41,194,45,42,217,123, 111,2,155,36,9,73,242,124,36,2,247,189,26,13,161,6,58,25,23,26,45,159,61, 221,91,72,212,224,218,236,212,145,190,187,148,52,66,82,120,36,151,242,163, 233,5,206,165,30,78,52,124,223,39,199,212,251,224,209,217,129,151,239,35,56, 238,227,130,198,3,234,213,69,69,21,45,241,60,194,61,125,191,132,116,127,248, 146,75,232,189,191,160,133,31,16,151,124,16,69,204,131,224,80,20,45,236,30, 228,74,150,33,37,203,10,135,116,226,184,91,174,227,91,46,227,110,185,140, 187,229,196,220,229,252,184,87,97,245,114,25,120,203,89,224,73,149,230,192, 83,87,91,85,54,7,28,124,15,145,134,30,34,162,15,137,67,67,5,216,135,140,209, 247,176,116,245,195,182,232,123,152,0,121,152,11,154,143,14,85,87,89,248,61, 108,8,191,71,36,166,71,204,225,247,136,49,252,30,69,145,243,104,97,203,18, 28,145,31,37,230,61,74,48,60,170,239,13,19,48,30,21,3,232,163,28,207,99,8, 207,99,218,89,82,16,210,99,4,210,99,4,210,99,236,108,49,129,234,49,129,234, 49,142,234,113,132,234,241,194,241,19,16,18,73,15,145,36,233,33,148,100,116, 20,139,192,243,184,188,107,197,40,35,199,136,152,244,105,246,61,206,237,123, 2,217,247,68,97,75,43,180,239,9,2,233,9,2,233,9,125,139,178,192,243,132,192, 243,4,199,179,2,225,89,225,125,87,6,193,172,32,96,86,16,48,43,162,143,59,5, 148,21,146,234,226,84,201,201,193,10,97,213,10,110,213,74,100,213,202,232, 211,15,104,26,201,205,145,36,185,57,148,172,254,41,144,192,180,82,96,90,201, 49,61,137,48,61,233,20,62,142,135,144,158,36,144,158,36,144,158,164,167,121, 8,72,79,74,198,99,212,209,243,39,254,15,20,106,39,37,152,180,105,140,61,201, 25,91,133,24,91,229,176,156,214,154,134,85,92,195,83,72,195,83,133,68,231, 181,100,157,80,211,243,20,215,243,52,210,243,180,83,56,161,20,250,238,105, 194,205,211,132,155,167,217,209,176,130,157,167,5,59,79,115,76,171,17,166, 213,225,90,10,48,107,53,87,241,12,82,241,140,139,211,56,214,62,67,140,122, 134,24,245,140,122,103,100,26,106,159,145,193,19,163,171,131,109,164,125,70, 240,243,12,55,238,89,100,220,179,46,241,158,222,172,227,52,235,175,246,52, 77,207,114,77,207,33,77,207,185,35,175,175,201,133,140,212,60,199,213,172, 65,106,214,56,137,237,60,53,42,14,204,17,185,134,43,123,30,41,83,217,65,140, 183,145,231,9,221,207,19,186,159,87,239,19,76,119,145,231,5,215,207,115,52, 47,32,52,47,168,195,156,218,26,90,107,37,164,0,196,11,4,196,11,106,83,94, 161,190,135,4,205,116,95,240,87,51,24,128,23,17,128,23,29,181,207,176,22,54, 253,34,105,218,173,217,222,173,89,1,87,98,94,132,45,174,69,45,174,117,10, 167,131,135,141,70,211,252,181,114,154,191,150,160,88,43,78,105,23,88,214, 202,121,254,90,54,207,23,58,45,243,124,247,106,135,160,69,111,150,207,141, 124,9,25,249,146,59,198,152,111,89,47,17,112,47,145,230,92,201,114,203,29, 235,37,57,70,196,104,235,104,189,97,253,124,125,101,230,251,213,75,162,23, 188,196,217,122,25,177,245,178,251,171,101,122,109,171,97,209,229,101,2,232, 101,2,232,101,69,151,39,10,17,189,44,16,189,12,215,11,85,22,30,255,125,175, 97,201,240,117,161,250,117,239,69,89,75,107,51,124,158,213,115,244,36,85, 142,158,35,115,85,133,243,220,125,141,188,134,175,12,173,46,110,64,156,109, 176,172,46,110,32,132,109,32,132,109,80,233,57,26,218,188,252,196,220,164, 13,161,73,58,99,27,184,15,55,34,60,27,109,139,130,27,9,160,141,4,208,70,127, 137,114,10,68,180,17,34,218,200,17,109,66,136,54,201,165,60,77,199,38,174, 227,77,164,227,77,186,88,166,15,85,111,202,161,138,228,13,82,21,72,38,107, 97,220,155,145,113,84,11,29,172,132,86,203,96,21,181,233,111,94,16,163,21, 202,60,148,124,203,190,192,243,22,87,242,54,82,242,54,91,224,33,42,222,230, 42,80,218,157,228,59,214,39,253,119,8,75,36,255,142,146,140,62,203,19,68, 191,3,163,232,29,142,105,51,194,180,57,238,105,127,51,129,181,153,192,218, 204,14,120,23,200,54,67,100,155,57,50,148,246,38,249,174,245,137,255,93,2, 139,228,191,81,146,209,105,184,2,211,187,16,211,187,28,211,22,132,105,139, 245,41,125,11,193,180,133,96,218,162,127,64,46,48,109,129,152,182,112,76, 239,33,76,239,153,159,212,223,35,128,72,90,29,37,22,156,134,37,208,188,7, 209,188,199,209,188,143,208,188,31,243,132,253,62,129,68,82,245,40,89,253, 28,20,129,235,125,136,235,125,142,235,3,132,235,3,249,148,173,233,248,128, 235,248,16,233,248,80,62,237,105,58,62,228,58,182,34,29,91,45,207,174,91, 185,134,127,32,13,255,136,125,118,253,7,215,243,79,164,231,159,182,231,196, 127,114,21,31,33,21,31,217,158,19,63,34,158,38,41,140,148,96,123,99,7,253,8, 186,249,35,142,8,37,42,74,126,108,122,184,211,145,125,76,144,145,188,69,74, 65,23,93,1,68,248,49,68,248,49,71,248,9,66,248,9,124,104,212,225,125,66,224, 145,76,66,74,186,83,40,13,177,125,2,177,125,194,177,125,138,176,125,106,121, 18,213,17,126,74,16,126,74,16,186,58,186,51,29,16,231,167,16,231,167,28,231, 103,8,231,103,182,135,220,207,8,184,207,8,184,207,10,15,185,8,209,103,16, 209,103,28,209,231,8,209,231,177,15,186,159,19,32,159,147,7,93,211,12,234, 243,104,14,206,64,108,67,32,182,161,135,221,128,149,109,4,204,54,2,198,149, 43,85,143,190,136,148,109,144,148,109,28,207,23,8,207,23,242,81,88,211,241, 5,215,241,37,210,241,165,120,210,212,84,124,201,85,124,133,84,124,37,31,191, 52,29,95,213,209,233,41,73,40,148,252,166,136,157,29,26,91,223,4,79,66,232, 25,236,123,171,42,188,147,230,123,1,247,123,96,194,15,156,134,31,165,255, 127,212,97,170,148,63,163,154,171,89,81,240,210,74,15,93,95,221,79,218,99, 193,79,110,67,234,28,215,22,122,206,7,201,196,227,85,242,247,177,9,134,126, 242,155,174,179,75,179,109,70,70,45,128,179,84,34,172,93,208,152,74,56,244, 101,157,214,118,42,193,107,254,12,127,123,138,125,214,24,136,118,18,68,59, 203,91,204,20,209,218,46,112,143,14,83,232,250,57,48,219,133,48,65,96,166, 202,213,26,67,219,20,117,124,134,218,26,133,190,79,72,149,251,76,107,58,93, 169,244,137,74,138,21,194,125,70,169,14,122,173,14,134,125,70,169,142,160, 251,166,58,146,149,0,186,14,145,234,164,235,237,228,70,233,216,253,8,109, 157,8,109,110,133,237,10,91,143,130,207,49,132,93,157,188,140,175,86,29,25, 143,173,161,72,52,160,196,42,110,220,253,228,183,93,71,7,164,84,103,34,223, 57,50,97,152,201,132,206,146,7,161,196,100,67,103,104,131,16,55,238,186,82, 23,163,77,107,154,111,183,67,190,221,142,174,170,48,231,118,209,245,118,145, 70,117,33,168,220,10,93,194,221,87,38,106,186,8,239,10,37,38,102,186,64,102, 132,184,121,7,152,223,56,119,111,87,162,160,171,102,132,209,191,93,37,21,66, 139,201,138,174,208,10,33,110,222,122,166,174,66,7,119,67,14,238,198,23,169, 152,139,187,235,154,187,75,187,186,19,96,110,133,110,218,22,52,19,63,221, 133,147,133,26,19,61,221,33,61,66,220,182,17,206,111,158,187,185,7,81,209, 131,24,98,116,116,15,73,136,208,99,178,164,7,180,68,136,219,246,224,169,235, 208,213,219,35,87,111,207,215,18,245,241,191,39,65,65,18,30,165,122,198,237, 85,83,53,240,110,161,84,47,121,159,237,69,239,179,44,224,244,92,64,169,222, 146,95,146,247,71,85,216,174,176,125,205,228,164,222,34,218,132,14,147,143, 122,67,31,9,113,227,14,58,191,109,30,106,36,65,80,106,7,247,121,76,223,176, 104,50,99,7,201,133,80,20,76,19,10,207,42,92,30,216,34,84,88,55,79,6,32,64, 196,245,145,126,238,99,153,212,145,124,60,169,29,139,164,96,71,225,73,161, 199,198,192,142,144,1,161,194,206,192,142,133,46,39,40,216,9,117,186,157, 112,66,183,130,182,157,253,247,67,84,209,46,72,209,46,98,121,91,239,190,253, 136,73,253,136,73,253,98,119,251,169,42,134,254,187,171,244,235,174,214,254, 187,155,174,119,55,25,179,187,17,93,110,133,46,81,210,111,131,219,119,19, 110,23,74,76,29,120,55,232,114,33,110,222,132,232,55,206,123,48,201,240,147, 218,221,73,244,32,91,63,77,134,236,46,233,16,154,108,1,188,59,180,70,168, 176,239,67,13,80,128,0,222,67,250,122,15,75,31,38,233,116,82,253,139,37,161, 191,240,166,80,100,227,160,63,228,64,168,136,225,160,191,177,23,239,133,58, 223,94,248,197,80,208,56,73,9,147,26,0,206,215,19,86,12,16,36,8,37,166,144, 30,0,9,16,226,230,141,167,126,227,192,244,129,200,244,129,198,247,79,65,203, 131,72,203,131,112,18,88,97,197,32,65,128,208,99,34,96,16,36,64,136,91,183, 185,250,237,3,14,246,70,28,236,205,222,116,177,33,111,176,174,120,176,236, 227,131,9,180,193,32,145,159,176,113,176,160,71,40,49,209,51,24,210,35,196, 205,91,110,253,198,249,144,55,132,40,24,130,19,222,9,48,67,36,27,66,145,201, 144,33,208,16,33,110,221,238,171,42,64,63,239,131,252,188,15,126,123,24,180, 188,47,105,121,95,112,142,175,48,97,95,225,70,161,196,100,253,190,208,122, 33,110,222,89,236,55,14,76,223,15,153,190,159,254,146,146,197,183,158,174, 36,53,84,122,148,100,27,82,21,88,62,22,97,219,80,65,139,80,97,162,101,40, 164,69,136,155,246,56,251,77,243,216,38,105,142,82,195,68,14,19,129,98,152, 36,65,232,48,89,48,12,90,32,196,77,91,171,213,53,232,214,95,32,183,254,194, 244,182,55,104,150,100,71,74,237,15,243,18,8,11,246,23,238,19,106,76,198, 239,15,141,23,226,182,125,220,126,243,128,128,3,16,1,7,240,215,202,244,80, 254,212,112,93,243,112,233,86,146,182,72,85,144,105,218,132,145,195,5,63,66, 139,137,159,225,144,31,33,110,217,180,237,183,30,68,120,100,167,158,185,40, 165,50,23,141,29,74,154,32,121,138,84,5,144,206,81,160,61,80,242,37,244,152, 44,61,16,90,42,196,109,219,231,213,117,217,153,73,110,163,212,8,67,206,67, 129,103,132,228,68,104,50,217,50,2,218,34,196,237,123,247,85,13,24,215,7, 161,184,86,201,139,200,54,5,77,209,72,244,80,121,48,210,114,48,222,170,160, 233,58,4,233,58,20,233,58,84,110,190,208,217,56,140,176,113,152,59,127,208, 55,215,155,188,114,152,232,74,66,143,201,41,135,65,167,8,113,235,30,127,191, 125,224,147,195,17,3,135,139,13,27,154,166,95,34,34,71,33,53,163,28,178,105, 131,221,140,143,208,149,30,33,59,32,73,38,164,42,108,23,55,215,60,66,112,44, 116,152,56,62,2,114,44,196,141,159,28,248,109,243,30,76,82,2,165,70,187,99, 81,17,51,205,209,146,10,161,199,100,198,104,104,134,16,183,125,237,160,174, 195,72,65,185,135,82,71,154,118,193,104,10,143,66,1,131,242,229,164,198,192, 29,43,154,170,163,145,170,95,33,85,191,178,108,48,209,20,142,69,10,127,141, 20,254,218,65,59,65,2,134,143,33,12,31,227,182,29,55,161,62,70,196,170,208, 97,114,242,49,208,201,66,220,248,141,133,223,54,240,240,56,100,247,184,184, 253,38,41,146,86,38,117,172,147,232,45,62,172,48,177,112,172,96,65,40,179, 45,161,28,11,153,16,42,226,63,244,240,129,0,74,198,35,74,198,163,221,47,65, 227,36,215,74,234,56,247,217,42,248,212,195,109,168,194,51,69,88,113,156,71, 2,45,240,205,18,112,38,32,56,19,228,230,23,29,209,241,4,209,241,78,98,123, 250,217,135,201,55,199,11,223,8,77,54,223,28,15,125,35,84,196,124,131,226, 163,0,142,57,1,49,113,2,219,194,195,166,200,39,234,138,79,148,195,236,137,4, 156,91,161,75,236,12,249,68,65,146,80,98,234,198,39,66,130,132,184,249,43, 17,191,113,49,65,158,168,87,153,40,39,131,19,73,11,110,133,174,241,243,227, 137,146,44,161,198,100,231,68,104,167,16,183,124,171,163,46,203,155,235,73, 68,195,73,238,60,172,152,217,241,73,146,16,161,200,100,201,73,208,18,33,110, 253,78,72,85,128,1,61,9,5,244,36,185,161,76,111,154,36,186,73,157,172,92,25, 126,193,99,34,224,100,17,177,66,139,201,254,147,161,253,66,220,242,25,145, 223,122,93,180,94,77,182,7,157,230,222,55,163,237,65,21,13,13,211,166,226, 61,66,34,159,139,18,149,123,132,78,51,237,17,58,93,175,117,186,105,143,208, 25,200,35,103,144,61,66,41,218,245,38,43,189,233,214,182,166,6,79,193,100,1, 115,178,147,40,245,19,190,12,99,197,25,15,253,80,26,226,147,9,181,110,173, 14,190,103,60,106,144,114,224,30,161,195,188,161,102,114,240,237,33,177,233, 55,212,166,223,136,102,127,19,218,52,148,21,183,171,160,230,252,134,64,249, 77,140,57,191,9,73,177,43,49,111,114,250,13,178,167,66,175,81,33,199,181,10, 162,191,162,136,125,92,21,252,254,93,17,49,66,9,248,45,209,253,219,34,54,88, 253,214,7,72,75,10,33,36,198,144,44,138,216,172,67,118,62,177,144,157,66, 221,59,69,32,152,130,67,118,138,33,100,167,16,19,167,196,248,120,10,12,89, 161,195,178,71,104,10,242,113,37,53,170,82,180,91,137,99,182,82,198,108,37, 193,82,25,99,79,37,142,89,161,196,178,117,171,18,25,228,232,53,28,25,180, 228,60,125,85,33,126,127,154,195,163,214,49,69,109,142,40,207,21,179,111,44, 39,194,54,103,9,219,42,20,182,85,124,63,23,11,220,106,234,99,145,151,38,85, 141,3,183,218,16,184,213,196,202,234,24,71,87,195,192,149,58,108,123,158, 170,145,167,107,168,89,53,162,229,26,28,186,53,50,116,201,7,141,170,130,213, 162,26,28,186,82,137,109,67,90,13,50,169,86,175,81,43,131,151,228,2,83,21, 138,217,121,87,203,195,183,214,20,190,36,99,77,170,174,184,253,112,117,34, 128,235,44,1,92,143,2,184,222,177,236,82,107,32,16,73,82,174,84,67,236,46, 181,6,227,46,151,104,27,124,168,110,42,221,229,194,186,81,158,198,91,94,48, 161,242,84,185,118,143,105,203,243,82,212,139,72,142,43,85,203,26,115,121, 216,139,132,14,243,174,180,60,138,183,70,106,82,163,104,182,209,157,163,186, 38,141,106,174,30,87,75,103,140,141,178,23,145,60,88,170,194,118,209,67,47, 182,170,17,247,36,161,200,190,61,171,17,153,166,39,134,78,53,201,174,68,18, 93,169,10,177,123,10,155,120,63,106,10,253,77,121,32,185,164,82,103,22,185, 209,237,76,209,143,206,36,228,139,174,36,79,1,79,53,59,250,214,29,182,138, 220,66,157,221,34,16,180,24,157,221,34,157,77,146,219,168,10,177,206,110, 129,33,44,244,216,125,221,18,249,58,84,209,74,84,180,22,201,119,43,119,103, 43,163,91,16,62,13,141,93,211,236,155,253,166,163,85,211,25,72,209,12,235, 102,191,153,196,98,146,242,38,53,51,126,179,223,76,227,48,56,75,70,209,44, 235,48,56,155,134,209,108,65,236,108,56,12,206,54,12,131,36,239,138,170,101, 29,6,103,195,24,18,58,44,123,251,102,163,193,226,44,106,211,89,162,221,179, 140,93,227,44,217,53,72,22,22,85,33,182,107,156,133,199,65,161,40,102,135, 219,89,200,182,179,245,26,103,203,129,144,228,93,81,21,226,55,103,158,205, 187,206,217,134,145,144,36,47,73,205,41,118,187,224,28,49,20,206,177,15,133, 231,200,32,62,199,54,20,206,165,254,158,43,16,204,53,250,123,174,244,247,92, 210,240,220,34,252,61,23,134,177,208,19,227,238,185,96,44,60,151,232,56,183, 88,198,207,229,30,61,55,110,48,60,31,141,97,231,179,61,147,140,246,121,148, 246,121,2,198,60,167,144,229,151,149,114,202,73,190,15,85,193,58,106,204, 131,116,11,29,150,237,147,243,0,213,36,125,71,234,130,98,182,128,94,192,105, 190,192,137,210,26,51,130,81,66,142,212,133,114,103,38,227,120,62,229,120, 190,192,48,31,114,60,95,114,60,159,216,55,63,134,227,249,144,99,161,195,190, 67,115,62,160,249,34,162,226,162,34,247,154,94,196,153,190,200,204,244,197, 136,233,139,217,254,79,118,23,188,132,210,124,137,0,112,9,164,249,18,195,93, 144,36,255,80,181,172,92,95,2,185,22,58,44,219,61,47,65,119,138,5,212,166,5, 162,221,5,174,78,215,166,227,188,229,122,118,129,71,207,2,130,102,65,140,69, 11,240,13,80,40,177,111,252,92,128,172,90,168,215,88,40,239,127,36,177,137, 170,16,191,83,119,33,15,174,133,81,112,17,221,36,47,73,106,81,145,27,104,23, 137,219,223,34,157,120,17,191,40,3,73,234,82,182,175,149,13,19,151,81,95,95, 38,64,92,6,227,247,50,233,232,203,136,141,151,197,56,250,50,24,186,66,135, 101,139,235,101,96,140,184,156,200,95,94,204,54,221,203,185,15,47,55,15,16, 191,67,4,255,78,223,61,203,70,135,197,148,221,197,162,245,197,120,197,109, 177,97,120,88,76,236,91,28,195,241,98,200,177,208,97,220,109,186,24,117,163, 43,168,73,87,136,86,175,192,171,109,87,200,136,33,153,91,84,5,171,53,87,224, 161,65,40,49,110,255,189,2,153,115,165,94,227,74,57,42,144,148,45,170,66, 220,254,230,43,121,60,93,105,90,101,187,138,168,190,42,126,231,241,85,98,60, 184,202,178,194,246,123,20,172,191,23,123,130,217,120,112,53,117,239,213,2, 196,213,112,60,184,90,122,247,106,98,222,213,49,222,189,26,198,170,212,97, 219,28,124,53,24,17,254,64,52,252,161,184,77,206,127,224,62,252,131,121,76, 184,6,209,124,13,223,121,156,161,44,95,75,89,190,86,32,184,22,178,124,173, 97,88,184,150,24,121,109,12,213,215,66,170,133,14,219,62,227,107,81,87,186, 142,26,117,157,104,248,58,63,90,143,200,182,228,88,177,111,213,48,106,213, 117,4,209,117,49,86,93,135,135,7,169,196,182,169,248,58,100,215,245,212,174, 235,69,211,215,155,166,67,215,203,94,113,61,193,115,125,140,81,215,135,212, 216,149,196,236,46,190,30,153,117,131,94,227,6,57,242,221,64,26,185,161,168, 221,239,55,240,142,115,3,157,16,69,173,223,168,215,186,81,238,48,185,145, 180,126,99,113,123,210,111,20,3,228,141,81,200,81,63,252,145,232,255,99,177, 59,197,255,232,35,165,37,150,41,217,159,208,232,240,39,199,188,127,251,38, 180,78,120,51,210,114,115,236,254,237,63,35,93,183,32,93,183,240,253,219, 236,174,112,43,237,2,183,10,94,110,117,159,71,93,22,78,86,27,169,89,57,239, 1,36,191,150,170,96,237,1,183,194,193,74,232,176,239,228,190,21,220,24,110, 35,42,110,43,114,79,250,109,60,192,111,211,12,23,222,255,11,226,250,47,182, 157,226,127,69,46,251,31,164,230,127,28,178,83,156,77,60,111,167,14,187,93, 24,114,59,188,193,220,110,184,193,220,78,200,186,61,198,103,183,67,159,9,29, 230,157,225,183,163,241,234,14,106,210,29,162,217,59,76,195,240,29,50,8,239, 32,96,238,136,49,232,14,124,111,145,74,108,15,165,119,32,163,244,20,111,169, 59,229,32,124,39,105,226,206,34,118,244,223,201,35,244,78,195,51,41,73,214, 150,186,171,184,157,246,119,137,17,246,46,235,248,135,114,184,165,150,20, 177,3,254,110,212,17,80,78,177,212,61,113,59,224,239,69,170,150,34,85,75, 139,219,1,127,31,82,120,63,82,168,146,93,153,159,189,31,160,17,253,128,96, 251,1,216,73,31,144,225,252,0,241,229,3,49,225,252,0,236,159,66,135,121,55, 252,3,96,60,125,144,136,63,88,196,126,254,7,121,164,62,104,158,101,163,180, 94,169,101,96,159,61,163,120,57,165,120,185,0,177,220,95,223,118,219,228,11, 252,203,37,205,36,69,151,170,16,187,192,191,28,82,45,244,20,177,221,126,57, 224,156,100,246,74,61,244,115,62,35,120,136,147,255,16,33,66,56,224,97,228, 128,135,29,243,174,254,71,8,182,71,138,217,213,255,8,199,244,136,113,87,255, 223,16,156,191,241,93,253,44,24,30,165,193,240,168,0,240,168,207,193,164, 108,51,15,134,71,101,48,144,116,95,170,66,108,48,60,10,131,65,232,137,219, 223,255,40,136,4,146,232,43,245,88,209,95,44,60,198,41,127,140,80,32,120,71, 233,191,82,143,179,111,8,216,195,238,19,148,246,39,4,136,39,224,48,247,132, 97,46,66,18,108,169,90,214,177,238,9,200,185,208,97,249,100,224,9,116,223, 94,65,109,90,33,218,93,129,159,117,87,24,158,117,87,16,64,43,98,140,90,129, 231,35,66,137,237,3,129,21,200,172,149,212,172,149,162,229,149,166,57,214, 74,217,65,86,18,56,43,99,108,90,137,31,117,133,18,251,167,2,43,145,85,79, 234,53,158,148,147,44,146,23,75,85,136,255,136,229,73,222,111,158,52,61,232, 174,210,107,173,146,15,186,171,72,227,171,138,250,182,100,149,152,133,173, 50,61,231,62,69,212,63,85,228,39,31,79,137,199,220,167,172,211,60,148,127, 43,245,52,255,18,131,13,199,171,105,176,173,22,40,86,195,113,97,181,140,180, 213,196,200,213,49,145,182,26,14,9,66,135,237,155,140,213,96,8,38,9,178,82, 207,20,245,101,201,51,60,140,158,209,166,64,232,123,143,53,242,54,131,191, 247,88,35,218,114,69,219,157,200,11,78,65,183,238,53,196,18,208,164,18,73, 74,221,84,135,31,12,65,34,17,169,51,173,180,181,240,210,210,230,220,180,92, 51,24,174,124,176,218,193,202,169,53,136,159,231,1,63,73,159,10,202,207,243, 194,134,231,61,27,180,6,158,103,87,147,163,42,43,181,167,129,40,114,159,23, 92,7,181,133,122,209,113,94,16,48,94,136,168,12,142,31,126,129,95,62,133,21, 148,156,210,194,74,34,168,172,207,189,72,145,191,40,144,191,232,54,236,6, 224,41,172,44,125,66,174,165,245,68,26,240,36,69,151,170,100,237,117,47,242, 240,123,209,247,168,174,145,164,198,74,173,45,34,240,214,22,160,177,66,69, 137,206,225,90,118,93,216,184,182,64,154,140,169,151,169,101,184,191,189,44, 12,86,233,159,70,241,130,35,80,127,35,89,165,120,115,194,100,172,87,15,220, 151,145,21,235,152,21,73,95,49,181,98,157,95,168,233,90,167,183,180,142,7, 223,58,75,175,88,39,24,49,139,51,24,175,250,48,116,7,190,74,149,191,42,148, 191,202,149,171,130,83,235,88,73,201,9,45,113,66,70,131,112,155,167,70,231, 175,123,13,236,189,55,208,39,81,8,155,215,75,155,215,235,98,235,221,182,78, 96,5,172,227,175,231,214,172,167,214,232,49,183,158,196,220,250,152,152,51, 181,245,179,208,154,250,215,107,78,162,147,223,207,11,89,208,96,15,123,77, 208,255,26,250,130,241,53,211,23,140,175,235,181,94,55,125,193,248,6,154, 201,188,225,232,95,48,82,34,73,134,179,212,6,247,241,45,200,112,102,186,231, 111,16,95,147,10,21,166,175,73,55,192,153,139,16,55,229,88,243,155,6,123, 248,80,82,181,20,78,170,22,180,185,137,180,185,201,255,44,111,138,205,236, 77,194,108,161,195,100,246,38,104,182,16,55,102,114,243,219,6,118,163,180, 107,169,55,249,87,84,68,213,91,104,237,15,229,36,75,189,237,192,143,89,124, 240,36,131,88,234,157,194,86,245,32,215,136,137,195,119,4,135,66,143,237, 124,129,119,32,143,66,133,53,113,156,143,1,112,137,18,152,165,54,219,55,197, 191,139,200,68,185,189,82,91,196,166,120,77,205,123,72,13,74,128,149,122, 223,177,157,229,249,1,97,226,131,112,35,167,37,170,63,16,30,17,74,76,81,253, 1,244,134,16,55,167,150,243,27,7,174,64,249,177,82,31,198,157,229,185,149, 180,188,85,223,95,105,33,96,171,32,64,232,49,17,176,21,18,32,196,173,73,236, 252,246,1,7,40,59,87,234,31,14,204,90,23,180,252,79,210,242,63,195,13,128, 22,235,255,41,172,23,74,76,214,255,19,90,47,196,205,185,242,252,198,129,233, 40,27,88,234,35,199,118,188,37,73,179,149,250,56,220,55,103,49,253,99,97, 186,80,98,50,253,99,104,186,16,55,167,228,243,27,7,166,163,164,94,169,79,64, 14,190,160,77,146,29,43,245,169,218,72,97,141,246,79,133,209,66,131,201,232, 79,161,209,82,28,167,253,243,91,6,22,163,20,92,169,207,98,78,126,36,233,174, 82,159,107,155,162,44,182,127,46,108,23,106,76,182,127,14,109,23,226,182, 252,130,126,243,128,0,148,108,43,181,141,239,191,34,170,190,64,247,11,148, 224,42,245,37,223,23,65,244,124,133,244,124,141,244,124,237,152,119,124,124, 131,180,124,139,180,124,27,187,227,227,95,72,215,119,72,215,119,182,93,8, 255,70,106,254,131,212,252,199,65,73,6,3,7,127,79,28,252,125,225,229,170,37, 198,190,23,49,38,116,152,98,236,123,24,99,66,220,152,217,208,111,27,4,216, 15,200,238,31,172,169,12,131,198,127,36,141,255,232,36,122,241,228,133,38, 30,126,20,60,8,93,38,30,126,132,60,8,241,216,60,138,62,6,192,199,79,136,143, 159,204,137,19,125,4,105,146,202,43,157,112,18,61,72,170,68,3,19,170,34,101, 66,42,50,48,161,46,73,38,164,184,61,101,163,15,64,210,144,110,7,104,72,183, 139,203,209,24,128,40,33,32,74,156,68,31,144,149,209,68,73,137,160,68,168, 51,81,82,2,41,17,226,197,228,136,244,97,0,98,146,136,24,213,128,105,246,145, 78,145,246,83,133,173,3,22,10,82,130,2,161,195,68,65,10,82,32,196,141,153, 40,253,182,129,221,105,100,119,58,238,40,192,116,134,180,156,33,239,240,237, 143,131,170,50,99,65,40,179,60,14,170,203,128,9,161,34,62,21,166,15,4,80,82, 138,40,41,117,140,155,6,210,237,73,227,237,157,68,231,32,245,165,137,130, 246,130,2,161,194,20,8,237,161,249,66,220,148,124,211,111,26,24,93,134,140, 46,227,91,19,136,170,114,112,191,77,119,64,122,58,56,60,227,166,166,166,35, 82,211,9,169,233,196,95,205,17,61,36,75,156,190,84,151,238,74,34,10,174,211, 165,187,10,166,187,178,165,127,85,80,114,138,158,205,178,164,161,82,149,119, 35,174,232,70,92,209,205,236,201,110,92,127,55,239,213,66,168,189,125,117, 46,159,107,206,122,47,162,124,173,164,34,43,240,144,73,211,163,108,94,190, 217,108,233,60,221,195,135,21,45,157,167,123,232,138,123,232,47,219,68,57, 211,181,189,175,75,91,93,77,111,175,132,194,181,232,66,13,77,209,246,220, 148,237,249,250,183,87,82,33,100,0,168,64,148,130,234,41,65,245,212,133,122, 114,237,61,249,162,177,87,5,189,113,76,147,156,99,170,154,201,213,70,157, 210,97,42,251,82,109,75,69,75,182,42,151,109,135,2,117,39,97,183,43,82,72, 233,43,214,143,211,59,235,53,119,46,212,4,107,200,105,148,195,41,189,11,91, 67,214,13,118,175,249,223,168,51,69,253,144,162,126,124,93,86,215,212,47,60, 178,129,169,218,21,169,218,21,46,117,134,202,118,53,41,219,13,41,219,141, 175,119,234,170,118,51,169,218,29,169,218,29,47,27,134,218,118,55,105,219,3, 105,219,3,173,29,134,186,246,48,233,234,143,116,245,23,11,136,186,174,254,6, 63,238,137,84,237,137,22,228,116,109,123,26,180,161,44,69,233,189,196,210, 150,174,106,47,131,170,1,72,213,0,177,84,164,171,26,96,80,133,18,8,165,7, 210,165,23,93,207,64,19,239,131,144,162,65,96,69,67,215,54,200,164,13,229, 244,73,239,13,151,7,66,101,123,155,148,13,70,202,6,195,53,130,80,217,96,147, 178,33,72,217,16,176,80,16,170,26,98,82,133,18,218,164,247,49,174,22,132,10, 247,49,41,220,23,41,220,23,45,25,132,186,246,53,196,5,202,56,147,222,143,47, 27,232,154,246,51,104,26,138,52,13,181,236,37,15,53,14,53,104,28,134,52,14, 51,237,39,15,213,13,51,168,67,89,88,210,191,176,239,41,15,149,254,194,160, 116,127,164,116,127,254,56,165,107,218,223,160,9,229,72,73,31,0,31,80,116, 117,7,24,212,13,71,234,134,179,201,189,174,104,184,65,209,129,72,209,129, 112,194,28,234,58,208,20,185,35,144,178,17,104,214,28,234,26,97,210,133,146, 111,164,15,130,83,231,80,217,65,161,50,52,39,25,239,36,58,168,57,73,77,109, 85,107,69,99,147,63,47,73,177,102,199,75,173,234,248,244,22,117,107,133,151, 32,171,199,201,170,199,41,45,205,80,203,113,6,45,19,100,213,9,158,150,44, 210,50,193,160,229,120,49,211,58,222,219,196,7,84,28,31,241,39,216,171,114, 251,122,115,206,169,117,157,209,90,81,55,181,41,155,68,211,186,42,127,118, 174,53,230,202,37,127,61,181,137,21,165,39,54,30,215,224,200,194,241,185, 233,104,250,167,31,201,152,174,245,53,170,90,25,214,124,29,10,154,58,62,209, 162,219,178,210,245,186,242,122,183,242,196,169,77,10,177,14,160,158,204, 152,235,9,107,174,72,215,224,136,70,197,127,133,55,76,11,210,235,125,212, 232,248,175,180,172,221,80,160,8,77,216,201,241,139,170,106,111,209,188,233, 145,189,65,122,163,33,34,158,193,154,42,96,77,101,145,163,149,123,198,213, 17,210,26,9,106,114,158,96,186,49,58,215,210,139,56,3,107,141,161,59,32,113, 77,66,160,201,70,28,57,19,48,125,166,147,216,65,66,48,49,119,102,20,24,180, 212,64,94,179,128,214,108,32,175,37,178,81,104,105,67,1,221,198,71,65,22, 208,211,116,237,211,252,205,201,227,166,52,180,104,15,251,211,136,163,166, 69,219,168,84,253,228,161,35,15,101,42,146,174,60,43,242,105,70,94,153,46, 71,150,233,14,77,103,170,169,154,30,82,200,212,204,144,106,102,56,228,80,60, 162,103,134,143,82,243,59,89,122,152,169,215,157,25,88,164,7,7,57,206,79, 213,232,20,108,33,246,194,66,124,215,234,233,208,99,222,215,50,139,104,153, 229,36,122,16,45,166,232,154,37,251,229,172,200,113,34,44,102,163,176,152, 77,159,77,89,80,156,165,235,62,11,143,114,103,17,83,200,193,119,74,196,223, 102,100,25,227,206,178,140,113,103,139,218,103,219,186,42,57,16,79,85,237, 201,26,55,49,121,182,100,242,108,99,39,157,35,64,205,49,116,210,57,112,132, 155,75,48,147,163,227,210,115,11,7,79,219,198,183,185,246,241,237,92,33,112, 174,141,52,114,238,156,170,218,139,3,48,177,118,46,28,221,206,53,18,119,158, 0,118,158,129,184,243,44,163,219,60,20,198,243,248,83,152,78,248,5,196,94, 114,248,91,250,130,194,51,23,166,250,2,75,112,94,40,106,95,104,227,249,66, 210,174,91,181,107,212,174,137,225,11,101,92,94,104,164,119,190,192,51,223, 64,239,252,66,92,114,21,232,60,181,244,197,116,153,136,13,17,151,232,138,47, 193,67,196,37,132,8,114,218,153,18,233,234,109,95,171,108,204,183,214,230, 219,178,106,238,40,16,95,98,241,195,2,81,123,129,205,15,228,100,50,85,181, 183,104,222,228,142,5,210,29,11,140,238,88,40,96,45,52,184,99,33,28,38,46, 37,168,47,37,168,47,117,159,1,61,212,85,217,90,25,180,151,218,199,135,203, 132,192,101,54,190,200,9,95,170,106,151,176,101,19,79,151,193,129,225,50,35, 85,151,11,68,151,27,168,186,220,50,48,44,22,181,23,27,180,92,17,198,191,124, 100,121,204,157,212,52,53,225,245,231,199,132,38,183,118,242,132,214,6,196, 219,227,132,183,199,61,181,33,83,122,121,135,150,214,108,222,201,170,181, 134,70,93,247,227,5,221,18,228,10,247,119,83,83,197,148,134,198,202,122,12, 117,133,128,170,62,65,244,22,192,91,16,90,242,213,94,90,125,52,232,234,175, 245,170,75,208,43,205,160,87,106,173,72,220,171,124,114,225,91,168,85,34, 140,220,218,201,35,115,211,120,81,200,119,57,177,224,169,96,216,10,190,95, 74,147,239,232,210,234,251,184,218,70,94,148,169,106,108,118,71,50,241,252, 249,84,212,114,198,181,165,54,95,237,149,214,39,146,115,166,15,32,47,84,158, 98,24,88,3,165,205,173,240,80,119,175,5,101,136,254,250,233,41,58,43,124, 154,40,123,90,189,216,108,82,159,99,139,227,191,213,53,15,174,85,186,92,65, 105,202,54,103,167,202,105,233,211,5,90,137,138,213,140,81,242,193,93,122, 181,100,116,181,153,209,213,144,209,213,245,137,204,192,126,67,14,155,147, 215,121,88,77,7,194,103,8,40,242,209,94,250,25,245,241,117,171,151,69,160, 178,161,177,165,173,89,124,135,166,170,120,182,161,161,240,89,249,180,240, 44,123,232,208,219,126,142,17,242,28,145,124,78,18,242,156,153,144,231,32, 33,207,213,39,58,28,124,112,191,209,190,45,229,58,43,207,137,1,111,141,68, 191,6,60,235,232,23,75,26,235,217,109,230,5,98,225,11,68,224,5,183,159,7, 236,54,228,178,85,130,218,23,44,212,190,40,219,127,209,66,237,90,70,45,249, 176,44,189,86,82,187,214,76,237,90,72,237,218,250,68,87,151,218,113,174,33, 253,10,99,18,33,120,173,32,248,37,105,195,75,54,130,95,162,4,251,150,189, 194,44,123,133,136,188,34,45,123,197,108,217,43,208,178,87,234,19,29,93,203, 198,230,171,26,71,246,155,51,189,156,12,80,175,48,48,172,165,246,158,127,93, 73,225,220,87,192,8,245,10,53,109,29,51,109,29,209,190,78,154,182,206,108, 218,58,104,218,186,250,68,167,125,142,204,182,102,79,204,85,171,151,139,196, 97,235,40,154,87,25,154,87,73,211,175,58,137,142,53,181,77,185,10,119,198, 146,173,104,106,226,23,131,187,115,74,199,244,42,24,87,133,86,143,65,165,84, 48,248,106,129,65,38,145,116,37,152,157,175,178,160,89,207,108,33,31,127, 165,215,75,102,215,155,153,93,15,153,93,175,152,29,221,232,228,16,179,235, 41,154,191,147,166,254,14,39,7,133,214,254,14,56,19,242,30,103,149,110,227, 130,179,191,135,147,30,57,123,120,93,111,216,159,68,240,81,231,117,129,199, 21,74,85,40,64,154,121,175,163,206,251,134,223,121,153,194,13,66,225,6,221, 192,160,147,109,96,21,200,39,226,170,160,100,108,75,225,233,41,227,94,104, 109,158,169,46,108,148,227,224,70,130,105,163,63,207,171,45,236,91,32,64,54, 202,233,209,198,96,31,16,154,95,109,10,77,142,54,165,108,18,193,178,137,239, 9,193,5,112,47,216,38,22,180,228,123,47,37,199,131,118,19,9,218,18,22,161, 155,220,123,225,160,65,131,220,17,173,159,251,63,58,170,109,226,136,198,234, 254,221,228,133,143,14,237,45,210,238,91,214,8,126,75,242,250,86,224,65,25, 147,239,104,30,194,243,218,119,68,3,239,200,6,222,49,124,3,153,222,172,215, 218,92,248,6,178,47,107,227,93,244,220,254,174,163,191,217,75,19,62,182,48, 87,109,33,252,108,145,174,218,98,30,95,182,192,241,101,75,125,34,213,207, 253,167,251,101,11,117,202,123,164,133,247,92,113,127,130,43,8,123,15,140, 41,66,216,184,237,239,61,121,244,67,250,125,102,255,251,68,219,251,210,254, 247,205,246,191,15,237,127,191,62,209,190,223,33,67,250,185,168,6,232,28, 188,79,129,144,175,199,210,31,184,19,46,151,131,224,220,37,25,154,31,0,34, 128,6,95,28,110,252,252,0,144,241,33,35,227,67,162,241,67,73,198,135,102,50, 62,132,100,124,232,62,57,13,164,147,252,15,197,108,107,43,10,226,173,14,121, 111,78,163,248,31,12,248,63,8,202,127,72,224,255,48,3,255,7,4,254,15,16,197, 255,160,236,145,15,192,210,255,52,71,241,63,129,243,132,176,121,23,243,63, 129,231,62,98,4,124,68,212,125,36,9,248,200,76,192,71,144,128,143,20,1,110, 24,235,4,124,68,65,144,207,192,210,31,155,9,248,24,16,32,132,141,103,216, 165,63,6,4,124,194,8,248,132,168,251,68,18,240,137,153,128,79,32,1,159,212, 39,74,104,228,126,34,34,247,83,20,185,159,130,125,26,52,124,63,99,224,63,35, 72,63,147,224,63,51,131,255,12,130,255,12,132,239,103,148,65,242,77,87,250, 115,203,42,195,231,192,125,66,186,136,189,231,159,3,63,110,99,84,108,35,122, 183,73,42,182,153,169,216,6,169,216,230,5,242,161,132,138,109,20,196,23,164, 133,47,44,84,124,1,168,16,210,241,71,4,166,191,0,84,124,201,168,248,146,232, 253,82,82,241,165,153,138,47,33,21,95,138,144,254,82,132,244,87,40,164,191, 114,37,162,29,177,165,4,246,215,12,246,215,4,227,215,18,246,215,102,216,95, 67,216,95,131,96,254,154,114,247,13,105,225,27,243,80,244,13,112,160,16,54, 157,202,144,254,6,184,237,91,102,255,183,68,219,183,210,254,111,205,246,127, 11,237,255,22,12,197,223,82,16,255,34,45,252,203,108,255,191,128,253,66,216, 152,116,58,253,47,64,192,119,140,128,239,136,186,239,36,1,223,153,9,248,14, 18,240,157,34,192,125,26,32,79,2,223,49,16,188,5,101,67,163,220,242,241,157, 255,229,133,70,229,119,212,156,127,19,77,255,54,83,249,111,64,165,16,54,230, 35,79,255,27,80,249,31,70,229,127,136,186,255,72,42,255,99,166,242,63,144, 202,255,136,33,224,63,98,8,248,30,13,1,223,59,100,31,40,93,130,255,129,225, 254,129,128,252,65,226,254,193,140,251,7,136,251,7,48,6,252,64,201,35,31,78, 166,127,52,59,238,71,224,56,33,108,252,250,52,253,35,112,220,79,140,128,159, 136,186,159,36,1,63,153,9,248,9,18,240,83,125,34,173,6,129,211,117,6,126,34, 40,50,228,131,201,76,194,200,128,186,196,25,144,194,198,67,191,51,9,201,64, 166,29,101,32,67,214,88,50,237,4,3,170,200,192,128,186,36,25,200,180,171,79, 180,219,91,179,62,211,142,34,32,175,170,50,37,102,235,75,128,245,66,216,118, 64,120,166,4,16,144,100,4,36,137,198,164,36,32,105,38,32,9,9,72,186,4,76, 214,9,72,146,21,253,76,138,224,33,223,73,102,82,133,173,210,45,181,213,226, 165,148,186,138,115,141,102,210,98,189,44,163,42,40,45,57,244,214,56,147, 102,52,164,185,44,167,33,109,166,33,13,105,72,171,7,236,33,62,2,157,141,52, 31,200,50,25,97,104,198,176,153,85,93,16,175,72,50,237,137,101,228,123,195, 76,251,136,208,89,98,53,51,211,62,36,148,109,25,206,148,201,182,203,220,191, 167,204,108,69,175,71,50,101,140,206,50,46,201,233,44,51,211,89,6,233,44, 171,79,100,250,13,81,237,235,100,150,9,50,203,37,240,114,39,145,174,205,183, 14,29,142,144,151,51,228,229,92,148,35,47,55,35,47,135,200,203,235,19,165, 253,134,120,0,116,232,229,2,122,7,9,189,131,15,253,23,195,16,244,14,12,122, 7,46,202,161,119,48,67,239,0,161,119,40,64,255,197,48,29,122,7,1,189,163,8, 173,142,166,16,238,8,94,66,101,58,51,83,58,19,145,206,210,148,206,102,83,58, 67,83,58,243,25,69,166,179,176,98,59,48,163,200,108,7,190,222,72,18,240,93, 24,248,46,4,105,23,9,190,139,25,124,23,8,190,139,156,86,100,186,80,6,187, 146,22,186,154,111,43,93,193,109,69,8,219,143,48,80,53,196,141,165,27,99, 129,124,108,155,233,38,89,232,102,102,161,27,100,161,91,125,162,187,154,91, 120,176,242,141,3,246,154,211,178,151,90,181,211,166,219,153,110,12,19,107, 176,115,100,151,250,143,48,172,27,159,118,103,186,137,40,233,142,162,164, 187,241,163,28,26,43,61,24,75,61,8,194,30,146,165,30,102,150,122,64,150,122, 128,88,233,65,93,181,61,105,97,123,115,172,108,15,98,69,8,23,115,182,131, 170,39,34,166,39,227,130,124,179,155,233,41,185,232,105,230,162,39,228,162, 103,125,98,23,21,49,26,56,55,110,250,29,57,110,78,211,233,115,154,38,247, 227,209,211,139,224,235,69,26,239,229,36,182,231,150,122,27,156,132,173,189, 252,32,250,111,20,123,255,53,41,214,28,219,75,68,103,111,20,157,189,209,151, 123,37,4,211,14,204,25,59,16,140,59,72,103,236,96,118,198,14,208,25,59,128, 192,220,129,70,68,31,6,162,15,105,177,143,4,209,199,12,162,15,4,209,167,62, 177,125,196,68,24,9,44,14,118,36,168,118,36,77,238,232,36,186,68,26,12,33, 176,163,12,129,159,161,19,123,127,71,225,253,29,133,247,251,34,239,247,197, 95,52,210,129,105,39,70,253,78,4,224,78,146,250,157,204,212,239,4,169,223,9, 248,127,39,234,255,157,73,11,59,155,7,166,157,193,192,36,132,99,79,36,82, 149,180,81,201,167,112,23,162,116,23,162,116,23,39,209,149,40,109,157,217, 36,103,213,187,132,179,106,118,164,67,166,159,156,14,245,115,159,96,85,136, 180,102,213,167,233,114,146,183,43,243,203,174,68,122,87,233,151,93,205,126, 217,21,250,101,215,250,68,185,26,36,85,95,96,253,96,87,6,133,181,67,185,80, 255,23,92,236,42,130,118,87,17,180,187,73,86,118,83,223,235,251,155,204,16, 41,187,51,82,118,39,194,187,75,82,118,55,147,178,59,36,101,247,96,174,225, 114,210,239,244,0,9,31,37,118,103,152,88,131,69,176,179,187,96,103,119,193, 206,30,66,106,15,183,157,137,110,224,33,102,250,51,102,250,19,84,253,37,51, 253,205,204,244,135,204,244,175,79,116,14,153,145,67,103,127,6,135,181,85,4, 41,253,229,216,217,159,93,247,204,215,105,235,47,143,205,201,160,83,13,50, 123,177,15,119,233,179,243,0,198,222,0,2,127,128,100,111,128,153,189,1,144, 189,1,106,125,204,253,167,175,143,101,6,208,81,112,32,105,98,160,121,20,28, 8,70,65,33,108,73,217,162,46,139,89,217,32,198,193,32,162,112,144,228,96, 144,153,131,65,144,131,65,124,133,108,16,69,176,55,81,191,183,217,254,189, 129,253,66,216,154,222,69,85,16,12,12,102,12,12,38,42,7,75,6,6,155,25,24,12, 25,24,236,70,193,100,246,174,36,51,152,162,24,66,154,24,98,102,97,8,96,65,8, 155,211,17,169,171,226,38,184,15,209,182,15,209,182,79,24,83,112,77,105,31, 227,154,210,190,114,156,223,215,178,166,180,47,115,195,190,92,146,187,97,95, 179,27,246,133,110,216,23,174,41,237,43,70,146,253,36,240,253,108,107,74, 251,49,228,251,113,81,142,124,63,51,242,253,32,242,253,240,154,210,126,2, 250,80,9,125,168,109,77,105,40,131,62,148,139,114,232,67,205,208,135,66,232, 67,241,154,210,80,1,93,188,139,202,12,51,173,41,13,67,107,74,251,51,83,246, 39,34,251,75,83,246,55,155,178,63,52,101,127,177,166,180,191,176,2,157,145, 145,57,64,28,124,162,3,31,206,128,15,39,40,135,75,224,195,205,192,135,67, 224,195,221,192,31,55,103,250,72,118,239,30,206,96,176,54,202,253,111,1,243, 217,169,178,215,15,23,51,153,225,130,10,116,44,71,70,29,203,65,14,50,32,123, 80,50,35,24,23,35,8,168,17,146,139,17,102,46,70,64,46,70,168,117,122,247,95, 109,85,63,125,35,92,102,4,141,166,131,72,43,7,153,135,227,131,192,112,44, 132,59,4,223,232,163,183,215,234,186,184,39,141,100,60,140,36,26,71,74,30, 70,154,121,24,9,121,24,9,222,94,251,205,106,32,88,11,5,51,220,234,142,48,99, 164,8,137,145,212,166,131,137,186,131,205,148,30,12,40,21,194,26,165,114, 228,56,24,80,122,8,163,244,16,162,241,16,73,233,33,102,74,15,129,148,30,82, 159,232,59,176,95,107,77,46,239,206,150,167,247,27,48,103,159,97,85,3,251, 229,26,90,114,234,55,235,124,135,18,112,135,146,150,15,45,230,52,14,85,139, 79,156,99,148,22,56,107,106,206,73,255,253,124,117,69,28,126,81,208,170,69, 197,161,98,160,56,12,13,20,135,57,236,128,8,58,80,28,206,188,121,56,1,119, 184,244,230,225,102,111,30,14,189,121,120,125,162,163,26,40,124,16,116,176, 56,156,134,214,47,73,75,191,52,71,246,47,65,100,11,97,75,222,56,117,89,4, 246,40,70,197,40,162,112,148,164,98,148,153,138,81,144,138,81,106,191,108, 191,67,116,6,70,81,12,71,144,6,142,80,201,90,155,42,196,217,19,132,139,35,0, 23,66,141,253,252,10,85,67,208,49,154,209,49,154,232,28,45,233,24,109,166, 99,52,164,99,180,59,15,56,76,255,64,37,51,90,196,244,145,40,166,143,84,173, 70,167,91,148,17,220,71,49,220,71,17,144,71,73,220,71,153,113,31,5,113,31,5, 86,228,142,162,228,141,33,45,140,49,71,242,24,224,61,33,108,76,168,163,46, 10,199,29,205,8,56,154,168,59,90,18,112,180,153,128,163,33,1,71,203,45,107, 153,163,41,136,95,145,22,126,101,38,224,87,128,0,33,92,230,17,0,239,250,191, 2,12,140,101,12,140,37,250,198,74,6,198,154,25,24,11,25,24,139,238,250,99, 25,8,214,66,169,103,132,220,180,166,174,177,177,125,44,181,231,215,68,213, 175,205,100,254,26,144,41,132,67,50,229,253,254,215,128,204,99,24,153,199, 16,125,199,72,50,143,49,147,121,12,36,243,24,119,88,116,231,145,58,1,199,80, 12,227,24,134,113,164,193,113,18,195,56,51,134,113,16,195,56,228,208,113,12, 4,107,193,39,18,78,226,198,9,151,142,163,22,29,203,44,58,150,40,63,86,90, 116,172,217,162,99,161,69,199,214,39,250,20,57,135,26,79,160,141,39,237,142, 143,63,235,71,213,225,83,158,24,149,62,117,112,254,244,243,149,197,30,173, 83,208,169,185,99,188,184,211,28,135,238,52,234,56,62,112,0,141,15,100,2, 243,225,4,2,108,130,244,225,4,179,15,39,64,31,78,80,139,198,238,63,5,1,248, 109,2,131,195,218,178,156,128,163,46,51,70,38,8,70,142,71,140,28,31,180,8, 239,189,39,48,70,78,32,144,78,144,140,156,96,102,228,4,200,200,9,224,222, 123,2,237,90,39,146,22,78,52,239,247,87,215,196,112,41,164,173,89,216,84,5, 49,98,78,100,44,76,36,42,39,74,22,38,154,89,152,8,89,152,8,110,192,19,233, 82,228,73,4,210,73,164,189,147,220,9,161,103,85,109,75,69,125,190,113,186, 220,50,120,146,113,203,224,36,185,140,52,201,65,7,0,248,213,79,38,48,78,38, 114,39,171,119,120,10,6,56,73,67,93,52,188,13,60,69,212,61,197,173,59,198, 111,92,246,210,83,72,155,167,248,135,145,195,93,44,190,26,212,211,79,101,30, 61,149,232,60,85,122,244,84,179,71,79,133,30,61,85,30,66,226,183,162,137, 181,27,163,251,251,84,209,95,79,11,45,10,63,5,246,203,72,251,167,185,138, 142,229,5,99,120,193,168,186,136,79,186,243,244,52,98,232,105,22,62,189,150, 234,254,11,225,49,49,194,229,174,112,109,190,53,87,157,147,175,195,124,35, 162,195,12,85,65,201,97,135,138,42,170,160,52,80,226,21,102,19,40,2,78,103, 17,112,58,193,114,186,140,128,211,205,17,112,58,140,128,211,235,19,25,181, 182,200,130,224,116,38,217,238,88,251,101,18,35,167,139,24,57,3,196,200,25, 98,96,60,131,135,196,25,44,36,232,38,136,51,136,229,103,88,188,122,134,244, 170,16,182,121,245,12,238,213,51,132,87,207,64,94,61,3,123,117,50,243,234, 100,130,101,178,244,234,100,179,87,39,67,175,78,6,253,122,50,19,163,62,155, 12,222,201,86,200,65,183,130,158,88,66,29,242,91,102,215,111,137,232,111, 165,93,191,53,219,245,91,104,215,111,235,19,237,200,82,206,111,169,87,179, 68,125,214,252,200,146,5,247,96,33,108,190,77,100,193,253,119,10,179,126,10, 81,55,69,90,63,197,108,253,20,104,253,148,250,68,201,64,98,254,20,118,52,65, 198,33,45,56,150,89,136,3,24,16,210,254,44,196,240,249,183,170,32,88,200,49, 22,114,68,101,78,178,144,51,179,144,131,44,228,220,24,24,168,147,144,163,83, 144,42,130,167,138,52,86,85,204,249,128,170,150,97,26,82,237,215,213,26,175, 70,111,184,170,29,120,16,118,166,70,52,85,227,18,50,122,52,26,36,106,25,145, 181,164,133,90,73,100,173,153,200,90,72,100,109,125,162,44,92,239,38,67,69, 45,19,118,33,234,54,215,214,177,23,208,228,108,234,12,57,155,58,83,111,59, 93,80,93,53,80,221,32,168,70,39,151,103,26,12,84,203,155,128,58,57,122,28, 98,58,207,152,206,147,6,242,146,233,188,153,233,60,100,58,175,22,163,149, 253,253,252,7,42,66,118,158,201,183,27,167,27,157,231,61,188,137,161,37,103, 15,101,154,36,218,38,51,218,38,136,182,73,188,40,109,18,183,134,51,209,67, 218,153,44,211,10,157,193,53,51,224,205,4,101,179,4,222,108,6,222,12,129,55, 131,167,180,102,26,169,45,4,82,11,105,175,197,73,116,246,224,155,31,80,90, 140,225,218,42,67,179,213,242,128,210,70,112,180,17,185,54,183,199,248,56, 208,173,167,205,248,132,50,77,212,157,102,123,66,153,70,26,157,102,153,62, 77,51,62,161,76,103,62,157,78,116,78,151,62,157,110,246,233,116,232,211,233, 96,38,51,157,137,209,153,140,56,17,52,19,237,206,141,102,159,51,68,251,51, 248,19,202,12,62,29,157,97,125,66,153,65,12,157,97,225,115,134,124,66,249, 121,194,99,98,132,109,115,217,25,124,46,59,67,204,101,103,160,185,236,12,60, 151,157,201,34,128,156,97,158,153,41,35,96,166,57,2,102,194,8,152,137,159, 80,102,50,73,246,132,34,46,147,24,153,41,98,100,22,136,145,89,98,210,52,139, 135,196,44,235,19,10,57,138,93,213,53,122,117,150,244,170,16,182,121,117,22, 247,234,44,225,213,89,200,171,179,176,87,103,51,175,206,38,88,102,75,175, 206,54,123,117,54,244,234,108,208,175,103,51,49,234,179,217,224,9,229,108, 57,234,158,109,123,66,153,195,236,154,67,68,231,72,187,230,152,237,154,3, 237,154,195,159,80,230,80,175,158,67,212,159,99,126,66,57,7,204,207,133,176, 229,62,113,14,152,156,207,101,230,147,227,226,51,115,165,249,115,205,230, 207,133,230,207,21,143,40,115,249,4,230,60,210,194,121,150,71,148,243,0,5, 66,186,147,79,129,233,25,229,60,64,195,249,140,134,243,137,206,243,37,13, 231,155,105,56,31,210,112,190,56,162,42,115,190,8,94,116,246,124,102,158, 195,18,31,209,0,190,128,65,39,231,207,103,46,144,208,47,48,67,191,0,66,191, 160,62,209,65,77,162,124,16,196,149,23,80,26,201,25,244,153,11,45,142,188, 16,56,82,72,119,246,91,172,112,101,160,39,47,4,158,156,207,232,152,79,148, 206,151,116,204,55,211,49,31,210,49,95,122,114,190,240,228,69,200,147,23, 129,44,134,58,246,139,25,246,139,9,208,139,37,246,139,205,216,47,134,216,47, 14,92,121,240,193,253,196,199,34,23,51,44,172,161,142,1,242,138,214,220,12, 233,138,139,197,107,156,139,5,39,151,32,78,46,145,73,15,51,4,200,2,70,10,57, 95,63,179,64,146,178,192,76,202,2,72,202,2,240,144,176,128,70,213,66,210, 194,66,243,24,189,16,196,181,16,238,88,48,24,110,165,88,8,162,122,17,35,97, 17,81,185,72,146,176,200,76,194,34,72,194,34,240,38,103,17,125,82,34,25,3, 50,36,99,64,230,82,119,216,13,173,130,95,85,93,106,124,80,186,76,222,178,47, 115,229,90,179,213,168,147,92,206,168,184,156,8,94,46,169,184,220,76,197, 229,144,138,203,221,78,226,219,82,225,98,32,227,221,229,34,168,127,39,193, 255,206,157,111,180,229,13,240,23,51,248,139,137,232,98,9,127,177,25,254,98, 8,127,113,125,193,21,21,30,10,98,192,98,126,239,189,146,52,118,165,57,178, 175,4,145,45,132,163,200,70,155,221,174,4,145,125,21,227,227,42,162,242,42, 201,199,85,102,62,174,130,124,92,37,199,235,171,132,27,127,143,198,166,223, 59,44,145,39,189,243,94,205,160,95,77,112,94,45,161,95,109,134,126,53,132, 126,117,48,92,251,32,136,35,175,166,52,254,129,52,244,7,179,27,255,0,220,40, 132,59,250,13,122,95,52,203,77,122,127,0,110,188,134,113,113,13,81,121,141, 228,226,26,51,23,215,64,46,174,145,110,188,70,184,241,58,228,198,235,88,38, 92,114,176,92,230,122,134,252,122,2,243,122,137,252,122,51,242,235,33,242, 235,193,253,229,122,74,223,13,164,133,27,204,238,187,1,184,79,8,151,85,153, 78,149,82,87,133,239,110,100,12,220,72,244,221,40,25,184,209,204,192,141, 144,129,27,213,135,58,135,12,169,162,159,205,221,72,97,252,145,180,241,71, 51,7,127,4,28,8,225,128,3,52,12,253,17,112,240,39,198,193,159,136,190,63,73, 14,254,100,230,224,79,144,131,63,241,175,230,254,68,17,220,68,212,223,100, 54,255,38,96,190,16,238,88,101,59,88,234,38,192,192,205,140,129,155,137,202, 155,37,3,55,155,25,184,25,50,112,179,219,131,39,211,30,124,179,232,193,127, 70,61,248,207,14,75,207,76,187,240,45,12,250,45,4,231,45,18,250,45,102,232, 183,64,232,183,160,207,62,111,161,4,222,74,154,184,213,236,192,91,129,3,133, 112,135,42,203,119,159,183,2,255,221,198,72,184,141,104,188,77,146,112,155, 153,132,219,32,9,183,241,8,190,141,34,248,11,81,255,23,51,1,127,1,4,8,225, 78,85,214,15,63,255,2,40,248,43,163,224,175,68,231,95,37,5,127,53,83,240,87, 72,193,95,209,135,159,127,165,40,254,135,52,241,63,102,26,254,7,208,32,132, 203,171,204,95,126,254,15,224,224,118,198,193,237,68,225,237,146,131,219, 205,28,220,14,57,184,93,188,12,186,93,244,226,59,80,47,190,67,207,253,78, 123,240,157,12,245,157,4,226,157,18,245,157,102,212,119,66,212,119,130,155, 240,157,148,186,187,72,11,119,153,29,119,23,112,156,20,174,194,143,119,119, 1,167,45,97,230,47,33,202,150,72,243,151,152,205,95,2,205,95,2,30,239,150, 80,16,119,147,22,238,54,155,127,55,48,95,8,151,86,53,225,125,242,119,3,251, 239,97,246,223,67,180,221,35,237,191,199,108,255,61,208,254,123,208,182,234, 123,24,8,214,66,218,53,1,236,146,191,71,44,117,220,67,173,185,151,40,186, 215,76,228,189,128,72,33,28,16,41,247,200,223,11,136,92,202,136,92,74,180, 45,149,68,46,53,19,185,20,18,185,84,244,254,165,162,247,223,135,122,255,125, 190,41,109,121,195,58,207,253,12,250,253,4,231,253,18,250,253,102,232,247, 67,232,247,131,33,224,126,202,223,3,164,133,7,204,174,123,0,184,78,8,119,8, 236,133,227,192,3,192,125,15,50,14,30,36,26,31,148,28,60,104,230,224,65,200, 193,131,96,28,120,144,130,88,198,64,44,35,45,46,147,32,150,153,65,44,131,32, 150,161,206,184,140,129,96,45,148,23,184,4,61,114,153,232,145,203,168,73, 203,137,182,229,102,183,46,7,110,21,194,161,91,209,61,121,57,112,235,67,140, 209,135,136,198,135,36,163,15,153,25,125,8,50,250,144,232,149,15,137,94,249, 48,234,149,15,171,97,206,148,65,32,243,8,3,254,8,65,249,136,4,254,136,25, 248,35,16,248,35,160,79,62,66,217,251,27,105,225,111,102,231,253,13,56,79,8, 151,85,153,50,96,168,171,194,117,143,50,6,30,37,250,30,149,12,60,106,102, 224,81,200,192,163,160,71,62,74,65,60,70,90,120,204,204,192,99,128,1,33,28, 48,128,130,247,49,192,192,227,140,1,146,119,52,243,184,100,224,113,51,3,143, 67,6,30,23,193,251,184,8,222,39,80,240,62,161,130,215,29,63,166,193,224,93, 193,128,175,32,40,87,72,224,43,204,192,87,64,224,43,64,240,174,160,236,145, 188,167,153,149,102,215,173,4,174,19,194,101,158,181,48,120,87,2,215,61,201, 24,120,146,232,123,82,50,240,164,153,129,39,33,3,79,170,13,131,135,12,241, 96,17,26,158,164,72,86,145,102,86,153,105,88,5,104,16,194,1,13,40,130,87,1, 26,88,230,214,12,201,162,154,145,153,91,51,230,204,173,25,152,185,53,243, 148,136,224,167,68,4,63,45,176,62,237,134,239,113,173,53,106,115,156,124,79, 64,146,161,102,86,187,127,231,102,212,70,110,143,182,164,172,14,49,234,181, 219,123,185,8,131,68,128,228,66,33,155,24,208,194,50,164,101,86,215,39,122, 181,229,189,125,111,253,78,152,56,174,159,39,215,230,229,38,211,237,88,29, 217,81,135,18,235,101,158,139,94,4,251,57,204,248,62,181,231,68,28,184,34, 60,173,94,230,57,180,219,115,13,74,171,151,121,94,40,124,94,15,172,96,202, 241,60,171,208,110,148,222,220,243,200,45,36,129,105,230,5,115,32,191,16,5, 138,86,164,118,6,49,168,47,10,209,23,1,212,23,89,5,127,223,142,86,80,50,170, 5,189,163,32,121,78,51,107,205,120,215,74,188,107,253,29,68,186,186,151,88, 87,122,137,168,127,73,118,165,151,204,93,233,37,216,149,94,114,187,210,96, 50,148,188,68,33,188,76,244,191,108,217,99,240,178,52,233,229,128,40,25,163, 235,104,106,52,63,78,249,9,88,235,68,27,235,64,156,174,67,113,186,14,198, 233,171,66,225,171,192,249,175,210,190,10,133,82,19,154,115,14,43,83,222, 211,112,189,138,2,132,101,2,205,144,76,160,25,153,9,52,99,206,4,154,129,153, 64,51,235,235,19,233,217,115,166,15,166,211,253,245,76,208,199,175,161,165, 57,66,51,36,199,103,230,239,230,64,254,187,244,250,223,101,32,191,198,204, 126,141,168,127,77,154,253,154,217,236,215,160,217,175,213,39,218,157,173, 27,244,154,232,250,34,155,104,230,117,224,253,215,169,247,161,144,240,254, 235,190,201,172,214,40,55,178,209,70,236,55,24,27,111,16,211,223,144,108, 188,97,102,227,13,200,198,27,48,8,222,96,130,34,8,222,160,94,219,64,64,108, 48,7,193,6,25,4,27,100,16,108,100,102,147,228,168,153,141,210,236,141,102, 179,55,66,179,55,214,39,146,103,211,225,108,35,197,64,146,152,102,54,217,19, 52,170,235,220,174,77,161,95,89,116,189,41,164,223,148,210,111,146,168,160, 247,58,146,212,52,243,150,101,164,149,41,77,85,81,160,88,142,181,239,248,86, 214,100,155,157,138,230,92,53,204,107,154,17,121,77,51,50,175,169,42,106,55, 30,97,223,204,92,187,153,216,178,89,186,118,179,217,181,155,161,107,55,171, 57,95,11,9,231,205,63,15,66,167,194,28,205,37,181,178,134,95,109,239,50,131, 207,106,219,236,25,173,199,212,102,196,242,22,191,123,24,9,222,34,8,222,34, 9,86,69,174,27,209,7,11,239,17,107,223,99,214,146,252,169,153,247,172,214, 186,87,59,215,182,168,83,24,42,27,27,26,219,208,97,12,239,5,56,208,254,161, 247,229,221,246,125,199,152,10,62,67,18,154,102,62,160,177,40,56,1,41,81, 165,134,50,229,43,124,234,247,7,5,2,121,247,252,80,162,254,144,39,127,215, 27,221,202,8,222,74,68,183,202,136,222,106,142,232,173,48,162,183,186,131, 85,51,251,20,105,43,195,192,26,176,24,190,53,48,92,143,211,173,248,249,224, 35,63,82,93,65,28,169,31,9,175,124,36,35,245,35,115,164,126,76,140,248,152, 17,73,82,132,102,62,182,70,234,199,241,145,250,177,37,82,63,145,62,255,196, 18,169,159,146,154,159,198,68,234,167,32,82,133,134,50,183,178,193,97,159, 154,34,245,51,137,250,51,26,169,52,21,193,231,140,96,146,196,51,243,185,140, 212,207,205,145,250,57,140,212,207,221,72,157,198,34,245,115,134,129,53,96, 49,252,115,16,169,159,211,173,143,219,136,114,146,61,52,179,205,73,116,84, 202,27,106,167,229,242,185,22,185,95,106,155,37,34,190,144,220,126,225,254, 237,228,178,48,237,213,23,140,218,47,184,36,167,246,11,51,181,95,64,106,191, 168,87,71,95,187,205,147,15,106,191,16,65,241,165,48,243,75,211,233,174,95, 6,167,187,194,190,255,109,56,137,195,125,255,91,17,231,223,202,190,255,173, 246,205,13,241,219,191,8,123,36,3,101,70,165,175,116,251,178,171,66,152,242, 47,79,31,242,215,119,210,188,239,44,61,152,36,106,204,252,59,28,231,132,81, 255,150,70,253,27,46,23,252,71,2,248,15,190,109,248,245,191,39,120,190,39, 130,223,251,12,4,131,9,97,224,123,35,3,63,72,0,63,88,24,32,25,15,51,63,134, 115,18,193,192,143,146,129,31,33,3,63,73,0,63,89,24,40,77,232,120,74,73,254, 193,210,132,207,64,237,84,241,253,149,186,132,25,40,109,39,0,148,182,51,51, 80,90,66,251,108,41,201,1,88,90,34,250,172,42,50,244,217,210,18,212,103,75, 75,212,84,148,140,134,165,37,12,2,211,95,230,90,236,198,97,67,155,152,93, 170,171,116,221,160,180,132,187,160,52,41,25,72,218,92,64,158,54,75,73,202, 192,82,247,74,123,215,5,85,77,32,12,213,69,131,19,100,198,192,210,180,197,9, 25,230,132,12,145,204,72,39,100,204,78,200,64,39,100,220,123,82,21,243,66, 134,97,96,13,116,240,140,198,119,37,117,157,249,33,35,252,80,42,73,40,181, 249,129,100,75,40,37,153,6,75,219,251,83,27,47,151,9,62,171,75,85,49,120,67, 166,27,44,45,179,120,131,37,237,43,37,73,251,74,101,210,190,82,115,210,190, 82,152,180,175,180,188,62,145,58,146,125,87,95,90,206,64,176,22,186,106,182, 27,24,40,23,78,17,105,0,75,101,26,192,210,14,150,137,125,105,71,82,181,163, 99,90,233,47,237,40,86,250,85,109,184,210,175,46,4,183,85,160,131,173,243, 151,118,172,79,116,152,146,117,188,53,254,64,162,96,112,71,127,8,38,255,248, 61,188,180,59,56,30,22,222,205,75,187,243,97,95,201,178,97,95,21,165,198,77, 105,64,107,18,165,36,223,90,105,15,195,185,180,36,64,122,200,22,122,4,45, 168,50,237,219,215,210,30,217,118,200,190,158,200,190,36,120,145,81,218,83, 180,94,72,108,166,199,97,79,86,129,156,239,32,174,166,42,38,52,66,46,122, 177,94,68,210,146,149,246,146,189,168,151,185,23,245,130,189,168,151,59,166, 241,78,212,139,137,81,240,34,161,89,105,111,209,86,111,64,73,111,86,161,221, 56,86,80,50,174,133,235,8,105,33,43,218,165,44,19,90,41,201,132,86,42,51, 161,149,154,51,161,149,194,76,104,165,59,212,39,210,227,248,98,166,223,142, 38,72,137,241,51,165,165,221,70,42,107,212,239,62,122,109,149,6,109,124,110, 186,107,16,25,174,119,212,235,236,232,91,140,70,223,190,225,96,161,7,115, 223,108,26,60,157,149,246,101,244,244,37,92,244,149,244,244,53,211,211,23, 210,211,183,62,177,93,121,63,242,239,255,27,114,72,200,100,161,187,84,54, 145,1,61,213,200,97,20,189,114,200,67,125,240,93,237,96,97,109,12,117,232, 54,200,129,50,54,74,48,40,160,248,81,129,152,130,68,1,179,32,81,192,72,152, 10,240,168,196,200,9,138,24,38,42,166,96,204,30,177,43,162,41,192,218,167, 98,87,130,221,152,1,210,153,154,159,6,18,83,206,2,0,1,9,48,176,0,0,0,76,105, 110,101,0,0,4,122,0,0,0,0,0,0,0,0,0,0,3,18,0,0,2,51,0,0,0,0,41,132,41,136, 41,137,41,138,41,139,41,140,41,141,41,142,41,146,41,148,41,149,41,161,41, 162,41,163,41,164,41,165,41,173,41,174,41,177,41,181,41,183,41,194,41,196, 41,198,41,200,41,201,41,203,41,206,41,207,41,208,41,210,41,211,41,212,41, 213,41,224,41,218,41,216,41,214,41,226,41,227,41,228,41,229,41,231,41,232, 41,239,41,241,41,242,41,243,41,244,41,245,41,246,41,247,41,253,41,254,73,3, 73,4,73,5,73,7,73,9,73,10,73,16,73,17,73,18,73,19,73,21,73,23,73,24,73,28, 73,31,73,32,73,38,73,40,73,41,73,42,73,43,73,44,73,45,73,52,73,53,73,57,73, 59,73,61,73,63,73,69,73,70,73,71,73,72,73,79,73,81,73,84,73,86,73,88,73,89, 73,91,73,93,73,102,73,104,73,107,73,109,73,111,73,112,73,114,73,115,73,117, 73,119,73,125,73,126,73,128,73,130,73,132,73,139,73,140,73,143,73,151,73, 153,73,161,73,162,73,170,73,171,73,172,73,173,73,174,73,175,73,177,73,179, 73,180,73,181,73,183,73,184,73,186,73,190,73,216,73,217,73,222,73,224,73, 226,73,227,73,235,73,236,73,243,73,245,73,253,73,255,105,0,105,1,105,3,105, 9,105,10,105,11,105,22,105,23,105,24,105,25,105,27,105,34,105,36,105,38,105, 40,105,48,105,50,105,52,105,53,105,54,105,56,105,58,105,64,105,66,105,67, 105,68,105,70,105,76,105,77,105,78,105,79,105,80,105,86,105,87,105,88,105, 89,105,108,105,110,105,111,105,112,105,113,105,114,105,115,105,116,105,121, 105,122,105,123,105,124,105,125,105,126,105,127,105,132,105,133,105,134,105, 135,105,140,105,141,105,142,105,147,105,148,105,149,105,164,105,165,105,171, 105,177,105,178,105,207,105,184,105,185,105,172,105,216,105,221,105,217,105, 252,137,1,137,10,137,77,41,184,137,75,137,47,137,40,105,90,137,16,73,110, 137,17,73,113,137,66,73,6,137,67,73,8,137,22,137,27,73,178,137,24,73,176, 137,25,137,81,137,62,137,19,73,85,137,20,73,87,169,22,105,41,137,55,105,37, 137,56,105,39,137,32,137,37,73,225,137,34,73,223,137,35,137,44,105,26,137, 45,105,28,137,52,105,69,137,42,105,2,137,87,73,129,73,62,137,84,73,58,137, 85,73,60,137,49,105,55,137,50,105,57,137,13,137,14,169,20,137,11,137,90,137, 203,137,209,137,108,137,121,137,184,137,132,137,143,137,181,137,99,137,98, 137,171,137,170,137,115,137,111,137,110,137,189,137,165,137,104,137,103,137, 128,137,124,137,123,137,156,137,155,137,154,137,139,137,138,137,135,137,151, 137,199,137,194,137,193,137,192,137,94,137,93,137,147,137,146,137,91,137, 204,137,206,137,211,137,212,137,215,137,252,137,224,137,220,73,108,137,238, 137,218,169,6,41,182,169,4,169,0,137,236,137,230,169,8,41,197,169,2,137,254, 137,240,137,234,137,232,137,216,169,17,169,18,169,29,169,30,169,78,169,102, 73,116,73,118,73,182,73,90,73,92,169,121,73,131,169,118,169,190,169,193,169, 196,169,197,169,198,169,199,169,202,169,207,169,210,169,211,169,212,169,213, 169,200,169,205,169,216,169,219,169,220,169,224,201,54,201,80,201,137,201, 133,201,134,201,135,201,151,201,152,201,153,201,193,201,194,201,195,201,196, 201,197,201,187,201,188,201,189,201,190,201,191,201,16,201,17,201,18,169, 239,169,240,169,241,169,242,169,243,169,233,169,234,169,235,169,236,169,237, 201,164,201,165,201,166,201,167,201,168,201,169,201,170,201,180,201,181,201, 182,201,183,201,184,201,185,201,139,201,140,201,141,201,146,201,144,201,148, 201,149,201,20,201,21,201,22,201,156,201,157,201,158,201,159,201,160,201, 161,201,162,201,29,201,30,201,35,201,33,201,37,201,114,201,115,201,119,201, 123,201,121,201,126,201,127,201,128,201,130,201,131,169,227,169,228,169,229, 169,230,169,231,201,63,201,64,201,65,233,20,201,67,201,25,201,26,201,82,201, 83,201,84,201,85,201,89,201,93,201,91,201,96,201,97,201,98,201,100,201,101, 201,105,201,110,201,112,201,40,201,41,201,42,201,43,201,44,201,45,201,49, 201,48,201,47,201,52,201,172,201,173,201,174,201,175,201,176,201,177,201, 178,169,245,169,246,169,247,169,248,169,249,169,250,169,251,169,253,169,254, 169,255,201,0,201,1,201,2,201,3,201,5,201,11,201,10,201,9,201,14,201,56,201, 57,201,58,201,59,201,60,201,69,201,70,201,71,201,72,201,73,201,74,201,75, 201,76,201,77,201,142,201,117,201,87,201,199,201,202,201,207,201,208,201, 211,201,213,201,214,201,215,201,217,201,218,201,219,201,227,201,228,201,225, 201,232,201,235,201,236,201,240,201,242,201,247,233,2,233,6,233,10,233,12, 233,22,233,23,233,25,233,28,233,30,41,199,0,0>>, []) in call from compile:native_compile_1/1 (compile.erl, line 1361) in call from compile:'-internal_comp/4-anonymous-1-'/2 (compile.erl, line 295) in call from compile:fold_comp/3 (compile.erl, line 321) in call from compile:internal_comp/4 (compile.erl, line 305) in call from compile:'-do_compile/2-anonymous-0-'/2 (compile.erl, line 155) make[3]: *** [../ebin/hipe_rtl.beam] Error 1 make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/rtl' make[2]: *** [opt] Error 2 make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe' make[1]: *** [opt] Error 2 make[1]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' make: *** [libs] Error 2 [ec2-user@REDACTED tmp_1]$ -------------- next part -------------- An HTML attachment was scrubbed... URL: From kuenishi@REDACTED Sun Aug 9 14:53:29 2015 From: kuenishi@REDACTED (UENISHI Kota) Date: Sun, 9 Aug 2015 21:53:29 +0900 Subject: [erlang-questions] standard_error not handling eagain? Message-ID: Hi folks, I'm asking here as I'm not sure how it should be although this looks like a bug to me. Reproduced in MacOS (mine is 10.10.4) AND 18.0 (maint-18 HEAD), but couldn't reproduce in Linux (Ubuntu 14.04) with 18.0 or R16B02 with Mac. To reproduce, it's pretty easy: just print out to standard_error by using io:put_char/1 or io:format/3, with writing a long iolist at least more than a thousand characters [1]: main(_) -> Arg0 = [ [["1234567890" || _ <- [1,2,3,4,5,6,7,8,9,0]], 32, integer_to_list(L), $\n] || L <- lists:seq(1, 200) ], io:format(standard_error, "~p~n", [whereis(standard_error)]), R = io:put_chars(standard_error, Arg0), io:format(standard_error, "~p, ~p~n", [R, whereis(standard_error)]). My result of this code is also copied in that gist [2]. This phenomena seems to happen when writing a long buffer to FD 2 via port driver and suddenly gets EAGAIN back, and the port exits with that error. I believe standard_error should not exit but should retry writing when eagain or eintr was received. Thoughts? [1] https://gist.github.com/kuenishi/76333a8a93bc8ccad308#file-stderr-erl [2] https://gist.github.com/kuenishi/76333a8a93bc8ccad308#file-otp-18-0-maint-18-head -- UENISHI Kota :-) From g@REDACTED Sun Aug 9 16:02:37 2015 From: g@REDACTED (Garrett Smith) Date: Sun, 9 Aug 2015 09:02:37 -0500 Subject: [erlang-questions] Refactoring in anger In-Reply-To: References: Message-ID: On Sun, Aug 9, 2015 at 3:48 AM, Jesper Louis Andersen wrote: > > On Sun, Aug 9, 2015 at 12:07 AM, Garrett Smith wrote: >> >> The original calculate/3 mixes user facing behavior (print error >> messages) with a calculation. If your function returns a mishmash of >> completely unrelated values (e.g. the result of io:format and also the >> result of an area calculation) *it's a mess*. > > > Another point to make could be the area/0 function: > > area() -> > Answer = io:get_line("R)ectangle, T)riangle, or E)llipse > "), > Shape = char_to_shape(hd(Answer)), > case Shape of > rectangle -> Numbers = get_dimensions("width", "height"); > triangle -> Numbers = get_dimensions("base", "height"); > ellipse -> Numbers = get_dimensions("major axis", "minor axis"); > unknown -> Numbers = {error, "Unknown shape " ++ [hd(Answer)]} > end, > > Area = calculate(Shape, element(1, Numbers), element(2, Numbers)), > Area. > > First, projecting out of Answer with hd/1 can be solved by just pattern > matching the first character out of the list. Of course, an empty list would > fail here, but input parsing is hard and Barbie wants to go shopping. > Second, you don't need to project out of numbers and bind it in every > variant if you use the return value of the case expression to match the > dimensions. Third, in addition to separating side-effects from computation, > it is often smart to let errors return structural data which can be handled > by a machine easily. And then provide a function which can interpret the > machine-readable structure into human-readable form. Garrett omits the input > that were failing. I like to keep it around in the error term[0]. Just to elaborate on Jesper's point, this function: char_to_shape("R") -> rectangle; ... char_to_shape(_) -> error(bad_shape). would become char_to_shape("R") -> rectangle; ... char_to_shape(Other) -> error({bad_shape, Other}). This is generally a good idea and I initially had this and used the invalid value in a message to the user. But as the UI is an interview that errors out on the first invalid value, printing the bad value was a bit redundant so in the in interest of simplifying the example I yanked it. But Jesper's right - it's a better general practice to include the offending value as context in an exception. In fact this is a major use of exceptions - to capture context of an error that would otherwise not be available in a bad match, case clause, etc. Garrett From jose.valim@REDACTED Sun Aug 9 17:03:33 2015 From: jose.valim@REDACTED (=?UTF-8?Q?Jos=C3=A9_Valim?=) Date: Sun, 9 Aug 2015 17:03:33 +0200 Subject: [erlang-questions] standard_error not handling eagain? In-Reply-To: References: Message-ID: Thanks for a report that includes a way to reproduce the issue! For reference, this has been reported a couple days ago as well: http://erlang.org/pipermail/erlang-questions/2015-August/085375.html *Jos? Valim* www.plataformatec.com.br Skype: jv.ptec Founder and Director of R&D On Sun, Aug 9, 2015 at 2:53 PM, UENISHI Kota wrote: > Hi folks, > I'm asking here as I'm not sure how it should be although this looks > like a bug to me. Reproduced in MacOS (mine is 10.10.4) AND 18.0 > (maint-18 HEAD), but couldn't reproduce in Linux (Ubuntu 14.04) with > 18.0 or R16B02 with Mac. > > To reproduce, it's pretty easy: just print out to standard_error by > using io:put_char/1 or io:format/3, with writing a long iolist at > least more than a thousand characters [1]: > > main(_) -> > Arg0 = [ [["1234567890" || _ <- [1,2,3,4,5,6,7,8,9,0]], 32, > integer_to_list(L), $\n] > || L <- lists:seq(1, 200) ], > io:format(standard_error, "~p~n", [whereis(standard_error)]), > R = io:put_chars(standard_error, Arg0), > io:format(standard_error, "~p, ~p~n", [R, whereis(standard_error)]). > > My result of this code is also copied in that gist [2]. > > This phenomena seems to happen when writing a long buffer to FD 2 via > port driver and suddenly gets EAGAIN back, and the port exits with > that error. I believe standard_error should not exit but should retry > writing when eagain or eintr was received. Thoughts? > > [1] https://gist.github.com/kuenishi/76333a8a93bc8ccad308#file-stderr-erl > [2] > https://gist.github.com/kuenishi/76333a8a93bc8ccad308#file-otp-18-0-maint-18-head > > -- > UENISHI Kota :-) > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From erlang@REDACTED Sun Aug 9 17:04:08 2015 From: erlang@REDACTED (Joe Armstrong) Date: Sun, 9 Aug 2015 17:04:08 +0200 Subject: [erlang-questions] Refactoring in anger (Felix Gallo) In-Reply-To: References: Message-ID: On Sun, Aug 9, 2015 at 8:25 AM, J David Eisenberg wrote: > Felix Gallo wrote: > >> Nevertheless, if you're going to level a thundering, public j'accuse at >> someone who has clearly gone to great effort to provide a beginner >> experience for erlang newbies, without (apparently) first contacting him >> privately and suggesting improvements in a constructively critical manner, >> please have the decency to run the code that you have etched into your >> stone tablets *before* you hold them aloft and, with fiery mane ablaze in >> the evening sun, present them as the replacement for the gentleman's work. >> >> There are many "problems" with the etudes code. I'm not sure that >> introducing a complex exception handling workflow is one of them, to be >> frank, pedagogically, at the moment that the student is trying to >> understand pattern matching and function headers. Could be. But I think >> we can say it's a matter of taste. >> >> And that's what really rubs me the wrong way about Garrett's post. Being >> 'very preachy', even when volubly disclaimed, is still pretty tasteless. >> But being 'very preachy' and then slapping up code you haven't even run >> once, directly in opposition to your preaching's core point: that's >> hypocritical, and super tasteless. And I enjoy my rich dark ironic comedy >> as much as the next guy, but come on. >> >> F. > > Author of Etudes here. > > There I was at Pepe's Tacos in Las Vegas, waiting for my meal, and I decided > to read the Erlang questions mail list and see what's going on. As the story > unfolded, I started cackling with laughter, until I realized that half > the people > in the restaurant were staring at me like "What the hell is wrong with this > crazy white guy laughing at his phone?" > > So no, I'm not even remotely offended. Hello David, nice to see you in here :-) Garret was of course attacking your code, which is not the same thing as attacking you. If we espouse to beautiful code we must expect people to attack the code when they think it is unbeautiful - this is not an attack on the person who wrote the code, but an opportunity to show how we think it could be done better. Actually if we just replaced the bad code with better code and no discussion we would learn nothing. So I value both your contribution, for giving us something to talk about in the first place, and Garrett for banging on it a bit :-) Me , I'm still learning how to write pretty Erlang code ... writing code that you can still understand years after you wrote it is really difficult. My current theory is that one needs to also write publication quality documentation. Cheers /Joe > Especially because I write in > the preface: > "I was learning Erlang as I was creating the solutions to the ?tudes, > following the philosophy that 'the first way that works is the right way.' > Therefore, don?t be surprised if you see some fairly na?ve code that an expert > Erlang programmer would never write." > > Since the book is open source, if anyone would like to add a better > solution with > a discussion of why it's better, I would be perfectly happy to see that. Modulo > the anger, of course :) > >> On Sat, Aug 8, 2015 at 6:19 PM, Leandro Ostera wrote: >> >> > Just a minor typo: Line 48 should is trying to reassign the Prompt >> > variable. >> > >> > But +1 on the rest. >> > >> > On Sun, Aug 9, 2015 at 2:36 AM, Felix Gallo wrote: >> > >> >> Eshell V7.0 (abort with ^G) >> >> 1> c(geom). >> >> {ok,geom} >> >> 2> c(ask_area). >> >> {ok,ask_area} >> >> 3> ask_area:print_area(). >> >> R)ectangle, T)riangle, or E)llipse > T >> >> ** exception error: no function clause matching >> >> ask_area:error_msg({badmatch,["Enter ","base"," > "]}) (ask_area.erl, line >> >> 69) >> >> in function ask_area:print_area/0 (ask_area.erl, line 9) >> >> >> >> >> >> glass houses, etc. >> >> >> >> F. >> >> >> >> On Sat, Aug 8, 2015 at 3:07 PM, Garrett Smith wrote: >> >> >> >>> We've had an ongoing thread on how to handle some problems >> >>> idiomatically in Erlang: >> >>> >> >>> http://erlang.org/pipermail/erlang-questions/2015-August/085382.html >> >>> >> >>> The OP's questions are coming out of an exercise here: >> >>> >> >>> http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 >> >>> >> >>> This in turn points to a proposed solution here: >> >>> >> >>> >> >>> http://chimera.labs.oreilly.com/books/1234000000726/apa.html#_literal_geom_erl_literal_9 >> >>> >> >>> Upon reading this solution, I became so enraged [1] that I rewrote the >> >>> module and want to make a number of points. >> >>> >> >>> Here's my rewrite: >> >>> >> >>> https://gist.github.com/gar1t/7bb80d728f804554ac32 >> >>> >> >>> The tone of my points below is *very preachy* which is going to annoy >> >>> some people here. I apologize in advance - but hey, ranters gotta >> >>> rant. >> >>> >> >>> # Clarity of "what's going on" >> >>> >> >>> Compare my area/0 to the original area/0. Which is easier to see >> >>> "what's going on"? I'm not boasting here but rather making the most >> >>> important point I can about programming: take the time to be clear in >> >>> your intent! If you're actually clear - in your brain - making the >> >>> code reflect your understanding *is not that hard*. If your code is >> >>> not clear, chances are your brain is not clear. >> >>> >> >>> Maybe the original code works, maybe it doesn't. I can't tell from >> >>> looking at that function, at all. I have to dig around various >> >>> implementation details and hold a bunch of information in my brain to >> >>> understand what the author is maybe trying to do. At some point I >> >>> can't keep it all straight and have to run the thing and observe its >> >>> behavior. *Now* I'm thinking, what happens to the pour schlep who has >> >>> to modify this code. In the real world, this causes fear, and >> >>> loathing, and tests - lots and lots of tests! >> >>> >> >>> We don't have to live this way. >> >>> >> >>> # Separation of concerns (in this case IO vs calculations) >> >>> >> >>> The original calculate/3 mixes user facing behavior (print error >> >>> messages) with a calculation. If your function returns a mishmash of >> >>> completely unrelated values (e.g. the result of io:format and also the >> >>> result of an area calculation) *it's a mess*. >> >>> >> >>> In the rewrite I've added print_area/0, which is responsible for >> >>> displaying results to the user. area/0 returns an area or raises an >> >>> exception. print_area/0 handles both the result and any error. >> >>> >> >>> # Handling invalid input >> >>> >> >>> The original thread here involves a discussion on how to handle bad >> >>> input to a function. My rewrite does one of two things on this front: >> >>> >> >>> - If input is from a user, there's an explicit exception raised on bad >> >>> input that can be used by an error handler to inform the user >> >>> >> >>> - If input is not from a user but rather internal, I don't handle bad >> >>> input at all, but let Erlang crash with a function or case clause >> >>> error >> >>> >> >>> The first case address the user experience. We could let exceptions >> >>> just propagate and upset users with arcane Erlang messages. Or we can >> >>> handle errors politely with intelligible messages. >> >>> >> >>> The original ask_erl.erl handles invalid input by passing atoms like >> >>> 'error' and 'unknown' along a call chain. This is tedious and finally >> >>> culminates in the original calculate/3 - a monster mishmash function >> >>> of error handling, IO, and calculation. >> >>> >> >>> My rewrite raises an exception for those functions that take user >> >>> provided input. I prefer exceptions in this case as they keep return >> >>> values on the happy path, which makes code easier to read. >> >>> >> >>> I don't care about handling internal errors, as long as they manifest >> >>> in an obvious way. >> >>> >> >>> # Avoid variable assignment/binding inside case expressions >> >>> >> >>> Just don't do this: >> >>> >> >>> case Shape of >> >>> rectangle -> Numbers = get_dimensions("width", "height"); >> >>> triangle -> Numbers = get_dimensions("base", "height"); >> >>> ellipse -> Numbers = get_dimensions("major axis", "minor axis") >> >>> end >> >>> >> >>> Now that you're not allowed to do that, what? Hey, a function! >> >>> >> >>> Numbers = get_dimensions(Shape) >> >>> >> >>> Every time, all the time. >> >>> >> >>> # Consider not using case expressions at all >> >>> >> >>> Think of a function as a named case expression with a well defined scope. >> >>> >> >>> You'll find that having to name the function forces you to think about >> >>> "what's going on" there. It will help your reader (often that means >> >>> you, later on) to understand your intention. >> >>> >> >>> My rewrite doesn't use a single case expression. Is it somehow worse? >> >>> It's better! >> >>> >> >>> # If it looks confusing, it's bad! >> >>> >> >>> Erlang is not C, or bash, or Perl, or Ruby. It's possible to write >> >>> really easy-to-read code in Erlang. People who complain about Erlang >> >>> syntax are probably complain about terrible code in Erlang. Terrible >> >>> code in any language is worth complaining about - but it's unrelated >> >>> to syntax. >> >>> >> >>> It's easy to spot bad code in Erlang: >> >>> >> >>> - Long functions >> >>> >> >>> - Excessive nesting (more than two levels is a train wreck, and IMO >> >>> more than one is bad) >> >>> >> >>> I hate nesting so much that I'll go to the trouble of writing >> >>> to_number/1 as a list of "try" attempts (see rewrite). Some people >> >>> call this monadic, which I like because it sounds super cool. >> >>> >> >>> - Variable assignment/binding inside case and if expressions (see above) >> >>> >> >>> - Functions that are a litany of imperative style instructions, like >> >>> this: >> >>> >> >>> get_number(Prompt) -> >> >>> Str = io:get_line("Enter " ++ Prompt ++ " > "), >> >>> {Test, _} = string:to_float(Str), >> >>> case Test of >> >>> error -> {N, _} = string:to_integer(Str); >> >>> _ -> N = Test >> >>> end, >> >>> N. >> >>> >> >>> This fails the "long functions" test - but lines per function is just >> >>> a proxy. The real problem here is that it takes too much effort to >> >>> read and understand. Really, this is an imperative pattern applied >> >>> naively to Erlang. No! >> >>> >> >>> Try this: >> >>> >> >>> number_from_user(Prompt) -> >> >>> to_positive_number(prompt_user(["Enter ", Prompt, " > "])). >> >>> >> >>> Where's the rest of the code? It's there, inside the other functions. >> >>> But *this* function doesn't make you deal with that detail because it >> >>> wants you to understand what *it* is doing. >> >>> >> >>> Okay, so I've been pretty critical here of this online training >> >>> resource, which some will consider bad form. So let's turn this into >> >>> something nice and kind! >> >>> >> >>> The subject of this email is "refactoring in anger", which turns out >> >>> to be something I routinely do with my own code. It's hard to write >> >>> the perfect code in one pass. So I tend to just "get it to work" and >> >>> then examine what seems to be working very carefully - and then change >> >>> it so that it becomes *super obvious* what's going on. This state can >> >>> take a few passes and still might have warts. Okay, no sweat - it's >> >>> just code. Nothing to get angry about. Calm down and fix it. >> >>> >> >>> Over time, when you practice this pattern of refactoring, you'll start >> >>> writing things clearly the first time. That's because you'll start >> >>> *thinking* more clearly the first time. >> >>> >> >>> Now that's positive and nice and kind right? >> >>> >> >>> Garrett >> >>> >> >>> --- >> >>> >> >>> [1] Of course I'm joking here, but only partly. The original solution >> >>> is presented to learners - and it's full of bad practices, so that >> >>> makes me cranky. I suppose it's good to have teaching material for >> >>> Erlang in any form - at least it serves as a point of discussion, even >> >>> if contentious. > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From r.wobben@REDACTED Sun Aug 9 17:31:27 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Sun, 9 Aug 2015 17:31:27 +0200 Subject: [erlang-questions] Refactoring in anger (Felix Gallo) In-Reply-To: References: Message-ID: <55C7724F.3020901@home.nl> Op 9-8-2015 om 17:04 schreef Joe Armstrong: > On Sun, Aug 9, 2015 at 8:25 AM, J David Eisenberg > wrote: >> Felix Gallo wrote: >> >>> Nevertheless, if you're going to level a thundering, public j'accuse at >>> someone who has clearly gone to great effort to provide a beginner >>> experience for erlang newbies, without (apparently) first contacting him >>> privately and suggesting improvements in a constructively critical manner, >>> please have the decency to run the code that you have etched into your >>> stone tablets *before* you hold them aloft and, with fiery mane ablaze in >>> the evening sun, present them as the replacement for the gentleman's work. >>> >>> There are many "problems" with the etudes code. I'm not sure that >>> introducing a complex exception handling workflow is one of them, to be >>> frank, pedagogically, at the moment that the student is trying to >>> understand pattern matching and function headers. Could be. But I think >>> we can say it's a matter of taste. >>> >>> And that's what really rubs me the wrong way about Garrett's post. Being >>> 'very preachy', even when volubly disclaimed, is still pretty tasteless. >>> But being 'very preachy' and then slapping up code you haven't even run >>> once, directly in opposition to your preaching's core point: that's >>> hypocritical, and super tasteless. And I enjoy my rich dark ironic comedy >>> as much as the next guy, but come on. >>> >>> F. >> Author of Etudes here. >> >> There I was at Pepe's Tacos in Las Vegas, waiting for my meal, and I decided >> to read the Erlang questions mail list and see what's going on. As the story >> unfolded, I started cackling with laughter, until I realized that half >> the people >> in the restaurant were staring at me like "What the hell is wrong with this >> crazy white guy laughing at his phone?" >> >> So no, I'm not even remotely offended. > Hello David, nice to see you in here :-) > > Garret was of course attacking your code, which is not the same thing > as attacking you. > > If we espouse to beautiful code we must expect people to attack the code > when they think it is unbeautiful - this is not an attack on the person who > wrote the code, but an opportunity to show how we think it could be done better. > > Actually if we just replaced the bad code with better code and no discussion > we would learn nothing. So I value both your contribution, for giving > us something to talk about in the first place, and Garrett for banging > on it a bit :-) > > Me , I'm still learning how to write pretty Erlang code ... writing code > that you can still understand years after you wrote it is really difficult. > > My current theory is that one needs to also write publication quality > documentation. > > Cheers > > /Joe > > > > >> Especially because I write in >> the preface: >> "I was learning Erlang as I was creating the solutions to the ?tudes, >> following the philosophy that 'the first way that works is the right way.' >> Therefore, don?t be surprised if you see some fairly na?ve code that an expert >> Erlang programmer would never write." >> >> Since the book is open source, if anyone would like to add a better >> solution with >> a discussion of why it's better, I would be perfectly happy to see that. Modulo >> the anger, of course :) >> >>> On Sat, Aug 8, 2015 at 6:19 PM, Leandro Ostera wrote: >>> >>>> Just a minor typo: Line 48 should is trying to reassign the Prompt >>>> variable. >>>> >>>> But +1 on the rest. >>>> >>>> On Sun, Aug 9, 2015 at 2:36 AM, Felix Gallo wrote: >>>> >>>>> Eshell V7.0 (abort with ^G) >>>>> 1> c(geom). >>>>> {ok,geom} >>>>> 2> c(ask_area). >>>>> {ok,ask_area} >>>>> 3> ask_area:print_area(). >>>>> R)ectangle, T)riangle, or E)llipse > T >>>>> ** exception error: no function clause matching >>>>> ask_area:error_msg({badmatch,["Enter ","base"," > "]}) (ask_area.erl, line >>>>> 69) >>>>> in function ask_area:print_area/0 (ask_area.erl, line 9) >>>>> >>>>> >>>>> glass houses, etc. >>>>> >>>>> F. >>>>> >>>>> On Sat, Aug 8, 2015 at 3:07 PM, Garrett Smith wrote: >>>>> >>>>>> We've had an ongoing thread on how to handle some problems >>>>>> idiomatically in Erlang: >>>>>> >>>>>> http://erlang.org/pipermail/erlang-questions/2015-August/085382.html >>>>>> >>>>>> The OP's questions are coming out of an exercise here: >>>>>> >>>>>> http://chimera.labs.oreilly.com/books/1234000000726/ch05.html#CH05-ET01 >>>>>> >>>>>> This in turn points to a proposed solution here: >>>>>> >>>>>> >>>>>> http://chimera.labs.oreilly.com/books/1234000000726/apa.html#_literal_geom_erl_literal_9 >>>>>> >>>>>> Upon reading this solution, I became so enraged [1] that I rewrote the >>>>>> module and want to make a number of points. >>>>>> >>>>>> Here's my rewrite: >>>>>> >>>>>> https://gist.github.com/gar1t/7bb80d728f804554ac32 >>>>>> >>>>>> The tone of my points below is *very preachy* which is going to annoy >>>>>> some people here. I apologize in advance - but hey, ranters gotta >>>>>> rant. >>>>>> >>>>>> # Clarity of "what's going on" >>>>>> >>>>>> Compare my area/0 to the original area/0. Which is easier to see >>>>>> "what's going on"? I'm not boasting here but rather making the most >>>>>> important point I can about programming: take the time to be clear in >>>>>> your intent! If you're actually clear - in your brain - making the >>>>>> code reflect your understanding *is not that hard*. If your code is >>>>>> not clear, chances are your brain is not clear. >>>>>> >>>>>> Maybe the original code works, maybe it doesn't. I can't tell from >>>>>> looking at that function, at all. I have to dig around various >>>>>> implementation details and hold a bunch of information in my brain to >>>>>> understand what the author is maybe trying to do. At some point I >>>>>> can't keep it all straight and have to run the thing and observe its >>>>>> behavior. *Now* I'm thinking, what happens to the pour schlep who has >>>>>> to modify this code. In the real world, this causes fear, and >>>>>> loathing, and tests - lots and lots of tests! >>>>>> >>>>>> We don't have to live this way. >>>>>> >>>>>> # Separation of concerns (in this case IO vs calculations) >>>>>> >>>>>> The original calculate/3 mixes user facing behavior (print error >>>>>> messages) with a calculation. If your function returns a mishmash of >>>>>> completely unrelated values (e.g. the result of io:format and also the >>>>>> result of an area calculation) *it's a mess*. >>>>>> >>>>>> In the rewrite I've added print_area/0, which is responsible for >>>>>> displaying results to the user. area/0 returns an area or raises an >>>>>> exception. print_area/0 handles both the result and any error. >>>>>> >>>>>> # Handling invalid input >>>>>> >>>>>> The original thread here involves a discussion on how to handle bad >>>>>> input to a function. My rewrite does one of two things on this front: >>>>>> >>>>>> - If input is from a user, there's an explicit exception raised on bad >>>>>> input that can be used by an error handler to inform the user >>>>>> >>>>>> - If input is not from a user but rather internal, I don't handle bad >>>>>> input at all, but let Erlang crash with a function or case clause >>>>>> error >>>>>> >>>>>> The first case address the user experience. We could let exceptions >>>>>> just propagate and upset users with arcane Erlang messages. Or we can >>>>>> handle errors politely with intelligible messages. >>>>>> >>>>>> The original ask_erl.erl handles invalid input by passing atoms like >>>>>> 'error' and 'unknown' along a call chain. This is tedious and finally >>>>>> culminates in the original calculate/3 - a monster mishmash function >>>>>> of error handling, IO, and calculation. >>>>>> >>>>>> My rewrite raises an exception for those functions that take user >>>>>> provided input. I prefer exceptions in this case as they keep return >>>>>> values on the happy path, which makes code easier to read. >>>>>> >>>>>> I don't care about handling internal errors, as long as they manifest >>>>>> in an obvious way. >>>>>> >>>>>> # Avoid variable assignment/binding inside case expressions >>>>>> >>>>>> Just don't do this: >>>>>> >>>>>> case Shape of >>>>>> rectangle -> Numbers = get_dimensions("width", "height"); >>>>>> triangle -> Numbers = get_dimensions("base", "height"); >>>>>> ellipse -> Numbers = get_dimensions("major axis", "minor axis") >>>>>> end >>>>>> >>>>>> Now that you're not allowed to do that, what? Hey, a function! >>>>>> >>>>>> Numbers = get_dimensions(Shape) >>>>>> >>>>>> Every time, all the time. >>>>>> >>>>>> # Consider not using case expressions at all >>>>>> >>>>>> Think of a function as a named case expression with a well defined scope. >>>>>> >>>>>> You'll find that having to name the function forces you to think about >>>>>> "what's going on" there. It will help your reader (often that means >>>>>> you, later on) to understand your intention. >>>>>> >>>>>> My rewrite doesn't use a single case expression. Is it somehow worse? >>>>>> It's better! >>>>>> >>>>>> # If it looks confusing, it's bad! >>>>>> >>>>>> Erlang is not C, or bash, or Perl, or Ruby. It's possible to write >>>>>> really easy-to-read code in Erlang. People who complain about Erlang >>>>>> syntax are probably complain about terrible code in Erlang. Terrible >>>>>> code in any language is worth complaining about - but it's unrelated >>>>>> to syntax. >>>>>> >>>>>> It's easy to spot bad code in Erlang: >>>>>> >>>>>> - Long functions >>>>>> >>>>>> - Excessive nesting (more than two levels is a train wreck, and IMO >>>>>> more than one is bad) >>>>>> >>>>>> I hate nesting so much that I'll go to the trouble of writing >>>>>> to_number/1 as a list of "try" attempts (see rewrite). Some people >>>>>> call this monadic, which I like because it sounds super cool. >>>>>> >>>>>> - Variable assignment/binding inside case and if expressions (see above) >>>>>> >>>>>> - Functions that are a litany of imperative style instructions, like >>>>>> this: >>>>>> >>>>>> get_number(Prompt) -> >>>>>> Str = io:get_line("Enter " ++ Prompt ++ " > "), >>>>>> {Test, _} = string:to_float(Str), >>>>>> case Test of >>>>>> error -> {N, _} = string:to_integer(Str); >>>>>> _ -> N = Test >>>>>> end, >>>>>> N. >>>>>> >>>>>> This fails the "long functions" test - but lines per function is just >>>>>> a proxy. The real problem here is that it takes too much effort to >>>>>> read and understand. Really, this is an imperative pattern applied >>>>>> naively to Erlang. No! >>>>>> >>>>>> Try this: >>>>>> >>>>>> number_from_user(Prompt) -> >>>>>> to_positive_number(prompt_user(["Enter ", Prompt, " > "])). >>>>>> >>>>>> Where's the rest of the code? It's there, inside the other functions. >>>>>> But *this* function doesn't make you deal with that detail because it >>>>>> wants you to understand what *it* is doing. >>>>>> >>>>>> Okay, so I've been pretty critical here of this online training >>>>>> resource, which some will consider bad form. So let's turn this into >>>>>> something nice and kind! >>>>>> >>>>>> The subject of this email is "refactoring in anger", which turns out >>>>>> to be something I routinely do with my own code. It's hard to write >>>>>> the perfect code in one pass. So I tend to just "get it to work" and >>>>>> then examine what seems to be working very carefully - and then change >>>>>> it so that it becomes *super obvious* what's going on. This state can >>>>>> take a few passes and still might have warts. Okay, no sweat - it's >>>>>> just code. Nothing to get angry about. Calm down and fix it. >>>>>> >>>>>> Over time, when you practice this pattern of refactoring, you'll start >>>>>> writing things clearly the first time. That's because you'll start >>>>>> *thinking* more clearly the first time. >>>>>> >>>>>> Now that's positive and nice and kind right? >>>>>> >>>>>> Garrett >>>>>> >>>>>> --- >>>>>> >>>>>> [1] Of course I'm joking here, but only partly. The original solution >>>>>> is presented to learners - and it's full of bad practices, so that >>>>>> makes me cranky. I suppose it's good to have teaching material for >>>>>> Erlang in any form - at least it serves as a point of discussion, even >>>>>> if contentious. >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions Can my question why geom:area() cannot be found be answered. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From g@REDACTED Sun Aug 9 17:32:23 2015 From: g@REDACTED (Garrett Smith) Date: Sun, 9 Aug 2015 10:32:23 -0500 Subject: [erlang-questions] Refactoring in anger (Felix Gallo) In-Reply-To: References: Message-ID: Weird, I'm not getting some of these emails - I got Joe's reply but not David's :/ On Sun, Aug 9, 2015 at 10:04 AM, Joe Armstrong wrote: > On Sun, Aug 9, 2015 at 8:25 AM, J David Eisenberg > wrote: >> Felix Gallo wrote: >> >>> Nevertheless, if you're going to level a thundering, public j'accuse at >>> someone who has clearly gone to great effort to provide a beginner >>> experience for erlang newbies, without (apparently) first contacting him >>> privately and suggesting improvements in a constructively critical manner, >>> please have the decency to run the code that you have etched into your >>> stone tablets *before* you hold them aloft and, with fiery mane ablaze in >>> the evening sun, present them as the replacement for the gentleman's work. >>> >>> There are many "problems" with the etudes code. I'm not sure that >>> introducing a complex exception handling workflow is one of them, to be >>> frank, pedagogically, at the moment that the student is trying to >>> understand pattern matching and function headers. Could be. But I think >>> we can say it's a matter of taste. >>> >>> And that's what really rubs me the wrong way about Garrett's post. Being >>> 'very preachy', even when volubly disclaimed, is still pretty tasteless. >>> But being 'very preachy' and then slapping up code you haven't even run >>> once, directly in opposition to your preaching's core point: that's >>> hypocritical, and super tasteless. And I enjoy my rich dark ironic comedy >>> as much as the next guy, but come on. >>> >>> F. >> >> Author of Etudes here. >> >> There I was at Pepe's Tacos in Las Vegas, waiting for my meal, and I decided >> to read the Erlang questions mail list and see what's going on. As the story >> unfolded, I started cackling with laughter, until I realized that half >> the people >> in the restaurant were staring at me like "What the hell is wrong with this >> crazy white guy laughing at his phone?" >> >> So no, I'm not even remotely offended. As I often work in libraries, cafes, and bars I've built the reputation around town as the crazy guy buried in his laptop laughing and cursing to himself. Of course any time I say anything negative about anything I'm concerned how people will feel about it and I did let myself go a bit... thank you for your generous response here :) > Hello David, nice to see you in here :-) +1 > Garret was of course attacking your code, which is not the same thing > as attacking you. Oh, that's not true for many people - as they and their code are one :) But yes. > If we espouse to beautiful code we must expect people to attack the code > when they think it is unbeautiful - this is not an attack on the person who > wrote the code, but an opportunity to show how we think it could be done better. > > Actually if we just replaced the bad code with better code and no discussion > we would learn nothing. So I value both your contribution, for giving > us something to talk about in the first place, and Garrett for banging > on it a bit :-) And I hope this spirit rises above what others might see as bad taste. The point, for me, is to raise specific points for the sake of improving. Right or wrong, the process of thinking about this, writing code, discussing - it's what will strengthen the community and how we use and teach Erlang. The ranting is just my personal demon :) From r.wobben@REDACTED Sun Aug 9 17:44:31 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Sun, 9 Aug 2015 17:44:31 +0200 Subject: [erlang-questions] Refactoring in anger (Felix Gallo) In-Reply-To: References: <55C7724F.3020901@home.nl> Message-ID: <55C7755F.2070807@home.nl> Op 9-8-2015 om 17:33 schreef Garrett Smith: > What error are you seeing? > I see this output: 1> c(ask_area). {ok,ask_area} 2> ask_area:area(). R)ectangle, T)riangle, or E)llipse > R Enter width > 2 Enter height > 4 ** exception error: undefined function geom:area/3 Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From g@REDACTED Sun Aug 9 17:47:32 2015 From: g@REDACTED (Garrett Smith) Date: Sun, 9 Aug 2015 10:47:32 -0500 Subject: [erlang-questions] Refactoring in anger (Felix Gallo) In-Reply-To: <55C7755F.2070807@home.nl> References: <55C7724F.3020901@home.nl> <55C7755F.2070807@home.nl> Message-ID: It's going to look for geom.beam in the current working directory. You need to compile geom.erl. To check what the VM sees in the current directory run this: > ls(). On Sun, Aug 9, 2015 at 10:44 AM, Roelof Wobben wrote: > Op 9-8-2015 om 17:33 schreef Garrett Smith: >> >> What error are you seeing? >> > > > I see this output: > > 1> c(ask_area). > {ok,ask_area} > 2> ask_area:area(). > R)ectangle, T)riangle, or E)llipse > R > Enter width > 2 > Enter height > 4 > ** exception error: undefined function geom:area/3 > > > Roelof > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From vinoski@REDACTED Sun Aug 9 17:56:46 2015 From: vinoski@REDACTED (Steve Vinoski) Date: Sun, 9 Aug 2015 11:56:46 -0400 Subject: [erlang-questions] standard_error not handling eagain? In-Reply-To: References: Message-ID: The patch below seems to fix it, so please give it a try if you're interested. Feedback welcomed. It requires more testing, as well as adding Kota's test to the suite to prevent regressions. I'll do that later and send in a PR. --steve diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index b036b20..adb449e 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -2527,7 +2527,7 @@ fd_async(void *async_data) SysIOVec *iov0; SysIOVec *iov; int iovlen; - int err; + int err = 0; /* much of this code is stolen from efile_drv:invoke_writev */ driver_pdl_lock(dd->blocking->pdl); iov0 = driver_peekq(dd->port_num, &iovlen); @@ -2542,8 +2542,11 @@ fd_async(void *async_data) memcpy(iov,iov0,iovlen*sizeof(SysIOVec)); driver_pdl_unlock(dd->blocking->pdl); - res = writev(dd->ofd, iov, iovlen); - err = errno; + do { + res = writev(dd->ofd, iov, iovlen); + } while (res < 0 && errno == EINTR); + if (res < 0) + err = errno; erts_free(ERTS_ALC_T_SYS_WRITE_BUF, iov); } @@ -2582,7 +2585,12 @@ void fd_ready_async(ErlDrvData drv_data, return /* 0; */; } } else if (dd->blocking->res < 0) { - driver_failure_posix(port_num, dd->blocking->err); + if (dd->blocking->err == EAGAIN) { + set_busy_port(port_num, 1); + /* still data left to write in queue */ + driver_async(port_num, &dd->blocking->pkey, fd_async, dd, NULL); + } else + driver_failure_posix(port_num, dd->blocking->err); return; /* -1; */ } return; /* 0; */ On Sun, Aug 9, 2015 at 11:03 AM, Jos? Valim wrote: > Thanks for a report that includes a way to reproduce the issue! > > For reference, this has been reported a couple days ago as well: > http://erlang.org/pipermail/erlang-questions/2015-August/085375.html > > > > *Jos? Valim* > www.plataformatec.com.br > Skype: jv.ptec > Founder and Director of R&D > > On Sun, Aug 9, 2015 at 2:53 PM, UENISHI Kota wrote: > >> Hi folks, >> I'm asking here as I'm not sure how it should be although this looks >> like a bug to me. Reproduced in MacOS (mine is 10.10.4) AND 18.0 >> (maint-18 HEAD), but couldn't reproduce in Linux (Ubuntu 14.04) with >> 18.0 or R16B02 with Mac. >> >> To reproduce, it's pretty easy: just print out to standard_error by >> using io:put_char/1 or io:format/3, with writing a long iolist at >> least more than a thousand characters [1]: >> >> main(_) -> >> Arg0 = [ [["1234567890" || _ <- [1,2,3,4,5,6,7,8,9,0]], 32, >> integer_to_list(L), $\n] >> || L <- lists:seq(1, 200) ], >> io:format(standard_error, "~p~n", [whereis(standard_error)]), >> R = io:put_chars(standard_error, Arg0), >> io:format(standard_error, "~p, ~p~n", [R, whereis(standard_error)]). >> >> My result of this code is also copied in that gist [2]. >> >> This phenomena seems to happen when writing a long buffer to FD 2 via >> port driver and suddenly gets EAGAIN back, and the port exits with >> that error. I believe standard_error should not exit but should retry >> writing when eagain or eintr was received. Thoughts? >> >> [1] https://gist.github.com/kuenishi/76333a8a93bc8ccad308#file-stderr-erl >> [2] >> https://gist.github.com/kuenishi/76333a8a93bc8ccad308#file-otp-18-0-maint-18-head >> >> -- >> UENISHI Kota :-) >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Sun Aug 9 18:02:05 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Sun, 9 Aug 2015 18:02:05 +0200 Subject: [erlang-questions] how do I make print_area work Message-ID: <55C7797D.6030801@home.nl> Hello, I have this code from another topic on this list. %% @author Roelof Wobben %% @doc Function to calculate the area of a rectangle %% @reference from Introducing Erlang, %% O'Reilly Media, Inc., 2012. %% @copyright 2012 by R.WObben %% @version 0.1 -module(ask_area). -export([area/0]). print_area() -> try area() of Area -> io:format("The area is ~p~n", [Area]) catch error:Err -> io:format("~s~n", [error_msg(Err)]) end. area() -> Shape = shape_from_user(), {X, Y} = dimensions_from_user(Shape), geom:area(Shape, X, Y). shape_from_user() -> Prompt = "R)ectangle, T)riangle, or E)llipse > ", char_to_shape(prompt_user(Prompt)). prompt_user(Prompt) -> strip_lf(io:get_line(Prompt)). strip_lf(Str) -> string:strip(Str, right, $\n). char_to_shape("R") -> rectangle; char_to_shape("r") -> rectangle; char_to_shape("T") -> triangle; char_to_shape("t") -> triangle; char_to_shape("E") -> ellipse; char_to_shape("e") -> ellipse; char_to_shape(_) -> error(bad_shape). dimensions_from_user(rectangle) -> numbers_from_user("width", "height"); dimensions_from_user(triangle) -> numbers_from_user("base", "height"); dimensions_from_user(ellipse) -> numbers_from_user("major axis", "minor axis"). numbers_from_user(XPrompt, YPrompt) -> X = number_from_user(XPrompt), Y = number_from_user(YPrompt), {X, Y}. number_from_user(Name) -> Prompt = ["Enter ", Name, " > "], to_positive_number(prompt_user(Prompt)). to_positive_number(Prompt) -> positive_number(to_number(Prompt)). positive_number(N) when N > 0 -> N; positive_number(_) -> error(bad_number). to_number(Str) -> try_number([fun list_to_float/1, fun list_to_integer/1], Str). try_number([Method|Rest], Arg) -> try Method(Arg) catch error:badarg -> try_number(Rest, Arg) end; try_number([], _Arg) -> error(bad_number). error_msg(bad_shape) -> "Please enter a valid shape"; error_msg(bad_number) -> "Please enter a positive number". How can I make it work so print_area is used ? Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From r.wobben@REDACTED Sun Aug 9 18:12:55 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Sun, 9 Aug 2015 18:12:55 +0200 Subject: [erlang-questions] how do I make print_area work In-Reply-To: References: <55C7797D.6030801@home.nl> Message-ID: <55C77C07.1050101@home.nl> At first sight that print_area is not in the export. But even then the sentence "the area is " is not printed. And sorry for beging a rookie who tries very hard to learn erlang. Roelof Op 9-8-2015 om 18:05 schreef Garrett Smith: > Roelof, these questions are very basic and you're running the risk of > getting some RTFM responses. > > Take a look at the current source: > > https://gist.github.com/gar1t/7bb80d728f804554ac32 > > What's different there? > > On Sun, Aug 9, 2015 at 11:02 AM, Roelof Wobben wrote: >> Hello, >> >> I have this code from another topic on this list. >> >> %% @author Roelof Wobben >> %% @doc Function to calculate the area of a rectangle >> %% @reference from > "http://shop.oreilly.com/product/0636920025818.do" >Introducing Erlang, >> %% O'Reilly Media, Inc., 2012. >> %% @copyright 2012 by R.WObben >> %% @version 0.1 >> >> -module(ask_area). >> >> -export([area/0]). >> >> print_area() -> >> try area() of >> Area -> io:format("The area is ~p~n", [Area]) >> catch >> error:Err -> io:format("~s~n", [error_msg(Err)]) >> end. >> >> area() -> >> Shape = shape_from_user(), >> {X, Y} = dimensions_from_user(Shape), >> geom:area(Shape, X, Y). >> >> shape_from_user() -> >> Prompt = "R)ectangle, T)riangle, or E)llipse > ", >> char_to_shape(prompt_user(Prompt)). >> >> prompt_user(Prompt) -> >> strip_lf(io:get_line(Prompt)). >> >> strip_lf(Str) -> >> string:strip(Str, right, $\n). >> >> char_to_shape("R") -> rectangle; >> char_to_shape("r") -> rectangle; >> char_to_shape("T") -> triangle; >> char_to_shape("t") -> triangle; >> char_to_shape("E") -> ellipse; >> char_to_shape("e") -> ellipse; >> char_to_shape(_) -> error(bad_shape). >> >> dimensions_from_user(rectangle) -> >> numbers_from_user("width", "height"); >> dimensions_from_user(triangle) -> >> numbers_from_user("base", "height"); >> dimensions_from_user(ellipse) -> >> numbers_from_user("major axis", "minor axis"). >> >> numbers_from_user(XPrompt, YPrompt) -> >> X = number_from_user(XPrompt), >> Y = number_from_user(YPrompt), >> {X, Y}. >> >> number_from_user(Name) -> >> Prompt = ["Enter ", Name, " > "], >> to_positive_number(prompt_user(Prompt)). >> >> to_positive_number(Prompt) -> >> positive_number(to_number(Prompt)). >> >> positive_number(N) when N > 0 -> N; >> positive_number(_) -> error(bad_number). >> >> to_number(Str) -> >> try_number([fun list_to_float/1, fun list_to_integer/1], Str). >> >> try_number([Method|Rest], Arg) -> >> try >> Method(Arg) >> catch >> error:badarg -> try_number(Rest, Arg) >> end; >> try_number([], _Arg) -> >> error(bad_number). >> >> error_msg(bad_shape) -> "Please enter a valid shape"; >> error_msg(bad_number) -> "Please enter a positive number". >> >> >> How can I make it work so print_area is used ? >> >> Roelof >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From g@REDACTED Sun Aug 9 18:16:57 2015 From: g@REDACTED (Garrett Smith) Date: Sun, 9 Aug 2015 11:16:57 -0500 Subject: [erlang-questions] how do I make print_area work In-Reply-To: <55C77C07.1050101@home.nl> References: <55C7797D.6030801@home.nl> <55C77C07.1050101@home.nl> Message-ID: Roelof, we've all been there before. Here's the thing though - what you're facing is stuff that's covered in the first few pages of every Erlang book written. I suggest you spend some quality time there and get familiar with some basics before posting questions here. If you get stuck on anything, or course ask away. Surely you've seen by now how much effort the folks here put into helping people learn Erlang. I'm also very happy to help you - feel free to send me a question when you run into an issue - you have my email! On Sun, Aug 9, 2015 at 11:12 AM, Roelof Wobben wrote: > At first sight that print_area is not in the export. > But even then the sentence "the area is " is not printed. > > And sorry for beging a rookie who tries very hard to learn erlang. > > Roelof > > > > Op 9-8-2015 om 18:05 schreef Garrett Smith: > >> Roelof, these questions are very basic and you're running the risk of >> getting some RTFM responses. >> >> Take a look at the current source: >> >> https://gist.github.com/gar1t/7bb80d728f804554ac32 >> >> What's different there? >> >> On Sun, Aug 9, 2015 at 11:02 AM, Roelof Wobben wrote: >>> >>> Hello, >>> >>> I have this code from another topic on this list. >>> >>> %% @author Roelof Wobben >>> %% @doc Function to calculate the area of a rectangle >>> %% @reference from >> "http://shop.oreilly.com/product/0636920025818.do" >Introducing >>> Erlang, >>> %% O'Reilly Media, Inc., 2012. >>> %% @copyright 2012 by R.WObben >>> %% @version 0.1 >>> >>> -module(ask_area). >>> >>> -export([area/0]). >>> >>> print_area() -> >>> try area() of >>> Area -> io:format("The area is ~p~n", [Area]) >>> catch >>> error:Err -> io:format("~s~n", [error_msg(Err)]) >>> end. >>> >>> area() -> >>> Shape = shape_from_user(), >>> {X, Y} = dimensions_from_user(Shape), >>> geom:area(Shape, X, Y). >>> >>> shape_from_user() -> >>> Prompt = "R)ectangle, T)riangle, or E)llipse > ", >>> char_to_shape(prompt_user(Prompt)). >>> >>> prompt_user(Prompt) -> >>> strip_lf(io:get_line(Prompt)). >>> >>> strip_lf(Str) -> >>> string:strip(Str, right, $\n). >>> >>> char_to_shape("R") -> rectangle; >>> char_to_shape("r") -> rectangle; >>> char_to_shape("T") -> triangle; >>> char_to_shape("t") -> triangle; >>> char_to_shape("E") -> ellipse; >>> char_to_shape("e") -> ellipse; >>> char_to_shape(_) -> error(bad_shape). >>> >>> dimensions_from_user(rectangle) -> >>> numbers_from_user("width", "height"); >>> dimensions_from_user(triangle) -> >>> numbers_from_user("base", "height"); >>> dimensions_from_user(ellipse) -> >>> numbers_from_user("major axis", "minor axis"). >>> >>> numbers_from_user(XPrompt, YPrompt) -> >>> X = number_from_user(XPrompt), >>> Y = number_from_user(YPrompt), >>> {X, Y}. >>> >>> number_from_user(Name) -> >>> Prompt = ["Enter ", Name, " > "], >>> to_positive_number(prompt_user(Prompt)). >>> >>> to_positive_number(Prompt) -> >>> positive_number(to_number(Prompt)). >>> >>> positive_number(N) when N > 0 -> N; >>> positive_number(_) -> error(bad_number). >>> >>> to_number(Str) -> >>> try_number([fun list_to_float/1, fun list_to_integer/1], Str). >>> >>> try_number([Method|Rest], Arg) -> >>> try >>> Method(Arg) >>> catch >>> error:badarg -> try_number(Rest, Arg) >>> end; >>> try_number([], _Arg) -> >>> error(bad_number). >>> >>> error_msg(bad_shape) -> "Please enter a valid shape"; >>> error_msg(bad_number) -> "Please enter a positive number". >>> >>> >>> How can I make it work so print_area is used ? >>> >>> Roelof >>> >>> >>> --- >>> Dit e-mailbericht is gecontroleerd op virussen met Avast >>> antivirussoftware. >>> https://www.avast.com/antivirus >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions > > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From josh.rubyist@REDACTED Sun Aug 9 22:30:38 2015 From: josh.rubyist@REDACTED (Josh Adams) Date: Sun, 9 Aug 2015 15:30:38 -0500 Subject: [erlang-questions] Refactoring in anger (Felix Gallo) In-Reply-To: References: <55C7724F.3020901@home.nl> <55C7755F.2070807@home.nl> Message-ID: Threads like this are 100% of the joy I get from the ML. Between the actual help, the rant, the minor drama, the detailed exposition of what it means to write good code based around a simple example, and the admission from a creator of the language that he's 'still learning how to write pretty Erlang code', I think this thread is the best example of the best things this list provides. I hesitated to even poke in here just to say this, but I think community is important and I love the effort that goes in to it. -Josh On Sun, Aug 9, 2015 at 10:47 AM, Garrett Smith wrote: > It's going to look for geom.beam in the current working directory. You > need to compile geom.erl. > > To check what the VM sees in the current directory run this: > >> ls(). > > On Sun, Aug 9, 2015 at 10:44 AM, Roelof Wobben wrote: >> Op 9-8-2015 om 17:33 schreef Garrett Smith: >>> >>> What error are you seeing? >>> >> >> >> I see this output: >> >> 1> c(ask_area). >> {ok,ask_area} >> 2> ask_area:area(). >> R)ectangle, T)riangle, or E)llipse > R >> Enter width > 2 >> Enter height > 4 >> ** exception error: undefined function geom:area/3 >> >> >> Roelof >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -- Josh Adams From kunthar@REDACTED Sun Aug 9 23:38:30 2015 From: kunthar@REDACTED (Gokhan Boranalp) Date: Mon, 10 Aug 2015 00:38:30 +0300 Subject: [erlang-questions] Refactoring in anger (Felix Gallo) In-Reply-To: References: <55C7724F.3020901@home.nl> <55C7755F.2070807@home.nl> Message-ID: The tone of talk, the level of the language usage and the attitude of all answers... that is why i like this community. btw; Joe \o/ On Sun, Aug 9, 2015 at 11:30 PM, Josh Adams wrote: > Threads like this are 100% of the joy I get from the ML. Between the > actual help, the rant, the minor drama, the detailed exposition of > what it means to write good code based around a simple example, and > the admission from a creator of the language that he's 'still learning > how to write pretty Erlang code', I think this thread is the best > example of the best things this list provides. > > I hesitated to even poke in here just to say this, but I think > community is important and I love the effort that goes in to it. > > -Josh > > On Sun, Aug 9, 2015 at 10:47 AM, Garrett Smith wrote: >> It's going to look for geom.beam in the current working directory. You >> need to compile geom.erl. >> >> To check what the VM sees in the current directory run this: >> >>> ls(). >> >> On Sun, Aug 9, 2015 at 10:44 AM, Roelof Wobben wrote: >>> Op 9-8-2015 om 17:33 schreef Garrett Smith: >>>> >>>> What error are you seeing? >>>> >>> >>> >>> I see this output: >>> >>> 1> c(ask_area). >>> {ok,ask_area} >>> 2> ask_area:area(). >>> R)ectangle, T)riangle, or E)llipse > R >>> Enter width > 2 >>> Enter height > 4 >>> ** exception error: undefined function geom:area/3 >>> >>> >>> Roelof >>> >>> >>> --- >>> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >>> https://www.avast.com/antivirus >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > > > -- > Josh Adams > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -- BR, \|/ Kunthar From kuenishi@REDACTED Mon Aug 10 03:58:54 2015 From: kuenishi@REDACTED (UENISHI Kota) Date: Mon, 10 Aug 2015 10:58:54 +0900 Subject: [erlang-questions] standard_error not handling eagain? In-Reply-To: References: Message-ID: Steve, Your patch also fixed my case. standard_error is no more exiting. It is awesome and thank you! Jose, Thank you for bringing it up, I should have read letters from erlang-questions more carefully :) On Mon, Aug 10, 2015 at 12:56 AM, Steve Vinoski wrote: > The patch below seems to fix it, so please give it a try if you're > interested. Feedback welcomed. It requires more testing, as well as adding > Kota's test to the suite to prevent regressions. I'll do that later and send > in a PR. > > --steve > > > diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c > index b036b20..adb449e 100644 > --- a/erts/emulator/sys/unix/sys.c > +++ b/erts/emulator/sys/unix/sys.c > @@ -2527,7 +2527,7 @@ fd_async(void *async_data) > SysIOVec *iov0; > SysIOVec *iov; > int iovlen; > - int err; > + int err = 0; > /* much of this code is stolen from efile_drv:invoke_writev */ > driver_pdl_lock(dd->blocking->pdl); > iov0 = driver_peekq(dd->port_num, &iovlen); > @@ -2542,8 +2542,11 @@ fd_async(void *async_data) > memcpy(iov,iov0,iovlen*sizeof(SysIOVec)); > driver_pdl_unlock(dd->blocking->pdl); > > - res = writev(dd->ofd, iov, iovlen); > - err = errno; > + do { > + res = writev(dd->ofd, iov, iovlen); > + } while (res < 0 && errno == EINTR); > + if (res < 0) > + err = errno; > > erts_free(ERTS_ALC_T_SYS_WRITE_BUF, iov); > } > @@ -2582,7 +2585,12 @@ void fd_ready_async(ErlDrvData drv_data, > return /* 0; */; > } > } else if (dd->blocking->res < 0) { > - driver_failure_posix(port_num, dd->blocking->err); > + if (dd->blocking->err == EAGAIN) { > + set_busy_port(port_num, 1); > + /* still data left to write in queue */ > + driver_async(port_num, &dd->blocking->pkey, fd_async, dd, > NULL); > + } else > + driver_failure_posix(port_num, dd->blocking->err); > return; /* -1; */ > } > return; /* 0; */ > > > > > On Sun, Aug 9, 2015 at 11:03 AM, Jos? Valim > wrote: >> >> Thanks for a report that includes a way to reproduce the issue! >> >> For reference, this has been reported a couple days ago as well: >> http://erlang.org/pipermail/erlang-questions/2015-August/085375.html >> >> >> >> Jos? Valim >> www.plataformatec.com.br >> Skype: jv.ptec >> Founder and Director of R&D >> >> On Sun, Aug 9, 2015 at 2:53 PM, UENISHI Kota wrote: >>> >>> Hi folks, >>> I'm asking here as I'm not sure how it should be although this looks >>> like a bug to me. Reproduced in MacOS (mine is 10.10.4) AND 18.0 >>> (maint-18 HEAD), but couldn't reproduce in Linux (Ubuntu 14.04) with >>> 18.0 or R16B02 with Mac. >>> >>> To reproduce, it's pretty easy: just print out to standard_error by >>> using io:put_char/1 or io:format/3, with writing a long iolist at >>> least more than a thousand characters [1]: >>> >>> main(_) -> >>> Arg0 = [ [["1234567890" || _ <- [1,2,3,4,5,6,7,8,9,0]], 32, >>> integer_to_list(L), $\n] >>> || L <- lists:seq(1, 200) ], >>> io:format(standard_error, "~p~n", [whereis(standard_error)]), >>> R = io:put_chars(standard_error, Arg0), >>> io:format(standard_error, "~p, ~p~n", [R, whereis(standard_error)]). >>> >>> My result of this code is also copied in that gist [2]. >>> >>> This phenomena seems to happen when writing a long buffer to FD 2 via >>> port driver and suddenly gets EAGAIN back, and the port exits with >>> that error. I believe standard_error should not exit but should retry >>> writing when eagain or eintr was received. Thoughts? >>> >>> [1] https://gist.github.com/kuenishi/76333a8a93bc8ccad308#file-stderr-erl >>> [2] >>> https://gist.github.com/kuenishi/76333a8a93bc8ccad308#file-otp-18-0-maint-18-head >>> >>> -- >>> UENISHI Kota :-) >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >> >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> > -- UENISHI Kota :-) From puzza007@REDACTED Mon Aug 10 11:58:38 2015 From: puzza007@REDACTED (Paul Oliver) Date: Mon, 10 Aug 2015 09:58:38 +0000 Subject: [erlang-questions] [ANN] Katipo - a compatible and high-performance HTTP client for Erlang Message-ID: Hi all, Where: https://github.com/puzza007/katipo What: Katipo is an HTTP client for Erlang based on libcurl and libevent. Why: We wanted a very compatible HTTP client for Erlang. How: Implemented as a pool of port executables, each running an instance of libcurl-multi. Usage: {ok, _} = application:ensure_all_started(katipo). Url = <<"https://testurl.com">>. ReqHeaders = [{<<"User-Agent">>, <<"katipo">>}]. Opts = #{headers => ReqHeaders, body => <<"0d5cb3c25b0c5678d5297efa448e1938">>, connecttimeout_ms => 5000}, {ok, #{status := 200, headers := RespHeaders, cookiejar := CookieJar, body := RespBody}} = katipo:post(Url, Opts). Status: The current status is alpha, with basic functionality working for OTP 18. There's still plenty from libcurl that can be exposed. Upcoming features are OTP 17.x support and the ability to stream responses to clients. -------------- next part -------------- An HTML attachment was scrubbed... URL: From max.lapshin@REDACTED Mon Aug 10 12:58:58 2015 From: max.lapshin@REDACTED (Max Lapshin) Date: Mon, 10 Aug 2015 13:58:58 +0300 Subject: [erlang-questions] [ANN] Katipo - a compatible and high-performance HTTP client for Erlang In-Reply-To: References: Message-ID: Paul, you have added binary dependency from libcurl to erlang application? What was the idea of such thing? -------------- next part -------------- An HTML attachment was scrubbed... URL: From puzza007@REDACTED Mon Aug 10 13:08:00 2015 From: puzza007@REDACTED (Paul Oliver) Date: Mon, 10 Aug 2015 11:08:00 +0000 Subject: [erlang-questions] [ANN] Katipo - a compatible and high-performance HTTP client for Erlang In-Reply-To: References: Message-ID: On Mon, Aug 10, 2015 at 12:58 PM Max Lapshin wrote: > Paul, you have added binary dependency from libcurl to erlang application? > Yes. > > What was the idea of such thing? > > To use the capabilities of libcurl. -------------- next part -------------- An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Mon Aug 10 14:00:08 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 10 Aug 2015 14:00:08 +0200 Subject: [erlang-questions] dialyzer output help Message-ID: <55C89248.5030002@home.nl> Hello, I try to document this function which I found on another topic. %% @author Roelof Wobben %% @doc Function to calculate the area of a rectangle, a ellipse or a triangle %% @reference from Introducing Erlang, %% O'Reilly Media, Inc., 2012. %% @copyright 2012 by R.Wobben %% @version 0.1 -module(ask_area). -export([area/0]). -spec(area() -> 'ok' | 'error'). %% @doc a function which looks if the function collect_data %% outputs a number which resambles the area of the shape the %% user has choosen with the dimensions which the user has entered %% if the user entered a wrong shape or not a number on the dimension %% part , there will be a right error message to tell what went wrong area() -> try collect_data() of Area -> io:format("The area is ~p~n", [Area]) catch error:Err -> io:format("~s~n", [error_msg(Err)]) end. -spec(collect_data() -> number() ). %% doc Function which controls the programm. %% First the shape is asked on the user. %% After that if a valid shape is entered the dimensions %% are asked , and if they are valid the area is being calculated. collect_data() -> Shape = shape_from_user(), {X, Y} = dimensions_from_user(Shape), geom:area(Shape, X, Y). -spec (shape_from_user() -> 'ellipse' | 'rectangle' | 'triangle' ) . %%doc Here the right prompt is made so the user %% can choose the shape they want. shape_from_user() -> Prompt = "R)ectangle, T)riangle, or E)llipse > ", char_to_shape(prompt_user(Prompt)). -spec (prompt_user(string()) -> string()). %% doc Here the prompt is displayed and send to %% the strip function so the newline is stripped. prompt_user(Prompt) -> strip_lf(io:get_line(Prompt)). -spec (strip_lf (string()) -> string() ). %%doc Here the newline is stripped from the userinput. strip_lf(Str) -> string:strip(Str, right, $\n). char_to_shape("R") -> rectangle; char_to_shape("r") -> rectangle; char_to_shape("T") -> triangle; char_to_shape("t") -> triangle; char_to_shape("E") -> ellipse; char_to_shape("e") -> ellipse; char_to_shape(_) -> error(bad_shape). dimensions_from_user(rectangle) -> numbers_from_user("width", "height"); dimensions_from_user(triangle) -> numbers_from_user("base", "height"); dimensions_from_user(ellipse) -> numbers_from_user("major axis", "minor axis"). numbers_from_user(XPrompt, YPrompt) -> X = number_from_user(XPrompt), Y = number_from_user(YPrompt), {X, Y}. number_from_user(Name) -> Prompt = ["Enter ", Name, " > "], to_positive_number(prompt_user(Prompt)). to_positive_number(Prompt) -> positive_number(to_number(Prompt)). positive_number(N) when N > 0 -> N; positive_number(_) -> error(bad_number). to_number(Str) -> try_number([fun list_to_float/1, fun list_to_integer/1], Str). try_number([Method|Rest], Arg) -> try Method(Arg) catch error:badarg -> try_number(Rest, Arg) end; try_number([], _Arg) -> error(bad_number). error_msg(bad_shape) -> "Please enter a valid shape"; error_msg(bad_number) -> "Please enter a positive number". but as soon as I run dialyzer I see this output : Checking whether the PLT /home/nitrous/.dialyzer_plt is up-to-date... yes Proceeding with analysis... ask_area.erl:34: Function collect_data/0 has no local return ask_area.erl:75: Function dimensions_from_user/1 has no local return ask_area.erl:82: Function numbers_from_user/2 has no local return ask_area.erl:87: Function number_from_user/1 has no local return ask_area.erl:89: The call ask_area:prompt_user(Prompt::[[1..255,...],...]) breaks the contract (string()) -> string() ask_area.erl:91: Function to_positive_number/1 will never be called ask_area.erl:94: Function positive_number/1 will never be called ask_area.erl:97: Function to_number/1 will never be called ask_area.erl:100: Function try_number/2 will never be called done in 0m0.51s done (warnings were emitted) hecking whether the PLT /home/nitrous/.dialyzer_plt is up-to-date... yes Proceeding with analysis... ask_area.erl:34: Function collect_data/0 has no local return ask_area.erl:75: Function dimensions_from_user/1 has no local return ask_area.erl:82: Function numbers_from_user/2 has no local return ask_area.erl:87: Function number_from_user/1 has no local return ask_area.erl:89: The call ask_area:prompt_user(Prompt::[[1..255,...],...]) breaks the contract (string()) -> string() ask_area.erl:91: Function to_positive_number/1 will never be called ask_area.erl:94: Function positive_number/1 will never be called ask_area.erl:97: Function to_number/1 will never be called ask_area.erl:100: Function try_number/2 will never be called Unknown functions: geom:area/3 done in 0m0.51s done (warnings were emitted) Can someone explain what these messages mean. This is the first time I use dialyzer and this confuses me. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From erlang@REDACTED Mon Aug 10 14:22:28 2015 From: erlang@REDACTED (Joe Armstrong) Date: Mon, 10 Aug 2015 14:22:28 +0200 Subject: [erlang-questions] Programmatic interface to the shell Message-ID: Hello, Is there a *simple* programmatic interface to the Erlang shell? I'd like a module "shell_interface" that works like this: Pid = shell_interface:new_shell(), Returns a new process that behaves like the Erlang shell OutStr = shell_interface:eval(Pid, InStr) This behaves like the Erlang shell. InStr should be what I typed into the shell. OutStr should be what the shell replied. For this purpose we can assume that InStr represents a complete sequence of expressions. Cheers /Joe From g@REDACTED Mon Aug 10 14:33:51 2015 From: g@REDACTED (Garrett Smith) Date: Mon, 10 Aug 2015 07:33:51 -0500 Subject: [erlang-questions] dialyzer output help In-Reply-To: <55C89248.5030002@home.nl> References: <55C89248.5030002@home.nl> Message-ID: Hi Roelof, My two cents of this style of docs... > %% doc Function which controls the programm. > %% First the shape is asked on the user. > %% After that if a valid shape is entered the dimensions > %% are asked , and if they are valid the area is being calculated. > > collect_data() -> > Shape = shape_from_user(), > {X, Y} = dimensions_from_user(Shape), > geom:area(Shape, X, Y). I would actually document this function this way: collect_data() -> Shape = shape_from_user(), {X, Y} = dimensions_from_user(Shape), geom:area(Shape, X, Y). This is very clear, at least to me. The upside is that it's also consistent with the code, every time, guaranteed! Your instructors may require that you "document your code" but consider this: %% Set Name Name = "Roelof" Sure, it looks absurd, but if you're required to "document your code" what else are you going to write there? Documenting functions that are completely obvious by restating the same code in another language inside a comment block is, well, see my last sentence. Of course if your function isn't obvious, commenting may help you come to an understanding of what you actually want to write. Take that learning, make the function obvious, then delete the comment! Skip pedantic restating of function implementations. Documenting user facing functions, on the other hand, is important to help your users understand how to use a function. It doesn't necessarily cover each and every implementation detail - for that you can always read the code - but it should provide what a user needs to use the function as it was intended to be used. I use edoc [1] to generate user docs for modules - I don't know if there's something new that folks are using these days. Anyone? Btw, 'collect_data' here is the wrong name for that function IMO as it's result is an area, rather than data used to calc an area. collect_data might look like this: collect_data() -> Shape = shape_from_user(), Dimensions = dimensions_from_user(Shape), {Shape, Dimensions}. Then maybe to highlight the user input + calc operation: area_from_user() -> {Shape, Dimensions} = collect_data(), area(Shape, Dimensions). area(Shape, {X, Y}) -> geom:area(Shape, X, Y). Back to comments - my point is that your *code* is the docs, as far as implementation. If your code is not clear, make it clear. If you can't make it clear, try harder. There are some very rare cases where some code is just hard and some comments can help clarify what's going on - but these are *unicorn rare* in my experience. I realize that you're just picking up a new language here and that's plenty to worry about, short of all this (my) religiosity - and I applaud you for pressing ahead to learn Erlang - great job! I'm picking on some things here that are common vestiges of imperative style programming (and possibly teaching) in order to showcase what I consider some serious benefits of Erlang (and functional/declarative/good programming in general). Garrett [1] http://www.erlang.org/doc/apps/edoc/chapter.html From essen@REDACTED Mon Aug 10 14:47:27 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Mon, 10 Aug 2015 14:47:27 +0200 Subject: [erlang-questions] dialyzer output help In-Reply-To: References: <55C89248.5030002@home.nl> Message-ID: <55C89D5F.8050809@ninenines.eu> On 08/10/2015 02:33 PM, Garrett Smith wrote: > I use edoc [1] to generate user docs for modules I will argue that documentation generated from code isn't documentation. After all, if everything is in the code, why not open the source file directly, use powerful tools like 'git grep' for searching, and read the source? You're guaranteed that the source is up to date, even if the little comment above it isn't, and can avoid mistakes due to outdated comments. If you're going to write documentation, at least don't do it in a half assed way. Make it an integral part of your project, not lousy comments. Separate the documentation from the code. And respect the following rule: *The documentation is always right*. If the code doesn't follow the documentation, it's a bug, not the other way around. Finally, for any large enough project you need three kinds of documentation: a function reference (if it's a library), a user guide and tutorials. The main reason you need all three is because different people learn things in different ways. (And yep, I still have to work on tutorials for my projects. This is actually a recurring question from users who are actively seeking them and have to rely on often outdated tutorials.) -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From vinoski@REDACTED Mon Aug 10 14:48:38 2015 From: vinoski@REDACTED (Steve Vinoski) Date: Mon, 10 Aug 2015 08:48:38 -0400 Subject: [erlang-questions] output to standard_error crashes sometimes on R18 In-Reply-To: <50F2A23D-EB3E-4D09-A50E-01930B61BDE7@gmail.com> References: <619163438.2710789.1438857682456.JavaMail.zimbra@tpip.net> <50F2A23D-EB3E-4D09-A50E-01930B61BDE7@gmail.com> Message-ID: This fixes it: https://github.com/erlang/otp/pull/807 --steve On Fri, Aug 7, 2015 at 12:58 PM, Lukas Larsson wrote: > Hello, > > Many thanks for the detailed analysis. I've gotten the similar reports > from a couple of places. > > I'll take a look at it when I get back from summer vacation. > > Lukas > > > > On 6 aug 2015, at 12:41, Andreas Schultz wrote: > > > > Hi, > > > > Since I upgraded to 18.0.2, my Erlang application Linux sometimes crash > > with egain in standard error. The crash is triggered by something like > this: > > > > io:format(standard_error, "started ~s~n", [application]). > > > > The actual crash looks like this: > > > > ** Generic server standard_error_sup terminating > > ** Last message in was {'EXIT',<0.28.0>,eagain} > > ** When Server state == > {state,standard_error,undefined,<0.28.0>,{local,standard_error_sup}} > > ** Reason for termination == > > ** eagain > > 2015-08-06 09:14:41 =CRASH REPORT==== > > crasher: > > initial call: supervisor_bridge:standard_error/1 > > pid: <0.27.0> > > registered_name: standard_error_sup > > exception exit: > {eagain,[{gen_server,terminate,7,[{file,"gen_server.erl"},{line,826}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]} > > ancestors: [kernel_sup,<0.10.0>] > > messages: [] > > links: [<0.11.0>] > > dictionary: [] > > trap_exit: true > > status: running > > heap_size: 376 > > stack_size: 27 > > reductions: 155 > > neighbours: > > 2015-08-06 09:14:41 =SUPERVISOR REPORT==== > > Supervisor: {local,kernel_sup} > > Context: child_terminated > > Reason: eagain > > Offender: > [{pid,<0.27.0>},{id,standard_error},{mfargs,{standard_error,start_link,[]}},{restart_type,temporary},{shutdown,2000},{child_type,supervisor}] > > > > I have straced erl and it does get an EAGAIN on fd 2: > > > > 14209 09:14:41.170429 writev(2, [{"started gen_listener_tcp\n", 25}], 1 > > > 14209 09:14:41.170446 <... writev resumed> ) = -1 EAGAIN (Resource > temporarily unavailable) > > > > So whats going on here??? > > > > After some searching I found a nice explanation about duped fd's and > file status flags > > here: http://stackoverflow.com/a/9677130 (a quick test program verifies > that this indeed > > happens on Linux). > > > > So according to that, setting any of the stdio file descriptors to > non-blocking, would > > set all of them to non-blocking. And sure enough, strace shows this: > > > > 14170 09:14:39.787004 fcntl(1, F_SETFL, O_RDWR|O_NONBLOCK|O_LARGEFILE) > = 0 > > > > (pid 14170 is the main erl process, pid 14209 one of the threads in erl) > > > > I have stopped digging through this at that point. Clearly, the > standard_error > > process or the underlying port driver should handle the EAGAIN > gracefully, but > > fail to do so. > > > > Andreas > > _______________________________________________ > > erlang-questions mailing list > > erlang-questions@REDACTED > > http://erlang.org/mailman/listinfo/erlang-questions > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From g@REDACTED Mon Aug 10 14:51:39 2015 From: g@REDACTED (Garrett Smith) Date: Mon, 10 Aug 2015 07:51:39 -0500 Subject: [erlang-questions] dialyzer output help In-Reply-To: <55C89D5F.8050809@ninenines.eu> References: <55C89248.5030002@home.nl> <55C89D5F.8050809@ninenines.eu> Message-ID: On Mon, Aug 10, 2015 at 7:47 AM, Lo?c Hoguin wrote: > Separate the documentation from the code For documenting modules along the lines of erlang.org's reference material [1] what do you do? [1] E.g. http://erlang.org/doc/man/lists.html From essen@REDACTED Mon Aug 10 14:56:34 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Mon, 10 Aug 2015 14:56:34 +0200 Subject: [erlang-questions] dialyzer output help In-Reply-To: References: <55C89248.5030002@home.nl> <55C89D5F.8050809@ninenines.eu> Message-ID: <55C89F82.60202@ninenines.eu> On 08/10/2015 02:51 PM, Garrett Smith wrote: > On Mon, Aug 10, 2015 at 7:47 AM, Lo?c Hoguin wrote: >> Separate the documentation from the code > > For documenting modules along the lines of erlang.org's reference > material [1] what do you do? > > [1] E.g. http://erlang.org/doc/man/lists.html This is what *they* do: https://github.com/erlang/otp/blob/maint/lib/stdlib/doc/src/lists.xml What I do is similar, except using Asciidoc: https://github.com/ninenines/gun/blob/master/doc/src/manual/gun.asciidoc (Tried a few formats over the years, settled on that one recently, don't think I'll switch again. :-) -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From hugo@REDACTED Mon Aug 10 14:58:25 2015 From: hugo@REDACTED (Hugo Mills) Date: Mon, 10 Aug 2015 12:58:25 +0000 Subject: [erlang-questions] dialyzer output help In-Reply-To: <55C89D5F.8050809@ninenines.eu> References: <55C89248.5030002@home.nl> <55C89D5F.8050809@ninenines.eu> Message-ID: <20150810125825.GD12976@carfax.org.uk> On Mon, Aug 10, 2015 at 02:47:27PM +0200, Lo?c Hoguin wrote: > On 08/10/2015 02:33 PM, Garrett Smith wrote: > >I use edoc [1] to generate user docs for modules > > I will argue that documentation generated from code isn't > documentation. After all, if everything is in the code, why not open > the source file directly, use powerful tools like 'git grep' for > searching, and read the source? You're guaranteed that the source is > up to date, even if the little comment above it isn't, and can avoid > mistakes due to outdated comments. > > If you're going to write documentation, at least don't do it in a > half assed way. Make it an integral part of your project, not lousy > comments. Separate the documentation from the code. And respect the > following rule: *The documentation is always right*. If the code > doesn't follow the documentation, it's a bug, not the other way > around. > > Finally, for any large enough project you need three kinds of > documentation: a function reference (if it's a library), a user > guide and tutorials. The main reason you need all three is because > different people learn things in different ways. I would also ask for a mid-level architecture guide showing how the different kinds of pieces should fit together. e.g. "This is the general flow of data through the processing. Part A can be any function of type: see A1, A2, A3 for example; part B must do , prebuilt ones are B1, B2, or write your own; part C is entirely optional and can be omitted." I've found it's a particular failing of projects with (autogenerated) function/API references: you get delivered a pile of parts with detailed specifications, and absolutely no idea of how to assemble them into something useful. If you're lucky, you'll get either a trivial example with no idea of how to generalise it, or you'll get an example of the general case, with no idea of which pieces you can leave out. The flow diagrams in cowboy showing all of the available hooks and flows are absolutely brilliant from this point of view. Hugo. > (And yep, I still have to work on tutorials for my projects. This is > actually a recurring question from users who are actively seeking > them and have to rely on often outdated tutorials.) > -- Hugo Mills | Most administrators wouldn't give their users the hugo@REDACTED carfax.org.uk | time of day. That's what NTP is for. http://carfax.org.uk/ | PGP: E2AB1DE4 | Tim Mullen -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: From xuxb1979@REDACTED Mon Aug 10 14:59:14 2015 From: xuxb1979@REDACTED (Xiaobin Xu) Date: Mon, 10 Aug 2015 20:59:14 +0800 Subject: [erlang-questions] 3des decryption in erlang Message-ID: Hi, all, For some reason i have to decrypt a message that is encrypted using 3DES algorithm, and I've PHP function example how to decrypt the message: public function decrypt($value) { $td = mcrypt_module_open ( MCRYPT_3DES, '', MCRYPT_MODE_ECB, '' ); mcrypt_generic_init ( $td, $this->key,$this->iv ); $ret = trim ( mdecrypt_generic ( $td, base64_decode ( $value ) ) ); $ret = $this->UnPaddingPKCS7 ( $ret ); mcrypt_generic_deinit ( $td ); mcrypt_module_close ( $td ); return $ret; } private function UnPaddingPKCS7($data) { $padlen = ord (substr($data, (strlen( $data )-1), 1 ) ); if ($padlen > 8 ) return $data; for($i = -1*($padlen-strlen($data)); $i < strlen ( $data ); $i ++) { if (ord ( substr ( $data, $i, 1 ) ) != $padlen)return false; } return substr ( $data, 0, -1*($padlen-strlen ( $data ) ) ); } I googled and read crypto module document for a couple hours, and got no idea how to translate these two functions into erlang. Any ideas? Thanks, Xiaobin -------------- next part -------------- An HTML attachment was scrubbed... URL: From g@REDACTED Mon Aug 10 15:02:48 2015 From: g@REDACTED (Garrett Smith) Date: Mon, 10 Aug 2015 08:02:48 -0500 Subject: [erlang-questions] dialyzer output help In-Reply-To: <55C89F82.60202@ninenines.eu> References: <55C89248.5030002@home.nl> <55C89D5F.8050809@ninenines.eu> <55C89F82.60202@ninenines.eu> Message-ID: On Mon, Aug 10, 2015 at 7:56 AM, Lo?c Hoguin wrote: > On 08/10/2015 02:51 PM, Garrett Smith wrote: >> >> On Mon, Aug 10, 2015 at 7:47 AM, Lo?c Hoguin wrote: >>> >>> Separate the documentation from the code >> >> For documenting modules along the lines of erlang.org's reference >> material [1] what do you do? >> >> [1] E.g. http://erlang.org/doc/man/lists.html > > This is what *they* do: > > https://github.com/erlang/otp/blob/maint/lib/stdlib/doc/src/lists.xml XML, for when life is going a little too well. > What I do is similar, except using Asciidoc: > > https://github.com/ninenines/gun/blob/master/doc/src/manual/gun.asciidoc > > (Tried a few formats over the years, settled on that one recently, don't > think I'll switch again. :-) This is great - I'll use this! From r.wobben@REDACTED Mon Aug 10 15:04:12 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 10 Aug 2015 15:04:12 +0200 Subject: [erlang-questions] dialyzer output help In-Reply-To: <55C89F82.60202@ninenines.eu> References: <55C89248.5030002@home.nl> <55C89D5F.8050809@ninenines.eu> <55C89F82.60202@ninenines.eu> Message-ID: <55C8A14C.8070906@home.nl> Op 10-8-2015 om 14:56 schreef Lo?c Hoguin: > On 08/10/2015 02:51 PM, Garrett Smith wrote: >> On Mon, Aug 10, 2015 at 7:47 AM, Lo?c Hoguin wrote: >>> Separate the documentation from the code >> >> For documenting modules along the lines of erlang.org's reference >> material [1] what do you do? >> >> [1] E.g. http://erlang.org/doc/man/lists.html > > This is what *they* do: > > https://github.com/erlang/otp/blob/maint/lib/stdlib/doc/src/lists.xml > > What I do is similar, except using Asciidoc: > > https://github.com/ninenines/gun/blob/master/doc/src/manual/gun.asciidoc > > (Tried a few formats over the years, settled on that one recently, > don't think I'll switch again. :-) > Thanks, But now I more confused. Im reading the introducing erlang book and there is always stated to document your code. I find this the most difficult part because how do I document something like the area function. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From essen@REDACTED Mon Aug 10 15:06:47 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Mon, 10 Aug 2015 15:06:47 +0200 Subject: [erlang-questions] dialyzer output help In-Reply-To: <55C8A14C.8070906@home.nl> References: <55C89248.5030002@home.nl> <55C89D5F.8050809@ninenines.eu> <55C89F82.60202@ninenines.eu> <55C8A14C.8070906@home.nl> Message-ID: <55C8A1E7.7010306@ninenines.eu> On 08/10/2015 03:04 PM, Roelof Wobben wrote: > Op 10-8-2015 om 14:56 schreef Lo?c Hoguin: >> On 08/10/2015 02:51 PM, Garrett Smith wrote: >>> On Mon, Aug 10, 2015 at 7:47 AM, Lo?c Hoguin wrote: >>>> Separate the documentation from the code >>> >>> For documenting modules along the lines of erlang.org's reference >>> material [1] what do you do? >>> >>> [1] E.g. http://erlang.org/doc/man/lists.html >> >> This is what *they* do: >> >> https://github.com/erlang/otp/blob/maint/lib/stdlib/doc/src/lists.xml >> >> What I do is similar, except using Asciidoc: >> >> https://github.com/ninenines/gun/blob/master/doc/src/manual/gun.asciidoc >> >> (Tried a few formats over the years, settled on that one recently, >> don't think I'll switch again. :-) >> > > > Thanks, > > But now I more confused. > Im reading the introducing erlang book and there is always stated to > document your code. > > I find this the most difficult part because how do I document something > like the area function. > > Roelof I think for commenting code, Garretttt's advice was spot on. If you make the code readable on its own, mainly through the use of proper function and variable names, you don't need to put a comment above it to explain how it works. -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From r.wobben@REDACTED Mon Aug 10 15:53:37 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 10 Aug 2015 15:53:37 +0200 Subject: [erlang-questions] Fwd: Re: dialyzer output help In-Reply-To: <55C8A241.3050700@home.nl> References: <55C8A241.3050700@home.nl> Message-ID: <55C8ACE1.2040209@home.nl> An HTML attachment was scrubbed... URL: From seancribbs@REDACTED Mon Aug 10 15:54:30 2015 From: seancribbs@REDACTED (Sean Cribbs) Date: Mon, 10 Aug 2015 08:54:30 -0500 Subject: [erlang-questions] 3des decryption in erlang In-Reply-To: References: Message-ID: Xiaobin, Here's what I came up with: crypto:start(), %% To decrypt the text, note Key and IV must be defined in this scope Unencoded = base64:decode(Value), Cleartext = crypto:block_decrypt(des3_cbc, Key, IV, Unencoded), %% To unpad the text, see https://github.com/camshaft/pkcs7.erl pkcs7:unpad(Cleartext) The main thing to note is the difference in how you use the crypto module. In Erlang, you don't need to initialize, decrypt, and cleanup in separate steps. You do however, need to make sure the crypto application is started before you try this. Generally, you would make crypto a dependency (see http://erlang.org/doc/man/app.html) of the application that contains this code and it would be started automatically when your release is booted. On Mon, Aug 10, 2015 at 7:59 AM, Xiaobin Xu wrote: > Hi, all, > > For some reason i have to decrypt a message that is encrypted using > 3DES algorithm, and I've PHP function example how to decrypt the message: > > public function decrypt($value) { > $td = mcrypt_module_open ( MCRYPT_3DES, '', MCRYPT_MODE_ECB, '' ); > mcrypt_generic_init ( $td, $this->key,$this->iv ); > $ret = trim ( mdecrypt_generic ( $td, base64_decode ( $value ) ) ); > $ret = $this->UnPaddingPKCS7 ( $ret ); > mcrypt_generic_deinit ( $td ); > mcrypt_module_close ( $td ); > return $ret; > } > > > private function UnPaddingPKCS7($data) { > $padlen = ord (substr($data, (strlen( $data )-1), 1 ) ); > if ($padlen > 8 ) > return $data; > > for($i = -1*($padlen-strlen($data)); $i < strlen ( $data ); $i ++) { > if (ord ( substr ( $data, $i, 1 ) ) != $padlen)return false; > } > > return substr ( $data, 0, -1*($padlen-strlen ( $data ) ) ); > } > > I googled and read crypto module document for a couple hours, and got > no idea how to translate these two functions into erlang. > > Any ideas? > > > Thanks, > Xiaobin > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From seancribbs@REDACTED Mon Aug 10 16:19:38 2015 From: seancribbs@REDACTED (Sean Cribbs) Date: Mon, 10 Aug 2015 09:19:38 -0500 Subject: [erlang-questions] dialyzer output help In-Reply-To: <55C89248.5030002@home.nl> References: <55C89248.5030002@home.nl> Message-ID: It seems Garrett and Loic missed your actual question. The problem is in prompt_user/1. How did I know that? Well, "has no local return" just means that something that function calls will likely crash, so until you fix the root problem you can ignore those. Likewise, "will never be called" can often be an indicator that something else is wrong. So let's look at prompt_user/1. The error says "call ... breaks the contract (string()) -> string()". This means that the caller of this function is not passing the correct type. Dialyzer thinks the type of the argument in the call on line 89 is [[1..255,...],...]. Herein lies the error, the string() type is an alias for [char()], where char() is 0..16#10ffff, or basically the Unicode character space. Why is this type erroneous? Because you are passing lists of lists to the function, not *flat lists* of characters. That is indeed the case in number_from_user/1 (and possibly elsewhere): Prompt = ["Enter ", Name, " > "], to_positive_number(prompt_user(Prompt)). Instead of string() as the argument type, I'd use iodata(), or less desirably, call lists:flatten/1 before passing the prompt. Now, that may solve your issue with dialyzer. However, look at the type of io:get_line/1 (http://erlang.org/doc/man/io.html#get_line-1): get_line(Prompt) -> Data ... Data = string() | unicode:unicode_binary() The return value might be a string, or it might be a unicode_binary() if the device is in binary mode! This is not likely for standard input, but you might need to match on that case. However, first fix the spec for prompt_user/1, then see if dialyzer still finds errors. What I like about this exercise of adding specs is it brings up a good point about using dialyzer. Generally, I try NOT to add specs to internal functions unless they are especially complex -- even then it might be a sign I need to refactor. Oftentimes, dialyzer will discover any static errors even without them, especially if I have added specs to my exported functions. There are also many other things that dialyzer uses to infer the types of parts of your program that don't require specs, for example, library functions that you call or destructuring pattern matches. Specs are most useful as documentation and for narrowing the inferred types so that external callers will be encouraged (forced?) to follow the contract. Unlike Hindley-Milner type systems, it can't guarantee that your types are correct, but it can ensure that you don't make a bunch of silly errors. On Mon, Aug 10, 2015 at 7:00 AM, Roelof Wobben wrote: > Hello, > > I try to document this function which I found on another topic. > > %% @author Roelof Wobben > %% @doc Function to calculate the area of a rectangle, a ellipse or a > triangle > %% @reference from Introducing Erlang, > %% O'Reilly Media, Inc., 2012. > %% @copyright 2012 by R.Wobben > %% @version 0.1 > > -module(ask_area). > > -export([area/0]). > > -spec(area() -> 'ok' | 'error'). > > %% @doc a function which looks if the function collect_data > %% outputs a number which resambles the area of the shape the > %% user has choosen with the dimensions which the user has entered > %% if the user entered a wrong shape or not a number on the dimension > %% part , there will be a right error message to tell what went wrong > > area() -> > try collect_data() of > Area -> io:format("The area is ~p~n", [Area]) > catch > error:Err -> io:format("~s~n", [error_msg(Err)]) > end. > > -spec(collect_data() -> number() ). > > %% doc Function which controls the programm. > %% First the shape is asked on the user. > %% After that if a valid shape is entered the dimensions > %% are asked , and if they are valid the area is being calculated. > > collect_data() -> > Shape = shape_from_user(), > {X, Y} = dimensions_from_user(Shape), > geom:area(Shape, X, Y). > > > > -spec (shape_from_user() -> 'ellipse' | 'rectangle' | 'triangle' ) . > > %%doc Here the right prompt is made so the user > %% can choose the shape they want. > > shape_from_user() -> > Prompt = "R)ectangle, T)riangle, or E)llipse > ", > char_to_shape(prompt_user(Prompt)). > > -spec (prompt_user(string()) -> string()). > > %% doc Here the prompt is displayed and send to > %% the strip function so the newline is stripped. > > prompt_user(Prompt) -> > strip_lf(io:get_line(Prompt)). > > -spec (strip_lf (string()) -> string() ). > > %%doc Here the newline is stripped from the userinput. > > strip_lf(Str) -> > string:strip(Str, right, $\n). > > > > char_to_shape("R") -> rectangle; > char_to_shape("r") -> rectangle; > char_to_shape("T") -> triangle; > char_to_shape("t") -> triangle; > char_to_shape("E") -> ellipse; > char_to_shape("e") -> ellipse; > char_to_shape(_) -> error(bad_shape). > > dimensions_from_user(rectangle) -> > numbers_from_user("width", "height"); > dimensions_from_user(triangle) -> > numbers_from_user("base", "height"); > dimensions_from_user(ellipse) -> > numbers_from_user("major axis", "minor axis"). > > numbers_from_user(XPrompt, YPrompt) -> > X = number_from_user(XPrompt), > Y = number_from_user(YPrompt), > {X, Y}. > > number_from_user(Name) -> > Prompt = ["Enter ", Name, " > "], > to_positive_number(prompt_user(Prompt)). > > to_positive_number(Prompt) -> > positive_number(to_number(Prompt)). > > positive_number(N) when N > 0 -> N; > positive_number(_) -> error(bad_number). > > to_number(Str) -> > try_number([fun list_to_float/1, fun list_to_integer/1], Str). > > try_number([Method|Rest], Arg) -> > try > Method(Arg) > catch > error:badarg -> try_number(Rest, Arg) > end; > try_number([], _Arg) -> > error(bad_number). > > error_msg(bad_shape) -> "Please enter a valid shape"; > error_msg(bad_number) -> "Please enter a positive number". > > > but as soon as I run dialyzer I see this output : > > Checking whether the PLT /home/nitrous/.dialyzer_plt is up-to-date... yes > Proceeding with analysis... > ask_area.erl:34: Function collect_data/0 has no local return > ask_area.erl:75: Function dimensions_from_user/1 has no local return > ask_area.erl:82: Function numbers_from_user/2 has no local return > ask_area.erl:87: Function number_from_user/1 has no local return > ask_area.erl:89: The call ask_area:prompt_user(Prompt::[[1..255,...],...]) > breaks the contract (string()) -> string() > ask_area.erl:91: Function to_positive_number/1 will never be called > ask_area.erl:94: Function positive_number/1 will never be called > ask_area.erl:97: Function to_number/1 will never be called > ask_area.erl:100: Function try_number/2 will never be called > done in 0m0.51s done (warnings were emitted) > > hecking whether the PLT /home/nitrous/.dialyzer_plt is up-to-date... yes > Proceeding with analysis... > ask_area.erl:34: Function collect_data/0 has no local return > ask_area.erl:75: Function dimensions_from_user/1 has no local return > ask_area.erl:82: Function numbers_from_user/2 has no local return > ask_area.erl:87: Function number_from_user/1 has no local return > ask_area.erl:89: The call ask_area:prompt_user(Prompt::[[1..255,...],...]) > breaks the contract (string()) -> string() > ask_area.erl:91: Function to_positive_number/1 will never be called > ask_area.erl:94: Function positive_number/1 will never be called > ask_area.erl:97: Function to_number/1 will never be called > ask_area.erl:100: Function try_number/2 will never be called > Unknown functions: > geom:area/3 > done in 0m0.51s > done (warnings were emitted) > > > > Can someone explain what these messages mean. > This is the first time I use dialyzer and this confuses me. > > Roelof > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jesper.louis.andersen@REDACTED Mon Aug 10 16:23:12 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Mon, 10 Aug 2015 16:23:12 +0200 Subject: [erlang-questions] dialyzer output help In-Reply-To: <55C89248.5030002@home.nl> References: <55C89248.5030002@home.nl> Message-ID: On Mon, Aug 10, 2015 at 2:00 PM, Roelof Wobben wrote: > -spec(area() -> 'ok' | 'error'). (Sean is beating me to it by a few minutes, but I have some things in here that pushes different perspectives on his answer, so I'll post it anyway) This is not the precise way to specify a function. I think it may work since the parens around the specification are ignored, but I wouldn't rely on it. See http://erlang.org/doc/reference_manual/typespec.html and the section "Function specifications". The notation for the above would be -spec area() -> 'ok' | 'error'. Anyway, on to the error. The problem is we have a spec for prompt_user/1 that looks like the following: -spec prompt_user(string()) -> string(). But then you define: number_from_user(Name) -> Prompt = ["Enter ", Name, " > "], to_positive_number(prompt_user(Prompt)). Note how the type we call with is a list(string()). This clearly breaks the contract in the code, since you said this can't occur in the -spec. At this point, it is often clever to ask the `typer` tool what it believes the type is, or you can change the code: either by altering the Prompt value in number_from_user/1 (lists:append/1 might come in handy here), or by switching the spec: -spec prompt_user(Input) -> string() when Input :: string() | [string()]. However, you may need to be more precise given that Unicode is in the game here. -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Mon Aug 10 16:34:39 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 10 Aug 2015 16:34:39 +0200 Subject: [erlang-questions] dialyzer output help In-Reply-To: References: <55C89248.5030002@home.nl> Message-ID: <55C8B67F.6030003@home.nl> An HTML attachment was scrubbed... URL: From mononcqc@REDACTED Mon Aug 10 17:32:02 2015 From: mononcqc@REDACTED (Fred Hebert) Date: Mon, 10 Aug 2015 11:32:02 -0400 Subject: [erlang-questions] dialyzer output help In-Reply-To: References: <55C89248.5030002@home.nl> Message-ID: <20150810153201.GB816@fhebert-ltm1> I wanted to comment here on specific points, so I've taken your email apart and reassembled it for what I felt fit a better narrative for my stuff. Please don't see some dishonesty in the argument there (creating a strawman or whatever) as this isn't my intent :) On 08/10, Garrett Smith wrote: >Back to comments - my point is that your *code* is the docs, as far as >implementation. If your code is not clear, make it clear. If you can't >make it clear, try harder. There are some very rare cases where some >code is just hard and some comments can help clarify what's going on - >but these are *unicorn rare* in my experience. > I've conducted a poll a few years ago (2012) on Erlang and Maintenance in this community (http://ferd.ca/poll-results-erlang-maintenance.html) and one of the interesting results was in the following image (also attached): http://ferd.ca/static/img/charts/correlations_comments-erlang.png The idea that comments are not required tends to decrease with experience in the language and familiarity with it. At the very least, there was decent correlation. I like to think of it as someone learning to read: you first start by reading out loud as you read; it helps build connections and solidify your grasp on language. As you get a more profficient reader, you subvocalize more and more up to the point where speed readers do not even 'mentally read' words -- they just glance over the text and can understand meaning from it anyway. Newcomers writing comments in the code, as far as I can rationalize it, tends to be about writing down a translation of what the code should be doing against the actual implementation. As you get more familiar, that translation takes place automatically and the comments become more useless. If I had to give a tip to newcomers, it would be that it's fine to write these comments first -- they act as a bit of a specification or pseudo code. As you go on, the refactoring Garrett mentions would be to try, as much as possible, to make the logic in your code look like the comments you wrote, so that they become obsolete and can be dropped. Let's take some fake code as an example: %% Verify that only adults (18 years or older) can enter can_enter(Age) when Age >= 18 -> true; can_enter(_) -> false. So that's a decent specification, and a newcomer gets to go "oh okay, Age is the variable, >= is how they compare here, not =>, and apparently the clauses are alternatives". As you get more used to it, you lose the interest for the comment, but there's still a lot of interesting stuff left untold: - The function assumes that age is the accepted factor for adulthood - The function assumes that the program runs in a jurisdiction where adulthood is defined as 18, rather than 16, 19, or 21, for example, or that - The function only expects numbers to be passed in. So a more complete form could be imagined to be written like: %% Age of adulthood in Quebec -define(ADULT_AGE, 18). -type age() :: number(). %% Age verification is required by the government %% on online betting websites; credit cards would work %% but can sometimes be granted to minors and isn't sufficient %% for proper verification. However, just asking for age %% can legally be considered good enough. -spec can_enter(age()) -> boolean(). can_enter(Age) when Age >= ?ADULT_AGE -> true; can_enter(_) -> false. And now the code has more criteria encoded. You'll noticed I pulled a bunch of information out of my rear end just to add comments, but really, those are the tricky things in code that bite us and are worth putting in there, on top of everything else. Why? Because the next time someone comes in and refactors, they know why the code was added, and it makes it so, so much easier to make a good decision on whether it should be removed or not without having to hope it's somewhere in source control. What should be kept in comments? The stuff that is hard to represent in code: - Why you picked a given algorithm or implementation details - Gotchas are how to use the code - Edge conditions that cannot be represented otherwise (through type specifications and whatnot) in your language of choice - The rationale for broader design decisions. "We picked UUIDs for identifiers because the system requires sharding and it is easier with them than sequential ids" Hell: should the ids be considered opaque or not? Details about what the code *does* are interesting to newcomers, still, so part of the question you have to ask yourself is: who is my target audience? Who will read this code? Even if the need is not there for veteran Erlangers, it might be there for newcomers. If you're the senior member (or consultant) on a team with a lot of new people, it might be interesting to put these 'useless' comments in to onboard everyone else. Development is extremely human, and knowing that such comments are important to some people means that they *should* be in your toolbox if you work with them, or want them to work with you. >Documenting user facing functions, on the other hand, is important to >help your users understand how to use a function. It doesn't >necessarily cover each and every implementation detail - for that you >can always read the code - but it should provide what a user needs to >use the function as it was intended to be used. > Yes! But "read the code" is a pisspoor thing to tell almost *anyone*. The reason is that there are many types of documentation for different audiences: Newcomers: what does it do, why did you write it, who should or shouldn't use this piece of code, where can additional info be found, short examples, etc. Regulars: Reference manuals, examples, edoc, wikis, websites, api descriptions Contributors: architecture, project structure, principles guiding the design ("we favor the users on errors", "the state on disk cannot be left inconsistent and we prefer to lose data", etc.), tests: where to find them and how to run them, issue tracker, **the source**. If anyone but a contributor (or someone looking for contributor-level information) has to read the source, your doc is not good enough. Regulars and newcomers shouldn't have to care about your code and how it does things; they care about whether they should use it, what it does, and how to use things. Only contributors or people debugging your stuff tend to care about *how* it does things or *why* it does it. I did expand a bunch on this in a blog post before, so I'll just link to it rather than filling everyone's mailboxes even more: http://ferd.ca/don-t-be-a-jerk-write-documentation.html Regards, Fred. From r.wobben@REDACTED Mon Aug 10 17:43:22 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 10 Aug 2015 17:43:22 +0200 Subject: [erlang-questions] dialyzer output help In-Reply-To: <20150810153201.GB816@fhebert-ltm1> References: <55C89248.5030002@home.nl> <20150810153201.GB816@fhebert-ltm1> Message-ID: <55C8C69A.8030402@home.nl> Op 10-8-2015 om 17:32 schreef Fred Hebert: > I wanted to comment here on specific points, so I've taken your email > apart and reassembled it for what I felt fit a better narrative for my > stuff. Please don't see some dishonesty in the argument there > (creating a strawman or whatever) as this isn't my intent :) > > On 08/10, Garrett Smith wrote: >> Back to comments - my point is that your *code* is the docs, as far as >> implementation. If your code is not clear, make it clear. If you can't >> make it clear, try harder. There are some very rare cases where some >> code is just hard and some comments can help clarify what's going on - >> but these are *unicorn rare* in my experience. >> > > I've conducted a poll a few years ago (2012) on Erlang and Maintenance > in this community > (http://ferd.ca/poll-results-erlang-maintenance.html) and one of the > interesting results was in the following image (also attached): > > http://ferd.ca/static/img/charts/correlations_comments-erlang.png > > The idea that comments are not required tends to decrease with > experience in the language and familiarity with it. At the very least, > there was decent correlation. > > I like to think of it as someone learning to read: you first start by > reading out loud as you read; it helps build connections and solidify > your grasp on language. As you get a more profficient reader, you > subvocalize more and more up to the point where speed readers do not > even 'mentally read' words -- they just glance over the text and can > understand meaning from it anyway. > > Newcomers writing comments in the code, as far as I can rationalize > it, tends to be about writing down a translation of what the code > should be doing against the actual implementation. > > As you get more familiar, that translation takes place automatically > and the comments become more useless. > > If I had to give a tip to newcomers, it would be that it's fine to > write these comments first -- they act as a bit of a specification or > pseudo code. As you go on, the refactoring Garrett mentions would be > to try, as much as possible, to make the logic in your code look like > the comments you wrote, so that they become obsolete and can be dropped. > > Let's take some fake code as an example: > > %% Verify that only adults (18 years or older) can enter > can_enter(Age) when Age >= 18 -> true; > can_enter(_) -> false. > > So that's a decent specification, and a newcomer gets to go "oh okay, > Age is the variable, >= is how they compare here, not =>, and > apparently the clauses are alternatives". > > As you get more used to it, you lose the interest for the comment, but > there's still a lot of interesting stuff left untold: > > - The function assumes that age is the accepted factor for adulthood > - The function assumes that the program runs in a jurisdiction where > adulthood is defined as 18, rather than 16, 19, or 21, for example, > or that - The function only expects numbers to be passed in. > > So a more complete form could be imagined to be written like: > > %% Age of adulthood in Quebec > -define(ADULT_AGE, 18). > -type age() :: number(). > > %% Age verification is required by the government > %% on online betting websites; credit cards would work > %% but can sometimes be granted to minors and isn't sufficient > %% for proper verification. However, just asking for age > %% can legally be considered good enough. > -spec can_enter(age()) -> boolean(). > can_enter(Age) when Age >= ?ADULT_AGE -> true; > can_enter(_) -> false. > > And now the code has more criteria encoded. You'll noticed I pulled a > bunch of information out of my rear end just to add comments, but > really, those are the tricky things in code that bite us and are worth > putting in there, on top of everything else. > > Why? Because the next time someone comes in and refactors, they know > why the code was added, and it makes it so, so much easier to make a > good decision on whether it should be removed or not without having to > hope it's somewhere in source control. > > What should be kept in comments? The stuff that is hard to represent > in code: > > - Why you picked a given algorithm or implementation details > - Gotchas are how to use the code > - Edge conditions that cannot be represented otherwise (through type > specifications and whatnot) in your language of choice > - The rationale for broader design decisions. "We picked UUIDs for > identifiers because the system requires sharding and it is easier > with them than sequential ids" Hell: should the ids be considered > opaque or not? > > Details about what the code *does* are interesting to newcomers, > still, so part of the question you have to ask yourself is: who is my > target audience? Who will read this code? > > Even if the need is not there for veteran Erlangers, it might be there > for newcomers. If you're the senior member (or consultant) on a team > with a lot of new people, it might be interesting to put these > 'useless' comments in to onboard everyone else. > > Development is extremely human, and knowing that such comments are > important to some people means that they *should* be in your toolbox > if you work with them, or want them to work with you. > >> Documenting user facing functions, on the other hand, is important to >> help your users understand how to use a function. It doesn't >> necessarily cover each and every implementation detail - for that you >> can always read the code - but it should provide what a user needs to >> use the function as it was intended to be used. >> > > Yes! But "read the code" is a pisspoor thing to tell almost *anyone*. > The reason is that there are many types of documentation for different > audiences: > > Newcomers: what does it do, why did you write it, who should or > shouldn't use this piece of code, where can additional info be found, > short examples, etc. > > Regulars: Reference manuals, examples, edoc, wikis, websites, api > descriptions > > Contributors: architecture, project structure, principles guiding the > design ("we favor the users on errors", "the state on disk cannot be > left inconsistent and we prefer to lose data", etc.), tests: where to > find them and how to run them, issue tracker, **the source**. > > If anyone but a contributor (or someone looking for contributor-level > information) has to read the source, your doc is not good enough. > > Regulars and newcomers shouldn't have to care about your code and how > it does things; they care about whether they should use it, what it > does, and how to use things. > > Only contributors or people debugging your stuff tend to care about > *how* it does things or *why* it does it. > > I did expand a bunch on this in a blog post before, so I'll just link > to it rather than filling everyone's mailboxes even more: > http://ferd.ca/don-t-be-a-jerk-write-documentation.html > > Regards, > Fred. > Thanks, I will try to do this one my next assignment where i working now. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From r.wobben@REDACTED Mon Aug 10 17:46:36 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 10 Aug 2015 17:46:36 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code Message-ID: <55C8C75C.2070301@home.nl> Hello, I have to make a programm which convert the iso-date to a list of numbers so 2015-08-10 will be [2015,08,10] As a working programm I have wrote this : -module(dates). -export([date_parts/1]). date_parts(Date)-> [Year, Month, Day] = re:split(Date, "-", [{return, list}] ), [element(1, string:to_integer(Year)), element(1,string:to_integer(Month)), element(1,string:to_integer(Day))]. Now my question is how to make this code beautifull. I think myself to make seperate functions for extracting the numbers out of the list and one for converting the string to numbers. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From sergej.jurecko@REDACTED Mon Aug 10 17:49:10 2015 From: sergej.jurecko@REDACTED (Sergej =?UTF-8?B?SnVyZcSNa28=?=) Date: Mon, 10 Aug 2015 17:49:10 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: <55C8C75C.2070301@home.nl> References: <55C8C75C.2070301@home.nl> Message-ID: date_parts(Date) -> [list_to_integer(N) || N <- string:tokens(Date,"-")]. Sergej On 10/08/15 17:46, "Roelof Wobben" wrote: >Hello, > >I have to make a programm which convert the iso-date to a list of >numbers so 2015-08-10 will be [2015,08,10] > >As a working programm I have wrote this : > >-module(dates). > >-export([date_parts/1]). > >date_parts(Date)-> > [Year, Month, Day] = re:split(Date, "-", [{return, list}] ), > [element(1, string:to_integer(Year)), >element(1,string:to_integer(Month)), element(1,string:to_integer(Day))]. > >Now my question is how to make this code beautifull. > >I think myself to make seperate functions for extracting the numbers out >of the list and one for converting the string to numbers. > >Roelof > > >--- >Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >https://www.avast.com/antivirus > >_______________________________________________ >erlang-questions mailing list >erlang-questions@REDACTED >http://erlang.org/mailman/listinfo/erlang-questions From r.wobben@REDACTED Mon Aug 10 17:52:30 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 10 Aug 2015 17:52:30 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: References: <55C8C75C.2070301@home.nl> Message-ID: <55C8C8BE.1080505@home.nl> Thanks, but I forget to mentioned that I have to use the re module. Op 10-8-2015 om 17:49 schreef Sergej Jure?ko: > date_parts(Date) -> > [list_to_integer(N) || N <- string:tokens(Date,"-")]. > > > > > Sergej > > > > > On 10/08/15 17:46, "Roelof Wobben" wrote: > >> Hello, >> >> I have to make a programm which convert the iso-date to a list of >> numbers so 2015-08-10 will be [2015,08,10] >> >> As a working programm I have wrote this : >> >> -module(dates). >> >> -export([date_parts/1]). >> >> date_parts(Date)-> >> [Year, Month, Day] = re:split(Date, "-", [{return, list}] ), >> [element(1, string:to_integer(Year)), >> element(1,string:to_integer(Month)), element(1,string:to_integer(Day))]. >> >> Now my question is how to make this code beautifull. >> >> I think myself to make seperate functions for extracting the numbers out >> of the list and one for converting the string to numbers. >> >> Roelof >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From garry@REDACTED Mon Aug 10 17:59:57 2015 From: garry@REDACTED (Garry Hodgson) Date: Mon, 10 Aug 2015 11:59:57 -0400 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: <55C8C8BE.1080505@home.nl> References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> Message-ID: <55C8CA7D.4090300@research.att.com> so replace string:tokens() call with re:split(). On 8/10/15 11:52 AM, Roelof Wobben wrote: > Thanks, but I forget to mentioned that I have to use the re module. > > > Op 10-8-2015 om 17:49 schreef Sergej Jure?ko: >> date_parts(Date) -> >> [list_to_integer(N) || N <- string:tokens(Date,"-")]. >> >> >> >> >> Sergej >> >> >> >> >> On 10/08/15 17:46, "Roelof Wobben" >> >> wrote: >> >>> Hello, >>> >>> I have to make a programm which convert the iso-date to a list of >>> numbers so 2015-08-10 will be [2015,08,10] >>> >>> As a working programm I have wrote this : >>> >>> -module(dates). >>> >>> -export([date_parts/1]). >>> >>> date_parts(Date)-> >>> [Year, Month, Day] = re:split(Date, "-", [{return, list}] ), >>> [element(1, string:to_integer(Year)), >>> element(1,string:to_integer(Month)), >>> element(1,string:to_integer(Day))]. >>> >>> Now my question is how to make this code beautifull. >>> >>> I think myself to make seperate functions for extracting the numbers >>> out >>> of the list and one for converting the string to numbers. >>> >>> Roelof >>> >>> >>> --- >>> Dit e-mailbericht is gecontroleerd op virussen met Avast >>> antivirussoftware. >>> https://www.avast.com/antivirus >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >> > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast > antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > From r.wobben@REDACTED Mon Aug 10 18:09:38 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 10 Aug 2015 18:09:38 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: <55C8CA7D.4090300@research.att.com> References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> <55C8CA7D.4090300@research.att.com> Message-ID: <55C8CCC2.6050100@home.nl> Op 10-8-2015 om 17:59 schreef Garry Hodgson: > date_parts(Date) -> > [list_to_integer(N) || N <- string:tokens(Date,"-")]. When testing I see this output: 2> dates:date_parts("2012-02-02"). ** exception error: bad argument in function list_to_integer/1 called as list_to_integer(<<"2012">>) in call from dates:'-date_parts/1-lc$^0/1-0-'/1 (dates.erl, line 6) --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From mononcqc@REDACTED Mon Aug 10 18:23:09 2015 From: mononcqc@REDACTED (Fred Hebert) Date: Mon, 10 Aug 2015 12:23:09 -0400 Subject: [erlang-questions] Programmatic interface to the shell In-Reply-To: References: Message-ID: <20150810162308.GC816@fhebert-ltm1> On 08/10, Joe Armstrong wrote: >Hello, > >Is there a *simple* programmatic interface to the Erlang shell? > >I'd like a module "shell_interface" that works like this: > > Pid = shell_interface:new_shell(), > >Returns a new process that behaves like the Erlang shell > > OutStr = shell_interface:eval(Pid, InStr) > Short answer is no. The Erlang shell in the `shell' module asks for information via the IO protocol and pulls it in, rather than you pushing it out. There's ways to inject yourself in there, but it's not simple. >This behaves like the Erlang shell. InStr should be what I typed into the >shell. OutStr should be what the shell replied. > >For this purpose we can assume that InStr represents a complete >sequence of expressions. > This sounds more like an evaluator/interpreter: 1> {ok, Tokens, _} = erl_scan:string("X + 4 * lists:sum([1,2,3,4])."). ... 2> {ok, [Form]} = erl_parse:parse_exprs(Tokens). ... 3> Bindings = erl_eval:add_binding('X', 17, erl_eval:new_bindings()). [{'X',17}] 4> {value, Value, _} = erl_eval:expr(Form, Bindings). {value,57,[{'X',17}]} 5> Value. 57 With these basic forms it becomes doable to write a mini-shell the way you'd like it. Eval = fun EvalLoop(Bindings) -> receive {cmd, Caller, Ref, String} -> try {ok, Tokens, _} = erl_scan:string(String), %% many forms can be comma-separated {ok, Forms} = erl_parse:parse_exprs(Tokens), %% eval individually {value, Val, NewBindings} = erl_eval:exprs(Forms, Bindings), Caller ! {ok, Ref, Val}, EvalLoop(NewBindings) catch T:R -> Caller ! {raise, Ref, T, R}, EvalLoop(Bindings) end end end. Send = fun(Pid, String) -> Ref = erlang:monitor(process, Pid), Pid ! {cmd, self(), Ref, String}, receive {ok, Ref, Value} -> Value; {raise, Ref, T, R} -> erlang:T(R) end end. 18> P = spawn(fun() -> Eval([]) end). <0.62.0> 19> Send(P, "X=2+2."). 4 20> Send(P, "X*X."). 16 21> Send(P, "X/0."). ** exception error: an error occurred when evaluating an arithmetic expression 22> Send(P, "X."). 4 And there you have an evaluator. It doesn't support all the stuff like 'h().' and whatnot, but is close enough otherwise. From garry@REDACTED Mon Aug 10 18:33:55 2015 From: garry@REDACTED (Garry Hodgson) Date: Mon, 10 Aug 2015 12:33:55 -0400 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: <55C8CCC2.6050100@home.nl> References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> <55C8CA7D.4090300@research.att.com> <55C8CCC2.6050100@home.nl> Message-ID: <55C8D273.1080709@research.att.com> right, because re.split() returns a list of binaries ( <<"2012">> ) where string:tokens() returns a list of strings ( "2012" ). so you either need to see if you can convince re:split() to return strings, or you need to coerce its output values from binaries to lists prior to converting those lists to integers. On 8/10/15 12:09 PM, Roelof Wobben wrote: > Op 10-8-2015 om 17:59 schreef Garry Hodgson: >> date_parts(Date) -> >> [list_to_integer(N) || N <- string:tokens(Date,"-")]. > > When testing I see this output: > > 2> dates:date_parts("2012-02-02"). > ** exception error: bad argument in function list_to_integer/1 called > as list_to_integer(<<"2012">>) in call from > dates:'-date_parts/1-lc$^0/1-0-'/1 (dates.erl, line 6) > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast > antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From roger@REDACTED Mon Aug 10 18:36:56 2015 From: roger@REDACTED (Roger Lipscombe) Date: Mon, 10 Aug 2015 17:36:56 +0100 Subject: [erlang-questions] Leader elections and quorum stuff Message-ID: I've got a situation where I have a cluster of nodes. What's the current state of the art for deciding who decides whether a node is down? To rephrase: are there any good algorithms (or Erlang libraries) that decide which subset of nodes should monitor another (all other?) nodes? I don't want every node monitoring every node (or do I?) Also, once they've detected a failure, how to distribute the dead node's work? By work, each node is running a *large* number of different long-lived jobs. If one of the nodes dies, I need to distribute those jobs fairly across the other nodes in the cluster. A single job should not run in more than one place. Assume that every node knows about every other node's assigned work, either through some kind of gossip protocol, or through a shared store. I'm kinda assuming that the monitoring nodes will hold a quick election, so that there's only a single arbiter, but anything that shows how to do that without a single leader would be good too. Thanks, Roger. From erlang@REDACTED Mon Aug 10 19:08:16 2015 From: erlang@REDACTED (Joe Armstrong) Date: Mon, 10 Aug 2015 19:08:16 +0200 Subject: [erlang-questions] Programmatic interface to the shell In-Reply-To: <20150810162308.GC816@fhebert-ltm1> References: <20150810162308.GC816@fhebert-ltm1> Message-ID: Wonderful - thanks The main problem now is that the error messages are not exactly the same as in the shell. ie: The above code for X/0 says > Send(P, "X/0."). ** exception error: an error occurred when evaluating an arithmetic expression But X/0. in the shell says: > X/0. ** exception error: an error occurred when evaluating an arithmetic expression in operator '/'/2 called as 4 / 0 Do you have any idea how to dig out the error message so it's exactly the same? I'm asking because I'm writing a tutorial in a "markdown like" language and I want to automate production of examples :-) Thanks again /Joe On Mon, Aug 10, 2015 at 6:23 PM, Fred Hebert wrote: > On 08/10, Joe Armstrong wrote: >> >> Hello, >> >> Is there a *simple* programmatic interface to the Erlang shell? >> >> I'd like a module "shell_interface" that works like this: >> >> Pid = shell_interface:new_shell(), >> >> Returns a new process that behaves like the Erlang shell >> >> OutStr = shell_interface:eval(Pid, InStr) >> > > Short answer is no. The Erlang shell in the `shell' module asks for > information via the IO protocol and pulls it in, rather than you pushing it > out. > > There's ways to inject yourself in there, but it's not simple. > >> This behaves like the Erlang shell. InStr should be what I typed into the >> shell. OutStr should be what the shell replied. >> >> For this purpose we can assume that InStr represents a complete >> sequence of expressions. >> > > This sounds more like an evaluator/interpreter: > > 1> {ok, Tokens, _} = erl_scan:string("X + 4 * lists:sum([1,2,3,4])."). > ... > 2> {ok, [Form]} = erl_parse:parse_exprs(Tokens). > ... > 3> Bindings = erl_eval:add_binding('X', 17, erl_eval:new_bindings()). > [{'X',17}] > 4> {value, Value, _} = erl_eval:expr(Form, Bindings). > {value,57,[{'X',17}]} > 5> Value. > 57 > > With these basic forms it becomes doable to write a mini-shell the way you'd > like it. > > Eval = fun EvalLoop(Bindings) -> > receive > {cmd, Caller, Ref, String} -> > try > {ok, Tokens, _} = erl_scan:string(String), > %% many forms can be comma-separated > {ok, Forms} = erl_parse:parse_exprs(Tokens), > %% eval individually > {value, Val, NewBindings} = erl_eval:exprs(Forms, > Bindings), > Caller ! {ok, Ref, Val}, > EvalLoop(NewBindings) > catch > T:R -> > Caller ! {raise, Ref, T, R}, > EvalLoop(Bindings) > end > end end. > > Send = fun(Pid, String) -> > Ref = erlang:monitor(process, Pid), > Pid ! {cmd, self(), Ref, String}, > receive > {ok, Ref, Value} -> Value; > {raise, Ref, T, R} -> erlang:T(R) > end end. > > 18> P = spawn(fun() -> Eval([]) end). > <0.62.0> > 19> Send(P, "X=2+2."). > 4 > 20> Send(P, "X*X."). > 16 > 21> Send(P, "X/0."). > ** exception error: an error occurred when evaluating an arithmetic > expression > 22> Send(P, "X."). > 4 > > And there you have an evaluator. It doesn't support all the stuff like > 'h().' and whatnot, but is close enough otherwise. > From mononcqc@REDACTED Mon Aug 10 19:14:39 2015 From: mononcqc@REDACTED (Fred Hebert) Date: Mon, 10 Aug 2015 13:14:39 -0400 Subject: [erlang-questions] Programmatic interface to the shell In-Reply-To: References: <20150810162308.GC816@fhebert-ltm1> Message-ID: <20150810171438.GE816@fhebert-ltm1> On 08/10, Joe Armstrong wrote: >Do you have any idea how to dig out the error message so it's exactly >the same? > >I'm asking because I'm writing a tutorial in a "markdown like" language >and I want to automate production of examples :-) > Probably would need to gather the Erlang stacktrace and raise it there too with erlang:get_stacktrace() and erlang:raise(T,R,Stacktrace) so that the shell evaluators (with lib:format_stacktrace) can handle it right: Eval = fun EvalLoop(Bindings) -> receive {cmd, Caller, Ref, String} -> try {ok, Tokens, _} = erl_scan:string(String), %% many forms can be comma-separated {ok, Forms} = erl_parse:parse_exprs(Tokens), %% eval individually {value, Val, NewBindings} = erl_eval:exprs(Forms, Bindings), Caller ! {ok, Ref, Val}, EvalLoop(NewBindings) catch T:R -> Caller ! {raise, Ref, T, R, erlang:get_stacktrace}, EvalLoop(Bindings) end end end. Send = fun(Pid, String) -> Ref = erlang:monitor(process, Pid), Pid ! {cmd, self(), Ref, String}, receive {ok, Ref, Value} -> Value; {raise, Ref, T, R, S} -> erlang:raise(T,R,S) end end. This should do it. From eric.pailleau@REDACTED Mon Aug 10 19:17:37 2015 From: eric.pailleau@REDACTED (=?ISO-8859-1?Q?=C9ric_Pailleau?=) Date: Mon, 10 Aug 2015 19:17:37 +0200 Subject: [erlang-questions] Programmatic interface to the shell In-Reply-To: Message-ID: <4fd220f8-2bc7-4598-b82c-cd4d0cef3651@email.android.com> Hello Joe, In bottom of this code https://github.com/erlang/otp/blob/maint/lib/observer/src/observer_procinfo.erl Is a simple io server, thanks to Dan Gudmunson. This may help ? Regards Le?10 ao?t 2015 19:08, Joe Armstrong a ?crit?: > > Wonderful - thanks > > The main problem now is that the error messages are not exactly the same > as in the shell. > > ie: The above code for X/0 says > > > Send(P, "X/0."). > ** exception error: an error occurred when evaluating an arithmetic expression > > But X/0. in the shell says: > > > X/0. > ** exception error: an error occurred when evaluating an arithmetic expression > ???? in operator? '/'/2 > ??????? called as 4 / 0 > > Do you have any idea how to dig out the error message so it's exactly the same? > > I'm asking because I'm writing a tutorial in a "markdown like" language > and I want to automate production of examples :-) > > > Thanks again > > /Joe > > > > > > > > On Mon, Aug 10, 2015 at 6:23 PM, Fred Hebert wrote: > > On 08/10, Joe Armstrong wrote: > >> > >> Hello, > >> > >> Is there a *simple* programmatic interface to the Erlang shell? > >> > >> I'd like a module "shell_interface" that works like this: > >> > >>????? Pid = shell_interface:new_shell(), > >> > >> Returns a new process that behaves like the Erlang shell > >> > >>????? OutStr = shell_interface:eval(Pid, InStr) > >> > > > > Short answer is no. The Erlang shell in the `shell' module asks for > > information via the IO protocol and pulls it in, rather than you pushing it > > out. > > > > There's ways to inject yourself in there, but it's not simple. > > > >> This behaves like the Erlang shell. InStr should be what I typed into the > >> shell. OutStr should be what the shell replied. > >> > >> For this purpose we can assume that InStr represents a complete > >> sequence of expressions. > >> > > > > This sounds more like an evaluator/interpreter: > > > >??? 1> {ok, Tokens, _} = erl_scan:string("X + 4 * lists:sum([1,2,3,4])."). > >??? ... > >??? 2> {ok, [Form]} = erl_parse:parse_exprs(Tokens). > >??? ... > >??? 3> Bindings = erl_eval:add_binding('X', 17, erl_eval:new_bindings()). > >??? [{'X',17}] > >??? 4> {value, Value, _} = erl_eval:expr(Form, Bindings). > >??? {value,57,[{'X',17}]} > >??? 5> Value. > >??? 57 > > > > With these basic forms it becomes doable to write a mini-shell the way you'd > > like it. > > > >??? Eval = fun EvalLoop(Bindings) -> > >??????? receive > >??????????? {cmd, Caller, Ref, String} -> > >??????????????? try > >??????????????????? {ok, Tokens, _} = erl_scan:string(String), > >??????????????????? %% many forms can be comma-separated > >??????????????????? {ok, Forms} = erl_parse:parse_exprs(Tokens), > >??????????????????? %% eval individually > >??????????????????? {value, Val, NewBindings} = erl_eval:exprs(Forms, > > Bindings), > >??????????????????? Caller ! {ok, Ref, Val}, > >??????????????????? EvalLoop(NewBindings) > >??????????????? catch > >??????????????????? T:R -> > >??????????????????????? Caller ! {raise, Ref, T, R}, > >??????????????????????? EvalLoop(Bindings) > >??????????????? end > >??????? end end. > > > >??? Send = fun(Pid, String) -> > >??????? Ref = erlang:monitor(process, Pid), > >??????? Pid ! {cmd, self(), Ref, String}, > >??????? receive > >??????????? {ok, Ref, Value} -> Value; > >??????????? {raise, Ref, T, R} -> erlang:T(R) > >??????? end end. > > > >??? 18> P = spawn(fun() -> Eval([]) end). > >??? <0.62.0> > >??? 19> Send(P, "X=2+2."). > >??? 4 > >??? 20> Send(P, "X*X."). > >??? 16 > >??? 21> Send(P, "X/0."). > >??? ** exception error: an error occurred when evaluating an arithmetic > > expression > >??? 22> Send(P, "X."). > >??? 4 > > > > And there? you have an evaluator. It doesn't support all the stuff like > > 'h().' and whatnot, but is close enough otherwise. > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From g@REDACTED Mon Aug 10 19:25:56 2015 From: g@REDACTED (Garrett Smith) Date: Mon, 10 Aug 2015 12:25:56 -0500 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: <55C8D273.1080709@research.att.com> References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> <55C8CA7D.4090300@research.att.com> <55C8CCC2.6050100@home.nl> <55C8D273.1080709@research.att.com> Message-ID: Personally I find the Erlang docs excellent, so this: http://erlang.org/doc/man/re.html#split-2 Roelof, I recommend that you spend some cycles reading these as a matter of course when you're using a function. The docs will help you get things right and you'll start to absorb some Erlang zen. The list is great to help after you've done that and still have questions. This link provides an index, which might also be helpful for finding the right module and function in the first place: http://erldocs.com On Mon, Aug 10, 2015 at 11:33 AM, Garry Hodgson wrote: > right, because re.split() returns a list of binaries ( <<"2012">> ) > where string:tokens() returns a list of strings ( "2012" ). > > so you either need to see if you can convince re:split() to > return strings, or you need to coerce its output values > from binaries to lists prior to converting those lists to integers. > > > > On 8/10/15 12:09 PM, Roelof Wobben wrote: >> >> Op 10-8-2015 om 17:59 schreef Garry Hodgson: >>> >>> date_parts(Date) -> >>> [list_to_integer(N) || N <- string:tokens(Date,"-")]. >> >> >> When testing I see this output: >> >> 2> dates:date_parts("2012-02-02"). >> ** exception error: bad argument in function list_to_integer/1 called as >> list_to_integer(<<"2012">>) in call from dates:'-date_parts/1-lc$^0/1-0-'/1 >> (dates.erl, line 6) >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast >> antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From sergej.jurecko@REDACTED Mon Aug 10 19:29:21 2015 From: sergej.jurecko@REDACTED (Sergej =?UTF-8?B?SnVyZcSNa28=?=) Date: Mon, 10 Aug 2015 19:29:21 +0200 Subject: [erlang-questions] Leader elections and quorum stuff In-Reply-To: References: Message-ID: Where is the persistent state? If a node goes down, where do new nodes get their data from so they can continue the work? Is there an outside DB or is data persistence a part of this system? Sergej On 10/08/15 18:36, "Roger Lipscombe" wrote: >I've got a situation where I have a cluster of nodes. > >What's the current state of the art for deciding who decides whether a >node is down? To rephrase: are there any good algorithms (or Erlang >libraries) that decide which subset of nodes should monitor another >(all other?) nodes? I don't want every node monitoring every node (or >do I?) > >Also, once they've detected a failure, how to distribute the dead node's work? > >By work, each node is running a *large* number of different long-lived >jobs. If one of the nodes dies, I need to distribute those jobs fairly >across the other nodes in the cluster. A single job should not run in >more than one place. > >Assume that every node knows about every other node's assigned work, >either through some kind of gossip protocol, or through a shared >store. > >I'm kinda assuming that the monitoring nodes will hold a quick >election, so that there's only a single arbiter, but anything that >shows how to do that without a single leader would be good too. > >Thanks, >Roger. >_______________________________________________ >erlang-questions mailing list >erlang-questions@REDACTED >http://erlang.org/mailman/listinfo/erlang-questions From felixgallo@REDACTED Mon Aug 10 19:29:34 2015 From: felixgallo@REDACTED (Felix Gallo) Date: Mon, 10 Aug 2015 10:29:34 -0700 Subject: [erlang-questions] Leader elections and quorum stuff In-Reply-To: References: Message-ID: The current state of the art for deciding who decides whether a node is down depends on what you mean by 'decides', 'is', and 'down'. It turns out to be quite difficult to determine that a node is down; for example, an issue with networking could cause a node to appear down to some other nodes, but not others. Is the node down? Who can say. One way of dealing with the problem is to centralize the work distribution, and have slave workers check out jobs and check in results. Any worker that doesn't check in within a particular timeout period is assumed to have died, and the work is returned to the queue. Any worker that 'recovers' and tries to check in its overdue work is ignored. This is obviously a single point of failure and doesn't scale further than your single master machine can handle work. That said, it probably works for 95% of job distribution problems in the real world. Beyond that, you get into the world of needing leader election and quorums. Basho has done a great deal of work in this area -- see, e.g. riak_ensemble. Another approach might be to use, eg., zookeeper or etcd as work queues. It's a very complicated area, but if you need it, you need it. Pragmatically I'd recommend going with the single master unless you can't have unavailability until operator intervention when the master crashes. It's conceptually and operationally easier to deal with, unless you truly are near that scaling wall. On Mon, Aug 10, 2015 at 9:36 AM, Roger Lipscombe wrote: > I've got a situation where I have a cluster of nodes. > > What's the current state of the art for deciding who decides whether a > node is down? To rephrase: are there any good algorithms (or Erlang > libraries) that decide which subset of nodes should monitor another > (all other?) nodes? I don't want every node monitoring every node (or > do I?) > > Also, once they've detected a failure, how to distribute the dead node's > work? > > By work, each node is running a *large* number of different long-lived > jobs. If one of the nodes dies, I need to distribute those jobs fairly > across the other nodes in the cluster. A single job should not run in > more than one place. > > Assume that every node knows about every other node's assigned work, > either through some kind of gossip protocol, or through a shared > store. > > I'm kinda assuming that the monitoring nodes will hold a quick > election, so that there's only a single arbiter, but anything that > shows how to do that without a single leader would be good too. > > Thanks, > Roger. > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From erlang@REDACTED Mon Aug 10 20:11:00 2015 From: erlang@REDACTED (Joe Armstrong) Date: Mon, 10 Aug 2015 20:11:00 +0200 Subject: [erlang-questions] Programmatic interface to the shell In-Reply-To: <20150810171438.GE816@fhebert-ltm1> References: <20150810162308.GC816@fhebert-ltm1> <20150810171438.GE816@fhebert-ltm1> Message-ID: On Mon, Aug 10, 2015 at 7:14 PM, Fred Hebert wrote: > On 08/10, Joe Armstrong wrote: >> >> Do you have any idea how to dig out the error message so it's exactly the >> same? >> >> I'm asking because I'm writing a tutorial in a "markdown like" language >> and I want to automate production of examples :-) >> > > Probably would need to gather the Erlang stacktrace and raise it there too > with erlang:get_stacktrace() and erlang:raise(T,R,Stacktrace) so that the > shell evaluators (with lib:format_stacktrace) can handle it right: > > Eval = fun EvalLoop(Bindings) -> > receive > {cmd, Caller, Ref, String} -> > try > {ok, Tokens, _} = erl_scan:string(String), > %% many forms can be comma-separated > {ok, Forms} = erl_parse:parse_exprs(Tokens), > %% eval individually > {value, Val, NewBindings} = erl_eval:exprs(Forms, > Bindings), > Caller ! {ok, Ref, Val}, > EvalLoop(NewBindings) > catch > T:R -> > Caller ! {raise, Ref, T, R, erlang:get_stacktrace}, > EvalLoop(Bindings) > end > end end. > > Send = fun(Pid, String) -> > Ref = erlang:monitor(process, Pid), > Pid ! {cmd, self(), Ref, String}, > receive > {ok, Ref, Value} -> Value; > {raise, Ref, T, R, S} -> erlang:raise(T,R,S) > end end. > > This should do it. erlang:raise seems to print a string (as a side effect) and then kill the process. This is not really what I want. I also found that the code you posted above behaves differently when compiled and when run in the shell. So some code takes the exception and turns it into a string which the shell prints - I've no idea where this happens - investigation proceeds ... /Joe From erlang@REDACTED Mon Aug 10 20:13:02 2015 From: erlang@REDACTED (Joe Armstrong) Date: Mon, 10 Aug 2015 20:13:02 +0200 Subject: [erlang-questions] Programmatic interface to the shell In-Reply-To: <4fd220f8-2bc7-4598-b82c-cd4d0cef3651@email.android.com> References: <4fd220f8-2bc7-4598-b82c-cd4d0cef3651@email.android.com> Message-ID: On Mon, Aug 10, 2015 at 7:17 PM, ?ric Pailleau wrote: > Hello Joe, > > In bottom of this code > > https://github.com/erlang/otp/blob/maint/lib/observer/src/observer_procinfo.erl > > Is a simple io server, thanks to Dan Gudmunson. > This may help ? I'm not sure how? /Joe > Regards > > > Le 10 ao?t 2015 19:08, Joe Armstrong a ?crit : >> >> Wonderful - thanks >> >> The main problem now is that the error messages are not exactly the same >> as in the shell. >> >> ie: The above code for X/0 says >> >> > Send(P, "X/0."). >> ** exception error: an error occurred when evaluating an arithmetic expression >> >> But X/0. in the shell says: >> >> > X/0. >> ** exception error: an error occurred when evaluating an arithmetic expression >> in operator '/'/2 >> called as 4 / 0 >> >> Do you have any idea how to dig out the error message so it's exactly the same? >> >> I'm asking because I'm writing a tutorial in a "markdown like" language >> and I want to automate production of examples :-) >> >> >> Thanks again >> >> /Joe >> >> >> >> >> >> >> >> On Mon, Aug 10, 2015 at 6:23 PM, Fred Hebert wrote: >> > On 08/10, Joe Armstrong wrote: >> >> >> >> Hello, >> >> >> >> Is there a *simple* programmatic interface to the Erlang shell? >> >> >> >> I'd like a module "shell_interface" that works like this: >> >> >> >> Pid = shell_interface:new_shell(), >> >> >> >> Returns a new process that behaves like the Erlang shell >> >> >> >> OutStr = shell_interface:eval(Pid, InStr) >> >> >> > >> > Short answer is no. The Erlang shell in the `shell' module asks for >> > information via the IO protocol and pulls it in, rather than you pushing it >> > out. >> > >> > There's ways to inject yourself in there, but it's not simple. >> > >> >> This behaves like the Erlang shell. InStr should be what I typed into the >> >> shell. OutStr should be what the shell replied. >> >> >> >> For this purpose we can assume that InStr represents a complete >> >> sequence of expressions. >> >> >> > >> > This sounds more like an evaluator/interpreter: >> > >> > 1> {ok, Tokens, _} = erl_scan:string("X + 4 * lists:sum([1,2,3,4])."). >> > ... >> > 2> {ok, [Form]} = erl_parse:parse_exprs(Tokens). >> > ... >> > 3> Bindings = erl_eval:add_binding('X', 17, erl_eval:new_bindings()). >> > [{'X',17}] >> > 4> {value, Value, _} = erl_eval:expr(Form, Bindings). >> > {value,57,[{'X',17}]} >> > 5> Value. >> > 57 >> > >> > With these basic forms it becomes doable to write a mini-shell the way you'd >> > like it. >> > >> > Eval = fun EvalLoop(Bindings) -> >> > receive >> > {cmd, Caller, Ref, String} -> >> > try >> > {ok, Tokens, _} = erl_scan:string(String), >> > %% many forms can be comma-separated >> > {ok, Forms} = erl_parse:parse_exprs(Tokens), >> > %% eval individually >> > {value, Val, NewBindings} = erl_eval:exprs(Forms, >> > Bindings), >> > Caller ! {ok, Ref, Val}, >> > EvalLoop(NewBindings) >> > catch >> > T:R -> >> > Caller ! {raise, Ref, T, R}, >> > EvalLoop(Bindings) >> > end >> > end end. >> > >> > Send = fun(Pid, String) -> >> > Ref = erlang:monitor(process, Pid), >> > Pid ! {cmd, self(), Ref, String}, >> > receive >> > {ok, Ref, Value} -> Value; >> > {raise, Ref, T, R} -> erlang:T(R) >> > end end. >> > >> > 18> P = spawn(fun() -> Eval([]) end). >> > <0.62.0> >> > 19> Send(P, "X=2+2."). >> > 4 >> > 20> Send(P, "X*X."). >> > 16 >> > 21> Send(P, "X/0."). >> > ** exception error: an error occurred when evaluating an arithmetic >> > expression >> > 22> Send(P, "X."). >> > 4 >> > >> > And there you have an evaluator. It doesn't support all the stuff like >> > 'h().' and whatnot, but is close enough otherwise. >> > >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions From eric.pailleau@REDACTED Mon Aug 10 20:27:17 2015 From: eric.pailleau@REDACTED (=?ISO-8859-1?Q?=C9ric_Pailleau?=) Date: Mon, 10 Aug 2015 20:27:17 +0200 Subject: [erlang-questions] Programmatic interface to the shell In-Reply-To: Message-ID: Hi, This allows to "write" in a Pid but without underlying file. This simulate a shell in the way you can send incomplete Erlang statements until a dot is detected. Then the complete statement can be evaluated and result sent back to the caller. (note the example gives only the io server layer). Le?10 ao?t 2015 20:13, Joe Armstrong a ?crit?: > > On Mon, Aug 10, 2015 at 7:17 PM, ?ric Pailleau wrote: > > Hello Joe, > > > > In bottom of this code > > > > https://github.com/erlang/otp/blob/maint/lib/observer/src/observer_procinfo.erl > > > > Is a simple io server, thanks to Dan Gudmunson. > > This may help ? > > I'm not sure how? > > /Joe > > > Regards > > > > > > Le 10 ao?t 2015 19:08, Joe Armstrong a ?crit : > >> > >> Wonderful - thanks > >> > >> The main problem now is that the error messages are not exactly the same > >> as in the shell. > >> > >> ie: The above code for X/0 says > >> > >> > Send(P, "X/0."). > >> ** exception error: an error occurred when evaluating an arithmetic expression > >> > >> But X/0. in the shell says: > >> > >> > X/0. > >> ** exception error: an error occurred when evaluating an arithmetic expression > >>????? in operator? '/'/2 > >>???????? called as 4 / 0 > >> > >> Do you have any idea how to dig out the error message so it's exactly the same? > >> > >> I'm asking because I'm writing a tutorial in a "markdown like" language > >> and I want to automate production of examples :-) > >> > >> > >> Thanks again > >> > >> /Joe > >> > >> > >> > >> > >> > >> > >> > >> On Mon, Aug 10, 2015 at 6:23 PM, Fred Hebert wrote: > >> > On 08/10, Joe Armstrong wrote: > >> >> > >> >> Hello, > >> >> > >> >> Is there a *simple* programmatic interface to the Erlang shell? > >> >> > >> >> I'd like a module "shell_interface" that works like this: > >> >> > >> >>????? Pid = shell_interface:new_shell(), > >> >> > >> >> Returns a new process that behaves like the Erlang shell > >> >> > >> >>????? OutStr = shell_interface:eval(Pid, InStr) > >> >> > >> > > >> > Short answer is no. The Erlang shell in the `shell' module asks for > >> > information via the IO protocol and pulls it in, rather than you pushing it > >> > out. > >> > > >> > There's ways to inject yourself in there, but it's not simple. > >> > > >> >> This behaves like the Erlang shell. InStr should be what I typed into the > >> >> shell. OutStr should be what the shell replied. > >> >> > >> >> For this purpose we can assume that InStr represents a complete > >> >> sequence of expressions. > >> >> > >> > > >> > This sounds more like an evaluator/interpreter: > >> > > >> >??? 1> {ok, Tokens, _} = erl_scan:string("X + 4 * lists:sum([1,2,3,4])."). > >> >??? ... > >> >??? 2> {ok, [Form]} = erl_parse:parse_exprs(Tokens). > >> >??? ... > >> >??? 3> Bindings = erl_eval:add_binding('X', 17, erl_eval:new_bindings()). > >> >??? [{'X',17}] > >> >??? 4> {value, Value, _} = erl_eval:expr(Form, Bindings). > >> >??? {value,57,[{'X',17}]} > >> >??? 5> Value. > >> >??? 57 > >> > > >> > With these basic forms it becomes doable to write a mini-shell the way you'd > >> > like it. > >> > > >> >??? Eval = fun EvalLoop(Bindings) -> > >> >??????? receive > >> >??????????? {cmd, Caller, Ref, String} -> > >> >??????????????? try > >> >??????????????????? {ok, Tokens, _} = erl_scan:string(String), > >> >??????????????????? %% many forms can be comma-separated > >> >??????????????????? {ok, Forms} = erl_parse:parse_exprs(Tokens), > >> >??????????????????? %% eval individually > >> >??????????????????? {value, Val, NewBindings} = erl_eval:exprs(Forms, > >> > Bindings), > >> >??????????????????? Caller ! {ok, Ref, Val}, > >> >??????????????????? EvalLoop(NewBindings) > >> >??????????????? catch > >> >??????????????????? T:R -> > >> >??????????????????????? Caller ! {raise, Ref, T, R}, > >> >??????????????????????? EvalLoop(Bindings) > >> >??????????????? end > >> >??????? end end. > >> > > >> >??? Send = fun(Pid, String) -> > >> >??????? Ref = erlang:monitor(process, Pid), > >> >??????? Pid ! {cmd, self(), Ref, String}, > >> >??????? receive > >> >??????????? {ok, Ref, Value} -> Value; > >> >??????????? {raise, Ref, T, R} -> erlang:T(R) > >> >??????? end end. > >> > > >> >??? 18> P = spawn(fun() -> Eval([]) end). > >> >??? <0.62.0> > >> >??? 19> Send(P, "X=2+2."). > >> >??? 4 > >> >??? 20> Send(P, "X*X."). > >> >??? 16 > >> >??? 21> Send(P, "X/0."). > >> >??? ** exception error: an error occurred when evaluating an arithmetic > >> > expression > >> >??? 22> Send(P, "X."). > >> >??? 4 > >> > > >> > And there? you have an evaluator. It doesn't support all the stuff like > >> > 'h().' and whatnot, but is close enough otherwise. > >> > > >> _______________________________________________ > >> erlang-questions mailing list > >> erlang-questions@REDACTED > >> http://erlang.org/mailman/listinfo/erlang-questions From erlang@REDACTED Mon Aug 10 20:29:45 2015 From: erlang@REDACTED (Joe Armstrong) Date: Mon, 10 Aug 2015 20:29:45 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: <55C8CCC2.6050100@home.nl> References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> <55C8CA7D.4090300@research.att.com> <55C8CCC2.6050100@home.nl> Message-ID: On Mon, Aug 10, 2015 at 6:09 PM, Roelof Wobben wrote: > Op 10-8-2015 om 17:59 schreef Garry Hodgson: >> >> date_parts(Date) -> >> [list_to_integer(N) || N <- string:tokens(Date,"-")]. > > > When testing I see this output: > > 2> dates:date_parts("2012-02-02"). > ** exception error: bad argument in function list_to_integer/1 called as > list_to_integer(<<"2012">>) in call from dates:'-date_parts/1-lc$^0/1-0-'/1 > (dates.erl, line 6) If you're a beginner it might be helpful to not combine function calls but to write the code with intermediate variables like this: date_parts(Date) -> L = string:tokens(Date,"-"), [list_to_integer(I) || I <- L]. That way you can add print statements to see what's going on like this: date_parts(Date) -> L = string:tokens(Date,"-"), io:format("L=~p~n",[L]), [list_to_integer(I) || I <- L]. As you become more experienced you'll omit the temporary variables because you'll *know* what they should be. But when you're beginning make each line of code do as little as possible and print the results to check your understanding. Poke each line into the shell to see what's happening. /Joe > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From r.wobben@REDACTED Mon Aug 10 20:34:23 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 10 Aug 2015 20:34:23 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> <55C8CA7D.4090300@research.att.com> <55C8CCC2.6050100@home.nl> Message-ID: <55C8EEAF.3000908@home.nl> Thanks for the tip. Op 10-8-2015 om 20:29 schreef Joe Armstrong: > On Mon, Aug 10, 2015 at 6:09 PM, Roelof Wobben wrote: >> Op 10-8-2015 om 17:59 schreef Garry Hodgson: >>> date_parts(Date) -> >>> [list_to_integer(N) || N <- string:tokens(Date,"-")]. >> >> When testing I see this output: >> >> 2> dates:date_parts("2012-02-02"). >> ** exception error: bad argument in function list_to_integer/1 called as >> list_to_integer(<<"2012">>) in call from dates:'-date_parts/1-lc$^0/1-0-'/1 >> (dates.erl, line 6) > If you're a beginner it might be helpful to not combine function calls > but to write the code with intermediate variables like this: > > date_parts(Date) -> > L = string:tokens(Date,"-"), > [list_to_integer(I) || I <- L]. > > That way you can add print statements to see what's going on > like this: > > date_parts(Date) -> > L = string:tokens(Date,"-"), > io:format("L=~p~n",[L]), > [list_to_integer(I) || I <- L]. > > As you become more experienced you'll omit the temporary variables > because you'll *know* what they should be. But when you're beginning > make each line of code do as little as possible and print the results to > check your understanding. > > Poke each line into the shell to see what's happening. > > /Joe > > >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From erlang@REDACTED Mon Aug 10 20:38:33 2015 From: erlang@REDACTED (Joe Armstrong) Date: Mon, 10 Aug 2015 20:38:33 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> <55C8CA7D.4090300@research.att.com> <55C8CCC2.6050100@home.nl> <55C8D273.1080709@research.att.com> Message-ID: On Mon, Aug 10, 2015 at 7:25 PM, Garrett Smith wrote: > Personally I find the Erlang docs excellent, so this: > > http://erlang.org/doc/man/re.html#split-2 > > Roelof, I recommend that you spend some cycles reading these as a > matter of course when you're using a function. The docs will help you > get things right and you'll start to absorb some Erlang zen. The list > is great to help after you've done that and still have questions. My goodness reading the manual first. I thought this was the only done when evoking the "if all else fails read the friendly manual bit" I usually poke around in the shell first. Not having a clue how re:split worked I guessed and tried this: > re:split("2015-08-06","-"). [<<"2015">>,<<"08">>,<<"06">>] One wild guess later (and some distant memory) I tried > re:split("2015-08-06","-"),[{return,list}]. ["2015","08","06"] Life is too short to waste it reading manual pages - or is it the other way around - life is too short to waste it by not reading manual pages - I can'tmake my mind up Cheers /Joe > > This link provides an index, which might also be helpful for finding > the right module and function in the first place: > > http://erldocs.com > > On Mon, Aug 10, 2015 at 11:33 AM, Garry Hodgson wrote: >> right, because re.split() returns a list of binaries ( <<"2012">> ) >> where string:tokens() returns a list of strings ( "2012" ). >> >> so you either need to see if you can convince re:split() to >> return strings, or you need to coerce its output values >> from binaries to lists prior to converting those lists to integers. >> >> >> >> On 8/10/15 12:09 PM, Roelof Wobben wrote: >>> >>> Op 10-8-2015 om 17:59 schreef Garry Hodgson: >>>> >>>> date_parts(Date) -> >>>> [list_to_integer(N) || N <- string:tokens(Date,"-")]. >>> >>> >>> When testing I see this output: >>> >>> 2> dates:date_parts("2012-02-02"). >>> ** exception error: bad argument in function list_to_integer/1 called as >>> list_to_integer(<<"2012">>) in call from dates:'-date_parts/1-lc$^0/1-0-'/1 >>> (dates.erl, line 6) >>> >>> --- >>> Dit e-mailbericht is gecontroleerd op virussen met Avast >>> antivirussoftware. >>> https://www.avast.com/antivirus >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From felixgallo@REDACTED Mon Aug 10 20:46:26 2015 From: felixgallo@REDACTED (Felix Gallo) Date: Mon, 10 Aug 2015 11:46:26 -0700 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> <55C8CA7D.4090300@research.att.com> <55C8CCC2.6050100@home.nl> <55C8D273.1080709@research.att.com> Message-ID: as the official e-mail list correction pedant this week: > re:split("2015-08-06","-"),[{return,list}]. doesn't return ["2015","08","06"]. > re:split("2015-08-06","-",[{return,list}]). is what Joe likely meant. F. On Mon, Aug 10, 2015 at 11:38 AM, Joe Armstrong wrote: > On Mon, Aug 10, 2015 at 7:25 PM, Garrett Smith wrote: > > Personally I find the Erlang docs excellent, so this: > > > > http://erlang.org/doc/man/re.html#split-2 > > > > Roelof, I recommend that you spend some cycles reading these as a > > matter of course when you're using a function. The docs will help you > > get things right and you'll start to absorb some Erlang zen. The list > > is great to help after you've done that and still have questions. > > My goodness reading the manual first. I thought this was the > only done when evoking the "if all else fails read the friendly manual bit" > > I usually poke around in the shell first. > Not having a clue how re:split worked I guessed and tried this: > > > re:split("2015-08-06","-"). > [<<"2015">>,<<"08">>,<<"06">>] > > One wild guess later (and some distant memory) I tried > > > re:split("2015-08-06","-"),[{return,list}]. > ["2015","08","06"] > > Life is too short to waste it reading manual pages - or is it the other way > around - life is too short to waste it by not reading manual pages - I > can'tmake my mind up > > Cheers > > /Joe > > > > > > > > This link provides an index, which might also be helpful for finding > > the right module and function in the first place: > > > > http://erldocs.com > > > > On Mon, Aug 10, 2015 at 11:33 AM, Garry Hodgson > wrote: > >> right, because re.split() returns a list of binaries ( <<"2012">> ) > >> where string:tokens() returns a list of strings ( "2012" ). > >> > >> so you either need to see if you can convince re:split() to > >> return strings, or you need to coerce its output values > >> from binaries to lists prior to converting those lists to integers. > >> > >> > >> > >> On 8/10/15 12:09 PM, Roelof Wobben wrote: > >>> > >>> Op 10-8-2015 om 17:59 schreef Garry Hodgson: > >>>> > >>>> date_parts(Date) -> > >>>> [list_to_integer(N) || N <- string:tokens(Date,"-")]. > >>> > >>> > >>> When testing I see this output: > >>> > >>> 2> dates:date_parts("2012-02-02"). > >>> ** exception error: bad argument in function list_to_integer/1 called > as > >>> list_to_integer(<<"2012">>) in call from > dates:'-date_parts/1-lc$^0/1-0-'/1 > >>> (dates.erl, line 6) > >>> > >>> --- > >>> Dit e-mailbericht is gecontroleerd op virussen met Avast > >>> antivirussoftware. > >>> https://www.avast.com/antivirus > >>> > >>> _______________________________________________ > >>> erlang-questions mailing list > >>> erlang-questions@REDACTED > >>> http://erlang.org/mailman/listinfo/erlang-questions > >> > >> > >> _______________________________________________ > >> erlang-questions mailing list > >> erlang-questions@REDACTED > >> http://erlang.org/mailman/listinfo/erlang-questions > > _______________________________________________ > > erlang-questions mailing list > > erlang-questions@REDACTED > > http://erlang.org/mailman/listinfo/erlang-questions > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From erlang@REDACTED Mon Aug 10 20:46:46 2015 From: erlang@REDACTED (Joe Armstrong) Date: Mon, 10 Aug 2015 20:46:46 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: <55C8EEAF.3000908@home.nl> References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> <55C8CA7D.4090300@research.att.com> <55C8CCC2.6050100@home.nl> <55C8EEAF.3000908@home.nl> Message-ID: On Mon, Aug 10, 2015 at 8:34 PM, Roelof Wobben wrote: > Thanks for the tip. My pleasure. Another tip. When I'm writing functions I often just write a function clause that I know will crash. For example date_parts(Date) -> L = string:tokens(Date,"-"), [my_to_int(I) || I <- L]. my_to_int(a) -> 1. Then I run this and it will crash. But the shell will print the argument that my_to_int was called with. Then I cut and paste this into the function head. Often I'm not 100% sure what arguments a function will be called with, so I just put dummy arguments a,b,c etc. that will cause the program to crash. Then I run test cases and fix the crashing cases - so the order in which the code is developed depends upon how it is crashing. Its a run->crash->fix cycle. It's almost like TDD I'd call it CDD (Crash Driven Development) Cheers /Joe > > Op 10-8-2015 om 20:29 schreef Joe Armstrong: > >> On Mon, Aug 10, 2015 at 6:09 PM, Roelof Wobben wrote: >>> >>> Op 10-8-2015 om 17:59 schreef Garry Hodgson: >>>> >>>> date_parts(Date) -> >>>> [list_to_integer(N) || N <- string:tokens(Date,"-")]. >>> >>> >>> When testing I see this output: >>> >>> 2> dates:date_parts("2012-02-02"). >>> ** exception error: bad argument in function list_to_integer/1 called >>> as >>> list_to_integer(<<"2012">>) in call from >>> dates:'-date_parts/1-lc$^0/1-0-'/1 >>> (dates.erl, line 6) >> >> If you're a beginner it might be helpful to not combine function calls >> but to write the code with intermediate variables like this: >> >> date_parts(Date) -> >> L = string:tokens(Date,"-"), >> [list_to_integer(I) || I <- L]. >> >> That way you can add print statements to see what's going on >> like this: >> >> date_parts(Date) -> >> L = string:tokens(Date,"-"), >> io:format("L=~p~n",[L]), >> [list_to_integer(I) || I <- L]. >> >> As you become more experienced you'll omit the temporary variables >> because you'll *know* what they should be. But when you're beginning >> make each line of code do as little as possible and print the results to >> check your understanding. >> >> Poke each line into the shell to see what's happening. >> >> /Joe >> >> >>> >>> --- >>> Dit e-mailbericht is gecontroleerd op virussen met Avast >>> antivirussoftware. >>> https://www.avast.com/antivirus >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions > > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From erlang@REDACTED Mon Aug 10 20:48:07 2015 From: erlang@REDACTED (Joe Armstrong) Date: Mon, 10 Aug 2015 20:48:07 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> <55C8CA7D.4090300@research.att.com> <55C8CCC2.6050100@home.nl> <55C8D273.1080709@research.att.com> Message-ID: On Mon, Aug 10, 2015 at 8:46 PM, Felix Gallo wrote: > as the official e-mail list correction pedant this week: > >> re:split("2015-08-06","-"),[{return,list}]. > > doesn't return ["2015","08","06"]. > >> re:split("2015-08-06","-",[{return,list}]). > > is what Joe likely meant. Indeed - well spotted Sir - hat's off /Joe > > F. > > On Mon, Aug 10, 2015 at 11:38 AM, Joe Armstrong wrote: >> >> On Mon, Aug 10, 2015 at 7:25 PM, Garrett Smith wrote: >> > Personally I find the Erlang docs excellent, so this: >> > >> > http://erlang.org/doc/man/re.html#split-2 >> > >> > Roelof, I recommend that you spend some cycles reading these as a >> > matter of course when you're using a function. The docs will help you >> > get things right and you'll start to absorb some Erlang zen. The list >> > is great to help after you've done that and still have questions. >> >> My goodness reading the manual first. I thought this was the >> only done when evoking the "if all else fails read the friendly manual >> bit" >> >> I usually poke around in the shell first. >> Not having a clue how re:split worked I guessed and tried this: >> >> > re:split("2015-08-06","-"). >> [<<"2015">>,<<"08">>,<<"06">>] >> >> One wild guess later (and some distant memory) I tried >> >> > re:split("2015-08-06","-"),[{return,list}]. >> ["2015","08","06"] >> >> Life is too short to waste it reading manual pages - or is it the other >> way >> around - life is too short to waste it by not reading manual pages - I >> can'tmake my mind up >> >> Cheers >> >> /Joe >> >> >> >> >> > >> > This link provides an index, which might also be helpful for finding >> > the right module and function in the first place: >> > >> > http://erldocs.com >> > >> > On Mon, Aug 10, 2015 at 11:33 AM, Garry Hodgson >> > wrote: >> >> right, because re.split() returns a list of binaries ( <<"2012">> ) >> >> where string:tokens() returns a list of strings ( "2012" ). >> >> >> >> so you either need to see if you can convince re:split() to >> >> return strings, or you need to coerce its output values >> >> from binaries to lists prior to converting those lists to integers. >> >> >> >> >> >> >> >> On 8/10/15 12:09 PM, Roelof Wobben wrote: >> >>> >> >>> Op 10-8-2015 om 17:59 schreef Garry Hodgson: >> >>>> >> >>>> date_parts(Date) -> >> >>>> [list_to_integer(N) || N <- string:tokens(Date,"-")]. >> >>> >> >>> >> >>> When testing I see this output: >> >>> >> >>> 2> dates:date_parts("2012-02-02"). >> >>> ** exception error: bad argument in function list_to_integer/1 called >> >>> as >> >>> list_to_integer(<<"2012">>) in call from >> >>> dates:'-date_parts/1-lc$^0/1-0-'/1 >> >>> (dates.erl, line 6) >> >>> >> >>> --- >> >>> Dit e-mailbericht is gecontroleerd op virussen met Avast >> >>> antivirussoftware. >> >>> https://www.avast.com/antivirus >> >>> >> >>> _______________________________________________ >> >>> erlang-questions mailing list >> >>> erlang-questions@REDACTED >> >>> http://erlang.org/mailman/listinfo/erlang-questions >> >> >> >> >> >> _______________________________________________ >> >> erlang-questions mailing list >> >> erlang-questions@REDACTED >> >> http://erlang.org/mailman/listinfo/erlang-questions >> > _______________________________________________ >> > erlang-questions mailing list >> > erlang-questions@REDACTED >> > http://erlang.org/mailman/listinfo/erlang-questions >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > From erlang@REDACTED Mon Aug 10 20:50:17 2015 From: erlang@REDACTED (Joe Armstrong) Date: Mon, 10 Aug 2015 20:50:17 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: <55C8C75C.2070301@home.nl> References: <55C8C75C.2070301@home.nl> Message-ID: On Mon, Aug 10, 2015 at 5:46 PM, Roelof Wobben wrote: > Hello, > > I have to make a programm which convert the iso-date to a list of numbers so > 2015-08-10 will be [2015,08,10] Impossible - there is no data structure in Erlang whose print value is [2015,08,10] - Here a shell example: $erl Eshell V6.2 (abort with ^G) 1> [2015,08,10]. [2015,8,10] 2> [2015,000000000000008,10]. [2015,8,10] The problem the leading zeros in the 08 - if you enter 0000000000008 the shell will print 8. So the output can be [2015,8,10] but never [2015,08,10] /Joe > > As a working programm I have wrote this : > > -module(dates). > > -export([date_parts/1]). > > date_parts(Date)-> > [Year, Month, Day] = re:split(Date, "-", [{return, list}] ), > [element(1, string:to_integer(Year)), > element(1,string:to_integer(Month)), element(1,string:to_integer(Day))]. > > Now my question is how to make this code beautifull. > > I think myself to make seperate functions for extracting the numbers out of > the list and one for converting the string to numbers. > > Roelof > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From g@REDACTED Mon Aug 10 21:15:16 2015 From: g@REDACTED (Garrett Smith) Date: Mon, 10 Aug 2015 14:15:16 -0500 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> <55C8CA7D.4090300@research.att.com> <55C8CCC2.6050100@home.nl> <55C8D273.1080709@research.att.com> Message-ID: On Mon, Aug 10, 2015 at 1:38 PM, Joe Armstrong wrote: > On Mon, Aug 10, 2015 at 7:25 PM, Garrett Smith wrote: >> Personally I find the Erlang docs excellent, so this: >> >> http://erlang.org/doc/man/re.html#split-2 >> >> Roelof, I recommend that you spend some cycles reading these as a >> matter of course when you're using a function. The docs will help you >> get things right and you'll start to absorb some Erlang zen. The list >> is great to help after you've done that and still have questions. > > My goodness reading the manual first. I thought this was the > only done when evoking the "if all else fails read the friendly manual bit" > > I usually poke around in the shell first. > Not having a clue how re:split worked I guessed and tried this: > >> re:split("2015-08-06","-"). > [<<"2015">>,<<"08">>,<<"06">>] > > One wild guess later (and some distant memory) I tried > >> re:split("2015-08-06","-"),[{return,list}]. > ["2015","08","06"] > > Life is too short to waste it reading manual pages - or is it the other way > around - life is too short to waste it by not reading manual pages - I > can'tmake my mind up So now I'm wondering how much tinkering's required to reverse engineer the docs on the third argument to re:split/3 ;) I'm always looking up function docs, for which args come when (they tend to be different, wildly) and options. erlang.org/doc/man is a very important resource and it'll answer a lot of questions for you. Of course the shell is indispensable for playing around with the functions - but life is much easier if you have an idea how to use them in the first place. From zxq9@REDACTED Mon Aug 10 21:16:04 2015 From: zxq9@REDACTED (zxq9) Date: Tue, 11 Aug 2015 04:16:04 +0900 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: References: <55C8C75C.2070301@home.nl> Message-ID: <5736574.vx6jFaoFpr@changa> On 2015?8?10? ??? 20:50:17 Joe Armstrong wrote: > On Mon, Aug 10, 2015 at 5:46 PM, Roelof Wobben wrote: > > Hello, > > > > I have to make a programm which convert the iso-date to a list of numbers so > > 2015-08-10 will be [2015,08,10] > > Impossible - there is no data structure in Erlang whose print value is > [2015,08,10] - > > Here a shell example: > > $erl > Eshell V6.2 (abort with ^G) > > 1> [2015,08,10]. > [2015,8,10] > > 2> [2015,000000000000008,10]. > [2015,8,10] > > The problem the leading zeros in the 08 - if you enter > 0000000000008 the shell will print 8. > > So the output can be [2015,8,10] but never [2015,08,10] Maybe he meant "output" as in "to a stream device"? 1> IOList = io_lib:format("[~B,~2..0B,~2..0B]", [2015,8,10]). [91,"2015",44,["0",56],44,"10",93] 2> FlattenedString = lists:flatten(IOList). "[2015,08,10]" As a side note to Mr. Wobben... Hi, Roelof. If you are curious about formatting, check out the docs on the io, io_lib, string and list modules. -Craig PS: Hi, again, Joe. :-) From zxq9@REDACTED Mon Aug 10 21:26:51 2015 From: zxq9@REDACTED (zxq9) Date: Tue, 11 Aug 2015 04:26:51 +0900 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: References: <55C8C75C.2070301@home.nl> Message-ID: <1806126.UGlHAvqm7Y@changa> > > Life is too short to waste it reading manual pages - or is it the other way > > around - life is too short to waste it by not reading manual pages - I > > can'tmake my mind up Mostly the second one. Sometimes the first. ...? > So now I'm wondering how much tinkering's required to reverse engineer > the docs on the third argument to re:split/3 ;) > > I'm always looking up function docs, for which args come when (they > tend to be different, wildly) and options. erlang.org/doc/man is a > very important resource and it'll answer a lot of questions for you. > > Of course the shell is indispensable for playing around with the > functions - but life is much easier if you have an idea how to use > them in the first place. As an additional voice from the peanut gallery... Erlang has so much stuff in it that you might not expect that I find it to actually be a timesaver to dedicate an entire [however long it takes you] to just skimming the docs to see what is in there. Once. You probably won't become a master from skimming them once, but you probably will find yourself constantly recalling things like "Hrm... how do I write something that takes an X and returns a Q... oh! There was something like that in the docs..." and saving yourself a lot of time overall. This becomes a particularly massive mental lever once you get into things larger than individual functions (cases where you wind up reinventing OTP components, which I think everyone does to some degree, at least once) or thinking that OTP is leaving you up a creek because you really need something that can play nicely with OTP pieces but isn't a standard OTP behavior. That said... I seem to constantly forget the simplest of things... like whether a particular option needs to be [{thingy, value}] or just [value], so knowing how to navigate the docs (which is hardly straightforward) is itself rather valuable. -Craig From michael.nisi@REDACTED Mon Aug 10 20:18:23 2015 From: michael.nisi@REDACTED (Michael Nisi) Date: Mon, 10 Aug 2015 20:18:23 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> <55C8CA7D.4090300@research.att.com> <55C8CCC2.6050100@home.nl> <55C8D273.1080709@research.att.com> Message-ID: <2508A2F2-6883-4634-B66A-879CE5F4913A@gmail.com> Could we do my homework too? > On 10.08.2015, at 19:25, Garrett Smith wrote: > > Personally I find the Erlang docs excellent, so this: > > http://erlang.org/doc/man/re.html#split-2 > > Roelof, I recommend that you spend some cycles reading these as a > matter of course when you're using a function. The docs will help you > get things right and you'll start to absorb some Erlang zen. The list > is great to help after you've done that and still have questions. > > This link provides an index, which might also be helpful for finding > the right module and function in the first place: > > http://erldocs.com > >> On Mon, Aug 10, 2015 at 11:33 AM, Garry Hodgson wrote: >> right, because re.split() returns a list of binaries ( <<"2012">> ) >> where string:tokens() returns a list of strings ( "2012" ). >> >> so you either need to see if you can convince re:split() to >> return strings, or you need to coerce its output values >> from binaries to lists prior to converting those lists to integers. >> >> >> >>> On 8/10/15 12:09 PM, Roelof Wobben wrote: >>> >>> Op 10-8-2015 om 17:59 schreef Garry Hodgson: >>>> >>>> date_parts(Date) -> >>>> [list_to_integer(N) || N <- string:tokens(Date,"-")]. >>> >>> >>> When testing I see this output: >>> >>> 2> dates:date_parts("2012-02-02"). >>> ** exception error: bad argument in function list_to_integer/1 called as >>> list_to_integer(<<"2012">>) in call from dates:'-date_parts/1-lc$^0/1-0-'/1 >>> (dates.erl, line 6) >>> >>> --- >>> Dit e-mailbericht is gecontroleerd op virussen met Avast >>> antivirussoftware. >>> https://www.avast.com/antivirus >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From r.wobben@REDACTED Mon Aug 10 22:19:15 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 10 Aug 2015 22:19:15 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: <2508A2F2-6883-4634-B66A-879CE5F4913A@gmail.com> References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> <55C8CA7D.4090300@research.att.com> <55C8CCC2.6050100@home.nl> <55C8D273.1080709@research.att.com> <2508A2F2-6883-4634-B66A-879CE5F4913A@gmail.com> Message-ID: <55C90743.20209@home.nl> Op 10-8-2015 om 20:18 schreef Michael Nisi: > Could we do my homework too? > This is not homework. Im self learning Erlang. Roelof > >> On 10.08.2015, at 19:25, Garrett Smith wrote: >> >> Personally I find the Erlang docs excellent, so this: >> >> http://erlang.org/doc/man/re.html#split-2 >> >> Roelof, I recommend that you spend some cycles reading these as a >> matter of course when you're using a function. The docs will help you >> get things right and you'll start to absorb some Erlang zen. The list >> is great to help after you've done that and still have questions. >> >> This link provides an index, which might also be helpful for finding >> the right module and function in the first place: >> >> http://erldocs.com >> >>> On Mon, Aug 10, 2015 at 11:33 AM, Garry Hodgson wrote: >>> right, because re.split() returns a list of binaries ( <<"2012">> ) >>> where string:tokens() returns a list of strings ( "2012" ). >>> >>> so you either need to see if you can convince re:split() to >>> return strings, or you need to coerce its output values >>> from binaries to lists prior to converting those lists to integers. >>> >>> >>> >>>> On 8/10/15 12:09 PM, Roelof Wobben wrote: >>>> >>>> Op 10-8-2015 om 17:59 schreef Garry Hodgson: >>>>> date_parts(Date) -> >>>>> [list_to_integer(N) || N <- string:tokens(Date,"-")]. >>>> >>>> When testing I see this output: >>>> >>>> 2> dates:date_parts("2012-02-02"). >>>> ** exception error: bad argument in function list_to_integer/1 called as >>>> list_to_integer(<<"2012">>) in call from dates:'-date_parts/1-lc$^0/1-0-'/1 >>>> (dates.erl, line 6) >>>> >>>> --- >>>> Dit e-mailbericht is gecontroleerd op virussen met Avast >>>> antivirussoftware. >>>> https://www.avast.com/antivirus >>>> >>>> _______________________________________________ >>>> erlang-questions mailing list >>>> erlang-questions@REDACTED >>>> http://erlang.org/mailman/listinfo/erlang-questions >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From ok@REDACTED Tue Aug 11 03:52:44 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 11 Aug 2015 13:52:44 +1200 Subject: [erlang-questions] syntax errror on : In-Reply-To: <55C5E1E9.8090804@home.nl> References: <55C5E1E9.8090804@home.nl> Message-ID: <8EEBD699-E475-4351-AF8C-C4C0D47ABE6B@cs.otago.ac.nz> Others have already pointed out the missing full stop at the end. I'm more than a little puzzled by this function: > > %% @doc convert the choice to a Shape and send the > %5 data to the dimension function > %% when the choice is a : > %% r or a R then the shape will be a rectangle > %% t or a T then the shape will be a triangle > %% e or a E then the shape will be a ellipse > > -spec(char_to_shape(char() ) -> atom() ). > > char_to_shape(Char) -> > case Char of > $R -> get_dimension(rectangle); > $T -> triangle; > $E -> ellipse; > $r -> rectangle; > $t -> triangle; > $e -> ellipse; > _Else -> "Wrong Shape" > end. The $R case calls get_dimension(rectangle). NONE OF THE OTHER CASES CALLS get_dimension/1. I think this was supposed to be char_to_shape($R) -> rectangle; char_to_shape($r) -> rectangle; char_to_shape($E) -> ellipse; char_to_shape($e) -> ellipse; char_to_shape($T) -> triangle; char_to_shape($t) -> triangle. and the call to char_to_shape(Value). should have been get_dimension(char_to_shape(Value)). I am also considerably puzzled by the idea of a rectangle with only one side. Rectangles have a *width* and a *height*. If there is only one dimension associated with it, the thing must be a square. I suggest splitting out a function string_to_number(String) -> case string:to_float(String) of {Float,""} -> Float ; _ -> case string:to_integer(String) of {Integer,""} -> Integer end end. with some careful and explicit thought given to what string_to_number("1.2T") -- your code succeeds string_to_number(" 1.2") -- your code fails string_to_number("0x1") -- your code goes completely haywire string_to_number(" 1") -- ditto should do. If I were designing an input format for this problem, it would be "R" ++ ++ " " ++ | "C" ++ | "T" ++ ++ " " ++ ++ " " ++ converting this to {rectangle,W,H} | {circle,D} | {triangle,S1,S2,S3}. I'd then finish off with area({rectangle,Width,Height}) -> Width * Height; area({circle,Diameter}) -> (math:pi()/4.0) * Diameter * Diameter; area({triangle,Side1,Side2,Side3}) -> % DON'T use Heron's formula. % Use the numerically stable formula in % https://en.wikipedia.org/wiki/Heron%27s_formula From ok@REDACTED Tue Aug 11 05:15:06 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 11 Aug 2015 15:15:06 +1200 Subject: [erlang-questions] how do I make print_area work In-Reply-To: <55C7797D.6030801@home.nl> References: <55C7797D.6030801@home.nl> Message-ID: <591270CD-B9D8-4A70-BF13-9F9A1486F29D@cs.otago.ac.nz> Once again I'm going to focus on a peripheral issue, which is actually quite important. > > area() -> > Shape = shape_from_user(), > {X, Y} = dimensions_from_user(Shape), > geom:area(Shape, X, Y). The Shape and the dimensions should not be *separate*; they should be in a *single* data structure. One of the reasons for this is that it is not the case that all shapes have the same number of dimensions. To use Haskell syntax here, imagine data Shape = Square Float -- side | Rectangle Float Float -- sides | Rhombus Float Float Float -- sides, acute angle | Triangle Float Float Float -- sides | Triangle2 Float Float -- base altitude | Circle Float -- radius | Ellipse Float Float -- semi-major & semi-minor | Point We see that the number of dimensions naturally varies from 0 to 3. Now this _could_ be represented as a Shape atom and a Dimensions list, but done that way there's no *connection* to make sure the two agree. It's far better to use {square,Side} | {rectangle,Width,Height} | {rhombus,Side1,Side2,Angle} | {triangle3,Side1,Side2,Side3} | {triangle2,Base,Altitude} | {circle,Radius} | {ellipse,SemiMajor,SemiMinor} | {point} So it should be area() -> Figure = figure_from_user(), Area = area(Figure), report_area_to_user(Area). Anyone else on the list remember "Hierarchical Input-Process-Output"? Input, processing, and output generally *should* be separated; putting area/1 and report_area_to_user/1 into a single operation is, um, looking for a tactful phrase, ah got it, suboptimal. I would expect someone posting from a .nl address to be acutely aware of the fact that there are many human languages in the world. (About 6000, as far as I know, with many hanging on by their fingernails.) Reading from the user needs to be localised. Writing to the user needs to be localised. The processing that happens in between does not. As noted before, I even reject the idea of prompting for the shape and dimensions separately, or if they are separate, it would be good to make the separation table-driven. Something like this: dimensions(square) -> [side]; ... dimensions(circle) -> [radius]; dimensions(point) -> []. figure_from_user() -> Shape = get the shape from the user, Dimension_Names = dimensions(Shape), Dimension_Values = get each dimension from the user(Dimension_Names), list_to_tuple([Shape|Dimension_Values]). This way 'get each dimension from the user' doesn't know ANYTHING about which shapes have what dimensions and a new shape can be added very easily. > > numbers_from_user(XPrompt, YPrompt) -> > X = number_from_user(XPrompt), > Y = number_from_user(YPrompt), > {X, Y}. Make this numbers_from_user([]) -> []; numbers_from_user([Prompt|Prompts]) -> Number = number_from_user( Prompt), Numbers = numbers_from_user(Prompts), [Number | Numbers]. Why on earth should this function know that there are exactly two dimensions when the number *ought* to vary? > > to_number(Str) -> > try_number([fun list_to_float/1, fun list_to_integer/1], Str). > > try_number([Method|Rest], Arg) -> > try > Method(Arg) > catch > error:badarg -> try_number(Rest, Arg) > end; > try_number([], _Arg) -> > error(bad_number). This is overkill. Here there are two and only two functions you ever intend to call. From ok@REDACTED Tue Aug 11 05:21:10 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 11 Aug 2015 15:21:10 +1200 Subject: [erlang-questions] dialyzer output help In-Reply-To: <55C89D5F.8050809@ninenines.eu> References: <55C89248.5030002@home.nl> <55C89D5F.8050809@ninenines.eu> Message-ID: <0F3671FD-F732-4007-ABB3-77ACD3B0049E@cs.otago.ac.nz> On 11/08/2015, at 12:47 am, Lo?c Hoguin wrote: absolutely spot-on perfect first-rate good stuff about documentation. +1. From ok@REDACTED Tue Aug 11 05:26:55 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 11 Aug 2015 15:26:55 +1200 Subject: [erlang-questions] dialyzer output help In-Reply-To: <55C8A14C.8070906@home.nl> References: <55C89248.5030002@home.nl> <55C89D5F.8050809@ninenines.eu> <55C89F82.60202@ninenines.eu> <55C8A14C.8070906@home.nl> Message-ID: <38887C98-D0D8-4DBF-ABE8-C2A6D4E41AC0@cs.otago.ac.nz> On 11/08/2015, at 1:04 am, Roelof Wobben wrote: > > But now I more confused. > Im reading the introducing erlang book and there is always stated to document your code. > > I find this the most difficult part because how do I document something like the area function. Documentation is EXPLAINING STUFF TO PEOPLE. How do you document the area function? Imagine someone coming along who knows enough about Erlang to call your function. WHAT DO THEY NEED TO KNOW ABOUT IT? If they have access to the source code, you ask a slightly different question: WHAT DO THEY NEED TO KNOW ABOUT IT THAT IS NOT OBVIOUS IN THE CODE? Nobody can give you precise programming-language-oriented rules about documentation because documentation is mainly about PEOPLE, not programs. The code tells people what DOES happen. The documentation tells people what SHOULD happen, WHY it should happen, and a few other things. You got one part of your documentation BRILLIANTLY RIGHT, either in this thread or another, where you said what the exercise was you were trying to solve. Honestly, that was by a very large factor the most useful comment you had. From ok@REDACTED Tue Aug 11 05:50:03 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 11 Aug 2015 15:50:03 +1200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: <55C8C75C.2070301@home.nl> References: <55C8C75C.2070301@home.nl> Message-ID: <98778534-09CB-4D17-B6A7-44E48BDA22C9@cs.otago.ac.nz> On 11/08/2015, at 3:46 am, Roelof Wobben wrote: > As a working programm I have wrote this : > > -module(dates). > > -export([date_parts/1]). > > date_parts(Date)-> > [Year, Month, Day] = re:split(Date, "-", [{return, list}] ), > [element(1, string:to_integer(Year)), element(1,string:to_integer(Month)), element(1,string:to_integer(Day))]. There are two things about this that I don't like. One is the repeated element(1, string:to_integer(___)). As you probably know, > string:to_integer("roelof"). {error,no_integer} so the element(1,...) thing might return 'error', not an integer. It would be better to use list_to_integer/1 so that you either get an integer or an exception. The other is that I'd rather the list_to_integer/1 function _didn't_ raise an exception. You're using regular expressions. So why not check for digits? So I'd be looking for a match to "^([1-9][0-9][0-9][0-9])-([1-9][0-9]?)-([1-9][0-9]?)$" so that once the match succeeds you *know* there are vaguely plausible integers there. I'm also unhappy that the date is not validated, so that with your code, "0-0-0" and "42-137-999999" are accepted. There are at least two kinds of beauty for code: - INTERFACE beauty - IMPLEMENTATION beauty. For me, interface beauty means that the function either gives me clean answers I don't have to worry about any further or crashes with a useful report, and there are no nasty glitches I have to worry about. There is a glitch in your function. My reading of ISO 8601 is that -0054-8-8 should be a valid date. (Using the "retrospective" or "proleptic" Gregorian calendar.) But your function will reject it. If that is what you WANT, that's fine, but you should SAY. A comment like % This accepts YYYY-MM-DD dates for 1900 < YYYY < 2100. would do. For the purposes of interface beauty, to the *user* of this function there is no real difference between a date that is invalid because it looks like "1-2-3-4" and a date that is invalid because it looks like "2015-02-29". So interface beauty would seem to require % is_valid(Y, M, D) is true when 1900 < Y < 2100 and % Y-M-D is a valid date. is_valid(Y, M, D) when is_integer(Y), 1900 < Y, Y < 2100, is_integer(M), 0 < M, M < 13, is_integer(D), 0 < D, D < 32 -> ... in this range, is_leap_year(Y) <=> Y mod 4 = 0 From xuxb1979@REDACTED Tue Aug 11 06:22:31 2015 From: xuxb1979@REDACTED (Alex Xu) Date: Tue, 11 Aug 2015 12:22:31 +0800 Subject: [erlang-questions] 3des decryption in erlang In-Reply-To: References: Message-ID: Thank you for your rapid answer, Sean. I?ve tried block_decrypt yesterday, but I couldn?t find the counterpart of ECB mode decryption. I tried des_ede3, des3_cbc, de3_cbf. For des_ede3/des3_cbc, the output seams the same, and only the first 8 bytes output result are correct. For des3_cbf, the output are completely incorrect. So I?m still confused how to do DES3 ECB decryption with block_decrypt? > On Aug 10, 2015, at 21:54, Sean Cribbs wrote: > > Xiaobin, > > Here's what I came up with: > > crypto:start(), > %% To decrypt the text, note Key and IV must be defined in this scope > Unencoded = base64:decode(Value), > Cleartext = crypto:block_decrypt(des3_cbc, Key, IV, Unencoded), > %% To unpad the text, see https://github.com/camshaft/pkcs7.erl > pkcs7:unpad(Cleartext) > > The main thing to note is the difference in how you use the crypto module. In Erlang, you don't need to initialize, decrypt, and cleanup in separate steps. You do however, need to make sure the crypto application is started before you try this. Generally, you would make crypto a dependency (see http://erlang.org/doc/man/app.html ) of the application that contains this code and it would be started automatically when your release is booted. > > On Mon, Aug 10, 2015 at 7:59 AM, Xiaobin Xu > wrote: > Hi, all, > > For some reason i have to decrypt a message that is encrypted using 3DES algorithm, and I've PHP function example how to decrypt the message: > > public function decrypt($value) { > $td = mcrypt_module_open ( MCRYPT_3DES, '', MCRYPT_MODE_ECB, '' ); > mcrypt_generic_init ( $td, $this->key,$this->iv ); > $ret = trim ( mdecrypt_generic ( $td, base64_decode ( $value ) ) ); > $ret = $this->UnPaddingPKCS7 ( $ret ); > mcrypt_generic_deinit ( $td ); > mcrypt_module_close ( $td ); > return $ret; > } > > > private function UnPaddingPKCS7($data) { > $padlen = ord (substr($data, (strlen( $data )-1), 1 ) ); > if ($padlen > 8 ) > return $data; > > for($i = -1*($padlen-strlen($data)); $i < strlen ( $data ); $i ++) { > if (ord ( substr ( $data, $i, 1 ) ) != $padlen)return false; > } > > return substr ( $data, 0, -1*($padlen-strlen ( $data ) ) ); > } > > I googled and read crypto module document for a couple hours, and got no idea how to translate these two functions into erlang. > > Any ideas? > > > Thanks, > Xiaobin > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rok@REDACTED Tue Aug 11 08:00:06 2015 From: rok@REDACTED (Robert Kowalski) Date: Tue, 11 Aug 2015 06:00:06 -0000 Subject: [erlang-questions] Who is interested in an Erlang Performance Improvement Book? Message-ID: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> Hi list, I wrote an article how to learn Erlang by example [1] which got a lot of good feedback recently when it was posted on HN. The past weeks I am working on finding bottlenecks and try to improve the performance of Erlang Open Source projects. Based on my work, findings and insights I was asking myself if you would be interested in a book about way to measure and improve Erlang performance. Like my blogpost it would use real world examples, this time from more Open Source Erlang projects. What do you think? Best, Robert [1] http://robert-kowalski.de/blog/lets-learn-erlang-and-fix-a-bug-on-a-couchdb-cluster/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Tue Aug 11 08:46:53 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Tue, 11 Aug 2015 08:46:53 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: <98778534-09CB-4D17-B6A7-44E48BDA22C9@cs.otago.ac.nz> References: <55C8C75C.2070301@home.nl> <98778534-09CB-4D17-B6A7-44E48BDA22C9@cs.otago.ac.nz> Message-ID: <55C99A5D.3070904@home.nl> An HTML attachment was scrubbed... URL: From ingela.andin@REDACTED Tue Aug 11 09:34:19 2015 From: ingela.andin@REDACTED (Ingela Andin) Date: Tue, 11 Aug 2015 09:34:19 +0200 Subject: [erlang-questions] bad certificate if trying to verify StartSsl certificate In-Reply-To: References: <5C14B5C7-3026-4AED-BD2F-DE333AF4482D@gmail.com> Message-ID: Hi! 2015-07-17 11:31 GMT+02:00 Alex Hudich : > But it seems to me thet there are some diffrernces between 17.4 and 17.5 > which make 17.5 ?more buggy? > > I prepared two files. cacert.pem.1 is empty file with length 0 and > cacert.pem which I?ve downloaded earlier. And there is an output of 17.5 > which seems to me wrong. > > Line 2 and 3 is ok. Line 4 is ok. But why line 5 gave me no error?? > > > > Erlang/OTP 17 [erts-6.4] [source] [64-bit] [async-threads:10] [hipe] > [kernel-poll:false] > > Eshell V6.4 (abort with ^G) > 1> application:ensure_all_started(ssl). > {ok,[crypto,asn1,public_key,ssl]} > 2> ssl:connect( "www.nicemine.ru", 443, > [{verify,verify_peer},{server_name_indication,"www.nicemine.ru"},{depth,2},{cacertfile,"cacert.pem.1"}] > ). > > =ERROR REPORT==== 17-Jul-2015::13:26:45 === > SSL: certify: ssl_handshake.erl:1401:Fatal error: unknown ca > {error,{tls_alert,"unknown ca"}} > 3> ssl:connect( "www.nicemine.ru", 443, > [{verify,verify_peer},{server_name_indication,"www.nicemine.ru"},{depth,2},{cacertfile,"cacert.pem.1"}] > ). > > =ERROR REPORT==== 17-Jul-2015::13:26:48 === > SSL: certify: ssl_handshake.erl:1401:Fatal error: unknown ca > {error,{tls_alert,"unknown ca"}} > 4> ssl:connect( "www.nicemine.ru", 443, > [{verify,verify_peer},{server_name_indication,"www.nicemine.ru"},{depth,2},{cacertfile,"cacert.pem"}] > ). > {ok,{sslsocket,{gen_tcp,#Port<0.1236>,tls_connection, > undefined}, > <0.53.0>}} > 5> ssl:connect( "www.nicemine.ru", 443, > [{verify,verify_peer},{server_name_indication,"www.nicemine.ru"},{depth,2},{cacertfile,"cacert.pem.1"}] > ). > {ok,{sslsocket,{gen_tcp,#Port<0.1243>,tls_connection, > undefined}, > <0.55.0>}} > > This is because the SSL/TLS-session established in 4 is reused to preform a abbreviated handshake where the chain is not checked. Regards Ingela Erlang/OTP team - Ericsson AB > 16 ???? 2015 ?., ? 21:16, Santiago Fern?ndez > ???????(?): > > can't reproduce: > > Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:8:8] [async-threads:10] > [kernel-poll:false] > > Eshell V6.4 (abort with ^G) > 1> application:ensure_all_started(ssl). > {ok,[crypto,asn1,public_key,ssl]} > 2> ssl:connect( "www.nicemine.ru", 443, > [{verify,verify_peer},{server_name_indication,"www.nicemine.ru"},{depth,2},{cacertfile,"cacert.pem"}] > ). > {ok,{sslsocket,{gen_tcp,#Port<0.821>,tls_connection, > undefined}, > <0.49.0>}} > > > > > > -- > Santiago > > On Thu, Jul 16, 2015 at 2:54 PM, Alex Hudich wrote: > >> Hi, >> >> It doesn?t help. Still {bad_cert,invalid_issuer} >> >> >> >> 16 ???? 2015 ?., ? 20:29, ?ric Pailleau >> ???????(?): >> >> Hi, try with depth = 3. Depth 0 to depth 2 is 3. >> Regards >> >> Le 16 juil. 2015 15:15, Alex Hudich a ?crit : >> >> >> When I tried to check connection with openssl command I?ve got w/o >> cacert.pem file: >> >> $ openssl s_client -connect nicemine.ru:443 -verify 99 >> verify depth is 99 >> CONNECTED(00000003) >> depth=2 /C=IL/O=StartCom Ltd./OU=Secure Digital Certificate >> Signing/CN=StartCom Certification Authority >> verify error:num=19:self signed certificate in certificate chain >> verify return:1 >> depth=2 /C=IL/O=StartCom Ltd./OU=Secure Digital Certificate >> Signing/CN=StartCom Certification Authority >> verify return:1 >> depth=1 /C=IL/O=StartCom Ltd./OU=Secure Digital Certificate >> Signing/CN=StartCom Class 1 Primary Intermediate Server CA >> verify return:1 >> depth=0 /C=KZ/CN=www.nicefiles.ru/emailAddress=webmaster@REDACTED >> verify return:1 >> >> >> and with it >> >> $ openssl s_client -connect nicemine.ru:443 -verify 99 -CAfile cacert.pem >> verify depth is 99 >> CONNECTED(00000003) >> depth=2 /C=IL/O=StartCom Ltd./OU=Secure Digital Certificate >> Signing/CN=StartCom Certification Authority >> verify return:1 >> depth=1 /C=IL/O=StartCom Ltd./OU=Secure Digital Certificate >> Signing/CN=StartCom Class 1 Primary Intermediate Server CA >> verify return:1 >> depth=0 /C=KZ/CN=www.nicefiles.ru/emailAddress=webmaster@REDACTED >> verify return:1 >> >> so cacert.pem file contains enough info for StartCom certificates to be >> checked as valid. >> >> >> Also I?ve tried to dig it more in erlang and I?ve found that I get error >> in OTP 18 too. >> >> And the reason for bad certificate error is {bad_cert,invalid_issuer} >> >> >> >> I also tried to add >> https://www.startssl.com/certs/sub.class1.server.ca.pem file to >> cacert.pem but with no luck. >> >> >> >> >> >> 16 ???? 2015 ?., ? 12:16, Alex Hudich ???????(?): >> >> Hi! >> >> >> >> wget http://curl.haxx.se/ca/cacert.pem >> >> and then >> >> ssl:connect( "www.nicemine.ru", 443, >> [{verify,verify_peer},{server_name_indication,"www.nicemine.ru"},{depth,2},{cacertfile,"cacert.pem"}] >> ). >> >> gives me {error,{tls_alert,"bad certificate"}} >> >> >> >> Why? Site can be opened ok in the browser. >> >> Erlang/OTP 17 [erts-6.3] >> >> >> >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> >> > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ingela.andin@REDACTED Tue Aug 11 09:54:40 2015 From: ingela.andin@REDACTED (Ingela Andin) Date: Tue, 11 Aug 2015 09:54:40 +0200 Subject: [erlang-questions] bad certificate if trying to verify StartSsl certificate In-Reply-To: References: Message-ID: Hi! 2015-07-16 11:16 GMT+02:00 Alex Hudich : > Hi! > > > > wget http://curl.haxx.se/ca/cacert.pem > > and then > > ssl:connect( "www.nicemine.ru", 443, > [{verify,verify_peer},{server_name_indication,"www.nicemine.ru"},{depth,2},{cacertfile,"cacert.pem"}] > ). > > gives me {error,{tls_alert,"bad certificate"}} > > > > This site is not sending a correct certificate chain, I get all the certificates that shall be in the chain but scrambled around and not in the correct order, this is breaking the SSL/TLS-protocol. OpenSSL will also get the error above when trying to verify that chain, but later versions of OpenSSL and also other implementations obviously tries to work around this by attempting to sort them and run the validation again. You could do that too using the verify_fun if you really want to. We would rather not make that a default feature as breaking security protocols is usually a bad idea that could lead to vulnerabilities. Regards Ingela Erlang/OTP Team - Ericsson AB > Why? Site can be opened ok in the browser. > > Erlang/OTP 17 [erts-6.3] > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ingela.andin@REDACTED Tue Aug 11 12:12:48 2015 From: ingela.andin@REDACTED (Ingela Andin) Date: Tue, 11 Aug 2015 12:12:48 +0200 Subject: [erlang-questions] 3des decryption in erlang In-Reply-To: References: Message-ID: Hi! 2015-08-11 6:22 GMT+02:00 Alex Xu : > Thank you for your rapid answer, Sean. > > I?ve tried block_decrypt yesterday, but I couldn?t find the counterpart of > ECB mode decryption. > > I tried des_ede3, des3_cbc, de3_cbf. For des_ede3/des3_cbc, the output > seams the same, and only the first 8 bytes output result are correct. > > For des3_cbf, the output are completely incorrect. > > So I?m still confused how to do DES3 ECB decryption with block_decrypt? > It actually looks like this algorithm was missed when making the new crypto-API. I think it could probably be added quite easily to the new API but this will probably not be highly prioritized by Ericsson. Regards Ingela Erlang/OTP Team - Ericsson AB > On Aug 10, 2015, at 21:54, Sean Cribbs wrote: > > Xiaobin, > > Here's what I came up with: > > crypto:start(), > %% To decrypt the text, note Key and IV must be defined in this scope > Unencoded = base64:decode(Value), > Cleartext = crypto:block_decrypt(des3_cbc, Key, IV, Unencoded), > %% To unpad the text, see https://github.com/camshaft/pkcs7.erl > pkcs7:unpad(Cleartext) > > The main thing to note is the difference in how you use the crypto module. > In Erlang, you don't need to initialize, decrypt, and cleanup in separate > steps. You do however, need to make sure the crypto application is started > before you try this. Generally, you would make crypto a dependency (see > http://erlang.org/doc/man/app.html) of the application that contains this > code and it would be started automatically when your release is booted. > > On Mon, Aug 10, 2015 at 7:59 AM, Xiaobin Xu wrote: > >> Hi, all, >> >> For some reason i have to decrypt a message that is encrypted using >> 3DES algorithm, and I've PHP function example how to decrypt the message: >> >> public function decrypt($value) { >> $td = mcrypt_module_open ( MCRYPT_3DES, '', MCRYPT_MODE_ECB, '' ); >> mcrypt_generic_init ( $td, $this->key,$this->iv ); >> $ret = trim ( mdecrypt_generic ( $td, base64_decode ( $value ) ) ); >> $ret = $this->UnPaddingPKCS7 ( $ret ); >> mcrypt_generic_deinit ( $td ); >> mcrypt_module_close ( $td ); >> return $ret; >> } >> >> >> private function UnPaddingPKCS7($data) { >> $padlen = ord (substr($data, (strlen( $data )-1), 1 ) ); >> if ($padlen > 8 ) >> return $data; >> >> for($i = -1*($padlen-strlen($data)); $i < strlen ( $data ); $i ++) { >> if (ord ( substr ( $data, $i, 1 ) ) != $padlen)return false; >> } >> >> return substr ( $data, 0, -1*($padlen-strlen ( $data ) ) ); >> } >> >> I googled and read crypto module document for a couple hours, and got >> no idea how to translate these two functions into erlang. >> >> Any ideas? >> >> >> Thanks, >> Xiaobin >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> >> > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From tony@REDACTED Tue Aug 11 12:54:03 2015 From: tony@REDACTED (Tony Rogvall) Date: Tue, 11 Aug 2015 12:54:03 +0200 Subject: [erlang-questions] 3des decryption in erlang In-Reply-To: References: Message-ID: Hi! > On 11 aug 2015, at 12:12, Ingela Andin wrote: > > Hi! > > > 2015-08-11 6:22 GMT+02:00 Alex Xu : > Thank you for your rapid answer, Sean. > > I?ve tried block_decrypt yesterday, but I couldn?t find the counterpart of ECB mode decryption. > > I tried des_ede3, des3_cbc, de3_cbf. For des_ede3/des3_cbc, the output seams the same, and only the first 8 bytes output result are correct. > > For des3_cbf, the output are completely incorrect. > > So I?m still confused how to do DES3 ECB decryption with block_decrypt? > > > It actually looks like this algorithm was missed when making the new crypto-API. I think it could probably be added quite easily to the new API but this will probably not be highly prioritized > by Ericsson. > The functions are still there, you just need to call them directly. They are deprecated and will vanish next release? But then maybe OTP fixes the api? Try this in the shell: application:start(crypto). ClearText = iolist_to_binary(lists:duplicate(10, lists:seq($1,$8))). Key = <>. IV = <<0,0,0,0, 0,0,0,0>>. Encrypted = crypto:des3_cbc_encrypt(Key, Key, Key, IV, ClearText). crypto:des3_cbc_decrypt(Key, Key, Key, IV, Encrypted). Note that the Key, IV needs to be 8 bytes and that the size of ClearText and Encrypted must be a multiple of 8 ( all arguments must be of type binary ). /Tony > Regards Ingela Erlang/OTP Team - Ericsson AB > > >> On Aug 10, 2015, at 21:54, Sean Cribbs wrote: >> >> Xiaobin, >> >> Here's what I came up with: >> >> crypto:start(), >> %% To decrypt the text, note Key and IV must be defined in this scope >> Unencoded = base64:decode(Value), >> Cleartext = crypto:block_decrypt(des3_cbc, Key, IV, Unencoded), >> %% To unpad the text, see https://github.com/camshaft/pkcs7.erl >> pkcs7:unpad(Cleartext) >> >> The main thing to note is the difference in how you use the crypto module. In Erlang, you don't need to initialize, decrypt, and cleanup in separate steps. You do however, need to make sure the crypto application is started before you try this. Generally, you would make crypto a dependency (see http://erlang.org/doc/man/app.html) of the application that contains this code and it would be started automatically when your release is booted. >> >> On Mon, Aug 10, 2015 at 7:59 AM, Xiaobin Xu wrote: >> Hi, all, >> >> For some reason i have to decrypt a message that is encrypted using 3DES algorithm, and I've PHP function example how to decrypt the message: >> >> public function decrypt($value) { >> $td = mcrypt_module_open ( MCRYPT_3DES, '', MCRYPT_MODE_ECB, '' ); >> mcrypt_generic_init ( $td, $this->key,$this->iv ); >> $ret = trim ( mdecrypt_generic ( $td, base64_decode ( $value ) ) ); >> $ret = $this->UnPaddingPKCS7 ( $ret ); >> mcrypt_generic_deinit ( $td ); >> mcrypt_module_close ( $td ); >> return $ret; >> } >> >> >> private function UnPaddingPKCS7($data) { >> $padlen = ord (substr($data, (strlen( $data )-1), 1 ) ); >> if ($padlen > 8 ) >> return $data; >> >> for($i = -1*($padlen-strlen($data)); $i < strlen ( $data ); $i ++) { >> if (ord ( substr ( $data, $i, 1 ) ) != $padlen)return false; >> } >> >> return substr ( $data, 0, -1*($padlen-strlen ( $data ) ) ); >> } >> >> I googled and read crypto module document for a couple hours, and got no idea how to translate these two functions into erlang. >> >> Any ideas? >> >> >> Thanks, >> Xiaobin >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> >> > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: Message signed with OpenPGP using GPGMail URL: From drormein@REDACTED Tue Aug 11 14:19:24 2015 From: drormein@REDACTED (Dror Mein) Date: Tue, 11 Aug 2015 12:19:24 +0000 (UTC) Subject: [erlang-questions] automatic etags and emacs Message-ID: <737851594.2576121.1439295564463.JavaMail.yahoo@mail.yahoo.com> I've discovered the ETAGS feature, and it sounds promising.But it appears that one would need to recreate etags for every new function written.Did anyone add etags to flymake or found a way to automatically run etags after every file save?how would you use etags in a project containing many applications? one per application or one for the entire project.Would you add it to the git repo? -------------- next part -------------- An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Tue Aug 11 14:30:15 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Tue, 11 Aug 2015 14:30:15 +0200 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: <5c5ee54bd50750e260b8fd0e2461133e.squirrel@chasm.otago.ac.nz> References: <55C8C75C.2070301@home.nl> <98778534-09CB-4D17-B6A7-44E48BDA22C9@cs.otago.ac.nz> <55C99A5D.3070904@home.nl> <5c5ee54bd50750e260b8fd0e2461133e.squirrel@chasm.otago.ac.nz> Message-ID: <55C9EAD7.2040904@home.nl> Op 11-8-2015 om 14:07 schreef ok@REDACTED: > You wrote: > >> Error checking is not needed here. > An ?tude that tells you not to worry about error checking > is an ?tude that is TEACHING YOU TO FAIL. > > Just the other day I ran into a commercial product that failed > to validate formats for timestamps. I am *SICK* of programs > that don't quite work (like the Apple Mail program where the > Search facility stopped working for me nearly a year ago, and > where I have to reboot the machine every couple of weeks because > Mail goes offline for no apparent reason and won't go online > again.) More than that, I am *FED UP* with the habit of mind > that says "error checking is not needed here." > > So you solved the ?tude. And then you wanted to make it > beautiful. Always producing good output is a major part of > beautiful behaviour. The ?tude doesn't say that beauty is > needed either. > >>
>> Here is the text of the etude I try to solve :
>>
>>

Write a module named > class="literal">dates that contains a function > class="literal">date_parts/1, > Right there is a bad idea. If the key term "date" is in the module > name, it shouldn't be repeated in the function name, at least not in > a language where the standard practice is to always write the module > name. > date:parts("...") > reads better than > dates:date_parts("..."). > >> which takes a string in ISO >> date format ("yyyy-mm-dd") > Ah hah! It *is* ISO8601 format that's required, and while > *this* text says the ISO format is yyyy-mm-dd, that's not > exactly what *ISO8601* says. The "basic format" is yyyymmdd > with no separators. The version with dashes is the "extended > format". There are some "reduced precision" dates that cannot > be expressed in the "extended" form, and the text of the standard > seems to make the digits-only "basic" form the preferred form. > > In any case, your code does NOT check for there being four > "year" digits, or two "month" digits ("2015-08-11" conforms > to ISO8601 but "2015"-8-11" does not), or two "day" digits. > >> and >> returns a list of integers in the form [yyyy, >> mm, dd]. > And this is bad practice. A list should be used when there is a > varying number of things with the same meaning. When you have a > fixed number of items, and especially when they have different > meanings, a tuple is appropriate. {Y,M,D} is ok; {date,Y,M,D} is > better. > >> This function does not need to do any error >> checking.

> Only in a fantasy world. The thing is, you *are* doing some error > checking: if there are not exactly two dashes in the input your > function will crash. It seems silly to check *that* and nothing > else. If you *really* weren't doing any error checking you > would do > [list_to_integer(Field) || Field <- re:split(...)]. > >>

You?ll use the > class="literal">re:split/3 >> function from Erlang?s regular expression (> class="literal">re) >> module to accomplish the task. > If you really wanted to solve this problem, re:split would not > be the preferred way to do it. You'd write something like > > parse_date(L) -> > {Y,"-"++L1} = digits(4, L), > {M,"-"++L2} = digits(2, L1), > {D,""} = digits(2, L2), > if 1900 < Y, Y < 2100, 0 < M, M < 13, 0 < D, D < 32 -> > {date,Y,M,D} > end. > > digits(N, L) -> > digits(N, 0, L). > > digits(0, A, L) -> > {A, L}; > digits(N, A, [C|L]) when $0 <= C, C <= $9 -> > digits(N-1, A*10+(C-$0), L). > > It appears that the ?tude is NOT an exercise in > processing dates (for which it trains you to do bad things) > but a pretext to use re:split, and a much cleaner pretext > could have been found. > > In this case, for example, regular expressions *can* be used > to good effect to match dates well, but re:split *cannot* be > used as other than a fairly disgusting hack. > >> How, you may ask, does that >> function work? Ask Erlang! The command erl >> -man re will give you the online documentation for the >> > class="literal">re module.
> Which does *not*, in fact, explain how re:split *works*. > > > Thanks for the feedback. I will try again to make this work with the help of your comments and with error checking. I get more and more the feeling that etudes are not the right exercises to work on for learning good erlang. Maybe I can better go back to programming erlang and do the exercises of that book and google for better exercises. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From g@REDACTED Tue Aug 11 14:42:04 2015 From: g@REDACTED (Garrett Smith) Date: Tue, 11 Aug 2015 07:42:04 -0500 Subject: [erlang-questions] how do I make print_area work In-Reply-To: <591270CD-B9D8-4A70-BF13-9F9A1486F29D@cs.otago.ac.nz> References: <55C7797D.6030801@home.nl> <591270CD-B9D8-4A70-BF13-9F9A1486F29D@cs.otago.ac.nz> Message-ID: Hi Richard, On Mon, Aug 10, 2015 at 10:15 PM, Richard A. O'Keefe wrote: > Once again I'm going to focus on a peripheral issue, > which is actually quite important. I was secretly hoping to get a critique from you - one of the benefits of any given post :) >> area() -> >> Shape = shape_from_user(), >> {X, Y} = dimensions_from_user(Shape), >> geom:area(Shape, X, Y). > > The Shape and the dimensions should not be *separate*; > they should be in a *single* data structure. > > One of the reasons for this is that it is not the case > that all shapes have the same number of dimensions. > > To use Haskell syntax here, imagine > > data Shape > = Square Float -- side > | Rectangle Float Float -- sides > | Rhombus Float Float Float -- sides, acute angle > | Triangle Float Float Float -- sides > | Triangle2 Float Float -- base altitude > | Circle Float -- radius > | Ellipse Float Float -- semi-major & semi-minor > | Point > > We see that the number of dimensions naturally varies from > 0 to 3. Now this _could_ be represented as a Shape atom > and a Dimensions list, but done that way there's no > *connection* to make sure the two agree. > > It's far better to use > > {square,Side} > | {rectangle,Width,Height} > | {rhombus,Side1,Side2,Angle} > | {triangle3,Side1,Side2,Side3} > | {triangle2,Base,Altitude} > | {circle,Radius} > | {ellipse,SemiMajor,SemiMinor} > | {point} > > So it should be > > area() -> > Figure = figure_from_user(), > Area = area(Figure), > report_area_to_user(Area). > > Anyone else on the list remember > "Hierarchical Input-Process-Output"? > Input, processing, and output generally *should* be separated; > putting area/1 and report_area_to_user/1 into a single operation > is, um, looking for a tactful phrase, ah got it, suboptimal. > > I would expect someone posting from a .nl address > to be acutely aware of the fact that there are many > human languages in the world. (About 6000, as far as > I know, with many hanging on by their fingernails.) > > Reading from the user needs to be localised. > Writing to the user needs to be localised. > The processing that happens in between does not. > > As noted before, I even reject the idea of prompting > for the shape and dimensions separately, or if they > are separate, it would be good to make the separation > table-driven. Something like this: > > dimensions(square) -> [side]; > ... > dimensions(circle) -> [radius]; > dimensions(point) -> []. > > figure_from_user() -> > Shape = get the shape from the user, > Dimension_Names = dimensions(Shape), > Dimension_Values = get each dimension from the user(Dimension_Names), > list_to_tuple([Shape|Dimension_Values]). > > This way 'get each dimension from the user' doesn't know > ANYTHING about which shapes have what dimensions and a > new shape can be added very easily. >> >> numbers_from_user(XPrompt, YPrompt) -> >> X = number_from_user(XPrompt), >> Y = number_from_user(YPrompt), >> {X, Y}. > > Make this > > numbers_from_user([]) -> > []; > numbers_from_user([Prompt|Prompts]) -> > Number = number_from_user( Prompt), > Numbers = numbers_from_user(Prompts), > [Number | Numbers]. > > Why on earth should this function know that there are > exactly two dimensions when the number *ought* to vary? >> >> to_number(Str) -> >> try_number([fun list_to_float/1, fun list_to_integer/1], Str). >> >> try_number([Method|Rest], Arg) -> >> try >> Method(Arg) >> catch >> error:badarg -> try_number(Rest, Arg) >> end; >> try_number([], _Arg) -> >> error(bad_number). > > This is overkill. Here there are two and only two functions > you ever intend to call. The alternative form that occurs to me, which calls the two functions directly is: to_number(Str) -> try list_to_float(Str) catch error:badarg -> try list_to_integer(Str) catch error:badarg -> error(bad_number) end end. Not only is this hard to read, it's longer in line and character count than my version! More importantly, generalizing to_number/1 here as a series of attempts clearly spells my intention. As a nice side effect, if I wanted to add try_octal (as to follow your own argument, a number from a user is not inherently two possible things) it's a trivial and coherent change. Garrett From g@REDACTED Tue Aug 11 15:05:41 2015 From: g@REDACTED (Garrett Smith) Date: Tue, 11 Aug 2015 08:05:41 -0500 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: <55C9EAD7.2040904@home.nl> References: <55C8C75C.2070301@home.nl> <98778534-09CB-4D17-B6A7-44E48BDA22C9@cs.otago.ac.nz> <55C99A5D.3070904@home.nl> <5c5ee54bd50750e260b8fd0e2461133e.squirrel@chasm.otago.ac.nz> <55C9EAD7.2040904@home.nl> Message-ID: > Thanks for the feedback. > I will try again to make this work with the help of your comments and with > error checking. > I get more and more the feeling that etudes are not the right exercises to > work on for learning good erlang. > Maybe I can better go back to programming erlang and do the exercises of > that book and google for better exercises. I think the exchanges here have shown that there's no perfect source of learning, but rather it's the process that counts. I know you're paying close attention to all this as I see you questions and focus improving. You're making progress, make no mistake! Don't give up on the etudes if you're working through them! But perhaps consider additional sources as well - and when you see some conflicts in the material, raise them as questions here. There are a *ton* of great resources online and in print form. Others here I'm sure will weigh in with links for you. As for exercises, I tend to skip those from the books and just find a problem in time and space that's interesting to me. Then I'll use the language to work on that problem. *Build something* that's meaningful to you personally and that will drive a huge chunk of learning. Another technique I use when learning a new language is to read others' code. I personally have learned from reading Ulf Wiger's code and can recommend it (there are of course others, but I'm picking on him today) This is a good read: https://github.com/uwiger/gproc If you want to play around with gproc (you should - it's easy from the shell) start with the docs from README. Any material can be subject to critique, but that doesn't make it harmful. Your best friends at this point might be persistence and patience. Garrett From Andras.Bekes@REDACTED Tue Aug 11 14:43:18 2015 From: Andras.Bekes@REDACTED (Bekes, Andras G) Date: Tue, 11 Aug 2015 12:43:18 +0000 Subject: [erlang-questions] {error,closed} vs. {error,econnreset} In-Reply-To: <20150624124817.GA30126@nybek.com> References: <54E4A07E.5010307@erlang.org> <20150502103209.GA19880@nybek.com> <20150624124817.GA30126@nybek.com> Message-ID: Hi Rory, I just tested this new feature in Erlang/OTP R18 and it works fine. Thank you very much all for implementing it! Regards, Andras -----Original Message----- From: erlang-questions-bounces@REDACTED [mailto:erlang-questions-bounces@REDACTED] On Behalf Of Rory Byrne Sent: Wednesday, June 24, 2015 2:48 PM To: erlang-questions@REDACTED Subject: Re: [erlang-questions] {error,closed} vs. {error,econnreset} Hi Andras, On Tue, May 05, 2015 at 07:44:47AM +0000, Bekes, Andras G wrote: > Thank you very much for your efforts Rory. > > The ability "to set a socket option that shows all econnreset errors" sounds like the right solution. I am wondering why hiding this detail is the default, but I believe there were good enough reasons to design it that way. > > I accept that your solution will not notice the connection reset event in some corner cases. I think this will not apply in my case: I am sending a small amount of data (<1KB) and wait for the reply. > > I am looking forward to see your patch in the next release of Erlang/OTP! The fix for this is in the 18.0 release. It should take care of the corner cases too. Use the socket option '{show_econnreset, true}' and you'll receive {error, econnreset} in passive mode or {tcp_error, Socket, econnreset} in active mode. See the docs [1] for more information. Regards, Rory [1] http://www.erlang.org/doc/man/inet.html#setopts-2 _______________________________________________ erlang-questions mailing list erlang-questions@REDACTED http://erlang.org/mailman/listinfo/erlang-questions From roger@REDACTED Tue Aug 11 16:39:22 2015 From: roger@REDACTED (Roger Lipscombe) Date: Tue, 11 Aug 2015 15:39:22 +0100 Subject: [erlang-questions] Validating binaries Message-ID: Simple question: what's the most efficient way to validate that a binary value is of a certain length, and contains only certain characters? I've got the following: %% @doc Check that 'Value' is a binary, exactly length 'Length', %% containing only ASCII characters [0-9af]. %% If the check succeeds, return the value; otherwise throw. validate_lower_case_hex(Value, Length) -> validate_lower_case_hex(Value, Length, Value). validate_lower_case_hex(<<>>, 0, Value) -> Value; validate_lower_case_hex(<<>>, N, _Value) when N > 0 -> % binary is too short. erlang:error(validation_failed); validate_lower_case_hex(<<_,_>>, 0, _Value) -> % binary is too long. erlang:error(validation_failed); validate_lower_case_hex(<>, N, Value) when C >= $0, C =< $9; C >= $a, C =< $f -> validate_lower_case_hex(Rest, N - 1, Value); validate_lower_case_hex(<<_C:8, _Rest/binary>>, _N, _Value) -> % unexpected character. erlang:error(validation_failed). Is there a better (faster) way to do it? Thanks, Roger. From roger@REDACTED Tue Aug 11 16:49:41 2015 From: roger@REDACTED (Roger Lipscombe) Date: Tue, 11 Aug 2015 15:49:41 +0100 Subject: [erlang-questions] Validating binaries In-Reply-To: References: Message-ID: On 11 August 2015 at 15:39, Roger Lipscombe wrote: > Simple question: what's the most efficient way to validate that a > binary value is of a certain length, and contains only certain > characters? > > I've got the following: [snip] It might be worth pointing out that I only have to deal with the following combinations: 16 lower-case hex characters or 24 upper-case hex characters. ASCII encoding. So would something like the following be better? validate_lower_case_hex_16(<= $0, C1 =< $9; C1 >= $a, C1 =< $f), (C2 >= $0, C2 =< $9; C2 >= $a, C2 =< $f), ... % lots of repitition here -> Value; From seancribbs@REDACTED Tue Aug 11 17:01:12 2015 From: seancribbs@REDACTED (Sean Cribbs) Date: Tue, 11 Aug 2015 10:01:12 -0500 Subject: [erlang-questions] Validating binaries In-Reply-To: References: Message-ID: This looks like a case where you could use a binary comprehension. validate_lower_case_hex(Value, Length) when is_binary(Value), byte_size(Value) == Length -> Value == << <> || <> <= Value, (C >= $0 andalso C =< $9) orelse (C >= $a andalso C =< $f) >>; validate_lower_case_hex(Value, _) when is_binary(Value) -> false. On Tue, Aug 11, 2015 at 9:39 AM, Roger Lipscombe wrote: > Simple question: what's the most efficient way to validate that a > binary value is of a certain length, and contains only certain > characters? > > I've got the following: > > %% @doc Check that 'Value' is a binary, exactly length 'Length', > %% containing only ASCII characters [0-9af]. > %% If the check succeeds, return the value; otherwise throw. > validate_lower_case_hex(Value, Length) -> > validate_lower_case_hex(Value, Length, Value). > > validate_lower_case_hex(<<>>, 0, Value) -> > Value; > validate_lower_case_hex(<<>>, N, _Value) when N > 0 -> > % binary is too short. > erlang:error(validation_failed); > validate_lower_case_hex(<<_,_>>, 0, _Value) -> > % binary is too long. > erlang:error(validation_failed); > validate_lower_case_hex(<>, N, Value) > when C >= $0, C =< $9; C >= $a, C =< $f -> > validate_lower_case_hex(Rest, N - 1, Value); > validate_lower_case_hex(<<_C:8, _Rest/binary>>, _N, _Value) -> > % unexpected character. > erlang:error(validation_failed). > > Is there a better (faster) way to do it? > > Thanks, > Roger. > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From marc@REDACTED Tue Aug 11 17:10:43 2015 From: marc@REDACTED (Marc Worrell) Date: Tue, 11 Aug 2015 17:10:43 +0200 Subject: [erlang-questions] [ANN] Zotonic release 0.13.2 Message-ID: <67FDB9BD-B831-4E88-886E-F0AB548D5548@worrell.nl> Hi, Zotonic is the Erlang Content Management System and Framework. We have just released version 0.13.2 This is a maintenance release. Zotonic now builds correctly on Erlang 18. You can find more about Zotonic on: http://zotonic.com/ The release can be downloaded from: https://github.com/zotonic/zotonic/releases/tag/release-0.13.2 And the complete Zotonic docs are here: http://zotonic.com/docs/latest/ Kind Regards, Marc Worrell Zotonic Core Team -------------- next part -------------- An HTML attachment was scrubbed... URL: From zxq9@REDACTED Tue Aug 11 17:13:23 2015 From: zxq9@REDACTED (zxq9) Date: Wed, 12 Aug 2015 00:13:23 +0900 Subject: [erlang-questions] Validating binaries In-Reply-To: References: Message-ID: <5035050.4My2lzPKbQ@changa> On 2015?8?11? ??? 15:49:41 Roger Lipscombe wrote: > On 11 August 2015 at 15:39, Roger Lipscombe wrote: > > Simple question: what's the most efficient way to validate that a > > binary value is of a certain length, and contains only certain > > characters? > > > > I've got the following: > > [snip] > > It might be worth pointing out that I only have to deal with the > following combinations: 16 lower-case hex characters or 24 upper-case > hex characters. ASCII encoding. So would something like the following > be better? > > validate_lower_case_hex_16(< when > (C1 >= $0, C1 =< $9; C1 >= $a, C1 =< $f), > (C2 >= $0, C2 =< $9; C2 >= $a, C2 =< $f), > ... % lots of repitition here > -> > Value; Hrm... Something along the lines of (the following totally untested code...): validate_hex(Value = <<_:16/binary>>) -> validate_hex(Value, "([0-9a-f]*)"); validate_hex(Value = <<_:24/binary>>) -> validate_hex(Value, "([0-9A-F]*)"); validate_hex(_) -> erlang:error(validation_failed). validate_hex(Value, Pattern) -> case re:run(Value, Pattern, [{capture, [1], binary}]) of {match, [Value]} -> Value; _ -> erlang:error(validation_failed) end. No idea how something like that would perform. -Craig From zxq9@REDACTED Tue Aug 11 17:14:38 2015 From: zxq9@REDACTED (zxq9) Date: Wed, 12 Aug 2015 00:14:38 +0900 Subject: [erlang-questions] Validating binaries In-Reply-To: References: Message-ID: <1942277.qaS5gjOahz@changa> On 2015?8?11? ??? 10:01:12 Sean Cribbs wrote: > This looks like a case where you could use a binary comprehension. > > validate_lower_case_hex(Value, Length) when is_binary(Value), > byte_size(Value) == Length -> > Value == << <> || <> <= Value, > (C >= $0 andalso C =< $9) orelse > (C >= $a andalso C =< $f) >>; > > validate_lower_case_hex(Value, _) when is_binary(Value) -> > false. O.o Neato! -Craig From mremond@REDACTED Wed Aug 12 12:41:31 2015 From: mremond@REDACTED (=?utf-8?b?TWlja2HDq2wgUsOpbW9uZA==?=) Date: Wed, 12 Aug 2015 12:41:31 +0200 Subject: [erlang-questions] Advanced Erlang ejabberd Workshop first talk published Message-ID: Hello, We have just released a preliminary schedule with the first talks that will take place in ejabberd Advanced Erlang workshop in Paris in November. The schedule can be see here: http://advanced-erlang.com/workshops/ We will have a strong focus on various approach to broadcast messages, from groupchat to pubsub, as well as operational challenges related to upgrading large scale production ejabberd server (a lot will apply to typical large scale Erlang apps). Enjoy ! -- Micka?l R?mond http://www.process-one.net From roberto@REDACTED Wed Aug 12 13:25:54 2015 From: roberto@REDACTED (Roberto Ostinelli) Date: Wed, 12 Aug 2015 13:25:54 +0200 Subject: [erlang-questions] [ANN] Syn 0.8.0 Message-ID: Dear all, I've just released Syn 0.8.0. The main new feature is that you can now attach metadata to processes. For those of you who don't know it, Syn is a global process registry for Erlang. https://github.com/ostinelli/syn Best, r. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jesper.louis.andersen@REDACTED Wed Aug 12 13:47:39 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Wed, 12 Aug 2015 13:47:39 +0200 Subject: [erlang-questions] [ANN] [Alpha Release] dht - a distributed hash-table Message-ID: Hi list, I'm hereby announcing an early alpha-release of the `dht` application. It is an implementation of the Kademlia distributed hash table for Erlang, loosely based on the code which is in eTorrent, which originates from Magnus Klaar a few years back, but it has been completely rewritten in a lot of places. While here, I've switched the system to use 256 bit SHA-256 hashes over SHA-1 160 bit hashes which should be deprecated anyway. The README.md contains an overview of the API as it stands now. The perhaps most interesting R&D feature is that the hash table is 2.2K lines of code including comments, but its quickcheck model is 4.2K lines of code, including comments. Apart from one top-level module, every module has been checked as an isolated component and as clusters of components as well through the use of Erlang QuickCheck's clustering features. This doesn't prove the DHT is correct, but it does create a link between the model and the system under test: they are likely to be synchronized. I believe there is at least some research-grade work in the EQC model, if not for anything else, it is one of the largest Open Source models I know of. Another feature is a submodule which is used to mock time. By using component callouts, timer triggering is handled by preconditions in the model, and time is advanced in isolation from the main component. This yields a very natural way to control timers from the model which in turn lets you test timing code precisely, even in the case where timer interaction between different components has relevance. I've only run fairly simple tests, so any bug report is appreciated. Mind you, I've only quickchecked this code, not run it in production :) https://github.com/jlouis/dht -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From josh.rubyist@REDACTED Wed Aug 12 15:07:32 2015 From: josh.rubyist@REDACTED (Josh Adams) Date: Wed, 12 Aug 2015 08:07:32 -0500 Subject: [erlang-questions] [ANN] [Alpha Release] dht - a distributed hash-table In-Reply-To: References: Message-ID: Jesper, I've really enjoyed seeing various tweets from you on this subject as you worked through it. I was curious if it would be worthwhile for someone (me? No clue of the effort involved) to port etorrent to use this in place of its existing dht implementation. That would at least make it easy to test it in a more 'production' environment fairly quickly, I would think. I just don't even know if it's feasible to do, or if this application is now too different from the etorrent dht for it to be anything less than a large undertaking to swap them out. -Josh On Wed, Aug 12, 2015 at 6:47 AM, Jesper Louis Andersen wrote: > Hi list, > > I'm hereby announcing an early alpha-release of the `dht` application. It is > an implementation of the Kademlia distributed hash table for Erlang, loosely > based on the code which is in eTorrent, which originates from Magnus Klaar a > few years back, but it has been completely rewritten in a lot of places. > > While here, I've switched the system to use 256 bit SHA-256 hashes over > SHA-1 160 bit hashes which should be deprecated anyway. The README.md > contains an overview of the API as it stands now. > > The perhaps most interesting R&D feature is that the hash table is 2.2K > lines of code including comments, but its quickcheck model is 4.2K lines of > code, including comments. Apart from one top-level module, every module has > been checked as an isolated component and as clusters of components as well > through the use of Erlang QuickCheck's clustering features. This doesn't > prove the DHT is correct, but it does create a link between the model and > the system under test: they are likely to be synchronized. > > I believe there is at least some research-grade work in the EQC model, if > not for anything else, it is one of the largest Open Source models I know > of. Another feature is a submodule which is used to mock time. By using > component callouts, timer triggering is handled by preconditions in the > model, and time is advanced in isolation from the main component. This > yields a very natural way to control timers from the model which in turn > lets you test timing code precisely, even in the case where timer > interaction between different components has relevance. > > I've only run fairly simple tests, so any bug report is appreciated. Mind > you, I've only quickchecked this code, not run it in production :) > > https://github.com/jlouis/dht > > -- > J. > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -- Josh Adams From jesper.louis.andersen@REDACTED Wed Aug 12 15:18:40 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Wed, 12 Aug 2015 15:18:40 +0200 Subject: [erlang-questions] [ANN] [Alpha Release] dht - a distributed hash-table In-Reply-To: References: Message-ID: On Wed, Aug 12, 2015 at 3:07 PM, Josh Adams wrote: > I was curious if it would be worthwhile for > someone (me? No clue of the effort involved) to port etorrent to use > this in place of its existing dht implementation. > It uses a different protocol, but a great first move would be to make the protocol and the node_id generation switchable in the dht code. It is fairly close at this point. As for etorrent, the right move in the long run is to pick parts, excise them from the system and then rebuild etorrent on top of those parts. I'd probably start by removing DHT support, reduce the system in size and then make the central components work. Then build the DHT in again. When I started that project, I had relatively little knowledge of how to think about app structure in Erlang projects, and it hurts the project quite a lot now, since things are not as self-contained and neatly isolated as they should have been. In short, etorrent requires some dedicated effort in order to bring it back into a proper shape. It is like an old beautiful car from the 60'es you've found, but the engine needs some cleaning. -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From garry@REDACTED Wed Aug 12 15:54:45 2015 From: garry@REDACTED (Garry Hodgson) Date: Wed, 12 Aug 2015 09:54:45 -0400 Subject: [erlang-questions] how to make beautifulll code of this working code In-Reply-To: References: <55C8C75C.2070301@home.nl> <55C8C8BE.1080505@home.nl> <55C8CA7D.4090300@research.att.com> <55C8CCC2.6050100@home.nl> <55C8D273.1080709@research.att.com> Message-ID: <55CB5025.4060001@research.att.com> that process of discovery/experimentation was what i was hoping to nudge the OP toward. On 8/10/15 2:38 PM, Joe Armstrong wrote: > On Mon, Aug 10, 2015 at 7:25 PM, Garrett Smith wrote: >> Personally I find the Erlang docs excellent, so this: >> >> http://erlang.org/doc/man/re.html#split-2 >> >> Roelof, I recommend that you spend some cycles reading these as a >> matter of course when you're using a function. The docs will help you >> get things right and you'll start to absorb some Erlang zen. The list >> is great to help after you've done that and still have questions. > My goodness reading the manual first. I thought this was the > only done when evoking the "if all else fails read the friendly manual bit" > > I usually poke around in the shell first. > Not having a clue how re:split worked I guessed and tried this: > >> re:split("2015-08-06","-"). > [<<"2015">>,<<"08">>,<<"06">>] > > One wild guess later (and some distant memory) I tried > >> re:split("2015-08-06","-"),[{return,list}]. > ["2015","08","06"] > > Life is too short to waste it reading manual pages - or is it the other way > around - life is too short to waste it by not reading manual pages - I > can'tmake my mind up > > Cheers > > /Joe > > > > >> This link provides an index, which might also be helpful for finding >> the right module and function in the first place: >> >> http://erldocs.com >> >> On Mon, Aug 10, 2015 at 11:33 AM, Garry Hodgson wrote: >>> right, because re.split() returns a list of binaries ( <<"2012">> ) >>> where string:tokens() returns a list of strings ( "2012" ). >>> >>> so you either need to see if you can convince re:split() to >>> return strings, or you need to coerce its output values >>> from binaries to lists prior to converting those lists to integers. >>> >>> >>> >>> On 8/10/15 12:09 PM, Roelof Wobben wrote: >>>> Op 10-8-2015 om 17:59 schreef Garry Hodgson: >>>>> date_parts(Date) -> >>>>> [list_to_integer(N) || N <- string:tokens(Date,"-")]. >>>> >>>> When testing I see this output: >>>> >>>> 2> dates:date_parts("2012-02-02"). >>>> ** exception error: bad argument in function list_to_integer/1 called as >>>> list_to_integer(<<"2012">>) in call from dates:'-date_parts/1-lc$^0/1-0-'/1 >>>> (dates.erl, line 6) >>>> >>>> --- >>>> Dit e-mailbericht is gecontroleerd op virussen met Avast >>>> antivirussoftware. >>>> https://www.avast.com/antivirus >>>> >>>> _______________________________________________ >>>> erlang-questions mailing list >>>> erlang-questions@REDACTED >>>> http://erlang.org/mailman/listinfo/erlang-questions >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions From r.wobben@REDACTED Wed Aug 12 17:34:16 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Wed, 12 Aug 2015 17:34:16 +0200 Subject: [erlang-questions] How to make this work Message-ID: <55CB6778.6050909@home.nl> Hello, Im trying this exercise from the programming erlang book. Look up the definitions of erlang:now/0, erlang:date/0, and erlang:time/0. Write a function called my_time_func(F), which evaluates the fun F and times how long it takes. So I did this : -module(my_time). -export( [time_spend/1] ). time_spend(F) -> Begintime = time:now(), F(3), Endtime = time:now(), Endtime - Begintime. but then when I do this in erl : 11> my_time:time_spend(fun x -> 2 * X end). * 1: syntax error before: '->' 11> my_time:time_spend(Double = fun x -> 2 * X end). * 1: syntax error before: '->' how can I make this work ? Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From garry@REDACTED Wed Aug 12 17:38:45 2015 From: garry@REDACTED (Garry Hodgson) Date: Wed, 12 Aug 2015 11:38:45 -0400 Subject: [erlang-questions] How to make this work In-Reply-To: <55CB6778.6050909@home.nl> References: <55CB6778.6050909@home.nl> Message-ID: <55CB6885.1030005@research.att.com> read the documentation on the proper syntax for defining funs. On 8/12/15 11:34 AM, Roelof Wobben wrote: > Hello, > > Im trying this exercise from the programming erlang book. > > Look up the definitions of erlang:now/0, erlang:date/0, and > erlang:time/0. Write a > function called my_time_func(F), which evaluates the fun F and times how > long it takes. > > So I did this : > > -module(my_time). > > -export( [time_spend/1] ). > > time_spend(F) -> > Begintime = time:now(), > F(3), > Endtime = time:now(), > Endtime - Begintime. > > > but then when I do this in erl : > > 11> my_time:time_spend(fun x -> 2 * X end). > * 1: syntax error before: '->' > 11> my_time:time_spend(Double = fun x -> 2 * X end). > * 1: syntax error before: '->' > > how can I make this work ? > > Roelof > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast > antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From g@REDACTED Wed Aug 12 17:37:54 2015 From: g@REDACTED (Garrett Smith) Date: Wed, 12 Aug 2015 10:37:54 -0500 Subject: [erlang-questions] How to make this work In-Reply-To: <55CB6778.6050909@home.nl> References: <55CB6778.6050909@home.nl> Message-ID: Joe, avert your eyes ;) http://erlang.org/doc/programming_examples/funs.html#id59660 On Wed, Aug 12, 2015 at 10:34 AM, Roelof Wobben wrote: > Hello, > > Im trying this exercise from the programming erlang book. > > Look up the definitions of erlang:now/0, erlang:date/0, and erlang:time/0. > Write a > function called my_time_func(F), which evaluates the fun F and times how > long it takes. > > So I did this : > > -module(my_time). > > -export( [time_spend/1] ). > > time_spend(F) -> > Begintime = time:now(), > F(3), > Endtime = time:now(), > Endtime - Begintime. > > > but then when I do this in erl : > > 11> my_time:time_spend(fun x -> 2 * X end). > * 1: syntax error before: '->' > 11> my_time:time_spend(Double = fun x -> 2 * X end). > * 1: syntax error before: '->' > > how can I make this work ? > > Roelof > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From dmkolesnikov@REDACTED Wed Aug 12 17:39:36 2015 From: dmkolesnikov@REDACTED (Dmitry Kolesnikov) Date: Wed, 12 Aug 2015 18:39:36 +0300 Subject: [erlang-questions] How to make this work In-Reply-To: <55CB6778.6050909@home.nl> References: <55CB6778.6050909@home.nl> Message-ID: <8461E032-003C-4D98-BF53-5E71C0CEF04B@gmail.com> Hello, You can use built-in function http://erldocs.com/17.0/stdlib/timer.html?i=0&search=timer:tc#tc/1 You can also check from OTP source the implementation of this function and compare it with your's https://github.com/erlang/otp/blob/maint/lib/stdlib/src/timer.erl#L160 It gives you hints :-) Best Regards, Dmitry > On 12 Aug 2015, at 18:34, Roelof Wobben wrote: > > Hello, > > Im trying this exercise from the programming erlang book. > > Look up the definitions of erlang:now/0, erlang:date/0, and erlang:time/0. Write a > function called my_time_func(F), which evaluates the fun F and times how > long it takes. > > So I did this : > > -module(my_time). > > -export( [time_spend/1] ). > > time_spend(F) -> > Begintime = time:now(), > F(3), > Endtime = time:now(), > Endtime - Begintime. > > > but then when I do this in erl : > > 11> my_time:time_spend(fun x -> 2 * X end). > * 1: syntax error before: '->' > 11> my_time:time_spend(Double = fun x -> 2 * X end). > * 1: syntax error before: '->' > > how can I make this work ? > > Roelof > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From r.wobben@REDACTED Wed Aug 12 17:42:09 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Wed, 12 Aug 2015 17:42:09 +0200 Subject: [erlang-questions] How to make this work In-Reply-To: <55CB6885.1030005@research.att.com> References: <55CB6778.6050909@home.nl> <55CB6885.1030005@research.att.com> Message-ID: <55CB6951.8080109@home.nl> Hello, According to the Programming Erlang book second edition this is the proper syntax. Double = fun X -> X * 2 end. Roelof Op 12-8-2015 om 17:38 schreef Garry Hodgson: > read the documentation on the proper syntax for defining funs. > > On 8/12/15 11:34 AM, Roelof Wobben wrote: >> Hello, >> >> Im trying this exercise from the programming erlang book. >> >> Look up the definitions of erlang:now/0, erlang:date/0, and >> erlang:time/0. Write a >> function called my_time_func(F), which evaluates the fun F and times how >> long it takes. >> >> So I did this : >> >> -module(my_time). >> >> -export( [time_spend/1] ). >> >> time_spend(F) -> >> Begintime = time:now(), >> F(3), >> Endtime = time:now(), >> Endtime - Begintime. >> >> >> but then when I do this in erl : >> >> 11> my_time:time_spend(fun x -> 2 * X end). >> * 1: syntax error before: '->' >> 11> my_time:time_spend(Double = fun x -> 2 * X end). >> * 1: syntax error before: '->' >> >> how can I make this work ? >> >> Roelof >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast >> antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From roberto@REDACTED Wed Aug 12 17:44:11 2015 From: roberto@REDACTED (Roberto Ostinelli) Date: Wed, 12 Aug 2015 17:44:11 +0200 Subject: [erlang-questions] How to make this work In-Reply-To: <55CB6951.8080109@home.nl> References: <55CB6778.6050909@home.nl> <55CB6885.1030005@research.att.com> <55CB6951.8080109@home.nl> Message-ID: You're just missing proper parenthesis. my_time:time_spend(fun(X) -> 2 * X end). BTW there isn't such thing as time:now(). On Wed, Aug 12, 2015 at 5:42 PM, Roelof Wobben wrote: > Hello, > > According to the Programming Erlang book second edition this is the proper > syntax. > > Double = fun X -> X * 2 end. > > Roelof > > > Op 12-8-2015 om 17:38 schreef Garry Hodgson: > > read the documentation on the proper syntax for defining funs. >> >> On 8/12/15 11:34 AM, Roelof Wobben wrote: >> >>> Hello, >>> >>> Im trying this exercise from the programming erlang book. >>> >>> Look up the definitions of erlang:now/0, erlang:date/0, and >>> erlang:time/0. Write a >>> function called my_time_func(F), which evaluates the fun F and times how >>> long it takes. >>> >>> So I did this : >>> >>> -module(my_time). >>> >>> -export( [time_spend/1] ). >>> >>> time_spend(F) -> >>> Begintime = time:now(), >>> F(3), >>> Endtime = time:now(), >>> Endtime - Begintime. >>> >>> >>> but then when I do this in erl : >>> >>> 11> my_time:time_spend(fun x -> 2 * X end). >>> * 1: syntax error before: '->' >>> 11> my_time:time_spend(Double = fun x -> 2 * X end). >>> * 1: syntax error before: '->' >>> >>> how can I make this work ? >>> >>> Roelof >>> >>> >>> --- >>> Dit e-mailbericht is gecontroleerd op virussen met Avast >>> antivirussoftware. >>> https://www.avast.com/antivirus >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >>> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> >> > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From siraaj@REDACTED Wed Aug 12 17:44:35 2015 From: siraaj@REDACTED (Siraaj Khandkar) Date: Wed, 12 Aug 2015 11:44:35 -0400 Subject: [erlang-questions] How to make this work In-Reply-To: <55CB6778.6050909@home.nl> References: <55CB6778.6050909@home.nl> Message-ID: The problem is exactly what the error message says - it is a syntax error. The message says that the syntax error is before the symbol '->'. 1) Can you find all the places where you used that symbol in the above example? 2) Now compare each one of your uses of '->' to examples in the tutorial you're reading. 3) Are you using it _exactly_ the same as in the tutorial? 4) What is different? Hint: I see 2 places to check. On Wed, Aug 12, 2015 at 11:34 AM, Roelof Wobben wrote: > Hello, > > Im trying this exercise from the programming erlang book. > > Look up the definitions of erlang:now/0, erlang:date/0, and erlang:time/0. > Write a > function called my_time_func(F), which evaluates the fun F and times how > long it takes. > > So I did this : > > -module(my_time). > > -export( [time_spend/1] ). > > time_spend(F) -> > Begintime = time:now(), > F(3), > Endtime = time:now(), > Endtime - Begintime. > > > but then when I do this in erl : > > 11> my_time:time_spend(fun x -> 2 * X end). > * 1: syntax error before: '->' > 11> my_time:time_spend(Double = fun x -> 2 * X end). > * 1: syntax error before: '->' > > how can I make this work ? > > Roelof > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Wed Aug 12 17:47:02 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Wed, 12 Aug 2015 17:47:02 +0200 Subject: [erlang-questions] How to make this work In-Reply-To: <8461E032-003C-4D98-BF53-5E71C0CEF04B@gmail.com> References: <55CB6778.6050909@home.nl> <8461E032-003C-4D98-BF53-5E71C0CEF04B@gmail.com> Message-ID: <55CB6A76.90907@home.nl> Correct but my question is how I can access the function with a fun. Roelof Op 12-8-2015 om 17:39 schreef Dmitry Kolesnikov: > Hello, > > You can use built-in function > http://erldocs.com/17.0/stdlib/timer.html?i=0&search=timer:tc#tc/1 > > You can also check from OTP source the implementation of this function and compare it with your's > https://github.com/erlang/otp/blob/maint/lib/stdlib/src/timer.erl#L160 > > It gives you hints :-) > > Best Regards, > Dmitry > >> On 12 Aug 2015, at 18:34, Roelof Wobben wrote: >> >> Hello, >> >> Im trying this exercise from the programming erlang book. >> >> Look up the definitions of erlang:now/0, erlang:date/0, and erlang:time/0. Write a >> function called my_time_func(F), which evaluates the fun F and times how >> long it takes. >> >> So I did this : >> >> -module(my_time). >> >> -export( [time_spend/1] ). >> >> time_spend(F) -> >> Begintime = time:now(), >> F(3), >> Endtime = time:now(), >> Endtime - Begintime. >> >> >> but then when I do this in erl : >> >> 11> my_time:time_spend(fun x -> 2 * X end). >> * 1: syntax error before: '->' >> 11> my_time:time_spend(Double = fun x -> 2 * X end). >> * 1: syntax error before: '->' >> >> how can I make this work ? >> >> Roelof >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From r.wobben@REDACTED Wed Aug 12 17:51:24 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Wed, 12 Aug 2015 17:51:24 +0200 Subject: [erlang-questions] How to make this work In-Reply-To: <55CB6A76.90907@home.nl> References: <55CB6778.6050909@home.nl> <8461E032-003C-4D98-BF53-5E71C0CEF04B@gmail.com> <55CB6A76.90907@home.nl> Message-ID: <55CB6B7C.2030501@home.nl> I think I have a too old version because I see this : exception error: undefined function erlang:monotonic_time/0 in function my_time:time_spend/1 (my_time.erl, line 6) I have R16B03, Roelof Op 12-8-2015 om 17:47 schreef Roelof Wobben: > Correct but my question is how I can access the function with a fun. > > Roelof > > > Op 12-8-2015 om 17:39 schreef Dmitry Kolesnikov: >> Hello, >> >> You can use built-in function >> http://erldocs.com/17.0/stdlib/timer.html?i=0&search=timer:tc#tc/1 >> >> You can also check from OTP source the implementation of this >> function and compare it with your's >> https://github.com/erlang/otp/blob/maint/lib/stdlib/src/timer.erl#L160 >> >> It gives you hints :-) >> >> Best Regards, >> Dmitry >> >>> On 12 Aug 2015, at 18:34, Roelof Wobben wrote: >>> >>> Hello, >>> >>> Im trying this exercise from the programming erlang book. >>> >>> Look up the definitions of erlang:now/0, erlang:date/0, and >>> erlang:time/0. Write a >>> function called my_time_func(F), which evaluates the fun F and times >>> how >>> long it takes. >>> >>> So I did this : >>> >>> -module(my_time). >>> >>> -export( [time_spend/1] ). >>> >>> time_spend(F) -> >>> Begintime = time:now(), >>> F(3), >>> Endtime = time:now(), >>> Endtime - Begintime. >>> >>> >>> but then when I do this in erl : >>> >>> 11> my_time:time_spend(fun x -> 2 * X end). >>> * 1: syntax error before: '->' >>> 11> my_time:time_spend(Double = fun x -> 2 * X end). >>> * 1: syntax error before: '->' >>> >>> how can I make this work ? >>> >>> Roelof >>> >>> >>> --- >>> Dit e-mailbericht is gecontroleerd op virussen met Avast >>> antivirussoftware. >>> https://www.avast.com/antivirus >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >> > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast > antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From rpettit@REDACTED Wed Aug 12 18:04:07 2015 From: rpettit@REDACTED (Rick Pettit) Date: Wed, 12 Aug 2015 11:04:07 -0500 Subject: [erlang-questions] How to make this work In-Reply-To: <55CB6B7C.2030501@home.nl> References: <55CB6778.6050909@home.nl> <8461E032-003C-4D98-BF53-5E71C0CEF04B@gmail.com> <55CB6A76.90907@home.nl> <55CB6B7C.2030501@home.nl> Message-ID: Not sure this is *exactly* what you are after, but? -module(my_time). -export([my_time_func/2]). my_time_func(F, Arg) -> T0 = erlang:now(), io:format("Fun returned: ~p~n", [F(Arg)]), T1 = erlang:now(), Elapsed = timer:now_diff(T1, T0), io:format("Elapsed time: ~p microseconds~n", [Elapsed]). === rpettit-ltm:~ rpettit$ erl Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace] Eshell V6.4 (abort with ^G) 1> c(my_time). {ok,my_time} 2> my_time:my_time_func(fun(X) -> 2 * X end, 3). Fun returned: 6 Elapsed time: 73 microseconds ok === Note that erlang:now/0 is deprecated, the above was just to illustrate one way to work with that fun you are having trouble with. Again, the above may not *exactly* solve your problem, but the code works and you can feel free to play with it until you are comfortable with what is going on there. My recommendation would be to use an iterative approach?take something which works, make very small changes and continually test. This way when you break something, you immediately know where to look. When starting from scratch, build something *small*, make it work, then slowly add to it all the while going back to run tests, verify you didn?t introduce any bugs, etc. -Rick > On Aug 12, 2015, at 10:51 AM, Roelof Wobben wrote: > > I think I have a too old version because I see this : > > exception error: undefined function erlang:monotonic_time/0 in function my_time:time_spend/1 (my_time.erl, line 6) > > I have R16B03, > > Roelof > > > > Op 12-8-2015 om 17:47 schreef Roelof Wobben: >> Correct but my question is how I can access the function with a fun. >> >> Roelof >> >> >> Op 12-8-2015 om 17:39 schreef Dmitry Kolesnikov: >>> Hello, >>> >>> You can use built-in function >>> http://erldocs.com/17.0/stdlib/timer.html?i=0&search=timer:tc#tc/1 >>> >>> You can also check from OTP source the implementation of this function and compare it with your's >>> https://github.com/erlang/otp/blob/maint/lib/stdlib/src/timer.erl#L160 >>> >>> It gives you hints :-) >>> >>> Best Regards, >>> Dmitry >>> >>>> On 12 Aug 2015, at 18:34, Roelof Wobben wrote: >>>> >>>> Hello, >>>> >>>> Im trying this exercise from the programming erlang book. >>>> >>>> Look up the definitions of erlang:now/0, erlang:date/0, and erlang:time/0. Write a >>>> function called my_time_func(F), which evaluates the fun F and times how >>>> long it takes. >>>> >>>> So I did this : >>>> >>>> -module(my_time). >>>> >>>> -export( [time_spend/1] ). >>>> >>>> time_spend(F) -> >>>> Begintime = time:now(), >>>> F(3), >>>> Endtime = time:now(), >>>> Endtime - Begintime. >>>> >>>> >>>> but then when I do this in erl : >>>> >>>> 11> my_time:time_spend(fun x -> 2 * X end). >>>> * 1: syntax error before: '->' >>>> 11> my_time:time_spend(Double = fun x -> 2 * X end). >>>> * 1: syntax error before: '->' >>>> >>>> how can I make this work ? >>>> >>>> Roelof >>>> >>>> >>>> --- >>>> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >>>> https://www.avast.com/antivirus >>>> >>>> _______________________________________________ >>>> erlang-questions mailing list >>>> erlang-questions@REDACTED >>>> http://erlang.org/mailman/listinfo/erlang-questions >>> >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From r.wobben@REDACTED Wed Aug 12 18:26:59 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Wed, 12 Aug 2015 18:26:59 +0200 Subject: [erlang-questions] How to make this work In-Reply-To: References: <55CB6778.6050909@home.nl> <8461E032-003C-4D98-BF53-5E71C0CEF04B@gmail.com> <55CB6A76.90907@home.nl> <55CB6B7C.2030501@home.nl> Message-ID: <55CB73D3.5080600@home.nl> Thanks, Now I see what went wrong and how to execute the fun with a argument. Roelof Op 12-8-2015 om 18:04 schreef Rick Pettit: > Not sure this is *exactly* what you are after, but? > > -module(my_time). > -export([my_time_func/2]). > > my_time_func(F, Arg) -> > T0 = erlang:now(), > io:format("Fun returned: ~p~n", [F(Arg)]), > T1 = erlang:now(), > Elapsed = timer:now_diff(T1, T0), > io:format("Elapsed time: ~p microseconds~n", [Elapsed]). > > > === > > rpettit-ltm:~ rpettit$ erl > Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace] > > Eshell V6.4 (abort with ^G) > 1> c(my_time). > {ok,my_time} > 2> my_time:my_time_func(fun(X) -> 2 * X end, 3). > Fun returned: 6 > Elapsed time: 73 microseconds > ok > > === > > Note that erlang:now/0 is deprecated, the above was just to illustrate one way to work with that fun you are having trouble with. > > Again, the above may not *exactly* solve your problem, but the code works and you can feel free to play with it until you are comfortable with what is going on there. > > My recommendation would be to use an iterative approach?take something which works, make very small changes and continually test. This way when you break something, you immediately know where to look. > > When starting from scratch, build something *small*, make it work, then slowly add to it all the while going back to run tests, verify you didn?t introduce any bugs, etc. > > -Rick > >> On Aug 12, 2015, at 10:51 AM, Roelof Wobben wrote: >> >> I think I have a too old version because I see this : >> >> exception error: undefined function erlang:monotonic_time/0 in function my_time:time_spend/1 (my_time.erl, line 6) >> >> I have R16B03, >> >> Roelof >> >> >> >> Op 12-8-2015 om 17:47 schreef Roelof Wobben: >>> Correct but my question is how I can access the function with a fun. >>> >>> Roelof >>> >>> >>> Op 12-8-2015 om 17:39 schreef Dmitry Kolesnikov: >>>> Hello, >>>> >>>> You can use built-in function >>>> http://erldocs.com/17.0/stdlib/timer.html?i=0&search=timer:tc#tc/1 >>>> >>>> You can also check from OTP source the implementation of this function and compare it with your's >>>> https://github.com/erlang/otp/blob/maint/lib/stdlib/src/timer.erl#L160 >>>> >>>> It gives you hints :-) >>>> >>>> Best Regards, >>>> Dmitry >>>> >>>>> On 12 Aug 2015, at 18:34, Roelof Wobben wrote: >>>>> >>>>> Hello, >>>>> >>>>> Im trying this exercise from the programming erlang book. >>>>> >>>>> Look up the definitions of erlang:now/0, erlang:date/0, and erlang:time/0. Write a >>>>> function called my_time_func(F), which evaluates the fun F and times how >>>>> long it takes. >>>>> >>>>> So I did this : >>>>> >>>>> -module(my_time). >>>>> >>>>> -export( [time_spend/1] ). >>>>> >>>>> time_spend(F) -> >>>>> Begintime = time:now(), >>>>> F(3), >>>>> Endtime = time:now(), >>>>> Endtime - Begintime. >>>>> >>>>> >>>>> but then when I do this in erl : >>>>> >>>>> 11> my_time:time_spend(fun x -> 2 * X end). >>>>> * 1: syntax error before: '->' >>>>> 11> my_time:time_spend(Double = fun x -> 2 * X end). >>>>> * 1: syntax error before: '->' >>>>> >>>>> how can I make this work ? >>>>> >>>>> Roelof >>>>> >>>>> >>>>> --- >>>>> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >>>>> https://www.avast.com/antivirus >>>>> >>>>> _______________________________________________ >>>>> erlang-questions mailing list >>>>> erlang-questions@REDACTED >>>>> http://erlang.org/mailman/listinfo/erlang-questions >>> >>> --- >>> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >>> https://www.avast.com/antivirus >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >>> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From mononcqc@REDACTED Wed Aug 12 19:20:55 2015 From: mononcqc@REDACTED (Fred Hebert) Date: Wed, 12 Aug 2015 13:20:55 -0400 Subject: [erlang-questions] How to make this work In-Reply-To: <55CB6778.6050909@home.nl> References: <55CB6778.6050909@home.nl> Message-ID: <20150812172053.GG816@fhebert-ltm1> On 08/12, Roelof Wobben wrote: >Hello, > >Im trying this exercise from the programming erlang book. > >Roelof > Hi Roelof. Honest advice here is that you really, really need to sit down and read more carefully through the documentation you have at hand, and to try experimenting with your programs a bit. We've been through this months ago already. Here's a quick list: Feb 2015: - http://erlang.org/pipermail/erlang-questions/2015-February/083087.html Valid question from the exercise book, because too simple of a solution was indeed too simple. - http://erlang.org/pipermail/erlang-questions/2015-February/083162.html correct implementations, but you confused strings and atoms. Those were exercises from 'Erlang Programming' book. Atoms are introduced on p.19, the exercises on p.44. - http://erlang.org/pipermail/erlang-questions/2015-February/083197.html This is a function again from Erlang Programming. The precise implementation you are looking for for sum_acc/3 is on page 68, and is not actually an exercise as mentioned - http://erlang.org/pipermail/erlang-questions/2015-February/083217.html You found a compile error for mismatching heads. I'm not sure when in the book it is, but I'd like to show you the link http://learnyousomeerlang.com/errors-and-exceptions#a-compilation-of-errors where I compiled the common compile errors, with their explanation and how to fix them. - http://erlang.org/pipermail/erlang-questions/2015-February/083233.html Valid enough question about list building, I have little to say here - http://erlang.org/pipermail/erlang-questions/2015-February/083240.html Error on the syntax of atoms, again introduced on p.19. The error *is* a bit cryptic though - http://erlang.org/pipermail/erlang-questions/2015-February/083301.html Exercise from the Erlang programming book. Trying the guards you had set in the shell with numbers would have revealed the problem directly (as pointed out in the first response) Fast forward to this month: - http://erlang.org/pipermail/erlang-questions/2015-August/085382.html I'll point you for some like this to the same learnyousomeerlang link in the future, it's also there! - http://erlang.org/pipermail/erlang-questions/2015-August/085410.html The problem there was an unexported function. The error you saw was probably something like 'undef'. In this case, and for other errors happening at runtime, I'd like to redirect you to http://learnyousomeerlang.com/errors-and-exceptions#run-time-errors which includes descriptions for such errors and ways to fix them in general. Note that the error is also described on page 70 of Erlang Programming. - http://erlang.org/pipermail/erlang-questions/2015-August/085419.html Dialyzer errors are legitimately confusing for a newcomer! - http://erlang.org/pipermail/erlang-questions/2015-August/085438.html Valid question from 'make it work -> make it beautiful' as a progress - http://erlang.org/pipermail/erlang-questions/2015-August/085496.html This very thread. The content there is from Programming Erlang (Armstrong). If it's the second edition, I don't have it, but in the first edition, the syntax to functions is explained on page 42. In Erlang programming (which you also have), it's on page 190, and in Etudes for Erlang, which you have also looked at, they're explained in chapter 7 (http://chimera.labs.oreilly.com/books/1234000000726/ch07.html) Don't get me wrong, I appreciate people posting to the mailing list. The thing is, I feel that it would be helpful for *your* learning as a whole to make use of the resources you have rather than coming to the list as often as you do. For one, the feedback loop and your progress will be much faster! Out of the 12 email threads I have linked here, at least 6 of them could have been solved by re-reading the learning material you have in your hands (because that's where you take exercises and examples from), or by experimenting rapidly with the shell. The other half were good questions to ask, so by all means, don't stop asking questions. Just make sure that you're not using us as your own private debugger! Old timers from the industry will tell you stories of when they had to take punched cards or hand-written programs, had to go to their university department to make them run, wait hours or days before finding if things were alright, and then repeating this over again for every bug. When you ask us to solve such problems for you while you have all the information required, you might just be throwing yourself back 30-40 years in the past in terms of feedback loops! You've got the material, the tools, and visibly the drive to do that stuff. It's likely going to be simpler in the long run to make a few experiments, run them, and see if you can figure it out (or go back and re-read significant chapters in one of the many books you have on the topic) than the time it takes for you to write an email and wait for a response. Regards, Fred. From erlang@REDACTED Wed Aug 12 19:48:50 2015 From: erlang@REDACTED (Joe Armstrong) Date: Wed, 12 Aug 2015 19:48:50 +0200 Subject: [erlang-questions] How to make this work In-Reply-To: <20150812172053.GG816@fhebert-ltm1> References: <55CB6778.6050909@home.nl> <20150812172053.GG816@fhebert-ltm1> Message-ID: On Wed, Aug 12, 2015 at 7:20 PM, Fred Hebert wrote: > On 08/12, Roelof Wobben wrote: >> >> Hello, >> >> Im trying this exercise from the programming erlang book. >> >> Roelof >> > > Hi Roelof. > > Honest advice here is that you really, really need to sit down and read more > carefully through the documentation you have at hand, and to try > experimenting with your programs a bit. We've been through this months ago > already. > > Here's a quick list: > > Feb 2015: > > - http://erlang.org/pipermail/erlang-questions/2015-February/083087.html > Valid question from the exercise book, because too simple of a solution was > indeed too simple. > - http://erlang.org/pipermail/erlang-questions/2015-February/083162.html > correct implementations, but you confused strings and atoms. Those were > exercises from 'Erlang Programming' book. Atoms are introduced on p.19, the > exercises on p.44. - > http://erlang.org/pipermail/erlang-questions/2015-February/083197.html > This is a function again from Erlang Programming. The precise implementation > you are looking for for sum_acc/3 is on page 68, and is not actually an > exercise as mentioned > - http://erlang.org/pipermail/erlang-questions/2015-February/083217.html > You found a compile error for mismatching heads. I'm not sure when in the > book it is, but I'd like to show you the link > http://learnyousomeerlang.com/errors-and-exceptions#a-compilation-of-errors > where I compiled the common compile errors, with their explanation and how > to fix them. > - http://erlang.org/pipermail/erlang-questions/2015-February/083233.html > Valid enough question about list building, I have little to say here > - http://erlang.org/pipermail/erlang-questions/2015-February/083240.html > Error on the syntax of atoms, again introduced on p.19. The error *is* a bit > cryptic though > - http://erlang.org/pipermail/erlang-questions/2015-February/083301.html > Exercise from the Erlang programming book. Trying the guards you had set in > the shell with numbers would have revealed the problem directly (as pointed > out in the first response) > > Fast forward to this month: > > - http://erlang.org/pipermail/erlang-questions/2015-August/085382.html > I'll point you for some like this to the same learnyousomeerlang link in the > future, it's also there! > - http://erlang.org/pipermail/erlang-questions/2015-August/085410.html > The problem there was an unexported function. The error you saw was probably > something like 'undef'. In this case, and for other errors happening at > runtime, I'd like to redirect you to > http://learnyousomeerlang.com/errors-and-exceptions#run-time-errors which > includes descriptions for such errors and ways to fix them in general. Note > that the error is also described on page 70 of Erlang Programming. > - http://erlang.org/pipermail/erlang-questions/2015-August/085419.html > Dialyzer errors are legitimately confusing for a newcomer! > - http://erlang.org/pipermail/erlang-questions/2015-August/085438.html > Valid question from 'make it work -> make it beautiful' as a progress > - http://erlang.org/pipermail/erlang-questions/2015-August/085496.html > This very thread. The content there is from Programming Erlang (Armstrong). > If it's the second edition, I don't have it, but in the first edition, the > syntax to functions is explained on page 42. In Erlang programming (which > you also have), it's on page 190, and in Etudes for Erlang, which you have > also looked at, they're explained in chapter 7 > (http://chimera.labs.oreilly.com/books/1234000000726/ch07.html) > > Don't get me wrong, I appreciate people posting to the mailing list. The > thing is, I feel that it would be helpful for *your* learning as a whole to > make use of the resources you have rather than coming to the list as often > as you do. For one, the feedback loop and your progress will be much faster! > > Out of the 12 email threads I have linked here, at least 6 of them could > have been solved by re-reading the learning material you have in your hands > (because that's where you take exercises and examples from), or by > experimenting rapidly with the shell. > > The other half were good questions to ask, so by all means, don't stop > asking questions. Just make sure that you're not using us as your own > private debugger! > > Old timers from the industry will tell you stories of when they had to take > punched cards or hand-written programs, had to go to their university > department to make them run, wait hours or days before finding if things > were alright, and then repeating this over again for every bug. Those were the days - it was actually three weeks. Week 1) send handwritten coding sheets to be turned into punched cards Week 2) get punched cards back and proof read them, if ok send to computer centre. If not ok go to beginning Week 3) Get results back from computer. The good old FORTRAN compiler stopped at the first syntax error it found and went no further. So K syntax errors took 3*K weeks to debug *before* the program ran for the first time. The van came one a week and drove the punched cards to the computer center. Once we had a visit to the computer center - the programmers wore white lab coats - I was *very* impressed. Years later the turn round time was down to a mere 3-hours and we could punch our own cards. Now the turn-round time is the time it takes the spring under the return button to uncoil - (apart from when running XCode that is) All I can say is that we thought a lot lot longer and harder before submitting our programs - three week turn-round time makes you stare really really hard at your code before sending it off. So in the old days we did a lot of thinking and the machines did very little. Now the machines are so fast we don't do much thinking, and in a few years time we probably won't do any! and then I remember .... Yawn ...... Sorry .... just an old timer PS. Don't set Mike off - he'll go on and on about paper-tapes .... he thought starting with punched cards was incredibly luxurious /Joe > > When you ask us to solve such problems for you while you have all the > information required, you might just be throwing yourself back 30-40 years > in the past in terms of feedback loops! > > You've got the material, the tools, and visibly the drive to do that stuff. > It's likely going to be simpler in the long run to make a few experiments, > run them, and see if you can figure it out (or go back and re-read > significant chapters in one of the many books you have on the topic) than > the time it takes for you to write an email and wait for a response. > > Regards, > Fred. > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From r.wobben@REDACTED Wed Aug 12 19:49:17 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Wed, 12 Aug 2015 19:49:17 +0200 Subject: [erlang-questions] How to make this work In-Reply-To: <20150812172053.GG816@fhebert-ltm1> References: <55CB6778.6050909@home.nl> <20150812172053.GG816@fhebert-ltm1> Message-ID: <55CB871D.3070801@home.nl> Op 12-8-2015 om 19:20 schreef Fred Hebert: > On 08/12, Roelof Wobben wrote: >> Hello, >> >> Im trying this exercise from the programming erlang book. >> >> Roelof >> > > Hi Roelof. > > Honest advice here is that you really, really need to sit down and > read more carefully through the documentation you have at hand, and to > try experimenting with your programs a bit. We've been through this > months ago already. > > Here's a quick list: > > Feb 2015: > > - http://erlang.org/pipermail/erlang-questions/2015-February/083087.html > Valid question from the exercise book, because too simple of a > solution was indeed too simple. > - http://erlang.org/pipermail/erlang-questions/2015-February/083162.html > correct implementations, but you confused strings and atoms. Those > were exercises from 'Erlang Programming' book. Atoms are introduced on > p.19, the exercises on p.44. - > http://erlang.org/pipermail/erlang-questions/2015-February/083197.html > This is a function again from Erlang Programming. The precise > implementation you are looking for for sum_acc/3 is on page 68, and is > not actually an exercise as mentioned > - http://erlang.org/pipermail/erlang-questions/2015-February/083217.html > You found a compile error for mismatching heads. I'm not sure when in > the book it is, but I'd like to show you the link > http://learnyousomeerlang.com/errors-and-exceptions#a-compilation-of-errors > where I compiled the common compile errors, with their explanation and > how to fix them. > - http://erlang.org/pipermail/erlang-questions/2015-February/083233.html > Valid enough question about list building, I have little to say here > - http://erlang.org/pipermail/erlang-questions/2015-February/083240.html > Error on the syntax of atoms, again introduced on p.19. The error *is* > a bit cryptic though > - http://erlang.org/pipermail/erlang-questions/2015-February/083301.html > Exercise from the Erlang programming book. Trying the guards you had > set in the shell with numbers would have revealed the problem directly > (as pointed out in the first response) > > Fast forward to this month: > > - http://erlang.org/pipermail/erlang-questions/2015-August/085382.html > I'll point you for some like this to the same learnyousomeerlang link > in the future, it's also there! > - http://erlang.org/pipermail/erlang-questions/2015-August/085410.html > The problem there was an unexported function. The error you saw was > probably something like 'undef'. In this case, and for other errors > happening at runtime, I'd like to redirect you to > http://learnyousomeerlang.com/errors-and-exceptions#run-time-errors > which includes descriptions for such errors and ways to fix them in > general. Note that the error is also described on page 70 of Erlang > Programming. > - http://erlang.org/pipermail/erlang-questions/2015-August/085419.html > Dialyzer errors are legitimately confusing for a newcomer! > - http://erlang.org/pipermail/erlang-questions/2015-August/085438.html > Valid question from 'make it work -> make it beautiful' as a progress > - http://erlang.org/pipermail/erlang-questions/2015-August/085496.html > This very thread. The content there is from Programming Erlang > (Armstrong). If it's the second edition, I don't have it, but in the > first edition, the syntax to functions is explained on page 42. In > Erlang programming (which you also have), it's on page 190, and in > Etudes for Erlang, which you have also looked at, they're explained in > chapter 7 (http://chimera.labs.oreilly.com/books/1234000000726/ch07.html) > > Don't get me wrong, I appreciate people posting to the mailing list. > The thing is, I feel that it would be helpful for *your* learning as a > whole to make use of the resources you have rather than coming to the > list as often as you do. For one, the feedback loop and your progress > will be much faster! > > Out of the 12 email threads I have linked here, at least 6 of them > could have been solved by re-reading the learning material you have in > your hands (because that's where you take exercises and examples > from), or by experimenting rapidly with the shell. > > The other half were good questions to ask, so by all means, don't stop > asking questions. Just make sure that you're not using us as your own > private debugger! > > Old timers from the industry will tell you stories of when they had to > take punched cards or hand-written programs, had to go to their > university department to make them run, wait hours or days before > finding if things were alright, and then repeating this over again for > every bug. > > When you ask us to solve such problems for you while you have all the > information required, you might just be throwing yourself back 30-40 > years in the past in terms of feedback loops! > > You've got the material, the tools, and visibly the drive to do that > stuff. It's likely going to be simpler in the long run to make a few > experiments, run them, and see if you can figure it out (or go back > and re-read significant chapters in one of the many books you have on > the topic) than the time it takes for you to write an email and wait > for a response. > > Regards, > Fred. > oke, point taken. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From carlosj.gf@REDACTED Wed Aug 12 22:51:10 2015 From: carlosj.gf@REDACTED (=?UTF-8?Q?Carlos_Gonz=C3=A1lez_Florido?=) Date: Wed, 12 Aug 2015 22:51:10 +0200 Subject: [erlang-questions] NkCLUSTER released Message-ID: Hi, after the recent release of NkDIST, we are now releasing a much more complex project, NkCLUSTER. NkCLUSTER is a framework for creating clusters of Erlang nodes of any size, and distributing and managing jobs into them. It uses its own cluster management solution, based on NkDIST, riak_core and a custom distribution protocol. Some features are: - Hybrid approach, all nodes are worker nodes and some of them are also control nodes, all running the same Erlang application. - Support for clusters with thousands of nodes, with automatic discovery. - Worker nodes talk using TLS, TCP, WSS, WS or SCTP transports, with very flexible configurations. - You can send requests and tasks to workers, and they send events back. - Nodes can be added or removed at any time, and the cluster rebalances automatically. NkCLUSTER is currently alpha quality, but it will mature quickly, since we have plans to use it in production pretty soon. Following versions will add also more tests and docs. It will be a core piece of our upcoming NetComposer platform. Please have a look at https://github.com/Nekso/nkcluster. Comments are very welcomed! Carlos Gonzalez @carlosjgf -------------- next part -------------- An HTML attachment was scrubbed... URL: From ok@REDACTED Thu Aug 13 02:46:15 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Thu, 13 Aug 2015 12:46:15 +1200 Subject: [erlang-questions] How to make this work In-Reply-To: <55CB6778.6050909@home.nl> References: <55CB6778.6050909@home.nl> Message-ID: On 13/08/2015, at 3:34 am, Roelof Wobben wrote: > Hello, > > Im trying this exercise from the programming erlang book. > > Look up the definitions of erlang:now/0, erlang:date/0, and erlang:time/0. These functions are documented in http://www.erlang.org/doc/man/erlang.html The documentation of erlang:date/1 does not say whether month numbers are 0 origin (as a C programmer would expect) or 1 origin (as everyone else would expect) but experimentation will tell you that. Of course, having separate date() and time() functions is about as far as you can get from a good idea so we should be grateful that erlang:localtime() exists and from the tablets of our memory erase all trivial fond records of date() and time(). The documentation for erlang:now(), as you may have noticed, has a big red Warning saying "This function is deprecated! Do not use it!" There is a link to http://www.erlang.org/doc/apps/erts/time_correction.html#Dos_and_Donts to tell you what to use instead. > Write a > function called my_time_func(F), which evaluates the fun F and times how > long it takes. > > So I did this : > > -module(my_time). > > -export( [time_spend/1] ). > > time_spend(F) -> > Begintime = time:now(), > F(3), > Endtime = time:now(), > Endtime - Begintime. First, the ?tude said to call the function "my_time_func" and you have called it "time_spend". Second, that is not grammatical English. It should be "time_spent" with a "t". Third, you were told about a function ERLANG:now(), so why are you calling TIME:now()? And fourth, you DIDN'T read the documentation for erlang:now(). It returns a TUPLE, not a number. The subtraction operator works only on NUMBERS, not tuples. Life is too short not to Read The Fine Manual. > > > but then when I do this in erl : > > 11> my_time:time_spend(fun x -> 2 * X end). > * 1: syntax error before: '->' You have two errors here. Error 1: the arguments of an Erlang fun are ALWAYS enclosed in parentheses. Always. Error 2: you have 'x' in the argument position but 'X' when you use it. This should be 11> my_time:time_spend(fun (X) -> 2*X end). > 11> my_time:time_spend(Double = fun x -> 2 * X end). > * 1: syntax error before: '->' > > how can I make this work ? What was the point of putting 'Double =' there? Just use legal syntax for funs: 11> my_time:time_spend(fun (X) -> 2*X end). By the way, do not expect the time for a function this simple to be measurable. Oh, there's an important issue here. When you measure "the time" taken by a function, what do you actually want to measure? - Physical "wall clock" time? - CPU time used by the Erlang node as a whole? - CPU time used by the current scheduler? - CPU time used by the current Erlang process? (Hint: the one you want is not actually provided by Erlang. See the documentation of erlang:statistics/1.) > From ok@REDACTED Thu Aug 13 02:51:11 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Thu, 13 Aug 2015 12:51:11 +1200 Subject: [erlang-questions] How to make this work In-Reply-To: References: <55CB6778.6050909@home.nl> <20150812172053.GG816@fhebert-ltm1> Message-ID: <73A641D3-7AEE-4EBB-AFAA-6DCD238FC36B@cs.otago.ac.nz> On 13/08/2015, at 5:48 am, Joe Armstrong wrote: > PS. Don't set Mike off - he'll go on and on about paper-tapes .... > he thought > starting with punched cards was incredibly luxurious Not if you had to use a hand punch it wasn't! From tavaresbm@REDACTED Thu Aug 13 00:12:52 2015 From: tavaresbm@REDACTED (Bruno Matos Tavares) Date: Wed, 12 Aug 2015 23:12:52 +0100 Subject: [erlang-questions] Build/release 18.0 with enable-native-libs doesn't work In-Reply-To: <21962.21626.768193.220299@gargle.gargle.HOWL> References: <21962.21626.768193.220299@gargle.gargle.HOWL> Message-ID: Hi Mikael, I?ve tried 1. and 2. and it compiles but not with native libs. 1> code:is_loaded(gen_server). {file,"/opt/erlang//lib/stdlib-2.5/ebin/gen_server.beam"} 2> code:is_loaded(gen_server). {file,?/opt/erlang//lib/stdlib-2.5/ebin/gen_server.beam"} Thank you, Bruno. > On 11 Aug 2015, at 21:00, Mikael Pettersson wrote: > > Bruno Matos Tavares writes: >> Hi, >> >> I'm trying to build Erlang on Amazon Linux AMI 2015.03 (HVM) (c3.4xlarge) without success. >> >> After some research I've bumped into this post https://groups.google.com/forum/#!searchin/erlang-programming/enable-native-libs/erlang-programming/qFJmWtUQHuA/EBHC750-4UYJ but the recipe doesn't work either. >> >> ./configure --prefix=/usr/local \ >> --disable-debug \ >> --enable-silent-rules \ >> --enable-m64-build \ >> --enable-threads \ >> --enable-smp-support \ >> --enable-kernel-poll \ >> --enable-hipe \ >> --enable-native-libs \ >> --with-ssl=/usr/bin \ >> --without-docs \ >> --without-wx \ >> --without-javac \ >> --without-odbc >> >> >> make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe' >> Makefile:72: warning: overriding recipe for target `clean' >> /home/ec2-user/tmp/tmp_1/otp_src_18.0/make/otp_subdir.mk:29: warning: ignoring old recipe for target `clean' >> === Entering application hipe >> make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/rtl' >> ERLC ../ebin/hipe_rtl.beam >> hipe_rtl.erl: internal error in native_compile; >> crash reason: undef >> >> in function hipe:compile/4 >> called as hipe:compile(hipe_rtl,[], >> <<70,79,82,49,0,0,235,184,66,69,65,77,65,116,111,109,0,0,12,228,0,0,1,36,8, >> 104,105,112,101,95,114,116,108,6,109,107,95,114,116,108,3,114,116,108,7,114, >> 116,108,95,102,117,110,10,114,116,108,95,112,97,114,97,109,115,14,114,116, >> 108,95,105,115,95,99,108,111,115,117,114,101,11,114,116,108,95,105,115,95, >> 108,101,97,102,8,114,116,108,95,99,111,100,101,15,114,116,108,95,99,111,100, >> 101,95,117,112,100,97,116,101,6,101,114,108,97,110,103,10,115,101,116,101, >> 108,101,109,101,110,116,5,101,114,114,111,114,8,114,116,108,95,100,97,116, [..] >> 57,201,58,201,59,201,60,201,69,201,70,201,71,201,72,201,73,201,74,201,75, >> 201,76,201,77,201,142,201,117,201,87,201,199,201,202,201,207,201,208,201, >> 211,201,213,201,214,201,215,201,217,201,218,201,219,201,227,201,228,201,225, >> 201,232,201,235,201,236,201,240,201,242,201,247,233,2,233,6,233,10,233,12, >> 233,22,233,23,233,25,233,28,233,30,41,199,0,0>>, >> []) >> in call from compile:native_compile_1/1 (compile.erl, line 1361) >> in call from compile:'-internal_comp/4-anonymous-1-'/2 (compile.erl, line 295) >> in call from compile:fold_comp/3 (compile.erl, line 321) >> in call from compile:internal_comp/4 (compile.erl, line 305) >> in call from compile:'-do_compile/2-anonymous-0-'/2 (compile.erl, line 155) >> make[3]: *** [../ebin/hipe_rtl.beam] Error 1 >> make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/rtl' >> make[2]: *** [opt] Error 2 >> make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe' >> make[1]: *** [opt] Error 2 >> make[1]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' >> make: *** [libs] Error 2 >> >> However when I just use `enable-native-libs' it does `make'. >> >> Is it something wrong with my config or some limitation on AWS Linux that I'm not aware of. >> >> Thank you, >> Bruno. >> >> full log (configure + make): >> [ tmp_1]$ cat output.log >> Ignoring the --cache-file argument since it can cause the system to be erroneously configured >> Disabling caching >> checking build system type... x86_64-unknown-linux-gnu >> checking host system type... x86_64-unknown-linux-gnu >> checking for gcc... gcc > > I can reproduce this error on Fedora 20 Linux / x86_64: it's triggered by the --enable-m64-build > option, which is totally weird: > > - gcc on x86_64-linux defaults to -m64 (except on obscure systems defaulting to -x32) > so the -m64 added by --enable-m64-build shouldn't have any effect, but it does; and > > - building with a fake gcc script that prepends -m64 to the command line arguments doesn't > cause this (or any other) error. > > I tried comparing the bin/ and erts/ directories from builds with and without --enable-m64-build, > but every single object file diffed, and numerous generated files also diffed (like symbolic > constants being listed in different order and with different values). > > Anyway, there are three easy workarounds: > > 1. Drop the --enable-m64-build option, it's unnecessary on normal systems. > 2. ./configure without the option but with CFLAGS='-O2 -m64' in the environment > 3. adjust PATH to point to a 'gcc' script that contains > ==snip== > #!/bin/sh > exec /usr/bin/gcc -m64 "@*" > ==snip== > (replace /usr/bin/ if needed) then ./configure without the option and make. > > /Mikael From ruel@REDACTED Thu Aug 13 04:04:12 2015 From: ruel@REDACTED (Pagayon, Ruel) Date: Thu, 13 Aug 2015 10:04:12 +0800 Subject: [erlang-questions] Excluding Modules in eunit coverage (rebar) Message-ID: Hi guys, I'm using rebar to execute my eunit tests, and I want some modules excluded from the coverage report (basically those that has been generated, etc). I can see that having a cover.spec file works only for common tests. Is there any way I can exclude modules in eunit as well? Thanks, *---Ruel Pagayon* - ruel@REDACTED Platform Engineer Networking and Communications -------------- next part -------------- An HTML attachment was scrubbed... URL: From tavaresbm@REDACTED Thu Aug 13 13:16:19 2015 From: tavaresbm@REDACTED (Bruno Matos Tavares) Date: Thu, 13 Aug 2015 12:16:19 +0100 Subject: [erlang-questions] Build/release 18.0 with enable-native-libs doesn't work In-Reply-To: <21964.24039.811227.20371@gargle.gargle.HOWL> References: <21962.21626.768193.220299@gargle.gargle.HOWL> <21964.24039.811227.20371@gargle.gargle.HOWL> Message-ID: <89EF5F93-7E28-4DCC-8252-9B0019743D82@gmail.com> I?ve tested on Ubuntu Server 14.04 LTS (HVM) (Amazon EC2) and I have the same result. It feels is a bug. I?ll send it to the bug mailing list. Thank you, Bruno. > On 13 Aug 2015, at 10:05, Mikael Pettersson wrote: > > Bruno Matos Tavares writes: >> Hi Mikael, >> >> I?ve tried 1. and 2. and it compiles but not with native libs. >> >> 1> code:is_loaded(gen_server). >> {file,"/opt/erlang//lib/stdlib-2.5/ebin/gen_server.beam"} >> 2> code:is_loaded(gen_server). >> {file,?/opt/erlang//lib/stdlib-2.5/ebin/gen_server.beam"} > > The .beam file also contains the native code, so this is expected. > Try calling Mod:module_info() or Mod:module_info(native) instead. > > However, trying that I see that only the HiPE application gets the > native libs treatment, which may be what dialyzer users want but may > not be enough for other users. You could report that as a bug in the > erlang-bugs mailing list. > > /Mikael > > >> >> Thank you, >> Bruno. >> >> >>> On 11 Aug 2015, at 21:00, Mikael Pettersson wrote: >>> >>> Bruno Matos Tavares writes: >>>> Hi, >>>> >>>> I'm trying to build Erlang on Amazon Linux AMI 2015.03 (HVM) (c3.4xlarge) without success. >>>> >>>> After some research I've bumped into this post https://groups.google.com/forum/#!searchin/erlang-programming/enable-native-libs/erlang-programming/qFJmWtUQHuA/EBHC750-4UYJ but the recipe doesn't work either. >>>> >>>> ./configure --prefix=/usr/local \ >>>> --disable-debug \ >>>> --enable-silent-rules \ >>>> --enable-m64-build \ >>>> --enable-threads \ >>>> --enable-smp-support \ >>>> --enable-kernel-poll \ >>>> --enable-hipe \ >>>> --enable-native-libs \ >>>> --with-ssl=/usr/bin \ >>>> --without-docs \ >>>> --without-wx \ >>>> --without-javac \ >>>> --without-odbc >>>> >>>> >>>> make[2]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe' >>>> Makefile:72: warning: overriding recipe for target `clean' >>>> /home/ec2-user/tmp/tmp_1/otp_src_18.0/make/otp_subdir.mk:29: warning: ignoring old recipe for target `clean' >>>> === Entering application hipe >>>> make[3]: Entering directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/rtl' >>>> ERLC ../ebin/hipe_rtl.beam >>>> hipe_rtl.erl: internal error in native_compile; >>>> crash reason: undef >>>> >>>> in function hipe:compile/4 >>>> called as hipe:compile(hipe_rtl,[], >>>> <<70,79,82,49,0,0,235,184,66,69,65,77,65,116,111,109,0,0,12,228,0,0,1,36,8, >>>> 104,105,112,101,95,114,116,108,6,109,107,95,114,116,108,3,114,116,108,7,114, >>>> 116,108,95,102,117,110,10,114,116,108,95,112,97,114,97,109,115,14,114,116, >>>> 108,95,105,115,95,99,108,111,115,117,114,101,11,114,116,108,95,105,115,95, >>>> 108,101,97,102,8,114,116,108,95,99,111,100,101,15,114,116,108,95,99,111,100, >>>> 101,95,117,112,100,97,116,101,6,101,114,108,97,110,103,10,115,101,116,101, >>>> 108,101,109,101,110,116,5,101,114,114,111,114,8,114,116,108,95,100,97,116, [..] >>>> 57,201,58,201,59,201,60,201,69,201,70,201,71,201,72,201,73,201,74,201,75, >>>> 201,76,201,77,201,142,201,117,201,87,201,199,201,202,201,207,201,208,201, >>>> 211,201,213,201,214,201,215,201,217,201,218,201,219,201,227,201,228,201,225, >>>> 201,232,201,235,201,236,201,240,201,242,201,247,233,2,233,6,233,10,233,12, >>>> 233,22,233,23,233,25,233,28,233,30,41,199,0,0>>, >>>> []) >>>> in call from compile:native_compile_1/1 (compile.erl, line 1361) >>>> in call from compile:'-internal_comp/4-anonymous-1-'/2 (compile.erl, line 295) >>>> in call from compile:fold_comp/3 (compile.erl, line 321) >>>> in call from compile:internal_comp/4 (compile.erl, line 305) >>>> in call from compile:'-do_compile/2-anonymous-0-'/2 (compile.erl, line 155) >>>> make[3]: *** [../ebin/hipe_rtl.beam] Error 1 >>>> make[3]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe/rtl' >>>> make[2]: *** [opt] Error 2 >>>> make[2]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib/hipe' >>>> make[1]: *** [opt] Error 2 >>>> make[1]: Leaving directory `/home/ec2-user/tmp/tmp_1/otp_src_18.0/lib' >>>> make: *** [libs] Error 2 >>>> >>>> However when I just use `enable-native-libs' it does `make'. >>>> >>>> Is it something wrong with my config or some limitation on AWS Linux that I'm not aware of. >>>> >>>> Thank you, >>>> Bruno. >>>> >>>> full log (configure + make): >>>> [ tmp_1]$ cat output.log >>>> Ignoring the --cache-file argument since it can cause the system to be erroneously configured >>>> Disabling caching >>>> checking build system type... x86_64-unknown-linux-gnu >>>> checking host system type... x86_64-unknown-linux-gnu >>>> checking for gcc... gcc >>> >>> I can reproduce this error on Fedora 20 Linux / x86_64: it's triggered by the --enable-m64-build >>> option, which is totally weird: >>> >>> - gcc on x86_64-linux defaults to -m64 (except on obscure systems defaulting to -x32) >>> so the -m64 added by --enable-m64-build shouldn't have any effect, but it does; and >>> >>> - building with a fake gcc script that prepends -m64 to the command line arguments doesn't >>> cause this (or any other) error. >>> >>> I tried comparing the bin/ and erts/ directories from builds with and without --enable-m64-build, >>> but every single object file diffed, and numerous generated files also diffed (like symbolic >>> constants being listed in different order and with different values). >>> >>> Anyway, there are three easy workarounds: >>> >>> 1. Drop the --enable-m64-build option, it's unnecessary on normal systems. >>> 2. ./configure without the option but with CFLAGS='-O2 -m64' in the environment >>> 3. adjust PATH to point to a 'gcc' script that contains >>> ==snip== >>> #!/bin/sh >>> exec /usr/bin/gcc -m64 "@*" >>> ==snip== >>> (replace /usr/bin/ if needed) then ./configure without the option and make. >>> >>> /Mikael > > -- -------------- next part -------------- An HTML attachment was scrubbed... URL: From henrik.x.nord@REDACTED Thu Aug 13 15:04:19 2015 From: henrik.x.nord@REDACTED (Henrik Nord X) Date: Thu, 13 Aug 2015 15:04:19 +0200 Subject: [erlang-questions] Patch package OTP 17.5.6.3 released Message-ID: <55CC95D3.9050509@ericsson.com> Patch Package: OTP 17.5.6.3 Git Tag: OTP-17.5.6.3 Date: 2015-08-13 Trouble Report Id: OTP-12871, OTP-12879, OTP-12891, OTP-12902, OTP-12912, OTP-12929, OTP-12930 Seq num: System: OTP Release: 17 Application: diameter-1.9.2.1 Predecessor: OTP 17.5.6.2 Check out the git tag OTP-17.5.6.3, and build a full OTP system including documentation. Apply one or more applications from this build as patches to your installation using the 'otp_patch_apply' tool. For information on install requirements, see descriptions for each application version below. --------------------------------------------------------------------- --- diameter-1.9.2.1 ------------------------------------------------ --------------------------------------------------------------------- The diameter-1.9.2.1 application can be applied independently of other applications on a full OTP 17 installation. --- Fixed Bugs and Malfunctions --- OTP-12871 Application(s): diameter Don't report 5005 (DIAMETER_AVP_MISSING) errors unnecessarily. An AVP whose decode failed was reported as missing, despite having been reported with another error as a consequence of the failure. OTP-12879 Application(s): diameter Related Id(s): OTP-12475 Fix relay encode of nested, Grouped AVPs. A fault in OTP-12475 caused encode to fail if the first AVP in a Grouped AVP was itself Grouped. OTP-12891 Application(s): diameter Improve decode performance. The time required to decode a message increased quadratically with the number of AVPs in the worst case, leading to extremely long execution times. OTP-12902 Application(s): diameter Match acceptable peer addresses case insensitively. Regular expressions passed in an 'accept' tuple to diameter_tcp or diameter_sctp inappropriately matched case. OTP-12912 Application(s): diameter Improve watchdog and statistics performance. Inefficient use of timers contributed to poor performance at high load, as did ordering of the table statistics are written to. OTP-12929 Application(s): diameter Fix start order of alternate transports. A transport configured with diameter:add_transport/2 can be passed multiple transport_module/transport_config tuples in order to specify alternate configuration, modules being attempted in order until one succeeds. This is primarily for the connecting case; for example, to allow a transport to be configured to first attempt connection over SCTP, and then TCP in case SCTP fails. Multiple module tuples can be paired with a single config tuple, but in this case the start order was reversed relative to the order in which the modules were specifed. OTP-12930 Application(s): diameter Fix decode of Grouped AVPs containing errors. RFC 6733 says this of Failed-AVP in 7.5: -- In the case where the offending AVP is embedded within a Grouped AVP, the Failed-AVP MAY contain the grouped AVP, which in turn contains the single offending AVP. The same method MAY be employed if the grouped AVP itself is embedded in yet another grouped AVP and so on. In this case, the Failed-AVP MAY contain the grouped AVP hierarchy up to the single offending AVP. This enables the recipient to detect the location of the offending AVP when embedded in a group. It says this of DIAMETER_INVALID_AVP_LENGTH in 7.1.5: -- The request contained an AVP with an invalid length. A Diameter message indicating this error MUST include the offending AVPs within a Failed-AVP AVP. In cases where the erroneous AVP length value exceeds the message length or is less than the minimum AVP header length, it is sufficient to include the offending AVP header and a zero filled payload of the minimum required length for the payloads data type. If the AVP is a Grouped AVP, the Grouped AVP header with an empty payload would be sufficient to indicate the offending AVP. In the case where the offending AVP header cannot be fully decoded when the AVP length is less than the minimum AVP header length, it is sufficient to include an offending AVP header that is formulated by padding the incomplete AVP header with zero up to the minimum AVP header length. The AVPs placed in the errors field of a diameter_packet record are intended to be appropriate for inclusion in a Failed-AVP, but neither of the above paragraphs has been followed in the Grouped case: the entire faulty AVP (non-faulty components and all) has been included. This made it difficult to identify the actual faulty AVP in all but simple cases. The decode is now adapted to the RFC, and implements the suggested single faulty AVP, nested in as many Grouped containers as required. Full runtime dependencies of diameter-1.9.2.1: erts-6.0, kernel-3.0, ssl-5.3.4, stdlib-2.0 -------------- next part -------------- An HTML attachment was scrubbed... URL: From sid5@REDACTED Thu Aug 13 17:26:28 2015 From: sid5@REDACTED (Sid Muller) Date: Thu, 13 Aug 2015 17:26:28 +0200 Subject: [erlang-questions] ** exception exit: shutdown Message-ID: Hi, does anyone have any pointers on how to debug an exception exit in shell? When I type q(). into the shell I get this: 3> q(). ok ** exception exit: shutdown 4> sidm@REDACTED:~/src/proj$ The problem is I don't know where to look since the exception is so terse. Does anyone have any pointers? From sid5@REDACTED Thu Aug 13 17:29:25 2015 From: sid5@REDACTED (Sid Muller) Date: Thu, 13 Aug 2015 17:29:25 +0200 Subject: [erlang-questions] Who is interested in an Erlang Performance Improvement Book? In-Reply-To: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> References: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> Message-ID: An HTML attachment was scrubbed... URL: From dmkolesnikov@REDACTED Thu Aug 13 20:47:30 2015 From: dmkolesnikov@REDACTED (Dmitry Kolesnikov) Date: Thu, 13 Aug 2015 21:47:30 +0300 Subject: [erlang-questions] ** exception exit: shutdown In-Reply-To: References: Message-ID: <3F1C4FA7-CDCF-42FE-B56A-D718EBFD93EC@gmail.com> Hi, I?ve seen such exception when some of my application have not cleaned up supervised processes properly. Check out your supervisor tree(s). Best Regards, Dmitry > On 13 Aug 2015, at 18:26, Sid Muller wrote: > > Hi, > > does anyone have any pointers on how to debug an exception exit in shell? > > When I type q(). into the shell I get this: > > 3> q(). > ok > ** exception exit: shutdown > 4> sidm@REDACTED:~/src/proj$ > > > The problem is I don't know where to look since the exception is so terse. Does anyone have any pointers? > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From rpettit@REDACTED Thu Aug 13 20:54:47 2015 From: rpettit@REDACTED (Rick Pettit) Date: Thu, 13 Aug 2015 13:54:47 -0500 Subject: [erlang-questions] Who is interested in an Erlang Performance Improvement Book? In-Reply-To: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> References: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> Message-ID: <39069152-C44D-41AB-9C4D-9E516DED275E@vailsys.com> +1 -Rick > On Aug 11, 2015, at 1:00 AM, Robert Kowalski wrote: > > Hi list, > > I wrote an article how to learn Erlang by example [1] which got a lot of good feedback recently when it was posted on HN. > > The past weeks I am working on finding bottlenecks and try to improve the performance of Erlang Open Source projects. > > Based on my work, findings and insights I was asking myself if you would be interested in a book about way to measure and improve Erlang performance. Like my blogpost it would use real world examples, this time from more Open Source Erlang projects. > > What do you think? > > Best, > Robert > > > [1] http://robert-kowalski.de/blog/lets-learn-erlang-and-fix-a-bug-on-a-couchdb-cluster/ > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From jay@REDACTED Thu Aug 13 21:48:59 2015 From: jay@REDACTED (Jay Doane) Date: Thu, 13 Aug 2015 12:48:59 -0700 Subject: [erlang-questions] Who is interested in an Erlang Performance Improvement Book? In-Reply-To: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> References: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> Message-ID: Hi Robert, Sounds interesting to me. I'm assuming CouchDB would be one of those projects under study. Which others did you have in mind? Jay On Mon, Aug 10, 2015 at 11:00 PM, Robert Kowalski wrote: > Hi list, > > I wrote an article how to learn Erlang by example [1] which got a lot of > good feedback recently when it was posted on HN. > > The past weeks I am working on finding bottlenecks and try to improve the > performance of Erlang Open Source projects. > > Based on my work, findings and insights I was asking myself if you would > be interested in a book about way to measure and improve Erlang > performance. Like my blogpost it would use real world examples, this time > from more Open Source Erlang projects. > > What do you think? > > Best, > Robert > > > [1] > http://robert-kowalski.de/blog/lets-learn-erlang-and-fix-a-bug-on-a-couchdb-cluster/ > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From dias.rodolfo@REDACTED Thu Aug 13 22:04:42 2015 From: dias.rodolfo@REDACTED (Rodolfo Dias) Date: Thu, 13 Aug 2015 17:04:42 -0300 Subject: [erlang-questions] Who is interested in an Erlang Performance Improvement Book? In-Reply-To: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> References: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> Message-ID: +1 2015-08-11 3:00 GMT-03:00 Robert Kowalski : > Hi list, > > I wrote an article how to learn Erlang by example [1] which got a lot of > good feedback recently when it was posted on HN. > > The past weeks I am working on finding bottlenecks and try to improve the > performance of Erlang Open Source projects. > > Based on my work, findings and insights I was asking myself if you would > be interested in a book about way to measure and improve Erlang > performance. Like my blogpost it would use real world examples, this time > from more Open Source Erlang projects. > > What do you think? > > Best, > Robert > > > [1] > http://robert-kowalski.de/blog/lets-learn-erlang-and-fix-a-bug-on-a-couchdb-cluster/ > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chandrashekhar.mullaparthi@REDACTED Thu Aug 13 23:55:35 2015 From: chandrashekhar.mullaparthi@REDACTED (Chandru) Date: Thu, 13 Aug 2015 22:55:35 +0100 Subject: [erlang-questions] ** exception exit: shutdown In-Reply-To: References: Message-ID: Which version of erlang are you using? What OS? Trying it on OS X, the node dies quietly. Not entirely sure why you are seeing the "exception exit" message. Did you have any processes running before you invoked q()? Basically the node shutdown procedure is being invoked, and all your processes get killed. Functions you type in the shell are defined in shell_default.erl. shell_default:q/0 is defined as: q() -> c:q(). c:q/0 is defined as: -spec q() -> no_return(). q() -> init:stop(). If you turn tracing on for the init process to see what happens. $ ~/erlang/R17-5/bin/erl Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] Eshell V6.4 (abort with ^G) 1> whereis(init). <0.0.0> 2> 2> 2> 2> dbg:tracer(). {ok,<0.35.0>} 3> dbg:p(whereis(init), [s,r]). {ok,[{matched,nonode@REDACTED,1}]} 4> 4> 4> q(). (<0.0.0>) << {stop,stop} (<0.0.0>) <0.7.0> ! {'EXIT',<0.2.0>,shutdown} ok 5> (no error logger present) error: "Error in process <0.35.0> with exit value: {badarg,[{io,format,[user,\"** dbg got EXIT - terminating: ~p~n\",[{trace_handler_crashed,{badarg,[{io,format,[user,\"(~p) << ~p~n\",[<0.0.0>,{'EXIT',<0.7.0>,shutdown}]],[]},{dbg,dhandler1,3,[{file,\"dbg.erl\"},{line,983}]},{dbg,invoke_handler... \n" Chandru On 13 August 2015 at 16:26, Sid Muller wrote: > Hi, > > does anyone have any pointers on how to debug an exception exit in shell? > > When I type q(). into the shell I get this: > > 3> q(). > ok > ** exception exit: shutdown > 4> sidm@REDACTED:~/src/proj$ > > > The problem is I don't know where to look since the exception is so terse. > Does anyone have any pointers? > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From carlosj.gf@REDACTED Fri Aug 14 10:25:32 2015 From: carlosj.gf@REDACTED (=?UTF-8?Q?Carlos_Gonz=C3=A1lez_Florido?=) Date: Fri, 14 Aug 2015 10:25:32 +0200 Subject: [erlang-questions] Who is interested in an Erlang Performance Improvement Book? In-Reply-To: References: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> Message-ID: Of course! On Thu, Aug 13, 2015 at 10:04 PM, Rodolfo Dias wrote: > > +1 > > 2015-08-11 3:00 GMT-03:00 Robert Kowalski : >> >> Hi list, >> >> I wrote an article how to learn Erlang by example [1] which got a lot of good feedback recently when it was posted on HN. >> >> The past weeks I am working on finding bottlenecks and try to improve the performance of Erlang Open Source projects. >> >> Based on my work, findings and insights I was asking myself if you would be interested in a book about way to measure and improve Erlang performance. Like my blogpost it would use real world examples, this time from more Open Source Erlang projects. >> >> What do you think? >> >> Best, >> Robert >> >> >> [1] http://robert-kowalski.de/blog/lets-learn-erlang-and-fix-a-bug-on-a-couchdb-cluster/ >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Fri Aug 14 10:29:01 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Fri, 14 Aug 2015 10:29:01 +0200 Subject: [erlang-questions] feedback on my solutions to programming erlang second edition Message-ID: <55CDA6CD.2050501@home.nl> Hello, I did the first 6 chapters of the Erlang programming book second editon. Now I wonder if I did things the righr way and if there are any improvements. My code can be found here: https://github.com/rwobben/programming_erlang_exercises I did not do the chapter 5 exercises because then you need to use map and that one is in R17 where I work on R16. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From g@REDACTED Fri Aug 14 13:17:45 2015 From: g@REDACTED (Garrett Smith) Date: Fri, 14 Aug 2015 06:17:45 -0500 Subject: [erlang-questions] feedback on my solutions to programming erlang second edition In-Reply-To: <55CDA6CD.2050501@home.nl> References: <55CDA6CD.2050501@home.nl> Message-ID: This function does two things that are unrelated, it returns a file and it prints a message to stdout. https://github.com/rwobben/programming_erlang_exercises/blob/master/chapter_6/my_file.erl#L8 Erlang uses two different patterns for surfacing errors from functions... Tagged tuples: do() -> {ok, Value} | {error, Error} | error and exceptions: do() -> Value In the first form, the caller must handle the value accordingly. dict:find/2 is an example of this: http://erlang.org/doc/man/dict.html#find-2 It's important in this case to use patterns that can differentiate between a good value and an error. We use {ok, Value} and {error, Error} respectively. If the error doesn't have or need any detail, use the atom error by itself. Don't do this though: do() -> Value | {error, Error} | error as it forces an order of pattern matching (and precludes error tuples/atom as valid results), which is easily avoided by tagging the good value as {ok, Value}. In the second form, the caller can safely assume that the value is correct, otherwise an exception would be raised (which doesn't have to be handled, though can be). dict:fetch/2 is an example of this: http://erlang.org/doc/man/dict.html#fetch-2 There's never a case IMO where a function should handle an error internally by printing a message somewhere and returning the atom ok, which is what your function does. Imagine the chagrin of a caller assuming everything is fine, then discovering that ok is not a binary, failing. Then what, a human has to screen scrape stdout somewhere? This reminds me of a common Java pattern: try { return do(); catch (Exception e) { e.printStackTrace(); return null; } As horrifying as this code is (truly) I see it *all the time*. People often ask which form of error surfacing is correct here - tagged tuples or exception. Both are correct and should be used - but according to the intent of the function. The dict module I think is a great example (find vs fetch). In my own practice, I tend to follow this order of progression: - Functions return good values, not tagged tuples - Avoid any non "happy path" code and let Erlang deal with the unhandled cases - i.e. your code only reflects what you care about handling, nothing else - In cases where a function itself (internally) has to deal with a tagged error, raise an error with appropriate context - If the function is low enough level that *it's job* is to surface *either* success or failure, then IMO it must use tagged tuples - that's its design and not a matter of aesthetics So, again, in progression of thinking, I'd start your function off like this: read(File) -> {ok, Bin} = file:read_file(File), Bin. The caller doesn't have to worry about getting some weird value and Erlang will stop dead in its tracks if there's a problem reading that file. Perfect! Except that in this case, you'll get a 'bad match' error that will complain about an error result, but it won't tell you about the file involved. So being slightly speculative about needing that information in case of an error, I'd write it this way: read(File) -> case file:read_file(File) of {ok, Bin}-> Bin ; {error, Err} -> error({read_file, File, Err}) end. But I concede that this is speculative - it's just in this case I have enough experience with this type of function to know that I'll certainly be interested in the file if something's wrong (this is obvious). But by default, I'd avoid that speculation and get some experience running the code to tell me if I need to take the next step of handling error cases explicitly and generating fuller-context exceptions. My motive there is to avoid typing *any* error handling code at all. That's IMO the right starting point. Then, let yourself be dragged reluctantly into error handling code by experience. In any case, stick to the two conventions here of surfacing errors. Otherwise from what I saw things look great! Now find *something to build* :) On Fri, Aug 14, 2015 at 3:29 AM, Roelof Wobben wrote: > Hello, > > I did the first 6 chapters of the Erlang programming book second editon. > > Now I wonder if I did things the righr way and if there are any > improvements. > > My code can be found here: > https://github.com/rwobben/programming_erlang_exercises > > I did not do the chapter 5 exercises because then you need to use map and > that one is in R17 where I work on R16. > > Roelof > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From r.wobben@REDACTED Fri Aug 14 13:29:13 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Fri, 14 Aug 2015 13:29:13 +0200 Subject: [erlang-questions] feedback on my solutions to programming erlang second edition In-Reply-To: References: <55CDA6CD.2050501@home.nl> Message-ID: <55CDD109.1080109@home.nl> Thanks, So it's fine to give this a error message : ** exception error: {read_file,"wrong.txt",enoent} in function my_file:read/1 (my_file.erl, line 8)) I think a unexperience users still does not know what went wrong. That's is why I choose for a more human readable error message( File not found or something else). Roelof ** exception error: {read_file,"wrong.txt",enoent} in function my_file:read/1 (my_file.erl, line 8) Op 14-8-2015 om 13:17 schreef Garrett Smith: > This function does two things that are unrelated, it returns a file > and it prints a message to stdout. > > https://github.com/rwobben/programming_erlang_exercises/blob/master/chapter_6/my_file.erl#L8 > > Erlang uses two different patterns for surfacing errors from functions... > > Tagged tuples: > > do() -> {ok, Value} | {error, Error} | error > > and exceptions: > > do() -> Value > > In the first form, the caller must handle the value accordingly. > dict:find/2 is an example of this: > > http://erlang.org/doc/man/dict.html#find-2 > > It's important in this case to use patterns that can differentiate > between a good value and an error. We use {ok, Value} and {error, > Error} respectively. If the error doesn't have or need any detail, use > the atom error by itself. Don't do this though: > > do() -> Value | {error, Error} | error > > as it forces an order of pattern matching (and precludes error > tuples/atom as valid results), which is easily avoided by tagging the > good value as {ok, Value}. > > In the second form, the caller can safely assume that the value is > correct, otherwise an exception would be raised (which doesn't have to > be handled, though can be). dict:fetch/2 is an example of this: > > http://erlang.org/doc/man/dict.html#fetch-2 > > There's never a case IMO where a function should handle an error > internally by printing a message somewhere and returning the atom ok, > which is what your function does. Imagine the chagrin of a caller > assuming everything is fine, then discovering that ok is not a binary, > failing. Then what, a human has to screen scrape stdout somewhere? > This reminds me of a common Java pattern: > > try { > return do(); > catch (Exception e) { > e.printStackTrace(); > return null; > } > > As horrifying as this code is (truly) I see it *all the time*. > > People often ask which form of error surfacing is correct here - > tagged tuples or exception. Both are correct and should be used - but > according to the intent of the function. The dict module I think is a > great example (find vs fetch). > > In my own practice, I tend to follow this order of progression: > > - Functions return good values, not tagged tuples > > - Avoid any non "happy path" code and let Erlang deal with the > unhandled cases - i.e. your code only reflects what you care about > handling, nothing else > > - In cases where a function itself (internally) has to deal with a > tagged error, raise an error with appropriate context > > - If the function is low enough level that *it's job* is to surface > *either* success or failure, then IMO it must use tagged tuples - > that's its design and not a matter of aesthetics > > So, again, in progression of thinking, I'd start your function off like this: > > read(File) -> > {ok, Bin} = file:read_file(File), > Bin. > > The caller doesn't have to worry about getting some weird value and > Erlang will stop dead in its tracks if there's a problem reading that > file. Perfect! > > Except that in this case, you'll get a 'bad match' error that will > complain about an error result, but it won't tell you about the file > involved. So being slightly speculative about needing that information > in case of an error, I'd write it this way: > > read(File) -> > case file:read_file(File) of > {ok, Bin}-> Bin ; > {error, Err} -> error({read_file, File, Err}) > end. > > But I concede that this is speculative - it's just in this case I have > enough experience with this type of function to know that I'll > certainly be interested in the file if something's wrong (this is > obvious). But by default, I'd avoid that speculation and get some > experience running the code to tell me if I need to take the next step > of handling error cases explicitly and generating fuller-context > exceptions. My motive there is to avoid typing *any* error handling > code at all. That's IMO the right starting point. Then, let yourself > be dragged reluctantly into error handling code by experience. > > In any case, stick to the two conventions here of surfacing errors. > > Otherwise from what I saw things look great! > > Now find *something to build* :) > > On Fri, Aug 14, 2015 at 3:29 AM, Roelof Wobben wrote: >> Hello, >> >> I did the first 6 chapters of the Erlang programming book second editon. >> >> Now I wonder if I did things the righr way and if there are any >> improvements. >> >> My code can be found here: >> https://github.com/rwobben/programming_erlang_exercises >> >> I did not do the chapter 5 exercises because then you need to use map and >> that one is in R17 where I work on R16. >> >> Roelof >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From g@REDACTED Fri Aug 14 13:39:44 2015 From: g@REDACTED (Garrett Smith) Date: Fri, 14 Aug 2015 06:39:44 -0500 Subject: [erlang-questions] feedback on my solutions to programming erlang second edition In-Reply-To: <55CDD109.1080109@home.nl> References: <55CDA6CD.2050501@home.nl> <55CDD109.1080109@home.nl> Message-ID: Treat UI/UX as a separate concern. If you raise an exception there, something ought to handle that if you're presenting it to a non technical user. But consider that in many applications, a user is an admin looking through log files or getting emails/text messages with cryptic blurbs. As long as that information is useful, fine. These people *love* arcane messages :) Consider also that even a nicely written message to a human may make no sense. If your program runs into some unexpected error, it could be a programming bug (or you're not handling a normal case) or some weird event that's hard to predict and probably rare. In both cases, users aren't going to be satisfied with anything you send them. They don't care about your bugs and they will have no clue about a rare weird event. So handle cases that make sense - e.g. if a user selects a file that doesn't exist, *that's* a reasonable "error" to handle gracefully. But that falls into the data validation case and it's business logic IMO - not lower level "what do I do if I can't read a file" error. In any case, I'd handle user facing issues from a level above the function in question. On Fri, Aug 14, 2015 at 6:29 AM, Roelof Wobben wrote: > Thanks, > > So it's fine to give this a error message : > > ** exception error: {read_file,"wrong.txt",enoent} in function > my_file:read/1 (my_file.erl, line 8)) > > I think a unexperience users still does not know what went wrong. > That's is why I choose for a more human readable error message( File not > found or something else). > > Roelof > > ** exception error: {read_file,"wrong.txt",enoent} > in function my_file:read/1 (my_file.erl, line 8) > > > > Op 14-8-2015 om 13:17 schreef Garrett Smith: > >> This function does two things that are unrelated, it returns a file >> and it prints a message to stdout. >> >> >> https://github.com/rwobben/programming_erlang_exercises/blob/master/chapter_6/my_file.erl#L8 >> >> Erlang uses two different patterns for surfacing errors from functions... >> >> Tagged tuples: >> >> do() -> {ok, Value} | {error, Error} | error >> >> and exceptions: >> >> do() -> Value >> >> In the first form, the caller must handle the value accordingly. >> dict:find/2 is an example of this: >> >> http://erlang.org/doc/man/dict.html#find-2 >> >> It's important in this case to use patterns that can differentiate >> between a good value and an error. We use {ok, Value} and {error, >> Error} respectively. If the error doesn't have or need any detail, use >> the atom error by itself. Don't do this though: >> >> do() -> Value | {error, Error} | error >> >> as it forces an order of pattern matching (and precludes error >> tuples/atom as valid results), which is easily avoided by tagging the >> good value as {ok, Value}. >> >> In the second form, the caller can safely assume that the value is >> correct, otherwise an exception would be raised (which doesn't have to >> be handled, though can be). dict:fetch/2 is an example of this: >> >> http://erlang.org/doc/man/dict.html#fetch-2 >> >> There's never a case IMO where a function should handle an error >> internally by printing a message somewhere and returning the atom ok, >> which is what your function does. Imagine the chagrin of a caller >> assuming everything is fine, then discovering that ok is not a binary, >> failing. Then what, a human has to screen scrape stdout somewhere? >> This reminds me of a common Java pattern: >> >> try { >> return do(); >> catch (Exception e) { >> e.printStackTrace(); >> return null; >> } >> >> As horrifying as this code is (truly) I see it *all the time*. >> >> People often ask which form of error surfacing is correct here - >> tagged tuples or exception. Both are correct and should be used - but >> according to the intent of the function. The dict module I think is a >> great example (find vs fetch). >> >> In my own practice, I tend to follow this order of progression: >> >> - Functions return good values, not tagged tuples >> >> - Avoid any non "happy path" code and let Erlang deal with the >> unhandled cases - i.e. your code only reflects what you care about >> handling, nothing else >> >> - In cases where a function itself (internally) has to deal with a >> tagged error, raise an error with appropriate context >> >> - If the function is low enough level that *it's job* is to surface >> *either* success or failure, then IMO it must use tagged tuples - >> that's its design and not a matter of aesthetics >> >> So, again, in progression of thinking, I'd start your function off like >> this: >> >> read(File) -> >> {ok, Bin} = file:read_file(File), >> Bin. >> >> The caller doesn't have to worry about getting some weird value and >> Erlang will stop dead in its tracks if there's a problem reading that >> file. Perfect! >> >> Except that in this case, you'll get a 'bad match' error that will >> complain about an error result, but it won't tell you about the file >> involved. So being slightly speculative about needing that information >> in case of an error, I'd write it this way: >> >> read(File) -> >> case file:read_file(File) of >> {ok, Bin}-> Bin ; >> {error, Err} -> error({read_file, File, Err}) >> end. >> >> But I concede that this is speculative - it's just in this case I have >> enough experience with this type of function to know that I'll >> certainly be interested in the file if something's wrong (this is >> obvious). But by default, I'd avoid that speculation and get some >> experience running the code to tell me if I need to take the next step >> of handling error cases explicitly and generating fuller-context >> exceptions. My motive there is to avoid typing *any* error handling >> code at all. That's IMO the right starting point. Then, let yourself >> be dragged reluctantly into error handling code by experience. >> >> In any case, stick to the two conventions here of surfacing errors. >> >> Otherwise from what I saw things look great! >> >> Now find *something to build* :) >> >> On Fri, Aug 14, 2015 at 3:29 AM, Roelof Wobben wrote: >>> >>> Hello, >>> >>> I did the first 6 chapters of the Erlang programming book second editon. >>> >>> Now I wonder if I did things the righr way and if there are any >>> improvements. >>> >>> My code can be found here: >>> https://github.com/rwobben/programming_erlang_exercises >>> >>> I did not do the chapter 5 exercises because then you need to use map and >>> that one is in R17 where I work on R16. >>> >>> Roelof >>> >>> >>> --- >>> Dit e-mailbericht is gecontroleerd op virussen met Avast >>> antivirussoftware. >>> https://www.avast.com/antivirus >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions > > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From neerajsharma.live@REDACTED Fri Aug 14 13:52:13 2015 From: neerajsharma.live@REDACTED (Neeraj Sharma) Date: Fri, 14 Aug 2015 17:22:13 +0530 Subject: [erlang-questions] Who is interested in an Erlang Performance Improvement Book? In-Reply-To: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> References: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> Message-ID: Sounds great! There are number of open source Erlang projects out there, although covering even a fraction does require a lot of work but definitely very useful for users like me. I would even take this forward and think about some of the best practices in terms of design/arch, but that would be push it too far and probably a different project altogether. -Neeraj On Tue, Aug 11, 2015 at 11:30 AM, Robert Kowalski wrote: > Hi list, > > I wrote an article how to learn Erlang by example [1] which got a lot of > good feedback recently when it was posted on HN. > > The past weeks I am working on finding bottlenecks and try to improve the > performance of Erlang Open Source projects. > > Based on my work, findings and insights I was asking myself if you would > be interested in a book about way to measure and improve Erlang > performance. Like my blogpost it would use real world examples, this time > from more Open Source Erlang projects. > > What do you think? > > Best, > Robert > > > [1] > http://robert-kowalski.de/blog/lets-learn-erlang-and-fix-a-bug-on-a-couchdb-cluster/ > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mrtndimitrov@REDACTED Fri Aug 14 13:53:59 2015 From: mrtndimitrov@REDACTED (Martin Koroudjiev) Date: Fri, 14 Aug 2015 14:53:59 +0300 Subject: [erlang-questions] Who is interested in an Erlang Performance Improvement Book? In-Reply-To: References: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> Message-ID: <55CDD6D7.3040304@gmail.com> Would be extremely useful! On 8/14/2015 11:25 AM, Carlos Gonz?lez Florido wrote: > Of course! > > > On Thu, Aug 13, 2015 at 10:04 PM, Rodolfo Dias > wrote: > > > > +1 > > > > 2015-08-11 3:00 GMT-03:00 Robert Kowalski >: > >> > >> Hi list, > >> > >> I wrote an article how to learn Erlang by example [1] which got a > lot of good feedback recently when it was posted on HN. > >> > >> The past weeks I am working on finding bottlenecks and try to > improve the performance of Erlang Open Source projects. > >> > >> Based on my work, findings and insights I was asking myself if you > would be interested in a book about way to measure and improve Erlang > performance. Like my blogpost it would use real world examples, this > time from more Open Source Erlang projects. > >> > >> What do you think? > >> > >> Best, > >> Robert > >> > >> > >> [1] > http://robert-kowalski.de/blog/lets-learn-erlang-and-fix-a-bug-on-a-couchdb-cluster/ > >> > >> _______________________________________________ > >> erlang-questions mailing list > >> erlang-questions@REDACTED > >> http://erlang.org/mailman/listinfo/erlang-questions > >> > > > > > > _______________________________________________ > > erlang-questions mailing list > > erlang-questions@REDACTED > > http://erlang.org/mailman/listinfo/erlang-questions > > > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- An HTML attachment was scrubbed... URL: From essen@REDACTED Fri Aug 14 13:58:54 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Fri, 14 Aug 2015 13:58:54 +0200 Subject: [erlang-questions] Who is interested in an Erlang Performance Improvement Book? In-Reply-To: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> References: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> Message-ID: <55CDD7FE.10205@ninenines.eu> Hey, What could be interesting to me is not so much the process one can use to detect performance issues and bottlenecks and solve them, but a fully automated way to ensure that the performance doesn't degrade with bug fixes and other changes. In other words: we have fantastic test tools to ensure we don't add new bugs with each commit; what would you do to make sure you don't kill performance with each commit? A good answer to that alone would be worth a thousand books on performance. Cheers, On 08/11/2015 08:00 AM, Robert Kowalski wrote: > Hi list, > > I wrote an article how to learn Erlang by example [1] which got a lot of > good feedback recently when it was posted on HN. > > The past weeks I am working on finding bottlenecks and try to improve > the performance of Erlang Open Source projects. > > Based on my work, findings and insights I was asking myself if you would > be interested in a book about way to measure and improve Erlang > performance. Like my blogpost it would use real world examples, this > time from more Open Source Erlang projects. > > What do you think? > > Best, > Robert > > > [1] > http://robert-kowalski.de/blog/lets-learn-erlang-and-fix-a-bug-on-a-couchdb-cluster/ > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From kxepal@REDACTED Fri Aug 14 14:12:15 2015 From: kxepal@REDACTED (Alexander Shorin) Date: Fri, 14 Aug 2015 15:12:15 +0300 Subject: [erlang-questions] Who is interested in an Erlang Performance Improvement Book? In-Reply-To: <55CDD7FE.10205@ninenines.eu> References: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> <55CDD7FE.10205@ninenines.eu> Message-ID: On Fri, Aug 14, 2015 at 2:58 PM, Lo?c Hoguin wrote: > > In other words: we have fantastic test tools to ensure we don't add new bugs > with each commit; what would you do to make sure you don't kill performance > with each commit? > > A good answer to that alone would be worth a thousand books on performance. Golang had used special benchmark test suite which ran on each commit against various configurations[1] and it was quite trivial to detect which commit caused performance and for what case, but suddenly it doesn't works anymore. Some bits web archive still remember[2] about how it looked like. But in general, solution of this problem is the same: make benchmarks as yet another test suite and track how long it being executed, not just ok/error status. At some point turning integration tests into benchmarks might be good idea. [1]: http://build.golang.org/perfgraph [2]: https://web.archive.org/web/20140825015726/http://build.golang.org/perfgraph -- ,,,^..^,,, From essen@REDACTED Fri Aug 14 14:28:38 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Fri, 14 Aug 2015 14:28:38 +0200 Subject: [erlang-questions] Who is interested in an Erlang Performance Improvement Book? In-Reply-To: References: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> <55CDD7FE.10205@ninenines.eu> Message-ID: <55CDDEF6.2010606@ninenines.eu> On 08/14/2015 02:12 PM, Alexander Shorin wrote: > On Fri, Aug 14, 2015 at 2:58 PM, Lo?c Hoguin wrote: >> >> In other words: we have fantastic test tools to ensure we don't add new bugs >> with each commit; what would you do to make sure you don't kill performance >> with each commit? >> >> A good answer to that alone would be worth a thousand books on performance. > > Golang had used special benchmark test suite which ran on each commit > against various configurations[1] and it was quite trivial to detect > which commit caused performance and for what case, but suddenly it > doesn't works anymore. Some bits web archive still remember[2] about > how it looked like. > > But in general, solution of this problem is the same: make benchmarks > as yet another test suite and track how long it being executed, not > just ok/error status. At some point turning integration tests into > benchmarks might be good idea. The time spent to run X is the worst kind of benchmark value you can rely on though. In Erlang for example you may replace some code with a NIF (or even a BIF), effectively making these benchmarks faster, only to find out later that it makes the whole system slower when you have 100k processes using it concurrently. Or perhaps a piece of code will run faster, but with double memory usage. Or the latency suffers. Etc. One thing for sure is that you need a benchmark test suite, but how to set it up to make sure the system as a whole benefits from all the changes is a guide I've never seen written. -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From snowwlex@REDACTED Fri Aug 14 13:49:19 2015 From: snowwlex@REDACTED (Alexander Turkin) Date: Fri, 14 Aug 2015 12:49:19 +0100 Subject: [erlang-questions] utf-8 and xmerl Message-ID: Dear list, I've got a problem with unicode & xmerl library. Input data for xmerl is utf-8 encoded xml, and what I've got as the result is encoded latin1. But I need utf8! EXAMPLES Body = <<"Ren?"/utf8>>. (for the sake of portability here is term_to_binary(Body): <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, 115,112,111,110,115,101,62>> (1): When I do xmerl_scan:string(binary_to_list(Body)). it returns {#xmlElement{name = response,expanded_name = response, nsinfo = [], namespace = #xmlNamespace{default = [],nodes = []}, parents = [],pos = 1,attributes = [], content = [#xmlElement{name = value,expanded_name = value, nsinfo = [], namespace = #xmlNamespace{default = [],nodes = []}, parents = [{response,1}], pos = 1,attributes = [], content = [#xmlText{parents = [{value,1},{response,1}], pos = 1,language = [], value = "Ren?", type = text}], language = [],xmlbase = "/Users/aturkin/ws/", elementdef = undeclared}], language = [],xmlbase = "/Users/aturkin/ws/", elementdef = undeclared}, []} So, note there is `value = "Ren?"` string, and it uses [233] symbol, which is latin1. (2): xmerl_scan:string(xmerl_ucs:to_utf8(binary_to_list(Body))) returns {#xmlElement{name = response,expanded_name = response, nsinfo = [], namespace = #xmlNamespace{default = [],nodes = []}, parents = [],pos = 1,attributes = [], content = [#xmlElement{name = value,expanded_name = value, nsinfo = [], namespace = #xmlNamespace{default = [],nodes = []}, parents = [{response,1}], pos = 1,attributes = [], content = [#xmlText{parents = [{value,1},{response,1}], pos = 1,language = [], value = "Ren??", type = text}], language = [],xmlbase = "/Users/aturkin/ws/", elementdef = undeclared}], language = [],xmlbase = "/Users/aturkin/ws/", elementdef = undeclared}, []} Now `value = "Ren??"`, so 2 bytes are used to code this symbol, and this is utf-8. So in (2) I get what I need, but why I need to force that conversion for xmerl? QUESTIONS 1. I don't understand why xmerl_scan allows you to set input encoding, but it looks like there is no way to set output encoding. Is there any way to make xmerl_scan to return utf8 instead of latin1? 2. How is that happen, that in (1) it does conversion utf-8 -> latin1, and in (2) it's utf-8? -- Best Regards, Alex Turkin -------------- next part -------------- An HTML attachment was scrubbed... URL: From kxepal@REDACTED Fri Aug 14 14:36:54 2015 From: kxepal@REDACTED (Alexander Shorin) Date: Fri, 14 Aug 2015 15:36:54 +0300 Subject: [erlang-questions] Who is interested in an Erlang Performance Improvement Book? In-Reply-To: <55CDDEF6.2010606@ninenines.eu> References: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> <55CDD7FE.10205@ninenines.eu> <55CDDEF6.2010606@ninenines.eu> Message-ID: On Fri, Aug 14, 2015 at 3:28 PM, Lo?c Hoguin wrote: > On 08/14/2015 02:12 PM, Alexander Shorin wrote: >> >> On Fri, Aug 14, 2015 at 2:58 PM, Lo?c Hoguin wrote: >>> >>> >>> In other words: we have fantastic test tools to ensure we don't add new >>> bugs >>> with each commit; what would you do to make sure you don't kill >>> performance >>> with each commit? >>> >>> A good answer to that alone would be worth a thousand books on >>> performance. >> >> >> Golang had used special benchmark test suite which ran on each commit >> against various configurations[1] and it was quite trivial to detect >> which commit caused performance and for what case, but suddenly it >> doesn't works anymore. Some bits web archive still remember[2] about >> how it looked like. >> >> But in general, solution of this problem is the same: make benchmarks >> as yet another test suite and track how long it being executed, not >> just ok/error status. At some point turning integration tests into >> benchmarks might be good idea. > > > The time spent to run X is the worst kind of benchmark value you can rely on > though. > > In Erlang for example you may replace some code with a NIF (or even a BIF), > effectively making these benchmarks faster, only to find out later that it > makes the whole system slower when you have 100k processes using it > concurrently. > > Or perhaps a piece of code will run faster, but with double memory usage. Or > the latency suffers. Etc. > > One thing for sure is that you need a benchmark test suite, but how to set > it up to make sure the system as a whole benefits from all the changes is a > guide I've never seen written. Good points. But if we move from "speed of code" to "behaviour of code", then for such comprehensive measurements we eventually involve monitoring systems into the process which also need to register "side effects" of the underlying system to make results more or less clear to understand. This all turns into good infrastructure setup task and devops domain. -- ,,,^..^,,, From jesper.louis.andersen@REDACTED Fri Aug 14 15:14:57 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Fri, 14 Aug 2015 15:14:57 +0200 Subject: [erlang-questions] Who is interested in an Erlang Performance Improvement Book? In-Reply-To: <55CDDEF6.2010606@ninenines.eu> References: <20150810212624.1059.82914@domU-12-31-39-0A-A0-4F> <55CDD7FE.10205@ninenines.eu> <55CDDEF6.2010606@ninenines.eu> Message-ID: On Fri, Aug 14, 2015 at 2:28 PM, Lo?c Hoguin wrote: > The time spent to run X is the worst kind of benchmark value you can rely > on though. This would be a worry of me as well. The Go benchmark runner is better than nothing, but it is highly naive. One, it doesn't try to figure out garbage collector interference. Two, it doesn't cook benchmarks until they reach a stable state. Three, it doesn't carry out the proper statistics. A simple bootstrapping analysis of the average could tell you if the average is stable or is perturbed by some internal thing in the system. The problem may not even be tied to the Erlang node. When you are measuring highly sensitive benchmarks at the nanosecond scale, a simple interrupt may be enough to mess up the benchmark. And you can't in general control for this in a complex environment. -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From eric.pailleau@REDACTED Fri Aug 14 18:23:36 2015 From: eric.pailleau@REDACTED (=?ISO-8859-1?Q?=C9ric_Pailleau?=) Date: Fri, 14 Aug 2015 18:23:36 +0200 Subject: [erlang-questions] utf-8 and xmerl In-Reply-To: Message-ID: <55733d25-129c-4f19-94a3-4e15fc22b692@email.android.com> Hello, Please precise what Erlang release you are using. Utf8 came lately in Erlang. Regards Le?14 ao?t 2015 13:49, Alexander Turkin a ?crit?: > > Dear list, > > > I've got a problem with unicode & xmerl library. > > Input data for xmerl is utf-8 encoded xml, and what I've got as the result is encoded latin1. But I need utf8! > > > EXAMPLES > > Body = <<"Ren?"/utf8>>. > > (for the sake of portability here is term_to_binary(Body):? > > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, > ? 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, > ? 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, > ? 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, > ? 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, > ? 115,112,111,110,115,101,62>> > > > > (1): > > When I do? > > xmerl_scan:string(binary_to_list(Body)). > > it returns? > > {#xmlElement{name = response,expanded_name = response, > ? ? ? ? ? ? ?nsinfo = [], > ? ? ? ? ? ? ?namespace = #xmlNamespace{default = [],nodes = []}, > ? ? ? ? ? ? ?parents = [],pos = 1,attributes = [], > ? ? ? ? ? ? ?content = [#xmlElement{name = value,expanded_name = value, > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? nsinfo = [], > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? namespace = #xmlNamespace{default = [],nodes = []}, > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? parents = [{response,1}], > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pos = 1,attributes = [], > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? content = [#xmlText{parents = [{value,1},{response,1}], > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pos = 1,language = [], > > > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? value = "Ren?", > > > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? type = text}], > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? language = [],xmlbase = "/Users/aturkin/ws/", > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? elementdef = undeclared}], > ? ? ? ? ? ? ?language = [],xmlbase = "/Users/aturkin/ws/", > ? ? ? ? ? ? ?elementdef = undeclared}, > ?[]} > > > So, note there is `value = "Ren?"` string, and it uses [233] symbol, which is latin1. > > > > > (2): > > xmerl_scan:string(xmerl_ucs:to_utf8(binary_to_list(Body))) > > returns? > > {#xmlElement{name = response,expanded_name = response, > ? ? ? ? ? ? ?nsinfo = [], > ? ? ? ? ? ? ?namespace = #xmlNamespace{default = [],nodes = []}, > ? ? ? ? ? ? ?parents = [],pos = 1,attributes = [], > ? ? ? ? ? ? ?content = [#xmlElement{name = value,expanded_name = value, > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? nsinfo = [], > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? namespace = #xmlNamespace{default = [],nodes = []}, > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? parents = [{response,1}], > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pos = 1,attributes = [], > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? content = [#xmlText{parents = [{value,1},{response,1}], > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pos = 1,language = [], > > > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? value = "Ren??", > > > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? type = text}], > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? language = [],xmlbase = "/Users/aturkin/ws/", > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? elementdef = undeclared}], > ? ? ? ? ? ? ?language = [],xmlbase = "/Users/aturkin/ws/", > ? ? ? ? ? ? ?elementdef = undeclared}, > ?[]} > > Now `value = "Ren??"`, so 2 bytes are used to code this symbol, and this is utf-8. > > So in (2) I get what I need, but why I need to force that conversion for xmerl?? > > > > > QUESTIONS > > 1. I don't understand why xmerl_scan allows you to set input encoding, but it looks like there is no way to set output encoding. Is there any way to make xmerl_scan to return utf8 instead of latin1? > > 2. How is that happen, that in (1) it does conversion utf-8 -> latin1, and in (2) it's utf-8? > > > > > -- > Best Regards, > Alex Turkin From christopher.meiklejohn@REDACTED Fri Aug 14 18:29:29 2015 From: christopher.meiklejohn@REDACTED (Christopher Meiklejohn) Date: Fri, 14 Aug 2015 12:29:29 -0400 Subject: [erlang-questions] "The Implementation and Use of a Generic Dataflow Behaviour in Erlang" preprint available Message-ID: Given there's been some discussion over the past few months on dataflow programming in Erlang, I wanted to share a preprint of our Erlang Workshop '15 paper on dataflow programming abstractions. This code was extracted from, and used to build, a series of academic prototypes on distributed computation as part of the SyncFree research project; specifically, Derflow, DerflowL, and Lasp. Here's a link to the paper: "The Implementation and Use of a Generic Dataflow Behaviour in Erlang" http://christophermeiklejohn.com/publications/erlang-workshop-2015-preprint.pdf And, here's a link to the Lasp repository, which contains an implementation of our prototype: https://github.com/lasp-lang/lasp Thanks! - Christopher From sid5@REDACTED Fri Aug 14 17:52:25 2015 From: sid5@REDACTED (Sid Muller) Date: Fri, 14 Aug 2015 17:52:25 +0200 Subject: [erlang-questions] ** exception exit: shutdown In-Reply-To: References: , Message-ID: An HTML attachment was scrubbed... URL: From jesper.louis.andersen@REDACTED Fri Aug 14 22:17:19 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Fri, 14 Aug 2015 22:17:19 +0200 Subject: [erlang-questions] [ANN] enacl v0.14.0 - NaCl/libsodium encryption for Erlang Message-ID: Hi Erlangers, I've just pushed enacl version 0.14.0. It is a bindings for the libsodium library from Frank Denis for Erlang. Since the last 0.9.0 release I announced in December 2014, the following changes have been made: ### v0.14.0 * Add support for libsodiums `box_seal` functions (Amir Ghassemi Nasr) * Add support for libsodiums `crypto_sign_detached` (Joel Stanley, Parnell Springmeyer) * Switch the tag names to the form `0.14.0` rather than `v0.14.0`. For this release both tags are present, but from the next release on, it won't be the case. ### v0.13.0 * Quell warnings from the C code * Add Ed 25519 utility API (Alexander F?r?y) * Add FreeBSD support for the NIF compilation (Ricardo Lanziano) ### v0.12.1 * Provide the `priv` directory for being able to properly build without manual intervention. ### v0.12.0 * Introduce an extension interface for various necessary extensions to the eNaCl system for handling the Tor network, thanks to Alexander F?r?y (ahf). * Introduce Curve25519 manipulations into the extension interface. * Write (rudimentary) QuickCheck tests for the new interface, to verify its correctness. ### v0.11.0 * Introduce NIF layer beforenm/afternm calls. * Introduce the API for precomputed keys (beforenm/afternm calls). * Use test cases which tries to inject `iodata()` rather than binaries in all places where `iodata()` tend to be accepted. * Fix type for `enacl:box_open/4`. The specification was wrong which results in errors in other applications using enacl. ### v0.10.2 Maintenance release. Fix some usability problems with the library. * Do not compile the C NIF code if there are no dirty scheduler support in the Erlang system (Thanks to David N. Welton) * Fix dialyzer warnings (Thanks Anthony Ramine) * Fix a wrong call in the timing code. Luckily, this error has not affected anything as it has only replaced a verification call with one that does not verify. In practice, the timing is roughly the same for both, save for a small constant factor (Thanks to the dialyzer) * Improve documentation around installation/building the software. Hopefully it is now more prominent (Thanks to David N. Welton) ### v0.10.1 This small patch-release provides tests for the `randombytes/1` function call, and optimizes EQC tests to make it easier to implement `largebinary`-support in EQC tests. The release also adds an (experimental) scrambling function for hiding the internal structure of counters. This is based on an enlarged TEA-cipher by Wheeler and Needham. It is neccessary for correct operation of the CurveCP implementation, which is why it is included in this library. ### v0.10.0 Ultra-late beta; tuning for the last couple of functions which could be nice to have. Added the function `randombytes/1` to obtain randombytes from the operating system. The system uses the "best" applicable (P)RNG on the target system: * Windows: `RtlGenRandom()` * OpenBSD, Bitrig: `arc4random()` * Unix in general: `/dev/urandom` Do note that on Linux and FreeBSD at the *least*, this is the best thing you can do. Relying on `/dev/random` is almost always wrong and gives no added security benefit. Key generation in NaCl relies on `/dev/urandom`. Go relies on `/dev/urandom`. It is about time Erlang does as well. -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From lloyd@REDACTED Sat Aug 15 03:50:04 2015 From: lloyd@REDACTED (Lloyd R. Prentice) Date: Fri, 14 Aug 2015 21:50:04 -0400 Subject: [erlang-questions] [ANN] enacl v0.14.0 - NaCl/libsodium encryption for Erlang In-Reply-To: References: Message-ID: Hi Jesper, Congratulations! But... Could you please provide a paragraph or so to describe what enacl is and what problems it solves? Yes, I can and will look up NaCl/libsodium on the web. But my larger point is that I run across so many intriguing sounding Erlang libraries and applications that have little to no meta description to help me decide how much effort I should invest to understand them. That said, you're still near the very top of my hero list. All the best, Lloyd Sent from my iPad > On Aug 14, 2015, at 4:17 PM, Jesper Louis Andersen wrote: > > Hi Erlangers, > > I've just pushed enacl version 0.14.0. > > It is a bindings for the libsodium library from Frank Denis for Erlang. > > Since the last 0.9.0 release I announced in December 2014, the following changes have been made: > > ### v0.14.0 > > * Add support for libsodiums `box_seal` functions (Amir Ghassemi Nasr) > * Add support for libsodiums `crypto_sign_detached` (Joel Stanley, Parnell Springmeyer) > * Switch the tag names to the form `0.14.0` rather than `v0.14.0`. For this release both tags are present, but > from the next release on, it won't be the case. > > ### v0.13.0 > > * Quell warnings from the C code > * Add Ed 25519 utility API (Alexander F?r?y) > * Add FreeBSD support for the NIF compilation (Ricardo Lanziano) > > ### v0.12.1 > > * Provide the `priv` directory for being able to properly build without manual intervention. > > ### v0.12.0 > > * Introduce an extension interface for various necessary extensions to the eNaCl system for handling the Tor network, thanks to Alexander F?r?y (ahf). > * Introduce Curve25519 manipulations into the extension interface. > * Write (rudimentary) QuickCheck tests for the new interface, to verify its correctness. > > ### v0.11.0 > > * Introduce NIF layer beforenm/afternm calls. > * Introduce the API for precomputed keys (beforenm/afternm calls). > * Use test cases which tries to inject `iodata()` rather than binaries in all places where `iodata()` tend to be accepted. > * Fix type for `enacl:box_open/4`. The specification was wrong which results in errors in other applications using enacl. > > ### v0.10.2 > > Maintenance release. Fix some usability problems with the library. > > * Do not compile the C NIF code if there are no dirty scheduler support in the Erlang system (Thanks to David N. Welton) > * Fix dialyzer warnings (Thanks Anthony Ramine) > * Fix a wrong call in the timing code. Luckily, this error has not affected anything as it has only replaced a verification call with one that does not verify. In practice, the timing is roughly the same for both, save for a small constant factor (Thanks to the dialyzer) > * Improve documentation around installation/building the software. Hopefully it is now more prominent (Thanks to David N. Welton) > > ### v0.10.1 > > This small patch-release provides tests for the `randombytes/1` function call, and optimizes EQC tests to make it easier to implement `largebinary`-support in EQC tests. The release also adds an (experimental) scrambling function for hiding the internal structure of counters. This is based on an enlarged TEA-cipher by Wheeler and Needham. It is neccessary for correct operation of the CurveCP implementation, which is why it is included in this library. > > ### v0.10.0 > > Ultra-late beta; tuning for the last couple of functions which could be nice to have. Added the function `randombytes/1` to obtain randombytes from the operating system. The system uses the "best" applicable (P)RNG on the target system: > > * Windows: `RtlGenRandom()` > * OpenBSD, Bitrig: `arc4random()` > * Unix in general: `/dev/urandom` > > Do note that on Linux and FreeBSD at the *least*, this is the best thing you can do. Relying on `/dev/random` is almost always wrong and gives no added security benefit. Key generation in NaCl relies on `/dev/urandom`. Go relies on `/dev/urandom`. It is about time Erlang does as well. > > > -- > J. > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From sid5@REDACTED Sat Aug 15 06:21:33 2015 From: sid5@REDACTED (Sid Muller) Date: Sat, 15 Aug 2015 06:21:33 +0200 Subject: [erlang-questions] ** exception exit: shutdown : SOLVED dets_server:stop(). In-Reply-To: References: , , Message-ID: An HTML attachment was scrubbed... URL: From vychodil.hynek@REDACTED Sat Aug 15 09:30:34 2015 From: vychodil.hynek@REDACTED (Hynek Vychodil) Date: Sat, 15 Aug 2015 09:30:34 +0200 Subject: [erlang-questions] utf-8 and xmerl In-Reply-To: <55733d25-129c-4f19-94a3-4e15fc22b692@email.android.com> References: <55733d25-129c-4f19-94a3-4e15fc22b692@email.android.com> Message-ID: The same result is in R18 and it it correct result. Letter ? has unicode 233 see http://unicode-table.com/en/#00E9 On Fri, Aug 14, 2015 at 6:23 PM, ?ric Pailleau wrote: > Hello, > Please precise what Erlang release you are using. Utf8 came lately in > Erlang. > Regards > > Le 14 ao?t 2015 13:49, Alexander Turkin a ?crit : > > > > Dear list, > > > > > > I've got a problem with unicode & xmerl library. > > > > Input data for xmerl is utf-8 encoded xml, and what I've got as the > result is encoded latin1. But I need utf8! > > > > > > EXAMPLES > > > > Body = <<" encoding=\"UTF-8\"?>Ren?"/utf8>>. > > > > (for the sake of portability here is term_to_binary(Body): > > > > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, > > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, > > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, > > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, > > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, > > 115,112,111,110,115,101,62>> > > > > > > > > (1): > > > > When I do > > > > xmerl_scan:string(binary_to_list(Body)). > > > > it returns > > > > {#xmlElement{name = response,expanded_name = response, > > nsinfo = [], > > namespace = #xmlNamespace{default = [],nodes = []}, > > parents = [],pos = 1,attributes = [], > > content = [#xmlElement{name = value,expanded_name = value, > > nsinfo = [], > > namespace = #xmlNamespace{default = > [],nodes = []}, > > parents = [{response,1}], > > pos = 1,attributes = [], > > content = [#xmlText{parents = > [{value,1},{response,1}], > > pos = 1,language > = [], > > > > > > value = "Ren?", > > > > > > type = text}], > > language = [],xmlbase = > "/Users/aturkin/ws/", > > elementdef = undeclared}], > > language = [],xmlbase = "/Users/aturkin/ws/", > > elementdef = undeclared}, > > []} > > > > > > So, note there is `value = "Ren?"` string, and it uses [233] symbol, > which is latin1. > > > > > > > > > > (2): > > > > xmerl_scan:string(xmerl_ucs:to_utf8(binary_to_list(Body))) > > > > returns > > > > {#xmlElement{name = response,expanded_name = response, > > nsinfo = [], > > namespace = #xmlNamespace{default = [],nodes = []}, > > parents = [],pos = 1,attributes = [], > > content = [#xmlElement{name = value,expanded_name = value, > > nsinfo = [], > > namespace = #xmlNamespace{default = > [],nodes = []}, > > parents = [{response,1}], > > pos = 1,attributes = [], > > content = [#xmlText{parents = > [{value,1},{response,1}], > > pos = 1,language > = [], > > > > > > value = "Ren??", > > > > > > type = text}], > > language = [],xmlbase = > "/Users/aturkin/ws/", > > elementdef = undeclared}], > > language = [],xmlbase = "/Users/aturkin/ws/", > > elementdef = undeclared}, > > []} > > > > Now `value = "Ren??"`, so 2 bytes are used to code this symbol, and this > is utf-8. > > > > So in (2) I get what I need, but why I need to force that conversion for > xmerl? > > > > > > > > > > QUESTIONS > > > > 1. I don't understand why xmerl_scan allows you to set input encoding, > but it looks like there is no way to set output encoding. Is there any way > to make xmerl_scan to return utf8 instead of latin1? > > > > 2. How is that happen, that in (1) it does conversion utf-8 -> latin1, > and in (2) it's utf-8? > > > > > > > > > > -- > > Best Regards, > > Alex Turkin > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From eric.pailleau@REDACTED Sat Aug 15 10:05:00 2015 From: eric.pailleau@REDACTED (=?ISO-8859-1?Q?=C9ric_Pailleau?=) Date: Sat, 15 Aug 2015 10:05:00 +0200 Subject: [erlang-questions] utf-8 and xmerl In-Reply-To: Message-ID: An HTML attachment was scrubbed... URL: From erlang@REDACTED Sat Aug 15 16:56:37 2015 From: erlang@REDACTED (Joe Armstrong) Date: Sat, 15 Aug 2015 16:56:37 +0200 Subject: [erlang-questions] Some functions must return values other may do so... Message-ID: For a while now I've adopted a convention for naming functions which I find rather useful, so I thought I'd discuss it here, (it's a kind of RFC-2119 lite notation :-) Rule1: Functions which return {ok,X} | {error,W} are called may_ Rule2: Functions which return a value or raise an exception are called must_ I use a small interface library which enforced this, for example, I have a wrapper round file:open which looks like this: must_open_file(File, Mode) -> case file:open(File, Mode) of {ok, X} -> X; {error, E} -> exit({most_open,File,in_mode,Mode,failed,E}) end. may_open_file(File, Mode) -> file:open(File, Mode). Using this convention dict:find(Key, D) should be called may_get(Key, Dict) dict:fetch(Key, D) should be renames must_get(Key, Dict) With this convention I can write code like: must_sequence() -> Handle = must_open_file("some_file_which_i_know_must_exist.txt", [read]), Data = must_read_file(Handle), must_write_file("fileout", Data). must_close_file(Handle). Or, when "file" might exist, I'd write: test1() -> case may_open_file("file", [read]) of {ok, Handle} -> ... {error, _} -> .. do something else ... end. may_ function are *always* called from case statements must_ function are called in linear code with no case statements I usually also wrap the top level call to a sequence of must_* functions in a catch, something like: top() -> case (catch must_sequence()) of {'EXIT', What} -> ... do some recovery stuff ... Ok -> Ok end. Code written using the must/may convention seems to be extremely easy to read, since from the name of the function I don't have to speculate as to the form of the return value - I know immediately if the function will raise and exception on error or give an ok/error return value. Cheers /Joe From erlang@REDACTED Sat Aug 15 16:59:12 2015 From: erlang@REDACTED (Joe Armstrong) Date: Sat, 15 Aug 2015 16:59:12 +0200 Subject: [erlang-questions] feedback on my solutions to programming erlang second edition In-Reply-To: References: <55CDA6CD.2050501@home.nl> Message-ID: On Fri, Aug 14, 2015 at 1:17 PM, Garrett Smith wrote: > This function does two things that are unrelated, it returns a file > and it prints a message to stdout. > > https://github.com/rwobben/programming_erlang_exercises/blob/master/chapter_6/my_file.erl#L8 > > Erlang uses two different patterns for surfacing errors from functions... > > Tagged tuples: > > do() -> {ok, Value} | {error, Error} | error > > and exceptions: > > do() -> Value > > In the first form, the caller must handle the value accordingly. > dict:find/2 is an example of this: > > http://erlang.org/doc/man/dict.html#find-2 > > It's important in this case to use patterns that can differentiate > between a good value and an error. We use {ok, Value} and {error, > Error} respectively. If the error doesn't have or need any detail, use > the atom error by itself. Don't do this though: > > do() -> Value | {error, Error} | error > > as it forces an order of pattern matching (and precludes error > tuples/atom as valid results), which is easily avoided by tagging the > good value as {ok, Value}. > > In the second form, the caller can safely assume that the value is > correct, otherwise an exception would be raised (which doesn't have to > be handled, though can be). dict:fetch/2 is an example of this: > > http://erlang.org/doc/man/dict.html#fetch-2 > > There's never a case IMO where a function should handle an error > internally by printing a message somewhere and returning the atom ok, > which is what your function does. Imagine the chagrin of a caller > assuming everything is fine, then discovering that ok is not a binary, > failing. Then what, a human has to screen scrape stdout somewhere? > This reminds me of a common Java pattern: > > try { > return do(); > catch (Exception e) { > e.printStackTrace(); > return null; > } > > As horrifying as this code is (truly) I see it *all the time*. > > People often ask which form of error surfacing is correct here - > tagged tuples or exception. Both are correct and should be used - but > according to the intent of the function. The dict module I think is a > great example (find vs fetch). > > In my own practice, I tend to follow this order of progression: > > - Functions return good values, not tagged tuples > > - Avoid any non "happy path" code and let Erlang deal with the > unhandled cases - i.e. your code only reflects what you care about > handling, nothing else > > - In cases where a function itself (internally) has to deal with a > tagged error, raise an error with appropriate context > > - If the function is low enough level that *it's job* is to surface > *either* success or failure, then IMO it must use tagged tuples - > that's its design and not a matter of aesthetics > > So, again, in progression of thinking, I'd start your function off like this: > > read(File) -> > {ok, Bin} = file:read_file(File), > Bin. > > The caller doesn't have to worry about getting some weird value and > Erlang will stop dead in its tracks if there's a problem reading that > file. Perfect! > > Except that in this case, you'll get a 'bad match' error that will > complain about an error result, but it won't tell you about the file > involved. So being slightly speculative about needing that information > in case of an error, I'd write it this way: > > read(File) -> > case file:read_file(File) of > {ok, Bin}-> Bin ; > {error, Err} -> error({read_file, File, Err}) > end. > > But I concede that this is speculative - it's just in this case I have > enough experience with this type of function to know that I'll > certainly be interested in the file if something's wrong (this is > obvious). But by default, I'd avoid that speculation and get some > experience running the code to tell me if I need to take the next step > of handling error cases explicitly and generating fuller-context > exceptions. My motive there is to avoid typing *any* error handling > code at all. That's IMO the right starting point. Then, let yourself > be dragged reluctantly into error handling code by experience. I was going to reply on-line here but broke this into a separate mailing. It touches what I call the must/may convention - if you read my latest posting you'll see what I mean /Joe > > In any case, stick to the two conventions here of surfacing errors. > > Otherwise from what I saw things look great! > > Now find *something to build* :) > > On Fri, Aug 14, 2015 at 3:29 AM, Roelof Wobben wrote: >> Hello, >> >> I did the first 6 chapters of the Erlang programming book second editon. >> >> Now I wonder if I did things the righr way and if there are any >> improvements. >> >> My code can be found here: >> https://github.com/rwobben/programming_erlang_exercises >> >> I did not do the chapter 5 exercises because then you need to use map and >> that one is in R17 where I work on R16. >> >> Roelof >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From vojta.rylko@REDACTED Sat Aug 15 17:08:25 2015 From: vojta.rylko@REDACTED (=?UTF-8?Q?Vojt=C4=9Bch_Rylko?=) Date: Sat, 15 Aug 2015 17:08:25 +0200 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: References: Message-ID: We use function ok2def( { ok, X } ) -> X; ok2def( { error, E } ) -> throw( E ). then must_open_file becomes: must_open_file(File, Mode) -> ok2def( file:open(File, Mode) ). I hope you'll enjoy this shortcut (although thrown error is not so specific as in your's implementation). Cheers, Vojta 2015-08-15 16:56 GMT+02:00 Joe Armstrong : > For a while now I've adopted a convention for naming functions > which I find rather useful, so I thought I'd discuss it here, > (it's a kind of RFC-2119 lite notation :-) > > Rule1: Functions which return {ok,X} | {error,W} are called may_ > > Rule2: Functions which return a value or raise an exception are called > must_ > > I use a small interface library which enforced this, for example, > I have a wrapper round file:open which looks like this: > > must_open_file(File, Mode) -> > case file:open(File, Mode) of > {ok, X} -> > X; > {error, E} -> > exit({most_open,File,in_mode,Mode,failed,E}) > end. > > may_open_file(File, Mode) -> > file:open(File, Mode). > > Using this convention > > dict:find(Key, D) should be called may_get(Key, Dict) > dict:fetch(Key, D) should be renames must_get(Key, Dict) > > With this convention I can write code like: > > must_sequence() -> > Handle = must_open_file("some_file_which_i_know_must_exist.txt", > [read]), > Data = must_read_file(Handle), > must_write_file("fileout", Data). > must_close_file(Handle). > > Or, when "file" might exist, I'd write: > > test1() -> > case may_open_file("file", [read]) of > {ok, Handle} -> > ... > {error, _} -> > .. do something else ... > end. > > may_ function are *always* called from case statements > must_ function are called in linear code with no case statements > > I usually also wrap the top level call to a sequence of > must_* functions in a catch, something like: > > top() -> > case (catch must_sequence()) of > {'EXIT', What} -> > ... do some recovery stuff ... > Ok -> > Ok > end. > > Code written using the must/may convention seems to be extremely easy > to read, since from the name of the function I don't have to speculate > as > to the form of the return value - I know immediately if the function > will raise and exception on error or give an ok/error return value. > > Cheers > > /Joe > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From co7eb@REDACTED Sat Aug 15 19:52:19 2015 From: co7eb@REDACTED (Gilberio Carmenates Garcia) Date: Sat, 15 Aug 2015 13:52:19 -0400 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: References: Message-ID: <001401d0d783$23aad430$6b007c90$@co.cu> Hi Joe, hi every one, I would like to ask a little question, I like Erlang a lot, I must always say that, it is inevitable and that is why I suffer, because there is not Erlang Specific IDE. I am currently using IntelliJ IDEA with an erlang plugin and that is the best thing I ever seem. I am just a young cuban man of 31 years old who does not have any relevant employment, but I like Erlang and like to write its code like this: %% ------------------------------------------------- %% @doc %% This is a function that does nice stuffs %% NOTE: this does nice, %% almost always... %% @end %% ------------------------------------------------- -spec my_function(Name, Opts) -> {ok, Result} | {error, Reason} when Name :: atom(), Opts :: [{OptionName :: atom(), OptionValue :: any()}, ...], Result :: any(), Reason :: term(). my_function(Name, Opts) -> %% maybe some comments ... maybe some nice code ;). Or %% ... %% @exception %% may throw an exception if ... %% ------------------------------------------------- -spec my_function(Name, Opts) -> Result when ... Since specs where introduced Erlang definitely got elegancy. I almost always do that, no matter which function is or that it does if it is private I just use @private edoc tag. That makes code good looking in a nice IDE. And more when I can go over a function with the mouse and see its spec and edoc. Maybe adding all this to Joe's convention will look even better. i.e.: %% ------------------------------------------------- %% @doc %% This is a function that does nice stuffs %% NOTE: this does nice, %% almost always... %% @end %% ------------------------------------------------- -spec may_open(Name, Opts) -> {ok, Result} | {error, Reason} when Name :: atom(), Opts :: [{OptionName :: atom(), OptionValue :: any()}, ...], Result :: any(), Reason :: term(). may_open(Name, Opts) -> %% maybe some comments ... maybe some nice code ;). With must: %% ------------------------------------------------- %% @doc %% This is a function that does nice stuffs %% NOTE: this does nice, %% almost always... %% @end %% @exception %% will throw an error if ... %% ------------------------------------------------- -spec must_open(Name, Opts) -> Result when Name :: atom(), Opts :: [{OptionName :: atom(), OptionValue :: any()}, ...], Result :: any(). must_open(Name, Opts) -> %% maybe some comments ... maybe some nice code ;). Then when you get a lot of functions and you see @exception tag is in edoc and the name of the function is called must_ that seems like a perfect match to me, it will definitely become beautiful ;). So Why cannot Erlang have its nice IDE of its own? Always using tiny and uncomfortable IDEs like vim, or emacs, etc, etc. My intention is not to critique anything, rather than that, I am just expressing my self. I will like to post thoughts since time to time in this email list if you are so kind to let me. Cheers, Ivan (son of Gilberio). -----Mensaje original----- De: erlang-questions-bounces@REDACTED [mailto:erlang-questions-bounces@REDACTED] En nombre de Joe Armstrong Enviado el: s?bado, 15 de agosto de 2015 10:57 Para: Erlang Asunto: [erlang-questions] Some functions must return values other may do so... For a while now I've adopted a convention for naming functions which I find rather useful, so I thought I'd discuss it here, (it's a kind of RFC-2119 lite notation :-) Rule1: Functions which return {ok,X} | {error,W} are called may_ Rule2: Functions which return a value or raise an exception are called must_ I use a small interface library which enforced this, for example, I have a wrapper round file:open which looks like this: must_open_file(File, Mode) -> case file:open(File, Mode) of {ok, X} -> X; {error, E} -> exit({most_open,File,in_mode,Mode,failed,E}) end. may_open_file(File, Mode) -> file:open(File, Mode). Using this convention dict:find(Key, D) should be called may_get(Key, Dict) dict:fetch(Key, D) should be renames must_get(Key, Dict) With this convention I can write code like: must_sequence() -> Handle = must_open_file("some_file_which_i_know_must_exist.txt", [read]), Data = must_read_file(Handle), must_write_file("fileout", Data). must_close_file(Handle). Or, when "file" might exist, I'd write: test1() -> case may_open_file("file", [read]) of {ok, Handle} -> ... {error, _} -> .. do something else ... end. may_ function are *always* called from case statements must_ function are called in linear code with no case statements I usually also wrap the top level call to a sequence of must_* functions in a catch, something like: top() -> case (catch must_sequence()) of {'EXIT', What} -> ... do some recovery stuff ... Ok -> Ok end. Code written using the must/may convention seems to be extremely easy to read, since from the name of the function I don't have to speculate as to the form of the return value - I know immediately if the function will raise and exception on error or give an ok/error return value. Cheers /Joe _______________________________________________ erlang-questions mailing list erlang-questions@REDACTED http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- An HTML attachment was scrubbed... URL: From jesper.louis.andersen@REDACTED Sat Aug 15 22:34:55 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Sat, 15 Aug 2015 22:34:55 +0200 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: <001401d0d783$23aad430$6b007c90$@co.cu> References: <001401d0d783$23aad430$6b007c90$@co.cu> Message-ID: On Sat, Aug 15, 2015 at 7:52 PM, Gilberio Carmenates Garcia < co7eb@REDACTED> wrote: > So Why cannot Erlang have its nice IDE of its own? Because IDEs take a lot of effort to build! There are at least the two well-known: IntelliJ has a plugin, and erlide is the other large one, which is eclipse-based. What makes Erlang remarkable however, is that the language is pretty easy to work with even if you have no IDE present, which is not the case for many other languages, where you have to provide a lot of completion-tooling in order to program decently fast in the system. People roughly fall into two camps: those who likes IDEs for their development, and those who like a simple, almost zen-like, approach to programming. The latter camp often uses editors which are based around the idea of manipulating text more than providing the basis for compilation, debugging and so on. Popular choices are indeed vi and/or emacs, but there are far more editors than just those two camps, so perhaps you would be happy if you looked around and found something which matches what you like in the editing environment. Do note: many of the vi/emacs proponents are UNIX users, and UNIX is already an IDE for building software. This helps a lot since you can avoid relying on the editor to provide for you. -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From essen@REDACTED Sun Aug 16 00:43:25 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Sun, 16 Aug 2015 00:43:25 +0200 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: References: Message-ID: <55CFC08D.2000506@ninenines.eu> On 08/15/2015 04:56 PM, Joe Armstrong wrote: > For a while now I've adopted a convention for naming functions > which I find rather useful, so I thought I'd discuss it here, > (it's a kind of RFC-2119 lite notation :-) > > Rule1: Functions which return {ok,X} | {error,W} are called may_ > > Rule2: Functions which return a value or raise an exception are called > must_ The concept is interesting, the implementation is too verbose for most people to follow it. That, and having a whole API fit under the letter M is not the best idea for documentation. Some languages have function names like open_file! or open_file? and so on, with special meanings attached to them (sometimes just a convention). We can't do that in Erlang, but something like 'open_file' for Rule1 and 'open_file!' for Rule2 would be pretty explicit. They would be the equivalent of "Please open the file thank you very much oh you failed? too bad" and "Open this file! Now!" The only thing in that spirit that we can do in Erlang today is something like open_file_ (meh) and open_file@ (not as bad imo). So using something like open_file@ could be interesting. But contrary to what I was saying in my email so far, I would suggest having open_file be the crash-only version (because I believe it fits Erlang programming best) and open_file@ be the one that returns errors. If you follow that, you not only know which function may return errors, but also you are explicitly requesting errors to be returned to your code which means a great deal for clarity, without sacrificing the spirit of "let it crash". I might consider doing something like this in Cowboy. -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From michael.french@REDACTED Sun Aug 16 09:08:56 2015 From: michael.french@REDACTED (French, Michael) Date: Sun, 16 Aug 2015 07:08:56 +0000 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: <55A810C00B7CDA48A5AB43C566064B41012DFD1877@SE-EX020.groupinfra.com> References: , <55A810C00B7CDA48A5AB43C566064B41012DFD1866@SE-EX020.groupinfra.com>, <55A810C00B7CDA48A5AB43C566064B41012DFD1877@SE-EX020.groupinfra.com> Message-ID: <55A810C00B7CDA48A5AB43C566064B41012DFD18A9@SE-EX020.groupinfra.com> Perhaps may(...) and must(...) are just higher-order combinators that can wrap any function. Mike ________________________________________ From: French, Michael Sent: Saturday, August 15, 2015 9:49 PM To: Joe Armstrong Subject: RE: [erlang-questions] Some functions must return values other may do so... ________________________________________ From: erlang-questions-bounces@REDACTED [erlang-questions-bounces@REDACTED] on behalf of Joe Armstrong [erlang@REDACTED] Sent: Saturday, August 15, 2015 4:56 PM To: Erlang Subject: [erlang-questions] Some functions must return values other may do so... For a while now I've adopted a convention for naming functions which I find rather useful, so I thought I'd discuss it here, (it's a kind of RFC-2119 lite notation :-) Rule1: Functions which return {ok,X} | {error,W} are called may_ Rule2: Functions which return a value or raise an exception are called must_ I use a small interface library which enforced this, for example, I have a wrapper round file:open which looks like this: must_open_file(File, Mode) -> case file:open(File, Mode) of {ok, X} -> X; {error, E} -> exit({most_open,File,in_mode,Mode,failed,E}) end. may_open_file(File, Mode) -> file:open(File, Mode). Using this convention dict:find(Key, D) should be called may_get(Key, Dict) dict:fetch(Key, D) should be renames must_get(Key, Dict) With this convention I can write code like: must_sequence() -> Handle = must_open_file("some_file_which_i_know_must_exist.txt", [read]), Data = must_read_file(Handle), must_write_file("fileout", Data). must_close_file(Handle). Or, when "file" might exist, I'd write: test1() -> case may_open_file("file", [read]) of {ok, Handle} -> ... {error, _} -> .. do something else ... end. may_ function are *always* called from case statements must_ function are called in linear code with no case statements I usually also wrap the top level call to a sequence of must_* functions in a catch, something like: top() -> case (catch must_sequence()) of {'EXIT', What} -> ... do some recovery stuff ... Ok -> Ok end. Code written using the must/may convention seems to be extremely easy to read, since from the name of the function I don't have to speculate as to the form of the return value - I know immediately if the function will raise and exception on error or give an ok/error return value. Cheers /Joe _______________________________________________ erlang-questions mailing list erlang-questions@REDACTED http://erlang.org/mailman/listinfo/erlang-questions From vladdu55@REDACTED Sun Aug 16 12:06:42 2015 From: vladdu55@REDACTED (Vlad Dumitrescu) Date: Sun, 16 Aug 2015 12:06:42 +0200 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: <55CFC08D.2000506@ninenines.eu> References: <55CFC08D.2000506@ninenines.eu> Message-ID: On Sun, Aug 16, 2015 at 12:43 AM, Lo?c Hoguin wrote: > On 08/15/2015 04:56 PM, Joe Armstrong wrote: > >> For a while now I've adopted a convention for naming functions >> which I find rather useful, so I thought I'd discuss it here, >> (it's a kind of RFC-2119 lite notation :-) >> >> Rule1: Functions which return {ok,X} | {error,W} are called may_ >> >> Rule2: Functions which return a value or raise an exception are called >> must_ >> > > The concept is interesting, the implementation is too verbose for most > people to follow it. That, and having a whole API fit under the letter M is > not the best idea for documentation. > > Some languages have function names like open_file! or open_file? and so > on, with special meanings attached to them (sometimes just a convention). > We can't do that in Erlang, but something like 'open_file' for Rule1 and > 'open_file!' for Rule2 would be pretty explicit. They would be the > equivalent of "Please open the file thank you very much oh you failed? too > bad" and "Open this file! Now!" > > The only thing in that spirit that we can do in Erlang today is something > like open_file_ (meh) and open_file@ (not as bad imo). > > So using something like open_file@ could be interesting. But contrary to > what I was saying in my email so far, I would suggest having open_file be > the crash-only version (because I believe it fits Erlang programming best) > and open_file@ be the one that returns errors. > > If you follow that, you not only know which function may return errors, > but also you are explicitly requesting errors to be returned to your code > which means a great deal for clarity, without sacrificing the spirit of > "let it crash". > Hi! Having a distinction between functions that throw exceptions (hereby named xfuns) and those that return error values (hereby named efuns) makes visible some interesting aspects (I hope I got these right) that make it easier to spot some coding errors: - efuns must call xfuns wrapped in try/catch - efuns must call efuns in 'case' or as a return value - xfuns should call efuns only in 'case' If a syntactical distinction between xfuns and efuns will prove impractical (due to too few special characters being available and possible clashes with existing APIs), an alternative might be to just qualify the functions at their definition points, either with a keyword or in the -spec declaration. Unqualified functions are treated as xfuns [*]. Dialyzer and xref can report calls that break the rules, and actually the compiler can do that too inside each module. I think that some of the cases would be caught by dialyzer as "function will never return" errors, but this would be more precise. [*] Dialyzer and typer might be able to infer qualifiers for functions (or report undecidable cases), making it possible to qualify basically only exported functions. I know I've been bitten by this more than once. best regards, Vlad -------------- next part -------------- An HTML attachment was scrubbed... URL: From essen@REDACTED Sun Aug 16 12:18:11 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Sun, 16 Aug 2015 12:18:11 +0200 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: References: <55CFC08D.2000506@ninenines.eu> Message-ID: <55D06363.2090403@ninenines.eu> On 08/16/2015 12:06 PM, Vlad Dumitrescu wrote: > > On Sun, Aug 16, 2015 at 12:43 AM, Lo?c Hoguin > wrote: > > On 08/15/2015 04:56 PM, Joe Armstrong wrote: > > For a while now I've adopted a convention for naming functions > which I find rather useful, so I thought I'd discuss it here, > (it's a kind of RFC-2119 lite notation :-) > > Rule1: Functions which return {ok,X} | {error,W} are called > may_ > > Rule2: Functions which return a value or raise an exception are > called > must_ > > > The concept is interesting, the implementation is too verbose for > most people to follow it. That, and having a whole API fit under the > letter M is not the best idea for documentation. > > Some languages have function names like open_file! or open_file? and > so on, with special meanings attached to them (sometimes just a > convention). We can't do that in Erlang, but something like > 'open_file' for Rule1 and 'open_file!' for Rule2 would be pretty > explicit. They would be the equivalent of "Please open the file > thank you very much oh you failed? too bad" and "Open this file! Now!" > > The only thing in that spirit that we can do in Erlang today is > something like open_file_ (meh) and open_file@ (not as bad imo). > > So using something like open_file@ could be interesting. But > contrary to what I was saying in my email so far, I would suggest > having open_file be the crash-only version (because I believe it > fits Erlang programming best) and open_file@ be the one that returns > errors. > > If you follow that, you not only know which function may return > errors, but also you are explicitly requesting errors to be returned > to your code which means a great deal for clarity, without > sacrificing the spirit of "let it crash". > > > Hi! > > Having a distinction between functions that throw exceptions (hereby > named xfuns) and those that return error values (hereby named efuns) > makes visible some interesting aspects (I hope I got these right) that > make it easier to spot some coding errors: > - efuns must call xfuns wrapped in try/catch > - efuns must call efuns in 'case' or as a return value > - xfuns should call efuns only in 'case' Not exactly. The way I see it, what you call "efuns" may still crash. Just it wouldn't crash on expected failure (ie a file can't be opened). A valid crash would be badarg, for example. Returning {error, badarg} when you pass an integer instead of a string is not very useful. Similarly, "xfuns" can call "efuns" with a plain match, expecting them to work and crashing otherwise without having to throw manually. The only difference between the two is that "xfuns" succeed or crash, while "efuns" succeed, return an error for expected failures and crash otherwise . -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From jesper.louis.andersen@REDACTED Sun Aug 16 12:42:26 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Sun, 16 Aug 2015 12:42:26 +0200 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: References: Message-ID: On Sat, Aug 15, 2015 at 4:56 PM, Joe Armstrong wrote: > Rule1: Functions which return {ok,X} | {error,W} are called may_ > > Rule2: Functions which return a value or raise an exception are called > must_ > Essentially, this is what the Janes St. Core library for OCaml does as well: val zip : 'a t * 'b t -> ('a * 'b) t option val zip_exn : 'a t * 'b t -> ('a * 'b) t Where the exception is raised, or None returned, if the t's are of different length. I think it is a good idea. Knowing off-hand if a function has effects is always a good thing. And the caller knows immediately when reading the code that this may fail in unexpected ways if the invariants are broken. -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From evnix.com@REDACTED Sun Aug 16 12:44:08 2015 From: evnix.com@REDACTED (avinash D'silva) Date: Sun, 16 Aug 2015 16:14:08 +0530 Subject: [erlang-questions] Noob question: Need some help to limit process spawing Message-ID: Hi, I have these lines code: timer:apply_after(5*1000,mymodule,myfunction,[Value]), timer:apply_after(5*1000,mymodule,myfunction,[Value]), timer:apply_after(5*1000,mymodule,myfunction,[Value]), timer:apply_after(5*1000,mymodule,myfunction,[Value]), timer:apply_after(5*1000,mymodule,myfunction,[Value]), "myfunction" looks like this: myfunction(Value)-> Val2=iolist_to_binary([Value,"_P"]), case pg2:get_members(Value2) of [] -> {ok,P}=mymodule:start_link(), pg2:join(Value2,P2), gen_server:call(P2,{push,Msg}); Otherwise -> [Px|_]=Otherwise, gen_server:call(Px,{push,Msg}) end, the problem is instead of creating a single process of mymodule. there are 5 processes, as time taken to register the process is more, Any solution to this problem? Regards, Avinash D' Silva -------------- next part -------------- An HTML attachment was scrubbed... URL: From vladdu55@REDACTED Sun Aug 16 13:31:58 2015 From: vladdu55@REDACTED (Vlad Dumitrescu) Date: Sun, 16 Aug 2015 13:31:58 +0200 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: <55D06363.2090403@ninenines.eu> References: <55CFC08D.2000506@ninenines.eu> <55D06363.2090403@ninenines.eu> Message-ID: On Sun, Aug 16, 2015 at 12:18 PM, Lo?c Hoguin wrote: > On 08/16/2015 12:06 PM, Vlad Dumitrescu wrote: > >> >> On Sun, Aug 16, 2015 at 12:43 AM, Lo?c Hoguin > > wrote: >> >> On 08/15/2015 04:56 PM, Joe Armstrong wrote: >> >> For a while now I've adopted a convention for naming functions >> which I find rather useful, so I thought I'd discuss it here, >> (it's a kind of RFC-2119 lite notation :-) >> >> Rule1: Functions which return {ok,X} | {error,W} are called >> may_ >> >> Rule2: Functions which return a value or raise an exception are >> called >> must_ >> >> >> The concept is interesting, the implementation is too verbose for >> most people to follow it. That, and having a whole API fit under the >> letter M is not the best idea for documentation. >> >> Some languages have function names like open_file! or open_file? and >> so on, with special meanings attached to them (sometimes just a >> convention). We can't do that in Erlang, but something like >> 'open_file' for Rule1 and 'open_file!' for Rule2 would be pretty >> explicit. They would be the equivalent of "Please open the file >> thank you very much oh you failed? too bad" and "Open this file! Now!" >> >> The only thing in that spirit that we can do in Erlang today is >> something like open_file_ (meh) and open_file@ (not as bad imo). >> >> So using something like open_file@ could be interesting. But >> contrary to what I was saying in my email so far, I would suggest >> having open_file be the crash-only version (because I believe it >> fits Erlang programming best) and open_file@ be the one that returns >> errors. >> >> If you follow that, you not only know which function may return >> errors, but also you are explicitly requesting errors to be returned >> to your code which means a great deal for clarity, without >> sacrificing the spirit of "let it crash". >> >> >> Hi! >> >> Having a distinction between functions that throw exceptions (hereby >> named xfuns) and those that return error values (hereby named efuns) >> makes visible some interesting aspects (I hope I got these right) that >> make it easier to spot some coding errors: >> - efuns must call xfuns wrapped in try/catch >> - efuns must call efuns in 'case' or as a return value >> - xfuns should call efuns only in 'case' >> > > Not exactly. > > The way I see it, what you call "efuns" may still crash. Just it wouldn't > crash on expected failure (ie a file can't be opened). A valid crash would > be badarg, for example. Returning {error, badarg} when you pass an integer > instead of a string is not very useful. > > Similarly, "xfuns" can call "efuns" with a plain match, expecting them to > work and crashing otherwise without having to throw manually. > > The only difference between the two is that "xfuns" succeed or crash, > while "efuns" succeed, return an error for expected failures and crash > otherwise . > Ah, I see, but Joe mentioned using this for dict:fetch and dict:find, so I assumed it was more general. In any case, there is more meta-data about functions that would be useful to have, by declaring it or by inferring it or both: is a function pure? does it interact with the environment (files, network, user input)? does it use callbacks (making other meta-data dependent on arbitrary third-party code)? This meta-data has also two "levels": local and global, where the global one is the recursive closure over all callees. All this would be useful, but it gets complicated fast. best regards, Vlad -------------- next part -------------- An HTML attachment was scrubbed... URL: From rtrlists@REDACTED Sun Aug 16 15:14:13 2015 From: rtrlists@REDACTED (Robert Raschke) Date: Sun, 16 Aug 2015 15:14:13 +0200 Subject: [erlang-questions] Noob question: Need some help to limit process spawing In-Reply-To: References: Message-ID: Could be the typo? Value2 vs Val2. On Aug 16, 2015 12:44 PM, "avinash D'silva" wrote: > Hi, > > I have these lines code: > > timer:apply_after(5*1000,mymodule,myfunction,[Value]), > timer:apply_after(5*1000,mymodule,myfunction,[Value]), > timer:apply_after(5*1000,mymodule,myfunction,[Value]), > timer:apply_after(5*1000,mymodule,myfunction,[Value]), > timer:apply_after(5*1000,mymodule,myfunction,[Value]), > > "myfunction" looks like this: > myfunction(Value)-> > > Val2=iolist_to_binary([Value,"_P"]), > > case pg2:get_members(Value2) of > > [] -> > {ok,P}=mymodule:start_link(), > pg2:join(Value2,P2), > gen_server:call(P2,{push,Msg}); > Otherwise -> > [Px|_]=Otherwise, > gen_server:call(Px,{push,Msg}) > end, > > the problem is instead of creating a single process of mymodule. > there are 5 processes, as time taken to register the process is more, > > Any solution to this problem? > > > Regards, > Avinash D' Silva > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From seglingskungen@REDACTED Sun Aug 16 15:29:27 2015 From: seglingskungen@REDACTED (Chris Williams) Date: Sun, 16 Aug 2015 15:29:27 +0200 Subject: [erlang-questions] TAP + Common test? Message-ID: Hi Has anyone had a go att writing an event handler or a ct_hook that can generate a TAP (Test Anything Protocol http://testanything.org/) Report for Common Test? Chris -------------- next part -------------- An HTML attachment was scrubbed... URL: From mononcqc@REDACTED Sun Aug 16 15:35:17 2015 From: mononcqc@REDACTED (Fred Hebert) Date: Sun, 16 Aug 2015 09:35:17 -0400 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: References: Message-ID: <20150816133515.GB1122@ferdmbp.local> On 08/16, Jesper Louis Andersen wrote: >On Sat, Aug 15, 2015 at 4:56 PM, Joe Armstrong wrote: > >> Rule1: Functions which return {ok,X} | {error,W} are called may_ >> >> Rule2: Functions which return a value or raise an exception are called >> must_ >> > >val zip : 'a t * 'b t -> ('a * 'b) t option >val zip_exn : 'a t * 'b t -> ('a * 'b) t > >I think it is a good idea. Knowing off-hand if a function has effects >is >always a good thing. And the caller knows immediately when reading the code >that this may fail in unexpected ways if the invariants are broken. > The thing that weirds me out about that approach is that it reminds me a lot of hungarian notation. Whereas scheme or ruby would follow functions with ? (for booleans) or ! (for destructive updates), Hungarian notation would have you encode the return types in other fun ways: - arru8NumberList : variable is an array of unsigned 8-bit integers ("arru8"); - strName : Variable represents a string ("str") containing the name, but does not specify how that string is implemented. And then you add: must_zip : returns the result or fails may_zip: returns {ok, Result} or {error, Reason} both of these look suspiciously like encoding your types in the names because the language does not offer enough support (without Dialyzer). I can't also imagine it a fun time to reimplement everything twice to offer changing semantics to please any given user. - raise exceptions for unforeseen errors that must be the caller or the developer's fault - return {ok, _} and {error, _} for expected errors that naturally flow from usage and that the user could reasonably be expected to handle. - encode these in the type system (-spec f() -> {ok, _} | {error, _} | no_return(). , where no_return() points to manually raised exceptions. That's my take on it anyway. From evnix.com@REDACTED Sun Aug 16 15:42:38 2015 From: evnix.com@REDACTED (avinash D'silva) Date: Sun, 16 Aug 2015 19:12:38 +0530 Subject: [erlang-questions] Noob question: Need some help to limit process spawing In-Reply-To: References: Message-ID: Sorry, it was just a typo. The original question holds. I was considering using a *Semaphore* to block the spawning of a new proccess with the help of ETS, but I fear performance issues. Code with Fixed Typo: timer:apply_after(5*1000,mymodule,myfunction,[Value]), timer:apply_after(5*1000,mymodule,myfunction,[Value]), timer:apply_after(5*1000,mymodule,myfunction,[Value]), timer:apply_after(5*1000,mymodule,myfunction,[Value]), timer:apply_after(5*1000,mymodule,myfunction,[Value]), "myfunction" looks like this: myfunction(Value)-> Val2=iolist_to_binary([Value,"_P"]), case pg2:get_members(Val2) of [] -> {ok,P}=mymodule:start_link(), pg2:join(Val2,P2), gen_server:call(P2,{push,Msg}); Otherwise -> [Px|_]=Otherwise, gen_server:call(Px,{push,Msg}) end, On Sun, Aug 16, 2015 at 7:07 PM, Edward Halls wrote: > Perhaps some better syntax highlighting can help you spot this in the > future. > > A good ide will also tell you when there are unused variables. > On 16 Aug 2015 2:22 pm, "Robert Raschke" wrote: > >> Could be the typo? Value2 vs Val2. >> On Aug 16, 2015 12:44 PM, "avinash D'silva" wrote: >> >>> Hi, >>> >>> I have these lines code: >>> >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >>> >>> "myfunction" looks like this: >>> myfunction(Value)-> >>> >>> Val2=iolist_to_binary([Value,"_P"]), >>> >>> case pg2:get_members(Value2) of >>> >>> [] -> >>> {ok,P}=mymodule:start_link(), >>> pg2:join(Value2,P2), >>> gen_server:call(P2,{push,Msg}); >>> Otherwise -> >>> [Px|_]=Otherwise, >>> gen_server:call(Px,{push,Msg}) >>> end, >>> >>> the problem is instead of creating a single process of mymodule. >>> there are 5 processes, as time taken to register the process is more, >>> >>> Any solution to this problem? >>> >>> >>> Regards, >>> Avinash D' Silva >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >>> >>> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> >> -- Powered By codologic -------------- next part -------------- An HTML attachment was scrubbed... URL: From essen@REDACTED Sun Aug 16 15:57:39 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Sun, 16 Aug 2015 15:57:39 +0200 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: <20150816133515.GB1122@ferdmbp.local> References: <20150816133515.GB1122@ferdmbp.local> Message-ID: <55D096D3.3070407@ninenines.eu> On 08/16/2015 03:35 PM, Fred Hebert wrote: > On 08/16, Jesper Louis Andersen wrote: >> On Sat, Aug 15, 2015 at 4:56 PM, Joe Armstrong wrote: >> >>> Rule1: Functions which return {ok,X} | {error,W} are called may_ >>> >>> Rule2: Functions which return a value or raise an exception are called >>> must_ >>> >> >> val zip : 'a t * 'b t -> ('a * 'b) t option >> val zip_exn : 'a t * 'b t -> ('a * 'b) t >> >> I think it is a good idea. Knowing off-hand if a function has effects is >> always a good thing. And the caller knows immediately when reading the >> code >> that this may fail in unexpected ways if the invariants are broken. >> > > The thing that weirds me out about that approach is that it reminds me a > lot of hungarian notation. > > Whereas scheme or ruby would follow functions with ? (for booleans) or ! > (for destructive updates), Hungarian notation would have you encode the > return types in other fun ways: > > - arru8NumberList : variable is an array of unsigned 8-bit integers > ("arru8"); > - strName : Variable represents a string ("str") containing the name, > but does not specify how that string is implemented. > > And then you add: > > must_zip : returns the result or fails > may_zip: returns {ok, Result} or {error, Reason} > > both of these look suspiciously like encoding your types in the names > because the language does not offer enough support (without Dialyzer). > > I can't also imagine it a fun time to reimplement everything twice to > offer changing semantics to please any given user. > > - raise exceptions for unforeseen errors that must be the caller or the > developer's fault > - return {ok, _} and {error, _} for expected errors that naturally flow > from usage and that the user could reasonably be expected to handle. > - encode these in the type system (-spec f() -> {ok, _} | {error, _} | > no_return(). , where no_return() points to manually raised exceptions. > > That's my take on it anyway. It's not just about what you return! Imagine you are validating input. There are two ways to go with validating input: * You detect all errors and display a nice message to the user * You crash on the first error and stop there (no need to do more if you do machine to machine) The functions do the same thing, validate input, take the same arguments, and return the validating input in a usable format. Their behavior differ only in how they handle errors (and therefore their return value). The first one will do what it can to provide you with all information you need to format a nice message to the nice user; the second one will just crash. You could make the immediate crash behavior configurable through an Opts argument, but then your function needs an Opts argument which it may not have had beforehand. It's also not as obvious to the user as a different function would be. And it's much easier to standardize on a prefix or a suffix than on option formats and names. And you don't have to reimplement everything twice! It's just the *interface* that has two functions. You can have a special argument for this (or a special value in place of your error accumulator) inside the private function that implements the input validation. -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From mononcqc@REDACTED Sun Aug 16 16:05:49 2015 From: mononcqc@REDACTED (Fred Hebert) Date: Sun, 16 Aug 2015 10:05:49 -0400 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: <55D096D3.3070407@ninenines.eu> References: <20150816133515.GB1122@ferdmbp.local> <55D096D3.3070407@ninenines.eu> Message-ID: <20150816140547.GC1122@ferdmbp.local> On 08/16, Lo?c Hoguin wrote: >It's not just about what you return! > >Imagine you are validating input. > >There are two ways to go with validating input: > >* You detect all errors and display a nice message to the user >* You crash on the first error and stop there (no need to do more if >you do machine to machine) > >The functions do the same thing, validate input, take the same >arguments, and return the validating input in a usable format. > >And you don't have to reimplement everything twice! It's just the >*interface* that has two functions. You can have a special argument for >this (or a special value in place of your error accumulator) inside the >private function that implements the input validation. > Yeah, there I tend to pick one and document what it does. How often do you end up validating at multiple points in the program and do it in different ways every time? If you need to re-validate input multiple times or places, I'd instead recommend to move your validation to the edge of the system where it an be done once and for all. I guess I can't understand the need as in ~6-7 years programming Erlang, I have never encountered the need to do that in a way that couldn't be fixed by that way of doing things. From essen@REDACTED Sun Aug 16 16:10:36 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Sun, 16 Aug 2015 16:10:36 +0200 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: <20150816140547.GC1122@ferdmbp.local> References: <20150816133515.GB1122@ferdmbp.local> <55D096D3.3070407@ninenines.eu> <20150816140547.GC1122@ferdmbp.local> Message-ID: <55D099DC.5070506@ninenines.eu> On 08/16/2015 04:05 PM, Fred Hebert wrote: > On 08/16, Lo?c Hoguin wrote: >> It's not just about what you return! >> >> Imagine you are validating input. >> >> There are two ways to go with validating input: >> >> * You detect all errors and display a nice message to the user >> * You crash on the first error and stop there (no need to do more if >> you do machine to machine) >> >> The functions do the same thing, validate input, take the same >> arguments, and return the validating input in a usable format. >> >> And you don't have to reimplement everything twice! It's just the >> *interface* that has two functions. You can have a special argument >> for this (or a special value in place of your error accumulator) >> inside the private function that implements the input validation. >> > > Yeah, there I tend to pick one and document what it does. How often do > you end up validating at multiple points in the program and do it in > different ways every time? > > If you need to re-validate input multiple times or places, I'd instead > recommend to move your validation to the edge of the system where it an > be done once and for all. > > I guess I can't understand the need as in ~6-7 years programming Erlang, > I have never encountered the need to do that in a way that couldn't be > fixed by that way of doing things. Well I *do* write Cowboy, which is typically at the edge of the system, and is used for a large number of different use cases, so picking one over the other, for input validation or otherwise, is a pretty difficult exercise... -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From hugo@REDACTED Sun Aug 16 16:19:40 2015 From: hugo@REDACTED (Hugo Mills) Date: Sun, 16 Aug 2015 14:19:40 +0000 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: <20150816133515.GB1122@ferdmbp.local> References: <20150816133515.GB1122@ferdmbp.local> Message-ID: <20150816141940.GT12976@carfax.org.uk> On Sun, Aug 16, 2015 at 09:35:17AM -0400, Fred Hebert wrote: > On 08/16, Jesper Louis Andersen wrote: > >On Sat, Aug 15, 2015 at 4:56 PM, Joe Armstrong wrote: > > > >>Rule1: Functions which return {ok,X} | {error,W} are called may_ > >> > >>Rule2: Functions which return a value or raise an exception are called > >>must_ > >> > > > >val zip : 'a t * 'b t -> ('a * 'b) t option > >val zip_exn : 'a t * 'b t -> ('a * 'b) t > > > >I think it is a good idea. Knowing off-hand if a function has > >effects is > >always a good thing. And the caller knows immediately when reading the code > >that this may fail in unexpected ways if the invariants are broken. > > > > The thing that weirds me out about that approach is that it reminds > me a lot of hungarian notation. It is -- but probably not the Hungarian notation you're thinking of. :) > Whereas scheme or ruby would follow functions with ? (for booleans) > or ! (for destructive updates), Hungarian notation would have you > encode the return types in other fun ways: > > - arru8NumberList : variable is an array of unsigned 8-bit integers > ("arru8"); > - strName : Variable represents a string ("str") containing the > name, but does not specify how that string is implemented. This is "Systems Hungarian" (the better known and justly reviled approach), where the fundamental storage types are encoded in the variable name -- something that automated tooling can deal with much better than people. > And then you add: > > must_zip : returns the result or fails > may_zip: returns {ok, Result} or {error, Reason} This is much closer to "Apps Hungarian", where additional semantics, beyond the type system, of the return type or function behaviour are encoded in the name. In this case, the error handling behaviour is being encoded. My favourite example of the "good" Apps Hungarian form is to encode which variables are unsafe, having come from user input, and which are safe, having been appropriately sanitised, escaped or validated from unsafe variables. This isn't something that could be tracked by the compiler in most languages, but it is vital to the semantics and correct operation of the software. What's being done here, to my mind, falls much more into that category. You could also look at it as similar to the "throw" annotation in C++, or the "throws" annotation in Java. > both of these look suspiciously like encoding your types in the > names because the language does not offer enough support (without > Dialyzer). I see it as being useful, but not because the language doesn't provide the type checking. This is more than basic type checking -- it's additional annotation about the exceptions that could be raised by a function. You could envisage a -raises() annotation, similar to -spec(), which gives enough information for an analysis tool to determine which exceptions might rise to the top of a process and cause it to terminate. (Actually, I suspect that there's already enough information in the compiled code to work it out without the annotations, but I don't have anywhere near the expertise in erlang to make that claim directly). Hugo. > I can't also imagine it a fun time to reimplement everything twice > to offer changing semantics to please any given user. > > - raise exceptions for unforeseen errors that must be the caller or > the developer's fault > - return {ok, _} and {error, _} for expected errors that naturally > flow from usage and that the user could reasonably be expected to > handle. > - encode these in the type system (-spec f() -> {ok, _} | {error, _} > | no_return(). , where no_return() points to manually raised > exceptions. > > That's my take on it anyway. > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -- Hugo Mills | Is it true that "last known good" on Windows XP hugo@REDACTED carfax.org.uk | boots into CP/M? http://carfax.org.uk/ | PGP: E2AB1DE4 | Adrian Bridgett -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: From mononcqc@REDACTED Sun Aug 16 17:31:52 2015 From: mononcqc@REDACTED (Fred Hebert) Date: Sun, 16 Aug 2015 11:31:52 -0400 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: <20150816141940.GT12976@carfax.org.uk> References: <20150816133515.GB1122@ferdmbp.local> <20150816141940.GT12976@carfax.org.uk> Message-ID: <20150816153150.GE1122@ferdmbp.local> On 08/16, Hugo Mills wrote: >> - arru8NumberList : variable is an array of unsigned 8-bit integers >> ("arru8"); >> - strName : Variable represents a string ("str") containing the >> name, but does not specify how that string is implemented. > > This is "Systems Hungarian" (the better known and justly reviled >approach), where the fundamental storage types are encoded in the >variable name -- something that automated tooling can deal with much >better than people. > Actually, the former is systems hungarian, the latter is apps hungarian, as lifted from the wikipedia page for both. They'er not *that* different ;) From ehalls@REDACTED Sun Aug 16 15:37:09 2015 From: ehalls@REDACTED (Edward Halls) Date: Sun, 16 Aug 2015 14:37:09 +0100 Subject: [erlang-questions] Noob question: Need some help to limit process spawing In-Reply-To: References: Message-ID: Perhaps some better syntax highlighting can help you spot this in the future. A good ide will also tell you when there are unused variables. On 16 Aug 2015 2:22 pm, "Robert Raschke" wrote: > Could be the typo? Value2 vs Val2. > On Aug 16, 2015 12:44 PM, "avinash D'silva" wrote: > >> Hi, >> >> I have these lines code: >> >> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >> >> "myfunction" looks like this: >> myfunction(Value)-> >> >> Val2=iolist_to_binary([Value,"_P"]), >> >> case pg2:get_members(Value2) of >> >> [] -> >> {ok,P}=mymodule:start_link(), >> pg2:join(Value2,P2), >> gen_server:call(P2,{push,Msg}); >> Otherwise -> >> [Px|_]=Otherwise, >> gen_server:call(Px,{push,Msg}) >> end, >> >> the problem is instead of creating a single process of mymodule. >> there are 5 processes, as time taken to register the process is more, >> >> Any solution to this problem? >> >> >> Regards, >> Avinash D' Silva >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> >> > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From g@REDACTED Sun Aug 16 18:06:31 2015 From: g@REDACTED (Garrett Smith) Date: Sun, 16 Aug 2015 11:06:31 -0500 Subject: [erlang-questions] Noob question: Need some help to limit process spawing In-Reply-To: References: Message-ID: On Sun, Aug 16, 2015 at 8:37 AM, Edward Halls wrote: > Perhaps some better syntax highlighting can help you spot this in the > future. > > A good ide will also tell you when there are unused variables. Better programming conventions - in particular making the code say what's going on - is even better than a super intelligent IDE that tells you what's wrong as you're typing. I turn those helper features off. Or, I would if Emacs had them on by default. > On 16 Aug 2015 2:22 pm, "Robert Raschke" wrote: >> >> Could be the typo? Value2 vs Val2. >> >> On Aug 16, 2015 12:44 PM, "avinash D'silva" wrote: >>> >>> Hi, >>> >>> I have these lines code: >>> >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), >>> >>> "myfunction" looks like this: >>> myfunction(Value)-> This should be a function: >>> Val2=iolist_to_binary([Value,"_P"]), You're making a decision to add this suffix here? Why? A well named function will make that obvious. Any time you find yourself adding 2, 3, 4s to the end of a variable, stop. What's the actual name of the variable there? I mean, what is it? Use that. Oh, and "value" should be "term" here. Kidding of course - it's no doubt a value, but take advantage of the variable name. Just spend a moment and think about what that thing actually is in the context of your function/problem. I'd flatten this all out: >>> case pg2:get_members(Value2) of >>> >>> [] -> >>> {ok,P}=mymodule:start_link(), >>> pg2:join(Value2,P2), >>> gen_server:call(P2,{push,Msg}); >>> Otherwise -> >>> [Px|_]=Otherwise, >>> gen_server:call(Px,{push,Msg}) >>> end, to be something like: handle_members(members_for_xxx(XXX)) I don't know what XXX is here (that's a bad name too) but it should make sense. >>> the problem is instead of creating a single process of mymodule. >>> there are 5 processes, as time taken to register the process is more, I didn't answer your question as I fixate on code clarity and it's an emotional blocker for me :) From evnix.com@REDACTED Sun Aug 16 18:27:28 2015 From: evnix.com@REDACTED (avinash D'silva) Date: Sun, 16 Aug 2015 21:57:28 +0530 Subject: [erlang-questions] Noob question: Need some help to limit process spawing In-Reply-To: References: Message-ID: @Garret, I purposely changed the variable names, so that they would be easier to understand, as I did not want to confuse/make it hard for the readers with the names specific to the project. I solved the problem by using a *mutex*: but I am not sure if this is the right way to do it in Erlang or if there are better ways of doing the same? myfunction(Value)-> Val2=iolist_to_binary([Value,"_P"]), case pg2:get_members(Val2) of [] -> case ets:lookup(myset,mylock) of [{_,0}] -> ets:insert(myset, {mylock, 1}), {ok,P}=mymodule:start_link(), pg2:join(Val2,P), ets:insert(myset, {mylock, 0}), gen_server:call(P,{push,Msg}); [{_,1}] -> %try again mymodule:myfunction(Value) end; Otherwise -> [Px|_]=Otherwise, gen_server:call(Px,{push,Msg}) end. On Sun, Aug 16, 2015 at 9:36 PM, Garrett Smith wrote: > On Sun, Aug 16, 2015 at 8:37 AM, Edward Halls wrote: > > Perhaps some better syntax highlighting can help you spot this in the > > future. > > > > A good ide will also tell you when there are unused variables. > > Better programming conventions - in particular making the code say > what's going on - is even better than a super intelligent IDE that > tells you what's wrong as you're typing. I turn those helper features > off. Or, I would if Emacs had them on by default. > > > On 16 Aug 2015 2:22 pm, "Robert Raschke" > wrote: > >> > >> Could be the typo? Value2 vs Val2. > >> > >> On Aug 16, 2015 12:44 PM, "avinash D'silva" > wrote: > >>> > >>> Hi, > >>> > >>> I have these lines code: > >>> > >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), > >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), > >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), > >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), > >>> timer:apply_after(5*1000,mymodule,myfunction,[Value]), > >>> > >>> "myfunction" looks like this: > >>> myfunction(Value)-> > > This should be a function: > > >>> Val2=iolist_to_binary([Value,"_P"]), > > You're making a decision to add this suffix here? Why? A well named > function will make that obvious. > > Any time you find yourself adding 2, 3, 4s to the end of a variable, > stop. What's the actual name of the variable there? I mean, what is > it? Use that. > > Oh, and "value" should be "term" here. Kidding of course - it's no > doubt a value, but take advantage of the variable name. Just spend a > moment and think about what that thing actually is in the context of > your function/problem. > > I'd flatten this all out: > > >>> case pg2:get_members(Value2) of > >>> > >>> [] -> > >>> {ok,P}=mymodule:start_link(), > >>> pg2:join(Value2,P2), > >>> gen_server:call(P2,{push,Msg}); > >>> Otherwise -> > >>> [Px|_]=Otherwise, > >>> gen_server:call(Px,{push,Msg}) > >>> end, > > to be something like: > > handle_members(members_for_xxx(XXX)) > > I don't know what XXX is here (that's a bad name too) but it should make > sense. > > >>> the problem is instead of creating a single process of mymodule. > >>> there are 5 processes, as time taken to register the process is more, > > I didn't answer your question as I fixate on code clarity and it's an > emotional blocker for me :) > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -- Powered By codologic -------------- next part -------------- An HTML attachment was scrubbed... URL: From felixgallo@REDACTED Sun Aug 16 18:48:09 2015 From: felixgallo@REDACTED (Felix Gallo) Date: Sun, 16 Aug 2015 09:48:09 -0700 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: <20150816153150.GE1122@ferdmbp.local> References: <20150816133515.GB1122@ferdmbp.local> <20150816141940.GT12976@carfax.org.uk> <20150816153150.GE1122@ferdmbp.local> Message-ID: I feel like the pragmatic negatives (API size, multiple 'ways to do it' enabling inter- and intra-team stylistic clashing, etc.) of creating another set of functions in any API annotated with exception handling preference outweigh the positives. F. On Sun, Aug 16, 2015 at 8:31 AM, Fred Hebert wrote: > On 08/16, Hugo Mills wrote: > >> - arru8NumberList : variable is an array of unsigned 8-bit integers >>> ("arru8"); >>> - strName : Variable represents a string ("str") containing the >>> name, but does not specify how that string is implemented. >>> >> >> This is "Systems Hungarian" (the better known and justly reviled >> approach), where the fundamental storage types are encoded in the >> variable name -- something that automated tooling can deal with much >> better than people. >> >> > Actually, the former is systems hungarian, the latter is apps hungarian, > as lifted from the wikipedia page for both. They'er not *that* different ;) > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From co7eb@REDACTED Sun Aug 16 19:47:47 2015 From: co7eb@REDACTED (Gilberio Carmenates Garcia) Date: Sun, 16 Aug 2015 13:47:47 -0400 Subject: [erlang-questions] Todays Topic: Performance Stuffs->records vs maps vs proplists Message-ID: <000c01d0d84b$aecece40$0c6c6ac0$@co.cu> Hi everyone here are some interesting tests about performance in Erlang. Today's Topic: performance stuffs->records vs maps vs proplists Test made against the same data represented in three format records, maps and proplists. Test case value: 10 000 000 iterations. Test case: get. Records: Rec#rec.id -> 237 ms Maps: maps:get(id, Map) -> 550 ms {id := Id} = Map -> ~277 ms Proplists: proplists:get_value/lookup(id, PPL) -> ~1642 ms Test case: create. Records: Rec = #rec{id = N, .} -> ~1046 ms Maps: Map = #{id = N, .} -> ~ 1440 ms Proplists: PPL = [{id, N}, .] -> ~2318 ms Test case: update. Records: case 1 (~908 ms): Rec2 = Rec#rec{id = N + N}, case 2 (~1057 ms): Rec2 = Rec#rec{id = N, name = N, age = N, dog = N, cat = N, mow = N, tin = N}, case 3: no equivalent case 4: no equivalent Maps: case 1 (~3013 ms): Map2 = Map#{id => N + N}, case 2 (~ 4441 ms): Map2 = Map#{id => N, name => N, age => N, dog => N, cat => N, mow => N, tin => N}, case 3 (~952 ms): Map2 = maps:update(id, N + 1, Map) case 4 (~6054 ms) Map2 = maps:update(id, N + 1, Map), Map3 = maps:update(name, N + 1, Map2), Map4 = maps:update(age, N + 1, Map3), Map5 = maps:update(dog, N + 1, Map4), Map6 = maps:update(cat, N + 1, Map5), Map7 = maps:update(mow, N + 1, Map6), Map8 = maps:update(tin, N + 1, Map7), Proplists: case 1: no equivalent case 2: no equivalent case 3: (~1529 ms) PPL2 = lists:keystore(id, 1, PPL, {id, N + N}), case 4: (~30705 ms) PPL2 = lists:keystore(id, 1, PPL, {id, N + N}), PPL3 = lists:keystore(name, 1, PPL2, {name, N + N}), PPL4 = lists:keystore(age, 1, PPL3, {age, N + N}), PPL5 = lists:keystore(dog, 1, PPL4, {dog, N + N}), PPL6 = lists:keystore(cat, 1, PPL5, {cat, N + N}), PPL7 = lists:keystore(mow, 1, PPL6, {mow, N + N}), PPL8 = lists:keystore(tin, 1, PPL7, {tin, N + N}), What about that? I think using maps:get/2 is not so fast as using map pattern matching. Cheers, Ivan (son of Gilberio). -------------- next part -------------- An HTML attachment was scrubbed... URL: From seancribbs@REDACTED Sun Aug 16 23:08:16 2015 From: seancribbs@REDACTED (Sean Cribbs) Date: Sun, 16 Aug 2015 16:08:16 -0500 Subject: [erlang-questions] TAP + Common test? In-Reply-To: References: Message-ID: You should look at the (largely defunct?) 'etap' for tidbits. Nick Gerakines demoed it at Erlang Factory SF 2009. On Sun, Aug 16, 2015 at 8:29 AM, Chris Williams wrote: > Hi > Has anyone had a go att writing an event handler or a ct_hook that can > generate a TAP (Test Anything Protocol http://testanything.org/) Report > for Common Test? > > > Chris > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From eric.pailleau@REDACTED Sun Aug 16 23:48:51 2015 From: eric.pailleau@REDACTED (PAILLEAU Eric) Date: Sun, 16 Aug 2015 23:48:51 +0200 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: References: Message-ID: <55D10543.3050002@wanadoo.fr> Hi, Use of macros could be easy for coding. 1) Must/May/Might are uppercase in the code, easy to see. 2) switch between must/may/might is easy without any code change except macro name. Regards _____________________________________________________________________________ -module(might). -export([test_must/1, test_may/1, test_might/1]). -define(MUST(M), case M of {ok, X} -> X; {error, E} -> exit({?MODULE, ?LINE, io_lib:format("~s",[??M]), E}) end). -define(MAY(M), M). -define(MIGHT(M), (catch ?MUST(M))). test_must(F) -> ?MUST( file:open(F, [read]) ) . test_may(F) -> ?MAY( file:open(F, [read]) ). test_might(F) -> ?MIGHT(file:open(F, [read])) . _____________________________________________________________________________ 1> might:test_must("/tmp/none"). ** exception exit: {might,15,["file : open ( F , [ read ] )"],enoent} in function might:test_must/1 (might.erl, line 15) 2> might:test_may("/tmp/none"). {error,enoent} 3> might:test_might("/tmp/none"). {'EXIT',{might,20,["file : open ( F , [ read ] )"],enoent}} Le 15/08/2015 16:56, Joe Armstrong a ?crit : > For a while now I've adopted a convention for naming functions > which I find rather useful, so I thought I'd discuss it here, > (it's a kind of RFC-2119 lite notation :-) > > Rule1: Functions which return {ok,X} | {error,W} are called may_ > > Rule2: Functions which return a value or raise an exception are called > must_ > > I use a small interface library which enforced this, for example, > I have a wrapper round file:open which looks like this: > > must_open_file(File, Mode) -> > case file:open(File, Mode) of > {ok, X} -> > X; > {error, E} -> > exit({most_open,File,in_mode,Mode,failed,E}) > end. > > may_open_file(File, Mode) -> > file:open(File, Mode). > > Using this convention > > dict:find(Key, D) should be called may_get(Key, Dict) > dict:fetch(Key, D) should be renames must_get(Key, Dict) > > With this convention I can write code like: > > must_sequence() -> > Handle = must_open_file("some_file_which_i_know_must_exist.txt", [read]), > Data = must_read_file(Handle), > must_write_file("fileout", Data). > must_close_file(Handle). > > Or, when "file" might exist, I'd write: > > test1() -> > case may_open_file("file", [read]) of > {ok, Handle} -> > ... > {error, _} -> > .. do something else ... > end. > > may_ function are *always* called from case statements > must_ function are called in linear code with no case statements > > I usually also wrap the top level call to a sequence of > must_* functions in a catch, something like: > > top() -> > case (catch must_sequence()) of > {'EXIT', What} -> > ... do some recovery stuff ... > Ok -> > Ok > end. > > Code written using the must/may convention seems to be extremely easy > to read, since from the name of the function I don't have to speculate > as > to the form of the return value - I know immediately if the function > will raise and exception on error or give an ok/error return value. > > Cheers > > /Joe > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > From eric.pailleau@REDACTED Sun Aug 16 23:57:20 2015 From: eric.pailleau@REDACTED (PAILLEAU Eric) Date: Sun, 16 Aug 2015 23:57:20 +0200 Subject: [erlang-questions] Some functions must return values other may do so... In-Reply-To: <55D10543.3050002@wanadoo.fr> References: <55D10543.3050002@wanadoo.fr> Message-ID: <55D10740.8040106@wanadoo.fr> Hello, sorry, read: {error, E} -> exit({?MODULE, ?LINE, ??M, E}) instead {error, E} -> exit({?MODULE, ?LINE, io_lib:format("~s",[??M]), E}) Le 16/08/2015 23:48, PAILLEAU Eric a ?crit : > Hi, > > Use of macros could be easy for coding. > 1) Must/May/Might are uppercase in the code, easy to see. > 2) switch between must/may/might is easy without any code change except > macro name. > > Regards > _____________________________________________________________________________ > > -module(might). > > -export([test_must/1, test_may/1, test_might/1]). > > -define(MUST(M), case M of > {ok, X} -> X; > {error, E} -> exit({?MODULE, ?LINE, > io_lib:format("~s",[??M]), E}) > end). > > -define(MAY(M), M). > > -define(MIGHT(M), (catch ?MUST(M))). > > > test_must(F) -> ?MUST( file:open(F, [read]) ) . > > test_may(F) -> ?MAY( file:open(F, [read]) ). > > test_might(F) -> ?MIGHT(file:open(F, [read])) . > _____________________________________________________________________________ > > > 1> might:test_must("/tmp/none"). > ** exception exit: {might,15,["file : open ( F , [ read ] )"],enoent} > in function might:test_must/1 (might.erl, line 15) > > 2> might:test_may("/tmp/none"). > {error,enoent} > > 3> might:test_might("/tmp/none"). > {'EXIT',{might,20,["file : open ( F , [ read ] )"],enoent}} > > > Le 15/08/2015 16:56, Joe Armstrong a ?crit : >> For a while now I've adopted a convention for naming functions >> which I find rather useful, so I thought I'd discuss it here, >> (it's a kind of RFC-2119 lite notation :-) >> >> Rule1: Functions which return {ok,X} | {error,W} are called may_ >> >> Rule2: Functions which return a value or raise an exception are called >> must_ >> >> I use a small interface library which enforced this, for example, >> I have a wrapper round file:open which looks like this: >> >> must_open_file(File, Mode) -> >> case file:open(File, Mode) of >> {ok, X} -> >> X; >> {error, E} -> >> exit({most_open,File,in_mode,Mode,failed,E}) >> end. >> >> may_open_file(File, Mode) -> >> file:open(File, Mode). >> >> Using this convention >> >> dict:find(Key, D) should be called may_get(Key, Dict) >> dict:fetch(Key, D) should be renames must_get(Key, Dict) >> >> With this convention I can write code like: >> >> must_sequence() -> >> Handle = >> must_open_file("some_file_which_i_know_must_exist.txt", [read]), >> Data = must_read_file(Handle), >> must_write_file("fileout", Data). >> must_close_file(Handle). >> >> Or, when "file" might exist, I'd write: >> >> test1() -> >> case may_open_file("file", [read]) of >> {ok, Handle} -> >> ... >> {error, _} -> >> .. do something else ... >> end. >> >> may_ function are *always* called from case statements >> must_ function are called in linear code with no case statements >> >> I usually also wrap the top level call to a sequence of >> must_* functions in a catch, something like: >> >> top() -> >> case (catch must_sequence()) of >> {'EXIT', What} -> >> ... do some recovery stuff ... >> Ok -> >> Ok >> end. >> >> Code written using the must/may convention seems to be extremely easy >> to read, since from the name of the function I don't have to speculate >> as >> to the form of the return value - I know immediately if the function >> will raise and exception on error or give an ok/error return value. >> >> Cheers >> >> /Joe >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > From ok@REDACTED Mon Aug 17 02:36:42 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Mon, 17 Aug 2015 12:36:42 +1200 Subject: [erlang-questions] feedback on my solutions to programming erlang second edition In-Reply-To: <55CDD109.1080109@home.nl> References: <55CDA6CD.2050501@home.nl> <55CDD109.1080109@home.nl> Message-ID: <051BD7DA-89C8-4877-B4E4-C0C5B1045855@cs.otago.ac.nz> On 14/08/2015, at 11:29 pm, Roelof Wobben wrote: > So it's fine to give this a error message : > > ** exception error: {read_file,"wrong.txt",enoent} in function my_file:read/1 (my_file.erl, line 8)) > I think a unexperience users still does not know what went wrong. You are 100% right that there is a conflict here between (P) reporting an error in a way that a PROGRAM can readily catch and handle (H) reporting an error in a way that a HUMAN can readily understand. You are not the first to run into this, and there is a pattern for dealing with it in Erlang: if a module M reports error E call M:format_error(E) to get a human-readable text. See http://www.erlang.org/doc/man/file.html#format_error-1 for an example. This means that the code that detects an error should be concerned *solely* with the (P) issue: how can callers or exception handlers or whatever reliably discriminate *this* error from other errors. Readability of the error term is NOT A CONCERN. When it's time to think about (H) you do that in a *separate* function, the format_error/1 function. Quintus Prolog did exactly the same. Code that raised exceptions generated terms that were easy for a *program* to decode. There was a separate user-pluggable predicate for mapping that to text. Not the least of the reasons for having a separate predicate was to support multiple human languages. You really don't want ANY English (or Dutch, or Japanese, or Hindi, or ...) natural language wired into your program, and certainly not *scattered* throughout it. You want the mapping from program structures to natural language text *separated* so that it is easy to translate. From eriksoe@REDACTED Mon Aug 17 09:30:09 2015 From: eriksoe@REDACTED (=?UTF-8?Q?Erik_S=C3=B8e_S=C3=B8rensen?=) Date: Mon, 17 Aug 2015 09:30:09 +0200 Subject: [erlang-questions] Todays Topic: Performance Stuffs->records vs maps vs proplists In-Reply-To: <000c01d0d84b$aecece40$0c6c6ac0$@co.cu> References: <000c01d0d84b$aecece40$0c6c6ac0$@co.cu> Message-ID: Hi - As for proplists, try replacing it with the simpler and faster lists:keyfind/3. Also, you don't state the size of the data structure you're manipulating - only the number of iterations. Den 16/08/2015 20.08 skrev "Gilberio Carmenates Garcia" : > Hi everyone here are some interesting tests about performance in Erlang. > > > > Today?s Topic: performance stuffs->records vs maps vs proplists > > > > Test made against the same data represented in three format records, maps > and proplists. > > Test case value: 10 000 000 iterations. > > > > Test case: get. > > Records: > > Rec#rec.id -> 237 ms > > Maps: > > maps:get(id, Map) -> 550 ms > > {id := Id} = Map -> ~277 ms > > Proplists: > > proplists:get_value/lookup(id, PPL) -> ~1642 ms > > > > Test case: create. > > Records: > > Rec = #rec{id = N, ?} -> ~1046 ms > > Maps: > > Map = #{id = N, ?} -> ~ 1440 ms > > Proplists: > > PPL = [{id, N}, ?] -> ~2318 ms > > > > Test case: update. > > Records: > > case 1 (~908 ms): > > Rec2 = Rec#rec{id = N + N}, > > case 2 (~1057 ms): > > Rec2 = Rec#rec{id = N, name = N, age = N, dog = N, cat = N, mow = N, > tin = N}, > > case 3: no equivalent > > case 4: no equivalent > > Maps: > > case 1 (~3013 ms): > > Map2 = Map#{id => N + N}, > > case 2 (~ 4441 ms): > > Map2 = Map#{id => N, name => N, age => N, dog => N, cat => N, mow => > N, tin => N}, > > case 3 (~952 ms): > > Map2 = maps:update(id, N + 1, Map) > > case 4 (~6054 ms) > > Map2 = maps:update(id, N + 1, Map), > > Map3 = maps:update(name, N + 1, Map2), > > Map4 = maps:update(age, N + 1, Map3), > > Map5 = maps:update(dog, N + 1, Map4), > > Map6 = maps:update(cat, N + 1, Map5), > > Map7 = maps:update(mow, N + 1, Map6), > > Map8 = maps:update(tin, N + 1, Map7), > > Proplists: > > case 1: no equivalent > > case 2: no equivalent > > case 3: (~1529 ms) > > PPL2 = lists:keystore(id, 1, PPL, {id, N + N}), > > case 4: (~30705 ms) > > PPL2 = lists:keystore(id, 1, PPL, {id, N + N}), > > PPL3 = lists:keystore(name, 1, PPL2, {name, N + N}), > > PPL4 = lists:keystore(age, 1, PPL3, {age, N + N}), > > PPL5 = lists:keystore(dog, 1, PPL4, {dog, N + N}), > > PPL6 = lists:keystore(cat, 1, PPL5, {cat, N + N}), > > PPL7 = lists:keystore(mow, 1, PPL6, {mow, N + N}), > > PPL8 = lists:keystore(tin, 1, PPL7, {tin, N + N}), > > > > What about that? I think using maps:get/2 is not so fast as using map > pattern matching. > > > > Cheers, > > Ivan (son of Gilberio). > > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From luis.rascao@REDACTED Mon Aug 17 10:05:20 2015 From: luis.rascao@REDACTED (=?UTF-8?B?THVpcyBSYXNjw6Nv?=) Date: Mon, 17 Aug 2015 09:05:20 +0100 Subject: [erlang-questions] Disabling a parse transform on a per-file basis? In-Reply-To: References: Message-ID: Hi Roger, >From what i can see, there is no way to disable a parse transform on a per-file basis. Even if there was you would get no compile errors, just undefined functions at runtime. On Mon, Aug 3, 2015 at 1:58 PM, Roger Lipscombe wrote: > It turns out that you can deadlock lager (2.0.3) if you attempt to use > lager:log (or lager:debug, etc.) from inside a lager backend. > > I have the lager parse transform enabled in rebar.config for every > module in the application. > > Is there a way to *remove* it for specific modules? Then, if anyone > attempts to use it in one of our lager backends, they'll get a compile > error, rather than a deadlock in production. > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -- PGP fingerprint: F708 E141 AE8D 2D38 E1BC DF3D 1719 3EA0 647D 7260 -------------- next part -------------- An HTML attachment was scrubbed... URL: From essen@REDACTED Mon Aug 17 10:15:00 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Mon, 17 Aug 2015 10:15:00 +0200 Subject: [erlang-questions] feedback on my solutions to programming erlang second edition In-Reply-To: <051BD7DA-89C8-4877-B4E4-C0C5B1045855@cs.otago.ac.nz> References: <55CDA6CD.2050501@home.nl> <55CDD109.1080109@home.nl> <051BD7DA-89C8-4877-B4E4-C0C5B1045855@cs.otago.ac.nz> Message-ID: <55D19804.4020101@ninenines.eu> On 08/17/2015 02:36 AM, Richard A. O'Keefe wrote: > > On 14/08/2015, at 11:29 pm, Roelof Wobben wrote: >> So it's fine to give this a error message : >> >> ** exception error: {read_file,"wrong.txt",enoent} in function my_file:read/1 (my_file.erl, line 8)) > >> I think a unexperience users still does not know what went wrong. > > You are 100% right that there is a conflict here between > > (P) reporting an error in a way that > a PROGRAM can readily catch and handle > (H) reporting an error in a way that > a HUMAN can readily understand. > > You are not the first to run into this, > and there is a pattern for dealing with it in Erlang: > > if a module M reports error E > call M:format_error(E) to get a human-readable text. > > See http://www.erlang.org/doc/man/file.html#format_error-1 > for an example. This is the pattern that is in Erlang but honestly it is very limited. Take the HTTP protocol for example. There are a thousand ways things can go wrong. Are you really going to make a separate atom for each error and then call format_error to know what went wrong? How do you call them, parse_error0, parse_error1, parse_error2? Are you going to end with parse_error formatted as "Parse error." without any clue of what actually went wrong? I find that returning {error, ErrorForPrograms, ErrorForHumans} is a much saner solution because the first error value helps the program know what kind of error it is, and the second error value says exactly what happened for the human who is debugging (locally or when calling an HTTP service, as this error can also be sent as response). This has the additional benefit that the ErrorForHumans value also serves as inlined documentation. -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From jesper.louis.andersen@REDACTED Mon Aug 17 10:35:46 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Mon, 17 Aug 2015 10:35:46 +0200 Subject: [erlang-questions] Noob question: Need some help to limit process spawing In-Reply-To: References: Message-ID: On Sun, Aug 16, 2015 at 6:27 PM, avinash D'silva wrote: > I solved the problem by using a *mutex*: > but I am not sure if this is the right way to do it in Erlang or if there > are better ways of doing the same? > The problem is you are using pg2 which provides different characteristics from what you expect. The purpose of pg2 is to build a group of processes, for instance 5 such processes. Internally it uses the `global` module to run transactions on every node joined in the cluster. It is not clear to me what consistency level this implies. A guess would be sequential consistency. The result is that between you getting the members and you joining, things can happen, and you have a race there which you then have to solve. A good guess on a solution would be to use either local registration, or the global module. There, you would have the ability to boot out any process which is being started on top of another one, so to speak. Also `global:set_lock/3` and `global:trans/2,3,4` may be of interest to you. -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From tuncer.ayaz@REDACTED Mon Aug 17 11:28:14 2015 From: tuncer.ayaz@REDACTED (Tuncer Ayaz) Date: Mon, 17 Aug 2015 11:28:14 +0200 Subject: [erlang-questions] Patch package OTP 17.5.6.3 released In-Reply-To: <55CC95D3.9050509@ericsson.com> References: <55CC95D3.9050509@ericsson.com> Message-ID: On Thu, Aug 13, 2015 at 3:04 PM, Henrik Nord X wrote: > Patch Package: OTP 17.5.6.3 > Git Tag: OTP-17.5.6.3 Are you sure you pushed the new tag to github? From hm@REDACTED Mon Aug 17 12:14:11 2015 From: hm@REDACTED (=?UTF-8?Q?H=C3=A5kan_Mattsson?=) Date: Mon, 17 Aug 2015 12:14:11 +0200 Subject: [erlang-questions] TAP + Common test? Message-ID: The using etap advice assumes that you need to extend Common Test with TAP support yourself. If you are going down that line you can also take a look at the TAP interface of the LUX test tool. It is used by a large american company. ;-) ? ? https://github.com/hawk/lux/blob/master/src/lux_tap.erl /H?kan On Sun, Aug 16, 2015 at 11:08 PM, Sean Cribbs wrote: > You should look at the (largely defunct?) 'etap' for tidbits. Nick > Gerakines demoed it at Erlang Factory SF 2009. > > On Sun, Aug 16, 2015 at 8:29 AM, Chris Williams > wrote: > >> Hi >> Has anyone had a go att writing an event handler or a ct_hook that can >> generate a TAP (Test Anything Protocol http://testanything.org/) Report >> for Common Test? >> >> Chris >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> >> > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From g@REDACTED Mon Aug 17 12:27:15 2015 From: g@REDACTED (Garrett Smith) Date: Mon, 17 Aug 2015 05:27:15 -0500 Subject: [erlang-questions] Todays Topic: Performance Stuffs->records vs maps vs proplists In-Reply-To: References: <000c01d0d84b$aecece40$0c6c6ac0$@co.cu> Message-ID: I have this from erlang-bench: https://github.com/gar1t/erlang-bench/blob/master/name-lookup.escript lists:keyfind is indeed faster, but surprisingly proplists is plenty fast too. The use case I was interested in there is small list (less than 100 items) lookup, which is common for configuration data. Fast is relative of course. And short of a real application bottleneck, completely pointless to obsess over. But it can be interesting and fun to argue about, like politics. Ivan, it'd be great to update that benchmark with maps :) On Mon, Aug 17, 2015 at 2:30 AM, Erik S?e S?rensen wrote: > Hi - > As for proplists, try replacing it with the simpler and faster > lists:keyfind/3. > Also, you don't state the size of the data structure you're manipulating - > only the number of iterations. > > Den 16/08/2015 20.08 skrev "Gilberio Carmenates Garcia" > : >> >> Hi everyone here are some interesting tests about performance in Erlang. >> >> >> >> Today?s Topic: performance stuffs->records vs maps vs proplists >> >> >> >> Test made against the same data represented in three format records, maps >> and proplists. >> >> Test case value: 10 000 000 iterations. >> >> >> >> Test case: get. >> >> Records: >> >> Rec#rec.id -> 237 ms >> >> Maps: >> >> maps:get(id, Map) -> 550 ms >> >> {id := Id} = Map -> ~277 ms >> >> Proplists: >> >> proplists:get_value/lookup(id, PPL) -> ~1642 ms >> >> >> >> Test case: create. >> >> Records: >> >> Rec = #rec{id = N, ?} -> ~1046 ms >> >> Maps: >> >> Map = #{id = N, ?} -> ~ 1440 ms >> >> Proplists: >> >> PPL = [{id, N}, ?] -> ~2318 ms >> >> >> >> Test case: update. >> >> Records: >> >> case 1 (~908 ms): >> >> Rec2 = Rec#rec{id = N + N}, >> >> case 2 (~1057 ms): >> >> Rec2 = Rec#rec{id = N, name = N, age = N, dog = N, cat = N, mow = N, >> tin = N}, >> >> case 3: no equivalent >> >> case 4: no equivalent >> >> Maps: >> >> case 1 (~3013 ms): >> >> Map2 = Map#{id => N + N}, >> >> case 2 (~ 4441 ms): >> >> Map2 = Map#{id => N, name => N, age => N, dog => N, cat => N, mow => >> N, tin => N}, >> >> case 3 (~952 ms): >> >> Map2 = maps:update(id, N + 1, Map) >> >> case 4 (~6054 ms) >> >> Map2 = maps:update(id, N + 1, Map), >> >> Map3 = maps:update(name, N + 1, Map2), >> >> Map4 = maps:update(age, N + 1, Map3), >> >> Map5 = maps:update(dog, N + 1, Map4), >> >> Map6 = maps:update(cat, N + 1, Map5), >> >> Map7 = maps:update(mow, N + 1, Map6), >> >> Map8 = maps:update(tin, N + 1, Map7), >> >> Proplists: >> >> case 1: no equivalent >> >> case 2: no equivalent >> >> case 3: (~1529 ms) >> >> PPL2 = lists:keystore(id, 1, PPL, {id, N + N}), >> >> case 4: (~30705 ms) >> >> PPL2 = lists:keystore(id, 1, PPL, {id, N + N}), >> >> PPL3 = lists:keystore(name, 1, PPL2, {name, N + N}), >> >> PPL4 = lists:keystore(age, 1, PPL3, {age, N + N}), >> >> PPL5 = lists:keystore(dog, 1, PPL4, {dog, N + N}), >> >> PPL6 = lists:keystore(cat, 1, PPL5, {cat, N + N}), >> >> PPL7 = lists:keystore(mow, 1, PPL6, {mow, N + N}), >> >> PPL8 = lists:keystore(tin, 1, PPL7, {tin, N + N}), >> >> >> >> What about that? I think using maps:get/2 is not so fast as using map >> pattern matching. >> >> >> >> Cheers, >> >> Ivan (son of Gilberio). >> >> >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > From g@REDACTED Mon Aug 17 12:38:02 2015 From: g@REDACTED (Garrett Smith) Date: Mon, 17 Aug 2015 05:38:02 -0500 Subject: [erlang-questions] feedback on my solutions to programming erlang second edition In-Reply-To: <55D19804.4020101@ninenines.eu> References: <55CDA6CD.2050501@home.nl> <55CDD109.1080109@home.nl> <051BD7DA-89C8-4877-B4E4-C0C5B1045855@cs.otago.ac.nz> <55D19804.4020101@ninenines.eu> Message-ID: On Mon, Aug 17, 2015 at 3:15 AM, Lo?c Hoguin wrote: > On 08/17/2015 02:36 AM, Richard A. O'Keefe wrote: >> >> >> On 14/08/2015, at 11:29 pm, Roelof Wobben wrote: >>> >>> So it's fine to give this a error message : >>> >>> ** exception error: {read_file,"wrong.txt",enoent} in function >>> my_file:read/1 (my_file.erl, line 8)) >> >> >>> I think a unexperience users still does not know what went wrong. >> >> >> You are 100% right that there is a conflict here between >> >> (P) reporting an error in a way that >> a PROGRAM can readily catch and handle >> (H) reporting an error in a way that >> a HUMAN can readily understand. >> >> You are not the first to run into this, >> and there is a pattern for dealing with it in Erlang: >> >> if a module M reports error E >> call M:format_error(E) to get a human-readable text. >> >> See http://www.erlang.org/doc/man/file.html#format_error-1 >> for an example. > > > This is the pattern that is in Erlang but honestly it is very limited. > > Take the HTTP protocol for example. There are a thousand ways things can go > wrong. Are you really going to make a separate atom for each error and then > call format_error to know what went wrong? How do you call them, > parse_error0, parse_error1, parse_error2? Are you going to end with > parse_error formatted as "Parse error." without any clue of what actually > went wrong? > > I find that returning {error, ErrorForPrograms, ErrorForHumans} is a much > saner solution because the first error value helps the program know what > kind of error it is, and the second error value says exactly what happened > for the human who is debugging (locally or when calling an HTTP service, as > this error can also be sent as response). > > This has the additional benefit that the ErrorForHumans value also serves as > inlined documentation. I wouldn't make this as a general recommendation for folks. It might make sense in a particular application. My rule is that an error should convey the minimal amount of information to identify and fix a problem. In a lot of cases that's an internal problem that needs some rethinking, additional logic, etc. but once handled properly shouldn't surface to the user. Problems that can legitimately be handled by a user, including some user readable content in the original message seems fine. As for i18n, it's common to translate the original message, usually in English, when presented to the user. For me the task at hand is to augment an error condition with context so you can resolve it. E.g. adding a filename to a file error, which by itself is completely useless. I wonder why stack variables aren't included in stack traces - I've never seen that in any language (Richard? :) but it would be fantastically useful. From essen@REDACTED Mon Aug 17 12:54:56 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Mon, 17 Aug 2015 12:54:56 +0200 Subject: [erlang-questions] feedback on my solutions to programming erlang second edition In-Reply-To: References: <55CDA6CD.2050501@home.nl> <55CDD109.1080109@home.nl> <051BD7DA-89C8-4877-B4E4-C0C5B1045855@cs.otago.ac.nz> <55D19804.4020101@ninenines.eu> Message-ID: <55D1BD80.6050707@ninenines.eu> On 08/17/2015 12:38 PM, Garrett Smith wrote: > On Mon, Aug 17, 2015 at 3:15 AM, Lo?c Hoguin wrote: >> On 08/17/2015 02:36 AM, Richard A. O'Keefe wrote: >>> >>> >>> On 14/08/2015, at 11:29 pm, Roelof Wobben wrote: >>>> >>>> So it's fine to give this a error message : >>>> >>>> ** exception error: {read_file,"wrong.txt",enoent} in function >>>> my_file:read/1 (my_file.erl, line 8)) >>> >>> >>>> I think a unexperience users still does not know what went wrong. >>> >>> >>> You are 100% right that there is a conflict here between >>> >>> (P) reporting an error in a way that >>> a PROGRAM can readily catch and handle >>> (H) reporting an error in a way that >>> a HUMAN can readily understand. >>> >>> You are not the first to run into this, >>> and there is a pattern for dealing with it in Erlang: >>> >>> if a module M reports error E >>> call M:format_error(E) to get a human-readable text. >>> >>> See http://www.erlang.org/doc/man/file.html#format_error-1 >>> for an example. >> >> >> This is the pattern that is in Erlang but honestly it is very limited. >> >> Take the HTTP protocol for example. There are a thousand ways things can go >> wrong. Are you really going to make a separate atom for each error and then >> call format_error to know what went wrong? How do you call them, >> parse_error0, parse_error1, parse_error2? Are you going to end with >> parse_error formatted as "Parse error." without any clue of what actually >> went wrong? >> >> I find that returning {error, ErrorForPrograms, ErrorForHumans} is a much >> saner solution because the first error value helps the program know what >> kind of error it is, and the second error value says exactly what happened >> for the human who is debugging (locally or when calling an HTTP service, as >> this error can also be sent as response). >> >> This has the additional benefit that the ErrorForHumans value also serves as >> inlined documentation. > > I wouldn't make this as a general recommendation for folks. It might > make sense in a particular application. > > My rule is that an error should convey the minimal amount of > information to identify and fix a problem. In a lot of cases that's an > internal problem that needs some rethinking, additional logic, etc. > but once handled properly shouldn't surface to the user. Problems that > can legitimately be handled by a user, including some user readable > content in the original message seems fine. As for i18n, it's common > to translate the original message, usually in English, when presented > to the user. The error message I am talking about is *not* for end users (i.e. your mom on Facebook) but for *developers* (i.e. Facebook engineers) who have to look at the logs and figure out what went wrong. > For me the task at hand is to augment an error condition with context > so you can resolve it. E.g. adding a filename to a file error, which > by itself is completely useless. Files are harder, because having the filename will probably not help you anyway. Sometimes you do know exactly what the error is about, though, so put a nice message with all the related info for the guy who will debug this. > I wonder why stack variables aren't included in stack traces - I've > never seen that in any language (Richard? :) but it would be > fantastically useful. That would be pretty cool. -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From g@REDACTED Mon Aug 17 13:07:27 2015 From: g@REDACTED (Garrett Smith) Date: Mon, 17 Aug 2015 06:07:27 -0500 Subject: [erlang-questions] feedback on my solutions to programming erlang second edition In-Reply-To: <55D1BD80.6050707@ninenines.eu> References: <55CDA6CD.2050501@home.nl> <55CDD109.1080109@home.nl> <051BD7DA-89C8-4877-B4E4-C0C5B1045855@cs.otago.ac.nz> <55D19804.4020101@ninenines.eu> <55D1BD80.6050707@ninenines.eu> Message-ID: On Mon, Aug 17, 2015 at 5:54 AM, Lo?c Hoguin wrote: > On 08/17/2015 12:38 PM, Garrett Smith wrote: >> >> On Mon, Aug 17, 2015 at 3:15 AM, Lo?c Hoguin wrote: >>> I find that returning {error, ErrorForPrograms, ErrorForHumans} is a much >>> saner solution because the first error value helps the program know what >>> kind of error it is, and the second error value says exactly what >>> happened >>> for the human who is debugging (locally or when calling an HTTP service, >>> as >>> this error can also be sent as response). >>> >>> This has the additional benefit that the ErrorForHumans value also serves >>> as >>> inlined documentation. >> >> >> I wouldn't make this as a general recommendation for folks. It might >> make sense in a particular application. >> >> My rule is that an error should convey the minimal amount of >> information to identify and fix a problem. In a lot of cases that's an >> internal problem that needs some rethinking, additional logic, etc. >> but once handled properly shouldn't surface to the user. Problems that >> can legitimately be handled by a user, including some user readable >> content in the original message seems fine. As for i18n, it's common >> to translate the original message, usually in English, when presented >> to the user. > > The error message I am talking about is *not* for end users (i.e. your mom > on Facebook) but for *developers* (i.e. Facebook engineers) who have to look > at the logs and figure out what went wrong. Yeah, my Mom hates those cryptic Erlang term errors :) For me as a programmer (though Facebook would never hire me so this is speculative) I will try to tie the error to it's source like this: open_user_config(Name) -> case open_file(Name) of {ok, File} -> File; {error, Err} -> error({open_user_config, Name, Err}) end. which will manifest as, e.g.: {'EXIT',{{open_user_config,"/etc/user.config",enoent}, ...} which is pretty easy to follow IMO. I imagine this is what you're talking about, the difference being in the use of atoms vs strings as "user descriptors", or no? From essen@REDACTED Mon Aug 17 13:14:39 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Mon, 17 Aug 2015 13:14:39 +0200 Subject: [erlang-questions] feedback on my solutions to programming erlang second edition In-Reply-To: References: <55CDA6CD.2050501@home.nl> <55CDD109.1080109@home.nl> <051BD7DA-89C8-4877-B4E4-C0C5B1045855@cs.otago.ac.nz> <55D19804.4020101@ninenines.eu> <55D1BD80.6050707@ninenines.eu> Message-ID: <55D1C21F.3070101@ninenines.eu> On 08/17/2015 01:07 PM, Garrett Smith wrote: > On Mon, Aug 17, 2015 at 5:54 AM, Lo?c Hoguin wrote: >> On 08/17/2015 12:38 PM, Garrett Smith wrote: >>> >>> On Mon, Aug 17, 2015 at 3:15 AM, Lo?c Hoguin wrote: >>>> I find that returning {error, ErrorForPrograms, ErrorForHumans} is a much >>>> saner solution because the first error value helps the program know what >>>> kind of error it is, and the second error value says exactly what >>>> happened >>>> for the human who is debugging (locally or when calling an HTTP service, >>>> as >>>> this error can also be sent as response). >>>> >>>> This has the additional benefit that the ErrorForHumans value also serves >>>> as >>>> inlined documentation. >>> >>> >>> I wouldn't make this as a general recommendation for folks. It might >>> make sense in a particular application. >>> >>> My rule is that an error should convey the minimal amount of >>> information to identify and fix a problem. In a lot of cases that's an >>> internal problem that needs some rethinking, additional logic, etc. >>> but once handled properly shouldn't surface to the user. Problems that >>> can legitimately be handled by a user, including some user readable >>> content in the original message seems fine. As for i18n, it's common >>> to translate the original message, usually in English, when presented >>> to the user. >> >> The error message I am talking about is *not* for end users (i.e. your mom >> on Facebook) but for *developers* (i.e. Facebook engineers) who have to look >> at the logs and figure out what went wrong. > > Yeah, my Mom hates those cryptic Erlang term errors :) > > For me as a programmer (though Facebook would never hire me so this is > speculative) I will try to tie the error to it's source like this: > > open_user_config(Name) -> > case open_file(Name) of > {ok, File} -> File; > {error, Err} -> error({open_user_config, Name, Err}) > end. > > which will manifest as, e.g.: > > {'EXIT',{{open_user_config,"/etc/user.config",enoent}, ...} > > which is pretty easy to follow IMO. Yes, though for errors as simple as this the benefits are not as obvious as errors where the answer is deep inside a hundred pages document. :-) Actually there's different kinds of errors, and the one kind that benefits the most from this would be programmer error when calling the function/service/.. In other words errors that say "YOU SHALL NOT PASS because of reasons X Y Z." > I imagine this is what you're talking about, the difference being in > the use of atoms vs strings as "user descriptors", or no? I use atoms because they're very cheap *but* if I had to have some variables bundled into it I would use a tuple like you do. -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From jesper.louis.andersen@REDACTED Mon Aug 17 14:03:53 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Mon, 17 Aug 2015 14:03:53 +0200 Subject: [erlang-questions] Todays Topic: Performance Stuffs->records vs maps vs proplists In-Reply-To: References: <000c01d0d84b$aecece40$0c6c6ac0$@co.cu> Message-ID: On Mon, Aug 17, 2015 at 9:30 AM, Erik S?e S?rensen wrote: > Also, you don't state the size of the data structure you're manipulating - > only the number of iterations. Indeed. And also you don't specify what the key order is. If I have a proplist of any size, PL, and then I do PropList = [{x, y} | PL], lists:keyfind(x, 1, PropList). Then the key lookup will be in constant time. If on the other hand I do PropList = PL ++ [{x,y}] Then the lookup is in the order of O(n) where n is the length of PL. In other words, a proplist can hit the two extreme cases, with the typical case being O(n) (since you have to search half the elements on average). In contrast, a map has an upper bound of O(lg n) (with an extremely wide branching factor). Beware the synthetic benchmark. For it lures you into false thinking. -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From snowwlex@REDACTED Mon Aug 17 13:46:46 2015 From: snowwlex@REDACTED (Alexander Turkin) Date: Mon, 17 Aug 2015 12:46:46 +0100 Subject: [erlang-questions] utf-8 and xmerl In-Reply-To: <55733d25-129c-4f19-94a3-4e15fc22b692@email.android.com> References: <55733d25-129c-4f19-94a3-4e15fc22b692@email.android.com> Message-ID: Hi ?ric, my Erlang is R16B03 On 14 August 2015 at 17:23, ?ric Pailleau wrote: > Hello, > Please precise what Erlang release you are using. Utf8 came lately in > Erlang. > Regards > > Le 14 ao?t 2015 13:49, Alexander Turkin a ?crit : > > > > Dear list, > > > > > > I've got a problem with unicode & xmerl library. > > > > Input data for xmerl is utf-8 encoded xml, and what I've got as the > result is encoded latin1. But I need utf8! > > > > > > EXAMPLES > > > > Body = <<" encoding=\"UTF-8\"?>Ren?"/utf8>>. > > > > (for the sake of portability here is term_to_binary(Body): > > > > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, > > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, > > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, > > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, > > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, > > 115,112,111,110,115,101,62>> > > > > > > > > (1): > > > > When I do > > > > xmerl_scan:string(binary_to_list(Body)). > > > > it returns > > > > {#xmlElement{name = response,expanded_name = response, > > nsinfo = [], > > namespace = #xmlNamespace{default = [],nodes = []}, > > parents = [],pos = 1,attributes = [], > > content = [#xmlElement{name = value,expanded_name = value, > > nsinfo = [], > > namespace = #xmlNamespace{default = > [],nodes = []}, > > parents = [{response,1}], > > pos = 1,attributes = [], > > content = [#xmlText{parents = > [{value,1},{response,1}], > > pos = 1,language > = [], > > > > > > value = "Ren?", > > > > > > type = text}], > > language = [],xmlbase = > "/Users/aturkin/ws/", > > elementdef = undeclared}], > > language = [],xmlbase = "/Users/aturkin/ws/", > > elementdef = undeclared}, > > []} > > > > > > So, note there is `value = "Ren?"` string, and it uses [233] symbol, > which is latin1. > > > > > > > > > > (2): > > > > xmerl_scan:string(xmerl_ucs:to_utf8(binary_to_list(Body))) > > > > returns > > > > {#xmlElement{name = response,expanded_name = response, > > nsinfo = [], > > namespace = #xmlNamespace{default = [],nodes = []}, > > parents = [],pos = 1,attributes = [], > > content = [#xmlElement{name = value,expanded_name = value, > > nsinfo = [], > > namespace = #xmlNamespace{default = > [],nodes = []}, > > parents = [{response,1}], > > pos = 1,attributes = [], > > content = [#xmlText{parents = > [{value,1},{response,1}], > > pos = 1,language > = [], > > > > > > value = "Ren??", > > > > > > type = text}], > > language = [],xmlbase = > "/Users/aturkin/ws/", > > elementdef = undeclared}], > > language = [],xmlbase = "/Users/aturkin/ws/", > > elementdef = undeclared}, > > []} > > > > Now `value = "Ren??"`, so 2 bytes are used to code this symbol, and this > is utf-8. > > > > So in (2) I get what I need, but why I need to force that conversion for > xmerl? > > > > > > > > > > QUESTIONS > > > > 1. I don't understand why xmerl_scan allows you to set input encoding, > but it looks like there is no way to set output encoding. Is there any way > to make xmerl_scan to return utf8 instead of latin1? > > > > 2. How is that happen, that in (1) it does conversion utf-8 -> latin1, > and in (2) it's utf-8? > > > > > > > > > > -- > > Best Regards, > > Alex Turkin > -- Best Regards, Alex Turkin -------------- next part -------------- An HTML attachment was scrubbed... URL: From sverker.eriksson@REDACTED Mon Aug 17 14:27:56 2015 From: sverker.eriksson@REDACTED (Sverker Eriksson) Date: Mon, 17 Aug 2015 14:27:56 +0200 Subject: [erlang-questions] The most effective way to check ETS-table created In-Reply-To: References: Message-ID: <55D1D34C.50808@ericsson.com> On 07/16/2015 02:09 PM, Oleksii Semilietov wrote: > Did somebody make research about the most cheap and effective way to > check is ets table exists? > > What should be faster ets:info(Table) or ets:first(Table) with > exception? Any other suggestion? > > I would think ets:info(Table, size) is cheapest. /Sverker, Erlang/OTP -------------- next part -------------- An HTML attachment was scrubbed... URL: From snowwlex@REDACTED Mon Aug 17 14:39:44 2015 From: snowwlex@REDACTED (Alexander Turkin) Date: Mon, 17 Aug 2015 13:39:44 +0100 Subject: [erlang-questions] utf-8 and xmerl In-Reply-To: References: <55733d25-129c-4f19-94a3-4e15fc22b692@email.android.com> Message-ID: Hi Hynek, On 15 August 2015 at 08:30, Hynek Vychodil wrote: > The same result is in R18 and it it correct result. Letter ? has unicode > 233 see http://unicode-table.com/en/#00E9 > Yeah, it has U+00E9 (= 233) code point number, but it is coded in 2 bytes in utf8: c3 a9 U+00E9?c3 a9LATIN SMALL LETTER E WITH ACUTE (http://www.utf8-chartable.de/) > > On Fri, Aug 14, 2015 at 6:23 PM, ?ric Pailleau > wrote: > >> Hello, >> Please precise what Erlang release you are using. Utf8 came lately in >> Erlang. >> Regards >> >> Le 14 ao?t 2015 13:49, Alexander Turkin a ?crit : >> > >> > Dear list, >> > >> > >> > I've got a problem with unicode & xmerl library. >> > >> > Input data for xmerl is utf-8 encoded xml, and what I've got as the >> result is encoded latin1. But I need utf8! >> > >> > >> > EXAMPLES >> > >> > Body = <<"> encoding=\"UTF-8\"?>Ren?"/utf8>>. >> > >> > (for the sake of portability here is term_to_binary(Body): >> > >> > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, >> > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, >> > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, >> > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, >> > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, >> > 115,112,111,110,115,101,62>> >> > >> > >> > >> > (1): >> > >> > When I do >> > >> > xmerl_scan:string(binary_to_list(Body)). >> > >> > it returns >> > >> > {#xmlElement{name = response,expanded_name = response, >> > nsinfo = [], >> > namespace = #xmlNamespace{default = [],nodes = []}, >> > parents = [],pos = 1,attributes = [], >> > content = [#xmlElement{name = value,expanded_name = value, >> > nsinfo = [], >> > namespace = #xmlNamespace{default = >> [],nodes = []}, >> > parents = [{response,1}], >> > pos = 1,attributes = [], >> > content = [#xmlText{parents = >> [{value,1},{response,1}], >> > pos = >> 1,language = [], >> > >> > >> > value = "Ren?", >> > >> > >> > type = text}], >> > language = [],xmlbase = >> "/Users/aturkin/ws/", >> > elementdef = undeclared}], >> > language = [],xmlbase = "/Users/aturkin/ws/", >> > elementdef = undeclared}, >> > []} >> > >> > >> > So, note there is `value = "Ren?"` string, and it uses [233] symbol, >> which is latin1. >> > >> > >> > >> > >> > (2): >> > >> > xmerl_scan:string(xmerl_ucs:to_utf8(binary_to_list(Body))) >> > >> > returns >> > >> > {#xmlElement{name = response,expanded_name = response, >> > nsinfo = [], >> > namespace = #xmlNamespace{default = [],nodes = []}, >> > parents = [],pos = 1,attributes = [], >> > content = [#xmlElement{name = value,expanded_name = value, >> > nsinfo = [], >> > namespace = #xmlNamespace{default = >> [],nodes = []}, >> > parents = [{response,1}], >> > pos = 1,attributes = [], >> > content = [#xmlText{parents = >> [{value,1},{response,1}], >> > pos = >> 1,language = [], >> > >> > >> > value = "Ren??", >> > >> > >> > type = text}], >> > language = [],xmlbase = >> "/Users/aturkin/ws/", >> > elementdef = undeclared}], >> > language = [],xmlbase = "/Users/aturkin/ws/", >> > elementdef = undeclared}, >> > []} >> > >> > Now `value = "Ren??"`, so 2 bytes are used to code this symbol, and >> this is utf-8. >> > >> > So in (2) I get what I need, but why I need to force that conversion >> for xmerl? >> > >> > >> > >> > >> > QUESTIONS >> > >> > 1. I don't understand why xmerl_scan allows you to set input encoding, >> but it looks like there is no way to set output encoding. Is there any way >> to make xmerl_scan to return utf8 instead of latin1? >> > >> > 2. How is that happen, that in (1) it does conversion utf-8 -> latin1, >> and in (2) it's utf-8? >> > >> > >> > >> > >> > -- >> > Best Regards, >> > Alex Turkin >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> > > -- Best Regards, Alex Turkin -------------- next part -------------- An HTML attachment was scrubbed... URL: From tony@REDACTED Mon Aug 17 14:52:36 2015 From: tony@REDACTED (Tony Rogvall) Date: Mon, 17 Aug 2015 14:52:36 +0200 Subject: [erlang-questions] utf-8 and xmerl In-Reply-To: References: <55733d25-129c-4f19-94a3-4e15fc22b692@email.android.com> Message-ID: <1DB676EA-140F-4049-8E6D-94D283D3D13D@rogvall.se> > On 17 aug 2015, at 14:39, Alexander Turkin wrote: > > Hi Hynek, > > On 15 August 2015 at 08:30, Hynek Vychodil > wrote: > The same result is in R18 and it it correct result. Letter ? has unicode 233 see http://unicode-table.com/en/#00E9 > > Yeah, it has U+00E9 (= 233) code point number, but it is coded in 2 bytes in utf8: c3 a9 > > U+00E9 ? c3 a9 LATIN SMALL LETTER E WITH ACUTE > > > (http://www.utf8-chartable.de/ ) > > On Fri, Aug 14, 2015 at 6:23 PM, ?ric Pailleau > wrote: > Hello, > Please precise what Erlang release you are using. Utf8 came lately in Erlang. > Regards > > Le 14 ao?t 2015 13:49, Alexander Turkin > a ?crit : > > > > Dear list, > > > > > > I've got a problem with unicode & xmerl library. > > > > Input data for xmerl is utf-8 encoded xml, and what I've got as the result is encoded latin1. But I need utf8! > > > > > > EXAMPLES > > > > Body = <<"Ren?"/utf8>>. > > > > (for the sake of portability here is term_to_binary(Body): > > > > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, > > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, > > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, > > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, > > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, > > 115,112,111,110,115,101,62>> > > > > > > > > (1): > > > > When I do > > > > xmerl_scan:string(binary_to_list(Body)). > > > > it returns > > > > {#xmlElement{name = response,expanded_name = response, > > nsinfo = [], > > namespace = #xmlNamespace{default = [],nodes = []}, > > parents = [],pos = 1,attributes = [], > > content = [#xmlElement{name = value,expanded_name = value, > > nsinfo = [], > > namespace = #xmlNamespace{default = [],nodes = []}, > > parents = [{response,1}], > > pos = 1,attributes = [], > > content = [#xmlText{parents = [{value,1},{response,1}], > > pos = 1,language = [], > > > > > > value = "Ren?", > > > > > > type = text}], > > language = [],xmlbase = "/Users/aturkin/ws/", > > elementdef = undeclared}], > > language = [],xmlbase = "/Users/aturkin/ws/", > > elementdef = undeclared}, > > []} > > > > > > So, note there is `value = "Ren?"` string, and it uses [233] symbol, which is latin1. > > > > > > > > > > (2): > > > > xmerl_scan:string(xmerl_ucs:to_utf8(binary_to_list(Body))) > > > > returns > > > > {#xmlElement{name = response,expanded_name = response, > > nsinfo = [], > > namespace = #xmlNamespace{default = [],nodes = []}, > > parents = [],pos = 1,attributes = [], > > content = [#xmlElement{name = value,expanded_name = value, > > nsinfo = [], > > namespace = #xmlNamespace{default = [],nodes = []}, > > parents = [{response,1}], > > pos = 1,attributes = [], > > content = [#xmlText{parents = [{value,1},{response,1}], > > pos = 1,language = [], > > > > > > value = "Ren??", > > > > > > type = text}], > > language = [],xmlbase = "/Users/aturkin/ws/", > > elementdef = undeclared}], > > language = [],xmlbase = "/Users/aturkin/ws/", > > elementdef = undeclared}, > > []} > > > > Now `value = "Ren??"`, so 2 bytes are used to code this symbol, and this is utf-8. > > > > So in (2) I get what I need, but why I need to force that conversion for xmerl? > > > > > > > > > > QUESTIONS > > > > 1. I don't understand why xmerl_scan allows you to set input encoding, but it looks like there is no way to set output encoding. Is there any way to make xmerl_scan to return utf8 instead of latin1? > > > > 2. How is that happen, that in (1) it does conversion utf-8 -> latin1, and in (2) it's utf-8? > > > > > > > > > > -- > > Best Regards, > > Alex Turkin > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > > > > -- > Best Regards, > Alex Turkin > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: Message signed with OpenPGP using GPGMail URL: From tony@REDACTED Mon Aug 17 14:55:41 2015 From: tony@REDACTED (Tony Rogvall) Date: Mon, 17 Aug 2015 14:55:41 +0200 Subject: [erlang-questions] utf-8 and xmerl In-Reply-To: References: <55733d25-129c-4f19-94a3-4e15fc22b692@email.android.com> Message-ID: Sorry for the empty message :-) But the coding you are looking for is already in your binary. <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, 115,112,111,110,115,101,62>> 195,169 = c3 a9 /Tony > On 17 aug 2015, at 14:39, Alexander Turkin wrote: > > Hi Hynek, > > On 15 August 2015 at 08:30, Hynek Vychodil > wrote: > The same result is in R18 and it it correct result. Letter ? has unicode 233 see http://unicode-table.com/en/#00E9 > > Yeah, it has U+00E9 (= 233) code point number, but it is coded in 2 bytes in utf8: c3 a9 > > U+00E9 ? c3 a9 LATIN SMALL LETTER E WITH ACUTE > > > (http://www.utf8-chartable.de/ ) > > On Fri, Aug 14, 2015 at 6:23 PM, ?ric Pailleau > wrote: > Hello, > Please precise what Erlang release you are using. Utf8 came lately in Erlang. > Regards > > Le 14 ao?t 2015 13:49, Alexander Turkin > a ?crit : > > > > Dear list, > > > > > > I've got a problem with unicode & xmerl library. > > > > Input data for xmerl is utf-8 encoded xml, and what I've got as the result is encoded latin1. But I need utf8! > > > > > > EXAMPLES > > > > Body = <<"Ren?"/utf8>>. > > > > (for the sake of portability here is term_to_binary(Body): > > > > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, > > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, > > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, > > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, > > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, > > 115,112,111,110,115,101,62>> > > > > > > > > (1): > > > > When I do > > > > xmerl_scan:string(binary_to_list(Body)). > > > > it returns > > > > {#xmlElement{name = response,expanded_name = response, > > nsinfo = [], > > namespace = #xmlNamespace{default = [],nodes = []}, > > parents = [],pos = 1,attributes = [], > > content = [#xmlElement{name = value,expanded_name = value, > > nsinfo = [], > > namespace = #xmlNamespace{default = [],nodes = []}, > > parents = [{response,1}], > > pos = 1,attributes = [], > > content = [#xmlText{parents = [{value,1},{response,1}], > > pos = 1,language = [], > > > > > > value = "Ren?", > > > > > > type = text}], > > language = [],xmlbase = "/Users/aturkin/ws/", > > elementdef = undeclared}], > > language = [],xmlbase = "/Users/aturkin/ws/", > > elementdef = undeclared}, > > []} > > > > > > So, note there is `value = "Ren?"` string, and it uses [233] symbol, which is latin1. > > > > > > > > > > (2): > > > > xmerl_scan:string(xmerl_ucs:to_utf8(binary_to_list(Body))) > > > > returns > > > > {#xmlElement{name = response,expanded_name = response, > > nsinfo = [], > > namespace = #xmlNamespace{default = [],nodes = []}, > > parents = [],pos = 1,attributes = [], > > content = [#xmlElement{name = value,expanded_name = value, > > nsinfo = [], > > namespace = #xmlNamespace{default = [],nodes = []}, > > parents = [{response,1}], > > pos = 1,attributes = [], > > content = [#xmlText{parents = [{value,1},{response,1}], > > pos = 1,language = [], > > > > > > value = "Ren??", > > > > > > type = text}], > > language = [],xmlbase = "/Users/aturkin/ws/", > > elementdef = undeclared}], > > language = [],xmlbase = "/Users/aturkin/ws/", > > elementdef = undeclared}, > > []} > > > > Now `value = "Ren??"`, so 2 bytes are used to code this symbol, and this is utf-8. > > > > So in (2) I get what I need, but why I need to force that conversion for xmerl? > > > > > > > > > > QUESTIONS > > > > 1. I don't understand why xmerl_scan allows you to set input encoding, but it looks like there is no way to set output encoding. Is there any way to make xmerl_scan to return utf8 instead of latin1? > > > > 2. How is that happen, that in (1) it does conversion utf-8 -> latin1, and in (2) it's utf-8? > > > > > > > > > > -- > > Best Regards, > > Alex Turkin > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > > > > -- > Best Regards, > Alex Turkin > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- An HTML attachment was scrubbed... URL: From hans.bolinder@REDACTED Mon Aug 17 15:13:53 2015 From: hans.bolinder@REDACTED (Hans Bolinder) Date: Mon, 17 Aug 2015 13:13:53 +0000 Subject: [erlang-questions] Re: Optional callbacks Message-ID: <56466BD70414EA48969B4064696CF28C21EF28F7@ESESSMB207.ericsson.se> Hi, [Lo?c Hoguin [essen@REDACTED:] > Started trying to play with those, and not managing to get a warning > from Dialyzer. I tried adding -optional_callbacks([sample_callback_1/0, sample_callback_2/0, sample_callback_3/0, sample_callback_4/1, sample_callback_5/1, sample_callback_6/3]). to lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_behaviour.erl, and got the expected Dialyzer messages, so I guess it's more complicated than that. Could you please provide an example? Best regards, Hans Bolinder, Erlang/OTP team, Ericsson From snowwlex@REDACTED Mon Aug 17 15:56:56 2015 From: snowwlex@REDACTED (Alexander Turkin) Date: Mon, 17 Aug 2015 14:56:56 +0100 Subject: [erlang-questions] utf-8 and xmerl In-Reply-To: References: <55733d25-129c-4f19-94a3-4e15fc22b692@email.android.com> Message-ID: Hey Tony, Yes, this binary is in utf8 - and it is what it's being fed to xmerl library, which returns it in the other encoding by some reasons. On 17 August 2015 at 13:55, Tony Rogvall wrote: > Sorry for the empty message :-) > > But the coding you are looking for is already in your binary. > > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, > 115,112,111,110,115,101,62>> > > 195,169 = c3 a9 > > /Tony > > > On 17 aug 2015, at 14:39, Alexander Turkin wrote: > > Hi Hynek, > > On 15 August 2015 at 08:30, Hynek Vychodil > wrote: > >> The same result is in R18 and it it correct result. Letter ? has unicode >> 233 see http://unicode-table.com/en/#00E9 >> > > Yeah, it has U+00E9 (= 233) code point number, but it is coded in 2 bytes > in utf8: c3 a9 > > U+00E9?c3 a9LATIN SMALL LETTER E WITH ACUTE > > > (http://www.utf8-chartable.de/) > >> >> On Fri, Aug 14, 2015 at 6:23 PM, ?ric Pailleau >> wrote: >> >>> Hello, >>> Please precise what Erlang release you are using. Utf8 came lately in >>> Erlang. >>> Regards >>> >>> Le 14 ao?t 2015 13:49, Alexander Turkin a ?crit : >>> > >>> > Dear list, >>> > >>> > >>> > I've got a problem with unicode & xmerl library. >>> > >>> > Input data for xmerl is utf-8 encoded xml, and what I've got as the >>> result is encoded latin1. But I need utf8! >>> > >>> > >>> > EXAMPLES >>> > >>> > Body = <<">> encoding=\"UTF-8\"?>Ren?"/utf8>>. >>> > >>> > (for the sake of portability here is term_to_binary(Body): >>> > >>> > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, >>> > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, >>> > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, >>> > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, >>> > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, >>> > 115,112,111,110,115,101,62>> >>> > >>> > >>> > >>> > (1): >>> > >>> > When I do >>> > >>> > xmerl_scan:string(binary_to_list(Body)). >>> > >>> > it returns >>> > >>> > {#xmlElement{name = response,expanded_name = response, >>> > nsinfo = [], >>> > namespace = #xmlNamespace{default = [],nodes = []}, >>> > parents = [],pos = 1,attributes = [], >>> > content = [#xmlElement{name = value,expanded_name = value, >>> > nsinfo = [], >>> > namespace = #xmlNamespace{default >>> = [],nodes = []}, >>> > parents = [{response,1}], >>> > pos = 1,attributes = [], >>> > content = [#xmlText{parents = >>> [{value,1},{response,1}], >>> > pos = >>> 1,language = [], >>> > >>> > >>> > value = "Ren?", >>> > >>> > >>> > type = text}], >>> > language = [],xmlbase = >>> "/Users/aturkin/ws/", >>> > elementdef = undeclared}], >>> > language = [],xmlbase = "/Users/aturkin/ws/", >>> > elementdef = undeclared}, >>> > []} >>> > >>> > >>> > So, note there is `value = "Ren?"` string, and it uses [233] symbol, >>> which is latin1. >>> > >>> > >>> > >>> > >>> > (2): >>> > >>> > xmerl_scan:string(xmerl_ucs:to_utf8(binary_to_list(Body))) >>> > >>> > returns >>> > >>> > {#xmlElement{name = response,expanded_name = response, >>> > nsinfo = [], >>> > namespace = #xmlNamespace{default = [],nodes = []}, >>> > parents = [],pos = 1,attributes = [], >>> > content = [#xmlElement{name = value,expanded_name = value, >>> > nsinfo = [], >>> > namespace = #xmlNamespace{default >>> = [],nodes = []}, >>> > parents = [{response,1}], >>> > pos = 1,attributes = [], >>> > content = [#xmlText{parents = >>> [{value,1},{response,1}], >>> > pos = >>> 1,language = [], >>> > >>> > >>> > value = >>> "Ren??", >>> > >>> > >>> > type = text}], >>> > language = [],xmlbase = >>> "/Users/aturkin/ws/", >>> > elementdef = undeclared}], >>> > language = [],xmlbase = "/Users/aturkin/ws/", >>> > elementdef = undeclared}, >>> > []} >>> > >>> > Now `value = "Ren??"`, so 2 bytes are used to code this symbol, and >>> this is utf-8. >>> > >>> > So in (2) I get what I need, but why I need to force that conversion >>> for xmerl? >>> > >>> > >>> > >>> > >>> > QUESTIONS >>> > >>> > 1. I don't understand why xmerl_scan allows you to set input encoding, >>> but it looks like there is no way to set output encoding. Is there any way >>> to make xmerl_scan to return utf8 instead of latin1? >>> > >>> > 2. How is that happen, that in (1) it does conversion utf-8 -> latin1, >>> and in (2) it's utf-8? >>> > >>> > >>> > >>> > >>> > -- >>> > Best Regards, >>> > Alex Turkin >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >>> >> >> > > > -- > Best Regards, > Alex Turkin > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > > -- Best Regards, Alex Turkin -------------- next part -------------- An HTML attachment was scrubbed... URL: From tony@REDACTED Mon Aug 17 17:26:05 2015 From: tony@REDACTED (Tony Rogvall) Date: Mon, 17 Aug 2015 17:26:05 +0200 Subject: [erlang-questions] utf-8 and xmerl In-Reply-To: References: <55733d25-129c-4f19-94a3-4e15fc22b692@email.android.com> Message-ID: <06CE3C59-5056-4B3C-ADE7-E48DCCB3BFE7@rogvall.se> Ok I see. So you expected to find utf8 in the text value instead of the unicode ( 233 is the same in latin1 and unicode btw ) But that is not how the xmerl works. It represents the characters in unicode iso-10646. Here is an example to get you a utf8 output. Bin is your binary. Term = binary_to_term(Bin). {Content,_} = xmerl_scan:string(binary_to_list(Term)). UnicodeChars = xmerl:export([Content], xmerl_xml). Utf8Bin = unicode:characters_to_binary(UnicodeChars). I guess you could scan the xml structure (Content) and convert the text values to utf8 strings. But that would complicate the process when you want to format the output. Why do you want to have utf8 in the values ? unicode is much more generic and you select the encoding on the way out! /Tony > On 17 aug 2015, at 15:56, Alexander Turkin wrote: > > Hey Tony, > > Yes, this binary is in utf8 - and it is what it's being fed to xmerl library, which returns it in the other encoding by some reasons. > > On 17 August 2015 at 13:55, Tony Rogvall wrote: > Sorry for the empty message :-) > > But the coding you are looking for is already in your binary. > > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, > 115,112,111,110,115,101,62>> > > 195,169 = c3 a9 > > /Tony > > >> On 17 aug 2015, at 14:39, Alexander Turkin wrote: >> >> Hi Hynek, >> >> On 15 August 2015 at 08:30, Hynek Vychodil wrote: >> The same result is in R18 and it it correct result. Letter ? has unicode 233 see http://unicode-table.com/en/#00E9 >> >> Yeah, it has U+00E9 (= 233) code point number, but it is coded in 2 bytes in utf8: c3 a9 >> >> U+00E9 ? c3 a9 LATIN SMALL LETTER E WITH ACUTE >> >> >> (http://www.utf8-chartable.de/) >> >> On Fri, Aug 14, 2015 at 6:23 PM, ?ric Pailleau wrote: >> Hello, >> Please precise what Erlang release you are using. Utf8 came lately in Erlang. >> Regards >> >> Le 14 ao?t 2015 13:49, Alexander Turkin a ?crit : >> > >> > Dear list, >> > >> > >> > I've got a problem with unicode & xmerl library. >> > >> > Input data for xmerl is utf-8 encoded xml, and what I've got as the result is encoded latin1. But I need utf8! >> > >> > >> > EXAMPLES >> > >> > Body = <<"Ren?"/utf8>>. >> > >> > (for the sake of portability here is term_to_binary(Body): >> > >> > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, >> > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, >> > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, >> > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, >> > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, >> > 115,112,111,110,115,101,62>> >> > >> > >> > >> > (1): >> > >> > When I do >> > >> > xmerl_scan:string(binary_to_list(Body)). >> > >> > it returns >> > >> > {#xmlElement{name = response,expanded_name = response, >> > nsinfo = [], >> > namespace = #xmlNamespace{default = [],nodes = []}, >> > parents = [],pos = 1,attributes = [], >> > content = [#xmlElement{name = value,expanded_name = value, >> > nsinfo = [], >> > namespace = #xmlNamespace{default = [],nodes = []}, >> > parents = [{response,1}], >> > pos = 1,attributes = [], >> > content = [#xmlText{parents = [{value,1},{response,1}], >> > pos = 1,language = [], >> > >> > >> > value = "Ren?", >> > >> > >> > type = text}], >> > language = [],xmlbase = "/Users/aturkin/ws/", >> > elementdef = undeclared}], >> > language = [],xmlbase = "/Users/aturkin/ws/", >> > elementdef = undeclared}, >> > []} >> > >> > >> > So, note there is `value = "Ren?"` string, and it uses [233] symbol, which is latin1. >> > >> > >> > >> > >> > (2): >> > >> > xmerl_scan:string(xmerl_ucs:to_utf8(binary_to_list(Body))) >> > >> > returns >> > >> > {#xmlElement{name = response,expanded_name = response, >> > nsinfo = [], >> > namespace = #xmlNamespace{default = [],nodes = []}, >> > parents = [],pos = 1,attributes = [], >> > content = [#xmlElement{name = value,expanded_name = value, >> > nsinfo = [], >> > namespace = #xmlNamespace{default = [],nodes = []}, >> > parents = [{response,1}], >> > pos = 1,attributes = [], >> > content = [#xmlText{parents = [{value,1},{response,1}], >> > pos = 1,language = [], >> > >> > >> > value = "Ren??", >> > >> > >> > type = text}], >> > language = [],xmlbase = "/Users/aturkin/ws/", >> > elementdef = undeclared}], >> > language = [],xmlbase = "/Users/aturkin/ws/", >> > elementdef = undeclared}, >> > []} >> > >> > Now `value = "Ren??"`, so 2 bytes are used to code this symbol, and this is utf-8. >> > >> > So in (2) I get what I need, but why I need to force that conversion for xmerl? >> > >> > >> > >> > >> > QUESTIONS >> > >> > 1. I don't understand why xmerl_scan allows you to set input encoding, but it looks like there is no way to set output encoding. Is there any way to make xmerl_scan to return utf8 instead of latin1? >> > >> > 2. How is that happen, that in (1) it does conversion utf-8 -> latin1, and in (2) it's utf-8? >> > >> > >> > >> > >> > -- >> > Best Regards, >> > Alex Turkin >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> >> >> >> >> -- >> Best Regards, >> Alex Turkin >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > > > > -- > Best Regards, > Alex Turkin -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: Message signed with OpenPGP using GPGMail URL: From r.wobben@REDACTED Mon Aug 17 19:14:54 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 17 Aug 2015 19:14:54 +0200 Subject: [erlang-questions] how to make the comprehension work Message-ID: <55D2168E.7050207@home.nl> Hello, I try to extract the modules names from the output of code:loaded_all. So I tried this : -module(module). -export([most_used_function_name/0]). most_used_function_name() -> process_module_data(code:all_loaded()). process_module_data(Loaded_modules) -> Module_list = get_modules_name(Loaded_modules). get_modules_name(Loaded_Modules_list) -> [ModuleList || [{ModuleList, _}] <- Loaded_Modules_List ]. but now I see a message that ModuleList is unbound. What did I do wrong here ? Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From tuncer.ayaz@REDACTED Mon Aug 17 19:16:36 2015 From: tuncer.ayaz@REDACTED (Tuncer Ayaz) Date: Mon, 17 Aug 2015 19:16:36 +0200 Subject: [erlang-questions] Excluding Modules in eunit coverage (rebar) In-Reply-To: References: Message-ID: On Thu, Aug 13, 2015 at 4:04 AM, Pagayon, Ruel wrote: > Hi guys, > > I'm using rebar to execute my eunit tests, and I want some modules > excluded from the coverage report (basically those that has been > generated, etc). I can see that having a cover.spec file works only > for common tests. Is there any way I can exclude modules in eunit as > well? Not that I'm aware of. When we give ct_run a cover spec, it uses excl_mods as an argument in the test_server_ctrl:cover_compile() call. When using eunit, rebar_eunit calls cover:compile_beam/1, so we could exclude modules there and skip analyzing them later as well. That said, I'm not sure if it's a good idea to add something like {eunit_cover_exclude_mods, []} to rebar.config. Maybe we can change eunit to support a spec file too. Fred, any opinion? From r.wobben@REDACTED Mon Aug 17 19:22:15 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 17 Aug 2015 19:22:15 +0200 Subject: [erlang-questions] how to make the comprehension work In-Reply-To: References: <55D2168E.7050207@home.nl> Message-ID: <55D21847.9080502@home.nl> Op 17-8-2015 om 19:17 schreef Lukas Winkler: > On 17 August 2015 at 19:14, Roelof Wobben wrote: >> Hello, >> >> I try to extract the modules names from the output of code:loaded_all. >> >> So I tried this : >> >> -module(module). >> >> -export([most_used_function_name/0]). >> >> most_used_function_name() -> >> process_module_data(code:all_loaded()). >> >> process_module_data(Loaded_modules) -> >> Module_list = get_modules_name(Loaded_modules). >> >> get_modules_name(Loaded_Modules_list) -> >> [ModuleList || [{ModuleList, _}] <- Loaded_Modules_List ]. > > Friendly reminder that we are not your compiler. Count the ].... > > -winlu > I know that. If I count the [ I see 2 and ] I see also 2. --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From g@REDACTED Mon Aug 17 19:32:54 2015 From: g@REDACTED (Garrett Smith) Date: Mon, 17 Aug 2015 12:32:54 -0500 Subject: [erlang-questions] how to make the comprehension work In-Reply-To: <55D21847.9080502@home.nl> References: <55D2168E.7050207@home.nl> <55D21847.9080502@home.nl> Message-ID: On Mon, Aug 17, 2015 at 12:22 PM, Roelof Wobben wrote: > Op 17-8-2015 om 19:17 schreef Lukas Winkler: >> >> On 17 August 2015 at 19:14, Roelof Wobben wrote: >>> >>> Hello, >>> >>> I try to extract the modules names from the output of code:loaded_all. >>> >>> So I tried this : >>> >>> -module(module). >>> >>> -export([most_used_function_name/0]). >>> >>> most_used_function_name() -> >>> process_module_data(code:all_loaded()). >>> >>> process_module_data(Loaded_modules) -> >>> Module_list = get_modules_name(Loaded_modules). >>> >>> get_modules_name(Loaded_Modules_list) -> >>> [ModuleList || [{ModuleList, _}] <- Loaded_Modules_List ]. >> >> >> Friendly reminder that we are not your compiler. Count the ].... >> >> -winlu >> > > I know that. If I count the [ I see 2 and ] I see also 2. He he - no, it's not that. The problem is that you're not taking the error message at face value. Unbound means it's unbound - so, it's not an argument and not otherwise defined at that point in the function. You can get this! From r.wobben@REDACTED Mon Aug 17 19:55:37 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 17 Aug 2015 19:55:37 +0200 Subject: [erlang-questions] how to make the comprehension work In-Reply-To: References: <55D2168E.7050207@home.nl> Message-ID: <55D22019.7070100@home.nl> An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Mon Aug 17 19:57:19 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 17 Aug 2015 19:57:19 +0200 Subject: [erlang-questions] how to make the comprehension work In-Reply-To: References: <55D2168E.7050207@home.nl> <55D21847.9080502@home.nl> Message-ID: <55D2207F.2050601@home.nl> Op 17-8-2015 om 19:42 schreef Lukas Winkler: > On 17 August 2015 at 19:32, Garrett Smith wrote: >> On Mon, Aug 17, 2015 at 12:22 PM, Roelof Wobben wrote: >>> Op 17-8-2015 om 19:17 schreef Lukas Winkler: >>>> On 17 August 2015 at 19:14, Roelof Wobben wrote: >>>>> Hello, >>>>> >>>>> I try to extract the modules names from the output of code:loaded_all. >>>>> >>>>> So I tried this : >>>>> >>>>> -module(module). >>>>> >>>>> -export([most_used_function_name/0]). >>>>> >>>>> most_used_function_name() -> >>>>> process_module_data(code:all_loaded()). >>>>> >>>>> process_module_data(Loaded_modules) -> >>>>> Module_list = get_modules_name(Loaded_modules). >>>>> >>>>> get_modules_name(Loaded_Modules_list) -> >>>>> [ModuleList || [{ModuleList, _}] <- Loaded_Modules_List ]. >>>> >>>> Friendly reminder that we are not your compiler. Count the ].... >>>> >>>> -winlu >>>> >>> I know that. If I count the [ I see 2 and ] I see also 2. >> He he - no, it's not that. > True, I jumped to the first error that my eyes saw, which is not what > the compile error was. Still if you ever manage to solve the unbound > error you already have a clue where the next problem might be. > > -winlu I solved that one. Next problem is why the outcome is a empty list. So time to use some io:format , Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From roger@REDACTED Mon Aug 17 20:21:52 2015 From: roger@REDACTED (Roger Lipscombe) Date: Mon, 17 Aug 2015 19:21:52 +0100 Subject: [erlang-questions] how to make the comprehension work In-Reply-To: <55D2207F.2050601@home.nl> References: <55D2168E.7050207@home.nl> <55D21847.9080502@home.nl> <55D2207F.2050601@home.nl> Message-ID: code:all_loaded/0, according to the documentation (http://www.erlang.org/doc/man/code.html#all_loaded-0) returns [{Module, Loaded}]. This is the notation for a list of tuples. Let's see: 1> code:all_loaded(). [{io,"/usr/local/erlang-R16B03-1/lib/stdlib-1.19.4/ebin/io.beam"}, {erl_distribution,"/usr/local/erlang-R16B03-1/lib/kernel-2.16.4/ebin/erl_distribution.beam"}, {edlin,"/usr/local/erlang-R16B03-1/lib/stdlib-1.19.4/ebin/edlin.beam"}, {zlib,preloaded}, {...}|...] You are attempting to use a list comprehension to extract just the module names from that (what's that got to do with most_used_function_name?), as follows: 2> [Mod || [{Mod, _}] <- code:all_loaded()]. [] Your problem is that the '<-' operator iterates over each *element* of the list, and you're attempting to match another list. If your generator doesn't match, it'll return nothing. For example: 3> L = [{a, 1}, {a, 2}, {b, 3}, {b, 4}, {c, 5}]. [{a,1},{a,2},{b,3},{b,4},{c,5}] 4> [X || {b, X} <- L]. [3,4] This, weirdly, is not spelled out in the documentation at http://erlang.org/doc/programming_examples/list_comprehensions.html, which refers to the '<-' operator as "is taken from" (I generally call it "comes from"). With that knowledge, you can play in the shell: 5> [X || X <- code:all_loaded()]. [{io,"/usr/local/erlang-R16B03-1/lib/stdlib-1.19.4/ebin/io.beam"}, {erl_distribution,"/usr/local/erlang-R16B03-1/lib/kernel-2.16.4/ebin/erl_distribution.beam"}, {...}|...] Same as before; let's try matching on this: 6> [Mod || {Mod, _} <- code:all_loaded()]. [io,erl_distribution,edlin,zlib,error_handler,io_lib, prim_eval,filename,erts_internal,unicode,orddict,gb_sets, inet_db,inet,ordsets,group,gen,erl_scan,kernel,erl_eval, prim_file,ets,lists,sets,inet_udp,io_lib_pretty,code, ram_file,dict|...] ...and we can even add a filter: 7> [Mod || {Mod, Loaded} <- code:all_loaded(), Loaded =:= preloaded]. [zlib,prim_eval,erts_internal,prim_file,prim_zip,prim_inet, erlang,otp_ring0,init,erl_prim_loader] ...which is equivalent to: 8> [Mod || {Mod, preloaded} <- code:all_loaded()]. [zlib,prim_eval,erts_internal,prim_file,prim_zip,prim_inet, erlang,otp_ring0,init,erl_prim_loader] On 17 August 2015 at 18:57, Roelof Wobben wrote: > Op 17-8-2015 om 19:42 schreef Lukas Winkler: >> >> On 17 August 2015 at 19:32, Garrett Smith wrote: >>> >>> On Mon, Aug 17, 2015 at 12:22 PM, Roelof Wobben wrote: >>>> >>>> Op 17-8-2015 om 19:17 schreef Lukas Winkler: >>>>> >>>>> On 17 August 2015 at 19:14, Roelof Wobben wrote: >>>>>> >>>>>> Hello, >>>>>> >>>>>> I try to extract the modules names from the output of code:loaded_all. >>>>>> >>>>>> So I tried this : >>>>>> >>>>>> -module(module). >>>>>> >>>>>> -export([most_used_function_name/0]). >>>>>> >>>>>> most_used_function_name() -> >>>>>> process_module_data(code:all_loaded()). >>>>>> >>>>>> process_module_data(Loaded_modules) -> >>>>>> Module_list = get_modules_name(Loaded_modules). >>>>>> >>>>>> get_modules_name(Loaded_Modules_list) -> >>>>>> [ModuleList || [{ModuleList, _}] <- Loaded_Modules_List ]. >>>>> >>>>> >>>>> Friendly reminder that we are not your compiler. Count the ].... >>>>> >>>>> -winlu >>>>> >>>> I know that. If I count the [ I see 2 and ] I see also 2. >>> >>> He he - no, it's not that. >> >> True, I jumped to the first error that my eyes saw, which is not what >> the compile error was. Still if you ever manage to solve the unbound >> error you already have a clue where the next problem might be. >> >> -winlu > > I solved that one. Next problem is why the outcome is a empty list. > So time to use some io:format , > > Roelof > > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From roger@REDACTED Mon Aug 17 20:27:28 2015 From: roger@REDACTED (Roger Lipscombe) Date: Mon, 17 Aug 2015 19:27:28 +0100 Subject: [erlang-questions] Disabling a parse transform on a per-file basis? In-Reply-To: References: Message-ID: It would indeed be an undefined function, rather than a compile error. Good point, thanks. It would, however, have died with an obvious error in development, rather than deadlocking in production and paging me while I was enjoying a pleasant glass or two of wine :-) Oh well. Thanks, Roger. On 17 August 2015 at 09:05, Luis Rasc?o wrote: > Hi Roger, > From what i can see, there is no way to disable a parse transform on a > per-file > basis. Even if there was you would get no compile errors, just undefined > functions > at runtime. > > On Mon, Aug 3, 2015 at 1:58 PM, Roger Lipscombe > wrote: >> >> It turns out that you can deadlock lager (2.0.3) if you attempt to use >> lager:log (or lager:debug, etc.) from inside a lager backend. >> >> I have the lager parse transform enabled in rebar.config for every >> module in the application. >> >> Is there a way to *remove* it for specific modules? Then, if anyone >> attempts to use it in one of our lager backends, they'll get a compile >> error, rather than a deadlock in production. >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > > > > -- > PGP fingerprint: F708 E141 AE8D 2D38 E1BC DF3D 1719 3EA0 647D 7260 From r.wobben@REDACTED Mon Aug 17 21:25:27 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 17 Aug 2015 21:25:27 +0200 Subject: [erlang-questions] how to make the comprehension work In-Reply-To: References: <55D2168E.7050207@home.nl> <55D21847.9080502@home.nl> <55D2207F.2050601@home.nl> Message-ID: <55D23527.10303@home.nl> Op 17-8-2015 om 20:21 schreef Roger Lipscombe: > code:all_loaded/0, according to the documentation > (http://www.erlang.org/doc/man/code.html#all_loaded-0) returns > [{Module, Loaded}]. This is the notation for a list of tuples. Let's > see: > > 1> code:all_loaded(). > [{io,"/usr/local/erlang-R16B03-1/lib/stdlib-1.19.4/ebin/io.beam"}, > {erl_distribution,"/usr/local/erlang-R16B03-1/lib/kernel-2.16.4/ebin/erl_distribution.beam"}, > {edlin,"/usr/local/erlang-R16B03-1/lib/stdlib-1.19.4/ebin/edlin.beam"}, > {zlib,preloaded}, > {...}|...] > > You are attempting to use a list comprehension to extract just the > module names from that (what's that got to do with > most_used_function_name?), as follows: > > 2> [Mod || [{Mod, _}] <- code:all_loaded()]. > [] > > Your problem is that the '<-' operator iterates over each *element* of > the list, and you're attempting to match another list. If your > generator doesn't match, it'll return nothing. For example: > > 3> L = [{a, 1}, {a, 2}, {b, 3}, {b, 4}, {c, 5}]. > [{a,1},{a,2},{b,3},{b,4},{c,5}] > > 4> [X || {b, X} <- L]. > [3,4] > > This, weirdly, is not spelled out in the documentation at > http://erlang.org/doc/programming_examples/list_comprehensions.html, > which refers to the '<-' operator as "is taken from" (I generally call > it "comes from"). > > With that knowledge, you can play in the shell: > > 5> [X || X <- code:all_loaded()]. > [{io,"/usr/local/erlang-R16B03-1/lib/stdlib-1.19.4/ebin/io.beam"}, > {erl_distribution,"/usr/local/erlang-R16B03-1/lib/kernel-2.16.4/ebin/erl_distribution.beam"}, > {...}|...] > > Same as before; let's try matching on this: > > 6> [Mod || {Mod, _} <- code:all_loaded()]. > [io,erl_distribution,edlin,zlib,error_handler,io_lib, > prim_eval,filename,erts_internal,unicode,orddict,gb_sets, > inet_db,inet,ordsets,group,gen,erl_scan,kernel,erl_eval, > prim_file,ets,lists,sets,inet_udp,io_lib_pretty,code, > ram_file,dict|...] > > ...and we can even add a filter: > > 7> [Mod || {Mod, Loaded} <- code:all_loaded(), Loaded =:= preloaded]. > [zlib,prim_eval,erts_internal,prim_file,prim_zip,prim_inet, > erlang,otp_ring0,init,erl_prim_loader] > > ...which is equivalent to: > > 8> [Mod || {Mod, preloaded} <- code:all_loaded()]. > [zlib,prim_eval,erts_internal,prim_file,prim_zip,prim_inet, > erlang,otp_ring0,init,erl_prim_loader] > > On 17 August 2015 at 18:57, Roelof Wobben wrote: >> Op 17-8-2015 om 19:42 schreef Lukas Winkler: >>> On 17 August 2015 at 19:32, Garrett Smith wrote: >>>> On Mon, Aug 17, 2015 at 12:22 PM, Roelof Wobben wrote: >>>>> Op 17-8-2015 om 19:17 schreef Lukas Winkler: >>>>>> On 17 August 2015 at 19:14, Roelof Wobben wrote: >>>>>>> Hello, >>>>>>> >>>>>>> I try to extract the modules names from the output of code:loaded_all. >>>>>>> >>>>>>> So I tried this : >>>>>>> >>>>>>> -module(module). >>>>>>> >>>>>>> -export([most_used_function_name/0]). >>>>>>> >>>>>>> most_used_function_name() -> >>>>>>> process_module_data(code:all_loaded()). >>>>>>> >>>>>>> process_module_data(Loaded_modules) -> >>>>>>> Module_list = get_modules_name(Loaded_modules). >>>>>>> >>>>>>> get_modules_name(Loaded_Modules_list) -> >>>>>>> [ModuleList || [{ModuleList, _}] <- Loaded_Modules_List ]. >>>>>> >>>>>> Friendly reminder that we are not your compiler. Count the ].... >>>>>> >>>>>> -winlu >>>>>> >>>>> I know that. If I count the [ I see 2 and ] I see also 2. >>>> He he - no, it's not that. >>> True, I jumped to the first error that my eyes saw, which is not what >>> the compile error was. Still if you ever manage to solve the unbound >>> error you already have a clue where the next problem might be. >>> >>> -winlu >> I solved that one. Next problem is why the outcome is a empty list. >> So time to use some io:format , >> >> Roelof >> >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From r.wobben@REDACTED Mon Aug 17 21:26:14 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Mon, 17 Aug 2015 21:26:14 +0200 Subject: [erlang-questions] how to make the comprehension work In-Reply-To: References: <55D2168E.7050207@home.nl> <55D21847.9080502@home.nl> <55D2207F.2050601@home.nl> Message-ID: <55D23556.8000307@home.nl> Thanks, I already found that that I have to change [ { } ] to { } Roelof Op 17-8-2015 om 20:21 schreef Roger Lipscombe: > code:all_loaded/0, according to the documentation > (http://www.erlang.org/doc/man/code.html#all_loaded-0) returns > [{Module, Loaded}]. This is the notation for a list of tuples. Let's > see: > > 1> code:all_loaded(). > [{io,"/usr/local/erlang-R16B03-1/lib/stdlib-1.19.4/ebin/io.beam"}, > {erl_distribution,"/usr/local/erlang-R16B03-1/lib/kernel-2.16.4/ebin/erl_distribution.beam"}, > {edlin,"/usr/local/erlang-R16B03-1/lib/stdlib-1.19.4/ebin/edlin.beam"}, > {zlib,preloaded}, > {...}|...] > > You are attempting to use a list comprehension to extract just the > module names from that (what's that got to do with > most_used_function_name?), as follows: > > 2> [Mod || [{Mod, _}] <- code:all_loaded()]. > [] > > Your problem is that the '<-' operator iterates over each *element* of > the list, and you're attempting to match another list. If your > generator doesn't match, it'll return nothing. For example: > > 3> L = [{a, 1}, {a, 2}, {b, 3}, {b, 4}, {c, 5}]. > [{a,1},{a,2},{b,3},{b,4},{c,5}] > > 4> [X || {b, X} <- L]. > [3,4] > > This, weirdly, is not spelled out in the documentation at > http://erlang.org/doc/programming_examples/list_comprehensions.html, > which refers to the '<-' operator as "is taken from" (I generally call > it "comes from"). > > With that knowledge, you can play in the shell: > > 5> [X || X <- code:all_loaded()]. > [{io,"/usr/local/erlang-R16B03-1/lib/stdlib-1.19.4/ebin/io.beam"}, > {erl_distribution,"/usr/local/erlang-R16B03-1/lib/kernel-2.16.4/ebin/erl_distribution.beam"}, > {...}|...] > > Same as before; let's try matching on this: > > 6> [Mod || {Mod, _} <- code:all_loaded()]. > [io,erl_distribution,edlin,zlib,error_handler,io_lib, > prim_eval,filename,erts_internal,unicode,orddict,gb_sets, > inet_db,inet,ordsets,group,gen,erl_scan,kernel,erl_eval, > prim_file,ets,lists,sets,inet_udp,io_lib_pretty,code, > ram_file,dict|...] > > ...and we can even add a filter: > > 7> [Mod || {Mod, Loaded} <- code:all_loaded(), Loaded =:= preloaded]. > [zlib,prim_eval,erts_internal,prim_file,prim_zip,prim_inet, > erlang,otp_ring0,init,erl_prim_loader] > > ...which is equivalent to: > > 8> [Mod || {Mod, preloaded} <- code:all_loaded()]. > [zlib,prim_eval,erts_internal,prim_file,prim_zip,prim_inet, > erlang,otp_ring0,init,erl_prim_loader] > > On 17 August 2015 at 18:57, Roelof Wobben wrote: >> Op 17-8-2015 om 19:42 schreef Lukas Winkler: >>> On 17 August 2015 at 19:32, Garrett Smith wrote: >>>> On Mon, Aug 17, 2015 at 12:22 PM, Roelof Wobben wrote: >>>>> Op 17-8-2015 om 19:17 schreef Lukas Winkler: >>>>>> On 17 August 2015 at 19:14, Roelof Wobben wrote: >>>>>>> Hello, >>>>>>> >>>>>>> I try to extract the modules names from the output of code:loaded_all. >>>>>>> >>>>>>> So I tried this : >>>>>>> >>>>>>> -module(module). >>>>>>> >>>>>>> -export([most_used_function_name/0]). >>>>>>> >>>>>>> most_used_function_name() -> >>>>>>> process_module_data(code:all_loaded()). >>>>>>> >>>>>>> process_module_data(Loaded_modules) -> >>>>>>> Module_list = get_modules_name(Loaded_modules). >>>>>>> >>>>>>> get_modules_name(Loaded_Modules_list) -> >>>>>>> [ModuleList || [{ModuleList, _}] <- Loaded_Modules_List ]. >>>>>> >>>>>> Friendly reminder that we are not your compiler. Count the ].... >>>>>> >>>>>> -winlu >>>>>> >>>>> I know that. If I count the [ I see 2 and ] I see also 2. >>>> He he - no, it's not that. >>> True, I jumped to the first error that my eyes saw, which is not what >>> the compile error was. Still if you ever manage to solve the unbound >>> error you already have a clue where the next problem might be. >>> >>> -winlu >> I solved that one. Next problem is why the outcome is a empty list. >> So time to use some io:format , >> >> Roelof >> >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From technion@REDACTED Tue Aug 18 00:40:35 2015 From: technion@REDACTED (Technion) Date: Mon, 17 Aug 2015 22:40:35 +0000 Subject: [erlang-questions] List comprehensions assistance Message-ID: Hi, I have the following piece of code, which works correctly: ConvertFun = fun({X, Y}) -> {[{<<"address">>, list_to_binary(inet:ntoa(X))}, {<<"stat">>, Y}]} end, ScanConverted = lists:map(ConvertFun, Results), The reason for this very specific mapping is to convert it into exactly the format jiffy expects (in order to generate the correct JSON). I've been experimenting with rewriting this as a list comprehension (largely as a learning exercise). Code like this fails to compile: ScanConverted = [[{<<"address">>, list_to_binary(inet:ntoa(X))}, {<<"stat">>, Y}]| {X, Y} <- Results] src/ipmangle.erl:31: syntax error before: '<-' Any pointers on this would be appreciated. -------------- next part -------------- An HTML attachment was scrubbed... URL: From hugo@REDACTED Tue Aug 18 00:44:59 2015 From: hugo@REDACTED (Hugo Mills) Date: Mon, 17 Aug 2015 22:44:59 +0000 Subject: [erlang-questions] List comprehensions assistance In-Reply-To: References: Message-ID: <20150817224459.GX12976@carfax.org.uk> On Mon, Aug 17, 2015 at 10:40:35PM +0000, Technion wrote: > Hi, > > > I have the following piece of code, which works correctly: > > > ConvertFun = fun({X, Y}) -> {[{<<"address">>, > list_to_binary(inet:ntoa(X))}, {<<"stat">>, Y}]} end, > ScanConverted = lists:map(ConvertFun, Results), > > > The reason for this very specific mapping is to convert it into exactly the format jiffy expects (in order to generate the correct JSON). I've been experimenting with rewriting this as a list comprehension (largely as a learning exercise). > > > Code like this fails to compile: > > > ScanConverted = [[{<<"address">>, list_to_binary(inet:ntoa(X))}, > {<<"stat">>, Y}]| {X, Y} <- Results] > > > src/ipmangle.erl:31: syntax error before: '<-' > > > Any pointers on this would be appreciated. A list comprehension is [ Expr || Var <- List ]. You have [ Expr | Var <- List ]. Hugo. PS. Yay! One I can answer! ;) > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -- Hugo Mills | I believe that it's closely correlated with the hugo@REDACTED carfax.org.uk | aeroswine coefficient http://carfax.org.uk/ | PGP: E2AB1DE4 | Adrian Bridgett -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: From mononcqc@REDACTED Tue Aug 18 00:54:45 2015 From: mononcqc@REDACTED (Fred Hebert) Date: Mon, 17 Aug 2015 18:54:45 -0400 Subject: [erlang-questions] Excluding Modules in eunit coverage (rebar) In-Reply-To: References: Message-ID: <20150817225444.GF1122@ferdmbp.local> On 08/17, Tuncer Ayaz wrote: >Fred, any opinion? No opinion. By the time my tests grow complex enough to need multiple modules and more complex tracking, setup, etc. I naturally end up migrating to CT suites. This overall does not sound me as either a particularly good nor bad idea. From technion@REDACTED Tue Aug 18 04:17:47 2015 From: technion@REDACTED (Technion) Date: Tue, 18 Aug 2015 02:17:47 +0000 Subject: [erlang-questions] List comprehensions assistance In-Reply-To: <20150817224459.GX12976@carfax.org.uk> References: , <20150817224459.GX12976@carfax.org.uk> Message-ID: Hi Hugo, Many thanks for the response. Argh! Nothing worse than spending hours on something only to introduce a dumb mistake on the home stretch. ________________________________________ From: Hugo Mills Sent: Tuesday, 18 August 2015 8:44 AM To: Technion Cc: Erlang Questions Subject: Re: [erlang-questions] List comprehensions assistance On Mon, Aug 17, 2015 at 10:40:35PM +0000, Technion wrote: > Hi, > > > I have the following piece of code, which works correctly: > > > ConvertFun = fun({X, Y}) -> {[{<<"address">>, > list_to_binary(inet:ntoa(X))}, {<<"stat">>, Y}]} end, > ScanConverted = lists:map(ConvertFun, Results), > > > The reason for this very specific mapping is to convert it into exactly the format jiffy expects (in order to generate the correct JSON). I've been experimenting with rewriting this as a list comprehension (largely as a learning exercise). > > > Code like this fails to compile: > > > ScanConverted = [[{<<"address">>, list_to_binary(inet:ntoa(X))}, > {<<"stat">>, Y}]| {X, Y} <- Results] > > > src/ipmangle.erl:31: syntax error before: '<-' > > > Any pointers on this would be appreciated. A list comprehension is [ Expr || Var <- List ]. You have [ Expr | Var <- List ]. Hugo. PS. Yay! One I can answer! ;) > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -- Hugo Mills | I believe that it's closely correlated with the hugo@REDACTED carfax.org.uk | aeroswine coefficient http://carfax.org.uk/ | PGP: E2AB1DE4 | Adrian Bridgett From technion@REDACTED Tue Aug 18 04:35:52 2015 From: technion@REDACTED (Technion) Date: Tue, 18 Aug 2015 02:35:52 +0000 Subject: [erlang-questions] List comprehensions assistance In-Reply-To: References: , <20150817224459.GX12976@carfax.org.uk>, Message-ID: Hi, Just a slight update, it took a bit more wrangling to get the correct format (ie, something jiffy liked) ScanConverted = [{[{<<"address">>, list_to_binary(inet:ntoa(X))}, {<<"stat">>, Y}]} || {X, Y} <- Results], ________________________________________ From: erlang-questions-bounces@REDACTED on behalf of Technion Sent: Tuesday, 18 August 2015 12:17 PM To: Hugo Mills Cc: Erlang Questions Subject: Re: [erlang-questions] List comprehensions assistance Hi Hugo, Many thanks for the response. Argh! Nothing worse than spending hours on something only to introduce a dumb mistake on the home stretch. ________________________________________ From: Hugo Mills Sent: Tuesday, 18 August 2015 8:44 AM To: Technion Cc: Erlang Questions Subject: Re: [erlang-questions] List comprehensions assistance On Mon, Aug 17, 2015 at 10:40:35PM +0000, Technion wrote: > Hi, > > > I have the following piece of code, which works correctly: > > > ConvertFun = fun({X, Y}) -> {[{<<"address">>, > list_to_binary(inet:ntoa(X))}, {<<"stat">>, Y}]} end, > ScanConverted = lists:map(ConvertFun, Results), > > > The reason for this very specific mapping is to convert it into exactly the format jiffy expects (in order to generate the correct JSON). I've been experimenting with rewriting this as a list comprehension (largely as a learning exercise). > > > Code like this fails to compile: > > > ScanConverted = [[{<<"address">>, list_to_binary(inet:ntoa(X))}, > {<<"stat">>, Y}]| {X, Y} <- Results] > > > src/ipmangle.erl:31: syntax error before: '<-' > > > Any pointers on this would be appreciated. A list comprehension is [ Expr || Var <- List ]. You have [ Expr | Var <- List ]. Hugo. PS. Yay! One I can answer! ;) > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -- Hugo Mills | I believe that it's closely correlated with the hugo@REDACTED carfax.org.uk | aeroswine coefficient http://carfax.org.uk/ | PGP: E2AB1DE4 | Adrian Bridgett _______________________________________________ erlang-questions mailing list erlang-questions@REDACTED http://erlang.org/mailman/listinfo/erlang-questions From ok@REDACTED Tue Aug 18 05:01:34 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 18 Aug 2015 15:01:34 +1200 Subject: [erlang-questions] feedback on my solutions to programming erlang second edition In-Reply-To: References: <55CDA6CD.2050501@home.nl> <55CDD109.1080109@home.nl> <051BD7DA-89C8-4877-B4E4-C0C5B1045855@cs.otago.ac.nz> <55D19804.4020101@ninenines.eu> Message-ID: On 17/08/2015, at 10:38 pm, Garrett Smith wrote: > I wonder why stack variables aren't included in stack traces - I've > never seen that in any language (Richard? :) but it would be > fantastically useful. Burroughs MCP: stack *traces* were just a list of lines, basically, but stack *dumps* showed you details (and since the B6700 was a tagged machine, it could do a darned good job of decoding stuff). The Edinburgh EMAS operating system: when an IMP (the EMAS equivalent of C, sort of Algolish) program crashed, you got a stack dump telling you about variables. As a user, I was quite annoyed by this, because of course the internals of a program I didn't have the source for were meaningless to me. Neither of these provided stack traces (or dumps) *to programs* as a data structure. It's not clear what a program could *do* with names and values of variables, considering that the internal structure of a function can be changed dramatically while still being the same interface. In Smalltalk, an exception handler gets full access to *everything*, because Smalltalk programs have full access to everything in the stack anyway. (Start with 'thisContext', which is the executing frame, and proceed from there. It's not in the standard, thankfully.) From ok@REDACTED Tue Aug 18 05:11:05 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 18 Aug 2015 15:11:05 +1200 Subject: [erlang-questions] how to make the comprehension work In-Reply-To: <55D2168E.7050207@home.nl> References: <55D2168E.7050207@home.nl> Message-ID: <79618C8F-6846-44FB-A7E6-B96FFB4E53DB@cs.otago.ac.nz> On 18/08/2015, at 5:14 am, Roelof Wobben wrote: > Hello, > > I try to extract the modules names from the output of code:loaded_all. > > So I tried this : > > -module(module). > > -export([most_used_function_name/0]). > > most_used_function_name() -> > process_module_data(code:all_loaded()). > > process_module_data(Loaded_modules) -> > Module_list = get_modules_name(Loaded_modules). > > get_modules_name(Loaded_Modules_list) -> > [ModuleList || [{ModuleList, _}] <- Loaded_Modules_List ]. > > > > but now I see a message that ModuleList is unbound. Are you *sure* that's the message you got? It looks to me as if you have Loaded_Modules_list in the arguments ^ lower case "l" Loaded_Modules_List in the body ^ upper case "L" Also, the elements of code:all_loaded() are tuples (with 2 elements), NOT lists of tuples, and the first element is a module NAME, not any kind of module List, so the whole thing reduces to [Name || {Name,_} <- code:all_loaded] 2> [Name || {Name,_} <- code:all_loaded()]. [io,erl_distribution,edlin,zlib,error_handler,io_lib, prim_eval,filename,erts_internal,unicode,orddict,gb_sets, inet_db,inet,ordsets,group,gen,erl_scan,kernel,erl_eval, prim_file,ets,lists,sets,inet_udp,io_lib_pretty,code, ram_file,dict|...] From osmuogar@REDACTED Tue Aug 18 01:19:00 2015 From: osmuogar@REDACTED (=?UTF-8?Q?Oscar_Mu=C3=B1oz_Garrig=C3=B3s?=) Date: Tue, 18 Aug 2015 01:19:00 +0200 Subject: [erlang-questions] Reading from mnesia Message-ID: Hi guys, I am creating a chat application android - erlang. The problem is i can't read from the table. What am i doing wrong? -record(message,{leido, from, to, text}). install(Nodes) -> mnesia:create_schema(Nodes), mnesia:start(), mnesia:create_table( message, [ {attributes, record_info(fields, message)} ] ). write_message(From, To, Text)-> Trans = fun()->mnesia:write(#message{leido = false,from = From, to = To, text = Text}) end, mnesia:transaction(Trans). read_message(To)-> Trans = fun() -> mnesia:read({message,To}) end, mnesia:transaction(Trans). *leido marks if the message has been readed Another question is i want to read only messages where leido = false, ?how can i do it? Thank you all -------------- next part -------------- An HTML attachment was scrubbed... URL: From ruel@REDACTED Tue Aug 18 05:39:18 2015 From: ruel@REDACTED (Pagayon, Ruel) Date: Tue, 18 Aug 2015 11:39:18 +0800 Subject: [erlang-questions] Excluding Modules in eunit coverage (rebar) In-Reply-To: <20150817225444.GF1122@ferdmbp.local> References: <20150817225444.GF1122@ferdmbp.local> Message-ID: Thanks for the inputs guys. I guess I'll just migrate fully to CT suites as well. Another question though, is there a value continuing the eunit tests? Or the CT will be enough? *Ruel Pagayon* - ruel@REDACTED Platform Engineer Networking and Communications On Tue, Aug 18, 2015 at 6:54 AM, Fred Hebert wrote: > On 08/17, Tuncer Ayaz wrote: > >> Fred, any opinion? >> > > No opinion. By the time my tests grow complex enough to need multiple > modules and more complex tracking, setup, etc. I naturally end up migrating > to CT suites. > > This overall does not sound me as either a particularly good nor bad idea. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From martink@REDACTED Tue Aug 18 06:23:28 2015 From: martink@REDACTED (Martin Karlsson) Date: Tue, 18 Aug 2015 16:23:28 +1200 Subject: [erlang-questions] Reading from mnesia In-Reply-To: References: Message-ID: Hi Oscar, Lets start with looking at your record: > -record(message,{leido, from, to, text}). The first attribute in the record is the primary key. The primary key of message is 'leido'. But 'leido' seems to be a boolean which doesn't make much sense. I.e. you can only have 2 entries in your table. You should use something else, either unique: For example a timestamp or a combination of To/From and a timestamp or change your tables to a bag type and use something like 'to' or a unique user id as key. For example: -record(message, {id, leido, from, to, text}). Where id is the message id or something like that. > read_message(To)-> > Trans = fun() -> mnesia:read({message,To}) end, > mnesia:transaction(Trans). mnesia:read reads using the primary key but as the primary key is leido not *to* you will not get anything back. To read data out of the table you can: * use a known primary key (for example 'id' if that is your primary key) * or add an index to the table (for example on to) and do an index_read * or use other mechanisms such as qlc. (See below) > Another question is i want to read only messages where leido = false, ?how > can i do it? You can use: * qlc (Query List Comprehensions. Which lets you filter and sort data from mnesia tables in a SQL like manner). * mnesia:select - A lower level utility which forces you to learn about MatchSpecs which are handy but slightly awkward to work with ;) with 'qlc' you'd do something like: mnesia:transcation(qlc:e(qlc:q([M || M <- mnesia:table(message), M#message.leido =:= false ]))) with 'select' something like: MatchSpec =[ {#message{leido = '$1', to = '_', from = '_', text='_'}, [ {'=:=', '$1', false} ], [ '$_']}], mnesia:transaction(mnesia:select(message, MatchSpec)) I haven't tested the code so it may not be fully functional but hopefully points you in the right direction. Helpful links: erl -man mnesia erl -man qlc http://learnyousomeerlang.com/mnesia http://erlang.org/doc/apps/mnesia/users_guide.html Hope this helps. Cheers, Martin From bchesneau@REDACTED Tue Aug 18 10:22:33 2015 From: bchesneau@REDACTED (Benoit Chesneau) Date: Tue, 18 Aug 2015 08:22:33 +0000 Subject: [erlang-questions] gen_tcp:controlling_process/2 impact Message-ID: Hi all, I am working on some some code that may need to chain and passe a socket connection between multiple process in a rapid manner and I am wondering what is the real impact of chaining multiple `gen_tcp:controlling_process` from one process to the other in a very fast manner. Is there any possibility to bypass it and just give the control to the target at the end? Beno?t -------------- next part -------------- An HTML attachment was scrubbed... URL: From bchesneau@REDACTED Tue Aug 18 11:15:50 2015 From: bchesneau@REDACTED (Benoit Chesneau) Date: Tue, 18 Aug 2015 09:15:50 +0000 Subject: [erlang-questions] socks5 types in inet_db? Message-ID: I was looking at the code of inet_db and saw the following types: %% Socks5 options %% -------------- %% socks5_server Server - IP address of the socks5 server %% socks5_port Port - TCP port of the socks5 server %% socks5_methods Ls - List of authentication methods %% socks5_noproxy IPs - List of {Net,Subnetmask} https://github.com/erlang/otp/blob/maint/lib/kernel/src/inet_db.erl#L822-L827 I wonder how it's used right now. Is there any modules that are using them? Can it be used by external modules? Btw why the inet_db module has no public documentation? - beno?t -------------- next part -------------- An HTML attachment was scrubbed... URL: From chandrashekhar.mullaparthi@REDACTED Tue Aug 18 12:27:56 2015 From: chandrashekhar.mullaparthi@REDACTED (Chandru) Date: Tue, 18 Aug 2015 11:27:56 +0100 Subject: [erlang-questions] ** exception exit: shutdown : SOLVED dets_server:stop(). In-Reply-To: References: Message-ID: On 15 August 2015 at 05:21, Sid Muller wrote: > It appears that when I close all dets files there is a lingering dets > process left because if I run: > dets_server:stop(). > > Then the shell doesn't report "** exception exit: shutdown" > > Is that normal? Should I be calling dets_server:stop() from my code once I > close dets files? None of the dets example use cases show that. > I doubt it is caused by dets_server. dets_server seems to be a "well behaved" process. It is a gen_server which traps exits, and the terminate function gets called when you shutdown the node using q(). My hunch is that you are not closing all your dets files. Not sure if you realise, multiple processes can open the same dets file concurrently and dets maintains a reference count. The reference count has to go down to zero before the process for the dets file gets shutdown gracefully. supervisor:which_children(dets_sup). should tell you if there are any pending dets processes. cheers, Chandru > *Sent:* Friday, August 14, 2015 at 8:52 AM > *From:* "Sid Muller" > *To:* Chandru > *Cc:* erlang-questions > *Subject:* Re: [erlang-questions] ** exception exit: shutdown > I'm using erlang 18.0, on ubuntu 14. It was also happening with 17.5, I'm > running my own application which has been working fine for months. This > issue showed up after I added code to open dets files, I do close all the > dets files before I quit my application. > > I ran the commands you suggested below but interestingly there is no more > info with it, matches your lines up untill the point it's supose to print > what went wrong but then nothing...., so frustrating: > > 3> whereis(init). > <0.0.0> > 4> dbg:tracer(). > {ok,<0.5341.0>} > 5> dbg:p(whereis(init), [s,r]). > {ok,[{matched,nonode@REDACTED,1}]} > 6> q(). > (<0.0.0>) << {stop,stop} > (<0.0.0>) <0.7.0> ! {'EXIT',<0.2.0>,shutdown} > ok > ** exception exit: shutdown > 7> (no error logger present) error: <0.5341.0> > sidm@REDACTED:~/src/proj$ > > > *Sent:* Thursday, August 13, 2015 at 2:55 PM > *From:* Chandru > *To:* "Sid Muller" > *Cc:* erlang-questions > *Subject:* Re: [erlang-questions] ** exception exit: shutdown > Which version of erlang are you using? What OS? Trying it on OS X, the > node dies quietly. Not entirely sure why you are seeing the "exception > exit" message. Did you have any processes running before you invoked q()? > Basically the node shutdown procedure is being invoked, and all your > processes get killed. > > Functions you type in the shell are defined in shell_default.erl. > > shell_default:q/0 is defined as: > > > > q() -> c:q(). > > c:q/0 is defined as: > > > -spec q() -> no_return(). > > > > q() -> > > init:stop(). > > If you turn tracing on for the init process to see what happens. > > > $ ~/erlang/R17-5/bin/erl > > Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:8:8] [async-threads:10] > [hipe] [kernel-poll:false] > > > > Eshell V6.4 (abort with ^G) > > 1> whereis(init). > > <0.0.0> > > 2> > > 2> > > 2> > > 2> dbg:tracer(). > > {ok,<0.35.0>} > > 3> dbg:p(whereis(init), [s,r]). > > {ok,[{matched,nonode@REDACTED,1}]} > > 4> > > 4> > > 4> q(). > > (<0.0.0>) << {stop,stop} > > (<0.0.0>) <0.7.0> ! {'EXIT',<0.2.0>,shutdown} > > ok > > 5> (no error logger present) error: "Error in process <0.35.0> with exit > value: {badarg,[{io,format,[user,\"** dbg got EXIT - terminating: > ~p~n\",[{trace_handler_crashed,{badarg,[{io,format,[user,\"(~p) << > ~p~n\",[<0.0.0>,{'EXIT',<0.7.0>,shutdown}]],[]},{dbg,dhandler1,3,[{file,\"dbg.erl\"},{line,983}]},{dbg,invoke_handler... > \n" > > > > Chandru > > > > On 13 August 2015 at 16:26, Sid Muller wrote: >> >> Hi, >> >> does anyone have any pointers on how to debug an exception exit in shell? >> >> When I type q(). into the shell I get this: >> >> 3> q(). >> ok >> ** exception exit: shutdown >> 4> sidm@REDACTED:~/src/proj$ >> >> >> The problem is I don't know where to look since the exception is so >> terse. Does anyone have any pointers? >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > _______________________________________________ erlang-questions mailing > list erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From g@REDACTED Tue Aug 18 13:12:00 2015 From: g@REDACTED (Garrett Smith) Date: Tue, 18 Aug 2015 06:12:00 -0500 Subject: [erlang-questions] List comprehensions assistance In-Reply-To: References: <20150817224459.GX12976@carfax.org.uk> Message-ID: I'd use this one weird trick: convert({Address, Stat}) -> [{<<"address">>, list_to_binary(inet:ntoa(Address))}, {<<"stat">>, Stat}]. And then: Converted = [convert(Result) || Result <- Results] In general if the code is blinding you and it's hard to see what's going on, a function, or even a few, can do wonders for clarity. On Mon, Aug 17, 2015 at 9:35 PM, Technion wrote: > Hi, > > Just a slight update, it took a bit more wrangling to get the correct format (ie, something jiffy liked) > > ScanConverted = [{[{<<"address">>, list_to_binary(inet:ntoa(X))}, > {<<"stat">>, Y}]} || {X, Y} <- Results], > > > ________________________________________ > From: erlang-questions-bounces@REDACTED on behalf of Technion > Sent: Tuesday, 18 August 2015 12:17 PM > To: Hugo Mills > Cc: Erlang Questions > Subject: Re: [erlang-questions] List comprehensions assistance > > Hi Hugo, > > Many thanks for the response. > > Argh! Nothing worse than spending hours on something only to introduce a dumb mistake on the home stretch. > ________________________________________ > From: Hugo Mills > Sent: Tuesday, 18 August 2015 8:44 AM > To: Technion > Cc: Erlang Questions > Subject: Re: [erlang-questions] List comprehensions assistance > > On Mon, Aug 17, 2015 at 10:40:35PM +0000, Technion wrote: >> Hi, >> >> >> I have the following piece of code, which works correctly: >> >> >> ConvertFun = fun({X, Y}) -> {[{<<"address">>, >> list_to_binary(inet:ntoa(X))}, {<<"stat">>, Y}]} end, >> ScanConverted = lists:map(ConvertFun, Results), >> >> >> The reason for this very specific mapping is to convert it into exactly the format jiffy expects (in order to generate the correct JSON). I've been experimenting with rewriting this as a list comprehension (largely as a learning exercise). >> >> >> Code like this fails to compile: >> >> >> ScanConverted = [[{<<"address">>, list_to_binary(inet:ntoa(X))}, >> {<<"stat">>, Y}]| {X, Y} <- Results] >> >> >> src/ipmangle.erl:31: syntax error before: '<-' >> >> >> Any pointers on this would be appreciated. > > A list comprehension is [ Expr || Var <- List ]. You have > [ Expr | Var <- List ]. > > Hugo. > > PS. Yay! One I can answer! ;) > >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > > -- > Hugo Mills | I believe that it's closely correlated with the > hugo@REDACTED carfax.org.uk | aeroswine coefficient > http://carfax.org.uk/ | > PGP: E2AB1DE4 | Adrian Bridgett > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From raimo+erlang-questions@REDACTED Tue Aug 18 13:53:06 2015 From: raimo+erlang-questions@REDACTED (Raimo Niskanen) Date: Tue, 18 Aug 2015 13:53:06 +0200 Subject: [erlang-questions] how to make the comprehension work In-Reply-To: <55D22019.7070100@home.nl> References: <55D2168E.7050207@home.nl> <55D22019.7070100@home.nl> Message-ID: <20150818115306.GA44336@erix.ericsson.se> Hi Roelof. I would like to encourage you to not send mail in HTML-only since I and others on this list has got text-only clients and as you see below such a post is not easy to read and practically impossible to answer. Best Regards / Raimo Niskanen, Erlang/OTP, Mailing list admin On Mon, Aug 17, 2015 at 07:55:37PM +0200, Roelof Wobben wrote: > > > > > >

Op 17-8-2015 om 19:26 schreef Vlad > Dumitrescu:
>
>
cite="mid:CAA-EFXubVdq-9vs4spOvGR8JVY13yf0Bi90e4+j_v7LHANSJuw@REDACTED" > type="cite"> >
>

>
On Mon, Aug 17, 2015 at 7:14 PM, > Roelof Wobben < href="mailto:r.wobben@REDACTED" target="_blank">r.wobben@REDACTED> > wrote:
>
>
-module(module).
>
> -export([most_used_function_name/0]).
>
> most_used_function_name() ->
> ?? ??process_module_data(code:all_loaded()).
>
> process_module_data(Loaded_modules)?? ->
> ?? ?? Module_list = get_modules_name(Loaded_modules).
>
> get_modules_name(Loaded_Modules_list) ->
> ?? ?? [ModuleList || [{ModuleList, _}] <- > Loaded_Modules_List ].
>
>
>
>
> You should try to read the error message more carefully - > yours says that Loaded_Modules_List is unbound, because the > function header declares it with a different spelling (list > instead of List).
>

>
>
regards,
>
Vlad
>

>
>
>
>
> Thanks,
>
> Now try to find out why the outcome is empty.
>
> Roelof
>
> >

>
> > > > > >
> > Avast logo > > >

> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >
www.avast.com >

>
>
> > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -- / Raimo Niskanen, Erlang/OTP, Ericsson AB From askjuise@REDACTED Tue Aug 18 14:18:07 2015 From: askjuise@REDACTED (Alexander Petrovsky) Date: Tue, 18 Aug 2015 15:18:07 +0300 Subject: [erlang-questions] Binary constantly growing on erlang 18 Message-ID: Hi! A few days ago a noticed that erlang vm eat too many memory. I've checked system and binary memory and found that it is constantly growing. I'm start debugging with recon but without success. After disabling all application the memory sill growing. I've checken on clean vm: 1> application:which_applications(). [{stdlib,"ERTS CXC 138 10","2.5"}, {kernel,"ERTS CXC 138 10","4.0"}] 2> [begin io:format("~p~n", [erlang:memory(binary)]), timer:sleep(1000) end || _ <- lists:seq(1, 5)]. 2105616 2113976 2122144 2130504 2138864 3> io:format("~p~n", [erlang:memory(binary)]), timer:sleep(5000), io:format("~p~n", [erlang:memory(binary)]). 3124360 3132720 4> 2138864 - 2105616. 33248 5> 3132720 - 3124360. 8360 As you can see, the binary grow non linear and only when I call erlang:memory(binary). System: Debian 7 Erlang: 18.0 esl-erlang Can anyone help me? -- ?????????? ????????? / Alexander Petrovsky, Skype: askjuise Phone: +7 914 8 820 815 -------------- next part -------------- An HTML attachment was scrubbed... URL: From mononcqc@REDACTED Tue Aug 18 15:12:24 2015 From: mononcqc@REDACTED (Fred Hebert) Date: Tue, 18 Aug 2015 09:12:24 -0400 Subject: [erlang-questions] gen_tcp:controlling_process/2 impact In-Reply-To: References: Message-ID: <20150818131223.GA24333@fhebert-ltm1> On 08/18, Benoit Chesneau wrote: >Hi all, > >I am working on some some code that may need to chain and passe a socket >connection between multiple process in a rapid manner and I am wondering >what is the real impact of chaining multiple `gen_tcp:controlling_process` >from one process to the other in a very fast manner. Is there any >possibility to bypass it and just give the control to the target at the end? > If the socket is used only for writing, then you don't need to change the controlling process, just send the thing directly. Anyone can write to a socket, just one process can read. If you do need to read from it, then the best idea is likely to resolve your chain, find the final destination pid, and hand the control there. The owner must hand the control, so rather than going: a -- give --> b -- give --> c go a -- ask pid --> b -- finds --> c a -- give --> c which will have a single control-handing form. You can also swap it around and let 'b' tell 'c' to "ask a for your port" and then do the switch. Also remember to let the socket in {accept, false} mode so that no messages are lost during the whole operation. From lukas@REDACTED Tue Aug 18 16:14:04 2015 From: lukas@REDACTED (Lukas Larsson) Date: Tue, 18 Aug 2015 16:14:04 +0200 Subject: [erlang-questions] Binary constantly growing on erlang 18 In-Reply-To: References: Message-ID: Hello, Erlang 18.0 seems to have introduced a memory leak in the tty driver for unix platforms. This means that when printing to stdout the binary usage will grow. I believe I have found a solution to the problem. If you have problems with this leak, using -oldshell removes the leak. Thanks for reporting this issue. Lukas On Tue, Aug 18, 2015 at 2:18 PM, Alexander Petrovsky wrote: > Hi! > > A few days ago a noticed that erlang vm eat too many memory. I've checked > system and binary memory and found that it is constantly growing. I'm start > debugging with recon but without success. After disabling all application > the memory sill growing. > > I've checken on clean vm: > > 1> application:which_applications(). > [{stdlib,"ERTS CXC 138 10","2.5"}, > {kernel,"ERTS CXC 138 10","4.0"}] > > 2> [begin io:format("~p~n", [erlang:memory(binary)]), timer:sleep(1000) > end || _ <- lists:seq(1, 5)]. > 2105616 > 2113976 > 2122144 > 2130504 > 2138864 > > 3> io:format("~p~n", [erlang:memory(binary)]), timer:sleep(5000), > io:format("~p~n", [erlang:memory(binary)]). > 3124360 > 3132720 > > 4> 2138864 - 2105616. > 33248 > > 5> 3132720 - 3124360. > 8360 > > As you can see, the binary grow non linear and only when I call > erlang:memory(binary). > > System: Debian 7 > Erlang: 18.0 esl-erlang > > Can anyone help me? > > -- > ?????????? ????????? / Alexander Petrovsky, > > Skype: askjuise > Phone: +7 914 8 820 815 > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From snowwlex@REDACTED Tue Aug 18 17:29:22 2015 From: snowwlex@REDACTED (Alexander Turkin) Date: Tue, 18 Aug 2015 16:29:22 +0100 Subject: [erlang-questions] utf-8 and xmerl In-Reply-To: <06CE3C59-5056-4B3C-ADE7-E48DCCB3BFE7@rogvall.se> References: <55733d25-129c-4f19-94a3-4e15fc22b692@email.android.com> <06CE3C59-5056-4B3C-ADE7-E48DCCB3BFE7@rogvall.se> Message-ID: > > Why do you want to have utf8 in the values ? unicode is much more > generic and you select the encoding on the way out! The thing is that I need to convert it to json, and mochijson (and jsx as well) doesn't understand this* iso-10646. *And when mochijson gets something not utf-8, it throws `{ucs,{bad_utf8_character_code}}}` error. On 17 August 2015 at 16:26, Tony Rogvall wrote: > Ok I see. > > So you expected to find utf8 in the text value instead of the unicode ( > 233 is the same in latin1 and unicode btw ) > But that is not how the xmerl works. It represents the characters in > unicode iso-10646. > > Here is an example to get you a utf8 output. Bin is your binary. > > Term = binary_to_term(Bin). > {Content,_} = xmerl_scan:string(binary_to_list(Term)). > UnicodeChars = xmerl:export([Content], xmerl_xml). > Utf8Bin = unicode:characters_to_binary(UnicodeChars). > > I guess you could scan the xml structure (Content) and convert the text > values > to utf8 strings. But that would complicate the process when you want > to format the output. > > Why do you want to have utf8 in the values ? unicode is much more > generic and you select the encoding on the way out! > > /Tony > > > > On 17 aug 2015, at 15:56, Alexander Turkin wrote: > > > > Hey Tony, > > > > Yes, this binary is in utf8 - and it is what it's being fed to xmerl > library, which returns it in the other encoding by some reasons. > > > > On 17 August 2015 at 13:55, Tony Rogvall wrote: > > Sorry for the empty message :-) > > > > But the coding you are looking for is already in your binary. > > > > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, > > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, > > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, > > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, > > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, > > 115,112,111,110,115,101,62>> > > > > 195,169 = c3 a9 > > > > /Tony > > > > > >> On 17 aug 2015, at 14:39, Alexander Turkin wrote: > >> > >> Hi Hynek, > >> > >> On 15 August 2015 at 08:30, Hynek Vychodil > wrote: > >> The same result is in R18 and it it correct result. Letter ? has > unicode 233 see http://unicode-table.com/en/#00E9 > >> > >> Yeah, it has U+00E9 (= 233) code point number, but it is coded in 2 > bytes in utf8: c3 a9 > >> > >> U+00E9 ? c3 a9 LATIN SMALL LETTER E WITH ACUTE > >> > >> > >> (http://www.utf8-chartable.de/) > >> > >> On Fri, Aug 14, 2015 at 6:23 PM, ?ric Pailleau < > eric.pailleau@REDACTED> wrote: > >> Hello, > >> Please precise what Erlang release you are using. Utf8 came lately in > Erlang. > >> Regards > >> > >> Le 14 ao?t 2015 13:49, Alexander Turkin a ?crit : > >> > > >> > Dear list, > >> > > >> > > >> > I've got a problem with unicode & xmerl library. > >> > > >> > Input data for xmerl is utf-8 encoded xml, and what I've got as the > result is encoded latin1. But I need utf8! > >> > > >> > > >> > EXAMPLES > >> > > >> > Body = <<" encoding=\"UTF-8\"?>Ren?"/utf8>>. > >> > > >> > (for the sake of portability here is term_to_binary(Body): > >> > > >> > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, > >> > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, > >> > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, > >> > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, > >> > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, > >> > 115,112,111,110,115,101,62>> > >> > > >> > > >> > > >> > (1): > >> > > >> > When I do > >> > > >> > xmerl_scan:string(binary_to_list(Body)). > >> > > >> > it returns > >> > > >> > {#xmlElement{name = response,expanded_name = response, > >> > nsinfo = [], > >> > namespace = #xmlNamespace{default = [],nodes = []}, > >> > parents = [],pos = 1,attributes = [], > >> > content = [#xmlElement{name = value,expanded_name = > value, > >> > nsinfo = [], > >> > namespace = #xmlNamespace{default > = [],nodes = []}, > >> > parents = [{response,1}], > >> > pos = 1,attributes = [], > >> > content = [#xmlText{parents = > [{value,1},{response,1}], > >> > pos = > 1,language = [], > >> > > >> > > >> > value = > "Ren?", > >> > > >> > > >> > type = text}], > >> > language = [],xmlbase = > "/Users/aturkin/ws/", > >> > elementdef = undeclared}], > >> > language = [],xmlbase = "/Users/aturkin/ws/", > >> > elementdef = undeclared}, > >> > []} > >> > > >> > > >> > So, note there is `value = "Ren?"` string, and it uses [233] symbol, > which is latin1. > >> > > >> > > >> > > >> > > >> > (2): > >> > > >> > xmerl_scan:string(xmerl_ucs:to_utf8(binary_to_list(Body))) > >> > > >> > returns > >> > > >> > {#xmlElement{name = response,expanded_name = response, > >> > nsinfo = [], > >> > namespace = #xmlNamespace{default = [],nodes = []}, > >> > parents = [],pos = 1,attributes = [], > >> > content = [#xmlElement{name = value,expanded_name = > value, > >> > nsinfo = [], > >> > namespace = #xmlNamespace{default > = [],nodes = []}, > >> > parents = [{response,1}], > >> > pos = 1,attributes = [], > >> > content = [#xmlText{parents = > [{value,1},{response,1}], > >> > pos = > 1,language = [], > >> > > >> > > >> > value = > "Ren??", > >> > > >> > > >> > type = text}], > >> > language = [],xmlbase = > "/Users/aturkin/ws/", > >> > elementdef = undeclared}], > >> > language = [],xmlbase = "/Users/aturkin/ws/", > >> > elementdef = undeclared}, > >> > []} > >> > > >> > Now `value = "Ren??"`, so 2 bytes are used to code this symbol, and > this is utf-8. > >> > > >> > So in (2) I get what I need, but why I need to force that conversion > for xmerl? > >> > > >> > > >> > > >> > > >> > QUESTIONS > >> > > >> > 1. I don't understand why xmerl_scan allows you to set input > encoding, but it looks like there is no way to set output encoding. Is > there any way to make xmerl_scan to return utf8 instead of latin1? > >> > > >> > 2. How is that happen, that in (1) it does conversion utf-8 -> > latin1, and in (2) it's utf-8? > >> > > >> > > >> > > >> > > >> > -- > >> > Best Regards, > >> > Alex Turkin > >> _______________________________________________ > >> erlang-questions mailing list > >> erlang-questions@REDACTED > >> http://erlang.org/mailman/listinfo/erlang-questions > >> > >> > >> > >> > >> -- > >> Best Regards, > >> Alex Turkin > >> _______________________________________________ > >> erlang-questions mailing list > >> erlang-questions@REDACTED > >> http://erlang.org/mailman/listinfo/erlang-questions > > > > > > > > > > -- > > Best Regards, > > Alex Turkin > > -- Best Regards, Alex Turkin -------------- next part -------------- An HTML attachment was scrubbed... URL: From vychodil.hynek@REDACTED Tue Aug 18 18:17:30 2015 From: vychodil.hynek@REDACTED (Hynek Vychodil) Date: Tue, 18 Aug 2015 18:17:30 +0200 Subject: [erlang-questions] utf-8 and xmerl In-Reply-To: References: <55733d25-129c-4f19-94a3-4e15fc22b692@email.android.com> <06CE3C59-5056-4B3C-ADE7-E48DCCB3BFE7@rogvall.se> Message-ID: So then there is a problem in jsx and mochijson. The type of result returned by xmerl is unicode:chardata() which is new standard for io operations (see module io as an example). You can convert it using unicode:characters_to_list/1 for old incompatible modules and fill bug report or feature request. On Tue, Aug 18, 2015 at 5:29 PM, Alexander Turkin wrote: > Why do you want to have utf8 in the values ? unicode is much more >> generic and you select the encoding on the way out! > > > The thing is that I need to convert it to json, and mochijson (and jsx as > well) doesn't understand this* iso-10646. *And when mochijson gets > something not utf-8, it throws `{ucs,{bad_utf8_character_code}}}` error. > > > > > On 17 August 2015 at 16:26, Tony Rogvall wrote: > >> Ok I see. >> >> So you expected to find utf8 in the text value instead of the unicode ( >> 233 is the same in latin1 and unicode btw ) >> But that is not how the xmerl works. It represents the characters in >> unicode iso-10646. >> >> Here is an example to get you a utf8 output. Bin is your binary. >> >> Term = binary_to_term(Bin). >> {Content,_} = xmerl_scan:string(binary_to_list(Term)). >> UnicodeChars = xmerl:export([Content], xmerl_xml). >> Utf8Bin = unicode:characters_to_binary(UnicodeChars). >> >> I guess you could scan the xml structure (Content) and convert the text >> values >> to utf8 strings. But that would complicate the process when you want >> to format the output. >> >> Why do you want to have utf8 in the values ? unicode is much more >> generic and you select the encoding on the way out! >> >> /Tony >> >> >> > On 17 aug 2015, at 15:56, Alexander Turkin wrote: >> > >> > Hey Tony, >> > >> > Yes, this binary is in utf8 - and it is what it's being fed to xmerl >> library, which returns it in the other encoding by some reasons. >> > >> > On 17 August 2015 at 13:55, Tony Rogvall wrote: >> > Sorry for the empty message :-) >> > >> > But the coding you are looking for is already in your binary. >> > >> > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, >> > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, >> > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, >> > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, >> > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, >> > 115,112,111,110,115,101,62>> >> > >> > 195,169 = c3 a9 >> > >> > /Tony >> > >> > >> >> On 17 aug 2015, at 14:39, Alexander Turkin wrote: >> >> >> >> Hi Hynek, >> >> >> >> On 15 August 2015 at 08:30, Hynek Vychodil >> wrote: >> >> The same result is in R18 and it it correct result. Letter ? has >> unicode 233 see http://unicode-table.com/en/#00E9 >> >> >> >> Yeah, it has U+00E9 (= 233) code point number, but it is coded in 2 >> bytes in utf8: c3 a9 >> >> >> >> U+00E9 ? c3 a9 LATIN SMALL LETTER E WITH ACUTE >> >> >> >> >> >> (http://www.utf8-chartable.de/) >> >> >> >> On Fri, Aug 14, 2015 at 6:23 PM, ?ric Pailleau < >> eric.pailleau@REDACTED> wrote: >> >> Hello, >> >> Please precise what Erlang release you are using. Utf8 came lately in >> Erlang. >> >> Regards >> >> >> >> Le 14 ao?t 2015 13:49, Alexander Turkin a ?crit : >> >> > >> >> > Dear list, >> >> > >> >> > >> >> > I've got a problem with unicode & xmerl library. >> >> > >> >> > Input data for xmerl is utf-8 encoded xml, and what I've got as the >> result is encoded latin1. But I need utf8! >> >> > >> >> > >> >> > EXAMPLES >> >> > >> >> > Body = <<"> encoding=\"UTF-8\"?>Ren?"/utf8>>. >> >> > >> >> > (for the sake of portability here is term_to_binary(Body): >> >> > >> >> > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, >> >> > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, >> >> > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, >> >> > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, >> >> > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, >> >> > 115,112,111,110,115,101,62>> >> >> > >> >> > >> >> > >> >> > (1): >> >> > >> >> > When I do >> >> > >> >> > xmerl_scan:string(binary_to_list(Body)). >> >> > >> >> > it returns >> >> > >> >> > {#xmlElement{name = response,expanded_name = response, >> >> > nsinfo = [], >> >> > namespace = #xmlNamespace{default = [],nodes = []}, >> >> > parents = [],pos = 1,attributes = [], >> >> > content = [#xmlElement{name = value,expanded_name = >> value, >> >> > nsinfo = [], >> >> > namespace = >> #xmlNamespace{default = [],nodes = []}, >> >> > parents = [{response,1}], >> >> > pos = 1,attributes = [], >> >> > content = [#xmlText{parents = >> [{value,1},{response,1}], >> >> > pos = >> 1,language = [], >> >> > >> >> > >> >> > value = >> "Ren?", >> >> > >> >> > >> >> > type = >> text}], >> >> > language = [],xmlbase = >> "/Users/aturkin/ws/", >> >> > elementdef = undeclared}], >> >> > language = [],xmlbase = "/Users/aturkin/ws/", >> >> > elementdef = undeclared}, >> >> > []} >> >> > >> >> > >> >> > So, note there is `value = "Ren?"` string, and it uses [233] symbol, >> which is latin1. >> >> > >> >> > >> >> > >> >> > >> >> > (2): >> >> > >> >> > xmerl_scan:string(xmerl_ucs:to_utf8(binary_to_list(Body))) >> >> > >> >> > returns >> >> > >> >> > {#xmlElement{name = response,expanded_name = response, >> >> > nsinfo = [], >> >> > namespace = #xmlNamespace{default = [],nodes = []}, >> >> > parents = [],pos = 1,attributes = [], >> >> > content = [#xmlElement{name = value,expanded_name = >> value, >> >> > nsinfo = [], >> >> > namespace = >> #xmlNamespace{default = [],nodes = []}, >> >> > parents = [{response,1}], >> >> > pos = 1,attributes = [], >> >> > content = [#xmlText{parents = >> [{value,1},{response,1}], >> >> > pos = >> 1,language = [], >> >> > >> >> > >> >> > value = >> "Ren??", >> >> > >> >> > >> >> > type = >> text}], >> >> > language = [],xmlbase = >> "/Users/aturkin/ws/", >> >> > elementdef = undeclared}], >> >> > language = [],xmlbase = "/Users/aturkin/ws/", >> >> > elementdef = undeclared}, >> >> > []} >> >> > >> >> > Now `value = "Ren??"`, so 2 bytes are used to code this symbol, and >> this is utf-8. >> >> > >> >> > So in (2) I get what I need, but why I need to force that conversion >> for xmerl? >> >> > >> >> > >> >> > >> >> > >> >> > QUESTIONS >> >> > >> >> > 1. I don't understand why xmerl_scan allows you to set input >> encoding, but it looks like there is no way to set output encoding. Is >> there any way to make xmerl_scan to return utf8 instead of latin1? >> >> > >> >> > 2. How is that happen, that in (1) it does conversion utf-8 -> >> latin1, and in (2) it's utf-8? >> >> > >> >> > >> >> > >> >> > >> >> > -- >> >> > Best Regards, >> >> > Alex Turkin >> >> _______________________________________________ >> >> erlang-questions mailing list >> >> erlang-questions@REDACTED >> >> http://erlang.org/mailman/listinfo/erlang-questions >> >> >> >> >> >> >> >> >> >> -- >> >> Best Regards, >> >> Alex Turkin >> >> _______________________________________________ >> >> erlang-questions mailing list >> >> erlang-questions@REDACTED >> >> http://erlang.org/mailman/listinfo/erlang-questions >> > >> > >> > >> > >> > -- >> > Best Regards, >> > Alex Turkin >> >> > > > -- > Best Regards, > Alex Turkin > -------------- next part -------------- An HTML attachment was scrubbed... URL: From tony@REDACTED Tue Aug 18 19:09:55 2015 From: tony@REDACTED (Tony Rogvall) Date: Tue, 18 Aug 2015 19:09:55 +0200 Subject: [erlang-questions] utf-8 and xmerl In-Reply-To: References: <55733d25-129c-4f19-94a3-4e15fc22b692@email.android.com> <06CE3C59-5056-4B3C-ADE7-E48DCCB3BFE7@rogvall.se> Message-ID: Then I suggest you use an other json module that support unicode OR scan the xml structure and reformat the text values into UTF while you are converting the XML into internal JSON structure? Must be super simple! /Tony > On 18 aug 2015, at 17:29, Alexander Turkin wrote: > > Why do you want to have utf8 in the values ? unicode is much more > generic and you select the encoding on the way out! > > The thing is that I need to convert it to json, and mochijson (and jsx as well) doesn't understand this iso-10646. And when mochijson gets something not utf-8, it throws `{ucs,{bad_utf8_character_code}}}` error. > > > > > On 17 August 2015 at 16:26, Tony Rogvall > wrote: > Ok I see. > > So you expected to find utf8 in the text value instead of the unicode ( 233 is the same in latin1 and unicode btw ) > But that is not how the xmerl works. It represents the characters in unicode iso-10646. > > Here is an example to get you a utf8 output. Bin is your binary. > > Term = binary_to_term(Bin). > {Content,_} = xmerl_scan:string(binary_to_list(Term)). > UnicodeChars = xmerl:export([Content], xmerl_xml). > Utf8Bin = unicode:characters_to_binary(UnicodeChars). > > I guess you could scan the xml structure (Content) and convert the text values > to utf8 strings. But that would complicate the process when you want > to format the output. > > Why do you want to have utf8 in the values ? unicode is much more > generic and you select the encoding on the way out! > > /Tony > > > > On 17 aug 2015, at 15:56, Alexander Turkin > wrote: > > > > Hey Tony, > > > > Yes, this binary is in utf8 - and it is what it's being fed to xmerl library, which returns it in the other encoding by some reasons. > > > > On 17 August 2015 at 13:55, Tony Rogvall > wrote: > > Sorry for the empty message :-) > > > > But the coding you are looking for is already in your binary. > > > > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, > > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, > > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, > > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, > > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, > > 115,112,111,110,115,101,62>> > > > > 195,169 = c3 a9 > > > > /Tony > > > > > >> On 17 aug 2015, at 14:39, Alexander Turkin > wrote: > >> > >> Hi Hynek, > >> > >> On 15 August 2015 at 08:30, Hynek Vychodil > wrote: > >> The same result is in R18 and it it correct result. Letter ? has unicode 233 see http://unicode-table.com/en/#00E9 > >> > >> Yeah, it has U+00E9 (= 233) code point number, but it is coded in 2 bytes in utf8: c3 a9 > >> > >> U+00E9 ? c3 a9 LATIN SMALL LETTER E WITH ACUTE > >> > >> > >> (http://www.utf8-chartable.de/ ) > >> > >> On Fri, Aug 14, 2015 at 6:23 PM, ?ric Pailleau > wrote: > >> Hello, > >> Please precise what Erlang release you are using. Utf8 came lately in Erlang. > >> Regards > >> > >> Le 14 ao?t 2015 13:49, Alexander Turkin > a ?crit : > >> > > >> > Dear list, > >> > > >> > > >> > I've got a problem with unicode & xmerl library. > >> > > >> > Input data for xmerl is utf-8 encoded xml, and what I've got as the result is encoded latin1. But I need utf8! > >> > > >> > > >> > EXAMPLES > >> > > >> > Body = <<"Ren?"/utf8>>. > >> > > >> > (for the sake of portability here is term_to_binary(Body): > >> > > >> > <<131,109,0,0,0,79,60,63,120,109,108,32,118,101,114,115, > >> > 105,111,110,61,34,49,46,48,34,32,101,110,99,111,100,105, > >> > 110,103,61,34,85,84,70,45,56,34,63,62,60,114,101,115, > >> > 112,111,110,115,101,62,60,118,97,108,117,101,62,82,101, > >> > 110,195,169,60,47,118,97,108,117,101,62,60,47,114,101, > >> > 115,112,111,110,115,101,62>> > >> > > >> > > >> > > >> > (1): > >> > > >> > When I do > >> > > >> > xmerl_scan:string(binary_to_list(Body)). > >> > > >> > it returns > >> > > >> > {#xmlElement{name = response,expanded_name = response, > >> > nsinfo = [], > >> > namespace = #xmlNamespace{default = [],nodes = []}, > >> > parents = [],pos = 1,attributes = [], > >> > content = [#xmlElement{name = value,expanded_name = value, > >> > nsinfo = [], > >> > namespace = #xmlNamespace{default = [],nodes = []}, > >> > parents = [{response,1}], > >> > pos = 1,attributes = [], > >> > content = [#xmlText{parents = [{value,1},{response,1}], > >> > pos = 1,language = [], > >> > > >> > > >> > value = "Ren?", > >> > > >> > > >> > type = text}], > >> > language = [],xmlbase = "/Users/aturkin/ws/", > >> > elementdef = undeclared}], > >> > language = [],xmlbase = "/Users/aturkin/ws/", > >> > elementdef = undeclared}, > >> > []} > >> > > >> > > >> > So, note there is `value = "Ren?"` string, and it uses [233] symbol, which is latin1. > >> > > >> > > >> > > >> > > >> > (2): > >> > > >> > xmerl_scan:string(xmerl_ucs:to_utf8(binary_to_list(Body))) > >> > > >> > returns > >> > > >> > {#xmlElement{name = response,expanded_name = response, > >> > nsinfo = [], > >> > namespace = #xmlNamespace{default = [],nodes = []}, > >> > parents = [],pos = 1,attributes = [], > >> > content = [#xmlElement{name = value,expanded_name = value, > >> > nsinfo = [], > >> > namespace = #xmlNamespace{default = [],nodes = []}, > >> > parents = [{response,1}], > >> > pos = 1,attributes = [], > >> > content = [#xmlText{parents = [{value,1},{response,1}], > >> > pos = 1,language = [], > >> > > >> > > >> > value = "Ren??", > >> > > >> > > >> > type = text}], > >> > language = [],xmlbase = "/Users/aturkin/ws/", > >> > elementdef = undeclared}], > >> > language = [],xmlbase = "/Users/aturkin/ws/", > >> > elementdef = undeclared}, > >> > []} > >> > > >> > Now `value = "Ren??"`, so 2 bytes are used to code this symbol, and this is utf-8. > >> > > >> > So in (2) I get what I need, but why I need to force that conversion for xmerl? > >> > > >> > > >> > > >> > > >> > QUESTIONS > >> > > >> > 1. I don't understand why xmerl_scan allows you to set input encoding, but it looks like there is no way to set output encoding. Is there any way to make xmerl_scan to return utf8 instead of latin1? > >> > > >> > 2. How is that happen, that in (1) it does conversion utf-8 -> latin1, and in (2) it's utf-8? > >> > > >> > > >> > > >> > > >> > -- > >> > Best Regards, > >> > Alex Turkin > >> _______________________________________________ > >> erlang-questions mailing list > >> erlang-questions@REDACTED > >> http://erlang.org/mailman/listinfo/erlang-questions > >> > >> > >> > >> > >> -- > >> Best Regards, > >> Alex Turkin > >> _______________________________________________ > >> erlang-questions mailing list > >> erlang-questions@REDACTED > >> http://erlang.org/mailman/listinfo/erlang-questions > > > > > > > > > > -- > > Best Regards, > > Alex Turkin > > > > > -- > Best Regards, > Alex Turkin -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: Message signed with OpenPGP using GPGMail URL: From r.wobben@REDACTED Tue Aug 18 20:13:35 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Tue, 18 Aug 2015 20:13:35 +0200 Subject: [erlang-questions] How can I make a list of this Message-ID: <55D375CF.1000701@home.nl> Hello, Im still trying to solve exercise 2 of chapter 8 of Programming erlang. Now I succeed in finding all functions that are exported by a module. I see now this output : [{get_rc,0}, {close,1}, {peername,1}, {setpeername,2}, {peernames,...}, {...}|...], [{module,2},{module_info,0},{module_info,1}], [{new,0},{is_set,1},{size,...},{...}|...], [{server,3},{interfaces,...},{...}|...], [{init_it,...},{...}|...], [{...}|...], [...]|...] So I have list which are containing more list which contains one of more tuples Is it possible to convert this to for example [get_rc/0, peername/1, peernames/? , module/2 ] I tried with lists:flatten( name_of_list) but that one do not give me the right output. I need the nice output because I have to sort them and then count them. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From seancribbs@REDACTED Tue Aug 18 20:31:52 2015 From: seancribbs@REDACTED (Sean Cribbs) Date: Tue, 18 Aug 2015 13:31:52 -0500 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <55D375CF.1000701@home.nl> References: <55D375CF.1000701@home.nl> Message-ID: Can you give us an example of how you got the list of exports? That is, did you do something other than the below? Module:module_info(exports) Note that the Function/Arity notation is not a regular Erlang term, but becomes {Function, Arity} in the return value from module_info/1. On Tue, Aug 18, 2015 at 1:13 PM, Roelof Wobben wrote: > Hello, > > Im still trying to solve exercise 2 of chapter 8 of Programming erlang. > > Now I succeed in finding all functions that are exported by a module. > > I see now this output : > > [{get_rc,0}, {close,1}, {peername,1}, {setpeername,2}, {peernames,...}, > {...}|...], [{module,2},{module_info,0},{module_info,1}], > [{new,0},{is_set,1},{size,...},{...}|...], > [{server,3},{interfaces,...},{...}|...], [{init_it,...},{...}|...], > [{...}|...], [...]|...] > > So I have list which are containing more list which contains one of more > tuples > > Is it possible to convert this to for example [get_rc/0, peername/1, > peernames/? , module/2 ] > > I tried with lists:flatten( name_of_list) but that one do not give me the > right output. > > I need the nice output because I have to sort them and then count them. > > Roelof > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Tue Aug 18 20:40:43 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Tue, 18 Aug 2015 20:40:43 +0200 Subject: [erlang-questions] How can I make a list of this In-Reply-To: References: <55D375CF.1000701@home.nl> Message-ID: <55D37C2B.4070402@home.nl> An HTML attachment was scrubbed... URL: From freza@REDACTED Tue Aug 18 21:02:26 2015 From: freza@REDACTED (Jachym Holecek) Date: Tue, 18 Aug 2015 15:02:26 -0400 Subject: [erlang-questions] gen_tcp:controlling_process/2 impact In-Reply-To: <20150818131223.GA24333@fhebert-ltm1> References: <20150818131223.GA24333@fhebert-ltm1> Message-ID: <20150818190226.GA13534@circlewave.net> # Fred Hebert 2015-08-18: > On 08/18, Benoit Chesneau wrote: > If the socket is used only for writing, then you don't need to > change the controlling process, just send the thing directly. Anyone > can write to a socket, just one process can read. > > If you do need to read from it, then the best idea is likely to > resolve your chain, find the final destination pid, and hand the > control there. The owner must hand the control, so rather than > going: > > a -- give --> b -- give --> c > > go > > a -- ask pid --> b -- finds --> c > a -- give --> c Just to give a more elaborate example of what Ferd is saying, from memory: accept peer connection proc server proc -+---------------+--------------+--------- | | o | accept(L) -> S | | +---------------> add_connection(S) | | | +--------------> spawn(S, ...) | | | <------------------------------+ reply(..., self()) | | | o | | controlling_process(S, P) | | | +------------------------------> handover_ack | | | | | o ready, active true In Benoit's case there's more than one intermediary, but the overall picture remains essentially the same. > which will have a single control-handing form. You can also swap it > around and let 'b' tell 'c' to "ask a for your port" and then do the > switch. > > Also remember to let the socket in {accept, false} mode so that no > messages are lost during the whole operation. One wants {active, false} here indeed. Let me add, just in case we're talking protocol stack implementation, that it may turn out surprisingly convenient to perform initial session setup with {active, false} using passive recv() instead (intuitively one might lean towards {active, true} socket run by a gen_fsm, which may end up nastily overcomplicated). It may also be very convenient to do initial session setup from a different process (and different code module) than where fully operational session is handled. Not sure this makes an awful lot of sense without context, just reminded me of something in my previous projects... Nevermind if not. :-) Have fun, -- Jachym From rpettit@REDACTED Tue Aug 18 21:20:17 2015 From: rpettit@REDACTED (Rick Pettit) Date: Tue, 18 Aug 2015 14:20:17 -0500 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <55D375CF.1000701@home.nl> References: <55D375CF.1000701@home.nl> Message-ID: <84196363-78DA-4AA7-9C6C-65C330871ED6@vailsys.com> Unless the exercise requires you to output in fun/arity format, that isn?t required in order to simply sort and count the elements in the list of lists you have below. -Rick P.S. I?m not suggesting the following code is the best way to do this, nor that lists should be used over binaries, but here?s one way to the conversion assuming it is required for the exercise (here I?m using the sorted list of exported functions from the ?inet? module as an example): 12> [lists:flatten(io_lib:format("~s/~s", [atom_to_list(Fun), integer_to_list(Arity)])) || {Fun,Arity} <- lists:keysort(1, inet:module_info(exports))]. ["close/1","connect_options/2","fdopen/6","format_error/1", "get_rc/0","getaddr/3","getaddr/2","getaddr_tm/3", "getaddrs/2","getaddrs/3","getaddrs_tm/3","getfd/1", "gethostbyaddr/1","gethostbyaddr/2","gethostbyaddr_tm/2", "gethostbyname/2","gethostbyname/3","gethostbyname/1", "gethostbyname_self/2","gethostbyname_string/2", "gethostbyname_tm/3","gethostname/1","gethostname/0", "getif/0","getif/1","getifaddrs/1","getifaddrs/0", "getiflist/1", [...]|?] suggesting Now if you are just going to output the resulting list using something like io:format/2, then you don?t even need to lists:flatten/1: 15> io:format([io_lib:format("~s/~s\n", [atom_to_list(Fun), integer_to_list(Arity)]) || {Fun,Arity} <- lists:keysort(1, inet:module_info(exports))]). close/1 connect_options/2 fdopen/6 format_error/1 get_rc/0 getaddr/3 getaddr/2 getaddr_tm/3 getaddrs/2 getaddrs/3 getaddrs_tm/3 getfd/1 gethostbyaddr/1 gethostbyaddr/2 gethostbyaddr_tm/2 gethostbyname/2 gethostbyname/3 gethostbyname/1 gethostbyname_self/2 gethostbyname_string/2 gethostbyname_tm/3 gethostname/1 ? ... > On Aug 18, 2015, at 1:13 PM, Roelof Wobben wrote: > > Hello, > > Im still trying to solve exercise 2 of chapter 8 of Programming erlang. > > Now I succeed in finding all functions that are exported by a module. > > I see now this output : > > [{get_rc,0}, {close,1}, {peername,1}, {setpeername,2}, {peernames,...}, {...}|...], [{module,2},{module_info,0},{module_info,1}], [{new,0},{is_set,1},{size,...},{...}|...], [{server,3},{interfaces,...},{...}|...], [{init_it,...},{...}|...], [{...}|...], [...]|...] > > So I have list which are containing more list which contains one of more tuples > > Is it possible to convert this to for example [get_rc/0, peername/1, peernames/? , module/2 ] > > I tried with lists:flatten( name_of_list) but that one do not give me the right output. > > I need the nice output because I have to sort them and then count them. > > Roelof > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- An HTML attachment was scrubbed... URL: From benhsu@REDACTED Tue Aug 18 22:16:12 2015 From: benhsu@REDACTED (Ben Hsu) Date: Tue, 18 Aug 2015 16:16:12 -0400 Subject: [erlang-questions] strings vs binaries Message-ID: Hello I have a simple question, I know Erlang has strings and binary strings as separate data types, and they're different even if they "look the same" in the console 1> io:format(<<"fnord">>). fnord 2> io:format("fnord"). fnord 3> "fnord"==<<"fnord">> 3> . false My question is when you will use each one. Are binary strings used for sending data over the wire, and normal strings used internally? what are the tradeoffs? -------------- next part -------------- An HTML attachment was scrubbed... URL: From rpettit@REDACTED Tue Aug 18 22:23:32 2015 From: rpettit@REDACTED (Rick Pettit) Date: Tue, 18 Aug 2015 15:23:32 -0500 Subject: [erlang-questions] strings vs binaries In-Reply-To: References: Message-ID: <8BB0D966-BC4F-4C1E-BAD2-0B01AA14CCD0@vailsys.com> Generally speaking, you probably want to use binaries these days as they consume far less memory (at least for ?large? strings): http://www.erlang.org/doc/efficiency_guide/advanced.html That goes for both sending over the wire as well as internally. -Rick > On Aug 18, 2015, at 3:16 PM, Ben Hsu wrote: > > Hello > > I have a simple question, I know Erlang has strings and binary strings as separate data types, and they're different even if they "look the same" in the console > > > 1> io:format(<<"fnord">>). > fnord > 2> io:format("fnord"). > fnord > > 3> "fnord"==<<"fnord">> > 3> . > false > > My question is when you will use each one. Are binary strings used for sending data over the wire, and normal strings used internally? what are the tradeoffs? > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- An HTML attachment was scrubbed... URL: From felixgallo@REDACTED Tue Aug 18 22:27:21 2015 From: felixgallo@REDACTED (Felix Gallo) Date: Tue, 18 Aug 2015 13:27:21 -0700 Subject: [erlang-questions] strings vs binaries In-Reply-To: <8BB0D966-BC4F-4C1E-BAD2-0B01AA14CCD0@vailsys.com> References: <8BB0D966-BC4F-4C1E-BAD2-0B01AA14CCD0@vailsys.com> Message-ID: The redoubtable @jlouis666 has an excellent blog post about strings that may be of interest: https://medium.com/@jlouis666/erlang-string-handling-7588daad8f05 F. On Tue, Aug 18, 2015 at 1:23 PM, Rick Pettit wrote: > Generally speaking, you probably want to use binaries these days as they > consume far less memory (at least for ?large? strings): > > http://www.erlang.org/doc/efficiency_guide/advanced.html > > That goes for both sending over the wire as well as internally. > > -Rick > > On Aug 18, 2015, at 3:16 PM, Ben Hsu wrote: > > Hello > > I have a simple question, I know Erlang has strings and binary strings as > separate data types, and they're different even if they "look the same" in > the console > > > 1> io:format(<<"fnord">>). > fnord > 2> io:format("fnord"). > fnord > > 3> "fnord"==<<"fnord">> > 3> . > false > > My question is when you will use each one. Are binary strings used for > sending data over the wire, and normal strings used internally? what are > the tradeoffs? > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rpettit@REDACTED Tue Aug 18 22:29:42 2015 From: rpettit@REDACTED (Rick Pettit) Date: Tue, 18 Aug 2015 15:29:42 -0500 Subject: [erlang-questions] strings vs binaries In-Reply-To: References: <8BB0D966-BC4F-4C1E-BAD2-0B01AA14CCD0@vailsys.com> Message-ID: <84DB1680-A81B-4130-871C-69D0947BF505@vailsys.com> Had not seen that before Felix?thanks for the link. -Rick > On Aug 18, 2015, at 3:27 PM, Felix Gallo wrote: > > The redoubtable @jlouis666 has an excellent blog post about strings that may be of interest: https://medium.com/@jlouis666/erlang-string-handling-7588daad8f05 > > F. > > On Tue, Aug 18, 2015 at 1:23 PM, Rick Pettit > wrote: > Generally speaking, you probably want to use binaries these days as they consume far less memory (at least for ?large? strings): > > http://www.erlang.org/doc/efficiency_guide/advanced.html > > That goes for both sending over the wire as well as internally. > > -Rick > >> On Aug 18, 2015, at 3:16 PM, Ben Hsu > wrote: >> >> Hello >> >> I have a simple question, I know Erlang has strings and binary strings as separate data types, and they're different even if they "look the same" in the console >> >> >> 1> io:format(<<"fnord">>). >> fnord >> 2> io:format("fnord"). >> fnord >> >> 3> "fnord"==<<"fnord">> >> 3> . >> false >> >> My question is when you will use each one. Are binary strings used for sending data over the wire, and normal strings used internally? what are the tradeoffs? >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From steven.charles.davis@REDACTED Wed Aug 19 00:47:53 2015 From: steven.charles.davis@REDACTED (Steve Davis) Date: Tue, 18 Aug 2015 17:47:53 -0500 Subject: [erlang-questions] strings vs binaries Message-ID: <52FB8F4D-EF4A-4239-B19B-D5E01464974B@gmail.com> In addition to what?s already been said... The old chestnut that ?erlang is bad at string manipulation? completely goes away if you choose to use binaries for all your text. In fact, erlang is far superior at text tasks than most platforms I have used if you keep all your text as binaries. My 2c /s From zxq9@REDACTED Wed Aug 19 01:37:09 2015 From: zxq9@REDACTED (zxq9) Date: Wed, 19 Aug 2015 08:37:09 +0900 Subject: [erlang-questions] strings vs binaries In-Reply-To: <52FB8F4D-EF4A-4239-B19B-D5E01464974B@gmail.com> References: <52FB8F4D-EF4A-4239-B19B-D5E01464974B@gmail.com> Message-ID: <2726160.SUYtYmxOkC@changa> On 2015?8?18? ??? 17:47:53 Steve Davis wrote: > In addition to what?s already been said... > > The old chestnut that ?erlang is bad at string manipulation? completely goes away if you choose to use binaries for all your text. > > In fact, erlang is far superior at text tasks than most platforms I have used if you keep all your text as binaries. ...unless you need to do it in utf8... From steven.charles.davis@REDACTED Wed Aug 19 01:39:57 2015 From: steven.charles.davis@REDACTED (Steve Davis) Date: Tue, 18 Aug 2015 18:39:57 -0500 Subject: [erlang-questions] How can I make a list of this Message-ID: <2A5408F7-968F-4A0A-AEA5-0BD6BEF33F9F@gmail.com> Hi Roelof, Here you go: 1> [[{sorted, lists:sort(X)}, {count, length(X)}] || X <- [inet:module_info(exports)]]. ... 2> [get_rc/0]. ** exception error: an error occurred when evaluating an arithmetic expression in operator '/'/2 called as get_rc / 0 What the book/lesson is trying to teach is probably not how to do basic operations on lists (which is notionally the point of the exercise). It?s actually trying to get you to reach for the right tool to do the job by getting you to explore the platform libraries and the power of the platform for yourself. Yes, I cheated above and used a comprehension above to present the answers you want, and also showed what happens when you get what you originally asked for. Likely you didn?t learn much from that, since what I typed in was born of spending time with the libraries and knowing what to do with a problem I?m presented with and understanding what erlang tells you when you get it ?wrong". You need to be patient and find your own solutions to things, since if you are merely taking others? solutions, you will never become a ?power user?. It?s a hard slog, I don?t deny that. However, the REPL, particularly in your early learning lets you try things out instantly, and is invaluable help in breaking down a problem. You can try individual steps extremely easily - and in a way that is simply not possible with non-functional languages. If it?s any help or encouragement, it took me months to ?grok? erlang and its unfamiliar ways, but once I had, I realized what I was missing. Each day, even after a few years, I learn something new and positive about the platform. It?s also been an empowerment in my relationship to computers; I can express concepts that would be essentially intractable in many popular languages. I wish you well in your journey (one that I have personally experienced) and offer the thought that it?s likely more rewarding, and more empowering in the long term, to sit with a problem, read the documentation that comes with Erlang (which is extremely good despite its many critics) and *find your own solution* than to look outside for help too quickly. Sure if you get totally stuck, there?s help here. I can promise you that the long path and all the hard work to becoming an ?erlang ninja? will be worth every second. /s -------------- next part -------------- An HTML attachment was scrubbed... URL: From steven.charles.davis@REDACTED Wed Aug 19 02:19:36 2015 From: steven.charles.davis@REDACTED (Steve Davis) Date: Tue, 18 Aug 2015 19:19:36 -0500 Subject: [erlang-questions] strings vs binaries Message-ID: <90AD63CD-FEC2-407D-B05B-C70AA43E2D8C@gmail.com> Hi zxq9, ?example?? ?test case?? (Did I miss a post already in history?) (Is the example/test case better handled in another platform? if so, which?, and how?) Please change my view if it is obviously incorrect. Best, /s > On 2015?8?18? ??? 17:47:53 Steve Davis wrote: >> In addition to what?s already been said... >> >> The old chestnut that ?erlang is bad at string manipulation? completely goes away if you choose to use binaries for all your text. >> >> In fact, erlang is far superior at text tasks than most platforms I have used if you keep all your text as binaries. >...unless you need to do it in utf8... -------------- next part -------------- An HTML attachment was scrubbed... URL: From ok@REDACTED Wed Aug 19 04:57:26 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Wed, 19 Aug 2015 14:57:26 +1200 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <55D375CF.1000701@home.nl> References: <55D375CF.1000701@home.nl> Message-ID: <1F93E56C-843F-44A6-98A5-35FEF0A6B073@cs.otago.ac.nz> On 19/08/2015, at 6:13 am, Roelof Wobben wrote: > Hello, > > Im still trying to solve exercise 2 of chapter 8 of Programming erlang. > > Now I succeed in finding all functions that are exported by a module. > > I see now this output : > > [{get_rc,0}, {close,1}, {peername,1}, {setpeername,2}, {peernames,...}, {...}|...], [{module,2},{module_info,0},{module_info,1}], [{new,0},{is_set,1},{size,...},{...}|...], [{server,3},{interfaces,...},{...}|...], [{init_it,...},{...}|...], [{...}|...], [...]|...] > > So I have list which are containing more list which contains one of more tuples > > Is it possible to convert this to for example [get_rc/0, peername/1, peernames/? , module/2 ] There is no get_rc/0 data structure. When you have F/N in a declaration, it is converted to {F,N}. [{get_rc,0}, {peername,1}, ...] is as close as you are going to get. > I need the nice output because I have to sort them and then count them. No you don't. You can sort a list of tuples. 1> lists:sort([{c,3},{a,2},{b,4},{a,1},{c,2}]). [{a,1},{a,2},{b,4},{c,2},{c,3}] Given a sorted list, sorted_list_unique_count(L) -> sorted_list_unique_count(L, 0). sorted_list_unique_count([X|Xs=[X|_]], N) -> % duplicate sorted_list_unique_count(Xs, N); sorted_list_unique_count([_|Xs], N) -> % non-duplicate sorted_list_unique_count(Xs, N+1); sorted_list_unique_count([], N) -> N. You can print such a list prettily if you want: format_functor_list(Fs) -> format_functor_list(Fs, ""). format_functor_list([{F,N}|Fs], Sep) -> io:format("~s~w/~w", [Sep, F,N]), format_functor_list(Fs, ", "); format_functor_list([], _) -> ok. From zxq9@REDACTED Wed Aug 19 05:26:35 2015 From: zxq9@REDACTED (zxq9) Date: Wed, 19 Aug 2015 12:26:35 +0900 Subject: [erlang-questions] strings vs binaries In-Reply-To: <90AD63CD-FEC2-407D-B05B-C70AA43E2D8C@gmail.com> References: <90AD63CD-FEC2-407D-B05B-C70AA43E2D8C@gmail.com> Message-ID: <7702810.fPd6DCQAtd@changa> On 2015?8?18? ??? 19:19:36 Steve Davis wrote: > Hi zxq9, > ?example?? > ?test case?? > (Did I miss a post already in history?) > (Is the example/test case better handled in another platform? if so, which?, and how?) > Please change my view if it is obviously incorrect. > Best, > /s > > > On 2015?8?18? ??? 17:47:53 Steve Davis wrote: > >> In addition to what?s already been said... > >> > >> The old chestnut that ?erlang is bad at string manipulation? completely goes away if you choose to use binaries for all your text. > >> > >> In fact, erlang is far superior at text tasks than most platforms I have used if you keep all your text as binaries. > > >...unless you need to do it in utf8... > > > Hi zxq9, > ?example?? > ?test case?? > (Did I miss a post already in history?) > (Is the example/test case better handled in another platform? if so, which?, and how?) > Please change my view if it is obviously incorrect. > Best, > /s Hi, Steve. Sure. Let's say you have a string where it is always known that you need to pull some specific segment, characters 3 to 11, for example. When these are ASCII that's marvelously easy with binaries. Not so much when they are utf8 multibyte charcters, though: <<"Getting characters from a range within this is easy.">> <<"binary??????????????string????????????"/utf8>> You will either have to use "(*UTF8)blahblah" regexes everywhere (which is appropriate for some cases, but not nearly enough) or convert those binaries to strings so that you can do the things you expected to be able to do with them easily. Quite a few of the split, split on X, split after segment X-Y, etc. type functions don't work the expected way with utf8 in binary form, but do with utf8 strings. The lucky thing there is that Erlang's output interfaces (format functions, socket output, etc.) accepts iolists, so it doesn't really matter how messy a cobbled together deep list happens to be before you hand it to them. Delimiters also can catch you by surprise -- there are "many" 'kinds' ?of? ?quotes? (and) ?brackets? `in` ?use? and not all are easy to make sense of or fit within a single byte. Spaces are spaces and tabs?are tabs, sure, but?check the spacing in this sentence carefully. Also, many multibyte characters are single width, ????????. My region obviously causes me to clash with this issue quite a bit more than seems to be the case with the rest of the Erlang world. That said, there are many tools/environments that make manipulating utf8 much easier than Erlang. -Craig From ok@REDACTED Wed Aug 19 05:30:32 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Wed, 19 Aug 2015 15:30:32 +1200 Subject: [erlang-questions] strings vs binaries In-Reply-To: <90AD63CD-FEC2-407D-B05B-C70AA43E2D8C@gmail.com> References: <90AD63CD-FEC2-407D-B05B-C70AA43E2D8C@gmail.com> Message-ID: <280A8ECB-A6C0-4C8D-90B9-76C740180805@cs.otago.ac.nz> Lists are sequences of whatever you want, so you can represent a Unicode text as a list of Unicode/ISO10646 code-points with no trouble. This means that string = list of integer is quite a convenient way to process Unicode. Binaries are a compact way to store Unicode sequences encoded in UTF-8 (or other explicitly specified encodings, thanks to the unicode module). UTF8 and UTF16 are not noticeably convenient representations for processing. In fact strictly speaking a Unicode text is a sequence of [Base_Character|Floating_Diacriticals] sequences (or possibly even something more complicated which I shall spare you), so for moving through a Unicode character one "logical" character at a time a list of lists of codepoints may be even more convenient. The one thing you must NOT do in ANY programming language is to believe for one instant that there is ANY text representation that should be used always and everywhere, still less that something *called* "string" is the right tool for the job (or that it isn't). Erlang, for example, has quite a few functions that support "iolists" or these days the unicode:chardata() type, see http://erlang.org/doc/man/unicode.html#type-chardata Now that representation is pretty awful for most processing purposes, but is absolutely BRILLIANT for concatenation and output. And the unicode module lets you convert it to a simple list or a binary if and when you need to. Always, you need to ask "What am I going to do with this?" From r.wobben@REDACTED Wed Aug 19 07:32:34 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Wed, 19 Aug 2015 07:32:34 +0200 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <2A5408F7-968F-4A0A-AEA5-0BD6BEF33F9F@gmail.com> References: <2A5408F7-968F-4A0A-AEA5-0BD6BEF33F9F@gmail.com> Message-ID: <55D414F2.5040505@home.nl> An HTML attachment was scrubbed... URL: From akrupicka@REDACTED Wed Aug 19 10:36:26 2015 From: akrupicka@REDACTED (Adam Krupicka) Date: Wed, 19 Aug 2015 10:36:26 +0200 Subject: [erlang-questions] strings vs binaries In-Reply-To: <2726160.SUYtYmxOkC@changa> References: <52FB8F4D-EF4A-4239-B19B-D5E01464974B@gmail.com> <2726160.SUYtYmxOkC@changa> Message-ID: <1439973112-sup-8025@arch.local> > ...unless you need to do it in utf8... Can you elaborate on what is the main concern when using Unicode UTF-8 in Erlang? Is it purely because of the lack of extensive UTF-8 support in the stdlib in certain modules, or are there some performance issues that I'm not aware of? Thanks, A. K. From jesper.louis.andersen@REDACTED Wed Aug 19 11:15:54 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Wed, 19 Aug 2015 11:15:54 +0200 Subject: [erlang-questions] strings vs binaries In-Reply-To: References: Message-ID: On Tue, Aug 18, 2015 at 10:16 PM, Ben Hsu wrote: > My question is when you will use each one. Are binary strings used for > sending data over the wire, and normal strings used internally? what are > the tradeoffs? Somewhat absent from the discussion until now are the 3rd string-like type in Erlang: atom()'s * A string() is a linked list of unicode code points on the process heap. * A binary() is a buffer of binary data which can contain utf-8 encoded strings. They are either allocated on the process heap, or for large strings, in the binary() arena in the memory allocator. This arena is shared among all processes. * An atom() is a name which is hashed to an integer internally and then the integer is used in place of the name. Caveats: * string()'s are easy to manipulate with a lot of functions, but their memory imprint is large. This makes them unsuitable for storing large amounts of data as strings, if that data is in-memory. They are usually fine for smaller things, and chunked flow however. * binary() data has problems if you reference subbinaries and those keep the underlying binary around. This is where `binary:copy/1` comes into the game. The general binary handling documentation in the performance guide linked here has the details of binaries, subbinaries, heap binaries and match contexts. * atom()'s have very fast equality checks. But the atom table is limited in size, you you can't have a program which dynamically creates new atoms. In many cases however, creating a mapping from external data to internal atoms yields very efficient programs. The general rule from my blog post still holds true to this day: it is often better to internalize external data into a symbolic format. A language such as Erlang is efficient when it operates on symbolic data: intern(<<"fnord">>) -> {ok, fnord}; intern(<<"frobnificatization">>) -> {ok, frobnificatization}; intern(Unknown) -> {error, {cannot_intern, Unknown}}. i(X) -> {ok, A} = intern(X), A. and so on. Of course, if the string is truly a random string of information for humans to read, you can't parse it, but have to lug it around as satellite data in your application. And then the size caveat of string()'s has to be taken into account for some programs which keep a large set of data in-memory. (Note: This is without discussing the problem of handling unicode data, which other people covered well already) -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From rvirding@REDACTED Wed Aug 19 11:44:20 2015 From: rvirding@REDACTED (Robert Virding) Date: Wed, 19 Aug 2015 10:44:20 +0100 Subject: [erlang-questions] strings vs binaries In-Reply-To: References: Message-ID: Someone did some benchmarking on this a few years ago to compare the speed of using binary utf-8 encoded strings vs list strings. They arrived at the for them surprising result that using list strings was actually faster. It is actually not surprising if you think about it. So what Richard says definitely very relevant: Always, you need to ask "What am I going to do with this?" Robert On 19 August 2015 at 10:15, Jesper Louis Andersen < jesper.louis.andersen@REDACTED> wrote: > > On Tue, Aug 18, 2015 at 10:16 PM, Ben Hsu wrote: > >> My question is when you will use each one. Are binary strings used for >> sending data over the wire, and normal strings used internally? what are >> the tradeoffs? > > > Somewhat absent from the discussion until now are the 3rd string-like type > in Erlang: atom()'s > > * A string() is a linked list of unicode code points on the process heap. > * A binary() is a buffer of binary data which can contain utf-8 encoded > strings. They are either allocated on the process heap, or for large > strings, in the binary() arena in the memory allocator. This arena is > shared among all processes. > * An atom() is a name which is hashed to an integer internally and then > the integer is used in place of the name. > > Caveats: > > * string()'s are easy to manipulate with a lot of functions, but their > memory imprint is large. This makes them unsuitable for storing large > amounts of data as strings, if that data is in-memory. They are usually > fine for smaller things, and chunked flow however. > * binary() data has problems if you reference subbinaries and those keep > the underlying binary around. This is where `binary:copy/1` comes into the > game. The general binary handling documentation in the performance guide > linked here has the details of binaries, subbinaries, heap binaries and > match contexts. > * atom()'s have very fast equality checks. But the atom table is limited > in size, you you can't have a program which dynamically creates new atoms. > In many cases however, creating a mapping from external data to internal > atoms yields very efficient programs. > > The general rule from my blog post still holds true to this day: it is > often better to internalize external data into a symbolic format. A > language such as Erlang is efficient when it operates on symbolic data: > > intern(<<"fnord">>) -> {ok, fnord}; > intern(<<"frobnificatization">>) -> {ok, frobnificatization}; > intern(Unknown) -> {error, {cannot_intern, Unknown}}. > > i(X) -> > {ok, A} = intern(X), > A. > > and so on. Of course, if the string is truly a random string of > information for humans to read, you can't parse it, but have to lug it > around as satellite data in your application. And then the size caveat of > string()'s has to be taken into account for some programs which keep a > large set of data in-memory. > > (Note: This is without discussing the problem of handling unicode data, > which other people covered well already) > > -- > J. > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From erlang@REDACTED Wed Aug 19 11:50:09 2015 From: erlang@REDACTED (Joe Armstrong) Date: Wed, 19 Aug 2015 11:50:09 +0200 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <2A5408F7-968F-4A0A-AEA5-0BD6BEF33F9F@gmail.com> References: <2A5408F7-968F-4A0A-AEA5-0BD6BEF33F9F@gmail.com> Message-ID: On Wed, Aug 19, 2015 at 1:39 AM, Steve Davis wrote: > Hi Roelof, > > Here you go: > > 1> [[{sorted, lists:sort(X)}, {count, length(X)}] || X <- > [inet:module_info(exports)]]. > ... > 2> [get_rc/0]. > ** exception error: an error occurred when evaluating an arithmetic > expression > in operator '/'/2 > called as get_rc / 0 > > What the book/lesson is trying to teach is probably not how to do basic > operations on lists (which is notionally the point of the exercise). It?s > actually trying to get you to reach for the right tool to do the job by > getting you to explore the platform libraries and the power of the platform > for yourself. > > Yes, I cheated above and used a comprehension above to present the answers > you want, and also showed what happens when you get what you originally > asked for. Likely you didn?t learn much from that, since what I typed in was > born of spending time with the libraries and knowing what to do with a > problem I?m presented with and understanding what erlang tells you when you > get it ?wrong". > > You need to be patient and find your own solutions to things, since if you > are merely taking others? solutions, you will never become a ?power user?. > It?s a hard slog, I don?t deny that. > > However, the REPL, particularly in your early learning lets you try things > out instantly, and is invaluable help in breaking down a problem. You can > try individual steps extremely easily - and in a way that is simply not > possible with non-functional languages. Yes ^ 100 I still use the REPL a lot when programming. I often try things out in the shell and then when they work cut-and-paste the shell text into my favorite. editor and prettyfy the result. This is the oppose of TDD. TDD says step 1) - write a test case 2) - run the test case 3) - if step 2 fails fix the error 4) - iterate My workflow might be 1) run a test case in the shell 2) if it works cut-and-parse into editor and prettyfy 3) iterate If you're a beginner you should write modules "one function at a time" testing as you go (I do this in all languages) - when you get more experience you can take bigger steps. The "one function at a time" bit is important - when you call a function that you have already written you should be confident that the called function is correct - so errors in the new function should be in the new function and not in the functions you are calling. When I work this way the vast majority of errors are in the function I'm currently writing. My advice is "think top down" - program "bottom up" write small functions first and build on them but have a clear idea in you head where you are going. Try and think out your entire program before writing it and do experiments where your understanding is unclear. The best way to be an efficient programmer is not to write any code at all if you think through an algorithm and realise it won't work then you save yourself a heck of a lot of time programming. Like most creative art forms programming is about seeing the world in a particular way, an artist stares at a scene for hours wondering how to represent it. A photographer plans there next photo. A programmer thinks about their problem for a long time wondering how to represent it. An guess what - tools (fancy editors, IDEs and the like) don't help thinking - they do help the mechanics of entering the code (just like power tools help a carpenter) but they don't *invent* algorithms, and they don't slve problems. Programming is a craft that takes years to get good at and it's not easy - that's why it's fun. Things that are easy are no challenge .... > > If it?s any help or encouragement, it took me months to ?grok? erlang and > its unfamiliar ways, but once I had, I realized what I was missing. Each > day, even after a few years, I learn something new and positive about the > platform. It?s also been an empowerment in my relationship to computers; I > can express concepts that would be essentially intractable in many popular > languages. I know the feeling - things that are obvious are surprisingly unobvious until somebody points them out > > I wish you well in your journey (one that I have personally experienced) and > offer the thought that it?s likely more rewarding, and more empowering in > the long term, to sit with a problem, read the documentation that comes with > Erlang (which is extremely good despite its many critics) and *find your own > solution* than to look outside for help too quickly. > > Sure if you get totally stuck, there?s help here. And if nothing else you can read long rambling discussions on how to program :-) > > I can promise you that the long path and all the hard work to becoming an > ?erlang ninja? will be worth every second. Well perhaps not every second - but the reward for hours of struggleing with mal-placed commas and swearing over the inadequacy of error message are flashes of insight. T.S.Eliot had a nice line ... or music heard so deeply That it is not heard at all, but you are the music While the music lasts He was really talking about programming - you are the computer while you are programming - this is called "flow" When flow happens hours pass in seconds and your programs will just work. Flow does not happen in open plan offices, nor while programmjng node.js Have a nice day /Joe > > /s > > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > From zxq9@REDACTED Wed Aug 19 12:04:44 2015 From: zxq9@REDACTED (zxq9) Date: Wed, 19 Aug 2015 19:04:44 +0900 Subject: [erlang-questions] strings vs binaries In-Reply-To: References: Message-ID: <1624114.0AcgWo10uL@changa> On 2015?8?19? ??? 10:44:20 Robert Virding wrote: > Someone did some benchmarking on this a few years ago to compare the speed > of using binary utf-8 encoded strings vs list strings. They arrived at the > for them surprising result that using list strings was actually faster. It > is actually not surprising if you think about it. So what Richard says > definitely very relevant: > > Always, you need to ask "What am I going to do with this?" With this in mind... If the Erlang program is an application service sitting between a data store of some sort on one side and a constellation of client applications on the other, then most of what is happening isn't string manipulation, but shuttling data between the two. It is incidental that much of this data happens to often be textual in the context of social and business application (but that's not a rule). In this case who cares what it is? It doesn't need to be inspected and it all remains binary. The protocols involved in this case are often textual and its somewhat rare to find a textual protocol that isn't 100% ASCII. Erlang makes parsing/consuming a textual ASCII protocol using binary syntax almost identical to parsing/consuming a binary protocol -- which feels pretty amazing if you've tried doing both in other environments before (sure its not usually super hard in C, but with binary syntax (or even string matches) in Erlang its just "write the protocol format out as matches" and you're done, unless the protocol sucks). If, however, we need to do anything at all interesting with the text that is coming in -- looking for matches on textual keys, for example, identifying a delimiter and splitting on it, complying with some new government contract that mandates a keyword check (sadly, not a joke), then passing part of the result around, filtering, etc. then it is, in my experience, *much* easier to take the received utf8 binary, convert it once to a string on receipt, and deal with it in those terms for the life of the procedure. Going out again, of course, iolists can accept binaries and strings, and you can write a string literal as a binary literal with no issue if you like. So you can let your binary and list results converge again at your output functions -- which is once again an extremely convenient detail someone was thoughtful enough to include in Erlang. I've never measured the performance of the output functions over different types of iolist data, so I have no idea how this plays out. Fortunately, I just haven't experienced such a performance bottleneck where worry over this detail was ever warranted -- but I imagine passing deep lists to format functions, at least, might be expensive(ish), even if it seems to be pretty lightweight to pass ugly deep lists to a socket. Sadly, neither approach is perfect for all cases. (But we can dream of a day...) -Craig From jesper.louis.andersen@REDACTED Wed Aug 19 12:27:38 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Wed, 19 Aug 2015 12:27:38 +0200 Subject: [erlang-questions] strings vs binaries In-Reply-To: References: Message-ID: On Wed, Aug 19, 2015 at 11:44 AM, Robert Virding wrote: > Someone did some benchmarking on this a few years ago to compare the speed > of using binary utf-8 encoded strings vs list strings. They arrived at the > for them surprising result that using list strings was actually faster. Indeed, the speed characteristics is a complex affair involving CPU types, caches, workload, how data is passed around and so on. What I am specifically trying to warn about is the memory imprint, which is much greater for string() types. -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Wed Aug 19 13:10:00 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Wed, 19 Aug 2015 13:10:00 +0200 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <1F93E56C-843F-44A6-98A5-35FEF0A6B073@cs.otago.ac.nz> References: <55D375CF.1000701@home.nl> <1F93E56C-843F-44A6-98A5-35FEF0A6B073@cs.otago.ac.nz> Message-ID: <55D46408.3000407@home.nl> Op 19-8-2015 om 4:57 schreef Richard A. O'Keefe: > On 19/08/2015, at 6:13 am, Roelof Wobben wrote: > >> Hello, >> >> Im still trying to solve exercise 2 of chapter 8 of Programming erlang. >> >> Now I succeed in finding all functions that are exported by a module. >> >> I see now this output : >> >> [{get_rc,0}, {close,1}, {peername,1}, {setpeername,2}, {peernames,...}, {...}|...], [{module,2},{module_info,0},{module_info,1}], [{new,0},{is_set,1},{size,...},{...}|...], [{server,3},{interfaces,...},{...}|...], [{init_it,...},{...}|...], [{...}|...], [...]|...] >> >> So I have list which are containing more list which contains one of more tuples >> >> Is it possible to convert this to for example [get_rc/0, peername/1, peernames/? , module/2 ] > There is no get_rc/0 data structure. > When you have F/N in a declaration, it is converted to {F,N}. > [{get_rc,0}, {peername,1}, ...] is as close as you are going to get. > >> I need the nice output because I have to sort them and then count them. > No you don't. > You can sort a list of tuples. > 1> lists:sort([{c,3},{a,2},{b,4},{a,1},{c,2}]). > [{a,1},{a,2},{b,4},{c,2},{c,3}] > > Given a sorted list, > > sorted_list_unique_count(L) -> > sorted_list_unique_count(L, 0). > > sorted_list_unique_count([X|Xs=[X|_]], N) -> % duplicate > sorted_list_unique_count(Xs, N); > sorted_list_unique_count([_|Xs], N) -> % non-duplicate > sorted_list_unique_count(Xs, N+1); > sorted_list_unique_count([], N) -> > N. > > You can print such a list prettily if you want: > > format_functor_list(Fs) -> > format_functor_list(Fs, ""). > > format_functor_list([{F,N}|Fs], Sep) -> > io:format("~s~w/~w", [Sep, F,N]), > format_functor_list(Fs, ", "); > format_functor_list([], _) -> > ok. > > > > Still my question stands. How do I get a nice list of the ourcome of the exports of the functions ot more then 1 module. I now have a list of list of tuples where every list is the outcome of 1 module. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From essen@REDACTED Wed Aug 19 13:44:23 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Wed, 19 Aug 2015 13:44:23 +0200 Subject: [erlang-questions] strings vs binaries In-Reply-To: <1624114.0AcgWo10uL@changa> References: <1624114.0AcgWo10uL@changa> Message-ID: <55D46C17.2040009@ninenines.eu> On 08/19/2015 12:04 PM, zxq9 wrote: > Going out again, of course, iolists can accept binaries and strings That's actually incorrect. iolist() does not include string() in the types it allows. The type is: iolist() :: maybe_improper_list(byte() | binary() | iolist(), binary() | []) If you have a string() that only has 0..255 characters, then it will work; but this is incidental. A Unicode string inside an iolist() will not work. So if you convert a binary to Unicode string to do manipulation, you have to *convert it back*. The fact that strings are faster is not very interesting considering the amount of conversion you have to do and the extra memory you end up using. That, and you can just send your binary to the i18n library and let it handle things anyway: i18n_string:from_utf8(Bin) That's assuming you use the i18n library, but if you're going to do anything with Unicode that's pretty much the only good choice. Cheers, -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From zxq9@REDACTED Wed Aug 19 13:44:47 2015 From: zxq9@REDACTED (zxq9) Date: Wed, 19 Aug 2015 20:44:47 +0900 Subject: [erlang-questions] strings vs binaries In-Reply-To: References: Message-ID: <3406736.oPxRf7zuh5@changa> On 2015?8?19? ??? 12:27:38 Jesper Louis Andersen wrote: > On Wed, Aug 19, 2015 at 11:44 AM, Robert Virding wrote: > > > Someone did some benchmarking on this a few years ago to compare the speed > > of using binary utf-8 encoded strings vs list strings. They arrived at the > > for them surprising result that using list strings was actually faster. > > > Indeed, the speed characteristics is a complex affair involving CPU types, > caches, workload, how data is passed around and so on. What I am > specifically trying to warn about is the memory imprint, which is much > greater for string() types. Separate from the memory issues that can sneak up on you when dealing with binaries (especially the bit you mentioned about references to segments of a large one in memory) is the number of CPU cycles required to identify and assemble individual characters from utf-8 binaries. The space/time tradeoff can speak heavily here, depending on the nature of the work to be done. Dealing with utf-8 strings that have already been identified and set into a list of discrete character values amortizes that part of the work (it is essentially a tokenization task, though not as staightforward as lexing is usually made to be). Compared to ASCII values where this entire task doesn't even exist, it is not difficult to imagine that in many (but by no means all) tasks strings would be considerably faster to deal with than raw utf-8 binaries. That's not even touching the bazillion different unicode categorization shortcuts ("match on a character that is like an 'x', regardless what accents or stacks of modifiers it has" or even "match on an assembled glyph that includes an 'x', or a complete character that would be an equivalent match", and so on). It is amazing to me that we have unicode and that usable implementations exist at all. Seriously, WOW! But it is by no means simple or easy. -Craig From zxq9@REDACTED Wed Aug 19 14:04:17 2015 From: zxq9@REDACTED (zxq9) Date: Wed, 19 Aug 2015 21:04:17 +0900 Subject: [erlang-questions] strings vs binaries In-Reply-To: <55D46C17.2040009@ninenines.eu> References: <1624114.0AcgWo10uL@changa> <55D46C17.2040009@ninenines.eu> Message-ID: <2511203.POo60EQRpN@changa> On 2015?8?19? ??? 13:44:23 you wrote: > On 08/19/2015 12:04 PM, zxq9 wrote: > > Going out again, of course, iolists can accept binaries and strings > > That's actually incorrect. iolist() does not include string() in the > types it allows. The type is: > > iolist() :: maybe_improper_list(byte() | binary() | iolist(), binary() | []) > > If you have a string() that only has 0..255 characters, then it will > work; but this is incidental. A Unicode string inside an iolist() will > not work. > > So if you convert a binary to Unicode string to do manipulation, you > have to *convert it back*. > > The fact that strings are faster is not very interesting considering the > amount of conversion you have to do and the extra memory you end up > using. That, and you can just send your binary to the i18n library and > let it handle things anyway: > > i18n_string:from_utf8(Bin) > > That's assuming you use the i18n library, but if you're going to do > anything with Unicode that's pretty much the only good choice. Most of the time I'm either putting something out through a socket, using io_lib:format, io:format, or doing something between `unicode:characters_to_list(Data, utf8)` and `unicode:characters_to_binary(UTF8_data, utf8)` (this last typically when dealing with files). So far I haven't run into any cases where having a utf8 binary or a utf8 string has caused problems in a deep list with these functions. Where will it break? (I really want to know, since I could easily run into something that will just suddenly break at some point!) For example: 1> io:format("~ts~n", [[["??","??"],"So why is this working?",<<"??"/utf8>>]]). ????So why is this working??? ok There are certainly functions that operate on strings that won't work on such a list, but I don't know that I've run into any places that say they accept iolist() and won't accept that. But I'm really curious to know what won't work. -Craig PS: Luckily it remains the case that performance (memory, aside from leaks, and generally processing speed) simply has never been a real issue for us, so whatever overhead is being incurred is richly paid back in savings in coding time not panicking about every form of input. But we're not webscale coolguys -- just solving business problems at roughly the lowest scale of aggregation possible. From kennethlakin@REDACTED Wed Aug 19 14:05:16 2015 From: kennethlakin@REDACTED (Kenneth Lakin) Date: Wed, 19 Aug 2015 05:05:16 -0700 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <55D46408.3000407@home.nl> References: <55D375CF.1000701@home.nl> <1F93E56C-843F-44A6-98A5-35FEF0A6B073@cs.otago.ac.nz> <55D46408.3000407@home.nl> Message-ID: <55D470FC.1060104@gmail.com> On 08/19/2015 04:10 AM, Roelof Wobben wrote: > Still my question stands. How do I get a nice list of the ourcome of the > exports of the functions ot more then 1 module. Richard O'Keefe demonstrated that lists:sort/1 will -when given a list of tuples- sort that list. He also presented code that will -when given a sorted list of tuples- give you a count of the number of distinct elements in that list. He *also* presented code that will -when given a list of tuples of the form {fun, arity}- pretty print them in just the way that you appear to require. Does your project require more than this? :) Here's a bit of unasked-for advice from an old guy who's been programming for way too long. It is sometimes helpful to step away from your code and your desk, go somewhere else and carefully restate -in a human language- the problem that you're trying to solve. When doing this, I find it helpful to entirely forget about the code I have written. It's easy to assume that the code that you've already written solves the problem you intend to solve. If you're not sure that you're on the right track, it's good to make as few assumptions as possible when verifying your current course. I've worked myself into a state of confusion in which I have lost the understanding of the problem I'm trying to solve more times than I care to admit. In most of those cases, stepping away and re-familiarizing myself with the problem at hand dispelled the confusion. Another piece of unasked-for advice: If I recall correctly, you mentioned that you're teaching yourself Erlang. If this is true, then you probably don't have any hard deadlines to contend with. Take time to peruse manuals and read user's guides. Take time to play around with code in the Erlang shell. Take time to play with code that folks hand you in response to your queries. I learn non-rote things best when I'm not stressed out and I allow myself to play around and experiment. Perhaps I'm atypical. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From r.wobben@REDACTED Wed Aug 19 14:13:42 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Wed, 19 Aug 2015 14:13:42 +0200 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <55D470FC.1060104@gmail.com> References: <55D375CF.1000701@home.nl> <1F93E56C-843F-44A6-98A5-35FEF0A6B073@cs.otago.ac.nz> <55D46408.3000407@home.nl> <55D470FC.1060104@gmail.com> Message-ID: <55D472F6.2010100@home.nl> An HTML attachment was scrubbed... URL: From bengt.kleberg@REDACTED Wed Aug 19 14:16:28 2015 From: bengt.kleberg@REDACTED (Bengt Kleberg) Date: Wed, 19 Aug 2015 14:16:28 +0200 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <55D472F6.2010100@home.nl> References: <55D375CF.1000701@home.nl> <1F93E56C-843F-44A6-98A5-35FEF0A6B073@cs.otago.ac.nz> <55D46408.3000407@home.nl> <55D470FC.1060104@gmail.com> <55D472F6.2010100@home.nl> Message-ID: <55D4739C.6080305@ericsson.com> Greetings, Please read the documentation for the lists module, http://www.erlang.org/doc/man/lists.html It has many useful functions for handling lists. bengt On 08/19/2015 02:13 PM, Roelof Wobben wrote: > oke, but I do not have a list of tuples but a list of lists that > contain tuples, > > So I have this [ [ {1,2}, {2,3}], [ { 1,3} , { 2,1} ] ] > > and I do experiment a lot in erl but I seem to be lost. > > Roelof > > > Op 19-8-2015 om 14:05 schreef Kenneth Lakin: >> On 08/19/2015 04:10 AM, Roelof Wobben wrote: >>> Still my question stands. How do I get a nice list of the ourcome of the >>> exports of the functions ot more then 1 module. >> Richard O'Keefe demonstrated that lists:sort/1 will -when given a list >> of tuples- sort that list. He also presented code that will -when given >> a sorted list of tuples- give you a count of the number of distinct >> elements in that list. He *also* presented code that will -when given a >> list of tuples of the form {fun, arity}- pretty print them in just the >> way that you appear to require. >> >> Does your project require more than this? :) >> >> Here's a bit of unasked-for advice from an old guy who's been >> programming for way too long. >> >> It is sometimes helpful to step away from your code and your desk, go >> somewhere else and carefully restate -in a human language- the problem >> that you're trying to solve. When doing this, I find it helpful to >> entirely forget about the code I have written. It's easy to assume that >> the code that you've already written solves the problem you intend to >> solve. If you're not sure that you're on the right track, it's good to >> make as few assumptions as possible when verifying your current course. >> >> I've worked myself into a state of confusion in which I have lost the >> understanding of the problem I'm trying to solve more times than I care >> to admit. In most of those cases, stepping away and re-familiarizing >> myself with the problem at hand dispelled the confusion. >> >> Another piece of unasked-for advice: If I recall correctly, you >> mentioned that you're teaching yourself Erlang. If this is true, then >> you probably don't have any hard deadlines to contend with. Take time to >> peruse manuals and read user's guides. Take time to play around with >> code in the Erlang shell. Take time to play with code that folks hand >> you in response to your queries. >> >> I learn non-rote things best when I'm not stressed out and I allow >> myself to play around and experiment. Perhaps I'm atypical. >> >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > > > ------------------------------------------------------------------------ > Avast logo > > Dit e-mailbericht is gecontroleerd op virussen met Avast > antivirussoftware. > www.avast.com > > > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- An HTML attachment was scrubbed... URL: From essen@REDACTED Wed Aug 19 14:20:36 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Wed, 19 Aug 2015 14:20:36 +0200 Subject: [erlang-questions] strings vs binaries In-Reply-To: <2511203.POo60EQRpN@changa> References: <1624114.0AcgWo10uL@changa> <55D46C17.2040009@ninenines.eu> <2511203.POo60EQRpN@changa> Message-ID: <55D47494.2030307@ninenines.eu> On 08/19/2015 02:04 PM, zxq9 wrote: > For example: > > 1> io:format("~ts~n", [[["??","??"],"So why is this working?",<<"??"/utf8>>]]). > ????So why is this working??? > ok I'm not sure how ~ts works but since it's not expecting iolist() I'm only half surprised. Here's one though: 1> file:write_file("/tmp/test.txt", [["??","??"],"So why is this working?",<<"??"/utf8>>]). {error,badarg} 2> file:write_file("/tmp/test.txt", ["So why is this working?",<<"? ?"/utf8>>]). ok Here's another: 3> {ok, S} = gen_tcp:connect("google.com", 80, []). {ok,#Port<0.548>} 4> gen_tcp:send(S, [["??","??"],"So why is this working?",<<"? ?"/utf8>>]). {error,einval} 5> =ERROR REPORT==== 19-Aug-2015::14:19:52 === Bad value on output port 'tcp_inet' 5> gen_tcp:send(S, ["So why is this working?",<<"??"/utf8>>]). ok Cheers, -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From kennethlakin@REDACTED Wed Aug 19 14:23:20 2015 From: kennethlakin@REDACTED (Kenneth Lakin) Date: Wed, 19 Aug 2015 05:23:20 -0700 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <55D472F6.2010100@home.nl> References: <55D375CF.1000701@home.nl> <1F93E56C-843F-44A6-98A5-35FEF0A6B073@cs.otago.ac.nz> <55D46408.3000407@home.nl> <55D470FC.1060104@gmail.com> <55D472F6.2010100@home.nl> Message-ID: <55D47538.6030000@gmail.com> On 08/19/2015 05:13 AM, Roelof Wobben wrote: > oke, but I do not have a list of tuples but a list of lists If you have a list of lists, you have several options. This http://www.erlang.org/doc/man/lists.html#foreach-2 is probably what you want. (BTW, *do* take some time to skim the functions available in the lists module and their descriptions.) You can also write functions that have the pattern fun([]) -> ok; fun([H|T]) -> %Stuff fun(T). to deal with lists of lists. Wasn't this already covered in your study material? If it wasn't even mentioned in passing, it's a little disturbing that your exercise requires you to work with lists of lists, but didn't present the knowledge required to handle them. Anyway. All the best, man. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From hugo@REDACTED Wed Aug 19 14:46:10 2015 From: hugo@REDACTED (Hugo Mills) Date: Wed, 19 Aug 2015 12:46:10 +0000 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <55D47538.6030000@gmail.com> References: <55D375CF.1000701@home.nl> <1F93E56C-843F-44A6-98A5-35FEF0A6B073@cs.otago.ac.nz> <55D46408.3000407@home.nl> <55D470FC.1060104@gmail.com> <55D472F6.2010100@home.nl> <55D47538.6030000@gmail.com> Message-ID: <20150819124610.GY12976@carfax.org.uk> On Wed, Aug 19, 2015 at 05:23:20AM -0700, Kenneth Lakin wrote: > On 08/19/2015 05:13 AM, Roelof Wobben wrote: > > oke, but I do not have a list of tuples but a list of lists > > If you have a list of lists, you have several options. This > http://www.erlang.org/doc/man/lists.html#foreach-2 is probably what you > want. (BTW, *do* take some time to skim the functions available in the > lists module and their descriptions.) Just to reinforce Kenneth's last comment here, reading and searching the documentation to find functions is a fairly important piece of learning. It's tedious, but it's not going to be wasted time. Very few people carry round in their heads all of the functions of even the most common modules (like lists). Nobody will have the whole erlang API in their head. So it's normal, when writing code, to spend time reading or searching through every function description that even vaguely looks like it might do what you want. The time taken in this exercise will decrease as you get more used to the language, and as you become familiar with the most often used functions, but there's no good substitute for the tedious business of trudging through the docs. In fact, for your specific problem here, I would *strongly* recommend doing that for the lists module, as you'll find the answer to your list-of-lists problem almost immediately. :) (And yes, I did know about the function in question... but I had forgotten it was called that until I went to read the docs). When reading the docs like this, even if you don't find the function you're looking for, it isn't wasted time, because you might just see a function that you find you need tomorrow -- and then you know where to find it. Or even just know that the function exists, which is at least half of the battle. I'd suggest that modules you should at least read through the whole documentation for are: io, io_lib, lists, orddict or dict (very similar APIs), proplists, and string. That will give you a good idea of what's possible, and maybe where to find it. Hugo. -- Hugo Mills | Q: What goes, "Pieces of seven! Pieces of seven!"? hugo@REDACTED carfax.org.uk | A: A parroty error. http://carfax.org.uk/ | PGP: E2AB1DE4 | -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: From zxq9@REDACTED Wed Aug 19 14:36:00 2015 From: zxq9@REDACTED (zxq9) Date: Wed, 19 Aug 2015 21:36 +0900 Subject: [erlang-questions] strings vs binaries In-Reply-To: <55D47494.2030307@ninenines.eu> References: <2511203.POo60EQRpN@changa> <55D47494.2030307@ninenines.eu> Message-ID: <2092484.IRXyZJ1j4d@changa> On 2015?8?19? ??? 14:20:36 you wrote: > On 08/19/2015 02:04 PM, zxq9 wrote: > > For example: > > > > 1> io:format("~ts~n", [[["??","??"],"So why is this working?",<<"??"/utf8>>]]). > > ????So why is this working??? > > ok > > I'm not sure how ~ts works but since it's not expecting iolist() I'm > only half surprised. > > Here's one though: > > 1> file:write_file("/tmp/test.txt", [["??","??"],"So why is this > working?",<<"??"/utf8>>]). > {error,badarg} > 2> file:write_file("/tmp/test.txt", ["So why is this working?",<<"? > ?"/utf8>>]). > ok > > Here's another: > > 3> {ok, S} = gen_tcp:connect("google.com", 80, []). > {ok,#Port<0.548>} > 4> gen_tcp:send(S, [["??","??"],"So why is this working?",<<"? > ?"/utf8>>]). > {error,einval} > 5> > =ERROR REPORT==== 19-Aug-2015::14:19:52 === > Bad value on output port 'tcp_inet' > 5> gen_tcp:send(S, ["So why is this working?",<<"??"/utf8>>]). > ok Ah, and that makes perfect sense. We have a function, zfile:write/2 where `zfile:write(File, Data)` expands in this case to: file:write_file("foo.txt", unicode:characters_to_binary([[["??","??"],"So why is this working?",<<"??"/utf8>>]], utf8)). And this works just fine. There are similar wrappers for sockets in some places. So the really magic functions aren't the output ones; we've wrapped them in the actually magical unicode:characters_to_binary/2, which appears to be capable of chewing through anything. This works well enough that I've not looked at the code in this module in at least a year and forgot this stuff was there! Thanks for pointing that out, I could have tripped myself on this, not to mention putting out wrong poop on the ML and tripping up others. :-) -Craig From mononcqc@REDACTED Wed Aug 19 15:48:44 2015 From: mononcqc@REDACTED (Fred Hebert) Date: Wed, 19 Aug 2015 09:48:44 -0400 Subject: [erlang-questions] strings vs binaries In-Reply-To: <1624114.0AcgWo10uL@changa> References: <1624114.0AcgWo10uL@changa> Message-ID: <20150819134842.GH24333@fhebert-ltm1> On 08/19, zxq9 wrote: >The protocols involved in this case are often textual and its somewhat >rare to find a textual protocol that isn't 100% ASCII. This is less and less true and I wouldn't count on it for long. Hell for the sake of the argument, I'd say almost no protocol is 100% ASCII anymore. Just think of all the protocols that include some form of JSON or XML; they most likely require unicode by specification or default. HTTP has mostly ASCII header names, but if I recall, header values (other than those in the RFC) have their encoding unspecified and people will stick unicode stuff in there. But most stuff in protocols that piggyback over HTTP ends up being in the payloads, where again, JSON or XML are common. Then think of other protocols: they may use a binary format that is nice to work with (in Erlang) than most text protocols: the lengths are known (and hopefully specified in bytes, not characters), values are tagged, and so on. You get candidates like Thrift (expects utf8 by default in strings iirc), protocol buffers (lets you define types), BERT (has binaries and lists, so undefined), BSON (strings are utf8), etc. Even in most of these, unicode encodings are very common. Now you may get away with not caring about encoding for a while, but it does not mean you're implementing the protocol correctly or that it will never happen. DNS is a fun example where yes, the protocol is ASCII only, but they ended up having to put in place IDNA encoding (punycode) to allow unicode through. The days of ASCII-only are almost over*, and the sun is setting really fast. There's just too many languages and cultures out there to want to be held back by ASCII. * of course there are legacy systems that nothing will kill or bring forward in time, but what can you do. From zxq9@REDACTED Wed Aug 19 16:17:47 2015 From: zxq9@REDACTED (zxq9) Date: Wed, 19 Aug 2015 23:17:47 +0900 Subject: [erlang-questions] strings vs binaries In-Reply-To: <20150819134842.GH24333@fhebert-ltm1> References: <1624114.0AcgWo10uL@changa> <20150819134842.GH24333@fhebert-ltm1> Message-ID: <1789109.ZDeuxgheFV@changa> On 2015?8?19? ??? 09:48:44 you wrote: > On 08/19, zxq9 wrote: > >The protocols involved in this case are often textual and its somewhat > >rare to find a textual protocol that isn't 100% ASCII. > > This is less and less true and I wouldn't count on it for long. Hell for > the sake of the argument, I'd say almost no protocol is 100% ASCII > anymore. Speaking strictly from my own experience in Asia, which is by no means representative of what may be going on elsewhere... This is universally true if you include the payloads as part of the protocol, but generally speaking, while the encoding is nearly always unicode, the control tokens of text-based protocols are nearly always ASCII. The payloads, at least in most of the cases I've dealt with, tend to get routed through in a mannger based on the ASCII/binary (sometimes a mix) protocol tags that preceed it. Or ASN.1, which is particularly easy to deal with anywhere an ASN1 compiler is available (which is still most environments, it seems). Even in Japan and Korea I've yet to see a custom protocol that did not adhere to this. So you may see the basic equivalent of <<"FETCH", " ", "some.obj.type", " ", PayloadSize:8, Payload:PayloadSize, Blah/binary>> The command token, the spaces, and the object type identifier will rarely be anything but ASCII, though this is occasionally not true for the object type id (which is more often an integer than some random utf8 named string). But in any case, you're right. The future is now, and it is whatever we make of it. Many are making an arbitrary linguistic stew of it. And we have to keep in mind that there is actually nothing wrong with that. -Craig From erlang@REDACTED Wed Aug 19 17:22:07 2015 From: erlang@REDACTED (Joe Armstrong) Date: Wed, 19 Aug 2015 17:22:07 +0200 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <55D46408.3000407@home.nl> References: <55D375CF.1000701@home.nl> <1F93E56C-843F-44A6-98A5-35FEF0A6B073@cs.otago.ac.nz> <55D46408.3000407@home.nl> Message-ID: On Wed, Aug 19, 2015 at 1:10 PM, Roelof Wobben wrote: > Op 19-8-2015 om 4:57 schreef Richard A. O'Keefe: > >> On 19/08/2015, at 6:13 am, Roelof Wobben wrote: >> >>> Hello, >>> >>> Im still trying to solve exercise 2 of chapter 8 of Programming erlang. >>> >>> Now I succeed in finding all functions that are exported by a module. >>> >>> I see now this output : >>> >>> [{get_rc,0}, {close,1}, {peername,1}, {setpeername,2}, {peernames,...}, >>> {...}|...], [{module,2},{module_info,0},{module_info,1}], >>> [{new,0},{is_set,1},{size,...},{...}|...], >>> [{server,3},{interfaces,...},{...}|...], [{init_it,...},{...}|...], >>> [{...}|...], [...]|...] >>> >>> So I have list which are containing more list which contains one of more >>> tuples >>> >>> Is it possible to convert this to for example [get_rc/0, peername/1, >>> peernames/? , module/2 ] >> >> There is no get_rc/0 data structure. >> When you have F/N in a declaration, it is converted to {F,N}. >> [{get_rc,0}, {peername,1}, ...] is as close as you are going to get. >> >>> I need the nice output because I have to sort them and then count them. >> >> No you don't. >> You can sort a list of tuples. >> 1> lists:sort([{c,3},{a,2},{b,4},{a,1},{c,2}]). >> [{a,1},{a,2},{b,4},{c,2},{c,3}] >> >> Given a sorted list, >> >> sorted_list_unique_count(L) -> >> sorted_list_unique_count(L, 0). >> >> sorted_list_unique_count([X|Xs=[X|_]], N) -> % duplicate >> sorted_list_unique_count(Xs, N); >> sorted_list_unique_count([_|Xs], N) -> % non-duplicate >> sorted_list_unique_count(Xs, N+1); >> sorted_list_unique_count([], N) -> >> N. >> >> You can print such a list prettily if you want: >> >> format_functor_list(Fs) -> >> format_functor_list(Fs, ""). >> >> format_functor_list([{F,N}|Fs], Sep) -> >> io:format("~s~w/~w", [Sep, F,N]), >> format_functor_list(Fs, ", "); >> format_functor_list([], _) -> >> ok. >> >> >> >> > > Still my question stands. How do I get a nice list of the ourcome of the > exports of the functions ot more then 1 module. Deep breath - long answer coming up ... Your original question said: >>> Is it possible to convert this to for example [get_rc/0, peername/1, >>> peernames/? , module/2 ] The answer is NO since [get_rc/0, peername/1, ...] etc is not a valid Erlang term (this is possibly badly explained, something like [foo/1,bar/2] is a syntactic form that can occur in Erlang programs (for example -import([foo/1,bar/2])) but it is not in itself a valid Erlang term. An Erlang term is something that an Erlang function can return. Terms are very simple, they are atomic (things like integers, floats, atoms, pids etc) or they are composed using a tuple or list constructor. A function *cannot* return [foo/1, bar/2] since it is not a valid Erlang term. So you have to make a design decision do you want to return ["foo/1", "bar/1"] which *is* an Erlang term, or "foo/1, bar/1" which is also an Erlang term. Let's assume the former and write module with a single test case: -module(t1). -compile(export_all). test() -> ["bar/1", "foo/1"] = f1([{bar,1}, {foo,1}]), horray. Now we have to write f1 f1(L) -> [atom_to_list(Name) ++ "/" ++ integer_to_list(Int) || {Name, Int} <- L]. Add this to the module compile and run: $ erl Eshell V6.2 (abort with ^G) 1> c(t1). {ok,t1} 2> t1:test(). horray 3> Now *extend the test case* test() -> ["bar/1", "foo/1"] = f1([{bar,1}, {foo,1}]), ["bar/1", "foo/1"] = f1([{foo,1}, {bar,1}]), horray. Compile and run 3> c(t1). {ok,t1} 4> t1:test(). ** exception error: no match of right hand side value ["foo/1","bar/1"] in function t1:test/0 (t1.erl, line 6) perhaps we need to sort the inputs? This is called test driven development (TDD) write a test case, make it work, write the next test case, and so on. The *problem* with you original question was that it was imprecise. Words like "nice list" don't really mean much. In this forum you'll often see questions that remain unanswered. One reason for this is that often the person who write the question thinks the question is precise but in fact it's so vague that nobody can answer, and then indeed nobody does answer. On other occasions you see very long answers and threads arising from vague questions, firstly because the question provides an opportunity to explain some things that might not be obvious, secondly because Mr Google will remember the answer forever, so hopefully one day some person will ask Mr Google the same of similar question and find the answer buried in the archives of this mailing list. I'd hazard a guess that a large fraction of all beginners Erlang questions can be found by Googling this list - you'll even find the best ever explanation of rounding errors in performing floating point operations written by one of our Antipodean friends ... Cheers /Joe > I now have a list of list of tuples where every list is the outcome of 1 > module. > > Roelof > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From vladdu55@REDACTED Wed Aug 19 18:54:12 2015 From: vladdu55@REDACTED (Vlad Dumitrescu) Date: Wed, 19 Aug 2015 18:54:12 +0200 Subject: [erlang-questions] erlang logo images Message-ID: Hi! Are the official logo images available nowadays? The old link at erlang.org/promotion doesn't exist anymore. A SVG variant would be nice too (I can't remember if there was any). best regards, Vlad -------------- next part -------------- An HTML attachment was scrubbed... URL: From steven.charles.davis@REDACTED Wed Aug 19 22:00:15 2015 From: steven.charles.davis@REDACTED (Steve Davis) Date: Wed, 19 Aug 2015 15:00:15 -0500 Subject: [erlang-questions] How can I make a list of this In-Reply-To: References: <2A5408F7-968F-4A0A-AEA5-0BD6BEF33F9F@gmail.com> Message-ID: ...and that one throwaway line at the end of your mail contains a startling amount of accumulated wisdom... > Flow does not happen in open plan offices, nor while programmjng node.js From g@REDACTED Wed Aug 19 22:05:45 2015 From: g@REDACTED (Garrett Smith) Date: Wed, 19 Aug 2015 15:05:45 -0500 Subject: [erlang-questions] How can I make a list of this In-Reply-To: References: <2A5408F7-968F-4A0A-AEA5-0BD6BEF33F9F@gmail.com> Message-ID: There's a flow, but more like mudslide, or lava. *Oh snap!* On Wed, Aug 19, 2015 at 3:00 PM, Steve Davis wrote: > ...and that one throwaway line at the end of your mail contains a startling amount of accumulated wisdom... > >> Flow does not happen in open plan offices, nor while programmjng node.js > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From steven.charles.davis@REDACTED Wed Aug 19 22:45:02 2015 From: steven.charles.davis@REDACTED (Steve Davis) Date: Wed, 19 Aug 2015 15:45:02 -0500 Subject: [erlang-questions] strings vs binaries In-Reply-To: <12859255.Ey1zpWod8m@changa> References: <90AD63CD-FEC2-407D-B05B-C70AA43E2D8C@gmail.com> <12859255.Ey1zpWod8m@changa> Message-ID: <4C1CC70F-064C-42F0-BE5F-D166DFAABC03@gmail.com> Hi Craig, Thank you so much for taking the time to explain the issues and to educate my original position. Exploring the ramifications in my own codebase now? probably will take a while! with thanks and regards, Steve > On Aug 18, 2015, at 10:25 PM, zxq9 wrote: > > On 2015?8?18? ??? 19:19:36 you wrote: > >>> On 2015?8?18? ??? 17:47:53 Steve Davis wrote: >>>> In addition to what?s already been said... >>>> >>>> The old chestnut that ?erlang is bad at string manipulation? completely goes away if you choose to use binaries for all your text. >>>> >>>> In fact, erlang is far superior at text tasks than most platforms I have used if you keep all your text as binaries. >> >>> ...unless you need to do it in utf8... >> >> Hi zxq9, >> ?example?? >> ?test case?? >> (Did I miss a post already in history?) >> (Is the example/test case better handled in another platform? if so, which?, and how?) >> Please change my view if it is obviously incorrect. >> Best, >> /s > > Hi, Steve. > > Sure. Let's say you have a string where it is always known that you need to pull some specific segment, characters 3 to 11, for example. When these are ASCII that's marvelously easy with binaries. Not so much when they are utf8 multibyte charcters, though: > > <<"Getting characters from a range within this is easy.">> > > <<"binary??????????????string????????????"/utf8>> > > You will either have to use "(*UTF8)blahblah" regexes everywhere (which is appropriate for some cases, but not nearly enough) or convert those binaries to strings so that you can do the things you expected to be able to do with them easily. > > Quite a few of the split, split on X, split after segment X-Y, etc. type functions don't work the expected way with utf8 in binary form, but do with utf8 strings. > > The lucky thing there is that Erlang's output interfaces (format functions, socket output, etc.) accepts iolists, so it doesn't really matter how messy a cobbled together deep list happens to be before you hand it to them. > > Delimiters also can catch you by surprise -- there are "many" 'kinds' ?of? ?quotes? (and) ?brackets? `in` ?use? and not all are easy to make sense of or fit within a single byte. Spaces are spaces and tabs?are tabs, sure, but?check the spacing in this sentence carefully. Also, many multibyte characters are single width, ????????. > > My region obviously causes me to clash with this issue quite a bit more than seems to be the case with the rest of the Erlang world. That said, there are many tools/environments that make manipulating utf8 much easier than Erlang. > > -Craig From bchesneau@REDACTED Thu Aug 20 05:21:16 2015 From: bchesneau@REDACTED (Benoit Chesneau) Date: Thu, 20 Aug 2015 03:21:16 +0000 Subject: [erlang-questions] gen_tcp:controlling_process/2 impact In-Reply-To: <20150818190226.GA13534@circlewave.net> References: <20150818131223.GA24333@fhebert-ltm1> <20150818190226.GA13534@circlewave.net> Message-ID: Jachym, Fred thanks for your answers :) It helps. To elaborate, my original intention was about maintaining different pools of sockets connections. Each pools would be layered, handling connection and handshaking if needed. Sockets will be bounded late to requester. For example in the SSL case: Process want to open SSL connection ---> ask SSL pool if socket if available --> no socket available => ask tcp pool for an available socket --> no socket available --> connect --> give the socket to the ssl pool --> SSL pool do handshaking if new connected socket --> SSL pool return the socket to the process and give it the control. Depending on the protocol, i could have a pool maintaining its own set of sockets. In that case it means at least 3 control passing (connection job is also asynchronous). I realise it's probably too much anyway. In the case of SSL it's should be possible to ask to the TCP pool to do the final control passing, I guess. But it's probably better to maintain 1 pool / protocol and handle the connection jobs differently to reduce the number of time the control of a socket should be given to a process. I will try to create a branch for both cases and measure. Benoit On Tue, Aug 18, 2015 at 9:07 PM Jachym Holecek wrote: > # Fred Hebert 2015-08-18: > > On 08/18, Benoit Chesneau wrote: > > If the socket is used only for writing, then you don't need to > > change the controlling process, just send the thing directly. Anyone > > can write to a socket, just one process can read. > > > > If you do need to read from it, then the best idea is likely to > > resolve your chain, find the final destination pid, and hand the > > control there. The owner must hand the control, so rather than > > going: > > > > a -- give --> b -- give --> c > > > > go > > > > a -- ask pid --> b -- finds --> c > > a -- give --> c > > Just to give a more elaborate example of what Ferd is saying, from memory: > > accept peer connection > proc server proc > -+---------------+--------------+--------- > | | > o | accept(L) -> S > | | > +---------------> add_connection(S) > | | > | +--------------> spawn(S, ...) > | | | > <------------------------------+ reply(..., self()) > | | | > o | | > controlling_process(S, P) > | | | > +------------------------------> handover_ack > | | | > | | o ready, active true > > In Benoit's case there's more than one intermediary, but the overall > picture > remains essentially the same. > > > which will have a single control-handing form. You can also swap it > > around and let 'b' tell 'c' to "ask a for your port" and then do the > > switch. > > > > Also remember to let the socket in {accept, false} mode so that no > > messages are lost during the whole operation. > > One wants {active, false} here indeed. Let me add, just in case we're > talking > protocol stack implementation, that it may turn out surprisingly convenient > to perform initial session setup with {active, false} using passive recv() > instead (intuitively one might lean towards {active, true} socket run by > a gen_fsm, which may end up nastily overcomplicated). It may also be very > convenient to do initial session setup from a different process (and > different code module) than where fully operational session is handled. > > Not sure this makes an awful lot of sense without context, just reminded > me of something in my previous projects... Nevermind if not. :-) > > Have fun, > -- Jachym > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ok@REDACTED Thu Aug 20 06:42:34 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Thu, 20 Aug 2015 16:42:34 +1200 Subject: [erlang-questions] strings vs binaries In-Reply-To: <8BB0D966-BC4F-4C1E-BAD2-0B01AA14CCD0@vailsys.com> References: <8BB0D966-BC4F-4C1E-BAD2-0B01AA14CCD0@vailsys.com> Message-ID: <7BF74ECC-1E11-4708-9D8D-F478343FABCE@cs.otago.ac.nz> On 19/08/2015, at 8:23 am, Rick Pettit wrote: > Generally speaking, you probably want to use binaries these days as they consume far less memory (at least for ?large? strings): Don't *have* large strings. Seriously. If you are receiving external data in big chunks, and passing it on unchanged, fine, use whatever fits, but even then, the biggest chunk size you can use may not be the _best_ chunk size you can use. If you're dealing with structured (or semistructured) data, a string of any kind is generally a poor choice. I had a nasty experience a couple of days ago, where a program in language X (not Erlang) using the standard regular expression library for language X overflowed the C stack trying to extract information from a measly 1 MiB source, which it read as a conventional packed-array-of- character string. (Why a 64-bit machine with 8GiB of memory has a hard ulimit of 64MiB on stack size, let alone a default soft limit of 8MiB, is beyond me, but that's another story.) Aside from the obvious lessons (don't use X, use a different regexp library, ...) there's a lesson for all of us: +-------------------------------------+ | the memory needed to HOLD your data | | is only a lower bound on the memory | | needed to USE your data. | +-------------------------------------+ From ok@REDACTED Thu Aug 20 07:04:51 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Thu, 20 Aug 2015 17:04:51 +1200 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <55D46408.3000407@home.nl> References: <55D375CF.1000701@home.nl> <1F93E56C-843F-44A6-98A5-35FEF0A6B073@cs.otago.ac.nz> <55D46408.3000407@home.nl> Message-ID: On 19/08/2015, at 11:10 pm, Roelof Wobben wrote: > > Still my question stands. How do I get a nice list of the ourcome of the exports of the functions ot more then 1 module. > I now have a list of list of tuples where every list is the outcome of 1 module. Step 1. Module:module_info() -> [ {exports, List_Of_Exports} , {imports, List_Of_Imports} , {attributes, List_Of_Attributes} , {compile, Information_About_Compiler_Source_And_Options} ... ]. A little familiarity with the standard libraries suggests that if f(Args) returns a list of {Key,Value} pairs then f(Args,Key) might return just the Value you are interested in. Play with it in the shell and discover that it is true. Step 2. Module:module_info(exports) -> a list of {Name,Arity} pairs, just the exports we wanted. Step 3. You already know about list comprehension. You may not realise that you can have more than one generator (Pattern <- List) in a list comprehension and that these operate as nested loops. all_exports(Modules) -> [ {Module,Name,Arity} || Module <- Modules, {Name,Arity} <- Module:module_info(exports) ]. You could try this in the shell: Modules = [orddict, proplists], Triples = [ {Module,Name,Arity} || Module <- Modules, {Name,Arity} <- Module:module_info(exports) ]. Step 4. If you want the list sorted on module, then name within module, then arity within name within module, you can just use lists:sort(Triples). Now suppose we want that listed sorted by Name, then Arity, then Module. You have to write your own comparison function, but that's not hard. Compare = fun ({M1,F,N}, {M2,F,N}) -> M1 =< M2 ; ({_,F,N1}, {_,F,N2}) -> N1 =< N2 ; ({_,F1,_}, {_,F2,_}) -> F1 =< F2 end, lists:sort(Compare, Triples). (try-it-in-the-shell code tested) From ok@REDACTED Thu Aug 20 08:00:02 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Thu, 20 Aug 2015 18:00:02 +1200 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <55D472F6.2010100@home.nl> References: <55D375CF.1000701@home.nl> <1F93E56C-843F-44A6-98A5-35FEF0A6B073@cs.otago.ac.nz> <55D46408.3000407@home.nl> <55D470FC.1060104@gmail.com> <55D472F6.2010100@home.nl> Message-ID: <1E643866-3F7E-45D0-9245-549243921AC3@cs.otago.ac.nz> On 20/08/2015, at 12:13 am, Roelof Wobben wrote: > oke, but I do not have a list of tuples but a list of lists that contain tuples, > > So I have this [ [ {1,2}, {2,3}], [ { 1,3} , { 2,1} ] ] > > and I do experiment a lot in erl but I seem to be lost. Many years ago when I was a teenager I wanted to learn to fly an aeroplane. My father took me to a local aerodrome and had me given lesson 1. It was great. I could *do* this. To get lesson 2, I had to get a student pilot licence. So I had to have a medical examination, ECG, the works. And I was rejected on the grounds that I needed glasses. I'm still upset by that. I had heard of lots of flying accidents caused by people flying in circumstances (low to the ground) or conditions (darkness, clouds) that they were not trained for, in order to show off or at least not to look bad to their companions. I had never heard (and still haven't) of an accident caused by someone's glasses falling off. And there was NO test to probe "which would you prefer? To look like an idiot to your friends, or to put their lives at risk?" Personal application: asking for help on this list about points that seem pretty obvious to the people answering does not make you look impressive. At first sight! To me, it makes you look like someone I *might* trust to fly me. To be brutally honest, I sometimes get the feeling "oh no, not another message from Roelof Wobben", but heck, I'm *paid* to teach people about programming. (OK, so those are *other* people who are enrolled here. But still...) But there's _always_ something to learn from giving a lesson. Let me get to the point. In preparation for the lessons I thought I was going to get, I read a couple of books. In one of them I found this advice: When something goes wrong, DON'T JUST DO SOMETHING, SIT THERE! I've come across basically the same advice in several contexts, including dealing with stroppy lawnmowers. DON'T JUST DO SOMETHING, SIT THERE! What is my present situation? How do I want it to be different? Is the problem that I have the one I thought I had? What I was doing just now was wrong, maybe I should stop doing that. Can I approach this another way? What if I just take it apart, clean the parts, and put them together again (works for lawnmowers but NOT aeroplanes in flight)? Maybe I should take the dog for a walk as a distraction. (If you can do that from an aeroplane in flight you have a very strange dog.) A well known phenomenon is "regression under stress to first learned behaviour". 1. Learn method M1. 2. Learn method M2 which is better in some way. 3. Be put under stress. 4. Be given a task for which M2 is more appropriate. OOPS. We tend to revert to M1. Floundering around lost while programming is stressful, and in such circumstances we *all* tend to revert to the habits we learned earlier. If you learned Lisp then C you'll be trying to emulate #'(LAMBDA (...) ...). If the other way around, you'll be trying to emulate *p++. (I am *so* lucky that C was about the 80th programming language I learned.) Another phenomenon is "mental set". From Wikipedia, " A mental set is a framework for thinking about a problem. It can be shaped by habit or by desire. Mental sets can make it easy to solve a class of problem, but attachment to the wrong mental set can inhibit problem-solving and creativity." That is, we can consciously or *unconsciously* adopt a particular way of approaching a problem and we not only tend to stick with it, we tend to forget that any other way of approaching it might be possible. One of the things we have to do when we get stuck is to try to step back and try to unjam our framework. This actually ties in with the "hypnosis" that Scott Adams (creator of "Dilbert") keeps talking about in his blog, which turns out to be more the Bandler and Grinder "Structure of Magic" stuff. For example, in my country, the Prime Minister is pushing for a change to the flag. A majority of people in the country are either passionately devoted to the flag we have, or don't care about flags one way or another, and would prefer to see the money spent on say health care or child poverty or something. We're going to get two referendums, like it or not. You'd think the first one would be "do you want to change the flag?" and the second would be "which of these designs do you prefer?" But it's going to be the other way around. People were asked to submit designs. Then a panel of so-called experts picked a short list of four. The first referendum is going to ask us which of the four *new* designs we prefer. Then the second one will ask us whether we want to stick with the old or adopt the winner of the first referendum. This back-to-front approach is not incompetence. Putting the "which new one?" question first *REFRAMES* the question from "do you want to change the flag" to "which new design do you want to change to" so that by the second referendum people will be feeling "but I already picked this new design". Half the art of politics is the art of controlling how a problem is described, so that you control how people perceive it, so that your solution looks good. Another example here is the way every random change is called a "reform", even by journalists who ought to know better. What's that got to do with you? If you get stuck, maybe you should try describing the problem a different way. Instead of talking about a "list of tuples", maybe you could talk about "a set of descriptors", or noting that a full function specification is Module:Name/Arity, "a set of incomplete descriptors". Maybe instead of saying "a nice X" you could say "an X that is like this Y". From r.wobben@REDACTED Thu Aug 20 08:17:32 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Thu, 20 Aug 2015 08:17:32 +0200 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <1E643866-3F7E-45D0-9245-549243921AC3@cs.otago.ac.nz> References: <55D375CF.1000701@home.nl> <1F93E56C-843F-44A6-98A5-35FEF0A6B073@cs.otago.ac.nz> <55D46408.3000407@home.nl> <55D470FC.1060104@gmail.com> <55D472F6.2010100@home.nl> <1E643866-3F7E-45D0-9245-549243921AC3@cs.otago.ac.nz> Message-ID: <55D570FC.8060008@home.nl> Op 20-8-2015 om 8:00 schreef Richard A. O'Keefe: > On 20/08/2015, at 12:13 am, Roelof Wobben wrote: > >> oke, but I do not have a list of tuples but a list of lists that contain tuples, >> >> So I have this [ [ {1,2}, {2,3}], [ { 1,3} , { 2,1} ] ] >> >> and I do experiment a lot in erl but I seem to be lost. > Many years ago when I was a teenager I wanted to learn to fly > an aeroplane. My father took me to a local aerodrome and had > me given lesson 1. It was great. I could *do* this. To get > lesson 2, I had to get a student pilot licence. So I had to > have a medical examination, ECG, the works. And I was rejected > on the grounds that I needed glasses. > > I'm still upset by that. I had heard of lots of flying accidents > caused by people flying in circumstances (low to the ground) or > conditions (darkness, clouds) that they were not trained for, > in order to show off or at least not to look bad to their > companions. I had never heard (and still haven't) of an accident > caused by someone's glasses falling off. And there was NO test > to probe "which would you prefer? To look like an idiot to your > friends, or to put their lives at risk?" > > Personal application: asking for help on this list about > points that seem pretty obvious to the people answering does > not make you look impressive. At first sight! To me, it > makes you look like someone I *might* trust to fly me. To > be brutally honest, I sometimes get the feeling "oh no, not > another message from Roelof Wobben", but heck, I'm *paid* > to teach people about programming. (OK, so those are > *other* people who are enrolled here. But still...) But > there's _always_ something to learn from giving a lesson. > > Let me get to the point. In preparation for the lessons I > thought I was going to get, I read a couple of books. In > one of them I found this advice: > > When something goes wrong, > DON'T JUST DO SOMETHING, SIT THERE! > > I've come across basically the same advice in several contexts, > including dealing with stroppy lawnmowers. > > DON'T JUST DO SOMETHING, SIT THERE! > > What is my present situation? > How do I want it to be different? > Is the problem that I have the one I thought I had? > What I was doing just now was wrong, maybe I should stop doing that. > Can I approach this another way? > What if I just take it apart, clean the parts, and put them > together again (works for lawnmowers but NOT aeroplanes in flight)? > Maybe I should take the dog for a walk as a distraction. > (If you can do that from an aeroplane in flight you have a > very strange dog.) > > A well known phenomenon is "regression under stress to first > learned behaviour". > > 1. Learn method M1. > 2. Learn method M2 which is better in some way. > 3. Be put under stress. > 4. Be given a task for which M2 is more appropriate. > OOPS. We tend to revert to M1. > > Floundering around lost while programming is stressful, and > in such circumstances we *all* tend to revert to the habits > we learned earlier. If you learned Lisp then C you'll be > trying to emulate #'(LAMBDA (...) ...). If the other way > around, you'll be trying to emulate *p++. (I am *so* > lucky that C was about the 80th programming language I > learned.) > > Another phenomenon is "mental set". From Wikipedia, > " A mental set is a framework for thinking about a problem. > It can be shaped by habit or by desire. > Mental sets can make it easy to solve a class of problem, > but attachment to the wrong mental set can inhibit > problem-solving and creativity." > > That is, we can consciously or *unconsciously* adopt a > particular way of approaching a problem and we not only > tend to stick with it, we tend to forget that any other > way of approaching it might be possible. One of the > things we have to do when we get stuck is to try to > step back and try to unjam our framework. > > This actually ties in with the "hypnosis" that Scott Adams > (creator of "Dilbert") keeps talking about in his blog, > which turns out to be more the Bandler and Grinder "Structure > of Magic" stuff. For example, in my country, the Prime > Minister is pushing for a change to the flag. A majority of > people in the country are either passionately devoted to > the flag we have, or don't care about flags one way or another, > and would prefer to see the money spent on say health care or > child poverty or something. We're going to get two > referendums, like it or not. You'd think the first one would > be "do you want to change the flag?" and the second would be > "which of these designs do you prefer?" But it's going to be > the other way around. People were asked to submit designs. > Then a panel of so-called experts picked a short list of four. > The first referendum is going to ask us which of the four > *new* designs we prefer. Then the second one will ask us > whether we want to stick with the old or adopt the winner of > the first referendum. > > This back-to-front approach is not incompetence. > Putting the "which new one?" question first *REFRAMES* > the question from "do you want to change the flag" to > "which new design do you want to change to" so that by > the second referendum people will be feeling "but I > already picked this new design". > > Half the art of politics is the art of controlling how a > problem is described, so that you control how people > perceive it, so that your solution looks good. Another > example here is the way every random change is called a > "reform", even by journalists who ought to know better. > > What's that got to do with you? If you get stuck, > maybe you should try describing the problem a different > way. Instead of talking about a "list of tuples", > maybe you could talk about "a set of descriptors", > or noting that a full function specification is > Module:Name/Arity, "a set of incomplete descriptors". > Maybe instead of saying "a nice X" you could say > "an X that is like this Y". > > > > I think that is one part of the problem, The other part is that I "just" started with Erlang so the language is unfamiliir in terms of which part casn help me solve the problem. Is it a LC or a map or just pattern matching. The last part can , in my oponion , only be solved by doing things. I could read a thousand books but to solve a problem myself I learn a lot more. Roelof > --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From ok@REDACTED Thu Aug 20 08:51:07 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Thu, 20 Aug 2015 18:51:07 +1200 Subject: [erlang-questions] How can I make a list of this In-Reply-To: <55D570FC.8060008@home.nl> References: <55D375CF.1000701@home.nl> <1F93E56C-843F-44A6-98A5-35FEF0A6B073@cs.otago.ac.nz> <55D46408.3000407@home.nl> <55D470FC.1060104@gmail.com> <55D472F6.2010100@home.nl> <1E643866-3F7E-45D0-9245-549243921AC3@cs.otago.ac.nz> <55D570FC.8060008@home.nl> Message-ID: <34D8B71C-13CA-4C3B-959D-FCC0A9F90984@cs.otago.ac.nz> On 20/08/2015, at 6:17 pm, Roelof Wobben wrote: > The other part is that I "just" started with Erlang so the language is unfamiliir in terms of > which part casn help me solve the problem. Is it a LC or a map or just pattern matching. Anything that can be done with a list comprehension can be done without it. TL;DR Master these four list processing functions: lists:map(Transformer, Elements) lists:filter(Tester, Elements) lists:foldl(Updater, Initial, Elements) lists:append(List_Of_Lists) Let's generalise the current example a bit. We want to compute [f(X,Y) || X <- g(U), Y <- h(X)] We can do it by writing our own recursive functions. answer(U) -> lists:reverse(outer(g(U), [])). outer([], L) -> L; outer([X|Xs], L) -> outer(Xs, inner(h(X), U, L)). inner([], _, L) -> L; inner([Y|Ys], X, L) -> inner(Ys, X, [f(X,Y)|L]). This builds the answer up from left to right using an accumulator, but that produces the wrong order, so we fix it up with reverse. To adapt this to a particular problem, plug in appropriate expressions in place of g(U), h(X), and f(X,Y). If you're going to sort the answer anyway, there's no point in reversing first. Let's put this another way. List comprehensions are pleasantly brief and clear, but they do not add to the power of the language. SML manages fine without them. Any list comprehension can be written using some combination of lists:map(F, Xs) -- [F(X) || X <- Xs] lists:filter(P, Xs) -- [X || X <- Xs, P(X)] lists:append(Xss) -- [X || Xs <- Xss, X <- Xs]. You should make sure that you understand these three functions thoroughly. A fourth function, lists:foldl(F, A, Xs) is also important to understand. In the case of [f(X,Y) || X <- g(U), Y <- h(X)] we have to (1) traverse g(U), for which map seems appropriate (2) traverse h(X), for which map seems appropriate (3) but that yields a list of lists, so we need append lists:append(lists:map( fun (X) -> lists:map( fun (Y) -> f(X, Y) end, h(X)) end, g(U))) List comprehensions add no computational power to map/2, filter/2, and append/1. The difference is brevity and clarity, that's all. A beginner had better keep the bodies of 'fun's simple. Simpler than this. So maybe Outer = fun (X) -> Inner = fun (Y) -> f(X, Y) end, lists:map(Inner, X) end, lists:append(lists:map(Outer, g(U))). From carlosj.gf@REDACTED Thu Aug 20 09:16:45 2015 From: carlosj.gf@REDACTED (=?UTF-8?Q?Carlos_Gonz=C3=A1lez_Florido?=) Date: Thu, 20 Aug 2015 09:16:45 +0200 Subject: [erlang-questions] NkROLE released Message-ID: Hi, we have released even another project based on riak_core and NkDIST, called NkROLE. It is very simple but useful for many cases. NkROLE is a framework for managing complex relations among arbitrary objects in a riak_core cluster. You can create any number of objects (Erlang terms) and define relations among them, based on roles. Any object can be said to have any role over any other object. Also, you can say that all objects having a specific role over an object have automatically the same or other role over other object, and this complex relations can be nested at any level. Please have a look at https://github.com/Nekso/nkrole Regards, Carlos -------------- next part -------------- An HTML attachment was scrubbed... URL: From henrik.x.nord@REDACTED Thu Aug 20 10:17:49 2015 From: henrik.x.nord@REDACTED (Henrik Nord X) Date: Thu, 20 Aug 2015 10:17:49 +0200 Subject: [erlang-questions] Patch package OTP 18.0.3 released Message-ID: <55D58D2D.3090100@ericsson.com> Patch Package: OTP 18.0.3 Git Tag: OTP-18.0.3 Date: 2015-08-20 Trouble Report Id: OTP-12941, OTP-12942 Seq num: System: OTP Release: 18 Application: erts-7.0.3 Predecessor: OTP 18.0.2 Check out the git tag OTP-18.0.3, and build a full OTP system including documentation. Apply one or more applications from this build as patches to your installation using the 'otp_patch_apply' tool. For information on install requirements, see descriptions for each application version below. --------------------------------------------------------------------- --- erts-7.0.3 ------------------------------------------------------ --------------------------------------------------------------------- The erts-7.0.3 application can be applied independently of other applications on a full OTP 18 installation. --- Fixed Bugs and Malfunctions --- OTP-12941 Application(s): erts Fixed a binary memory leak when printing to shell using the tty driver (i.e. not -oldshell). OTP-12942 Application(s): erts Fix a bug where the standard error port sometimes crashes with eagain as the reason. Full runtime dependencies of erts-7.0.3: kernel-4.0, sasl-2.4, stdlib-2.5 --------------------------------------------------------------------- --- Thanks to ------------------------------------------------------- --------------------------------------------------------------------- Steve Vinoski --------------------------------------------------------------------- --------------------------------------------------------------------- --------------------------------------------------------------------- From hans.bolinder@REDACTED Thu Aug 20 13:39:47 2015 From: hans.bolinder@REDACTED (Hans Bolinder) Date: Thu, 20 Aug 2015 11:39:47 +0000 Subject: [erlang-questions] Is it possible to have nested parametrised types when the base type is opaque? In-Reply-To: References: Message-ID: <56466BD70414EA48969B4064696CF28C21EF5106@ESESSMB207.ericsson.se> Hi, [James Fish:] > I am never one to doubt that dialyzer is correct, and I am wrong. In > this case I am perplexed by the warning generated with nested > parametrised types. Sorry for the long response time. Commit 050d93 fixes a Dialyzer bug, and it seems that your example now passes without warnings. Best regards, Hans Bolinder, Erlang/OTP team, Ericsson -------------- next part -------------- An HTML attachment was scrubbed... URL: From jesper.louis.andersen@REDACTED Thu Aug 20 15:33:27 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Thu, 20 Aug 2015 15:33:27 +0200 Subject: [erlang-questions] sys.config and OTP-4867 Message-ID: In the config(5) man page we have a sys.config section: http://www.erlang.org/doc/man/config.html Which allows us to merge a file into the existing sys.config: [{myapp,[{par1,val1},{par2,val2}]}, "/home/user/myconfig"]. This is a very neat trick, but if we read the code in `application_controller` there is a reference to OTP-4867 and this is only enabled for files named `sys.config`. This has bitten me several times, when people end up naming their configuration file differently. What is the reasoning behind limiting this to sys.config? And would it be possible to relax the naming constraint such that there is a set of files which gets file expansion? The reason I'm asking is because the whole game of configuring an application is a complex afair. Some environments are able to write files, whereas others are relying on the OS environment variables for certain settings. And yet others would like to be able to point to a file-chain which gets progressively merged into the configuration, like in sys.config. In some environments, sys.config is run through a preprocessor and its contents are replaced by writing a temporary file next to sys.config. But once loaded, this newly temp file is not amenable to OTP-4867 substitution :/ And writing in the other direction, from a stanza file into sys.config also seems somewhat futile. Clearly there were a lot of thought put into this configuration inside Ericsson, so in particular, how is a large Erlang system configured in a painless way? Specifically, how does one go about procuring a release of the software which doesn't change its checksum but can run in several environments: staging, user-acceptance-testing, production and contains *no* secret keys as part of its build but reads these from outside (e.g., the environmental "context" in which it has been deployed?) -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From candres.bolanos@REDACTED Thu Aug 20 16:10:30 2015 From: candres.bolanos@REDACTED (=?UTF-8?Q?CARLOS_ANDRES_BOLA=C3=91OS_REALPE?=) Date: Thu, 20 Aug 2015 09:10:30 -0500 Subject: [erlang-questions] [ANN] cowboy-swagger: Swagger for Erlang using Cowboy Message-ID: Cowboy Swagger is an open source project built on top of Trails that integrates Swagger, so you can have a really nice Web documentation for your RESTful APIs in only a few simple steps. Read more here: http://inaka.net/blog/2015/08/19/cowboy-swagger/ Repository: https://github.com/inaka/cowboy-swagger -------------- next part -------------- An HTML attachment was scrubbed... URL: From steven.charles.davis@REDACTED Thu Aug 20 16:30:26 2015 From: steven.charles.davis@REDACTED (Steve Davis) Date: Thu, 20 Aug 2015 09:30:26 -0500 Subject: [erlang-questions] strings vs binaries In-Reply-To: <12859255.Ey1zpWod8m@changa> References: <90AD63CD-FEC2-407D-B05B-C70AA43E2D8C@gmail.com> <12859255.Ey1zpWod8m@changa> Message-ID: <0B3F41F3-27CA-43CE-B99C-4894C4B6D4A9@gmail.com> Actually, I don?t seem to have ever faced the problem of "get characters 3 to 11?. And I?ve dealt with some pretty diverse protocols... If I did, I guess I?d use a small function that calls unicode:characters_to_list? extract them and convert the result back to binary! regs, /s > On Aug 18, 2015, at 10:25 PM, zxq9 wrote: > > <<"binary??????????????string????????????"/utf8>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From zxq9@REDACTED Thu Aug 20 16:51:26 2015 From: zxq9@REDACTED (zxq9) Date: Thu, 20 Aug 2015 23:51:26 +0900 Subject: [erlang-questions] strings vs binaries In-Reply-To: <0B3F41F3-27CA-43CE-B99C-4894C4B6D4A9@gmail.com> References: <90AD63CD-FEC2-407D-B05B-C70AA43E2D8C@gmail.com> <12859255.Ey1zpWod8m@changa> <0B3F41F3-27CA-43CE-B99C-4894C4B6D4A9@gmail.com> Message-ID: <1667073.xMWhrEW5Mv@changa> On 2015?8?20? ??? 09:30:26 you wrote: > Actually, I don?t seem to have ever faced the problem of "get characters 3 to 11?. And I?ve dealt with some pretty diverse protocols... > > If I did, I guess I?d use a small function that calls unicode:characters_to_list? extract them and convert the result back to binary! In essence this exactly what we do, we just do it with the entire binary input (given that it is supposed to be a utf8 string), and it winds up becoming a binary again on its way out -- but no pieces of the initial binary survive that initial conversion, and this is on purpose. Before the processing phase we only do the work of making X-characters of Z-bytes once, instead of letting that task grow over time into something that happens all over the place. In my experience it is the only way to maintain sanity in the face of utf8. Count yourself lucky if this is not your situation and you can be sure it never will be! As I mentioned before, though, most string processing occurs in data services designed to handle text, or in clients that deal with text directly as a core part of what they do. In Erlang, which tends to be in the middle of all this in my case, we just don't do much text processing, at least not as a core task (generally speaking, the application server could care less if the data is a text message, a voice message, a video, a document, game save data, etc.). Where we do deal with text directly it has been consistently easier to manage it in utf8 than anything else, and and in Erlang that has been much easier to deal with as lists than binaries. -Craig From sid5@REDACTED Thu Aug 20 17:00:45 2015 From: sid5@REDACTED (Sid Muller) Date: Thu, 20 Aug 2015 17:00:45 +0200 Subject: [erlang-questions] ** exception exit: shutdown : SOLVED dets_server:stop(). In-Reply-To: References: , Message-ID: An HTML attachment was scrubbed... URL: From felixgallo@REDACTED Thu Aug 20 17:08:07 2015 From: felixgallo@REDACTED (Felix Gallo) Date: Thu, 20 Aug 2015 08:08:07 -0700 Subject: [erlang-questions] sys.config and OTP-4867 In-Reply-To: References: Message-ID: I've had some success with the following automatable steps: 1. Build a node in the usual way 2. Replace its sys.config with a canary unbootable "you screwed up" sys.config 3. Commit that node as an artifact to porcelain artifact repository of choice, i.e. git 4. Commit per-environment sys.config setups separately 5. As part of build process, pull the node artifact, marry it with appropriately environmented and versioned sys.config Beyond the raw confusion and complexity issues you note, there's also pragmatically the question of live upgrades; if app x was booted with sys.config a, and you upgrade app y in the same node that wants sys.config b, then the unitary nature of sys.config starts to feel a little difficult. Fundamentally the 12 factor app principles (http://12factor.net/) which I believe you may be obliquely referencing are still themselves pretty new, and erlang hasn't made the jump over there yet. Some of the ideas (e.g. http://12factor.net/config, 'store everything in environment variables') are super great for webapps, but webapps are normally written in single-threaded memory-leaky buggy dynamic languages and so the expectation that they'll be constantly murdered by their users or operators or frameworks themselves and subsequently restarted is built into the thinking. Nodes, which stay up until armageddon happens, probably need a more dynamic and mutable configuration system than that, because it may not be seconds or minutes or indeed years between unix-process-restarts refreshing the env vars. Since misconfiguration is probably the #1 cause of outages at scale ( http://danluu.com/postmortem-lessons/, and extrapolating from my own extensive experience killing clusters and data centers), this is a really great area of exploration for some enterprising and thoughtful erlanger. F. On Thu, Aug 20, 2015 at 6:33 AM, Jesper Louis Andersen < jesper.louis.andersen@REDACTED> wrote: > In the config(5) man page we have a sys.config section: > > http://www.erlang.org/doc/man/config.html > > Which allows us to merge a file into the existing sys.config: > > [{myapp,[{par1,val1},{par2,val2}]}, > "/home/user/myconfig"]. > > This is a very neat trick, but if we read the code in > `application_controller` there is a reference to OTP-4867 and this is only > enabled for files named `sys.config`. This has bitten me several times, > when people end up naming > their configuration file differently. What is the reasoning behind > limiting this to sys.config? And would it be possible to relax the naming > constraint such that there is a set of files which gets file expansion? > > The reason I'm asking is because the whole game of configuring an > application is a complex afair. Some environments are able to write files, > whereas others are relying on the OS environment variables for certain > settings. And yet others would like to be able to point to a file-chain > which gets progressively merged into the configuration, like in sys.config. > > In some environments, sys.config is run through a preprocessor and its > contents are replaced by writing a temporary file next to sys.config. But > once loaded, this newly temp file is not amenable to OTP-4867 substitution > :/ And writing in the other direction, from a stanza file into sys.config > also seems somewhat futile. > > Clearly there were a lot of thought put into this configuration inside > Ericsson, so in particular, how is a large Erlang system configured in a > painless way? Specifically, how does one go about procuring a release of > the software which doesn't change its checksum but can run in several > environments: staging, user-acceptance-testing, production and contains > *no* secret keys as part of its build but reads these from outside (e.g., > the environmental "context" in which it has been deployed?) > > -- > J. > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From erlang@REDACTED Thu Aug 20 18:24:52 2015 From: erlang@REDACTED (Joe Armstrong) Date: Thu, 20 Aug 2015 18:24:52 +0200 Subject: [erlang-questions] strings vs binaries In-Reply-To: <8BB0D966-BC4F-4C1E-BAD2-0B01AA14CCD0@vailsys.com> References: <8BB0D966-BC4F-4C1E-BAD2-0B01AA14CCD0@vailsys.com> Message-ID: On Tue, Aug 18, 2015 at 10:23 PM, Rick Pettit wrote: > Generally speaking, you probably want to use binaries these days as they > consume far less memory (at least for ?large? strings): Right - but with the caveat that most string's aren't "large". As an example the source code of the text of my Erlang book (27 chapters and 4 appendices) is 1.22 MBytes of XML text. At 16 bytes/byte overhead this is 19.5 MBytes - so I could store 50 books in 1GByte - I have 8GBytes of memory enough for 400 books. I have often parsed all this XML and manipulated (as strings) it in the twinking of an eye. So this notion of "small" must be in relation to what you want to do. My rule of thumb is that any text I have entered by hand is "small" - including entire books and all the code I have every written. I use binaries as memory buffers and when I need to know the exact memory layout (in terms of bits and bytes) - I use lists when I want to perform symbolic manipulation of data. What's big and small and whether to use lists or binaries depends upon what you want to do - at the end of the day the choice should be based on measurements not guesswork. Cheers /Joe > > http://www.erlang.org/doc/efficiency_guide/advanced.html > > That goes for both sending over the wire as well as internally. > > -Rick > > On Aug 18, 2015, at 3:16 PM, Ben Hsu wrote: > > Hello > > I have a simple question, I know Erlang has strings and binary strings as > separate data types, and they're different even if they "look the same" in > the console > > > 1> io:format(<<"fnord">>). > fnord > 2> io:format("fnord"). > fnord > > 3> "fnord"==<<"fnord">> > 3> . > false > > My question is when you will use each one. Are binary strings used for > sending data over the wire, and normal strings used internally? what are the > tradeoffs? > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > From co7eb@REDACTED Thu Aug 20 18:42:16 2015 From: co7eb@REDACTED (Gilberio Carmenates Garcia) Date: Thu, 20 Aug 2015 12:42:16 -0400 Subject: [erlang-questions] Todays Topic: Performance Stuffs->records vs maps vs proplists In-Reply-To: References: <000c01d0d84b$aecece40$0c6c6ac0$@co.cu> Message-ID: <000001d0db67$30da9450$928fbcf0$@co.cu> Hi all, well I think maps are super nice, I will do the test again but including lists:keyfind/3... to compare all values. How I can do to test memory occupation but with fine details? because, I see it in observer and all cases have no appreciable difference between them. Regards test data size, I didn't state it because I use the same data in all cases, but in its correspondent format, i.e. for proplists I use [{id, N}, ...] and for maps: #{id => N, ...} and so on. I only included a few data, I think was 9 keys with its number values, but for the number values I used the same variable N as I was decreasing it in the recursive loop. #{ id => N, name => N, ...}. I will be doing some other interesting test since time to time. I have another one I will post later soon. Best regards, Ivan (son of Gilberio). -----Mensaje original----- De: Garrett Smith [mailto:g@REDACTED] Enviado el: lunes, 17 de agosto de 2015 6:27 Para: Erik S?e S?rensen CC: Gilberio Carmenates Garcia; Erlang Questions Asunto: Re: [erlang-questions] Todays Topic: Performance Stuffs->records vs maps vs proplists I have this from erlang-bench: https://github.com/gar1t/erlang-bench/blob/master/name-lookup.escript lists:keyfind is indeed faster, but surprisingly proplists is plenty fast too. The use case I was interested in there is small list (less than 100 items) lookup, which is common for configuration data. Fast is relative of course. And short of a real application bottleneck, completely pointless to obsess over. But it can be interesting and fun to argue about, like politics. Ivan, it'd be great to update that benchmark with maps :) On Mon, Aug 17, 2015 at 2:30 AM, Erik S?e S?rensen wrote: > Hi - > As for proplists, try replacing it with the simpler and faster > lists:keyfind/3. > Also, you don't state the size of the data structure you're manipulating - > only the number of iterations. > > Den 16/08/2015 20.08 skrev "Gilberio Carmenates Garcia" > : >> >> Hi everyone here are some interesting tests about performance in Erlang. >> >> >> >> Today?s Topic: performance stuffs->records vs maps vs proplists >> >> >> >> Test made against the same data represented in three format records, maps >> and proplists. >> >> Test case value: 10 000 000 iterations. >> >> >> >> Test case: get. >> >> Records: >> >> Rec#rec.id -> 237 ms >> >> Maps: >> >> maps:get(id, Map) -> 550 ms >> >> {id := Id} = Map -> ~277 ms >> >> Proplists: >> >> proplists:get_value/lookup(id, PPL) -> ~1642 ms >> >> >> >> Test case: create. >> >> Records: >> >> Rec = #rec{id = N, ?} -> ~1046 ms >> >> Maps: >> >> Map = #{id = N, ?} -> ~ 1440 ms >> >> Proplists: >> >> PPL = [{id, N}, ?] -> ~2318 ms >> >> >> >> Test case: update. >> >> Records: >> >> case 1 (~908 ms): >> >> Rec2 = Rec#rec{id = N + N}, >> >> case 2 (~1057 ms): >> >> Rec2 = Rec#rec{id = N, name = N, age = N, dog = N, cat = N, mow = N, >> tin = N}, >> >> case 3: no equivalent >> >> case 4: no equivalent >> >> Maps: >> >> case 1 (~3013 ms): >> >> Map2 = Map#{id => N + N}, >> >> case 2 (~ 4441 ms): >> >> Map2 = Map#{id => N, name => N, age => N, dog => N, cat => N, mow => >> N, tin => N}, >> >> case 3 (~952 ms): >> >> Map2 = maps:update(id, N + 1, Map) >> >> case 4 (~6054 ms) >> >> Map2 = maps:update(id, N + 1, Map), >> >> Map3 = maps:update(name, N + 1, Map2), >> >> Map4 = maps:update(age, N + 1, Map3), >> >> Map5 = maps:update(dog, N + 1, Map4), >> >> Map6 = maps:update(cat, N + 1, Map5), >> >> Map7 = maps:update(mow, N + 1, Map6), >> >> Map8 = maps:update(tin, N + 1, Map7), >> >> Proplists: >> >> case 1: no equivalent >> >> case 2: no equivalent >> >> case 3: (~1529 ms) >> >> PPL2 = lists:keystore(id, 1, PPL, {id, N + N}), >> >> case 4: (~30705 ms) >> >> PPL2 = lists:keystore(id, 1, PPL, {id, N + N}), >> >> PPL3 = lists:keystore(name, 1, PPL2, {name, N + N}), >> >> PPL4 = lists:keystore(age, 1, PPL3, {age, N + N}), >> >> PPL5 = lists:keystore(dog, 1, PPL4, {dog, N + N}), >> >> PPL6 = lists:keystore(cat, 1, PPL5, {cat, N + N}), >> >> PPL7 = lists:keystore(mow, 1, PPL6, {mow, N + N}), >> >> PPL8 = lists:keystore(tin, 1, PPL7, {tin, N + N}), >> >> >> >> What about that? I think using maps:get/2 is not so fast as using map >> pattern matching. >> >> >> >> Cheers, >> >> Ivan (son of Gilberio). >> >> >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > From co7eb@REDACTED Thu Aug 20 18:53:36 2015 From: co7eb@REDACTED (Gilberio Carmenates Garcia) Date: Thu, 20 Aug 2015 12:53:36 -0400 Subject: [erlang-questions] Todays Topic: Performance Stuffs->records vs maps vs proplists Message-ID: <000101d0db68$c4161e50$4c425af0$@co.cu> Hi all. Yes indeed thanks for replying, Jesper, luckedly I did all test with the same order and I did the lookup with the first element. The only problem is with maps, because maps reorders its keys. So I will do the test again taking in count the order of the final constructed map and make that same order to the records and proplists, and lookup with the first and last key, just to see the different between cases and O(1) y O(N). Cheers, Ivan (son of Gilberio). De: Jesper Louis Andersen [mailto:jesper.louis.andersen@REDACTED] Enviado el: lunes, 17 de agosto de 2015 8:04 Para: Erik S?e S?rensen CC: Gilberio Carmenates Garcia; Erlang Questions Asunto: Re: [erlang-questions] Todays Topic: Performance Stuffs->records vs maps vs proplists On Mon, Aug 17, 2015 at 9:30 AM, Erik S?e S?rensen wrote: Also, you don't state the size of the data structure you're manipulating - only the number of iterations. Indeed. And also you don't specify what the key order is. If I have a proplist of any size, PL, and then I do PropList = [{x, y} | PL], lists:keyfind(x, 1, PropList). Then the key lookup will be in constant time. If on the other hand I do PropList = PL ++ [{x,y}] Then the lookup is in the order of O(n) where n is the length of PL. In other words, a proplist can hit the two extreme cases, with the typical case being O(n) (since you have to search half the elements on average). In contrast, a map has an upper bound of O(lg n) (with an extremely wide branching factor). Beware the synthetic benchmark. For it lures you into false thinking. -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jesper.louis.andersen@REDACTED Thu Aug 20 19:47:25 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Thu, 20 Aug 2015 19:47:25 +0200 Subject: [erlang-questions] Todays Topic: Performance Stuffs->records vs maps vs proplists In-Reply-To: <000101d0db68$c4161e50$4c425af0$@co.cu> References: <000101d0db68$c4161e50$4c425af0$@co.cu> Message-ID: Simple test: -module(z). -compile(export_all). t() -> L = [{X, y} || X <- lists:seq(1, 100*1000)], L2 = L ++ [{z, z}], M = maps:from_list(L2), {Proplists, z} = timer:tc(fun() -> proplists:get_value(z, L2) end), {Keyfind, {z,z}} = timer:tc(fun() -> lists:keyfind(z,1, L2) end), {Map, z} = timer:tc(fun() -> maps:get(z, M) end), #{ pl => Proplists, kf => Keyfind, m => Map }. Running this: 30> c(z). {ok,z} 31> z:t(). #{kf => 939,m => 2,pl => 3147} maps win over kf by roughly a factor 500 and proplists by a factor 1500. Beware the benchmark, for it may be wrong. On Thu, Aug 20, 2015 at 6:53 PM, Gilberio Carmenates Garcia < co7eb@REDACTED> wrote: > Hi all. Yes indeed thanks for replying, Jesper, luckedly I did all test > with the same order and I did the lookup with the first element. The only > problem is with maps, because maps reorders its keys. So I will do the test > again taking in count the order of the final constructed map and make that > same order to the records and proplists, and lookup with the first and last > key, just to see the different between cases and O(1) y O(N). > > > > Cheers, > > Ivan (son of Gilberio). > > > > > > > > > > *De:* Jesper Louis Andersen [mailto:jesper.louis.andersen@REDACTED] > *Enviado el:* lunes, 17 de agosto de 2015 8:04 > *Para:* Erik S?e S?rensen > *CC:* Gilberio Carmenates Garcia; Erlang Questions > *Asunto:* Re: [erlang-questions] Todays Topic: Performance > Stuffs->records vs maps vs proplists > > > > > > On Mon, Aug 17, 2015 at 9:30 AM, Erik S?e S?rensen > wrote: > > Also, you don't state the size of the data structure you're manipulating - > only the number of iterations. > > > > Indeed. And also you don't specify what the key order is. If I have a > proplist of any size, PL, and then I do > > PropList = [{x, y} | PL], > > lists:keyfind(x, 1, PropList). > > Then the key lookup will be in constant time. If on the other hand I do > > PropList = PL ++ [{x,y}] > > Then the lookup is in the order of O(n) where n is the length of PL. > > In other words, a proplist can hit the two extreme cases, with the typical > case being O(n) (since you have to search half the elements on average). In > contrast, a map has an upper bound of O(lg n) (with an extremely wide > branching factor). > > Beware the synthetic benchmark. For it lures you into false thinking. > > > -- > > J. > -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ok@REDACTED Fri Aug 21 02:40:30 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Fri, 21 Aug 2015 12:40:30 +1200 Subject: [erlang-questions] strings vs binaries In-Reply-To: <0B3F41F3-27CA-43CE-B99C-4894C4B6D4A9@gmail.com> References: <90AD63CD-FEC2-407D-B05B-C70AA43E2D8C@gmail.com> <12859255.Ey1zpWod8m@changa> <0B3F41F3-27CA-43CE-B99C-4894C4B6D4A9@gmail.com> Message-ID: <27B8762A-FF96-4A07-854A-21D009BB7B83@cs.otago.ac.nz> On 21/08/2015, at 2:30 am, Steve Davis wrote: > Actually, I don?t seem to have ever faced the problem of "get characters 3 to 11?. And I?ve dealt with some pretty diverse protocols... I've faced basically that problem, using data with fixed field widths, not delimiters. Fortunately I haven't had to deal with numeric data in non-ASCII digits. Yet. From sdl.web@REDACTED Fri Aug 21 04:11:21 2015 From: sdl.web@REDACTED (Leo Liu) Date: Fri, 21 Aug 2015 10:11:21 +0800 Subject: [erlang-questions] Make sense of appmon_info:load/1 Message-ID: Hi there, I can understand everything appmon_info:load/1 does except these bits: 1. Q/6, what is the magic number 6? 2. What does `prog' stand for as in appmon_info:prog/1? Thanks, Leo From zxq9@REDACTED Fri Aug 21 07:25:49 2015 From: zxq9@REDACTED (zxq9) Date: Fri, 21 Aug 2015 14:25:49 +0900 Subject: [erlang-questions] strings vs binaries In-Reply-To: <27B8762A-FF96-4A07-854A-21D009BB7B83@cs.otago.ac.nz> References: <90AD63CD-FEC2-407D-B05B-C70AA43E2D8C@gmail.com> <0B3F41F3-27CA-43CE-B99C-4894C4B6D4A9@gmail.com> <27B8762A-FF96-4A07-854A-21D009BB7B83@cs.otago.ac.nz> Message-ID: <2179323.JNPhikZpzV@changa> On 2015?8?21? ??? 12:40:30 you wrote: > > On 21/08/2015, at 2:30 am, Steve Davis wrote: > > > Actually, I don?t seem to have ever faced the problem of "get characters 3 to 11?. And I?ve dealt with some pretty diverse protocols... > > I've faced basically that problem, using data with fixed field > widths, not delimiters. Fortunately I haven't had to deal > with numeric data in non-ASCII digits. Yet. > As a side note, to let the occidentals around here know this actually exists... Parsing for numeric values in text is a rodeo in a few languages. Using Japanese as an example, numbers are not grouped in periods of 3, but periods of 4, though decimal notation often uses periods of 3 in software (originally because l10n is hard, but users here just came to accept that only game makers would ever cater to them, and have grown accustomed to periods of 3 over the last two decades... ). So you have to identify strings that not only have values like "123456789" and "123,456,789", but also "1,2345,6789". There are also full-width, multibyte characters which any decent input widgets/functions should accept: "123" ~= "???". But that is just romaji. Local numbers come in a few different flavors. Everyone has probably seen "123" as ?????, and while these are in use, the first three numerals are actually simplifications, the real ones (which are mandatory in accounting software output and invoices) are ?????. But back to grouping... Zeroes are typically not written in native script, though the concept certainly exists. Any zeroes below a power of 10 aggregate are truncated (the same way we speak in English, I don't say "one thousand, zero, zero, zero" or "five-hundred zero one"), and instead of using simple commas to delimit periods (powers of 10,000) the actual name of the period is used. This can be mixed with native periods and Arabic numerals. This is just integers, of course. Decimal, mixed and native fractional notation is a different discussion entirely. These are all valid textual representations of the same number: 1. 120030240 2. 120,030,240 3. 1,2003,0240 4. 1?2003?240 5. ?????????? 6. ?????????? When you decide that you will accept numbers as text, it is important to consider carefully what that means based on your proximity to actual user input (or whether the input is the output of a system designed with user output in mind). Erlang binaries are not the friendliest tool for this particular flavor of numbers-as-text. This is an actual problem that I actually deal with (but I don't deal with it in Erlang, at least not so far). -Craig From kvratkin@REDACTED Fri Aug 21 14:13:14 2015 From: kvratkin@REDACTED (Kirill Ratkin) Date: Fri, 21 Aug 2015 15:13:14 +0300 Subject: [erlang-questions] Simple question about Erlang macro Message-ID: Hi, Does Erlang have some symbols to say preprocessor 'stop' to parse macro name and make substitution? I explain on example. In bash I can do: *A = a* *echo $A # -> a* *B = $A_b #* *echo $B # -> nothing good* But if : *B = ${A}_b* *echo $B # -> it works. Result is a_b* May I do same in Erlang preprocessor? Are there some symbols like bash's '{' and '}' in macro preprocessor? -------------- next part -------------- An HTML attachment was scrubbed... URL: From osmuogar@REDACTED Fri Aug 21 14:15:02 2015 From: osmuogar@REDACTED (=?UTF-8?Q?Oscar_Mu=C3=B1oz_Garrig=C3=B3s?=) Date: Fri, 21 Aug 2015 14:15:02 +0200 Subject: [erlang-questions] Sending UDP packets Message-ID: Hi, I am using a server to send some packets. The problem is actually the packets are truncated and my client does not receive the full packet. I created two sockets but only the socket wich receives the packet returns it to the client, if i change it the packet is lost. Could you give me some advice? Here is the code: -behaviour(gen_server). init(_Args)-> ... {ok,Socket} = gen_udp:open(49900), {ok, #state{socket=Socket}}. handle_info(Info, State)-> error_logger:info_msg("Received via INFO: ~p~n", [Info]), {udp, Socket, IP, InPortNo, Packet} = Info, [{"from",From},{"to",To},{"text",Text}] = parser:read_xml(Packet), write_to_db(Socket, IP, InPortNo, From, To, Text), {noreply, State}. write_to_db(WSocket, WAdress, WMPort, WFrom, WTo, WText)-> ... ... Message = analizar_resultados(Respuesta), {ok, SSocket} = gen_udp:open(0,[inet]), %%ok = gen_udp:send(SSocket, WAdress, WMPort, Message), <-------- This does not works cause the packet is lost ok = gen_udp:send(WSocket, WAdress, WMPort, Message), <-------- This works but the packet is truncated gen_udp:close(SSocket), ok. Thank you all for your help. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jesper.louis.andersen@REDACTED Fri Aug 21 15:14:16 2015 From: jesper.louis.andersen@REDACTED (Jesper Louis Andersen) Date: Fri, 21 Aug 2015 15:14:16 +0200 Subject: [erlang-questions] Sending UDP packets In-Reply-To: References: Message-ID: This ought to work: Including my typos: Eshell V7.0.3 (abort with ^G) 1> {ok, S} = gen_udp:open(0, [inet]). {ok,#Port<0.533>} 2> P = S. #Port<0.533> 3> inet:port(P). {ok,63315} 4> {ok, RP} = gen_udp:open(1234, [inet]). {ok,#Port<0.549>} 5> flush(). ok 6> gen_udp:send(P, {127,0,0,1}, 1234, term_to_binary(hello)). ok 7> flush(). Shell got {udp,#Port<0.549>, {127,0,0,1}, 63315, [131,100,0,5,104,101,108,108,111]} ok 8> Bytes = [131,100,0,5,104,101,108,108,111]. [131,100,0,5,104,101,108,108,111] 9> binary_to_term(Bytes). ** exception error: bad argument in function binary_to_term/1 called as binary_to_term([131,100,0,5,104,101,108,108,111]) 10> binary_to_term(iolist_to_binary(Bytes)). hello Immediate questions: * You are not guaranteed message delivery when using UDP. What is your strategy when this happens? Also, beware kernel settings! Usually the UDP buffer at the kernel side is pretty small, so Erlang doesn't even get a chance to run before the kernel throws away packets. * What is your MTU? Over localhost, it can be pretty big: OSX, FreeBSD: tiefling:turtle jlouis$ ifconfig lo0 | head -n 1 lo0: flags=8049 mtu 16384 Linux can use a 64 kilobyte MTU on localhost. But the Ethernet usually has an MTU of 1500 bytes or even lower, so you cannot send an UDP message above that size without it truncating. What is the iolist_size/1 of your Message? You will need to split your message over several UDP datagrams then. And you will have to handle that the internet may reorder your datagrams, or lose them mid-flight. On Fri, Aug 21, 2015 at 2:15 PM, Oscar Mu?oz Garrig?s wrote: > Hi, > I am using a server to send some packets. The problem is actually the > packets are truncated and my client does not receive the full packet. I > created two sockets but only the socket wich receives the packet returns it > to the client, if i change it the packet is lost. Could you give me some > advice? > > Here is the code: > > > > -behaviour(gen_server). > init(_Args)-> > ... > {ok,Socket} = gen_udp:open(49900), > {ok, #state{socket=Socket}}. > > handle_info(Info, State)-> > error_logger:info_msg("Received via INFO: ~p~n", [Info]), > {udp, Socket, IP, InPortNo, Packet} = Info, > [{"from",From},{"to",To},{"text",Text}] = parser:read_xml(Packet), > > write_to_db(Socket, IP, InPortNo, From, To, Text), > {noreply, State}. > > write_to_db(WSocket, WAdress, WMPort, WFrom, WTo, WText)-> > ... > ... > Message = analizar_resultados(Respuesta), > > {ok, SSocket} = gen_udp:open(0,[inet]), > %%ok = gen_udp:send(SSocket, WAdress, WMPort, Message), <-------- This > does not works cause the packet is lost > ok = gen_udp:send(WSocket, WAdress, WMPort, Message), <-------- This > works but the packet is truncated > gen_udp:close(SSocket), > ok. > > > > > > Thank you all for your help. > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -- J. -------------- next part -------------- An HTML attachment was scrubbed... URL: From chandrashekhar.mullaparthi@REDACTED Fri Aug 21 15:27:21 2015 From: chandrashekhar.mullaparthi@REDACTED (Chandru) Date: Fri, 21 Aug 2015 14:27:21 +0100 Subject: [erlang-questions] Sending UDP packets In-Reply-To: References: Message-ID: On 21 August 2015 at 13:15, Oscar Mu?oz Garrig?s wrote: > Hi, > I am using a server to send some packets. The problem is actually the > packets are truncated and my client does not receive the full packet. I > created two sockets but only the socket wich receives the packet returns it > to the client, if i change it the packet is lost. Could you give me some > advice? > > > > write_to_db(WSocket, WAdress, WMPort, WFrom, WTo, WText)-> > ... > ... > Message = analizar_resultados(Respuesta), > > {ok, SSocket} = gen_udp:open(0,[inet]), > %%ok = gen_udp:send(SSocket, WAdress, WMPort, Message), <-------- This > does not works cause the packet is lost > Do you have a stateful firewall between the client and server? Maybe the firewall is dropping packets because you are originating them from a random port? > ok = gen_udp:send(WSocket, WAdress, WMPort, Message), <-------- This > works but the packet is truncated > Is the other end written in Erlang as well or a different language? Could it be buggy? Can you see your complete packet in a packet capture? Chandru -------------- next part -------------- An HTML attachment was scrubbed... URL: From valentin@REDACTED Fri Aug 21 18:08:45 2015 From: valentin@REDACTED (Valentin Micic) Date: Fri, 21 Aug 2015 18:08:45 +0200 Subject: [erlang-questions] Sending UDP packets In-Reply-To: References: Message-ID: <7D590A1D-54D3-41F0-902F-13BA5F4714ED@pixie.co.za> The case that you mentioned is quite curious, as UDP, by definition, may drop a message, but *must* honor the message boundaries. In other words, UDP may *not* truncate the message -- messages are either delivered as a whole or not at all. I am a big fan of UDP, however, I usually try to keep the UDP message size to the length lower that MTU (MTU - IP/UDP header). Although possible, it is not advisable to send longer messages for a number of reasons, none of which, mind you, may cause message to be truncated, but rather dropped as a whole (assuming that OS kernel does its job). Thus, if you have to send UDP message that is longer than MTU, you will be far better of writing a simple custom message disassembly-reassembly routines then relying on kernel's ability to transfer big messages over UDP. V/ On 21 Aug 2015, at 2:15 PM, Oscar Mu?oz Garrig?s wrote: > Hi, > I am using a server to send some packets. The problem is actually the packets are truncated and my client does not receive the full packet. I created two sockets but only the socket wich receives the packet returns it to the client, if i change it the packet is lost. Could you give me some advice? > > Here is the code: > > > > -behaviour(gen_server). > init(_Args)-> > ... > {ok,Socket} = gen_udp:open(49900), > {ok, #state{socket=Socket}}. > > handle_info(Info, State)-> > error_logger:info_msg("Received via INFO: ~p~n", [Info]), > {udp, Socket, IP, InPortNo, Packet} = Info, > [{"from",From},{"to",To},{"text",Text}] = parser:read_xml(Packet), > > write_to_db(Socket, IP, InPortNo, From, To, Text), > {noreply, State}. > > write_to_db(WSocket, WAdress, WMPort, WFrom, WTo, WText)-> > ... > ... > Message = analizar_resultados(Respuesta), > > {ok, SSocket} = gen_udp:open(0,[inet]), > %%ok = gen_udp:send(SSocket, WAdress, WMPort, Message), <-------- This does not works cause the packet is lost > ok = gen_udp:send(WSocket, WAdress, WMPort, Message), <-------- This works but the packet is truncated > gen_udp:close(SSocket), > ok. > > > > > > Thank you all for your help. > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From mark.h.bruch@REDACTED Fri Aug 21 18:27:03 2015 From: mark.h.bruch@REDACTED (Mark Bruch) Date: Fri, 21 Aug 2015 18:27:03 +0200 Subject: [erlang-questions] Testing api with jsongen and quickcheck Message-ID: Hi. I've got a small json api that is in desperate need for better testing. Read a little about jsongen [1] from the prowess project [2] that looks pretty awesome. Unfortunately it doesn't compile on any of my machines. Is anyone using jsongen, or is it just in "research"-stage? Can someone recommend me any other tool for testing a json api? Thanks Mark [1] https://github.com/fredlund/jsongen [2] http://www.prowessproject.eu From garret.smith@REDACTED Fri Aug 21 18:53:23 2015 From: garret.smith@REDACTED (Garret Smith) Date: Fri, 21 Aug 2015 09:53:23 -0700 Subject: [erlang-questions] Testing api with jsongen and quickcheck In-Reply-To: References: Message-ID: On Fri, Aug 21, 2015 at 9:27 AM, Mark Bruch wrote: > Hi. > > I've got a small json api that is in desperate need for better > testing. Read a little about jsongen [1] from the prowess project [2] > that looks pretty awesome. Unfortunately it doesn't compile on any of > my machines. > Is anyone using jsongen, or is it just in "research"-stage? Can > someone recommend me any other tool for testing a json api? > > Thanks > Mark > > [1] https://github.com/fredlund/jsongen > [2] http://www.prowessproject.eu > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions As far as I can tell, jsongen is just for Go, not Erlang. Is your json api in Erlang? Or are you looking to test a json api using erlang? -Garret From garret.smith@REDACTED Fri Aug 21 19:06:08 2015 From: garret.smith@REDACTED (Garret Smith) Date: Fri, 21 Aug 2015 10:06:08 -0700 Subject: [erlang-questions] Testing api with jsongen and quickcheck In-Reply-To: References: Message-ID: On Fri, Aug 21, 2015 at 9:53 AM, Garret Smith wrote: > On Fri, Aug 21, 2015 at 9:27 AM, Mark Bruch wrote: >> Hi. >> >> I've got a small json api that is in desperate need for better >> testing. Read a little about jsongen [1] from the prowess project [2] >> that looks pretty awesome. Unfortunately it doesn't compile on any of >> my machines. >> Is anyone using jsongen, or is it just in "research"-stage? Can >> someone recommend me any other tool for testing a json api? >> >> Thanks >> Mark >> >> [1] https://github.com/fredlund/jsongen >> [2] http://www.prowessproject.eu >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > As far as I can tell, jsongen is just for Go, not Erlang. Is your > json api in Erlang? Or are you looking to test a json api using > erlang? > > -Garret Oops, my bad. I was looking at the wrong jsongen. This looks intriguing. Same questions though, are you writing Erlang tests against a json api, or tests against a json api written in Erlang? From kennethlakin@REDACTED Fri Aug 21 19:24:25 2015 From: kennethlakin@REDACTED (Kenneth Lakin) Date: Fri, 21 Aug 2015 10:24:25 -0700 Subject: [erlang-questions] Testing api with jsongen and quickcheck In-Reply-To: References: Message-ID: <55D75EC9.9090301@gmail.com> On 08/21/2015 09:27 AM, Mark Bruch wrote: > Unfortunately [jsongen] doesn't compile on any of > my machines. It fails to compile with rebar3 on my machine, too. Stupid question, but do you have QuickCheck installed? The missing include files that the build whines about seem to be related to QuickCheck. I found an eqcmini GitHub project, but that doesn't seem to provide enough to get jsongen to build. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From attila.r.nohl@REDACTED Fri Aug 21 19:31:12 2015 From: attila.r.nohl@REDACTED (Attila Rajmund Nohl) Date: Fri, 21 Aug 2015 19:31:12 +0200 Subject: [erlang-questions] Sending UDP packets In-Reply-To: References: Message-ID: Hello! Check the traffic on the network using wireshark or a similar tool and see what data is sent and in how many packets. 2015-08-21 14:15 GMT+02:00 Oscar Mu?oz Garrig?s : > Hi, > I am using a server to send some packets. The problem is actually the > packets are truncated and my client does not receive the full packet. I > created two sockets but only the socket wich receives the packet returns it > to the client, if i change it the packet is lost. Could you give me some > advice? > > Here is the code: > > > > -behaviour(gen_server). > init(_Args)-> > ... > {ok,Socket} = gen_udp:open(49900), > {ok, #state{socket=Socket}}. > > handle_info(Info, State)-> > error_logger:info_msg("Received via INFO: ~p~n", [Info]), > {udp, Socket, IP, InPortNo, Packet} = Info, > [{"from",From},{"to",To},{"text",Text}] = parser:read_xml(Packet), > > write_to_db(Socket, IP, InPortNo, From, To, Text), > {noreply, State}. > > write_to_db(WSocket, WAdress, WMPort, WFrom, WTo, WText)-> > ... > ... > Message = analizar_resultados(Respuesta), > > {ok, SSocket} = gen_udp:open(0,[inet]), > %%ok = gen_udp:send(SSocket, WAdress, WMPort, Message), <-------- This > does not works cause the packet is lost > ok = gen_udp:send(WSocket, WAdress, WMPort, Message), <-------- This > works but the packet is truncated > gen_udp:close(SSocket), > ok. > > > > > > Thank you all for your help. > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > From garret.smith@REDACTED Fri Aug 21 19:33:33 2015 From: garret.smith@REDACTED (Garret Smith) Date: Fri, 21 Aug 2015 10:33:33 -0700 Subject: [erlang-questions] Testing api with jsongen and quickcheck In-Reply-To: <55D75EC9.9090301@gmail.com> References: <55D75EC9.9090301@gmail.com> Message-ID: On Fri, Aug 21, 2015 at 10:24 AM, Kenneth Lakin wrote: > On 08/21/2015 09:27 AM, Mark Bruch wrote: >> Unfortunately [jsongen] doesn't compile on any of >> my machines. > > It fails to compile with rebar3 on my machine, too. > > Stupid question, but do you have QuickCheck installed? The missing > include files that the build whines about seem to be related to QuickCheck. > > I found an eqcmini GitHub project, but that doesn't seem to provide > enough to get jsongen to build. > > > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > Same problem with eqc.hrl here, once I replace 'make' with 'gmake' since I'm on FreeBSD. It's a different approach than jsongen, but I have a similar setup of a JSON API for an Erlang codebase. I'm using aeon* to convert JSON <=> Erlang records and sanitize the json input along the way. Since QuickCheck (and PropEr) can use the type info in Erlang records, you could: 1) Write Erlang records that correspond to your JSON 2) Use QC/PropEr to generate the Erlang records 3) Use aeon to convert the Erlang to JSON and call your API with it *aeon: https://github.com/garret-smith/aeon Yes, aeon is my own project. Hopefully others can use it too. -Garret From garret.smith@REDACTED Fri Aug 21 19:58:12 2015 From: garret.smith@REDACTED (Garret Smith) Date: Fri, 21 Aug 2015 10:58:12 -0700 Subject: [erlang-questions] Testing api with jsongen and quickcheck In-Reply-To: References: <55D75EC9.9090301@gmail.com> Message-ID: On Fri, Aug 21, 2015 at 10:45 AM, Mark Bruch wrote: > On Fri, Aug 21, 2015 at 7:33 PM, Garret Smith wrote: >> On Fri, Aug 21, 2015 at 10:24 AM, Kenneth Lakin wrote: >>> On 08/21/2015 09:27 AM, Mark Bruch wrote: >>>> Unfortunately [jsongen] doesn't compile on any of >>>> my machines. >>> >>> It fails to compile with rebar3 on my machine, too. >>> >>> Stupid question, but do you have QuickCheck installed? The missing >>> include files that the build whines about seem to be related to QuickCheck. >>> >>> I found an eqcmini GitHub project, but that doesn't seem to provide >>> enough to get jsongen to build. >>> >>> >>> >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >>> >> >> Same problem with eqc.hrl here, once I replace 'make' with 'gmake' >> since I'm on FreeBSD. >> >> It's a different approach than jsongen, but I have a similar setup of >> a JSON API for an Erlang codebase. >> I'm using aeon* to convert JSON <=> Erlang records and sanitize the >> json input along the way. >> Since QuickCheck (and PropEr) can use the type info in Erlang records, >> you could: >> 1) Write Erlang records that correspond to your JSON >> 2) Use QC/PropEr to generate the Erlang records >> 3) Use aeon to convert the Erlang to JSON and call your API with it >> >> *aeon: https://github.com/garret-smith/aeon >> >> Yes, aeon is my own project. Hopefully others can use it too. >> >> -Garret >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > Yes, I've got the full version of QuickCheck installed. > For me it complains on: "src/js_links_machine.erl:none: > double_occurence of callouts in js_links_machine. Only grouped > functions or ungrouped functions, not both" > > Thanks for the pointers Garret, that sounds like a good and easy way > to do it. Will give your aeon a go :) I'd love to hear your experiences. Hopefully doing it this way will give you better control over the testing since you're using Erlang types to generate the JSON. From mark.h.bruch@REDACTED Fri Aug 21 19:12:50 2015 From: mark.h.bruch@REDACTED (Mark Bruch) Date: Fri, 21 Aug 2015 19:12:50 +0200 Subject: [erlang-questions] Testing api with jsongen and quickcheck In-Reply-To: References: Message-ID: Yes it's an unfortunate name conflict. I'm want to write Erlang tests against my json api that I also have written in Erlang. Of course I could skip testing the json parsing and just shoot Erlang messages at it, but it feels like that should be plan B. On Fri, Aug 21, 2015 at 7:06 PM, Garret Smith wrote: > On Fri, Aug 21, 2015 at 9:53 AM, Garret Smith wrote: >> On Fri, Aug 21, 2015 at 9:27 AM, Mark Bruch wrote: >>> Hi. >>> >>> I've got a small json api that is in desperate need for better >>> testing. Read a little about jsongen [1] from the prowess project [2] >>> that looks pretty awesome. Unfortunately it doesn't compile on any of >>> my machines. >>> Is anyone using jsongen, or is it just in "research"-stage? Can >>> someone recommend me any other tool for testing a json api? >>> >>> Thanks >>> Mark >>> >>> [1] https://github.com/fredlund/jsongen >>> [2] http://www.prowessproject.eu >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >> >> As far as I can tell, jsongen is just for Go, not Erlang. Is your >> json api in Erlang? Or are you looking to test a json api using >> erlang? >> >> -Garret > > Oops, my bad. I was looking at the wrong jsongen. This looks > intriguing. Same questions though, are you writing Erlang tests > against a json api, or tests against a json api written in Erlang? From mark.h.bruch@REDACTED Fri Aug 21 19:45:54 2015 From: mark.h.bruch@REDACTED (Mark Bruch) Date: Fri, 21 Aug 2015 19:45:54 +0200 Subject: [erlang-questions] Testing api with jsongen and quickcheck In-Reply-To: References: <55D75EC9.9090301@gmail.com> Message-ID: On Fri, Aug 21, 2015 at 7:33 PM, Garret Smith wrote: > On Fri, Aug 21, 2015 at 10:24 AM, Kenneth Lakin wrote: >> On 08/21/2015 09:27 AM, Mark Bruch wrote: >>> Unfortunately [jsongen] doesn't compile on any of >>> my machines. >> >> It fails to compile with rebar3 on my machine, too. >> >> Stupid question, but do you have QuickCheck installed? The missing >> include files that the build whines about seem to be related to QuickCheck. >> >> I found an eqcmini GitHub project, but that doesn't seem to provide >> enough to get jsongen to build. >> >> >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> > > Same problem with eqc.hrl here, once I replace 'make' with 'gmake' > since I'm on FreeBSD. > > It's a different approach than jsongen, but I have a similar setup of > a JSON API for an Erlang codebase. > I'm using aeon* to convert JSON <=> Erlang records and sanitize the > json input along the way. > Since QuickCheck (and PropEr) can use the type info in Erlang records, > you could: > 1) Write Erlang records that correspond to your JSON > 2) Use QC/PropEr to generate the Erlang records > 3) Use aeon to convert the Erlang to JSON and call your API with it > > *aeon: https://github.com/garret-smith/aeon > > Yes, aeon is my own project. Hopefully others can use it too. > > -Garret > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions Yes, I've got the full version of QuickCheck installed. For me it complains on: "src/js_links_machine.erl:none: double_occurence of callouts in js_links_machine. Only grouped functions or ungrouped functions, not both" Thanks for the pointers Garret, that sounds like a good and easy way to do it. Will give your aeon a go :) From jim.rosenblum@REDACTED Sat Aug 22 04:37:15 2015 From: jim.rosenblum@REDACTED (jim rosenblum) Date: Fri, 21 Aug 2015 22:37:15 -0400 Subject: [erlang-questions] Surprising overhead to a Mnesia transaction: Message-ID: Dear List I need some Mnesia help, please. I will try to be precise in my question and give appropriate context: I am really grateful to all of you who help the rest of us cultivate some skill with Erlang. I developed a special-purpose, in-memory distributed cache for our company's Java application. It has been very successful thus far. My need was for a cache consisting of about 10,000 rows that needed to be distributed amongst 2 - 4 nodes and be capable of handling 100s of transactions per second at most. All operations (put, evict, etc.) can happen at any node. My current version has been in production, doing fine. According to basho_bench (admittedly synthetic), the cache is good to about 20,000 ops per second with mean latency for puts at 0.75 ms at the 95th percentile. And, up until now, all transactions have been in a sync-dirty context. As is typical in these types of environments we have a race-condition that we are trying to solve. Java client, A, does a put:(K, V0) to the cache while, at about the same time, another Java client, B, puts an updated version of the same key - put:(K,V1). And, of course, it can happen that the second write gets presented to the cache first putting the "newest" value, V1, in the cache and then the first write gets presented to the cache putting the "stale" V0 in the cache. Our strategy for addressing this is that the Java application will include a strictly monotonic sequence number with each Put. The cache will maintain a table that persists the highest sequence number that it has seen and if a Put with a smaller sequence number is presented to the cache, the cache rejects the Put; otherwise it writes the new sequence to the sequence table and does the Put. My implementation of the above involves having a replicated table which persists the highest sequence number seen, and I wrap the following steps in an async_transaction 1. Compare the sequence number in the Put with the "high-water-mark" sequence number 2. If the Put's sequence number is higher, do the put and update the high-water-mark; 3. else, abandon the put I knew that there would be a cost to a non-dirty transaction, but I was really surprised at the magnitude of the cost. Puts went from 20,000 ops per second with mean latency at 0.75 ms to 1,500 ops per second with mean latency of 12ms. So, now to my questions: 1. If I am trying to transactionally protect this sequence table, do I need to use sync_transaction or will async_transaction work. I don't understand what an ACID transaction means when there are more than 1 node and a transaction context which is async. If two Puts are happening on two different nodes, will one block until the other completes EVEN when in async mode? 2. is the magnitude of the performance hit seem "normal"? 3. Is there a better way to achieve what I am looking for then the above? Thanks very much... and some code if it helps... put(Key, Value, SeqNo) -> F = fun() -> case mnesia:wread(seq, global) of [] -> simple_put(Key, Value), mnesia:write(#seq{key=global, value = SeqNo}); [#seq{value = Old}=S] when SeqNo > Old -> simple_put(Key, Value), mnesia:write(S#seq{value = SeqNo}); [#seq{value = Old}] -> lager:warning("~p: out of order put. Map: ~p, Old: ~p, New: ~p.", [?MODULE, Old, SeqNo]), {out_of_seq, {put, Key, Old, SeqNo}} end end, case mnesia:sync_transaction(F) of {atomic, {out_of_seq, _}} = R -> R; {atomic, Result} -> Result; {aborted, Reason} -> {error, Reason} end. e -------------- next part -------------- An HTML attachment was scrubbed... URL: From dangud@REDACTED Sat Aug 22 08:44:43 2015 From: dangud@REDACTED (Dan Gudmundsson) Date: Sat, 22 Aug 2015 06:44:43 +0000 Subject: [erlang-questions] Surprising overhead to a Mnesia transaction: In-Reply-To: References: Message-ID: On Sat, Aug 22, 2015 at 4:37 AM jim rosenblum wrote: > Dear List > > So, now to my questions: > 1. If I am trying to transactionally protect this sequence table, do I > need to use sync_transaction or will async_transaction work. I don't > understand what an ACID transaction means when there are more than 1 node > and a transaction context which is async. If two Puts are happening on two > different nodes, will one block until the other completes EVEN when in > async mode? > In the normal case async should be fine, if you do not mix transactions and dirty operations, and do not cause an overload on mnesia_tm. In the async case a message to commit the transaction is broadcasted, and when one reply is received the transaction returns to user code. I.e. the transaction does not (as in the sync case) wait on every node to return a result, which is ok since no other transaction can get a write-lock on that record anyway until all nodes have commited the data and released the lock. 2. is the magnitude of the performance hit seem "normal"? > The difference between dirty and transaction are huge, dirty is a couple of ets read and ets write and a message send if remote table. Transactions grabs locks, for write on every involved node so you have communication internally and over the network. 3. Is there a better way to achieve what I am looking for then the above? > > > Thanks very much... and some code if it helps... > > > put(Key, Value, SeqNo) -> > F = fun() -> > case mnesia:wread(seq, global) of > [] -> > simple_put(Key, Value), > mnesia:write(#seq{key=global, value = SeqNo}); > [#seq{value = Old}=S] when SeqNo > Old -> > simple_put(Key, Value), > mnesia:write(S#seq{value = SeqNo}); > [#seq{value = Old}] -> > lager:warning("~p: out of order put. Map: ~p, Old: ~p, New: ~p.", > [?MODULE, Old, SeqNo]), > {out_of_seq, {put, Key, Old, SeqNo}} > end > end, > case mnesia:sync_transaction(F) of > {atomic, {out_of_seq, _}} = R -> > R; > {atomic, Result} -> > Result; > {aborted, Reason} -> > {error, Reason} > end. > > > > > e > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From felixgallo@REDACTED Sun Aug 23 02:15:05 2015 From: felixgallo@REDACTED (Felix Gallo) Date: Sat, 22 Aug 2015 17:15:05 -0700 Subject: [erlang-questions] escript standard archive layout Message-ID: I've recently had the opportunity to dive into escripts a little. Fascinating. I haven't been able to glean a few things from the documentation, however, and if anyone has experience with escripts, I'd love to hear their thoughts. 1. It looks like, if your OTP application named 'bob' with one dependency 'mary' looks like this: src/bob.erl ebin/bob.beam ebin/bob.app.src deps/mary/src/mary.erl deps/mary/ebin/mary.beam deps/mary/ebin/mary.app.src priv/secret.code that the code module wants to get an {archive, ZippedBinary} block that unzips to bob/ebin/bob.beam bob/ebin/bob.app.src mary/ebin/mary.app.src mary/ebin/mary.beam priv/secret.code is that, for want of a formal document, the accepted right way of forming an archive block, all else being equal? 2. Is there an escript 2nd-line (%%!) best practice/optimal options for most standard escripts that some old timer can recommend? F. -------------- next part -------------- An HTML attachment was scrubbed... URL: From eric.pailleau@REDACTED Sun Aug 23 14:32:45 2015 From: eric.pailleau@REDACTED (=?ISO-8859-1?Q?=C9ric_Pailleau?=) Date: Sun, 23 Aug 2015 14:32:45 +0200 Subject: [erlang-questions] escript standard archive layout In-Reply-To: Message-ID: <368c0eb6-81c0-405e-b8a2-893a73ef6ffe@email.android.com> Hello You may look at this plugin for erlang.mk : https://github.com/ninenines/erlang.mk/blob/master/plugins/escript.mk Regards Le?23 ao?t 2015 02:15, Felix Gallo a ?crit?: > > I've recently had the opportunity to dive into escripts a little.? Fascinating. ? > > I haven't been able to glean a few things from the documentation, however, and if anyone has experience with escripts, I'd love to hear their thoughts. > > 1.? It looks like, if your OTP application named 'bob' with one dependency 'mary' looks like this: > > src/bob.erl > ebin/bob.beam > ebin/bob.app.src > deps/mary/src/mary.erl > deps/mary/ebin/mary.beam > deps/mary/ebin/mary.app.src > priv/secret.code > > that the code module wants to get an {archive, ZippedBinary} block that unzips to > > bob/ebin/bob.beam > bob/ebin/bob.app.src > mary/ebin/mary.app.src > mary/ebin/mary.beam > priv/secret.code > > is that, for want of a formal document, the accepted right way of forming an archive block, all else being equal? > > 2.? Is there an escript 2nd-line (%%!) best practice/optimal options for most standard escripts that some old timer can recommend? > > F. From essen@REDACTED Sun Aug 23 14:35:30 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Sun, 23 Aug 2015 14:35:30 +0200 Subject: [erlang-questions] escript standard archive layout In-Reply-To: <368c0eb6-81c0-405e-b8a2-893a73ef6ffe@email.android.com> References: <368c0eb6-81c0-405e-b8a2-893a73ef6ffe@email.android.com> Message-ID: <55D9BE12.2060305@ninenines.eu> He did. This plugin is a user contribution with a particular layout (taken from mad), and we want to improve it. But as far as we can see there is no standard layout for escripts, hence the first question. On 08/23/2015 02:32 PM, ?ric Pailleau wrote: > Hello > You may look at this plugin for erlang.mk : > https://github.com/ninenines/erlang.mk/blob/master/plugins/escript.mk > > Regards > > Le 23 ao?t 2015 02:15, Felix Gallo a ?crit : >> >> I've recently had the opportunity to dive into escripts a little. Fascinating. >> >> I haven't been able to glean a few things from the documentation, however, and if anyone has experience with escripts, I'd love to hear their thoughts. >> >> 1. It looks like, if your OTP application named 'bob' with one dependency 'mary' looks like this: >> >> src/bob.erl >> ebin/bob.beam >> ebin/bob.app.src >> deps/mary/src/mary.erl >> deps/mary/ebin/mary.beam >> deps/mary/ebin/mary.app.src >> priv/secret.code >> >> that the code module wants to get an {archive, ZippedBinary} block that unzips to >> >> bob/ebin/bob.beam >> bob/ebin/bob.app.src >> mary/ebin/mary.app.src >> mary/ebin/mary.beam >> priv/secret.code >> >> is that, for want of a formal document, the accepted right way of forming an archive block, all else being equal? >> >> 2. Is there an escript 2nd-line (%%!) best practice/optimal options for most standard escripts that some old timer can recommend? >> >> F. > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From eric.pailleau@REDACTED Sun Aug 23 15:16:51 2015 From: eric.pailleau@REDACTED (=?ISO-8859-1?Q?=C9ric_Pailleau?=) Date: Sun, 23 Aug 2015 15:16:51 +0200 Subject: [erlang-questions] escript standard archive layout In-Reply-To: <55D9BE12.2060305@ninenines.eu> Message-ID: Hi Sorry, this plugin help me few month ago to better understand how an escript is built. But indeed looks like reverse ingeneering and more documentation is necessary. Regards Le?23 ao?t 2015 14:35, Lo?c Hoguin a ?crit?: > > He did. This plugin is a user contribution with a particular layout > (taken from mad), and we want to improve it. But as far as we can see > there is no standard layout for escripts, hence the first question. > > On 08/23/2015 02:32 PM, ?ric Pailleau wrote: > > Hello > > You may look at this plugin for erlang.mk : > > https://github.com/ninenines/erlang.mk/blob/master/plugins/escript.mk > > > > Regards > > > > Le 23 ao?t 2015 02:15, Felix Gallo a ?crit : > >> > >> I've recently had the opportunity to dive into escripts a little.? Fascinating. > >> > >> I haven't been able to glean a few things from the documentation, however, and if anyone has experience with escripts, I'd love to hear their thoughts. > >> > >> 1.? It looks like, if your OTP application named 'bob' with one dependency 'mary' looks like this: > >> > >> src/bob.erl > >> ebin/bob.beam > >> ebin/bob.app.src > >> deps/mary/src/mary.erl > >> deps/mary/ebin/mary.beam > >> deps/mary/ebin/mary.app.src > >> priv/secret.code > >> > >> that the code module wants to get an {archive, ZippedBinary} block that unzips to > >> > >> bob/ebin/bob.beam > >> bob/ebin/bob.app.src > >> mary/ebin/mary.app.src > >> mary/ebin/mary.beam > >> priv/secret.code > >> > >> is that, for want of a formal document, the accepted right way of forming an archive block, all else being equal? > >> > >> 2.? Is there an escript 2nd-line (%%!) best practice/optimal options for most standard escripts that some old timer can recommend? > >> > >> F. > > _______________________________________________ > > erlang-questions mailing list > > erlang-questions@REDACTED > > http://erlang.org/mailman/listinfo/erlang-questions > > > > -- > Lo?c Hoguin > http://ninenines.eu > Author of The Erlanger Playbook, > A book about software development using Erlang From ivan@REDACTED Sun Aug 23 19:05:40 2015 From: ivan@REDACTED (Ivan Uemlianin) Date: Sun, 23 Aug 2015 18:05:40 +0100 Subject: [erlang-questions] Merging maps with a fun like dict:merge/3 Message-ID: <55D9FD64.4080608@llaisdy.com> Dear All The maps module does not have a merge/3 like dict:merge/3, which calls a function fun(Key, Val1, Val2) when both dicts have the same key. From the documentation, "If a key occurs in both dictionaries then Fun is called with the key and both values to return a new value." The dict documentation says that dict:merge/3 is faster than an equivalent implemented in erlang. http://www.erlang.org/doc/man/dict.html#merge-3 Why does the maps module not have a similar merge/3? Is it because writing our own erlang implementation is at fast as it gets? Below is an implementation which seems to work. Can it be made faster? merge_maps(Fun, M1, M2) -> maps:fold(fun(K, V1, Acc) -> case maps:is_key(K, Acc) of false -> maps:put(K, V1, Acc); true -> V2 = maps:get(K, Acc), maps:put(K, Fun(K, V1, V2), Acc) end end, M1, M2). merge_maps_test() -> merge_maps(fun(_K, V1, V2) -> V1 + V2 end, #{a => 1, b => 2, c => 3}, #{b => 2, c => 3, d => 4}) =:= #{a => 1, b => 4, c => 6, d => 4}. With thanks and best wishes Ivan -- ============================================================ Ivan A. Uemlianin PhD Llaisdy Speech Technology Research and Development ivan@REDACTED @llaisdy llaisdy.wordpress.com github.com/llaisdy www.linkedin.com/in/ivanuemlianin festina lente ============================================================ From kennethlakin@REDACTED Sun Aug 23 23:10:54 2015 From: kennethlakin@REDACTED (Kenneth Lakin) Date: Sun, 23 Aug 2015 14:10:54 -0700 Subject: [erlang-questions] JCL mode remote shell start annoyance Message-ID: <55DA36DE.3040805@gmail.com> I've been playing around with distributed Erlang and remote shells today. For a few minutes, I was somewhat convinced that remote shells *only* worked with nodes started with the -sname flag. Playing around with net_adm:ping/1 reminded me that node names are atoms, and I should *probably* enclose a node name that contains '.' in single quotes. Lo and behold, this made the JCL mode 'r' command happy. Would it break anything to make the JCL mode 'r' command wrap the provided remote node name in single quotes if it hasn't already been wrapped by the user? If this isn't feasible, could the error message be changed from "Unknown command" to something more descriptive? (Maybe something like "Error. Try single quotes around node name."?) For clarity, a transcript of my shell conversation follows: $ ERL_EPMD_ADDRESS="127.0.0.1" erl -name observer -hidden Erlang/OTP 18 [erts-7.0] [source] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false] Eshell V7.0 (abort with ^G) (observer@REDACTED)1> User switch command --> r remote-node@REDACTED Unknown command --> j 1* {shell,start,[init]} --> r 'remote-node@REDACTED' --> j 1 {shell,start,[init]} 2* {'remote-node@REDACTED',shell,start,[]} --> q $ -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From Tobias.Schlager@REDACTED Mon Aug 24 11:52:23 2015 From: Tobias.Schlager@REDACTED (Tobias Schlager) Date: Mon, 24 Aug 2015 09:52:23 +0000 Subject: [erlang-questions] escript standard archive layout In-Reply-To: References: Message-ID: <12F2115FD1CCEE4294943B2608A18FA301A233F718@MAIL01.win.lbaum.eu> Hi, AFAIK, the layout you propose under 1. is correct. Additionally, the code server is also able to handle something like this (application name and version): bob-1.0.0/ebin/bob.beam bob-1.0.0/ebin/bob.app.src mary-2.0.0/ebin/mary.app.src mary-2.0.0/ebin/mary.beam Packaging priv directories doesn't make much sense, since there's no automagic way to get the files' content at runtime. Even if you package priv directories in a standard location (in your case bob/priv/secret.code), the code server will return a non-existent path for code:priv_dir(bob) and you can't access the files with the file module. You'll have to use the erl_prim_loader module to extract file contents (other than .beam) from .ez archives (this also applies for embedded archives). I worked around this limitation when writing the rebar_escript_plugin [1] to create standalone escripts. Look at the rebar_escript_plugin_runner module to see erl_prim_loader in action. Regards Tobias [1] https://github.com/schlagert/rebar_escript_plugin ________________________________ Von: erlang-questions-bounces@REDACTED [erlang-questions-bounces@REDACTED]" im Auftrag von "Felix Gallo [felixgallo@REDACTED] Gesendet: Sonntag, 23. August 2015 02:15 An: erlang-questions@REDACTED Betreff: [erlang-questions] escript standard archive layout I've recently had the opportunity to dive into escripts a little. Fascinating. I haven't been able to glean a few things from the documentation, however, and if anyone has experience with escripts, I'd love to hear their thoughts. 1. It looks like, if your OTP application named 'bob' with one dependency 'mary' looks like this: src/bob.erl ebin/bob.beam ebin/bob.app.src deps/mary/src/mary.erl deps/mary/ebin/mary.beam deps/mary/ebin/mary.app.src priv/secret.code that the code module wants to get an {archive, ZippedBinary} block that unzips to bob/ebin/bob.beam bob/ebin/bob.app.src mary/ebin/mary.app.src mary/ebin/mary.beam priv/secret.code is that, for want of a formal document, the accepted right way of forming an archive block, all else being equal? 2. Is there an escript 2nd-line (%%!) best practice/optimal options for most standard escripts that some old timer can recommend? F. -------------- next part -------------- An HTML attachment was scrubbed... URL: From rj@REDACTED Mon Aug 24 18:20:16 2015 From: rj@REDACTED (Richard Jones) Date: Mon, 24 Aug 2015 17:20:16 +0100 Subject: [erlang-questions] release handler crash during relup, sys:get_status noproc Message-ID: Anyone else experienced a crash like this when doing a release upgrade? ie, calling release_handler:install_release, with a valid relup {"init terminating in do_boot",{{badmatch,{error,{'EXIT',{noproc,{sys,get_status,[<6453.14610.13>]}}}}},[{erl_eval,expr,3,[]}]}} I've seen this a couple of times now (erlang 17.x) when upgrading production systems under load, even with a trivial relup. No idea what that pid was. I think it might be a race in release_handler_1 where it calls sys:get_status without a catch, when the process in question may have been a supervision tree that had legitimately shut down since the list of pids was fetched. ie: https://github.com/erlang/otp/blob/OTP-17.5.6.3/lib/sasl/src/release_handler_1.erl#L589 which calls get_proc_state, which does: {status, _, {module, _}, [_, State, _, _, _]} = sys:get_status(Proc) I've not managed to make a test for this yet, planning to spam lots of terminate_childs to a busy supervisor while calling release_handler_1:get_supervised_procs to try and reproduce. If i'm right, it would only be triggered if parts of a supervision tree are shutting down during a release_upgrade, which perhaps isn't very common, depending on how dynamic the average supervision tree is in erlang apps. Any feedback appreciated before I spend more time studying release handler code :) RJ -------------- next part -------------- An HTML attachment was scrubbed... URL: From co7eb@REDACTED Mon Aug 24 22:20:30 2015 From: co7eb@REDACTED (Ivan Carmenates Garcia) Date: Mon, 24 Aug 2015 16:20:30 -0400 Subject: [erlang-questions] I need some advices for a framework I'm doing Message-ID: <000001d0deaa$5479cf20$fd6d6d60$@frcuba.co.cu> Hi everyone, I am making a little framework for cowboy, but in general what I need is some advices regards final looking, i.e.: I have implemented a multi database backend connection pool that manages available connections for me. Here is an example: database_manager:connection_session(fun(DBSession) -> {ok, 1, #{id : UserID}} = database_manager:insert_and_return(DBSession, {users, #{ username => security_lib:generate_unique_id(), password => security_lib:hash_password(security_lib:generate_unique_id()), password_old => security_lib:hash_password(security_lib:generate_unique_id()), online => true, last_online_date => datetime_lib:universal_datetime(), created_date => datetime_lib:universal_datetime(), activation_email => security_lib:generate_unique_id() ++ "@eoc.com"}}, %% returning id!!! [id], [{result_format, map}]), {ok, 1} = database_manager:insert(DBSession, {user_activation_tokens, #{ user_id => UserID, activation_token => security_lib:hash_random(integer_to_list(UserID)) }}) end, postgres_backend), database_manager:connection_session/2 gives me an available connection for a postgres backend in this case, and inside of It I can make any query I want, using DBSession information to redirect the query to the appropriate backend. So anywhere I want I can call database_manager:connection_session/2 to obtain a database connection from any backend, I have to specify the backend I will use at the end, because I could simultaneously use the backend I want to access many different database systems at the same time. But later I think that if writing all over the code the backend I will use, then if I want to change the database I have to check all the source code and changes the backend, later I came up with an idea of setting an alias and use the alias instead so in the app.config file I just need to change the database configuration and backend for an specific alias, but I don't know, seems too much work to do to implement it. What I want to know is that if as it is seems look nice and is a good idea to have a connection_session available all over the place, because other framework what they do is simply call an insert or a find function and the connection is managed under the hood, that seems fine, but I don't know why I like my implementation, seems to me like I have the control over the connection I want and use it until I want. You can also choose in each function insert or find how you want the result data to be, if in map format or proplist or simple raw as the database driver says. I have another interesting things like handler/action routes that matches a handler module and a function as an action, pretty similar to ChicagoBoss, but just I like it more ;). And the last thing I do, is that you can change any of your code in the fly, just by refreshing the page and just the recently changed code got compiled and reload. Pretty fast for development mode proposes, for production I just need to call ec_control:recompile_all() and has the same effect than refreshing the page but only that it is when I wanted. Work pretty well to me. I also have sessions mechanism, url parameters like /param-value1-value2/param2-value3. etc and many other interesting things. Today I even don't sleep programing, lol, I like when things get interesting. Well anybody could give some advices to improve it, I will put it on github as soon as it is ready at least to test it. I also need to implement other backends, it is pretty easy because it is a template module free of dirty code, simple as putting a name you want and implement a certain interface, and later just use the same name in connection_session/2 calls, and database manager manages to redirect and handles the calls and connection pool, you need also to install it, calling database_manager:install_backend/2 to create its connection pool and all its stuffs, you can remove it the same. -------------- next part -------------- An HTML attachment was scrubbed... URL: From eric.pailleau@REDACTED Mon Aug 24 22:55:15 2015 From: eric.pailleau@REDACTED (=?ISO-8859-1?Q?=C9ric_Pailleau?=) Date: Mon, 24 Aug 2015 22:55:15 +0200 Subject: [erlang-questions] release handler crash during relup, sys:get_status noproc In-Reply-To: Message-ID: <978e125d-6474-4dfc-9258-9be24def9abe@email.android.com> Hi, Pid not beginning with 0 is not a local Pid. Is your release upgradeing a distributed application ? Le?24 ao?t 2015 18:20, Richard Jones a ?crit?: > > Anyone else experienced a crash like this when doing a release upgrade? > ie, calling release_handler:install_release, with a valid relup > > {"init terminating in do_boot",{{badmatch,{error,{'EXIT',{noproc,{sys,get_status,[<6453.14610.13>]}}}}},[{erl_eval,expr,3,[]}]}} > > I've seen this a couple of times now (erlang 17.x) when upgrading production systems under load, even with a trivial relup. No idea what that pid was. > > I think it might be a race in release_handler_1 where it calls sys:get_status without a catch, when the process in question may have been a supervision tree that had legitimately shut down since the list of pids was fetched. > > ie: > > https://github.com/erlang/otp/blob/OTP-17.5.6.3/lib/sasl/src/release_handler_1.erl#L589 > > which calls get_proc_state, which does: > > {status, _, {module, _}, [_, State, _, _, _]} = sys:get_status(Proc) > > I've not managed to make a test for this yet, planning to spam lots of terminate_childs to a busy supervisor while calling release_handler_1:get_supervised_procs to try and reproduce. > > If i'm right, it would only be triggered if parts of a supervision tree are shutting down during a release_upgrade, which perhaps isn't very common, depending on how dynamic the average supervision tree is in erlang apps. > > Any feedback appreciated before I spend more time studying release handler code :) > > RJ > > > > > From rj@REDACTED Mon Aug 24 23:29:08 2015 From: rj@REDACTED (Richard Jones) Date: Mon, 24 Aug 2015 22:29:08 +0100 Subject: [erlang-questions] release handler crash during relup, sys:get_status noproc In-Reply-To: <978e125d-6474-4dfc-9258-9be24def9abe@email.android.com> References: <978e125d-6474-4dfc-9258-9be24def9abe@email.android.com> Message-ID: Hi, It's not a distributed application. Release handler is called from another script, as part of the deployment process. It runs "erl -name deployer@REDACTED -setcookie .. " and then does rpc:call(TargetNode, release_handler, ....) RJ On 24 Aug 2015 21:55, "?ric Pailleau" wrote: > Hi, > > Pid not beginning with 0 is not a local Pid. > Is your release upgradeing a distributed application ? > > > Le 24 ao?t 2015 18:20, Richard Jones a ?crit : > > > > Anyone else experienced a crash like this when doing a release upgrade? > > ie, calling release_handler:install_release, with a valid relup > > > > {"init terminating in > do_boot",{{badmatch,{error,{'EXIT',{noproc,{sys,get_status,[<6453.14610.13>]}}}}},[{erl_eval,expr,3,[]}]}} > > > > I've seen this a couple of times now (erlang 17.x) when upgrading > production systems under load, even with a trivial relup. No idea what that > pid was. > > > > I think it might be a race in release_handler_1 where it calls > sys:get_status without a catch, when the process in question may have been > a supervision tree that had legitimately shut down since the list of pids > was fetched. > > > > ie: > > > > > https://github.com/erlang/otp/blob/OTP-17.5.6.3/lib/sasl/src/release_handler_1.erl#L589 > > > > which calls get_proc_state, which does: > > > > {status, _, {module, _}, [_, State, _, _, _]} = sys:get_status(Proc) > > > > I've not managed to make a test for this yet, planning to spam lots of > terminate_childs to a busy supervisor while calling > release_handler_1:get_supervised_procs to try and reproduce. > > > > If i'm right, it would only be triggered if parts of a supervision tree > are shutting down during a release_upgrade, which perhaps isn't very > common, depending on how dynamic the average supervision tree is in erlang > apps. > > > > Any feedback appreciated before I spend more time studying release > handler code :) > > > > RJ > > > > > > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From essen@REDACTED Mon Aug 24 23:45:05 2015 From: essen@REDACTED (=?UTF-8?B?TG/Dr2MgSG9ndWlu?=) Date: Mon, 24 Aug 2015 23:45:05 +0200 Subject: [erlang-questions] I need some advices for a framework I'm doing In-Reply-To: <000001d0deaa$5479cf20$fd6d6d60$@frcuba.co.cu> References: <000001d0deaa$5479cf20$fd6d6d60$@frcuba.co.cu> Message-ID: <55DB9061.8050501@ninenines.eu> On 08/24/2015 10:20 PM, Ivan Carmenates Garcia wrote: > Hi everyone, I am making a little framework for cowboy, but in general > what I need is some advices regards final looking, i.e.: OK I am a bit lost on everything you explained so allow me to give some generic advice: * Make it work * Start making apps with it * Notice everything inefficient in how you now write apps * Update your framework * Repeat Practice makes perfect. Add a little of looking at how everyone else does things in the mix to get ideas; sometimes you will notice something is bad in your framework but have no idea how to make it better, that's why you need to look elsewhere. Sometimes the idea might come from a completely unrelated source. A few more things: * Keep it simple and explicit * Focus on the use cases that benefit the majority of users * Choose good, short names * Write a user guide when things stabilize On the last point, you want the guide separate from code entirely because this forces you to think about how you really use it rather than just documenting functions or modules one after another. Think of it like writing a book, except the only role of this book is to explain to others *what* they can do with your framework and *why* they will do things that way. Once you get there, you should have a pretty good product, and you'll most likely have gotten a ton of users along the way. Cheers, -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From mark.h.bruch@REDACTED Tue Aug 25 00:41:29 2015 From: mark.h.bruch@REDACTED (Mark Bruch) Date: Tue, 25 Aug 2015 00:41:29 +0200 Subject: [erlang-questions] Testing api with jsongen and quickcheck In-Reply-To: References: <55D75EC9.9090301@gmail.com> Message-ID: On Fri, Aug 21, 2015 at 7:58 PM, Garret Smith wrote: > On Fri, Aug 21, 2015 at 10:45 AM, Mark Bruch wrote: >> On Fri, Aug 21, 2015 at 7:33 PM, Garret Smith wrote: >>> On Fri, Aug 21, 2015 at 10:24 AM, Kenneth Lakin wrote: >>>> On 08/21/2015 09:27 AM, Mark Bruch wrote: >>>>> Unfortunately [jsongen] doesn't compile on any of >>>>> my machines. >>>> >>>> It fails to compile with rebar3 on my machine, too. >>>> >>>> Stupid question, but do you have QuickCheck installed? The missing >>>> include files that the build whines about seem to be related to QuickCheck. >>>> >>>> I found an eqcmini GitHub project, but that doesn't seem to provide >>>> enough to get jsongen to build. >>>> >>>> >>>> >>>> >>>> _______________________________________________ >>>> erlang-questions mailing list >>>> erlang-questions@REDACTED >>>> http://erlang.org/mailman/listinfo/erlang-questions >>>> >>> >>> Same problem with eqc.hrl here, once I replace 'make' with 'gmake' >>> since I'm on FreeBSD. >>> >>> It's a different approach than jsongen, but I have a similar setup of >>> a JSON API for an Erlang codebase. >>> I'm using aeon* to convert JSON <=> Erlang records and sanitize the >>> json input along the way. >>> Since QuickCheck (and PropEr) can use the type info in Erlang records, >>> you could: >>> 1) Write Erlang records that correspond to your JSON >>> 2) Use QC/PropEr to generate the Erlang records >>> 3) Use aeon to convert the Erlang to JSON and call your API with it >>> >>> *aeon: https://github.com/garret-smith/aeon >>> >>> Yes, aeon is my own project. Hopefully others can use it too. >>> >>> -Garret >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >> >> Yes, I've got the full version of QuickCheck installed. >> For me it complains on: "src/js_links_machine.erl:none: >> double_occurence of callouts in js_links_machine. Only grouped >> functions or ungrouped functions, not both" >> >> Thanks for the pointers Garret, that sounds like a good and easy way >> to do it. Will give your aeon a go :) > > I'd love to hear your experiences. Hopefully doing it this way will > give you better control over the testing since you're using Erlang > types to generate the JSON. Managed to create some property based tests for my API today and it turned out awesome! :) The only thing that could have made aeon a better fit is if was possible to set fields to optional, so that missing fields in the JSON-input doesn't give validation errors when converting to a record. Would rather do validation with something like jesse [1] and allow fields to be optional. All in all I'm extremely pleased how it turned out, so thanks a lot Garret and Kenneth! Now off to fix the bugs that the tests found... ;) [1] https://github.com/klarna/jesse From r.wobben@REDACTED Tue Aug 25 14:16:03 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Tue, 25 Aug 2015 14:16:03 +0200 Subject: [erlang-questions] json to map Message-ID: <55DC5C83.2070409@home.nl> Hello, As a challenge I need to convert a json file to a erlang map. So I have this file : { "foo": { "id": 1, "username": "Foo Foo", "first": "Foo", "last": "Foo", "password": "foo", "email": "foo@REDACTED", "scope": ["admin", "user"] }, "bar": { "id": 2, "username": "Bar Head", "first": "Bar", "last": "Head", "password": "bar", "email": "bar@REDACTED", "scope": ["user"] } } as far as I can see it's a tuple of tuples. What are the steps to convert it. I do not need the code just some steps which point me to the right direction. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From bengt.kleberg@REDACTED Tue Aug 25 14:21:24 2015 From: bengt.kleberg@REDACTED (Bengt Kleberg) Date: Tue, 25 Aug 2015 14:21:24 +0200 Subject: [erlang-questions] json to map In-Reply-To: <55DC5C83.2070409@home.nl> References: <55DC5C83.2070409@home.nl> Message-ID: <55DC5DC4.50402@ericsson.com> Greetings, If you replace all : with , and add a final . you can use file:consult/1 to read the file directly. bengt On 08/25/2015 02:16 PM, Roelof Wobben wrote: > Hello, > > As a challenge I need to convert a json file to a erlang map. > > So I have this file : > > { > "foo": { > "id": 1, > "username": "Foo Foo", > "first": "Foo", > "last": "Foo", > "password": "foo", > "email": "foo@REDACTED", > "scope": ["admin", "user"] > }, > "bar": { > "id": 2, > "username": "Bar Head", > "first": "Bar", > "last": "Head", > "password": "bar", > "email": "bar@REDACTED", > "scope": ["user"] > } > } > > > as far as I can see it's a tuple of tuples. > What are the steps to convert it. > > I do not need the code just some steps which point me to the right > direction. > > Roelof > > > --- > Dit e-mailbericht is gecontroleerd op virussen met Avast > antivirussoftware. > https://www.avast.com/antivirus > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From kennethlakin@REDACTED Tue Aug 25 14:26:27 2015 From: kennethlakin@REDACTED (Kenneth Lakin) Date: Tue, 25 Aug 2015 05:26:27 -0700 Subject: [erlang-questions] json to map In-Reply-To: <55DC5DC4.50402@ericsson.com> References: <55DC5C83.2070409@home.nl> <55DC5DC4.50402@ericsson.com> Message-ID: <55DC5EF3.9090305@gmail.com> On 08/25/2015 05:21 AM, Bengt Kleberg wrote: > Greetings, > > If you replace all > : > with > , > > and add a final > . That's an *excellent* suggestion! I was unaware of file:consult/1. I bet that one could play with the replacement character to make map conversion even easier. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From kennethlakin@REDACTED Tue Aug 25 14:40:15 2015 From: kennethlakin@REDACTED (Kenneth Lakin) Date: Tue, 25 Aug 2015 05:40:15 -0700 Subject: [erlang-questions] json to map In-Reply-To: <55DC5C83.2070409@home.nl> References: <55DC5C83.2070409@home.nl> Message-ID: <55DC622F.8080405@gmail.com> On 08/25/2015 05:16 AM, Roelof Wobben wrote: > I do not need the code just some steps which point me to the right > direction. Also, if you end up trying to convert a string containing JSON -rather than a file-, the results of the Google search for "erlang string to terms" turns up an interesting erlang-questions thread from way back. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From g@REDACTED Tue Aug 25 14:45:59 2015 From: g@REDACTED (Garrett Smith) Date: Tue, 25 Aug 2015 07:45:59 -0500 Subject: [erlang-questions] json to map In-Reply-To: <55DC5DC4.50402@ericsson.com> References: <55DC5C83.2070409@home.nl> <55DC5DC4.50402@ericsson.com> Message-ID: Doesn't seem very challenging :) But that's a valid point - a good programmer cheats! Another cheat would be to use a JSON parsing library. Again not particularly challenging, but it does send you down the road of "find an existing solution to a problem, rather than roll your own". For serious fun, write a parser! You could roll your own, or again cheat by using Erlang's pretty darn good yecc module: http://erlang.org/doc/man/yecc.html On Tue, Aug 25, 2015 at 7:21 AM, Bengt Kleberg wrote: > Greetings, > > If you replace all > : > with > , > > and add a final > . > > you can use file:consult/1 to read the file directly. > > > bengt > > > On 08/25/2015 02:16 PM, Roelof Wobben wrote: >> >> Hello, >> >> As a challenge I need to convert a json file to a erlang map. >> >> So I have this file : >> >> { >> "foo": { >> "id": 1, >> "username": "Foo Foo", >> "first": "Foo", >> "last": "Foo", >> "password": "foo", >> "email": "foo@REDACTED", >> "scope": ["admin", "user"] >> }, >> "bar": { >> "id": 2, >> "username": "Bar Head", >> "first": "Bar", >> "last": "Head", >> "password": "bar", >> "email": "bar@REDACTED", >> "scope": ["user"] >> } >> } >> >> >> as far as I can see it's a tuple of tuples. >> What are the steps to convert it. >> >> I do not need the code just some steps which point me to the right >> direction. >> >> Roelof >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast >> antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From tony@REDACTED Tue Aug 25 15:21:05 2015 From: tony@REDACTED (Tony Rogvall) Date: Tue, 25 Aug 2015 15:21:05 +0200 Subject: [erlang-questions] json to map In-Reply-To: <55DC5DC4.50402@ericsson.com> References: <55DC5C83.2070409@home.nl> <55DC5DC4.50402@ericsson.com> Message-ID: <96D019D7-94FF-4E91-A388-392857049951@rogvall.se> Or even replace: { with #{ : with => and add the final dot. :-) /Tony > On 25 aug 2015, at 14:21, Bengt Kleberg wrote: > > Greetings, > > If you replace all > : > with > , > > and add a final > . > > you can use file:consult/1 to read the file directly. > > > bengt > > On 08/25/2015 02:16 PM, Roelof Wobben wrote: >> Hello, >> >> As a challenge I need to convert a json file to a erlang map. >> >> So I have this file : >> >> { >> "foo": { >> "id": 1, >> "username": "Foo Foo", >> "first": "Foo", >> "last": "Foo", >> "password": "foo", >> "email": "foo@REDACTED", >> "scope": ["admin", "user"] >> }, >> "bar": { >> "id": 2, >> "username": "Bar Head", >> "first": "Bar", >> "last": "Head", >> "password": "bar", >> "email": "bar@REDACTED", >> "scope": ["user"] >> } >> } >> >> >> as far as I can see it's a tuple of tuples. >> What are the steps to convert it. >> >> I do not need the code just some steps which point me to the right direction. >> >> Roelof >> >> >> --- >> Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. >> https://www.avast.com/antivirus >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: Message signed with OpenPGP using GPGMail URL: From r.wobben@REDACTED Tue Aug 25 16:49:38 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Tue, 25 Aug 2015 16:49:38 +0200 Subject: [erlang-questions] json to map In-Reply-To: References: <55DC5C83.2070409@home.nl> <55DC5DC4.50402@ericsson.com> Message-ID: <55DC8082.7020000@home.nl> Op 25-8-2015 om 14:45 schreef Garrett Smith: > Doesn't seem very challenging :) > > But that's a valid point - a good programmer cheats! > > Another cheat would be to use a JSON parsing library. Again not > particularly challenging, but it does send you down the road of "find > an existing solution to a problem, rather than roll your own". > > For serious fun, write a parser! You could roll your own, or again > cheat by using Erlang's pretty darn good yecc module: > > http://erlang.org/doc/man/yecc.html > > Hello Gareth, That seems to be a good idea to keep me busy for some days. I will read a lot about that topic and hopefully I can make this work. Roelof --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From co7eb@REDACTED Tue Aug 25 17:58:09 2015 From: co7eb@REDACTED (Ivan Carmenates Garcia) Date: Tue, 25 Aug 2015 11:58:09 -0400 Subject: [erlang-questions] I need some advices for a framework I'm doing In-Reply-To: <55DB9061.8050501@ninenines.eu> References: <000001d0deaa$5479cf20$fd6d6d60$@frcuba.co.cu> <55DB9061.8050501@ninenines.eu> Message-ID: <000001d0df4e$d852e9e0$88f8bda0$@frcuba.co.cu> Hi, Well the good news here is that I am making it together with a system a am also doing so, it any problems present I will notice they quickly and at the same time I will get feedbacks. Regards documentation, that one of the thing a love more, so it will be plenty of it, with a lot of examples and explanations. Currently the code doc for any function and even examples of how to use them. i.e. this is a nice doc for one of the functions: %% ------------------------------------------------------------------- %% @doc %% Makes a query to a database using a 'DBSession'. %% Returns a 'ResultData': %% - 'ResultData' depends of 'result_format' Option. %% - 'result_format' could be one of 'raw', 'proplist', 'map'. %% - 'proplist' and 'map' result formats have the same %% 'ResultData' struct: %% {ok, Data} when using 'select'. %% {ok, Count} when using 'update', 'insert', 'delete'. %% {ok, Count, Data} when using 'update', 'insert' with returning. %% The only differences are: %% 0 results: %% 'map' -> no_data, %% 'proplist' -> [], %% 1 result: %% 'map' -> a single map #{...}, %% 'proplist' -> a list of proplist [[...]], (template compatible) %% N results: %% 'map' -> a list of maps [#{...}, ...], %% 'proplist' -> a list of proplists [[...], ...], %% 'raw' by the other hand is 'Backend' dependent. %% Example: %% {ok, #{id := Id}} = database_manager:query(DBSession, %% Query, Params, [{result_format, map}]). %% NOTE: 'map' is the default result format for 'query/3' function. %% NOTE: All result format has its pros and cons, 'raw' is the fastest %% but uncomfortable to deal with, 'map' is the slowest but very %% easy to deal with. So this is the performance order from %% fastest to slowest 'raw' > 'proplist' > 'map'. 'proplist' can %% be used to return directly to a template. %% @end %% ------------------------------------------------------------------- -spec query(DBSession, Query, Params, Options) -> ResultData | {error, Reason} when DBSession :: db_session(), Query :: string() | bitstring(), Params :: [] | [any(), ...], Options :: proplists:proplist(), ResultData :: any(), Reason :: term(). query({Backend, Connection}, Query, Params, Options) -> %% executes query/4 in the current 'Backend'. Backend:query(Connection, Query, Params, Options). Anyone have more suggestions I could use?, thanks in advantage. Regards, Ivan. -----Original Message----- From: Lo?c Hoguin [mailto:essen@REDACTED] Sent: Monday, August 24, 2015 5:45 PM To: Ivan Carmenates Garcia; erlang-questions@REDACTED Subject: Re: [erlang-questions] I need some advices for a framework I'm doing On 08/24/2015 10:20 PM, Ivan Carmenates Garcia wrote: > Hi everyone, I am making a little framework for cowboy, but in general > what I need is some advices regards final looking, i.e.: OK I am a bit lost on everything you explained so allow me to give some generic advice: * Make it work * Start making apps with it * Notice everything inefficient in how you now write apps * Update your framework * Repeat Practice makes perfect. Add a little of looking at how everyone else does things in the mix to get ideas; sometimes you will notice something is bad in your framework but have no idea how to make it better, that's why you need to look elsewhere. Sometimes the idea might come from a completely unrelated source. A few more things: * Keep it simple and explicit * Focus on the use cases that benefit the majority of users * Choose good, short names * Write a user guide when things stabilize On the last point, you want the guide separate from code entirely because this forces you to think about how you really use it rather than just documenting functions or modules one after another. Think of it like writing a book, except the only role of this book is to explain to others *what* they can do with your framework and *why* they will do things that way. Once you get there, you should have a pretty good product, and you'll most likely have gotten a ton of users along the way. Cheers, -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang -------------- next part -------------- An HTML attachment was scrubbed... URL: From co7eb@REDACTED Tue Aug 25 20:11:50 2015 From: co7eb@REDACTED (Ivan Carmenates Garcia) Date: Tue, 25 Aug 2015 14:11:50 -0400 Subject: [erlang-questions] I need some advices for a framework I'm doing In-Reply-To: <000001d0deaa$5479cf20$fd6d6d60$@frcuba.co.cu> References: <000001d0deaa$5479cf20$fd6d6d60$@frcuba.co.cu> Message-ID: <000001d0df61$857f2b30$907d8190$@frcuba.co.cu> I think the idea of an alias is not so bad, that's what I did. Before I had {database_manager, [ {postgres_backend, [ {server, "localhost"}, {username, "postgres"}, {password, "server"}, {database, "eoc_db"}, %% max amount of database connections in the connection pool. {max_reusable_connections, 10}, % 10 connections. %% max time it will wait for an available connection. {wait_for_reusable_connection_timeout, 5000} % 5 seconds. ]} ]}, Now I have: {database_manager, [ {main_backend, [ {backend, postgres_backend}, {server, "localhost"}, {username, "postgres"}, {password, "server"}, {database, "eoc_db"}, %% max amount of database connections in the connection pool. {max_reusable_connections, 10}, % 10 connections. %% max time it will wait for an available connection. {wait_for_reusable_connection_timeout, 5000} % 5 seconds. ]} ]}, Then I can safely use database:connection_session(fun(DBSession)-> . end, main_backend). So if I have to change the database I only need to change the configuration for main_backend to use anther backend module with other config. That enables me to have multiple postgres backend for example under different alias. And I could name backends with names I like, ie, main_backend, backup_backend, other_stuffs. Cheers, Ivan. From: erlang-questions-bounces@REDACTED [mailto:erlang-questions-bounces@REDACTED] On Behalf Of Ivan Carmenates Garcia Sent: Monday, August 24, 2015 4:21 PM To: erlang-questions@REDACTED Subject: [erlang-questions] I need some advices for a framework I'm doing Hi everyone, I am making a little framework for cowboy, but in general what I need is some advices regards final looking, i.e.: I have implemented a multi database backend connection pool that manages available connections for me. Here is an example: database_manager:connection_session(fun(DBSession) -> {ok, 1, #{id : UserID}} = database_manager:insert_and_return(DBSession, {users, #{ username => security_lib:generate_unique_id(), password => security_lib:hash_password(security_lib:generate_unique_id()), password_old => security_lib:hash_password(security_lib:generate_unique_id()), online => true, last_online_date => datetime_lib:universal_datetime(), created_date => datetime_lib:universal_datetime(), activation_email => security_lib:generate_unique_id() ++ "@eoc.com"}}, %% returning id!!! [id], [{result_format, map}]), {ok, 1} = database_manager:insert(DBSession, {user_activation_tokens, #{ user_id => UserID, activation_token => security_lib:hash_random(integer_to_list(UserID)) }}) end, postgres_backend), database_manager:connection_session/2 gives me an available connection for a postgres backend in this case, and inside of It I can make any query I want, using DBSession information to redirect the query to the appropriate backend. So anywhere I want I can call database_manager:connection_session/2 to obtain a database connection from any backend, I have to specify the backend I will use at the end, because I could simultaneously use the backend I want to access many different database systems at the same time. But later I think that if writing all over the code the backend I will use, then if I want to change the database I have to check all the source code and changes the backend, later I came up with an idea of setting an alias and use the alias instead so in the app.config file I just need to change the database configuration and backend for an specific alias, but I don't know, seems too much work to do to implement it. What I want to know is that if as it is seems look nice and is a good idea to have a connection_session available all over the place, because other framework what they do is simply call an insert or a find function and the connection is managed under the hood, that seems fine, but I don't know why I like my implementation, seems to me like I have the control over the connection I want and use it until I want. You can also choose in each function insert or find how you want the result data to be, if in map format or proplist or simple raw as the database driver says. I have another interesting things like handler/action routes that matches a handler module and a function as an action, pretty similar to ChicagoBoss, but just I like it more ;). And the last thing I do, is that you can change any of your code in the fly, just by refreshing the page and just the recently changed code got compiled and reload. Pretty fast for development mode proposes, for production I just need to call ec_control:recompile_all() and has the same effect than refreshing the page but only that it is when I wanted. Work pretty well to me. I also have sessions mechanism, url parameters like /param-value1-value2/param2-value3. etc and many other interesting things. Today I even don't sleep programing, lol, I like when things get interesting. Well anybody could give some advices to improve it, I will put it on github as soon as it is ready at least to test it. I also need to implement other backends, it is pretty easy because it is a template module free of dirty code, simple as putting a name you want and implement a certain interface, and later just use the same name in connection_session/2 calls, and database manager manages to redirect and handles the calls and connection pool, you need also to install it, calling database_manager:install_backend/2 to create its connection pool and all its stuffs, you can remove it the same. -------------- next part -------------- An HTML attachment was scrubbed... URL: From tony@REDACTED Tue Aug 25 21:23:27 2015 From: tony@REDACTED (Tony Rogvall) Date: Tue, 25 Aug 2015 21:23:27 +0200 Subject: [erlang-questions] I need some advices for a framework I'm doing In-Reply-To: <000001d0df4e$d852e9e0$88f8bda0$@frcuba.co.cu> References: <000001d0deaa$5479cf20$fd6d6d60$@frcuba.co.cu> <55DB9061.8050501@ninenines.eu> <000001d0df4e$d852e9e0$88f8bda0$@frcuba.co.cu> Message-ID: <2FDD2B4B-466E-48D5-8E10-29E967948A05@rogvall.se> Ha ha ha This is funny, please stop! "typed while hacking!" > On 25 aug 2015, at 17:58, Ivan Carmenates Garcia wrote: > > Hi, > > Well the good news here is that I am making it together with a system a am also doing so, it any problems present I will notice they quickly and at the same time I will get feedbacks. > > Regards documentation, that one of the thing a love more, so it will be plenty of it, with a lot of examples and explanations. Currently the code doc for any function and even examples of how to use them. i.e. this is a nice doc for one of the functions: > > %% ------------------------------------------------------------------- > > %% @doc > > %% Makes a query to a database using a 'DBSession'. > > %% Returns a 'ResultData': > > %% - 'ResultData' depends of 'result_format' Option. > > %% - 'result_format' could be one of 'raw', 'proplist', 'map'. > > %% - 'proplist' and 'map' result formats have the same > > %% 'ResultData' struct: > > %% {ok, Data} when using 'select'. > > %% {ok, Count} when using 'update', 'insert', 'delete'. > > %% {ok, Count, Data} when using 'update', 'insert' with returning. > > %% The only differences are: > > %% 0 results: > > %% 'map' -> no_data, > > %% 'proplist' -> [], > > %% 1 result: > > %% 'map' -> a single map #{...}, > > %% 'proplist' -> a list of proplist [[...]], (template compatible) > > %% N results: > > %% 'map' -> a list of maps [#{...}, ...], > > %% 'proplist' -> a list of proplists [[...], ...], > > %% 'raw' by the other hand is 'Backend' dependent. > > %% Example: > > %% {ok, #{id := Id}} = database_manager:query(DBSession, > > %% Query, Params, [{result_format, map}]). > > %% NOTE: 'map' is the default result format for 'query/3' function. > > %% NOTE: All result format has its pros and cons, 'raw' is the fastest > > %% but uncomfortable to deal with, 'map' is the slowest but very > > %% easy to deal with. So this is the performance order from > > %% fastest to slowest 'raw' > 'proplist' > 'map'. 'proplist' can > > %% be used to return directly to a template. > > %% @end > > %% ------------------------------------------------------------------- > > -spec query(DBSession, Query, Params, Options) -> > > ResultData | {error, Reason} when > > DBSession :: db_session(), > > Query :: string() | bitstring(), > > Params :: [] | [any(), ...], > > Options :: proplists:proplist(), > > ResultData :: any(), > > Reason :: term(). > > query({Backend, Connection}, Query, Params, Options) -> > > %% executes query/4 in the current 'Backend'. > > Backend:query(Connection, Query, Params, Options). > > > > Anyone have more suggestions I could use?, thanks in advantage. > > Regards, > > Ivan. > > > > -----Original Message----- > From: Lo?c Hoguin [mailto:essen@REDACTED] > Sent: Monday, August 24, 2015 5:45 PM > To: Ivan Carmenates Garcia; erlang-questions@REDACTED > Subject: Re: [erlang-questions] I need some advices for a framework I'm doing > > On 08/24/2015 10:20 PM, Ivan Carmenates Garcia wrote: > > > Hi everyone, I am making a little framework for cowboy, but in general > > > what I need is some advices regards final looking, i.e.: > > OK I am a bit lost on everything you explained so allow me to give some generic advice: > > * Make it work > > * Start making apps with it > > * Notice everything inefficient in how you now write apps > > * Update your framework > > * Repeat > > Practice makes perfect. Add a little of looking at how everyone else does things in the mix to get ideas; sometimes you will notice something is bad in your framework but have no idea how to make it better, that's why you need to look elsewhere. Sometimes the idea might come from a completely unrelated source. > > A few more things: > > * Keep it simple and explicit > > * Focus on the use cases that benefit the majority of users > > * Choose good, short names > > * Write a user guide when things stabilize > > On the last point, you want the guide separate from code entirely because this forces you to think about how you really use it rather than just documenting functions or modules one after another. Think of it like writing a book, except the only role of this book is to explain to others *what* they can do with your framework and *why* they will do things that way. > > Once you get there, you should have a pretty good product, and you'll most likely have gotten a ton of users along the way. > > Cheers, > > -- > > Lo?c Hoguin > > http://ninenines.eu > > Author of The Erlanger Playbook, > > A book about software development using Erlang > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- An HTML attachment was scrubbed... URL: From co7eb@REDACTED Tue Aug 25 23:06:27 2015 From: co7eb@REDACTED (Ivan Carmenates Garcia) Date: Tue, 25 Aug 2015 17:06:27 -0400 Subject: [erlang-questions] I need some advices for a framework I'm doing In-Reply-To: <2FDD2B4B-466E-48D5-8E10-29E967948A05@rogvall.se> References: <000001d0deaa$5479cf20$fd6d6d60$@frcuba.co.cu> <55DB9061.8050501@ninenines.eu> <000001d0df4e$d852e9e0$88f8bda0$@frcuba.co.cu> <2FDD2B4B-466E-48D5-8E10-29E967948A05@rogvall.se> Message-ID: <000201d0df79$e9c7d9d0$bd578d70$@frcuba.co.cu> Yes usually happens when people try to build nice things and other people not. From: Tony Rogvall [mailto:tony@REDACTED] Sent: Tuesday, August 25, 2015 3:23 PM To: Ivan Carmenates Garcia Cc: Lo?c Hoguin; Subject: Re: [erlang-questions] I need some advices for a framework I'm doing Ha ha ha This is funny, please stop! "typed while hacking!" On 25 aug 2015, at 17:58, Ivan Carmenates Garcia > wrote: Hi, Well the good news here is that I am making it together with a system a am also doing so, it any problems present I will notice they quickly and at the same time I will get feedbacks. Regards documentation, that one of the thing a love more, so it will be plenty of it, with a lot of examples and explanations. Currently the code doc for any function and even examples of how to use them. i.e. this is a nice doc for one of the functions: %% ------------------------------------------------------------------- %% @doc %% Makes a query to a database using a 'DBSession'. %% Returns a 'ResultData': %% - 'ResultData' depends of 'result_format' Option. %% - 'result_format' could be one of 'raw', 'proplist', 'map'. %% - 'proplist' and 'map' result formats have the same %% 'ResultData' struct: %% {ok, Data} when using 'select'. %% {ok, Count} when using 'update', 'insert', 'delete'. %% {ok, Count, Data} when using 'update', 'insert' with returning. %% The only differences are: %% 0 results: %% 'map' -> no_data, %% 'proplist' -> [], %% 1 result: %% 'map' -> a single map #{...}, %% 'proplist' -> a list of proplist [[...]], (template compatible) %% N results: %% 'map' -> a list of maps [#{...}, ...], %% 'proplist' -> a list of proplists [[...], ...], %% 'raw' by the other hand is 'Backend' dependent. %% Example: %% {ok, #{id := Id}} = database_manager:query(DBSession, %% Query, Params, [{result_format, map}]). %% NOTE: 'map' is the default result format for 'query/3' function. %% NOTE: All result format has its pros and cons, 'raw' is the fastest %% but uncomfortable to deal with, 'map' is the slowest but very %% easy to deal with. So this is the performance order from %% fastest to slowest 'raw' > 'proplist' > 'map'. 'proplist' can %% be used to return directly to a template. %% @end %% ------------------------------------------------------------------- -spec query(DBSession, Query, Params, Options) -> ResultData | {error, Reason} when DBSession :: db_session(), Query :: string() | bitstring(), Params :: [] | [any(), ...], Options :: proplists:proplist(), ResultData :: any(), Reason :: term(). query({Backend, Connection}, Query, Params, Options) -> %% executes query/4 in the current 'Backend'. Backend:query(Connection, Query, Params, Options). Anyone have more suggestions I could use?, thanks in advantage. Regards, Ivan. -----Original Message----- From: Lo?c Hoguin [mailto:essen@REDACTED] Sent: Monday, August 24, 2015 5:45 PM To: Ivan Carmenates Garcia; erlang-questions@REDACTED Subject: Re: [erlang-questions] I need some advices for a framework I'm doing On 08/24/2015 10:20 PM, Ivan Carmenates Garcia wrote: > Hi everyone, I am making a little framework for cowboy, but in general > what I need is some advices regards final looking, i.e.: OK I am a bit lost on everything you explained so allow me to give some generic advice: * Make it work * Start making apps with it * Notice everything inefficient in how you now write apps * Update your framework * Repeat Practice makes perfect. Add a little of looking at how everyone else does things in the mix to get ideas; sometimes you will notice something is bad in your framework but have no idea how to make it better, that's why you need to look elsewhere. Sometimes the idea might come from a completely unrelated source. A few more things: * Keep it simple and explicit * Focus on the use cases that benefit the majority of users * Choose good, short names * Write a user guide when things stabilize On the last point, you want the guide separate from code entirely because this forces you to think about how you really use it rather than just documenting functions or modules one after another. Think of it like writing a book, except the only role of this book is to explain to others *what* they can do with your framework and *why* they will do things that way. Once you get there, you should have a pretty good product, and you'll most likely have gotten a ton of users along the way. Cheers, -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang _______________________________________________ erlang-questions mailing list erlang-questions@REDACTED http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- An HTML attachment was scrubbed... URL: From ok@REDACTED Wed Aug 26 07:38:15 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Wed, 26 Aug 2015 17:38:15 +1200 Subject: [erlang-questions] json to map In-Reply-To: <55DC5C83.2070409@home.nl> References: <55DC5C83.2070409@home.nl> Message-ID: <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> On 26/08/2015, at 12:16 am, Roelof Wobben wrote: > Hello, > > As a challenge I need to convert a json file to a erlang map. You need a more precise specification. A map with an arbitrary key whose associated value was a binary containing the text of the JSON term would technically satisfy this. > > So I have this file : > > { > "foo": { > "id": 1, > "username": "Foo Foo", > "first": "Foo", > "last": "Foo", > "password": "foo", > "email": "foo@REDACTED", > "scope": ["admin", "user"] > }, > "bar": { > "id": 2, > "username": "Bar Head", > "first": "Bar", > "last": "Head", > "password": "bar", > "email": "bar@REDACTED", > "scope": ["user"] > } > } > > > as far as I can see it's a tuple of tuples. No, it's not a tuple of tuples. To start with, it's >>JSON<<, not Erlang. JSON has arrays, not tuples. Here's a table that may help JSON Erlang null null (the atom) false false true true a number the same number a string a binary with the UTF-8 encoding an array ([]) a list an object ({}) a map Again, you don't say *how* the conversion is to be done. You could probably whip something up in a few minutes using lex to make a C program that basically changed opening " to <<", closing " to ">>, and did the right things for { } and : . That would convert JSON syntax to Erlang syntax quite quickly. Probably what you meant was WEB-SEARCH(JSON parser for Erlang using maps) This might lead you to https://github.com/talentdeficit/jsx or to one of the other JSON libraries with which Erlang is so liberally equipped. From r.wobben@REDACTED Wed Aug 26 07:56:29 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Wed, 26 Aug 2015 07:56:29 +0200 Subject: [erlang-questions] json to map In-Reply-To: <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> Message-ID: <55DD550D.6000904@home.nl> Op 26-8-2015 om 7:38 schreef Richard A. O'Keefe: > On 26/08/2015, at 12:16 am, Roelof Wobben wrote: > >> Hello, >> >> As a challenge I need to convert a json file to a erlang map. > You need a more precise specification. > A map with an arbitrary key whose associated value > was a binary containing the text of the JSON term > would technically satisfy this. > the exact text of the challenge is here : Configuration files can be conveniently represented as JSON terms. Write some functions to read configuration files containing JSON terms and turn them into Erlang maps. Write some code to perform sanity checks on the data in the configuration files. --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From neerajsharma.live@REDACTED Wed Aug 26 08:25:07 2015 From: neerajsharma.live@REDACTED (Neeraj Sharma) Date: Wed, 26 Aug 2015 11:55:07 +0530 Subject: [erlang-questions] Porint erlang on rumpkernel Message-ID: Hi, I am trying to port erlang on rumpkernel and running into some issues. RumpKernel do not have fork/execve, so there are some constraints. Please note that I am new to erlang internals, so please be a bit more verbose. 1. Erlang allocates pages which are aligned to superblock. I found strange pthread issues and debug it to due to the mmap allocation which does multiple allocation/deallocation to get the desired alignment. Can this be changed to align on just the pagesize instead? Is the alignment a strict requirement? 2. Erlang fork/execve, which is bad when running on rump because there is no such support at present. I am trying to run beam directly and even got a shell but then things fail while trying to run erlang application. I suspect that there are more fork at other places (probably for port). There are couple of things I'd like to know in this case. 2.1 What is the best way to run beam directly (instead of going via erl)? 2.2 Can I change fork/execve to pthread_create instead? Thanks, Neeraj -------------- next part -------------- An HTML attachment was scrubbed... URL: From tony@REDACTED Wed Aug 26 09:00:16 2015 From: tony@REDACTED (Tony Rogvall) Date: Wed, 26 Aug 2015 09:00:16 +0200 Subject: [erlang-questions] I need some advices for a framework I'm doing In-Reply-To: <000201d0df79$e9c7d9d0$bd578d70$@frcuba.co.cu> References: <000001d0deaa$5479cf20$fd6d6d60$@frcuba.co.cu> <55DB9061.8050501@ninenines.eu> <000001d0df4e$d852e9e0$88f8bda0$@frcuba.co.cu> <2FDD2B4B-466E-48D5-8E10-29E967948A05@rogvall.se> <000201d0df79$e9c7d9d0$bd578d70$@frcuba.co.cu> Message-ID: I am terribly sorry. I thought it was a joke. I am utterly ashamed. Sincerely /Tony > On 25 aug 2015, at 23:06, Ivan Carmenates Garcia wrote: > > Yes usually happens when people try to build nice things and other people not. > > > > From: Tony Rogvall [mailto:tony@REDACTED ] > Sent: Tuesday, August 25, 2015 3:23 PM > To: Ivan Carmenates Garcia > Cc: Lo?c Hoguin; > > Subject: Re: [erlang-questions] I need some advices for a framework I'm doing > > Ha ha ha > This is funny, please stop! > > "typed while hacking!" > > On 25 aug 2015, at 17:58, Ivan Carmenates Garcia > wrote: > >> Hi, >> >> Well the good news here is that I am making it together with a system a am also doing so, it any problems present I will notice they quickly and at the same time I will get feedbacks. >> >> Regards documentation, that one of the thing a love more, so it will be plenty of it, with a lot of examples and explanations. Currently the code doc for any function and even examples of how to use them. i.e. this is a nice doc for one of the functions: >> >> %% ------------------------------------------------------------------- >> >> %% @doc >> >> %% Makes a query to a database using a 'DBSession'. >> >> %% Returns a 'ResultData': >> >> %% - 'ResultData' depends of 'result_format' Option. >> >> %% - 'result_format' could be one of 'raw', 'proplist', 'map'. >> >> %% - 'proplist' and 'map' result formats have the same >> >> %% 'ResultData' struct: >> >> %% {ok, Data} when using 'select'. >> >> %% {ok, Count} when using 'update', 'insert', 'delete'. >> >> %% {ok, Count, Data} when using 'update', 'insert' with returning. >> >> %% The only differences are: >> >> %% 0 results: >> >> %% 'map' -> no_data, >> >> %% 'proplist' -> [], >> >> %% 1 result: >> >> %% 'map' -> a single map #{...}, >> >> %% 'proplist' -> a list of proplist [[...]], (template compatible) >> >> %% N results: >> >> %% 'map' -> a list of maps [#{...}, ...], >> >> %% 'proplist' -> a list of proplists [[...], ...], >> >> %% 'raw' by the other hand is 'Backend' dependent. >> >> %% Example: >> >> %% {ok, #{id := Id}} = database_manager:query(DBSession, >> >> %% Query, Params, [{result_format, map}]). >> >> %% NOTE: 'map' is the default result format for 'query/3' function. >> >> %% NOTE: All result format has its pros and cons, 'raw' is the fastest >> >> %% but uncomfortable to deal with, 'map' is the slowest but very >> >> %% easy to deal with. So this is the performance order from >> >> %% fastest to slowest 'raw' > 'proplist' > 'map'.'proplist' can >> >> %% be used to return directly to a template. >> >> %% @end >> >> %% ------------------------------------------------------------------- >> >> -spec query(DBSession, Query, Params, Options) -> >> >> ResultData | {error, Reason} when >> >> DBSession :: db_session(), >> >> Query :: string() | bitstring(), >> >> Params :: [] | [any(), ...], >> >> Options :: proplists:proplist(), >> >> ResultData :: any(), >> >> Reason :: term(). >> >> query({Backend, Connection}, Query, Params, Options) -> >> >> %% executes query/4 in the current 'Backend'. >> >> Backend:query(Connection, Query, Params, Options). >> >> Anyone have more suggestions I could use?, thanks in advantage. >> >> Regards, >> >> Ivan. >> >> -----Original Message----- >> From: Lo?c Hoguin [mailto:essen@REDACTED ] >> Sent: Monday, August 24, 2015 5:45 PM >> To: Ivan Carmenates Garcia; erlang-questions@REDACTED >> Subject: Re: [erlang-questions] I need some advices for a framework I'm doing >> >> On 08/24/2015 10:20 PM, Ivan Carmenates Garcia wrote: >> >> > Hi everyone, I am making a little framework for cowboy, but in general >> >> > what I need is some advices regards final looking, i.e.: >> >> OK I am a bit lost on everything you explained so allow me to give some generic advice: >> >> * Make it work >> >> * Start making apps with it >> >> * Notice everything inefficient in how you now write apps >> >> * Update your framework >> >> * Repeat >> >> Practice makes perfect. Add a little of looking at how everyone else does things in the mix to get ideas; sometimes you will notice something is bad in your framework but have no idea how to make it better, that's why you need to look elsewhere. Sometimes the idea might come from a completely unrelated source. >> >> A few more things: >> >> * Keep it simple and explicit >> >> * Focus on the use cases that benefit the majority of users >> >> * Choose good, short names >> >> * Write a user guide when things stabilize >> >> On the last point, you want the guide separate from code entirely because this forces you to think about how you really use it rather than just documenting functions or modules one after another. Think of it like writing a book, except the only role of this book is to explain to others *what* they can do with your framework and *why* they will do things that way. >> >> Once you get there, you should have a pretty good product, and you'll most likely have gotten a ton of users along the way. >> >> Cheers, >> >> -- >> >> Lo?c Hoguin >> >> http://ninenines.eu >> Author of The Erlanger Playbook, >> >> A book about software development using Erlang >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: Message signed with OpenPGP using GPGMail URL: From garazdawi@REDACTED Wed Aug 26 10:14:06 2015 From: garazdawi@REDACTED (Lukas Larsson) Date: Wed, 26 Aug 2015 10:14:06 +0200 Subject: [erlang-questions] Porint erlang on rumpkernel In-Reply-To: References: Message-ID: Hello! On Wed, Aug 26, 2015 at 8:25 AM, Neeraj Sharma wrote: > Hi, > > I am trying to port erlang on rumpkernel and running into some issues. > RumpKernel do not have fork/execve, so there are some constraints. Please > note that I am new to erlang internals, so please be a bit more verbose. > > 1. Erlang allocates pages which are aligned to superblock. I found strange > pthread issues and debug it to due to the mmap allocation which does > multiple allocation/deallocation to get the desired alignment. Can this be > changed to align on just the pagesize instead? Is the alignment a strict > requirement? > It is not a strict requirement. For instance windows and ose do not have use this feature. It can be disabled by playing around with the defines in erl_mmap.h. There might also be a configure test for it, can't remember of the top of my head. > > 2. Erlang fork/execve, which is bad when running on rump because there is > no such support at present. I am trying to run beam directly and even got a > shell but then things fail while trying to run erlang application. I > suspect that there are more fork at other places (probably for port). There > are couple of things I'd like to know in this case. > > 2.1 What is the best way to run beam directly (instead of going via erl)? > For OSE there is no erl wrapper, instead beam is invoked directly. This is not very beautiful, but it works good enough. You can read about how it is started here: http://www.erlang.org/doc/apps/ose/ose_intro.html#id56869 > > 2.2 Can I change fork/execve to pthread_create instead? > No, I don't think that would work. What you can do is configure the Erlang to not use the native dns resolver. This normally this gets rid of most of the child programs that are needed. See the inet configuration manual for details on how to do this: http://www.erlang.org/doc/apps/erts/inet_cfg.html . Happy porting! Lukas -------------- next part -------------- An HTML attachment was scrubbed... URL: From askjuise@REDACTED Wed Aug 26 10:16:23 2015 From: askjuise@REDACTED (Alexander Petrovsky) Date: Wed, 26 Aug 2015 11:16:23 +0300 Subject: [erlang-questions] Merging maps with a fun like dict:merge/3 In-Reply-To: <55D9FD64.4080608@llaisdy.com> References: <55D9FD64.4080608@llaisdy.com> Message-ID: Hi! I've make some little benchmarks, and noticed that the most effective way is: merge(F, [Head | Tail]) -> lists:foldl(fun(Y, X) -> maps:merge(X, maps:map(fun(Key, Value) -> F(maps:get(Key, X, 0), Value) end, Y)) end, Head, Tail). 2015-08-23 20:05 GMT+03:00 Ivan Uemlianin : > Dear All > > The maps module does not have a merge/3 like dict:merge/3, which calls a > function fun(Key, Val1, Val2) when both dicts have the same key. From the > documentation, "If a key occurs in both dictionaries then Fun is called > with the key and both values to return a new value." > > The dict documentation says that dict:merge/3 is faster than an equivalent > implemented in erlang. > > http://www.erlang.org/doc/man/dict.html#merge-3 > > Why does the maps module not have a similar merge/3? Is it because > writing our own erlang implementation is at fast as it gets? > > Below is an implementation which seems to work. Can it be made faster? > > > merge_maps(Fun, M1, M2) -> > maps:fold(fun(K, V1, Acc) -> > case maps:is_key(K, Acc) of > false -> > maps:put(K, V1, Acc); > true -> > V2 = maps:get(K, Acc), > maps:put(K, Fun(K, V1, V2), Acc) > end > end, > M1, > M2). > > merge_maps_test() -> > merge_maps(fun(_K, V1, V2) -> V1 + V2 end, > #{a => 1, b => 2, c => 3}, > #{b => 2, c => 3, d => 4}) =:= > #{a => 1, b => 4, c => 6, d => 4}. > > > With thanks and best wishes > > Ivan > > -- > ============================================================ > Ivan A. Uemlianin PhD > Llaisdy > Speech Technology Research and Development > > ivan@REDACTED > @llaisdy > llaisdy.wordpress.com > github.com/llaisdy > www.linkedin.com/in/ivanuemlianin > > festina lente > ============================================================ > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -- ?????????? ????????? / Alexander Petrovsky, Skype: askjuise Phone: +7 914 8 820 815 -------------- next part -------------- An HTML attachment was scrubbed... URL: From desired.mta@REDACTED Wed Aug 26 10:56:02 2015 From: desired.mta@REDACTED (=?UTF-8?Q?Motiejus_Jak=C5=A1tys?=) Date: Wed, 26 Aug 2015 10:56:02 +0200 Subject: [erlang-questions] Porint erlang on rumpkernel In-Reply-To: References: Message-ID: On Wed, Aug 26, 2015 at 8:25 AM, Neeraj Sharma wrote: > Hi, > > I am trying to port erlang on rumpkernel and running into some issues. > RumpKernel do not have fork/execve, so there are some constraints. Please > note that I am new to erlang internals, so please be a bit more verbose. Hi, Neeraj, Erlang was recently ported to OSv, which also doesn't have fork(). Might help: * https://www.youtube.com/watch?v=tz1TWwc9KhQ * https://github.com/cloudius-systems/osv-apps/tree/master/erlang Good luck! Motiejus From ivan@REDACTED Wed Aug 26 10:45:37 2015 From: ivan@REDACTED (Ivan Uemlianin) Date: Wed, 26 Aug 2015 09:45:37 +0100 Subject: [erlang-questions] Merging maps with a fun like dict:merge/3 In-Reply-To: References: <55D9FD64.4080608@llaisdy.com> Message-ID: <55DD7CB1.2080703@llaisdy.com> Dear Alexander Thanks! That looks excellent! I notice that your function F is different from the dict:merge/3 function: instead of taking a key and the two values, is takes two values, defaulting the first to 0. I've put my case clause into your framework: merge_ap(F, [Head | Tail]) -> lists:foldl(fun(Y, X) -> maps:merge(X, maps:map(fun(Key, Value) -> case maps:is_key(Key, X) of false -> Value; true -> F(Key, Value, maps:get(Key, X)) end end, Y)) end, Head, Tail). This has desired behaviour, and will probably still perform well. Using lists:foldl is a brilliant idea. Best wishes Ivan On 26/08/2015 09:16, Alexander Petrovsky wrote: > Hi! > > I've make some little benchmarks, and noticed that the most effective > way is: > > merge(F, [Head | Tail]) -> > lists:foldl(fun(Y, X) -> maps:merge(X, maps:map(fun(Key, Value) -> > F(maps:get(Key, X, 0), Value) end, Y)) end, Head, Tail). > > > 2015-08-23 20:05 GMT+03:00 Ivan Uemlianin >: > > Dear All > > The maps module does not have a merge/3 like dict:merge/3, which > calls a function fun(Key, Val1, Val2) when both dicts have the > same key. From the documentation, "If a key occurs in both > dictionaries then Fun is called with the key and both values to > return a new value." > > The dict documentation says that dict:merge/3 is faster than an > equivalent implemented in erlang. > > http://www.erlang.org/doc/man/dict.html#merge-3 > > Why does the maps module not have a similar merge/3? Is it > because writing our own erlang implementation is at fast as it gets? > > Below is an implementation which seems to work. Can it be made > faster? > > > merge_maps(Fun, M1, M2) -> > maps:fold(fun(K, V1, Acc) -> > case maps:is_key(K, Acc) of > false -> > maps:put(K, V1, Acc); > true -> > V2 = maps:get(K, Acc), > maps:put(K, Fun(K, V1, V2), Acc) > end > end, > M1, > M2). > > merge_maps_test() -> > merge_maps(fun(_K, V1, V2) -> V1 + V2 end, > #{a => 1, b => 2, c => 3}, > #{b => 2, c => 3, d => 4}) =:= > #{a => 1, b => 4, c => 6, d => 4}. > > > With thanks and best wishes > > Ivan > > -- > ============================================================ > Ivan A. Uemlianin PhD > Llaisdy > Speech Technology Research and Development > > ivan@REDACTED > @llaisdy > llaisdy.wordpress.com > github.com/llaisdy > www.linkedin.com/in/ivanuemlianin > > > festina lente > ============================================================ > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > > > > -- > ?????????? ????????? / Alexander Petrovsky, > > Skype: askjuise > Phone: +7 914 8 820 815 > -- ============================================================ Ivan A. Uemlianin PhD Llaisdy Speech Technology Research and Development ivan@REDACTED @llaisdy llaisdy.wordpress.com github.com/llaisdy www.linkedin.com/in/ivanuemlianin festina lente ============================================================ -------------- next part -------------- An HTML attachment was scrubbed... URL: From vychodil.hynek@REDACTED Wed Aug 26 11:32:00 2015 From: vychodil.hynek@REDACTED (Hynek Vychodil) Date: Wed, 26 Aug 2015 11:32:00 +0200 Subject: [erlang-questions] Merging maps with a fun like dict:merge/3 In-Reply-To: <55DD7CB1.2080703@llaisdy.com> References: <55D9FD64.4080608@llaisdy.com> <55DD7CB1.2080703@llaisdy.com> Message-ID: I would consider: merge_ap(F, [Head | Tail]) -> lists:foldl(fun(Y, X) -> maps:merge(X, maps:map(fun(Key, Value) -> case maps:find(Key, X) of {ok, V} -> F(Key, V, Value); error -> Value end end, Y)) end, Head, Tail). On Wed, Aug 26, 2015 at 10:45 AM, Ivan Uemlianin wrote: > Dear Alexander > > Thanks! That looks excellent! > > I notice that your function F is different from the dict:merge/3 > function: instead of taking a key and the two values, is takes two values, > defaulting the first to 0. > > I've put my case clause into your framework: > > merge_ap(F, [Head | Tail]) -> > lists:foldl(fun(Y, X) -> > maps:merge(X, maps:map(fun(Key, Value) -> > case > maps:is_key(Key, X) of > false -> > Value; > true -> > F(Key, > Value, maps:get(Key, X)) > end > end, > Y)) > end, > Head, > Tail). > > This has desired behaviour, and will probably still perform well. Using > lists:foldl is a brilliant idea. > > Best wishes > > Ivan > > > > On 26/08/2015 09:16, Alexander Petrovsky wrote: > > Hi! > > I've make some little benchmarks, and noticed that the most effective way > is: > > merge(F, [Head | Tail]) -> > lists:foldl(fun(Y, X) -> maps:merge(X, maps:map(fun(Key, Value) -> F( > maps:get(Key, X, 0), Value) end, Y)) end, Head, Tail). > > > 2015-08-23 20:05 GMT+03:00 Ivan Uemlianin : > >> Dear All >> >> The maps module does not have a merge/3 like dict:merge/3, which calls a >> function fun(Key, Val1, Val2) when both dicts have the same key. From the >> documentation, "If a key occurs in both dictionaries then Fun is called >> with the key and both values to return a new value." >> >> The dict documentation says that dict:merge/3 is faster than an >> equivalent implemented in erlang. >> >> http://www.erlang.org/doc/man/dict.html#merge-3 >> >> Why does the maps module not have a similar merge/3? Is it because >> writing our own erlang implementation is at fast as it gets? >> >> Below is an implementation which seems to work. Can it be made faster? >> >> >> merge_maps(Fun, M1, M2) -> >> maps:fold(fun(K, V1, Acc) -> >> case maps:is_key(K, Acc) of >> false -> >> maps:put(K, V1, Acc); >> true -> >> V2 = maps:get(K, Acc), >> maps:put(K, Fun(K, V1, V2), Acc) >> end >> end, >> M1, >> M2). >> >> merge_maps_test() -> >> merge_maps(fun(_K, V1, V2) -> V1 + V2 end, >> #{a => 1, b => 2, c => 3}, >> #{b => 2, c => 3, d => 4}) =:= >> #{a => 1, b => 4, c => 6, d => 4}. >> >> >> With thanks and best wishes >> >> Ivan >> >> -- >> ============================================================ >> Ivan A. Uemlianin PhD >> Llaisdy >> Speech Technology Research and Development >> >> ivan@REDACTED >> @llaisdy >> llaisdy.wordpress.com >> github.com/llaisdy >> www.linkedin.com/in/ivanuemlianin >> >> festina lente >> ============================================================ >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> > > > > -- > ?????????? ????????? / Alexander Petrovsky, > > Skype: askjuise > Phone: +7 914 8 820 815 > > > -- > ============================================================ > Ivan A. Uemlianin PhD > Llaisdy > Speech Technology Research and Development > > ivan@REDACTED > @llaisdy > llaisdy.wordpress.com > github.com/llaisdy > www.linkedin.com/in/ivanuemlianin > > festina lente > ============================================================ > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From neerajsharma.live@REDACTED Wed Aug 26 12:31:55 2015 From: neerajsharma.live@REDACTED (Neeraj Sharma) Date: Wed, 26 Aug 2015 16:01:55 +0530 Subject: [erlang-questions] Porint erlang on rumpkernel In-Reply-To: References: Message-ID: Thanks Lukas and Motiejus. On Wed, Aug 26, 2015 at 2:26 PM, Motiejus Jak?tys wrote: > On Wed, Aug 26, 2015 at 8:25 AM, Neeraj Sharma > wrote: > > Hi, > > > > I am trying to port erlang on rumpkernel and running into some issues. > > RumpKernel do not have fork/execve, so there are some constraints. Please > > note that I am new to erlang internals, so please be a bit more verbose. > > Hi, Neeraj, > > Erlang was recently ported to OSv, which also doesn't have fork(). Might > help: > > * https://www.youtube.com/watch?v=tz1TWwc9KhQ > * https://github.com/cloudius-systems/osv-apps/tree/master/erlang > > Good luck! > > Motiejus > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ivan@REDACTED Wed Aug 26 11:38:59 2015 From: ivan@REDACTED (Ivan Uemlianin) Date: Wed, 26 Aug 2015 10:38:59 +0100 Subject: [erlang-questions] Merging maps with a fun like dict:merge/3 In-Reply-To: References: <55D9FD64.4080608@llaisdy.com> <55DD7CB1.2080703@llaisdy.com> Message-ID: <55DD8933.10001@llaisdy.com> Oh yes of course that's better. Thanks Ivan On 26/08/2015 10:32, Hynek Vychodil wrote: > I would consider: > > merge_ap(F, [Head | Tail]) -> > lists:foldl(fun(Y, X) -> > maps:merge(X, maps:map(fun(Key, Value) -> > case > maps:find(Key, X) of > {ok, V} -> F(Key, V, Value); > error -> Value > end > end, > Y)) > end, > Head, > Tail). > > On Wed, Aug 26, 2015 at 10:45 AM, Ivan Uemlianin > wrote: > > Dear Alexander > > Thanks! That looks excellent! > > I notice that your function F is different from the dict:merge/3 > function: instead of taking a key and the two values, is takes two > values, defaulting the first to 0. > > I've put my case clause into your framework: > > merge_ap(F, [Head | Tail]) -> > lists:foldl(fun(Y, X) -> > maps:merge(X, maps:map(fun(Key, Value) -> > case maps:is_key(Key, X) of > false -> > Value; > true -> > F(Key, Value, maps:get(Key, X)) > end > end, > Y)) > end, > Head, > Tail). > > This has desired behaviour, and will probably still perform well. > Using lists:foldl is a brilliant idea. > > Best wishes > > Ivan > > > > On 26/08/2015 09:16, Alexander Petrovsky wrote: >> Hi! >> >> I've make some little benchmarks, and noticed that the most >> effective way is: >> >> merge(F, [Head | Tail]) -> >> lists:foldl(fun(Y, X) -> maps:merge(X, maps:map(fun(Key, >> Value) -> F(maps:get(Key, X, 0), Value) end, Y)) end, Head, Tail). >> >> >> 2015-08-23 20:05 GMT+03:00 Ivan Uemlianin > >: >> >> Dear All >> >> The maps module does not have a merge/3 like dict:merge/3, >> which calls a function fun(Key, Val1, Val2) when both dicts >> have the same key. From the documentation, "If a key occurs >> in both dictionaries then Fun is called with the key and both >> values to return a new value." >> >> The dict documentation says that dict:merge/3 is faster than >> an equivalent implemented in erlang. >> >> http://www.erlang.org/doc/man/dict.html#merge-3 >> >> Why does the maps module not have a similar merge/3? Is it >> because writing our own erlang implementation is at fast as >> it gets? >> >> Below is an implementation which seems to work. Can it be >> made faster? >> >> >> merge_maps(Fun, M1, M2) -> >> maps:fold(fun(K, V1, Acc) -> >> case maps:is_key(K, Acc) of >> false -> >> maps:put(K, V1, Acc); >> true -> >> V2 = maps:get(K, Acc), >> maps:put(K, Fun(K, V1, V2), Acc) >> end >> end, >> M1, >> M2). >> >> merge_maps_test() -> >> merge_maps(fun(_K, V1, V2) -> V1 + V2 end, >> #{a => 1, b => 2, c => 3}, >> #{b => 2, c => 3, d => 4}) =:= >> #{a => 1, b => 4, c => 6, d => 4}. >> >> >> With thanks and best wishes >> >> Ivan >> >> -- >> ============================================================ >> Ivan A. Uemlianin PhD >> Llaisdy >> Speech Technology Research and Development >> >> ivan@REDACTED >> @llaisdy >> llaisdy.wordpress.com >> github.com/llaisdy >> www.linkedin.com/in/ivanuemlianin >> >> >> festina lente >> ============================================================ >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> >> >> >> >> -- >> ?????????? ????????? / Alexander Petrovsky, >> >> Skype: askjuise >> Phone: +7 914 8 820 815 >> > > -- > ============================================================ > Ivan A. Uemlianin PhD > Llaisdy > Speech Technology Research and Development > > ivan@REDACTED > @llaisdy > llaisdy.wordpress.com > github.com/llaisdy > www.linkedin.com/in/ivanuemlianin > > > festina lente > ============================================================ > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -- ============================================================ Ivan A. Uemlianin PhD Llaisdy Speech Technology Research and Development ivan@REDACTED @llaisdy llaisdy.wordpress.com github.com/llaisdy www.linkedin.com/in/ivanuemlianin festina lente ============================================================ -------------- next part -------------- An HTML attachment was scrubbed... URL: From kvratkin@REDACTED Wed Aug 26 15:09:24 2015 From: kvratkin@REDACTED (Kirill Ratkin) Date: Wed, 26 Aug 2015 17:09:24 +0400 Subject: [erlang-questions] Diameter service restart Message-ID: Hi all. I'm working with application which implements several Diameter Applications (Gy, Cx and so on). When I start all Dia Applications together in diameter:start_service function then all Applications works well. But I need a little bit more. I want to start one Application (for example Gy) and provide API function from my module to add/remove another Applications (for example Cx) "on fly" without stop_service/start_service. Yes, I know every Application has code generated from dictionary file. How I understand this code can be re-loaded automatically by code_server (in theory). And then Diameter stack could use call_back module of new added Application. I probably read all manuals and examples of Diameter library but I didn't manager to find similar functionality. Guys, who knows is it possible or not? P.S. yes, solution with stop_service/start_service works but stop_service closes tcp/sctp sockets and start_service creates it again sending CER as required by RFC. I'd eliminate socket destruction. Just sending CER would be Ok. I afraid some vendors can dislike such situation with transport ... -------------- next part -------------- An HTML attachment was scrubbed... URL: From chandrashekhar.mullaparthi@REDACTED Wed Aug 26 16:44:04 2015 From: chandrashekhar.mullaparthi@REDACTED (Chandru) Date: Wed, 26 Aug 2015 15:44:04 +0100 Subject: [erlang-questions] Diameter service restart In-Reply-To: References: Message-ID: Hi, One way is to create virtual interfaces on your box so that each of your application is exposed via a different IP/Port combination. That way when you stop a service, only the transport connections associated with that service would get torn down. It wouldn't be right to allow you to stop an application while keeping the associated transport up. From the peer's point of view, after the CER/CEA dialogue, it is expected that you will be able to field requests for all applications which you advertised in your CEA. I can't imagine a valid scenario where this kind of feature would be required. Can you please elaborate? Chandru On 26 August 2015 at 14:09, Kirill Ratkin wrote: > Hi all. > > I'm working with application which implements several Diameter > Applications (Gy, Cx and so on). > When I start all Dia Applications together in diameter:start_service > function then all Applications works well. > > But I need a little bit more. I want to start one Application (for example > Gy) and provide API function from my module to add/remove another > Applications (for example Cx) "on fly" without stop_service/start_service. > > Yes, I know every Application has code generated from dictionary file. How > I understand this code can be re-loaded automatically by code_server (in > theory). And then Diameter stack could use call_back module of new added > Application. > > I probably read all manuals and examples of Diameter library but I didn't > manager to find similar functionality. > > Guys, who knows is it possible or not? > > P.S. yes, solution with stop_service/start_service works but stop_service > closes tcp/sctp sockets and start_service creates it again sending CER as > required by RFC. I'd eliminate socket destruction. Just sending CER would > be Ok. I afraid some vendors can dislike such situation with transport ... > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ivan@REDACTED Wed Aug 26 20:44:42 2015 From: ivan@REDACTED (Ivan Uemlianin) Date: Wed, 26 Aug 2015 19:44:42 +0100 Subject: [erlang-questions] Merging maps with a fun like dict:merge/3 In-Reply-To: <55DD8933.10001@llaisdy.com> References: <55D9FD64.4080608@llaisdy.com> <55DD7CB1.2080703@llaisdy.com> <55DD8933.10001@llaisdy.com> Message-ID: <55DE091A.5090104@llaisdy.com> Dear Alexander, Hynek That is a *lot* faster! :D Thanks very much both. Ivan On 08/26/15 10:38, Ivan Uemlianin wrote: > Oh yes of course that's better. Thanks > > Ivan > > > On 26/08/2015 10:32, Hynek Vychodil wrote: >> I would consider: >> >> merge_ap(F, [Head | Tail]) -> >> lists:foldl(fun(Y, X) -> >> maps:merge(X, maps:map(fun(Key, Value) -> >> case maps:find(Key, X) of >> {ok, V} -> F(Key, V, Value); >> error -> Value >> end >> end, >> Y)) >> end, >> Head, >> Tail). >> >> On Wed, Aug 26, 2015 at 10:45 AM, Ivan Uemlianin >> wrote: >> >> Dear Alexander >> >> Thanks! That looks excellent! >> >> I notice that your function F is different from the dict:merge/3 >> function: instead of taking a key and the two values, is takes >> two values, defaulting the first to 0. >> >> I've put my case clause into your framework: >> >> merge_ap(F, [Head | Tail]) -> >> lists:foldl(fun(Y, X) -> >> maps:merge(X, maps:map(fun(Key, Value) -> >> case maps:is_key(Key, X) of >> false -> >> Value; >> true -> >> F(Key, Value, maps:get(Key, X)) >> end >> end, >> Y)) >> end, >> Head, >> Tail). >> >> This has desired behaviour, and will probably still perform >> well. Using lists:foldl is a brilliant idea. >> >> Best wishes >> >> Ivan >> >> >> >> On 26/08/2015 09:16, Alexander Petrovsky wrote: >>> Hi! >>> >>> I've make some little benchmarks, and noticed that the most >>> effective way is: >>> >>> merge(F, [Head | Tail]) -> >>> lists:foldl(fun(Y, X) -> maps:merge(X, maps:map(fun(Key, >>> Value) -> F(maps:get(Key, X, 0), Value) end, Y)) end, Head, Tail). >>> >>> >>> 2015-08-23 20:05 GMT+03:00 Ivan Uemlianin : >>> >>> Dear All >>> >>> The maps module does not have a merge/3 like dict:merge/3, >>> which calls a function fun(Key, Val1, Val2) when both dicts >>> have the same key. From the documentation, "If a key occurs >>> in both dictionaries then Fun is called with the key and >>> both values to return a new value." >>> >>> The dict documentation says that dict:merge/3 is faster than >>> an equivalent implemented in erlang. >>> >>> http://www.erlang.org/doc/man/dict.html#merge-3 >>> >>> Why does the maps module not have a similar merge/3? Is it >>> because writing our own erlang implementation is at fast as >>> it gets? >>> >>> Below is an implementation which seems to work. Can it be >>> made faster? >>> >>> >>> merge_maps(Fun, M1, M2) -> >>> maps:fold(fun(K, V1, Acc) -> >>> case maps:is_key(K, Acc) of >>> false -> >>> maps:put(K, V1, Acc); >>> true -> >>> V2 = maps:get(K, Acc), >>> maps:put(K, Fun(K, V1, V2), Acc) >>> end >>> end, >>> M1, >>> M2). >>> >>> merge_maps_test() -> >>> merge_maps(fun(_K, V1, V2) -> V1 + V2 end, >>> #{a => 1, b => 2, c => 3}, >>> #{b => 2, c => 3, d => 4}) =:= >>> #{a => 1, b => 4, c => 6, d => 4}. >>> >>> >>> With thanks and best wishes >>> >>> Ivan >>> >>> -- >>> ============================================================ >>> Ivan A. Uemlianin PhD >>> Llaisdy >>> Speech Technology Research and Development >>> >>> ivan@REDACTED >>> @llaisdy >>> llaisdy.wordpress.com >>> github.com/llaisdy >>> www.linkedin.com/in/ivanuemlianin >>> >>> festina lente >>> ============================================================ >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >>> >>> >>> >>> >>> -- >>> ?????????? ????????? / Alexander Petrovsky, >>> >>> Skype: askjuise >>> Phone: +7 914 8 820 815 >>> >> >> -- >> ============================================================ >> Ivan A. Uemlianin PhD >> Llaisdy >> Speech Technology Research and Development >> >> ivan@REDACTED >> @llaisdy >> llaisdy.wordpress.com >> github.com/llaisdy >> www.linkedin.com/in/ivanuemlianin >> >> festina lente >> ============================================================ >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions >> >> > > -- > ============================================================ > Ivan A. Uemlianin PhD > Llaisdy > Speech Technology Research and Development > > ivan@REDACTED > @llaisdy > llaisdy.wordpress.com > github.com/llaisdy > www.linkedin.com/in/ivanuemlianin > > festina lente > ============================================================ > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -- ============================================================ Ivan A. Uemlianin PhD Llaisdy Speech Technology Research and Development ivan@REDACTED @llaisdy llaisdy.wordpress.com github.com/llaisdy www.linkedin.com/in/ivanuemlianin festina lente ============================================================ -------------- next part -------------- An HTML attachment was scrubbed... URL: From mjtruog@REDACTED Wed Aug 26 22:21:03 2015 From: mjtruog@REDACTED (Michael Truog) Date: Wed, 26 Aug 2015 13:21:03 -0700 Subject: [erlang-questions] Merging maps with a fun like dict:merge/3 In-Reply-To: <55DE091A.5090104@llaisdy.com> References: <55D9FD64.4080608@llaisdy.com> <55DD7CB1.2080703@llaisdy.com> <55DD8933.10001@llaisdy.com> <55DE091A.5090104@llaisdy.com> Message-ID: <55DE1FAF.3000306@gmail.com> A straight-forward way to provide a maps merge function based on the dict documentation is: maps_update(K, F, V0, Map) -> try maps:get(K, Map) of V1 -> maps:put(K, F(V1), Map) catch error:{badkey, K} -> maps:put(K, V0, Map) end. maps_merge(Fun, Map1, Map2) -> maps:fold(fun (K, V1, Map) -> maps_update(K, fun (V2) -> Fun(K, V1, V2) end, V1, Map) end, Map2, Map1). Not sure about the speed compared to the code below, but both results should be the same if everything is working properly. On 08/26/2015 11:44 AM, Ivan Uemlianin wrote: > Dear Alexander, Hynek > > That is a *lot* faster! :D > > Thanks very much both. > > Ivan > > > On 08/26/15 10:38, Ivan Uemlianin wrote: >> Oh yes of course that's better. Thanks >> >> Ivan >> >> >> On 26/08/2015 10:32, Hynek Vychodil wrote: >>> I would consider: >>> >>> merge_ap(F, [Head | Tail]) -> >>> lists:foldl(fun(Y, X) -> >>> maps:merge(X, maps:map(fun(Key, Value) -> >>> case maps:find(Key, X) of >>> {ok, V} -> F(Key, V, Value); >>> error -> Value >>> end >>> end, >>> Y)) >>> end, >>> Head, >>> Tail). >>> >>> On Wed, Aug 26, 2015 at 10:45 AM, Ivan Uemlianin wrote: >>> >>> Dear Alexander >>> >>> Thanks! That looks excellent! >>> >>> I notice that your function F is different from the dict:merge/3 function: instead of taking a key and the two values, is takes two values, defaulting the first to 0. >>> >>> I've put my case clause into your framework: >>> >>> merge_ap(F, [Head | Tail]) -> >>> lists:foldl(fun(Y, X) -> >>> maps:merge(X, maps:map(fun(Key, Value) -> >>> case maps:is_key(Key, X) of >>> false -> >>> Value; >>> true -> >>> F(Key, Value, maps:get(Key, X)) >>> end >>> end, >>> Y)) >>> end, >>> Head, >>> Tail). >>> >>> This has desired behaviour, and will probably still perform well. Using lists:foldl is a brilliant idea. >>> >>> Best wishes >>> >>> Ivan >>> >>> >>> >>> On 26/08/2015 09:16, Alexander Petrovsky wrote: >>>> Hi! >>>> >>>> I've make some little benchmarks, and noticed that the most effective way is: >>>> >>>> merge(F, [Head | Tail]) -> >>>> lists:foldl(fun(Y, X) -> maps:merge(X, maps:map(fun(Key, Value) -> F(maps:get(Key, X, 0), Value) end, Y)) end, Head, Tail). >>>> >>>> >>>> 2015-08-23 20:05 GMT+03:00 Ivan Uemlianin : >>>> >>>> Dear All >>>> >>>> The maps module does not have a merge/3 like dict:merge/3, which calls a function fun(Key, Val1, Val2) when both dicts have the same key. From the documentation, "If a key occurs in both dictionaries then Fun is called with the key and both values to return a new value." >>>> >>>> The dict documentation says that dict:merge/3 is faster than an equivalent implemented in erlang. >>>> >>>> http://www.erlang.org/doc/man/dict.html#merge-3 >>>> >>>> Why does the maps module not have a similar merge/3? Is it because writing our own erlang implementation is at fast as it gets? >>>> >>>> Below is an implementation which seems to work. Can it be made faster? >>>> >>>> >>>> merge_maps(Fun, M1, M2) -> >>>> maps:fold(fun(K, V1, Acc) -> >>>> case maps:is_key(K, Acc) of >>>> false -> >>>> maps:put(K, V1, Acc); >>>> true -> >>>> V2 = maps:get(K, Acc), >>>> maps:put(K, Fun(K, V1, V2), Acc) >>>> end >>>> end, >>>> M1, >>>> M2). >>>> >>>> merge_maps_test() -> >>>> merge_maps(fun(_K, V1, V2) -> V1 + V2 end, >>>> #{a => 1, b => 2, c => 3}, >>>> #{b => 2, c => 3, d => 4}) =:= >>>> #{a => 1, b => 4, c => 6, d => 4}. >>>> >>>> >>>> With thanks and best wishes >>>> >>>> Ivan >>>> >>>> -- >>>> ============================================================ >>>> Ivan A. Uemlianin PhD >>>> Llaisdy >>>> Speech Technology Research and Development >>>> >>>> ivan@REDACTED >>>> @llaisdy >>>> llaisdy.wordpress.com >>>> github.com/llaisdy >>>> www.linkedin.com/in/ivanuemlianin >>>> >>>> festina lente >>>> ============================================================ >>>> >>>> _______________________________________________ >>>> erlang-questions mailing list >>>> erlang-questions@REDACTED >>>> http://erlang.org/mailman/listinfo/erlang-questions >>>> >>>> >>>> >>>> >>>> -- >>>> ?????????? ????????? / Alexander Petrovsky, >>>> >>>> Skype: askjuise >>>> Phone: +7 914 8 820 815 >>>> >>> >>> -- >>> ============================================================ >>> Ivan A. Uemlianin PhD >>> Llaisdy >>> Speech Technology Research and Development >>> >>> ivan@REDACTED >>> @llaisdy >>> llaisdy.wordpress.com >>> github.com/llaisdy >>> www.linkedin.com/in/ivanuemlianin >>> >>> festina lente >>> ============================================================ >>> >>> >>> _______________________________________________ >>> erlang-questions mailing list >>> erlang-questions@REDACTED >>> http://erlang.org/mailman/listinfo/erlang-questions >>> >>> >> >> -- >> ============================================================ >> Ivan A. Uemlianin PhD >> Llaisdy >> Speech Technology Research and Development >> >> ivan@REDACTED >> @llaisdy >> llaisdy.wordpress.com >> github.com/llaisdy >> www.linkedin.com/in/ivanuemlianin >> >> festina lente >> ============================================================ >> >> >> _______________________________________________ >> erlang-questions mailing list >> erlang-questions@REDACTED >> http://erlang.org/mailman/listinfo/erlang-questions > > -- > ============================================================ > Ivan A. Uemlianin PhD > Llaisdy > Speech Technology Research and Development > > ivan@REDACTED > @llaisdy > llaisdy.wordpress.com > github.com/llaisdy > www.linkedin.com/in/ivanuemlianin > > festina lente > ============================================================ > > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- An HTML attachment was scrubbed... URL: From ok@REDACTED Thu Aug 27 02:50:29 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Thu, 27 Aug 2015 12:50:29 +1200 Subject: [erlang-questions] Merging maps with a fun like dict:merge/3 In-Reply-To: References: <55D9FD64.4080608@llaisdy.com> <55DD7CB1.2080703@llaisdy.com> Message-ID: Merging whatevers has three cases: - this is in the left but not the right - this is in the right but not the left - this is in both with these values That is, given data Map k v I'd expect merge :: (k -> v -> Maybe r) -> -- left handler (k -> w -> Maybe r) -> -- right handler (k -> v -> w -> Maybe r) -> -- union handler Map k v -> -- left map Map k w -> -- right map Map k r -- result map The left handler is given a key and value from the left map and the assurance that the key is not in the right map. It either returns Nothing, discarding this element, or Just r meaning that k :-> r should be in the result. The other handlers work in the same way. Of course there can be specialisations, but this is what I would expect as the foundation. The frames proposal didn't include such a function because a good record substitute and a good dictionary are not the same kind of animal and should not be mixed up. From ok@REDACTED Thu Aug 27 04:41:04 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Thu, 27 Aug 2015 14:41:04 +1200 Subject: [erlang-questions] json to map In-Reply-To: <55DD550D.6000904@home.nl> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> Message-ID: On 26/08/2015, at 5:56 pm, Roelof Wobben wrote: > the exact text of the challenge is here : > > Configuration files can be conveniently represented as JSON terms. Yuck. This has "representation" backwards. Here's what we have, using [thing] for "things" and (action) for "processes". In our heads In our processes In our file system [abstract [stored configuration -(implement) -> configuration value] data] | | (conversion) (programmed conversion) | | v | [abstract v JSON value] -(implement) -> [stored JSON value] | | v | (unparse) (programmed unparsing) | | [abstract token v sequence] -(implement) -> [stored token sequence] | | (layout + unlex) (programmed layout + unlex) | | v | [abstract character v sequence] -(implement) -> [stored character sequence] | | (Unicode encoding) (programmed encoding) | | v | [abstract byte v sequence] -(implement) -> [stored byte sequence] | | (compress, (programmed compression. encrypt, encryption, signing, sign, &c) and so on) | | v v [another abstract [another stored byte sequence] byte sequence] ---(store)---> [FILE] There is an ABSTRACT space of JSON terms. Each of the arrows (down and right) is a "representation" arrow. The thing at the tip of the arrow represents the thing at the base of the arrow. The file we end up with is the thing that does the representing (GIVEN this framework), and the configuration data is what is represented. Don't take "stored" too literally. A "stored" data in the middle column could be a data structure or a communication pattern. I just mean that it's "inside the computer" in the sense that it is directly accessible to code. This diagram must commute, that is, whatever path you take through the arrows, you must end up with *equivalent* things. Not equal. Converting configuration values to JSON values need not be unique. For example, a set of n elements might be converted to a JSON array without duplicates in n! ways. But we can arrange to treat permuted arrays in certain contexts as equivalent. Converting JSON values to token sequences is not unique. For example, a JSON object doesn't *have* any order to it, but for unparsing, you have to pick an order. Given an object with n pairs, there are n! ways to order them. We can arrange to treat those as equivalent. Unlexing, converting tokens to character sequences, is not unique. 1, 1e0, 10e-1, 1.0e1, &c are the same, so even without allowing leading zeros there are hundreds of ways (but not infinitely many ways) to represent a number token. Most unicode characters can be represented in two ways (/ can be represented in three), so a string of n characters can be unlexed in at least 2**n ways. (It's worse than that because \u002f and \u002F are equivalent, so / has four alternatives.) Layout can insert arbitrary amounts of white space between tokens, and there are infinitely many ways to do that. There are multiple definitions of JSON. ECMA 404 stops at the level of Unicode character sequences, and has nothing to say about encoding. There are LOTS of encodings. There are also many compression, encryption, and digital signature algorithms, which be freely composed. JSON qua JSON has nothing to say about how files are encoded or whether they are compressed, encrypted, or signed. But to put text into a file, you have to encode it somehow, and you have to make some decision about other matters. (And don't get me onto file systems with fixed length records, where you have to figure out how to fit a 1 million character string into 128 byte records... > Write > some functions to read configuration files containing JSON terms and > turn them into Erlang maps. What if a configuration file represents this JSON term: [["target","some program"], ["source","some other program"], ["date",[2015,08,27,14,05]], ["gibberish",[3,1,4,1,5,9,2,7]]] How are you supposed to convert *that* to an Erlang map? In any way that makes sense? Oh, I know: {"": <<"[[\"target...7,]]]>>} or whatever the syntax for maps is. It technically satisfies the requirements! The first thing to do with these exercises is CRITICISE them. I do not mean to sneer at them and throw them away, but to start from a presupposition that the language is muddled, the contents confused, and the requirements either incomplete or inconsistent. (Like practically *every* requirement we start with including some published standards. I'm looking at you, ECMA 404!) I am not kidding. You have to start out by trying to understand the requirements, EXPECTING to find problems, RESOLVING them, and writing down REVISED requirements that spell out everything you actually need to know. For example, you might include the following: - Only the UTF-8 encoding is to be supported. - No compression, encryption, or signing are to be supported. - You may assume that the file system treats a file as an arbitrary sequence of bytes with no record boundaries. - You are to convert null, false, true to the Erlang atoms 'null, 'false', 'true'. - You are to convert JSON numbers to Erlang floats. - You are to convert JSON strings to Erlang binaries. - You are to convert JSON arrays to Erlang lists; nothing else is to be converted to a list. - You are to convert JSON objects to Erlang maps; nothing else is to be converted to a map. - You are not to worry about inverting the conversion from configuration data to JSON terms; there is no configuration data, that was just put in to make it interesting. > Write some code to perform sanity checks > on the data in the configuration files. Here is another piece of confusion/incompleteness, or possibly even questionable advice. This presupposes some procedure where you FIRST convert a JSON text stored in a file to some Erlang term and THEN you check the sanity. Or at least, it seems to. Another approach is to check as you go so that there is never any insane Erlang data at all. This is highly topical, because we've recently seen a bunch of serious Android security bugs caused by overly trusting object deserialisation which allowed objects to be constructed violating their invariants. In fact this has triggered a burst of work on my Smalltalk system, because I had a great big OOPS: oh dear, I have the same problem. So I'm now slogging through nearly a thousand files turning comments about invariants into executable code and writing invariants for the *shameful* number of classes that had none, so that the deserialisation code can call each newly reconstructed object's #invariant method before trusting it. So I strongly recommend validating data as you parse it, and if a sanity check is failed, crash immediately. This leaves nothing for subsequent sanity checks to do. UNLESS you have configuration data that's converted to JSON terms in such a way that not all terms represent valid configuration data. But from what you quote, you haven't been given anything for sanity checks like that to DO. All things considerd, the exercise appears to be a cryptic way of saying "WRITE A JSON PARSER". For what it's worth, my JSON parser in Smalltalk is 117 lines for a tokeniser + 45 lines for a parser. Being stricter about the input would let me shave about 20 lines off the total. Much of the trickiness is in handling strings, where JSON requires that a character outside the Basic Multilingual plane must be encoded as a surrogate pair. Processing a sequence of characters as an Erlang string will probably make your life simpler; and processing a sequence of tokens as an Erlang list will also be likely to make your life simpler. > From andra.dinu@REDACTED Thu Aug 27 12:46:30 2015 From: andra.dinu@REDACTED (Andra Dinu) Date: Thu, 27 Aug 2015 11:46:30 +0100 Subject: [erlang-questions] Chicago Erlang - workshop edition! 10 October Message-ID: Hi all, This year Chicago Erlang is shifting to a hands-on, write-some-code workshop edition. We prepared two parallel tracks: Essentials: Led by Erlang authors and instructors Martin Logan and Fred Hebert, this track is tailored for programmers who are new to Erlang and want to lay a solid foundation. IoT App Buildout is for more advanced developers. Web Scale engineers Brian Troutwine and Garrett Smith take you into the deep end of the pool with an Internet of Things (IoT) backend that features Erlang?s concurrency model and network support. Early Bird rate is $49. It doesn't get any better than this, and places are limited: http://www.chicagoerlang.com/ Best, Andra *Andra Dinu* Community & Social Code Mesh London 2-4 November : NOT your usual tech conference... -------------- next part -------------- An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Thu Aug 27 13:04:22 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Thu, 27 Aug 2015 13:04:22 +0200 Subject: [erlang-questions] json to map In-Reply-To: References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> Message-ID: <55DEEEB6.5060008@home.nl> Thanks, Can this be a way to solve the challenge : http://www.evanmiller.org/write-a-template-compiler-for-erlang.html Roelof Op 27-8-2015 om 4:41 schreef Richard A. O'Keefe: > On 26/08/2015, at 5:56 pm, Roelof Wobben wrote: >> the exact text of the challenge is here : >> >> Configuration files can be conveniently represented as JSON terms. > > Yuck. This has "representation" backwards. > Here's what we have, using [thing] for "things" > and (action) for "processes". > > In our heads In our processes In our file system > [abstract [stored > configuration -(implement) -> configuration > value] data] > | | > (conversion) (programmed conversion) > | | > v | > [abstract v > JSON value] -(implement) -> [stored JSON value] > | | > v | > (unparse) (programmed unparsing) > | | > [abstract token v > sequence] -(implement) -> [stored token sequence] > | | > (layout + unlex) (programmed layout + unlex) > | | > v | > [abstract character v > sequence] -(implement) -> [stored character sequence] > | | > (Unicode encoding) (programmed encoding) > | | > v | > [abstract byte v > sequence] -(implement) -> [stored byte sequence] > | | > (compress, (programmed compression. > encrypt, encryption, signing, > sign, &c) and so on) > | | > v v > [another abstract [another stored > byte sequence] byte sequence] ---(store)---> [FILE] > There is an ABSTRACT space of JSON terms. > > Each of the arrows (down and right) is a "representation" arrow. > The thing at the tip of the arrow represents the thing at the > base of the arrow. The file we end up with is the thing that > does the representing (GIVEN this framework), and the > configuration data is what is represented. > > Don't take "stored" too literally. A "stored" data in the > middle column could be a data structure or a communication > pattern. I just mean that it's "inside the computer" in > the sense that it is directly accessible to code. > > This diagram must commute, that is, whatever path you take > through the arrows, you must end up with *equivalent* things. > > Not equal. > > Converting configuration values to JSON values need not be > unique. For example, a set of n elements might be converted > to a JSON array without duplicates in n! ways. But we can > arrange to treat permuted arrays in certain contexts as > equivalent. > > Converting JSON values to token sequences is not unique. > For example, a JSON object doesn't *have* any order to it, > but for unparsing, you have to pick an order. Given an > object with n pairs, there are n! ways to order them. > We can arrange to treat those as equivalent. > > Unlexing, converting tokens to character sequences, is not > unique. 1, 1e0, 10e-1, 1.0e1, &c are the same, so even > without allowing leading zeros there are hundreds of > ways (but not infinitely many ways) to represent a number > token. Most unicode characters can be represented in two > ways (/ can be represented in three), so a string of n > characters can be unlexed in at least 2**n ways. (It's > worse than that because \u002f and \u002F are equivalent, > so / has four alternatives.) > Layout can insert arbitrary amounts of white space between tokens, > and there are infinitely many ways to do that. > > There are multiple definitions of JSON. ECMA 404 stops at > the level of Unicode character sequences, and has nothing > to say about encoding. There are LOTS of encodings. > > There are also many compression, encryption, and digital > signature algorithms, which be freely composed. > > JSON qua JSON has nothing to say about how files are encoded > or whether they are compressed, encrypted, or signed. But > to put text into a file, you have to encode it somehow, and > you have to make some decision about other matters. (And > don't get me onto file systems with fixed length records, > where you have to figure out how to fit a 1 million character > string into 128 byte records... > >> Write >> some functions to read configuration files containing JSON terms and >> turn them into Erlang maps. > What if a configuration file represents this JSON term: > [["target","some program"], > ["source","some other program"], > ["date",[2015,08,27,14,05]], > ["gibberish",[3,1,4,1,5,9,2,7]]] > > How are you supposed to convert *that* to an Erlang map? > In any way that makes sense? > Oh, I know: > > {"": <<"[[\"target...7,]]]>>} > > or whatever the syntax for maps is. > It technically satisfies the requirements! > > The first thing to do with these exercises is CRITICISE them. > I do not mean to sneer at them and throw them away, but to > start from a presupposition that the language is muddled, > the contents confused, and the requirements either incomplete > or inconsistent. (Like practically *every* requirement we > start with including some published standards. I'm looking > at you, ECMA 404!) > > I am not kidding. You have to start out by trying to > understand the requirements, EXPECTING to find problems, > RESOLVING them, and writing down REVISED requirements > that spell out everything you actually need to know. > > For example, you might include the following: > > - Only the UTF-8 encoding is to be supported. > - No compression, encryption, or signing are to be supported. > - You may assume that the file system treats a file as > an arbitrary sequence of bytes with no record boundaries. > - You are to convert null, false, true to the Erlang atoms > 'null, 'false', 'true'. > - You are to convert JSON numbers to Erlang floats. > - You are to convert JSON strings to Erlang binaries. > - You are to convert JSON arrays to Erlang lists; > nothing else is to be converted to a list. > - You are to convert JSON objects to Erlang maps; > nothing else is to be converted to a map. > - You are not to worry about inverting the conversion > from configuration data to JSON terms; there is no > configuration data, that was just put in to make it > interesting. > >> Write some code to perform sanity checks >> on the data in the configuration files. > Here is another piece of confusion/incompleteness, or > possibly even questionable advice. > > This presupposes some procedure where you FIRST convert > a JSON text stored in a file to some Erlang term and > THEN you check the sanity. Or at least, it seems to. > > Another approach is to check as you go so that there is > never any insane Erlang data at all. > > This is highly topical, because we've recently seen a > bunch of serious Android security bugs caused by > overly trusting object deserialisation which allowed > objects to be constructed violating their invariants. > In fact this has triggered a burst of work on my > Smalltalk system, because I had a great big OOPS: > oh dear, I have the same problem. So I'm now slogging > through nearly a thousand files turning comments > about invariants into executable code and writing > invariants for the *shameful* number of classes that > had none, so that the deserialisation code can call > each newly reconstructed object's #invariant method > before trusting it. > > So I strongly recommend validating data as you parse > it, and if a sanity check is failed, crash immediately. > This leaves nothing for subsequent sanity checks to do. > > UNLESS you have configuration data that's converted to > JSON terms in such a way that not all terms represent > valid configuration data. But from what you quote, > you haven't been given anything for sanity checks like > that to DO. > > All things considerd, the exercise appears to be a > cryptic way of saying "WRITE A JSON PARSER". > > For what it's worth, my JSON parser in Smalltalk is > 117 lines for a tokeniser + 45 lines for a parser. > Being stricter about the input would let me shave > about 20 lines off the total. > > Much of the trickiness is in handling strings, > where JSON requires that a character outside the > Basic Multilingual plane must be encoded as a > surrogate pair. > > Processing a sequence of characters as an Erlang > string will probably make your life simpler; and > processing a sequence of tokens as an Erlang list > will also be likely to make your life simpler. > --- Dit e-mailbericht is gecontroleerd op virussen met Avast antivirussoftware. https://www.avast.com/antivirus From g@REDACTED Thu Aug 27 16:01:13 2015 From: g@REDACTED (Garrett Smith) Date: Thu, 27 Aug 2015 09:01:13 -0500 Subject: [erlang-questions] json to map In-Reply-To: <55DEEEB6.5060008@home.nl> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> Message-ID: On Thu, Aug 27, 2015 at 6:04 AM, Roelof Wobben wrote: > Thanks, > > Can this be a way to solve the challenge : > http://www.evanmiller.org/write-a-template-compiler-for-erlang.html I think the challenge is to take smaller steps here... Either solve this challenge by finding a JSON parser and using it, or redefine the challenge to "create a simple parser". Parsing JSON is a challenge, but I think you should define an interim challenge first - one that's less challenging. Strictly speaking the challenge of parsing JSON in Erlang (and therefore being able to generate other forms) is not that challenging as there are like half a dozen decent libraries to do that already. It can be a challenge to find them, compile and use them - but not that challenging. So why not just do that and cross this challenge off your list? Then, create a new challenge, which is to parse some simply expression like "1 + 1" into a term in Erlang. You can then do something interesting with that term! See hint [1] This is a good challenge IMO because you'll learn a lot about Erlang (your goal) and you'll also experience the empowerment of building your own language, even if a very simple one. What I'm really trying to say is that it's challenging to define the right challenge. Richard said it best: > The first thing to do with these exercises is CRITICISE them. But don't criticize mine :) [1] https://gist.github.com/cooldaemon/13773/6133f606a809dbd05683f290afaac21fbe7e2ce4 From g@REDACTED Thu Aug 27 16:10:10 2015 From: g@REDACTED (Garrett Smith) Date: Thu, 27 Aug 2015 09:10:10 -0500 Subject: [erlang-questions] Chicago Erlang - workshop edition! 10 October In-Reply-To: References: Message-ID: I agree with everything said here! On Thu, Aug 27, 2015 at 5:46 AM, Andra Dinu wrote: > Hi all, > > This year Chicago Erlang is shifting to a hands-on, write-some-code workshop > edition. We prepared two parallel tracks: > > > Essentials: Led by Erlang authors and instructors Martin Logan and Fred > Hebert, this track is tailored for programmers who are new to Erlang and > want to lay a solid foundation. > > > IoT App Buildout is for more advanced developers. Web Scale engineers Brian > Troutwine and Garrett Smith take you into the deep end of the pool with an > Internet of Things (IoT) backend that features Erlang?s concurrency model > and network support. > > > Early Bird rate is $49. It doesn't get any better than this, and places are > limited: http://www.chicagoerlang.com/ > > > Best, > Andra > > > > Andra Dinu > Community & Social > > Code Mesh London 2-4 November: NOT your usual tech conference... > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > From felixgallo@REDACTED Thu Aug 27 18:05:06 2015 From: felixgallo@REDACTED (Felix Gallo) Date: Thu, 27 Aug 2015 09:05:06 -0700 Subject: [erlang-questions] json to map In-Reply-To: References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> Message-ID: Roelof: don't do the JSON parser. Do Garrett's suggestion instead. I recommend the added facet of trying to build a simple, complete four-function calculator. For extra credit, add the ability to use parentheses, which gets you to some fundamental computer science discoveries. ROK is, as always, correct that this area (parsing ill-defined specifications involving text) is one of the Great Problems of Computer Science, rife with monsters named lex and yacc and their cousins yecc and leex, in the lair of the dread throne of the Basic Multilingual Plane where surrogate pairs lurk in the deep pits of context-free grammar, gnawing on abstract syntax trees. Nevertheless, the admonition to criticise the exercise doesn't really help all the Roelofs, because they haven't spent countless years in the trenches yet, so have no basis to independently formulate the notion that a maximalist reading of the problem would necessitate a lawyerly reading of iso/iec 10646, or the implementation of an LR(1) parser, or whatever. The analysis and subsequent constructive exercise-sculpting does need to come from a grizzled, irascible, greying mentor; in my opinion. F. On Thu, Aug 27, 2015 at 7:01 AM, Garrett Smith wrote: > On Thu, Aug 27, 2015 at 6:04 AM, Roelof Wobben wrote: > > Thanks, > > > > Can this be a way to solve the challenge : > > http://www.evanmiller.org/write-a-template-compiler-for-erlang.html > > I think the challenge is to take smaller steps here... > > Either solve this challenge by finding a JSON parser and using it, or > redefine the challenge to "create a simple parser". > > Parsing JSON is a challenge, but I think you should define an interim > challenge first - one that's less challenging. > > Strictly speaking the challenge of parsing JSON in Erlang (and > therefore being able to generate other forms) is not that challenging > as there are like half a dozen decent libraries to do that already. It > can be a challenge to find them, compile and use them - but not that > challenging. So why not just do that and cross this challenge off your > list? > > Then, create a new challenge, which is to parse some simply expression > like "1 + 1" into a term in Erlang. You can then do something > interesting with that term! See hint [1] > > This is a good challenge IMO because you'll learn a lot about Erlang > (your goal) and you'll also experience the empowerment of building > your own language, even if a very simple one. > > What I'm really trying to say is that it's challenging to define the > right challenge. Richard said it best: > > > The first thing to do with these exercises is CRITICISE them. > > But don't criticize mine :) > > [1] > https://gist.github.com/cooldaemon/13773/6133f606a809dbd05683f290afaac21fbe7e2ce4 > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ok@REDACTED Fri Aug 28 07:21:57 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Fri, 28 Aug 2015 17:21:57 +1200 Subject: [erlang-questions] json to map In-Reply-To: <55DEEEB6.5060008@home.nl> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> Message-ID: <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> On 27/08/2015, at 11:04 pm, Roelof Wobben wrote: > Thanks, > > Can this be a way to solve the challenge : http://www.evanmiller.org/write-a-template-compiler-for-erlang.html That link starts by making three claims: ? Erlang is hard to refactor I don't find manual refactoring harder in Erlang than in any other language (not excluding Java and Smalltalk). I haven't tried Wrangler or RefactorErl (see http://plc.inf.elte.hu/erlang/) yet, but they look good. ? There is no built-in syntax for hash maps This is no longer true. ? String manipulation is hard That's a puzzler. I've found string manipulation using lists *easier* in Erlang than in almost anything but SNOBOL or Prolog. I would certainly ***MUCH*** rather write a string -> JSON parser in Erlang than in say Java or even Lisp. (Of course the Bigloo implementation of Scheme has special support for lexers and parsers built in, which does change the picture.) The question is always "compared with WHAT?" In many case the key trick for manipulating strings is DON'T. My JSON parser in Smalltalk, for example, is only concerned with strings to the extent that they are a nasty problem posed by JSON that it has to solve; they are not something that it uses for its own purposes. The tokeniser converts a stream of characters to a stream of tokens, and the parser works with tokens, not characters. (Yes, I know about scannerless parsers, but the factoring has always helped me to get a parser working. A separate tokeniser is something that I can *TEST* without having to have the rest of the parser working.) Then it turns out that the web page is really about writing a compiler from "Django Template Language" to Erlang. "It helps to get a hold of a language specification if there is one. I am implementing the Django Template Language. There's not really a spec, but there is an official implementation in Python," OUCH! What *IS* it about this industry? Why do we get notations that become popular where there is no spec (like Markdown, originally, or JSON, ditto -- it had syntax but no semantics) or the spec is confused (like XML, where they muddled up syntax and semantics so that we ended up with several different semantics for XML, or the first version of RDF, where they meant to define it in terms of XML semantics, but there wasn't really one, so they defined it in terms of XML syntax *by mistake*). That page talks about writing a scanner with an argument to say what the state is. This is almost always a bad idea. Each state should be modelled by a separate Erlang function. Let's see an example of this. Let's consider dates written in one of four ways: dd/mm/yyyy dd MON yyyy MON dd[,] yyyy yyyy-mm-dd (By the way, we give matching and cleaning up data that's just a little bit more complex than this as an exercise to 3rd year students. Thinking in Java makes it *impossible* for them to get something like this right in a 2-hour lab session. Regular expressions are a royal road to ruin.) I'll do this in Haskell. data Token = TInt Int | TWord String | TSlash | TDash | TComma tokens :: [Char] -> [Token] tokens [] = [] tokens (c:cs) | isSpace c = tokens cs tokens (c:cs) | isDigit c = digits cs (ord c - ord '0') tokens (c:cs) | isAlpha c = word cs [c] tokens ('/':cs) = TSlash : tokens cs tokens ('-':cs) = TDash : tokens cs tokens (',':cs) = TComma : tokens cs -- anything else will crash digits (c:cs) n | isDigit c = digits cs (ord c - ord '0' + n*10) : digits cs digits cs n = TInt : tokens cs word (c:cs) w | isAlpha c = word cs (toLower c : w) word cs w = TWord (reverse w) : tokens cs Converting the tokeniser to Erlang is a trivial exercise for the reader. valid_month :: String -> Int valid_month "jan" = 1 valid_month "january" = 1 ... valid_month "december" = 12 -- anything else will crash string_to_date :: [Char] -> (Int,Int,Int) string_to_date cs = case tokens cs of [TInt d,TSlash,TInt m,TSlash,TInt y] -> check y m d [TInt y,TDash, TInt m,TDash, TInt d] -> check y m d [TInt d,TWord m,TInt y] -> check y (valid_month m) d [TWord m,TInt d,TComma,TInt y] -> check y (valid_month m) d [TWord m,TInt d, TInt y] -> check y (valid_month m) d -- anything else will crash check :: Int -> Int -> Int -> (Int,Int,Int) -- left as a boring exercise for the reader. Converting this to Erlang is also a trivial exercise for the reader. You will notice that there are multiple scanning functions and no 'what state am I in?' parameter. Your scanner should KNOW what state it is in because it knows what function is running. Yecc is a great tool, but for something like this there's no real point in it, and even for something like JSON I would rather not use it. One thing that Leex and Yecc can do for you is to help you track source position for reporting errors. For a configuration file, it may be sufficient to just say "Can't parse configuration file X as JSON." OK, the technique I used above is "recursive descent", which works brilliantly for LL(k) languages with small k. But you knew that. Oh yes, this does mean that writing a parser is just like writing a lexical analyser, except that you get to use general recursion. Again, you typically have (at least) one function per non-terminal symbol, plus (if your original specification used extended BNF) one function per repetition. Heck. s expression = word | "(", [s expression+, [".", s expression]], ")". data SExpr = Word String | Cons SExpr SExpr | Nil s_expression :: [Token] -> (SExpr, [Token]) s_expression (TWord w : ts) = (Word w, ts) s_expression (TLp : TRp : ts) = (Nil, ts) s_expression (TLp : ts) = s_expr_body ts s_expr_body (TRp : ts) = (Nil ts) s_expr_body (TDot : ts) = let (e, TRp : ts') = s_expression ts in (e, ts') s_expr_body ts = let (f, ts') = s_expression ts (r, ts'') = s_expr_body ts' in (f:r, ts'') This is so close to JSON that handling JSON without "objects" should now be straightforward. And it makes a good development step. From r.wobben@REDACTED Fri Aug 28 09:45:18 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Fri, 28 Aug 2015 09:45:18 +0200 Subject: [erlang-questions] json to map In-Reply-To: <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> Message-ID: <55E0118E.8070301@home.nl> I will take the challenge but im stuck at the types part. so far I have this : -module(time_parser). -export([]). -type token :: tInt() | tWord() | tSlash() | tDash() | tComma(). -type tint() :: integer(). -type tword() :: binary(). -type tSlash() :: binary(). -type tDash() :: binary(). -type tComma() :: binary(). and I see this error : time_parser.erl:5: bad type declaration Roelof ime_parser.erl:5: bad type declaration Op 28-8-2015 om 07:21 schreef Richard A. O'Keefe: > On 27/08/2015, at 11:04 pm, Roelof Wobben wrote: > >> Thanks, >> >> Can this be a way to solve the challenge : http://www.evanmiller.org/write-a-template-compiler-for-erlang.html > That link starts by making three claims: > > ? Erlang is hard to refactor > > I don't find manual refactoring harder in Erlang than in > any other language (not excluding Java and Smalltalk). > I haven't tried Wrangler or RefactorErl (see > http://plc.inf.elte.hu/erlang/) yet, but they look good. > > ? There is no built-in syntax for hash maps > > This is no longer true. > > ? String manipulation is hard > > That's a puzzler. I've found string manipulation using > lists *easier* in Erlang than in almost anything but SNOBOL > or Prolog. I would certainly ***MUCH*** rather write a > string -> JSON parser in Erlang than in say Java or even > Lisp. (Of course the Bigloo implementation of Scheme has > special support for lexers and parsers built in, which does > change the picture.) > > The question is always "compared with WHAT?" In many case > the key trick for manipulating strings is DON'T. My JSON > parser in Smalltalk, for example, is only concerned with > strings to the extent that they are a nasty problem posed > by JSON that it has to solve; they are not something that > it uses for its own purposes. The tokeniser converts a > stream of characters to a stream of tokens, and the parser > works with tokens, not characters. (Yes, I know about > scannerless parsers, but the factoring has always helped me > to get a parser working. A separate tokeniser is something > that I can *TEST* without having to have the rest of the > parser working.) > > Then it turns out that the web page is really about writing > a compiler from "Django Template Language" to Erlang. > "It helps to get a hold of a language specification if there > is one. I am implementing the Django Template Language. There's > not really a spec, but there is an official implementation in Python," > > OUCH! What *IS* it about this industry? Why do we get notations > that become popular where there is no spec (like Markdown, > originally, or JSON, ditto -- it had syntax but no semantics) > or the spec is confused (like XML, where they muddled up > syntax and semantics so that we ended up with several different > semantics for XML, or the first version of RDF, where they > meant to define it in terms of XML semantics, but there wasn't > really one, so they defined it in terms of XML syntax *by mistake*). > > That page talks about writing a scanner with an argument to > say what the state is. This is almost always a bad idea. > Each state should be modelled by a separate Erlang function. > > Let's see an example of this. > Let's consider dates written in one of four ways: > dd/mm/yyyy > dd MON yyyy > MON dd[,] yyyy > yyyy-mm-dd > > (By the way, we give matching and cleaning up data that's just > a little bit more complex than this as an exercise to 3rd year > students. Thinking in Java makes it *impossible* for them to > get something like this right in a 2-hour lab session. > Regular expressions are a royal road to ruin.) > > I'll do this in Haskell. > > data Token > = TInt Int > | TWord String > | TSlash > | TDash > | TComma > > tokens :: [Char] -> [Token] > > tokens [] = [] > tokens (c:cs) | isSpace c = tokens cs > tokens (c:cs) | isDigit c = digits cs (ord c - ord '0') > tokens (c:cs) | isAlpha c = word cs [c] > tokens ('/':cs) = TSlash : tokens cs > tokens ('-':cs) = TDash : tokens cs > tokens (',':cs) = TComma : tokens cs > -- anything else will crash > > digits (c:cs) n | isDigit c = digits cs (ord c - ord '0' + n*10) : digits cs > digits cs n = TInt : tokens cs > > word (c:cs) w | isAlpha c = word cs (toLower c : w) > word cs w = TWord (reverse w) : tokens cs > > Converting the tokeniser to Erlang is a trivial exercise for > the reader. > > valid_month :: String -> Int > valid_month "jan" = 1 > valid_month "january" = 1 > ... > valid_month "december" = 12 > -- anything else will crash > > string_to_date :: [Char] -> (Int,Int,Int) > > string_to_date cs = > case tokens cs of > [TInt d,TSlash,TInt m,TSlash,TInt y] -> check y m d > [TInt y,TDash, TInt m,TDash, TInt d] -> check y m d > [TInt d,TWord m,TInt y] -> check y (valid_month m) d > [TWord m,TInt d,TComma,TInt y] -> check y (valid_month m) d > [TWord m,TInt d, TInt y] -> check y (valid_month m) d > -- anything else will crash > > check :: Int -> Int -> Int -> (Int,Int,Int) > -- left as a boring exercise for the reader. > > Converting this to Erlang is also a trivial exercise for the reader. > > You will notice that there are multiple scanning functions and > no 'what state am I in?' parameter. Your scanner should KNOW > what state it is in because it knows what function is running. > > Yecc is a great tool, but for something like this there's no > real point in it, and even for something like JSON I would > rather not use it. > > One thing that Leex and Yecc can do for you > is to help you track source position for reporting > errors. For a configuration file, it may be sufficient to > just say "Can't parse configuration file X as JSON." > > OK, the technique I used above is "recursive descent", > which works brilliantly for LL(k) languages with small k. > But you knew that. > Oh yes, this does mean that writing a parser is just like > writing a lexical analyser, except that you get to use > general recursion. Again, you typically have (at least) > one function per non-terminal symbol, plus (if your > original specification used extended BNF) one function > per repetition. > > Heck. > s expression > = word > | "(", [s expression+, [".", s expression]], ")". > > data SExpr > = Word String > | Cons SExpr SExpr > | Nil > > s_expression :: [Token] -> (SExpr, [Token]) > > s_expression (TWord w : ts) = (Word w, ts) > s_expression (TLp : TRp : ts) = (Nil, ts) > s_expression (TLp : ts) = s_expr_body ts > > s_expr_body (TRp : ts) = (Nil ts) > s_expr_body (TDot : ts) = > let (e, TRp : ts') = s_expression ts > in (e, ts') > s_expr_body ts = > let (f, ts') = s_expression ts > (r, ts'') = s_expr_body ts' > in (f:r, ts'') > > This is so close to JSON that handling JSON without > "objects" should now be straightforward. And it makes > a good development step. > > > > > > > ----- > Geen virus gevonden in dit bericht. > Gecontroleerd door AVG - www.avg.com > Versie: 2015.0.6140 / Virusdatabase: 4409/10524 - datum van uitgifte: 08/27/15 > > > From bengt.kleberg@REDACTED Fri Aug 28 10:31:27 2015 From: bengt.kleberg@REDACTED (Bengt Kleberg) Date: Fri, 28 Aug 2015 10:31:27 +0200 Subject: [erlang-questions] json to map In-Reply-To: <55E0118E.8070301@home.nl> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> Message-ID: <55E01C5F.3050504@ericsson.com> Greetings, Dialyzer is not my forte, but on line 5 you have a type (token) without () after it. All other types have () as suffix. Could this be a problem? bengt On 08/28/2015 09:45 AM, Roelof Wobben wrote: > I will take the challenge but im stuck at the types part. > > so far I have this : > > -module(time_parser). > > -export([]). > > -type token :: tInt() > | tWord() > | tSlash() > | tDash() > | tComma(). > > -type tint() :: integer(). > -type tword() :: binary(). > -type tSlash() :: binary(). > -type tDash() :: binary(). > -type tComma() :: binary(). > > > and I see this error : time_parser.erl:5: bad type declaration > > Roelof > > ime_parser.erl:5: bad type declaration > > > Op 28-8-2015 om 07:21 schreef Richard A. O'Keefe: >> On 27/08/2015, at 11:04 pm, Roelof Wobben wrote: >> >>> Thanks, >>> >>> Can this be a way to solve the challenge : >>> http://www.evanmiller.org/write-a-template-compiler-for-erlang.html >> That link starts by making three claims: >> >> ? Erlang is hard to refactor >> >> I don't find manual refactoring harder in Erlang than in >> any other language (not excluding Java and Smalltalk). >> I haven't tried Wrangler or RefactorErl (see >> http://plc.inf.elte.hu/erlang/) yet, but they look good. >> >> ? There is no built-in syntax for hash maps >> >> This is no longer true. >> >> ? String manipulation is hard >> >> That's a puzzler. I've found string manipulation using >> lists *easier* in Erlang than in almost anything but SNOBOL >> or Prolog. I would certainly ***MUCH*** rather write a >> string -> JSON parser in Erlang than in say Java or even >> Lisp. (Of course the Bigloo implementation of Scheme has >> special support for lexers and parsers built in, which does >> change the picture.) >> >> The question is always "compared with WHAT?" In many case >> the key trick for manipulating strings is DON'T. My JSON >> parser in Smalltalk, for example, is only concerned with >> strings to the extent that they are a nasty problem posed >> by JSON that it has to solve; they are not something that >> it uses for its own purposes. The tokeniser converts a >> stream of characters to a stream of tokens, and the parser >> works with tokens, not characters. (Yes, I know about >> scannerless parsers, but the factoring has always helped me >> to get a parser working. A separate tokeniser is something >> that I can *TEST* without having to have the rest of the >> parser working.) >> >> Then it turns out that the web page is really about writing >> a compiler from "Django Template Language" to Erlang. >> "It helps to get a hold of a language specification if there >> is one. I am implementing the Django Template Language. There's >> not really a spec, but there is an official implementation in Python," >> >> OUCH! What *IS* it about this industry? Why do we get notations >> that become popular where there is no spec (like Markdown, >> originally, or JSON, ditto -- it had syntax but no semantics) >> or the spec is confused (like XML, where they muddled up >> syntax and semantics so that we ended up with several different >> semantics for XML, or the first version of RDF, where they >> meant to define it in terms of XML semantics, but there wasn't >> really one, so they defined it in terms of XML syntax *by mistake*). >> >> That page talks about writing a scanner with an argument to >> say what the state is. This is almost always a bad idea. >> Each state should be modelled by a separate Erlang function. >> >> Let's see an example of this. >> Let's consider dates written in one of four ways: >> dd/mm/yyyy >> dd MON yyyy >> MON dd[,] yyyy >> yyyy-mm-dd >> >> (By the way, we give matching and cleaning up data that's just >> a little bit more complex than this as an exercise to 3rd year >> students. Thinking in Java makes it *impossible* for them to >> get something like this right in a 2-hour lab session. >> Regular expressions are a royal road to ruin.) >> >> I'll do this in Haskell. >> >> data Token >> = TInt Int >> | TWord String >> | TSlash >> | TDash >> | TComma >> >> tokens :: [Char] -> [Token] >> >> tokens [] = [] >> tokens (c:cs) | isSpace c = tokens cs >> tokens (c:cs) | isDigit c = digits cs (ord c - ord '0') >> tokens (c:cs) | isAlpha c = word cs [c] >> tokens ('/':cs) = TSlash : tokens cs >> tokens ('-':cs) = TDash : tokens cs >> tokens (',':cs) = TComma : tokens cs >> -- anything else will crash >> >> digits (c:cs) n | isDigit c = digits cs (ord c - ord '0' + n*10) : >> digits cs >> digits cs n = TInt : tokens cs >> >> word (c:cs) w | isAlpha c = word cs (toLower c : w) >> word cs w = TWord (reverse w) : tokens cs >> >> Converting the tokeniser to Erlang is a trivial exercise for >> the reader. >> >> valid_month :: String -> Int >> valid_month "jan" = 1 >> valid_month "january" = 1 >> ... >> valid_month "december" = 12 >> -- anything else will crash >> >> string_to_date :: [Char] -> (Int,Int,Int) >> >> string_to_date cs = >> case tokens cs of >> [TInt d,TSlash,TInt m,TSlash,TInt y] -> check y m d >> [TInt y,TDash, TInt m,TDash, TInt d] -> check y m d >> [TInt d,TWord m,TInt y] -> check y (valid_month m) d >> [TWord m,TInt d,TComma,TInt y] -> check y (valid_month m) d >> [TWord m,TInt d, TInt y] -> check y (valid_month m) d >> -- anything else will crash >> >> check :: Int -> Int -> Int -> (Int,Int,Int) >> -- left as a boring exercise for the reader. >> >> Converting this to Erlang is also a trivial exercise for the reader. >> >> You will notice that there are multiple scanning functions and >> no 'what state am I in?' parameter. Your scanner should KNOW >> what state it is in because it knows what function is running. >> >> Yecc is a great tool, but for something like this there's no >> real point in it, and even for something like JSON I would >> rather not use it. >> >> One thing that Leex and Yecc can do for you >> is to help you track source position for reporting >> errors. For a configuration file, it may be sufficient to >> just say "Can't parse configuration file X as JSON." >> >> OK, the technique I used above is "recursive descent", >> which works brilliantly for LL(k) languages with small k. >> But you knew that. >> Oh yes, this does mean that writing a parser is just like >> writing a lexical analyser, except that you get to use >> general recursion. Again, you typically have (at least) >> one function per non-terminal symbol, plus (if your >> original specification used extended BNF) one function >> per repetition. >> >> Heck. >> s expression >> = word >> | "(", [s expression+, [".", s expression]], ")". >> >> data SExpr >> = Word String >> | Cons SExpr SExpr >> | Nil >> >> s_expression :: [Token] -> (SExpr, [Token]) >> >> s_expression (TWord w : ts) = (Word w, ts) >> s_expression (TLp : TRp : ts) = (Nil, ts) >> s_expression (TLp : ts) = s_expr_body ts >> >> s_expr_body (TRp : ts) = (Nil ts) >> s_expr_body (TDot : ts) = >> let (e, TRp : ts') = s_expression ts >> in (e, ts') >> s_expr_body ts = >> let (f, ts') = s_expression ts >> (r, ts'') = s_expr_body ts' >> in (f:r, ts'') >> >> This is so close to JSON that handling JSON without >> "objects" should now be straightforward. And it makes >> a good development step. >> >> >> >> >> >> >> ----- >> Geen virus gevonden in dit bericht. >> Gecontroleerd door AVG - www.avg.com >> Versie: 2015.0.6140 / Virusdatabase: 4409/10524 - datum van uitgifte: >> 08/27/15 >> >> >> > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions From ok@REDACTED Fri Aug 28 11:02:12 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Fri, 28 Aug 2015 21:02:12 +1200 Subject: [erlang-questions] json to map In-Reply-To: <55E01C5F.3050504@ericsson.com> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> Message-ID: <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> On 28/08/2015, at 8:31 pm, Bengt Kleberg wrote: > On 08/28/2015 09:45 AM, Roelof Wobben wrote: >> I will take the challenge but im stuck at the types part. By far the easiest way to convert my Haskell sample code to Erlang is to throw the types completely away, or just leave them as comments. >> >> so far I have this : >> >> -module(time_parser). >> >> -export([]). >> >> -type token :: tInt() >> | tWord() >> | tSlash() >> | tDash() >> | tComma(). >> >> -type tint() :: integer(). >> -type tword() :: binary(). >> -type tSlash() :: binary(). >> -type tDash() :: binary(). >> -type tComma() :: binary(). Leaving the omitted () aside, this isn't even CLOSE to a good translation of the Haskell data type. This makes tword -- should have been tWord and both of them should be t_word in idiomatic Erlang -- and tSlash and tDash and tComma the *same* type. But the whole point is to make them DIFFERENT. -type token :: {int,integer()} | {word,string()} %% NOT binary! | '/' | '-' | ','. The alternatives MUST be such that they cannot be confused with one another. tokens([]) -> []; tokens([C|Cs]) when C =< 32 -> tokens(Cs); tokens([C|Cs]) when $0 =< C, C =< $9 -> digits(Cs, C-$0); tokens([C|Cs]) when $a =< C, C =< $z -> word(Cs, [C]); tokens([C|Cs]) when $A =< C, C =< $Z -> word(Cs, [C]); tokens("/"++Cs) -> ['/' | tokens(Cs)]; tokens("-"++Cs) -> ['-' | tokens(Cs)]; tokens(","++Cs) -> [',' | tokens(Cs)]. Of course this wants to convert the letters to lower case, and it would be really nice to have standard is_digit(Codepoint[, Base]) is_lower(Codepoint) is_upper(Codepoint) is_alpha(Codepoint) is_space(Codepoint) guards. No, macros are NOT good enough; -define(is_alpha(C), $a =< ((C) bor 32) =< $z). was fine for ASCII, but failed dramatically for Latin 1, and these are the days of Unicode. It's nearly 9pm, time to go home. Maybe I should write an EEP about this. You might say, well, use regular expressions. Match letters using the POSIX '[[:alpha:]]' construction. But what does _that_ rely on, eh? I have completed the translation of the tokeniser from Haskell to Erlang, and it is pretty much line for line, and it works. 4> t:t("Jan 26, 1942"). [{word,"jan"},{int,26},',',{int,1942}] 5> t:t("You need gumboots"). [{word,"you"},{word,"need"},{word,"gumboots"}] 6> t:t("Can you dance the Watusi?"). ** exception error: no function clause matching t:tokens("?") (t.erl, line 7) in function t:word/2 (t.erl, line 22) in call from t:word/2 (t.erl, line 22) Here's a curious thought. The use of [Token | tokens(Cs)] means that the stack builds up a tower of tokens/1 calls, one per token. By passing the list of tokens so far through, this can all be tail calls. tokens(Cs) -> lists:reverse(tokens(Cs, [])). ... tokens("/"++Cs, Ts) -> tokens(Cs, ['/'|Ts]); ... But then there's that reversal step. Not a big deal, BUT it's no harder to parse JSON backwards than it is to parse JSON forwards! (Even if you allow JavaScript comments, they disappear in tokenising, so the *tokens* can be parsed backwards easily.) This is a peculiarity of JSON. I think you can pull the same trick with XML: lex it forwards, parse the token sequence backwards. From r.wobben@REDACTED Fri Aug 28 12:59:55 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Fri, 28 Aug 2015 12:59:55 +0200 Subject: [erlang-questions] json to map In-Reply-To: <55E01C5F.3050504@ericsson.com> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> Message-ID: <55E03F2B.9090907@home.nl> Op 28-8-2015 om 10:31 schreef Bengt Kleberg: > Greetings, > > Dialyzer is not my forte, but on line 5 you have a type (token) > without () after it. All other types have () as suffix. > Could this be a problem? > > > bengt > I do noy think so. When I changed it to this : -module(time_parser). -export([]). -type tint() :: integer(). -type tword() :: binary(). -type tSlash() :: binary(). -type tDash() :: binary(). -type tComma() :: binary(). -type token() :: tInt() | tWord() | tSlash() | tDash() | tComma(). I see these error messagaes; time_parser.erl:12: type tInt() undefined time_parser.erl:13: type tWord() undefined time_parser.erl:5: Warning: type tint() is unused time_parser.erl:6: Warning: type tword() is unused time_parser.erl:12: Warning: type token() is unused error Roelof From r.wobben@REDACTED Fri Aug 28 13:04:14 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Fri, 28 Aug 2015 13:04:14 +0200 Subject: [erlang-questions] json to map In-Reply-To: <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> Message-ID: <55E0402E.50500@home.nl> Op 28-8-2015 om 11:02 schreef Richard A. O'Keefe: > On 28/08/2015, at 8:31 pm, Bengt Kleberg wrote: > >> On 08/28/2015 09:45 AM, Roelof Wobben wrote: >>> I will take the challenge but im stuck at the types part. > By far the easiest way to convert my Haskell sample code > to Erlang is to throw the types completely away, or just > leave them as comments. >>> so far I have this : >>> >>> -module(time_parser). >>> >>> -export([]). >>> >>> -type token :: tInt() >>> | tWord() >>> | tSlash() >>> | tDash() >>> | tComma(). >>> >>> -type tint() :: integer(). >>> -type tword() :: binary(). >>> -type tSlash() :: binary(). >>> -type tDash() :: binary(). >>> -type tComma() :: binary(). > Leaving the omitted () aside, this isn't even CLOSE to a > good translation of the Haskell data type. > This makes tword -- should have been tWord and both of > them should be t_word in idiomatic Erlang -- and tSlash > and tDash and tComma the *same* type. But the whole point > is to make them DIFFERENT. I have made them the same type because all three are only 1 character. I have used the code from fiffy as reference to make my own. I understand that they must be different but on some point they are the same. > -type token > :: {int,integer()} > | {word,string()} %% NOT binary! > | '/' > | '-' > | ','. > > The alternatives MUST be such that they cannot be > confused with one another. > > tokens([]) -> []; > tokens([C|Cs]) when C =< 32 -> tokens(Cs); > tokens([C|Cs]) when $0 =< C, C =< $9 -> digits(Cs, C-$0); > tokens([C|Cs]) when $a =< C, C =< $z -> word(Cs, [C]); > tokens([C|Cs]) when $A =< C, C =< $Z -> word(Cs, [C]); > tokens("/"++Cs) -> ['/' | tokens(Cs)]; > tokens("-"++Cs) -> ['-' | tokens(Cs)]; > tokens(","++Cs) -> [',' | tokens(Cs)]. > Pity , you gave me the answer. Now I can do a copy/paste and go on and the next time I do it wrong again. That is why I want to try this one on my own and make my own mistakes and learn from it , make more mistake and also learn from them. From essen@REDACTED Fri Aug 28 13:15:07 2015 From: essen@REDACTED (=?UTF-8?Q?Lo=c3=afc_Hoguin?=) Date: Fri, 28 Aug 2015 13:15:07 +0200 Subject: [erlang-questions] json to map In-Reply-To: <55E0402E.50500@home.nl> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> Message-ID: <55E042BB.4060409@ninenines.eu> On 08/28/2015 01:04 PM, Roelof Wobben wrote: > Pity , you gave me the answer. Now I can do a copy/paste and go on and > the next time I do it wrong again. > That is why I want to try this one on my own and make my own mistakes > and learn from it , make more mistake and also learn from them. Short piece of advice: if you do want to make your own mistakes and learn from it, *you have to find the solutions on your own*. Even if they are incomplete or barely working solutions. Practice makes perfect. Not asking questions every time things doesn't work. Even if people don't give you the solution directly. If you can't solve certain problems, it means you are lacking required knowledge, so move back to earlier problems and continue learning from there. Or try to give yourself a few gradually harder challenges until you get to the point where you can solve the problems you got stuck with. Considering your recent questions, you clearly lack knowledge that's *very basic* so I am not sure why you start writing typespecs and parsers which are advanced topics. -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang From g@REDACTED Fri Aug 28 13:23:33 2015 From: g@REDACTED (Garrett Smith) Date: Fri, 28 Aug 2015 06:23:33 -0500 Subject: [erlang-questions] json to map In-Reply-To: <55E0402E.50500@home.nl> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> Message-ID: On Fri, Aug 28, 2015 at 6:04 AM, Roelof Wobben wrote: > Op 28-8-2015 om 11:02 schreef Richard A. O'Keefe: > >> On 28/08/2015, at 8:31 pm, Bengt Kleberg >> wrote: >> >>> On 08/28/2015 09:45 AM, Roelof Wobben wrote: >>>> >>>> I will take the challenge but im stuck at the types part. >> >> By far the easiest way to convert my Haskell sample code >> to Erlang is to throw the types completely away, or just >> leave them as comments. >>>> >>>> so far I have this : >>>> >>>> -module(time_parser). >>>> >>>> -export([]). >>>> >>>> -type token :: tInt() >>>> | tWord() >>>> | tSlash() >>>> | tDash() >>>> | tComma(). >>>> >>>> -type tint() :: integer(). >>>> -type tword() :: binary(). >>>> -type tSlash() :: binary(). >>>> -type tDash() :: binary(). >>>> -type tComma() :: binary(). >> >> Leaving the omitted () aside, this isn't even CLOSE to a >> good translation of the Haskell data type. >> This makes tword -- should have been tWord and both of >> them should be t_word in idiomatic Erlang -- and tSlash >> and tDash and tComma the *same* type. But the whole point >> is to make them DIFFERENT. > > > I have made them the same type because all three are only 1 character. > I have used the code from fiffy as reference to make my own. > I understand that they must be different but on some point they are the > same. > > >> -type token >> :: {int,integer()} >> | {word,string()} %% NOT binary! >> | '/' >> | '-' >> | ','. >> >> The alternatives MUST be such that they cannot be >> confused with one another. >> >> tokens([]) -> []; >> tokens([C|Cs]) when C =< 32 -> tokens(Cs); >> tokens([C|Cs]) when $0 =< C, C =< $9 -> digits(Cs, C-$0); >> tokens([C|Cs]) when $a =< C, C =< $z -> word(Cs, [C]); >> tokens([C|Cs]) when $A =< C, C =< $Z -> word(Cs, [C]); >> tokens("/"++Cs) -> ['/' | tokens(Cs)]; >> tokens("-"++Cs) -> ['-' | tokens(Cs)]; >> tokens(","++Cs) -> [',' | tokens(Cs)]. >> > > > Pity , you gave me the answer. Now I can do a copy/paste and go on and the > next time I do it wrong again. > That is why I want to try this one on my own and make my own mistakes and > learn from it , make more mistake and also learn from them. No no no no. That's not the way to think about this IMO. In software you learn from your failures, but you learn *a lot more* from others' successes! I had originally suggested that you start learning about parser generating by giving you a complete working example, albeit a simple one. That's not depriving you of learning, it's giving you a road map for learning. With a working model you can start to tinker with the code, *use it*, start to change little bits of it to experiment with it and see how things change. IMO that's a learning process, it doesn't give anything away or make anything less valuable - to the contrary. I haven't read this thread carefully enough to know what this new challenge is, but I'd go back to the challenge I suggested earlier, which is to create a simple calculator. Use the hint - just use it! (Maybe you have already and have moved on to your next challenge - again, I'm not reading carefully here.) Then play with the stuff that's *working* and start to improve it (or simplify it event) - you should not move onto any new challenges until you know that code inside and out and understand what each and every character is there for. And IMO that requires exercising it iteratively as you make changes. And please be sensitive to the challenges of your readers here - you are asking for help on specific topics and the temptation is to help you. You've got the best humans on earth (excluding me, work in progress) reading your challenges and thinking carefully about your learning process and the issues you're facing - and then taking a great deal of time and care to respond constructively. If someone slips up and give you an answer here or there, please forgive them as they are ony trying to help you. From montuori@REDACTED Fri Aug 28 13:50:47 2015 From: montuori@REDACTED (Kevin Montuori) Date: Fri, 28 Aug 2015 07:50:47 -0400 Subject: [erlang-questions] json to map In-Reply-To: <55E03F2B.9090907@home.nl> (Roelof Wobben's message of "Fri, 28 Aug 2015 12:59:55 +0200") References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <55E03F2B.9090907@home.nl> Message-ID: >>>>> "rw" == Roelof Wobben writes: rw> -type tword() :: binary(). rw> -type token() :: tInt() rw> | tWord() rw> time_parser.erl:12: type tInt() undefined time_parser.erl:13: type rw> tWord() undefined rw> time_parser.erl:6: Warning: type tword() is unused [Leaving aside all of the excellent advice that's been proffered...] Did you read these messages carefully? tWord() is undefined but tword() is unused: the answer's staring you in the face. If you've been writing Erlang for a while this error/warning pair should ring a bell. Perhaps you should revisit Mr. O'Keefe's email, specifically the part where he discusses Erlang naming conventions (and tells you *exactly* what's wrong with what you have)? k. -- Kevin Montuori montuori@REDACTED From hugo@REDACTED Fri Aug 28 14:27:14 2015 From: hugo@REDACTED (Hugo Mills) Date: Fri, 28 Aug 2015 12:27:14 +0000 Subject: [erlang-questions] json to map In-Reply-To: <55E042BB.4060409@ninenines.eu> References: <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> <55E042BB.4060409@ninenines.eu> Message-ID: <20150828122714.GP23769@carfax.org.uk> On Fri, Aug 28, 2015 at 01:15:07PM +0200, Lo?c Hoguin wrote: > On 08/28/2015 01:04 PM, Roelof Wobben wrote: > >Pity , you gave me the answer. Now I can do a copy/paste and go on and > >the next time I do it wrong again. > >That is why I want to try this one on my own and make my own mistakes > >and learn from it , make more mistake and also learn from them. > > Short piece of advice: if you do want to make your own mistakes and > learn from it, *you have to find the solutions on your own*. Even if > they are incomplete or barely working solutions. > > Practice makes perfect. Not asking questions every time things > doesn't work. Even if people don't give you the solution directly. > > If you can't solve certain problems, it means you are lacking > required knowledge, so move back to earlier problems and continue > learning from there. Or try to give yourself a few gradually harder > challenges until you get to the point where you can solve the > problems you got stuck with. I second this. It seems to me that you're treating the exercises as a simple checklist of things you have to do before moving on to the next topic. That's not a particularly good approach to take. The world doesn't need another implementation of counting the number of functions in each module in erlang. What it does need is another person who knows how to use list comprehensions and folds on structured data to turn it into the desired output (whatever that desired output is). So... when you've done an exercise, don't just ask if the code works. Ask yourself what that exercise was trying to help you to learn, in the context of the chapter in question. An exercise asking for a JSON parser may be written in exactly the same way, but will have different learning goals depending on context. Consider: - You've just learned about I/O and binaries versus - You've just learned about maps versus - You've just learned about leex and yecc, the parser-generation tools In each case, your solution to writing a JSON "parser" is going to look very different, because you're using the problem *to exercise your new knowledge*. The author doesn't care about having another JSON parser -- there's lots of them out there already. What they're trying to do is get you to think about the problem *in terms of the thing they've just taught you*. One thing that's missing in your questions here, and which is leading inevitably to misleading recommendations (like using jsx or leex in this particular case) is the context: you're not saying what the goal of the learning experience is. As a result, you're getting good general-purpose engineering solutions to the *problem*, rather than things that will help you *learn*. The best people to listen to here are generally the ones who ask you the awkward or difficult questions, because they're generally the ones who are trying to get you to think about the problem in a particular way. If you can answer those questions for yourself, you will usually be thinking about the problem in a way that will get you to the answer. If you can learn to think about problems in that way on your own, then you will actually be able to write useful code. This comes with practice, and lots of fiddling and failure on the way, but it's not something that can be taught directly as a step-by-step process to follow. So, to reinforce the primary point here: consider the exercises as *practice* for what you were being taught, not as goals in their own right. Do the practice, not "the exercises". The goal, for you, is to be able to take the separate pieces and techniques and assemble them into something that solves the problem at hand. > Considering your recent questions, you clearly lack knowledge that's > *very basic* so I am not sure why you start writing typespecs and > parsers which are advanced topics. This is, I think, a symptom of the problems I've talked about above. You do seem to have treated the exercises as "things to get past", rather than "things to practice with". As a novice to programming as well as Erlang, you may well have to have more practice. As an extra exercise in each chapter, try coming up with your own (simple) problem that shows off your skills with the techniques used in that chapter. This has two parts to it: thinking of something appropriate (which is itself a fairly hard problem), and then writing the code for it (which is easier, if you came up with a suitable problem in the first step). I used to be a mathematician(*), so I've got a whole raft of interesting little exercises I can fiddle around with when I'm learning the basics of a new language. Probably my first self-driven code in erlang was something to generate all possible permutations of a list. My first (and, to date, only) code in Julia was, appropriately, a Julia set generator. If you have any kind of technical or scientific training, think of a simple problem -- one you could do on a piece of paper -- based on structures and concepts you already know, and try to solve it in code. You should be thinking, when you read the text of your book, "ah, now I understand, I could use this for of ". Make connections with the things you already understand and know how to do. See if the stuff in the new chapter helps you understand any of the problems in the previous chapter any better. That turned out to be longer than I originally intended. I hope it's useful, anyway. Hugo. (*) I'm better now. -- Hugo Mills | Great oxymorons of the world, no. 10: hugo@REDACTED carfax.org.uk | Business Ethics http://carfax.org.uk/ | PGP: E2AB1DE4 | -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: From r.wobben@REDACTED Fri Aug 28 14:34:36 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Fri, 28 Aug 2015 14:34:36 +0200 Subject: [erlang-questions] json to map In-Reply-To: References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <55E03F2B.9090907@home.nl> Message-ID: <55E0555C.10509@home.nl> Op 28-8-2015 om 13:50 schreef Kevin Montuori: >>>>>> "rw" == Roelof Wobben writes: > rw> -type tword() :: binary(). > rw> -type token() :: tInt() > rw> | tWord() > > rw> time_parser.erl:12: type tInt() undefined time_parser.erl:13: type > rw> tWord() undefined > rw> time_parser.erl:6: Warning: type tword() is unused > > [Leaving aside all of the excellent advice that's been proffered...] > > Did you read these messages carefully? tWord() is undefined but tword() > is unused: the answer's staring you in the face. If you've been writing > Erlang for a while this error/warning pair should ring a bell. > > Perhaps you should revisit Mr. O'Keefe's email, specifically the part > where he discusses Erlang naming conventions (and tells you *exactly* > what's wrong with what you have)? > > > k. > With the help of everything I found this piece working. -module(time_parser). -export([]). -type token() :: t_Int() | t_Word() | '/' | '-' | ','. -type t_Int() :: integer() | int. -type t_Word() :: word | string(). So in normal Englisch a token can be a t-int , a t_word , a / , a - or a , If its something else its failing which is allright. type t_int can be a integer or a atom called int. type t_word can be a string or a atom called word. if it' something else it's failing. Roelof From hugo@REDACTED Fri Aug 28 15:11:06 2015 From: hugo@REDACTED (Hugo Mills) Date: Fri, 28 Aug 2015 13:11:06 +0000 Subject: [erlang-questions] json to map In-Reply-To: <20150828122714.GP23769@carfax.org.uk> References: <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> <55E042BB.4060409@ninenines.eu> <20150828122714.GP23769@carfax.org.uk> Message-ID: <20150828131106.GQ23769@carfax.org.uk> [Roelof, apologies for missing you out on the cc on my last mail -- I hope you got it through the mailing list. I don't know how that happened.] On Fri, Aug 28, 2015 at 12:27:14PM +0000, Hugo Mills wrote: > The best people to listen to here are generally the ones who ask > you the awkward or difficult questions, because they're generally the > ones who are trying to get you to think about the problem in a > particular way. If you can answer those questions for yourself, you > will usually be thinking about the problem in a way that will get you > to the answer. If you can learn to think about problems in that way on > your own, then you will actually be able to write useful code. This > comes with practice, and lots of fiddling and failure on the way, but > it's not something that can be taught directly as a step-by-step > process to follow. Sorry to drone on here, but I wanted to follow up on this point a bit. Most problems in CS don't have linear paths to the solution. You don't just start with "here's the input, so I do this, do this, do this, and there's the answer". You have to pick at them around the edges, find the pieces you know how to do. Consider doing something because it looks like it might get you closer to the structure you need. Work from both ends at once: you have some data as input, and you want a particular structure as output; what can you do to the input to simplify it? What's the simplest data that you could use to generate the output, and how would you do it? Do those two meet in the middle? If not, try again and work the edges towards each other. Is there a simpler version of the problem you *can* solve? Do that first, then see if you can modify it to deal with the other pieces. Example: For this JSON-parsing problem, what's your input? (I'd guess you just read the whole file in as a binary or a string to start with -- pick one, do it; bear in mind what the chapter is trying to teach you, as this may make a difference in which one you pick). Given input in that form, if the first thing in your input is a plain quoted string, can you turn that into an Erlang string and a piece of unused input? Do that. What about a number to an Erlang number? Do that. An unquoted string to an atom? Do that. Can you turn a simple JSON array into an Erlang list of terms (and some unused input)? Do that. Can you modify that to parse an array of arrays? Do that. Can you turn a simple non-nested JSON map into an Erlang map (or dict, or whatever)? Do that. Can you use those as building blocks to parse a full JSON structure? You're done. It'll be a pretty useless JSON parser for practical purposes, but that's OK, you're just learning. (To repeat my last email, the output of your work is not a program; the output is a programmer). Try writing down (in your own language) a problem description for each of the stages above, and treat it as a self-contained problem. Some of them will be trivial. Some will be a bit more complicated. The later ones will build on the earlier ones. Write code (or modify existing code) for each one. Being able to do this -- break a problem down into separate pieces you know how to solve -- is the essence of writing software, and it's the hardest thing to learn how to do well. Hugo. -- Hugo Mills | Jazz is the sort of music where no-one plays hugo@REDACTED carfax.org.uk | anything the same way once. http://carfax.org.uk/ | PGP: E2AB1DE4 | -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: From r.wobben@REDACTED Fri Aug 28 15:18:37 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Fri, 28 Aug 2015 15:18:37 +0200 Subject: [erlang-questions] json to map In-Reply-To: <20150828131106.GQ23769@carfax.org.uk> References: <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> <55E042BB.4060409@ninenines.eu> <20150828122714.GP23769@carfax.org.uk> <20150828131106.GQ23769@carfax.org.uk> Message-ID: <55E05FAD.60802@home.nl> Op 28-8-2015 om 15:11 schreef Hugo Mills: > [Roelof, apologies for missing you out on the cc on my last mail -- I > hope you got it through the mailing list. I don't know how that > happened.] > > On Fri, Aug 28, 2015 at 12:27:14PM +0000, Hugo Mills wrote: >> The best people to listen to here are generally the ones who ask >> you the awkward or difficult questions, because they're generally the >> ones who are trying to get you to think about the problem in a >> particular way. If you can answer those questions for yourself, you >> will usually be thinking about the problem in a way that will get you >> to the answer. If you can learn to think about problems in that way on >> your own, then you will actually be able to write useful code. This >> comes with practice, and lots of fiddling and failure on the way, but >> it's not something that can be taught directly as a step-by-step >> process to follow. > Sorry to drone on here, but I wanted to follow up on this point a > bit. > > Most problems in CS don't have linear paths to the solution. You > don't just start with "here's the input, so I do this, do this, do > this, and there's the answer". You have to pick at them around the > edges, find the pieces you know how to do. Consider doing something > because it looks like it might get you closer to the structure you > need. Work from both ends at once: you have some data as input, and > you want a particular structure as output; what can you do to the > input to simplify it? What's the simplest data that you could use to > generate the output, and how would you do it? Do those two meet in the > middle? If not, try again and work the edges towards each other. Is > there a simpler version of the problem you *can* solve? Do that first, > then see if you can modify it to deal with the other pieces. > > Example: For this JSON-parsing problem, what's your input? (I'd > guess you just read the whole file in as a binary or a string to start > with -- pick one, do it; bear in mind what the chapter is trying to > teach you, as this may make a difference in which one you pick). Given > input in that form, if the first thing in your input is a plain quoted > string, can you turn that into an Erlang string and a piece of unused > input? Do that. What about a number to an Erlang number? Do that. An > unquoted string to an atom? Do that. Can you turn a simple JSON array > into an Erlang list of terms (and some unused input)? Do that. Can > you modify that to parse an array of arrays? Do that. Can you turn a > simple non-nested JSON map into an Erlang map (or dict, or whatever)? > Do that. Can you use those as building blocks to parse a full JSON > structure? You're done. It'll be a pretty useless JSON parser for > practical purposes, but that's OK, you're just learning. (To repeat my > last email, the output of your work is not a program; the output is a > programmer). > > Try writing down (in your own language) a problem description for > each of the stages above, and treat it as a self-contained problem. > Some of them will be trivial. Some will be a bit more complicated. The > later ones will build on the earlier ones. Write code (or modify > existing code) for each one. Being able to do this -- break a problem > down into separate pieces you know how to solve -- is the essence of > writing software, and it's the hardest thing to learn how to do well. > > Hugo. Thanks for the advise. Roelof From co7eb@REDACTED Fri Aug 28 17:18:38 2015 From: co7eb@REDACTED (Ivan Carmenates Garcia) Date: Fri, 28 Aug 2015 11:18:38 -0400 Subject: [erlang-questions] I need some advices for a framework I'm doing In-Reply-To: References: <000001d0deaa$5479cf20$fd6d6d60$@frcuba.co.cu> <55DB9061.8050501@ninenines.eu> <000001d0df4e$d852e9e0$88f8bda0$@frcuba.co.cu> <2FDD2B4B-466E-48D5-8E10-29E967948A05@rogvall.se> <000201d0df79$e9c7d9d0$bd578d70$@frcuba.co.cu> Message-ID: <006101d0e1a4$d22e24f0$768a6ed0$@frcuba.co.cu> Regards, don?t be, apologizes accepted. Cheers, Ivan. From: Tony Rogvall [mailto:tony@REDACTED] Sent: Wednesday, August 26, 2015 3:00 AM To: Ivan Carmenates Garcia Cc: erlang-questions@REDACTED Subject: Re: [erlang-questions] I need some advices for a framework I'm doing I am terribly sorry. I thought it was a joke. I am utterly ashamed. Sincerely /Tony On 25 aug 2015, at 23:06, Ivan Carmenates Garcia > wrote: Yes usually happens when people try to build nice things and other people not. From: Tony Rogvall [ mailto:tony@REDACTED] Sent: Tuesday, August 25, 2015 3:23 PM To: Ivan Carmenates Garcia Cc: Lo?c Hoguin; < erlang-questions@REDACTED> Subject: Re: [erlang-questions] I need some advices for a framework I'm doing Ha ha ha This is funny, please stop! "typed while hacking!" On 25 aug 2015, at 17:58, Ivan Carmenates Garcia < co7eb@REDACTED> wrote: Hi, Well the good news here is that I am making it together with a system a am also doing so, it any problems present I will notice they quickly and at the same time I will get feedbacks. Regards documentation, that one of the thing a love more, so it will be plenty of it, with a lot of examples and explanations. Currently the code doc for any function and even examples of how to use them. i.e. this is a nice doc for one of the functions: %% ------------------------------------------------------------------- %% @doc %% Makes a query to a database using a 'DBSession'. %% Returns a 'ResultData': %% - 'ResultData' depends of 'result_format' Option. %% - 'result_format' could be one of 'raw', 'proplist', 'map'. %% - 'proplist' and 'map' result formats have the same %% 'ResultData' struct: %% {ok, Data} when using 'select'. %% {ok, Count} when using 'update', 'insert', 'delete'. %% {ok, Count, Data} when using 'update', 'insert' with returning. %% The only differences are: %% 0 results: %% 'map' -> no_data, %% 'proplist' -> [], %% 1 result: %% 'map' -> a single map #{...}, %% 'proplist' -> a list of proplist [[...]], (template compatible) %% N results: %% 'map' -> a list of maps [#{...}, ...], %% 'proplist' -> a list of proplists [[...], ...], %% 'raw' by the other hand is 'Backend' dependent. %% Example: %% {ok, #{id := Id}} = database_manager:query(DBSession, %% Query, Params, [{result_format, map}]). %% NOTE: 'map' is the default result format for 'query/3' function. %% NOTE: All result format has its pros and cons, 'raw' is the fastest %% but uncomfortable to deal with, 'map' is the slowest but very %% easy to deal with. So this is the performance order from %% fastest to slowest 'raw' > 'proplist' > 'map'.'proplist' can %% be used to return directly to a template. %% @end %% ------------------------------------------------------------------- -spec query(DBSession, Query, Params, Options) -> ResultData | {error, Reason} when DBSession :: db_session(), Query :: string() | bitstring(), Params :: [] | [any(), ...], Options :: proplists:proplist(), ResultData :: any(), Reason :: term(). query({Backend, Connection}, Query, Params, Options) -> %% executes query/4 in the current 'Backend'. Backend:query(Connection, Query, Params, Options). Anyone have more suggestions I could use?, thanks in advantage. Regards, Ivan. -----Original Message----- From: Lo?c Hoguin [ mailto:essen@REDACTED] Sent: Monday, August 24, 2015 5:45 PM To: Ivan Carmenates Garcia; erlang-questions@REDACTED Subject: Re: [erlang-questions] I need some advices for a framework I'm doing On 08/24/2015 10:20 PM, Ivan Carmenates Garcia wrote: > Hi everyone, I am making a little framework for cowboy, but in general > what I need is some advices regards final looking, i.e.: OK I am a bit lost on everything you explained so allow me to give some generic advice: * Make it work * Start making apps with it * Notice everything inefficient in how you now write apps * Update your framework * Repeat Practice makes perfect. Add a little of looking at how everyone else does things in the mix to get ideas; sometimes you will notice something is bad in your framework but have no idea how to make it better, that's why you need to look elsewhere. Sometimes the idea might come from a completely unrelated source. A few more things: * Keep it simple and explicit * Focus on the use cases that benefit the majority of users * Choose good, short names * Write a user guide when things stabilize On the last point, you want the guide separate from code entirely because this forces you to think about how you really use it rather than just documenting functions or modules one after another. Think of it like writing a book, except the only role of this book is to explain to others *what* they can do with your framework and *why* they will do things that way. Once you get there, you should have a pretty good product, and you'll most likely have gotten a ton of users along the way. Cheers, -- Lo?c Hoguin http://ninenines.eu Author of The Erlanger Playbook, A book about software development using Erlang _______________________________________________ erlang-questions mailing list erlang-questions@REDACTED http://erlang.org/mailman/listinfo/erlang-questions -------------- next part -------------- An HTML attachment was scrubbed... URL: From r.wobben@REDACTED Fri Aug 28 21:20:51 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Fri, 28 Aug 2015 21:20:51 +0200 Subject: [erlang-questions] json to map In-Reply-To: <55E05FAD.60802@home.nl> References: <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> <55E042BB.4060409@ninenines.eu> <20150828122714.GP23769@carfax.org.uk> <20150828131106.GQ23769@carfax.org.uk> <55E05FAD.60802@home.nl> Message-ID: <55E0B493.1030801@home.nl> One question where I cannot find the answer to. So far I have this : -module(time_parser). -export([tokens/1]). tokens([]) -> []; tokens ([Head|Rest]) when Head =:= 32 -> tokens(Rest); tokens ([Head|Rest]) when Head >= $0 , Head =< $9 -> digits(Head,Rest) ; %tokens([Head|Rest]) when Head >= "a" , Head =< "z" -> % word(Rest, [Head]); tokens (['/'| Rest]) -> [ '/' | tokens (Rest) ]; tokens (['-' | Rest]) -> [ '-' | tokens (Rest)]; tokens ([','| Rest]) -> [ '_' | tokens (Rest)]. digits( Number, [Head | Rest]) when Head >= $0 , Head =< $9 -> digits(Number * 10 + Head , Rest); digits(Number, Number2) when Number >= $0 , Number =< $9 -> Number + Number2. so I do this in erl; 7> c(time_parser). {ok,time_parser} 8> time_parser:tokens([10]). ** exception error: no function clause matching time_parser:tokens("\n") (time_parser.erl, line 5) where do the /n come from ? Roelof Op 28-8-2015 om 15:18 schreef Roelof Wobben: > Op 28-8-2015 om 15:11 schreef Hugo Mills: >> [Roelof, apologies for missing you out on the cc on my last mail -- I >> hope you got it through the mailing list. I don't know how that >> happened.] >> >> On Fri, Aug 28, 2015 at 12:27:14PM +0000, Hugo Mills wrote: >>> The best people to listen to here are generally the ones who ask >>> you the awkward or difficult questions, because they're generally the >>> ones who are trying to get you to think about the problem in a >>> particular way. If you can answer those questions for yourself, you >>> will usually be thinking about the problem in a way that will get you >>> to the answer. If you can learn to think about problems in that way on >>> your own, then you will actually be able to write useful code. This >>> comes with practice, and lots of fiddling and failure on the way, but >>> it's not something that can be taught directly as a step-by-step >>> process to follow. >> Sorry to drone on here, but I wanted to follow up on this point a >> bit. >> >> Most problems in CS don't have linear paths to the solution. You >> don't just start with "here's the input, so I do this, do this, do >> this, and there's the answer". You have to pick at them around the >> edges, find the pieces you know how to do. Consider doing something >> because it looks like it might get you closer to the structure you >> need. Work from both ends at once: you have some data as input, and >> you want a particular structure as output; what can you do to the >> input to simplify it? What's the simplest data that you could use to >> generate the output, and how would you do it? Do those two meet in the >> middle? If not, try again and work the edges towards each other. Is >> there a simpler version of the problem you *can* solve? Do that first, >> then see if you can modify it to deal with the other pieces. >> >> Example: For this JSON-parsing problem, what's your input? (I'd >> guess you just read the whole file in as a binary or a string to start >> with -- pick one, do it; bear in mind what the chapter is trying to >> teach you, as this may make a difference in which one you pick). Given >> input in that form, if the first thing in your input is a plain quoted >> string, can you turn that into an Erlang string and a piece of unused >> input? Do that. What about a number to an Erlang number? Do that. An >> unquoted string to an atom? Do that. Can you turn a simple JSON array >> into an Erlang list of terms (and some unused input)? Do that. Can >> you modify that to parse an array of arrays? Do that. Can you turn a >> simple non-nested JSON map into an Erlang map (or dict, or whatever)? >> Do that. Can you use those as building blocks to parse a full JSON >> structure? You're done. It'll be a pretty useless JSON parser for >> practical purposes, but that's OK, you're just learning. (To repeat my >> last email, the output of your work is not a program; the output is a >> programmer). >> >> Try writing down (in your own language) a problem description for >> each of the stages above, and treat it as a self-contained problem. >> Some of them will be trivial. Some will be a bit more complicated. The >> later ones will build on the earlier ones. Write code (or modify >> existing code) for each one. Being able to do this -- break a problem >> down into separate pieces you know how to solve -- is the essence of >> writing software, and it's the hardest thing to learn how to do well. >> >> Hugo. > > Thanks for the advise. > > Roelof > > From hugo@REDACTED Fri Aug 28 21:30:47 2015 From: hugo@REDACTED (Hugo Mills) Date: Fri, 28 Aug 2015 19:30:47 +0000 Subject: [erlang-questions] json to map In-Reply-To: <55E0B493.1030801@home.nl> References: <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> <55E042BB.4060409@ninenines.eu> <20150828122714.GP23769@carfax.org.uk> <20150828131106.GQ23769@carfax.org.uk> <55E05FAD.60802@home.nl> <55E0B493.1030801@home.nl> Message-ID: <20150828193047.GR23769@carfax.org.uk> On Fri, Aug 28, 2015 at 09:20:51PM +0200, Roelof Wobben wrote: > One question where I cannot find the answer to. > > So far I have this : > > -module(time_parser). > > -export([tokens/1]). > > tokens([]) -> []; > > tokens ([Head|Rest]) when Head =:= 32 -> > tokens(Rest); > > tokens ([Head|Rest]) when Head >= $0 , Head =< $9 -> > digits(Head,Rest) ; > > %tokens([Head|Rest]) when Head >= "a" , Head =< "z" -> > % word(Rest, [Head]); > > tokens (['/'| Rest]) -> > [ '/' | tokens (Rest) ]; > > tokens (['-' | Rest]) -> > [ '-' | tokens (Rest)]; > > tokens ([','| Rest]) -> > [ '_' | tokens (Rest)]. > > > digits( Number, [Head | Rest]) when Head >= $0 , Head =< $9 -> > digits(Number * 10 + Head , Rest); > > digits(Number, Number2) when Number >= $0 , Number =< $9 -> > Number + Number2. > > so I do this in erl; > > 7> c(time_parser). {ok,time_parser} > 8> time_parser:tokens([10]). > ** exception error: no function clause matching > time_parser:tokens("\n") (time_parser.erl, line 5) > > where do the /n come from ? ASCII 10 is a newline character, usually rendered as \n You passed a list containing the single number 10. In erlang, strings are lists of integers, with each integer being the code (a Unicode code point) of a character of the string. Hugo. > > > > > Op 28-8-2015 om 15:18 schreef Roelof Wobben: > >Op 28-8-2015 om 15:11 schreef Hugo Mills: > >>[Roelof, apologies for missing you out on the cc on my last mail -- I > >> hope you got it through the mailing list. I don't know how that > >> happened.] > >> > >>On Fri, Aug 28, 2015 at 12:27:14PM +0000, Hugo Mills wrote: > >>> The best people to listen to here are generally the ones who ask > >>>you the awkward or difficult questions, because they're generally the > >>>ones who are trying to get you to think about the problem in a > >>>particular way. If you can answer those questions for yourself, you > >>>will usually be thinking about the problem in a way that will get you > >>>to the answer. If you can learn to think about problems in that way on > >>>your own, then you will actually be able to write useful code. This > >>>comes with practice, and lots of fiddling and failure on the way, but > >>>it's not something that can be taught directly as a step-by-step > >>>process to follow. > >> Sorry to drone on here, but I wanted to follow up on this point a > >>bit. > >> > >> Most problems in CS don't have linear paths to the solution. You > >>don't just start with "here's the input, so I do this, do this, do > >>this, and there's the answer". You have to pick at them around the > >>edges, find the pieces you know how to do. Consider doing something > >>because it looks like it might get you closer to the structure you > >>need. Work from both ends at once: you have some data as input, and > >>you want a particular structure as output; what can you do to the > >>input to simplify it? What's the simplest data that you could use to > >>generate the output, and how would you do it? Do those two meet in the > >>middle? If not, try again and work the edges towards each other. Is > >>there a simpler version of the problem you *can* solve? Do that first, > >>then see if you can modify it to deal with the other pieces. > >> > >> Example: For this JSON-parsing problem, what's your input? (I'd > >>guess you just read the whole file in as a binary or a string to start > >>with -- pick one, do it; bear in mind what the chapter is trying to > >>teach you, as this may make a difference in which one you pick). Given > >>input in that form, if the first thing in your input is a plain quoted > >>string, can you turn that into an Erlang string and a piece of unused > >>input? Do that. What about a number to an Erlang number? Do that. An > >>unquoted string to an atom? Do that. Can you turn a simple JSON array > >>into an Erlang list of terms (and some unused input)? Do that. Can > >>you modify that to parse an array of arrays? Do that. Can you turn a > >>simple non-nested JSON map into an Erlang map (or dict, or whatever)? > >>Do that. Can you use those as building blocks to parse a full JSON > >>structure? You're done. It'll be a pretty useless JSON parser for > >>practical purposes, but that's OK, you're just learning. (To repeat my > >>last email, the output of your work is not a program; the output is a > >>programmer). > >> > >> Try writing down (in your own language) a problem description for > >>each of the stages above, and treat it as a self-contained problem. > >>Some of them will be trivial. Some will be a bit more complicated. The > >>later ones will build on the earlier ones. Write code (or modify > >>existing code) for each one. Being able to do this -- break a problem > >>down into separate pieces you know how to solve -- is the essence of > >>writing software, and it's the hardest thing to learn how to do well. > >> > >> Hugo. > > > >Thanks for the advise. > > > >Roelof > > > > > > _______________________________________________ > erlang-questions mailing list > erlang-questions@REDACTED > http://erlang.org/mailman/listinfo/erlang-questions -- Hugo Mills | Hey, Virtual Memory! Now I can have a *really big* hugo@REDACTED carfax.org.uk | ramdisk! http://carfax.org.uk/ | PGP: E2AB1DE4 | -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: From montuori@REDACTED Fri Aug 28 21:33:56 2015 From: montuori@REDACTED (Kevin Montuori) Date: Fri, 28 Aug 2015 15:33:56 -0400 Subject: [erlang-questions] json to map In-Reply-To: <55E0B493.1030801@home.nl> (Roelof Wobben's message of "Fri, 28 Aug 2015 21:20:51 +0200") References: <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> <55E042BB.4060409@ninenines.eu> <20150828122714.GP23769@carfax.org.uk> <20150828131106.GQ23769@carfax.org.uk> <55E05FAD.60802@home.nl> <55E0B493.1030801@home.nl> Message-ID: >>>>> "rw" == Roelof Wobben writes: 8> time_parser:tokens([10]). rw> ** exception error: no function clause matching rw> time_parser:tokens("\n") (time_parser.erl, line 5) rw> where do the /n come from ? What happens when you type 1> ([10]). in the REPL? k. -- Kevin Montuori montuori@REDACTED From hugo@REDACTED Fri Aug 28 21:47:10 2015 From: hugo@REDACTED (Hugo Mills) Date: Fri, 28 Aug 2015 19:47:10 +0000 Subject: [erlang-questions] json to map In-Reply-To: References: <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> <55E042BB.4060409@ninenines.eu> <20150828122714.GP23769@carfax.org.uk> <20150828131106.GQ23769@carfax.org.uk> <55E05FAD.60802@home.nl> <55E0B493.1030801@home.nl> Message-ID: <20150828194710.GS23769@carfax.org.uk> On Fri, Aug 28, 2015 at 03:33:56PM -0400, Kevin Montuori wrote: > >>>>> "rw" == Roelof Wobben writes: > > 8> time_parser:tokens([10]). > rw> ** exception error: no function clause matching > rw> time_parser:tokens("\n") (time_parser.erl, line 5) > > rw> where do the /n come from ? > > What happens when you type > > 1> ([10]). > > in the REPL? Roelof: This is the kind of question that I was saying you should be paying attention to. If you can answer this question and explain it, you've got your answer to your original question. You should have the knowledge from earlier reading in your book to explain the results you see. (Or just read my mail from a few minutes ago, which gives you the answer directly... my teaching error). Hugo. -- Hugo Mills | Hey, Virtual Memory! Now I can have a *really big* hugo@REDACTED carfax.org.uk | ramdisk! http://carfax.org.uk/ | PGP: E2AB1DE4 | -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: From r.wobben@REDACTED Fri Aug 28 21:52:04 2015 From: r.wobben@REDACTED (Roelof Wobben) Date: Fri, 28 Aug 2015 21:52:04 +0200 Subject: [erlang-questions] json to map In-Reply-To: <20150828194710.GS23769@carfax.org.uk> References: <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> <55E042BB.4060409@ninenines.eu> <20150828122714.GP23769@carfax.org.uk> <20150828131106.GQ23769@carfax.org.uk> <55E05FAD.60802@home.nl> <55E0B493.1030801@home.nl> <20150828194710.GS23769@carfax.org.uk> Message-ID: <55E0BBE4.7010506@home.nl> Op 28-8-2015 om 21:47 schreef Hugo Mills: > On Fri, Aug 28, 2015 at 03:33:56PM -0400, Kevin Montuori wrote: >>>>>>> "rw" == Roelof Wobben writes: >> 8> time_parser:tokens([10]). >> rw> ** exception error: no function clause matching >> rw> time_parser:tokens("\n") (time_parser.erl, line 5) >> >> rw> where do the /n come from ? >> >> What happens when you type >> >> 1> ([10]). >> >> in the REPL? > Roelof: This is the kind of question that I was saying you should > be paying attention to. If you can answer this question and explain > it, you've got your answer to your original question. You should have > the knowledge from earlier reading in your book to explain the results > you see. > > (Or just read my mail from a few minutes ago, which gives you the > answer directly... my teaching error). > > Hugo. > Thanks, I understand it now. My mind is still not set up for seeing this sort of things. Maybe to late. Also I see that I have to rewrite my digits function. When entering 10 I see the answer 538 which is the 49 (1) * 10 + 48(0) Now time to sleep and rethink it. Roelof From akrupicka@REDACTED Fri Aug 28 21:29:58 2015 From: akrupicka@REDACTED (Adam Krupicka) Date: Fri, 28 Aug 2015 21:29:58 +0200 Subject: [erlang-questions] json to map In-Reply-To: <55E0B493.1030801@home.nl> References: <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> <55E042BB.4060409@ninenines.eu> <20150828122714.GP23769@carfax.org.uk> <20150828131106.GQ23769@carfax.org.uk> <55E05FAD.60802@home.nl> <55E0B493.1030801@home.nl> Message-ID: <1440789826-sup-1818@arch.local> Excerpts from Roelof Wobben's message of 2015-08-28 21:20:51 +0200: > > 7> c(time_parser). {ok,time_parser} > 8> time_parser:tokens([10]). > ** exception error: no function clause matching time_parser:tokens("\n") > (time_parser.erl, line 5) > > where do the /n come from ? Hi! 10 is the decimal ASCII code for the newline character. This is how strings are actually usually represented in Erlang: a list of code points. If you want to have the parser parse the integer 10, you probably need to supply it as a string: 9> time_parser:tokens("10"). "10" is in fact syntax sugar for [$1, $0]. The dollar character($) followed by a character is evaluated to the numerical value of the character. For example: 1> $\n. 10 Cheers, A. K. From ok@REDACTED Sat Aug 29 13:56:13 2015 From: ok@REDACTED (ok@REDACTED) Date: Sat, 29 Aug 2015 23:56:13 +1200 Subject: [erlang-questions] json to map In-Reply-To: <55E0402E.50500@home.nl> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> Message-ID: <3fe0ffa42c5d027d1dacfa88e5d07f8c.squirrel@chasm.otago.ac.nz> > > I have made them the same type because all three are only 1 character. I am suddenly feeling very cross. YOU WANT TO BE ABLE TO TELL AT A GLANCE WHAT KIND OF TOKEN YOU HAVE. That means *NOT* hiding stuff inside a binary. > I have used the code from fiffy as reference to make my own. > I understand that they must be different but on some point they are the > same. No, and no, and NO. THEY ARE DIFFERENT. The fact that they *happened* to be represented by single characters in the input is UTTERLY UNINTERESTING. You have LESS THAN NO INTEREST in knowing what the characters were. It's like the way in Pascal "[" and "(*" were different *character sequences* but the same *token*. When you are dealing with TOKENS, you not only do not want to know anything about the characters, you WANT NOT TO KNOW any thing about the characters. Here again is the Haskell type declaration: data Token -- a Token is = TInt Int -- an integer, or | TWord String -- a word, or | TDash -- a dash, or | TSlash -- a slash, or | TComma -- a comma. When we are dealing with tokens, WE NEED TO BE ABLE TO TELL ONE KIND OF TOKEN FROM ANOTHER BY A SINGLE PATTERN MATCH. That's what a sum-of-products data type is all about; it's a thing that lets us tell what we have by a single 'case' analysis. When we are dealing with tokens, we have made that choice so we don't have to deal with characters. We don't *care* whether an integer was written as 10, 010, 000000000000010, or in another context, 2r1010, 3r101, 0xA, $\n, ... Notice that a TInt token has some associated information, and a TWord token has some associated information, in both cases *derived from* but *not identical to* their source characters, but a TDash, a TSlash, or a TComma have *NO* associated information. They are NOT associated with any character or string. As far as the rest of the program is concerned, IT DOES NOT MATTER whether TDash stands for U+002D, U+2010, U+2011, U+2012, U+2013, U+2014, U+2052, U+2053, U+2448, U+2212, or whatever. That information is *GONE*, and it's gone because we WANT it gone. We need to be able to tell one token from another and to recover any important information, BUT WE HAVE NO INTEREST IN WHAT THE TOKENS LOOKED LIKE ANY MORE. Like I said before, this separation of concerns between a stage where we *do* have to care about the textual representation of tokens and a stage where we can heave a huge sigh of relief and forget that rubbish is one of the reasons why we make a distinction between character sequences and token sequences in the first place; it's one of the reasons why I have no desire ever to use "scannerless" parsing technology. Now we want to map that token representation into Erlang. And we DON'T start by writing -type declarations. We start by saying "There are five situations that I want to be able to discriminate with a single 'case' in Erlang. Two of them have one item of associated information each, and the other three have no associated information." The first thing to do is to sort these things into groups where all the situations in each group have the same number of pieces of associated information. Situations with NO associated information can (and should!) be represented by atoms. Situations with N pieces of associated information should normally be represented by tuples with N+1 elements, the first being an atom. The atoms within a group MUST be different, so that a single 'case' can trivially distinguish the situations. All the atoms SHOULD be different so that people can make sense of them. So we end up with TInt i {int,I} TWord w {word,W} TDash dash % I used '-' before TSlash slash % I used '/' before TComma comma % I used ',' before I've used different atoms this time to make the point that there is NO necessary connection between the names we use to distinguish the cases and the spelling of any of the tokens. It does not make sense, in *any* programming language, to associate a binary with the dash, slash, or comma tokens. We DO need to know what kind of token we are dealing with. We do NOT need to know how it was spelled. Suppose we were doing this in C. We might have enum Tag {T_Int, T_Word, T_Dash, T_Slash, T_Comma}; typedef struct Token { enum Tag tag; union { int val; // Used only when tag == T_Int char const *str; // Used only when tag == T_Word /* NOTHING */ // T_Dash, T_Slash, T_Comma } u; } Token; This really isn't about Erlang, in fact. It is wrong in *any* language to represent three *different* tokens by the *same* thing. Now that we've figured out that we want to use {int,I} {word,"w..."} dash slash comma to represent the different tokens, *NOW* you can write a type declaration that expresses this. -type token() :: {int,integer()} | {word,string()} | dash | slash | comma. This is not a matter of taste or style. Any time you write a type union in Erlang where two of the alternatives even overlap, you should get worried. Because that means you have an *ambiguous* type; one where there is some value such that you cannot tell which of the alternatives it belongs to on the basis of its form. This is not always a mistake, but "mistake" is the way to bet. Amongst other things, while the *computer* may be able to work it out, ambiguous alternatives are situations where *people* are likely to be confused. Oh yeah, the other thing. There is only ONE type introduced here. There was ONE type in the Haskell code; that should have been a clue that ONE type was probably the right thing in the Erlang translation. 'dash' and 'comma' are distinct VALUES of the token() type; they are not usefully to be thought of as distinct TYPES. > Pity , you gave me the answer. Now I can do a copy/paste and go on and > the next time I do it wrong again. > That is why I want to try this one on my own and make my own mistakes > and learn from it , make more mistake and also learn from them. On present showing, you have nothing to worry about on that score, and I hope you have learned something about designing data types. From ok@REDACTED Sat Aug 29 14:13:43 2015 From: ok@REDACTED (ok@REDACTED) Date: Sun, 30 Aug 2015 00:13:43 +1200 Subject: [erlang-questions] json to map In-Reply-To: <55E0555C.10509@home.nl> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <55E03F2B.9090907@home.nl> <55E0555C.10509@home.nl> Message-ID: <5c36e8e29c3682c86d1a4f95ea2c9156.squirrel@chasm.otago.ac.nz> > Op 28-8-2015 om 13:50 schreef Kevin Montuori: >>>>>>> "rw" == Roelof Wobben writes: > -type t_Int() :: integer() | int. > -type t_Word() :: word | string(). First, there should not be any t_Int() or t_Word() type at all. Second, you are saying here that "Something is a t_Int() if and only if (1) it is an integer() or (2) it is the atom 'int'." That does not make sense. Going back to the Haskell example, data Token = TInt Int | ... says "Token is a new type. One kind of token is called TInt; that kind has an Int inside it. ...." TInt here is NOT A TYPE (the "T" prefix stood for "token", not "type"; Haskell has no type prefix convention), it is a constructor function. It's a *label* pasted onto a record to distinguish it from all the other kinds of token. I could write this type in Pascal: type Token = record case tag : (TInt, TWord, TDash, TSlash, TComma) of TInt : (val : Integer); TWord : (Str : Alpha); TDash : (); TSlash: (); TComma: () end; The thing is that we want to be able to recognise an integer token by PATTERN MATCHING (as in the example Haskell code), *not* by type testing with a guard. There's nothing wrong with type testing with a guard when we have to, but we prefer pattern matching when we can because it is easier for *us* as well as the computer to tell when two patterns do not overlap. We want to say "Here is an int token AND here is its value", as in {int,integer()}, not "here is an int token OR here is its value". But using integer() | int you are saying "an integer OR the atom 'int'". And there is no case where the input is going to justify a "token" that is, in its entirety, 'int'. It would be really helpful if Erlang had distinct notation for "this is a union of types that are meant to be disjoint" and "this is a union of types that I expect to overlap". Look, it seems as though you don't yet have a clue how types in Erlang work. FORGET THEM until you have mastered pattern matching and the design of data structures that are meant to be used through pattern matching. From ok@REDACTED Mon Aug 31 02:27:23 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Mon, 31 Aug 2015 12:27:23 +1200 Subject: [erlang-questions] json to map In-Reply-To: <3fe0ffa42c5d027d1dacfa88e5d07f8c.squirrel@chasm.otago.ac.nz> References: <55DC5C83.2070409@home.nl> <4CFD4053-76AB-4C40-8403-7A050722FF09@cs.otago.ac.nz> <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> <3fe0ffa42c5d027d1dacfa88e5d07f8c.squirrel@chasm.otago.ac.nz> Message-ID: <7B07A6C1-9C25-4DF3-9F4B-E9AC8C29B185@cs.otago.ac.nz> On 29/08/2015, at 11:56 pm, wrote: > knowing what the characters were. It's like the way in Pascal > "[" and "(*" were different *character sequences* but the same > *token*. What nonsense! "(*" is equivalent (6.1.8) to "{", not "[". The equivalent of "[" is "(." (6.1.9), not "(*". This howler doesn't invalidate the main point. From charles@REDACTED Sun Aug 30 23:13:32 2015 From: charles@REDACTED (Charles Weitzer) Date: Sun, 30 Aug 2015 21:13:32 +0000 Subject: [erlang-questions] Senior software opportunity with machine learning group Message-ID: Voleon Capital Management LP, a startup quantitative hedge fund located in Berkeley, California. We would like to hire a senior software engineer as soon as possible. Voleon's founders previously worked together at one of the most successful quantitative hedge funds in the world. Our CEO has a PhD in Computer Science from Stanford and has been CEO and founder of a successful Internet infrastructure startup. Our Chief Investment Officer has a PhD in Statistics from Berkeley. Voleon's team includes PhD's from leading departments in statistics, computer science, and mathematics. We have made several unpublished advances in the field of machine learning and in other areas as well. Here is our formal job description: ********************************************************** * Senior Software Engineer * Technology-driven investment firm employing cutting-edge statistical machine learning techniques seeks an exceptionally capable software engineer. You will architect and implement new production trading systems, machine learning infrastructure, data integration pipelines, and large-scale storage systems. The firm researches and deploys systematic trading strategies designed to generate attractive returns without being dependent on the performance of the overall market. Join a team of under 30 people that includes a Berkeley statistics professor as well as over ten PhD's from Berkeley, Chicago, CMU, Princeton, Stanford, and UCLA, led by the founder and CEO of a successful Internet infrastructure technology firm. The firm's offices are walking distance from BART and the UC Berkeley campus in downtown Berkeley, California. We have a casual and collegial office environment, weekly catered lunches, and competitive benefits packages. We seek candidates with a proven track record of writing correct, well-designed software, solving hard problems, and delivering complex projects on time. You should preferably have experience designing and implementing fault-tolerant distributed systems. Experience with building large-scale data infrastructure, stream processing systems, or latency-sensitive programs is a bonus. We are growing rapidly. Willingness to take initiative and a gritty determination to productize are essential. Required experience: - developing with C/C++/Python/Go in a Linux environment with a focus on performance, concurrency, and correctness. - experience with functional programming environments (Haskell, Erlang, others). - working in TCP/IP networking, multi-threading, and server development. - working with common Internet protocols (IP, TCP/UDP, SSL/TLS, HTTP, SNMP, etc.). - architecting and designing highly available systems. - architecting and designing large-scale data management infrastructure. - working in large codebases and building modular, manageable code. Preferred experience.: - debugging and performance profiling, including the use of tools such as strace, valgrind, gdb, tcpdump, etc. - working with build and test automation tools. - working with well-defined change management processes. - diagnosing RDBMS performance problems, exploiting indexing, using EXPLAIN PLAN, optimizing at the code layer, etc. - working with messaging queues (RabbitMQ, Redis, etc.) as well as distributed caching systems. Interest in financial applications is essential, but experience in finance is not a primary factor in our hiring. Benefits and compensation are highly competitive. ********************************************************** The above job description is just a starting point in terms of possible duties and seniority. We can be very flexible for the right person. If you are interested or if you know of anyone who might be interested, let me know the best way to get in touch and we can discuss details. Thank you, Charles Weitzer Senior Recruiter Voleon Capital Management LP Charles@REDACTED Office: 510.704.9870 x 7012 Mobile: (510) 558-9182 www.Voleon.com Confidential: This e-mail may contain confidential and/or privileged information. If you are not the intended recipient (or have received this e-mail in error) please notify the sender immediately and destroy this e-mail. Any unauthorized copying, disclosure or distribution of the material in this e-mail is strictly forbidden. Any comments or statements made herein do not necessarily reflect those of The Voleon Group, Voleon Funds LP, Voleon Capital Management LP, and their subsidiaries or affiliates. Please note that this e-mail has been created with the knowledge that Internet e-mail is not a 100% secure communications medium. We advise that you understand and observe this lack of security when sending and/or receiving email communications between Voleon Funds LP, Voleon Capital Management LP, and any of their subsidiaries/affiliates and yourself. Privacy: Voleon Funds LP, Voleon Capital Management LP, and their subsidiaries and affiliates archive incoming and outgoing emails and accordingly, may, at their discretion, monitor and review the content of all e-mail communications. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ok@REDACTED Mon Aug 31 06:25:17 2015 From: ok@REDACTED (Richard A. O'Keefe) Date: Mon, 31 Aug 2015 16:25:17 +1200 Subject: [erlang-questions] json to map In-Reply-To: <20150828131106.GQ23769@carfax.org.uk> References: <55DD550D.6000904@home.nl> <55DEEEB6.5060008@home.nl> <2530BD8D-66DB-4BB1-920F-F10480A57833@cs.otago.ac.nz> <55E0118E.8070301@home.nl> <55E01C5F.3050504@ericsson.com> <64F01CF4-9CA9-42C7-8D52-B00851756890@cs.otago.ac.nz> <55E0402E.50500@home.nl> <55E042BB.4060409@ninenines.eu> <20150828122714.GP23769@carfax.org.uk> <20150828131106.GQ23769@carfax.org.uk> Message-ID: <8A59297C-DD0A-4EC8-B57F-69C3E6F35F1F@cs.otago.ac.nz> Specifically concerning the parsing of JSON, actual numbers for my json.erl. % SIZE Lines Functions clauses % entry 5 1 1 % tokenising 77 6 29 (or 36, if you count 'case') % parsing 28 3 6 (or 12, if you count 'case') % utility 4 1 2 % TOTAL 114 11 38 (or 51, if you count 'case') It was amusing that *parsing* JSON required just 3 functions (parse any JSON value, parse body of non-empty array, parse body of non-empty object). It was interesting to see where the difficulty was: numbers (four functions) and strings (handling backslash escapes). Strings can appear in two places in the JSON grammar, so having them recognised once in the tokeniser avoids duplication in the parser. From erlang@REDACTED Mon Aug 31 12:57:20 2015 From: erlang@REDACTED (Joe Armstrong) Date: Mon, 31 Aug 2015 12:57:20 +0200 Subject: [erlang-questions] crypto tutorial Message-ID: I have written a crypto tutorial which shows how various cryptographic algorithms can be written in Erlang. https://github.com/joearms/crypto_tutorial/blob/master/crypto_tutorial.pdf I'm going to present this next week in Dublin. It's a bit rough round the edges, but it's at the stage where I'd appreciate feedback. My intention is not to present 'the best' techniques nor the fastest algorithms but to encourage understanding. Cheers /Joe From community-manager@REDACTED Mon Aug 31 15:55:12 2015 From: community-manager@REDACTED (Bruce Yinhe) Date: Mon, 31 Aug 2015 15:55:12 +0200 Subject: [erlang-questions] Scheduled downtime [September 1 8:00 AM UTC] Erlang.org and mailing lists Message-ID: Hello everyone Please be aware that we have scheduled a downtime on Tuesday 1 September 2015 at 8:00 AM UTC due to server hardware relocation. The duration will be maximum 2 hours. Erlang.org and the mailing lists will be unavailable at this time. *When:* Tuesday 1 September 8:00 AM UTC, maximum 2 hours *Why:* Hardware relocation *What:* Erlang.org website and mailing lists will be unavailable at this time. Mails sent and received during this time will be delayed. *Who*: If you have questions, please contact webmaster@REDACTED For server status news, follow us @erlang_org and @erlangcentral on Twitter. Best regards *Bruce Yinhe* Community Manager Industrial Erlang User Group +46 72 311 43 89 community-manager@REDACTED -- Visit our Erlang community site ErlangCentral.org | @ErlangCentral | Industrial Erlang User Group -------------- next part -------------- An HTML attachment was scrubbed... URL: