Related
I'm working on a ruamel.yaml (v0.17.4) based YAML reformatter (using the RoundTrip variant to preserve comments).
I want to allow a mix of block- and flow-style maps, but in some cases, I want to convert a flow-style map to use block-style.
In particular, if the flow-style map would be longer than the max line length^, I want to convert that to a block-style map instead of wrapping the line somewhere in the middle of the flow-style map.
^ By "max line length" I mean the best_width that I configure by setting something like yaml.width = 120 where yaml is a ruamel.yaml.YAML instance.
What should I extend to achieve this? The emitter is where the line-length gets calculated so wrapping can occur, but I suspect that is too late to convert between block- and flow-style. I'm also concerned about losing comments when I switch the styles. Here are some possible extension points, can you give me a pointer on where I'm most likely to have success with this?
Emitter.expect_flow_mapping() probably too late for converting flow->block
Serializer.serialize_node() probably too late as it consults node.flow_style
RoundTripRepresenter.represent_mapping() maybe? but this has no idea about line length
I could also walk the data before calling yaml.dump(), but this has no idea about line length.
So, where should I and where can I adjust the flow_style whether a flow-style map would trigger line wrapping?
What I think the most accurate approach is when you encounter a flow-style mapping in the dumping process is to first try to emit it to a buffer and then get the length of the buffer and if that combined with the column that you are in, actually emit block-style.
Any attempt to guesstimate the length of the output without actually trying to write that part of a tree is going to be hard, if not impossible to do without doing the actual emit. Among other things the dumping process actually dumps scalars and reads them back to make sure no quoting needs to be forced (e.g. when you dump a string that reads back like a date). It also handles single key-value pairs in a list in a special way ( [1, a: 42, 3] instead of the more verbose [1, {a: 42}, 3]. So a simple calculation of the length of the scalars that are the keys and values and separating comma, colon and spaces is not going to be precise.
A different approach is to dump your data with a large line width and parse the output and make a set of line numbers for which the line is too long according to the width that you actually want to use. After loading that output back you can walk over the data structure recursively, inspect the .lc attribute to determine the line number on which a flow style mapping (or sequence) started and if that line number is in the set you built beforehand change the mapping to block style. If you have nested flow-style collections, you might have to repeat this process.
If you run the following, the initial dumped value for quote will be on one line.
The change_to_block method as presented changes all mappings/sequences that are too long
that are on one line.
import sys
import ruamel.yaml
yaml_str = """\
movie: bladerunner
quote: {[Batty, Roy]: [
I have seen things you people wouldn't believe.,
Attack ships on fire off the shoulder of Orion.,
I watched C-beams glitter in the dark near the Tannhäuser Gate.,
]}
"""
class Blockify:
def __init__(self, width, only_first=False, verbose=0):
self._width = width
self._yaml = None
self._only_first = only_first
self._verbose = verbose
#property
def yaml(self):
if self._yaml is None:
self._yaml = y = ruamel.yaml.YAML(typ=['rt', 'string'])
y.preserve_quotes = True
y.width = 2**16
return self._yaml
def __call__(self, d):
pass_nr = 0
changed = [True]
while changed[0]:
changed[0] = False
try:
s = self.yaml.dumps(d)
except AttributeError:
print("use 'pip install ruamel.yaml.string' to install plugin that gives 'dumps' to string")
sys.exit(1)
if self._verbose > 1:
print(s)
too_long = set()
max_ll = -1
for line_nr, line in enumerate(s.splitlines()):
if len(line) > self._width:
too_long.add(line_nr)
if len(line) > max_ll:
max_ll = len(line)
if self._verbose > 0:
print(f'pass: {pass_nr}, lines: {sorted(too_long)}, longest: {max_ll}')
sys.stdout.flush()
new_d = self.yaml.load(s)
self.change_to_block(new_d, too_long, changed, only_first=self._only_first)
d = new_d
pass_nr += 1
return d, s
#staticmethod
def change_to_block(d, too_long, changed, only_first):
if isinstance(d, dict):
if d.fa.flow_style() and d.lc.line in too_long:
d.fa.set_block_style()
changed[0] = True
return # don't convert nested flow styles, might not be necessary
# don't change keys if any value is changed
for v in d.values():
Blockify.change_to_block(v, too_long, changed, only_first)
if only_first and changed[0]:
return
if changed[0]: # don't change keys if value has changed
return
for k in d:
Blockify.change_to_block(k, too_long, changed, only_first)
if only_first and changed[0]:
return
if isinstance(d, (list, tuple)):
if d.fa.flow_style() and d.lc.line in too_long:
d.fa.set_block_style()
changed[0] = True
return # don't convert nested flow styles, might not be necessary
for elem in d:
Blockify.change_to_block(elem, too_long, changed, only_first)
if only_first and changed[0]:
return
blockify = Blockify(96, verbose=2) # set verbose to 0, to suppress progress output
yaml = ruamel.yaml.YAML(typ=['rt', 'string'])
data = yaml.load(yaml_str)
blockified_data, string_output = blockify(data)
print('-'*32, 'result:', '-'*32)
print(string_output) # string_output has no final newline
which gives:
movie: bladerunner
quote: {[Batty, Roy]: [I have seen things you people wouldn't believe., Attack ships on fire off the shoulder of Orion., I watched C-beams glitter in the dark near the Tannhäuser Gate.]}
pass: 0, lines: [1], longest: 186
movie: bladerunner
quote:
[Batty, Roy]: [I have seen things you people wouldn't believe., Attack ships on fire off the shoulder of Orion., I watched C-beams glitter in the dark near the Tannhäuser Gate.]
pass: 1, lines: [2], longest: 179
movie: bladerunner
quote:
[Batty, Roy]:
- I have seen things you people wouldn't believe.
- Attack ships on fire off the shoulder of Orion.
- I watched C-beams glitter in the dark near the Tannhäuser Gate.
pass: 2, lines: [], longest: 67
-------------------------------- result: --------------------------------
movie: bladerunner
quote:
[Batty, Roy]:
- I have seen things you people wouldn't believe.
- Attack ships on fire off the shoulder of Orion.
- I watched C-beams glitter in the dark near the Tannhäuser Gate.
Please note that when using ruamel.yaml<0.18 the sequence [Batty, Roy] never will be in block style
because the tuple subclass CommentedKeySeq does never get a line number attached.
I have created separate groups on supercollider for each instrument so that I may apply FX, like echo, to the group and only affect one instrument rather than all instruments playing on that sc server.
On the node tree, the echo synthdef correctly appears in the required group (box) and the FX is applied to the instrument in that group, but ALSO incorrectly applying echo to the nodes in other groups on the same server.
What I have noticed is that it affects all higher number groups and not lower number groups. Applying FX (echo) to group 1 or group 2 also applies the same FX to groups 3,4,5,6,7,8, etc., but applying FX to group 8 does NOT seem to affect groups 1,2,3,4,5,6,& 7.
I have tested this on the following systems/versions....
supercollider version (1:3.10.0+repack-1ubuntu2) on ubuntu (Linux
Optiplex-3010 5.4.0-70-generic #78-Ubuntu SMP x86_64 x86_64 x86_64
GNU/Linux)
supercollider version (1:3.10.0+repack-1+rpi1) on Linux raspberrypi
4.19.75-v7l+ #1270 SMP armv7l GNU/Linux
supercollider version (1:3.8.0~repack-2) on Linux advent
5.0.0-32-generic #34~18.04.2-Ubuntu SMP 2019 i686 i686 i686 GNU/Linux
Is this a known bug? Can I make any manual changes to the supercollider code to resolve this? If not, then it will have to be a separate RPi4 for each instrument, underutilising each RPi and increasing project costs significantly.
Regards to all SCcoders,
Phil
Requested code:
(SynthDef(\echo,{|in, out, length = 1, fb = 0.6, sep = 1|
var input = In.ar(in, 2);
var feedback = LocalIn.ar(2);
var output = LeakDC.ar(feedback*fb + input);
LocalOut.ar(DelayC.ar(output, length, sep));
ReplaceOut.ar(out, output);
}).writeDefFile("/home/phil/Supercollider/syndef");)
I instigate the echo via OSC over tcp/ip, but essentially it would be called by:
/s_new s 'echo' i 1028 i 0 i 8 //in this case 1028 is the node for track 8
//and 8 is the SC group
and adjusted by:
/n_set i 1028 s 'fb' f 0.7
UPDATE: In answer to Fizz's comment about...
how I created groups, initially in the startup.scd file and then clear every time the live performance stops and create every time the live performance starts...
oscStream.Clear();
oscStream << osc::BeginBundleImmediate
<< osc::BeginMessage("/g_freeAll") << 1 << osc::EndMessage
<< osc::BeginMessage("/clearSched") << osc::EndMessage
<< osc::EndBundle;
transmitSocketMelody1.Send(oscStream.Data(),oscStream.Size());
oscStream.Clear();
oscStream << osc::BeginMessage("/g_new") << 1 << 0 << 0
<< osc::EndMessage;
transmitSocketMelody1.Send(oscStream.Data(),oscStream.Size());
oscStream.Clear();
oscStream << osc::BeginMessage("/g_new") << 2 << 0 << 0
<< osc::EndMessage;
transmitSocketMelody1.Send(oscStream.Data(),oscStream.Size());
which is the equivalent of...
s.sendMsg(\g_freeAll, 0);
s.sendMsg(\clearSched);
s.sendMsg(\g_new,1,0,0);
s.sendMsg(\g_new,2,0,0);
Order that I create synthdefs...
The echo synthdef (already shown above) is the first created via the supercollider startup.scd file.
Then the sound synthdefs are created in numerical order Piano1, Piano2, Piano3, etc... also via the supercollider startup.scd file.
s.sendMsg(\b_allocRead, 101,"piano-p-c4.wav"); //buffer 101
SynthDef.new("piano1", {|amp=1, freq|
var output,sig,sig2;
sig=PlayBuf.ar(2, 101, freq/523.25, doneAction:2);
sig=sig*amp;
sig = Splay.ar(sig);
Out.ar(0,sig!2);
}).store;
s.sendMsg(\b_allocRead, 111,"piano-p-c5.wav"); //buffer 111
SynthDef.new("piano2", {|amp=1, freq|
var sig;
sig=PlayBuf.ar(2, 111, freq/523.25, doneAction:2);
sig=sig*amp;
sig = Splay.ar(sig);
Out.ar(0,sig!2);
}).store;
The piano synthdefs are played live from the commands..
oscStream_melody1 << osc::BeginMessage("/s_new")
<< "piano1"
<< NextSCNode << 0 << 1
<< "freq" << OscFrequency[OSCOctave][OSCNote]
<< "amp" << Melody1Amplitude*Melody1Volume
<< osc::EndMessage
transmitSocketMelody1.Send(oscStream_melody1.Data(),oscStream_melody1.Size());
oscStream_melody2 << osc::BeginMessage("/s_new")
<< "piano2"
<< NextSCNode << 0 << 2
<< "freq" << OscFrequency[OSCOctave][OSCNote]
<< "amp" << Melody2Amplitude*Melody2Volume
<< osc::EndMessage;
transmitSocketMelody2.Send(oscStream_melody2.Data(),oscStream_melody2.Size());
which is the equivalent of...
s.sendMsg("/s_new","\piano1",1234, 0, 1,"freq",440,"amp", 0.8)
s.sendMsg("/s_new","\piano2",1235, 0, 2,"freq",880,"amp", 0.7)
echo is turned on, modified and off live thus...
s.sendMsg(\s_new,'echo',1001,0,X); //where X is the group to apply to
s.sendMsg(\n_set, 1001,'fb',0.5,'length',1,'sep',1);
s.sendMsg(\n_free, 1001);
but this turns on the echo for all groups with higher numbers, e.g group2, group3, group4 etc.
Whereas if reverb is set on group2 it affects group3, group4, etc but not group1.
Without seeing any code, this is hard to answer, but I wonder if you are using buses? Your instrument group should output to an echo bus and that bus should output to where you wish the sound to go next - another FX bus or to 0.
You'd want to draw a block diagram of your groups, connecting inputs and outputs. Keep in mind that any FX group can take ins from multiple places, but will only have one output. This means you may end up running the same FX synth more than once, for example, if you want echo on groups A and B, but then you want group B to go to a compressor afterwards.
Make sure to declare every bus, give it a good variable name and remember to pass it as an argument on synth creation.
I am trying to count the correct inputs from the user. An input looks like:
m = "<ex=1>test xxxx <ex=1>test xxxxx test <ex=1>"
The tag ex=1 and the word test have to be connected and in this particular order to count as correct. In case of an invalid input, I want to send the user an error message that explains the error.
I tried to do it as written below:
ex_test_size = m.scan(/<ex=1>test/).size # => 2
test_size = m.scan(/test/).size # => 3
ex_size = m.scan(/<ex=1>/).size # => 3
puts "lack of tags(<ex=1>)" if ex_test_size < ex_size
puts "Lack of the word(test)" if ex_test_size < test_size
I believe it can be written in a better way as the way I wrote, I guess, is prone to errors. How can I make sure that all the errors will be found and shown to the user?
You might use negative lookarounds:
#⇒ ["xxx test", "<ex=1>"]
m.scan(/<ex=1>(?!test).{,4}|.{,4}(?<!<ex=1>)test/).map do |msg|
"<ex=1>test expected, #{msg} got"
end.join(', ')
We scan the string for either <ex=1> not followed by test or vice versa. Also, we grab up to 4 characters that violate the rule for the more descriptive message.
I am using LLDB and wondering how to print the contents of a specific memory address, for example 0xb0987654.
To complement Michael's answer.
I tend to use:
memory read -s1 -fu -c10000 0xb0987654 --force
That will print in the debugger.
-s for bytes grouping so use 1 for uint8 for example and 4 for int
-f for format. I inherently forget the right symbol. Just put the statement with -f and it will snap back at you and give you the list of all the options
-c is for count of bytes
if you are printing more than 1024 bytes, append with --force
Hope this helps.
Xcode has a very nice Memory Browser window, which will very nicely display the contents of memory addresses. It also lets you control byte grouping and number of bytes displayed, and move back or forward a memory page:
You can access it by pressing ⌘^⌥⇧M. After entering it, press enter to open the memory browser in the main editor.
or
Debug --> Debug Workflow --> View Memory
Notice the field on its bottom left corner where you can paste the memory address you want to inspect!
Documentation here: https://developer.apple.com/library/ios/recipes/xcode_help-debugger/articles/viewing_memory.html
Related answer here: How do I open the memory browser in Xcode 4?
"me" is the command you're looking for.
For example, this lldb command:
me -r -o /tmp/mem.txt -c512 0xb0987654
will copy 512 bytes from your memory address into a file at /tmp/mem.txt.
for example, print memory of length 16x4 bytes.
x/16 0xb0987654
Here's a simple trick for displaying typed arrays of fixed-length in lldb. If your program contains a long* variable that points to 9 elements, you can declare a struct type that contains a fixed array of 9 long values and cast the pointer to that type:
long *values = new long[9]{...};
(lldb) expr typedef struct { long values[9]; } l9; *(l9 *)values
(l9) $1 = {
values = {
[0] = 0
[1] = 1
[2] = 4
[3] = 9
[4] = 16
[5] = 25
[6] = 36
[7] = 49
[8] = 64
}
}
I use the typedef when I'm coding in C, it's not needed in C++.
0.upto(9) do
STDOUT.print "Flash!"
sleep 0.5
STDOUT.print "\b\b\b\b\b\b" # (6 backspaces, the length of "Flash!")
sleep 0.5
end
This code doesn't work. It prints Flash! to the screen, but it doesn't flash. It just stays there, as though the backspaces aren't taking effect. But I do this:
0.upto(9) do
STDOUT.print "Flash!"
sleep 0.5
STDOUT.print "\b\b\b\b\b" # (5 backspaces, the length of "Flash! - 1")
sleep 0.5
end
and it almost works. It prints this: FFFFFFFFFFlash!(after 9 loops) Why do the backspaces stop taking effect when their number is equal to the length of the string they're deleting?
How can I overcome this problem and create a flashing message, only using libraries that are part of rails?
I tried a workaround like this:
0.upto(9) do
STDOUT.print " Flash!"
sleep 0.5
STDOUT.print "\b\b\b\b\b\b"
sleep 0.5
end
(Note the space in " Flash!"), but what happens is the message appears to crawl across the screen! An interesting effect, but not what I want.
I'm using Command Prompt with Ruby and Rails in Windows 7
Typically this would be written something like:
0.upto(9) do
STDOUT.print "\rFlash!"
sleep 0.5
STDOUT.print "\r " # Send return and six spaces
sleep 0.5
end
Back in the days when we'd talk to TTY and dot-matrix printers, we'd rapidly become used to the carriage-control characters, like "\r", "\n", "\t", etc. Today, people rarely do that to start, because they want to use the web, and browsers; Learning to talk to devices comes a lot later.
"\r" means return the carriage to its home position, which, on a type-writer moved the roller all the way to the right so we could start typing on the left margin again. Printers with moving heads reversed that and would move the print-head all the way to the left, but, in either case, printing started on the left-margin again. With the console/telnet/video-TTY, it moves the cursor to the left margin. It's all the same, just different technology.
A little more usable routine would be:
msg = 'Flash!'
10.times do
print "\r#{ msg }"
sleep 0.5
print "\r#{ ' ' * msg.size }" # Send return and however many spaces are needed.
sleep 0.5
end
Change msg to what you want, and the code will automatically use the right number of spaces to overwrite the characters.
Anyway, it looks like backspace (at least in windows) just positions the cursor back, you need/want to overwrite the character with a space at that point (or 6 of them) to "blank" the text out.
Or, you can just use this
def text_flasher(text)
puts "\e[5m#{text}\e[0m"
end
use text_flasher in the console and you'll see the magic :)
Right, based on #rogerdpack 's input I have devised a solution:
def flashing_output(output)
message = output
backspace = "\b"
space = " "
backspace_array = []
space_array = []
length = message.length
length.times do
backspace_array << backspace
space_array << space
end
0.upto(9) do
print message
sleep 0.5
print backspace_array.join.to_s + space_array.join.to_s + backspace_array.join.to_s + backspace_array.join.to_s
sleep 0.5
end
end
flashing_output("Flashing Foobars! (not a euphemism)")