Graphviz Dot, different shaped self-pointing arrows - graphviz

I am trying to make a finate state machine with a few loopbacks to certain nodes.
digraph g{
rankdir=TB;
forcelabels=true;
ranksep=1.5;
pad=0.5;
nodesep=2;
node[shape=circle];
A[label="Wait for call\n0 from above"];
B[label="Wait for\nACK 0 || ACK 1"];
E[label="Wait for call\n1 from above"];
F[label="Wait for\nACk 2 || ACK 3"];
C[label="Wait for ACK 0"];
D[label="Wait for ACK 1"];
G[label="Wait for ACK 2"];
H[label="Wait for ACk 3"];
A -> B[label=" rdt_send(data) \n sndpkt=make_pkt(0,data,checksum) \n udt_send(sndpkt) \n start_timer 1 and 2 \n"];
B -> D[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0) \n stop_timer 1"];
B -> C[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1) \n stop_timer 2"];
C -> E[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0) \n stop_timer 2"];
D -> E[label= " rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1) \n stop_timer 1"];
C:nw -> C:nw[constraint=none,xlabel="PLACEHOLDER"];
C:sw -> C:sw[constraint=none,xlabel="PLACEHOLDER"];
D:ne -> D:ne[constraint=none,xlabel="PLACEHOLDER"];
D:se -> D:se[constraint=none,xlabel="PLACEHOLDER"];
E -> F[constraint=none, xlabel=" \n rdt_send(data) \n sndpkt=make_pkt(1,data,checksum) \n udt_send(sndpkt)\n start_timer "];
F -> G[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,3) \n stop_timer "];
F -> H[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,2) \n stop_timer "];
G -> A[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,3) \n stop_timer "];
H -> A[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,2) \n stop_timer "];
G:sw -> G:sw[constraint=none,xlabel="PLACEHOLDER"];
G:nw -> G:nw[constraint=none,xlabel="PLACEHOLDER"];
H:se -> H:se[constraint=none,xlabel="PLACEHOLDER"];
H:ne -> H:ne[constraint=none,xlabel="PLACEHOLDER"];
A:w -> A:w[label=" rdt_rcv(rcvpkt) \n ᐱ"];
B:n -> B:n[label=" rdt_rcv(rcvpkt) \n && corrupt(rcvpkt) \n || isAck(rcvpkt,1) \n ᐱ "];
B:e -> B:e[label=" timeout \n udt_send(sndpkt) \n start_timer \n "];
E:e -> E:e[label=" rdt_rcv(rcvpkt)\nᐱ "];
F:s -> F:s[label=" rdt_rcv(rcvpkt) \n && corrupt(rcvpkt) \n || isAck(rcvpkt,0) \n ᐱ "];
F:w -> F:w[label=" timeout \n udt_send(sndpkt) \n start_timer "];
{rank=same;A;B}
{rank=same;C,D,G,H}
{rank=same;E;F}
}
I then use the command
dot -Tsvg in.dot -o out.svg
This generates following graph
Note the different loopback edges on the four middle nodes and their label placements. The edges also seems stretched, even if I increase the nodesep attribute. How do I solve this efficiently?

Surprisingly, increasing nodesep also increases the loop size.
The following reduces nodesep, adds an invisible node (and 2 edges), and adds some spaces to (some of) the edge labels.
digraph g{
rankdir=TB;
forcelabels=true;
ranksep=1.5;
pad=0.5;
nodesep=1; // was 2
node[shape=circle];
A[label="Wait for call\n0 from above"];
B[label="Wait for\nACK 0 || ACK 1"];
E[label="Wait for call\n1 from above"];
F[label="Wait for\nACk 2 || ACK 3"];
C[label="Wait for ACK 0"];
D[label="Wait for ACK 1"];
G[label="Wait for ACK 2"];
H[label="Wait for ACk 3"];
A -> B[label=" rdt_send(data) \n sndpkt=make_pkt(0,data,checksum) \n udt_send(sndpkt) \n start_timer 1 and 2 \n"];
B -> D[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0) \n stop_timer 1"];
B -> C[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1) \n stop_timer 2"];
C -> E[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0) \n stop_timer 2"];
D -> E[label= " rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1) \n stop_timer 1"];
C:nw -> C:nw[constraint=none,xlabel="1PLACEHOLDER"];
C:sw -> C:sw[constraint=none,xlabel="2PLACEHOLDER "]; // spaces
D:ne -> D:ne[constraint=none,xlabel=" 3PLACEHOLDER"]; // spaces
D:se -> D:se[constraint=none,xlabel="4PLACEHOLDER"];
E -> F[constraint=none, xlabel=" \n rdt_send(data) \n sndpkt=make_pkt(1,data,checksum) \n udt_send(sndpkt)\n start_timer "];
F -> G[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,3) \n stop_timer "];
F -> H[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,2) \n stop_timer "];
G -> A[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,3) \n stop_timer "];
H -> A[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,2) \n stop_timer "];
G:sw -> G:sw[constraint=none,xlabel="5PLACEHOLDER"];
G:nw -> G:nw[constraint=none,xlabel="6PLACEHOLDER"];
H:se -> H:se[constraint=none,xlabel=" 7PLACEHOLDER"]; // spaces
H:ne -> H:ne[constraint=none,xlabel="8PLACEHOLDER"];
A:w -> A:w[label=" rdt_rcv(rcvpkt) \n ᐱ"];
B:n -> B:n[label=" rdt_rcv(rcvpkt) \n && corrupt(rcvpkt) \n || isAck(rcvpkt,1) \n ᐱ "];
B:e -> B:e[label=" timeout \n udt_send(sndpkt) \n start_timer \n "];
E:e -> E:e[label=" rdt_rcv(rcvpkt)\nᐱ "];
F:s -> F:s[label=" rdt_rcv(rcvpkt) \n && corrupt(rcvpkt) \n || isAck(rcvpkt,0) \n ᐱ "];
F:w -> F:w[label=" timeout \n udt_send(sndpkt) \n start_timer "];
{rank=same;A;B}
{rank=same;C,D,G,H BOGUS[style=invis]}
{rank=same;E;F}
edge [style=invis]
H -> BOGUS -> C
}
Giving this:

Related

How do I make a stopwatch for discord bot?

I am a cuber and a programmer, I was helping a friend who suggested an idea in making a cubing bot! So we started on doing the scrambles for different cubes, and then we were trying to make a stopwatch for the bot, but when we run !stop in the channel, it doesn't stop the while loop, instead it just keeps on going!
import random
import discord
import os
import re
import keep_alive
import time
client = discord.Client()
#client.event
async def on_ready():
print("Bot is ready")
#client.event
async def on_message(message):
timer = 0.97
limit = 600.00
if message.author == client.user:
return
if message.content.startswith("!3X3"):
num = 0
Scramble = []
num2 = random.randint(15,26)
while num < num2:
notation = random.randint(1,18)
num += 1
if notation == 1:
Scramble.append("U ")
elif notation == 2:
Scramble.append("U' ")
elif notation == 3:
Scramble.append("U2 ")
elif notation == 4:
Scramble.append("D ")
elif notation == 5:
Scramble.append("D' ")
elif notation == 6:
Scramble.append("D2 ")
elif notation == 7:
Scramble.append("R ")
elif notation == 8:
Scramble.append("R' ")
elif notation == 9:
Scramble.append("R2 ")
elif notation == 10:
Scramble.append("L ")
elif notation == 11:
Scramble.append("L' ")
elif notation == 12:
Scramble.append("L2 ")
elif notation == 13:
Scramble.append("F ")
elif notation == 14:
Scramble.append("F' ")
elif notation == 15:
Scramble.append("F2 ")
elif notation == 16:
Scramble.append("B ")
elif notation == 17:
Scramble.append("B' ")
else:
Scramble.append("B2 ")
ScrambleBR = (','.join(Scramble))
ScrambleAF = re.sub(",","",ScrambleBR)
ctx1 = await message.channel.send("`Generating 3X3 scramble . . .`")
time.sleep(0.2)
ScrambleRRL = re.sub("l' l'" or "l l","l2",ScrambleAF)
time.sleep(0.2)
ScrambleRRLL = re.sub("L' L'" or "L L","L2",ScrambleRRL)
time.sleep(0.2)
ScrambleRRLLL = re.sub("l2 l2" or "L2 L2" or "l' l' l' l'" or "L' L' L' L'" or "l l l l" or "L L L L" "l' l' l2" or "l2 l' l'" or "l l l2" or "l2 l l" or "L' L' L2" or "L2 L' L'" or "L L L2" or "L2 L L","",ScrambleRRLL)
time.sleep(0.2)
ScrambleRRR = re.sub("r' r'" or "r r","r2",ScrambleRRLLL)
time.sleep(0.2)
ScrambleRRRR = re.sub("R' R'" or "R R","R2",ScrambleRRR)
time.sleep(0.2)
ScrambleRRRRR = re.sub("r2 r2" or "R2 R2" or "r' r' r' r'" or "R' R' R' R'" or "r r r r" or "R R R R" "r' r' r2" or "r2 r' r'" or "r r r2" or "r2 r r" or "R' R' R2" or "R2 R' R'" or "R R R2" or "R2 R R","",ScrambleRRRR)
time.sleep(0.2)
ScrambleRRF = re.sub("f' f'" or "f f","f2",ScrambleRRRRR)
time.sleep(0.2)
ScrambleRRFF = re.sub("F' F'" or "F F","F2",ScrambleRRF)
time.sleep(0.2)
ScrambleRRFFF = re.sub("f2 f2" or "F2 F2" or "f' f' f' f'" or "F' F' F' F'" or "f f f f" or "F F F F" or "f' f' f2" or "f2 f' f'" or "f f f2" or "f2 f f" "F' F' F2" or "F2 F' F'" or "F F F2" or "F2 F F","",ScrambleRRFF)
time.sleep(0.2)
ScrambleRRD = re.sub("D' D'" or "D D","D2",ScrambleRRFFF)
time.sleep(0.2)
ScrambleRRDD = re.sub("D' D' D' D'" or "D D D D","",ScrambleRRD)
time.sleep(0.2)
ScrambleRRBB = re.sub("B' B'" or "B B","B2",ScrambleRRDD)
time.sleep(0.2)
ScrambleFinal = re.sub("B2 B2" or "B' B' B' B'" or "B B B B" or "B' B' B2" or "B2 B' B'" or "B B B2" or "B2 B B","",ScrambleRRBB)
await ctx1.edit(content = ScrambleFinal)
if message.content.startswith("!2X2"):
numm = 0
Scramble2X2 = []
numm2 = random.randint(8,10)
while numm < numm2:
notationn = random.randint(1,18)
if notationn == 1:
Scramble2X2.append("U ")
elif notationn == 2:
Scramble2X2.append("U' ")
elif notationn == 3:
Scramble2X2.append("U2 ")
elif notationn == 4:
Scramble2X2.append("D ")
elif notationn == 5:
Scramble2X2.append("D' ")
elif notationn == 6:
Scramble2X2.append("D2 ")
elif notationn == 7:
Scramble2X2.append("R ")
elif notationn == 8:
Scramble2X2.append("R' ")
elif notationn == 9:
Scramble2X2.append("R2 ")
elif notationn == 10:
Scramble2X2.append("L ")
elif notationn == 11:
Scramble2X2.append("L' ")
elif notationn == 12:
Scramble2X2.append("L2 ")
elif notationn == 13:
Scramble2X2.append("F ")
elif notationn == 14:
Scramble2X2.append("F' ")
elif notationn == 15:
Scramble2X2.append("F2 ")
elif notationn == 16:
Scramble2X2.append("B ")
elif notationn == 17:
Scramble2X2.append("B' ")
else:
Scramble2X2.append("B2 ")
numm += 1
ScrambleBRR = (','.join(Scramble2X2))
ScrambleAF2 = re.sub(",","",ScrambleBRR)
ctx1 = await message.channel.send("`Generating 2X2 scramble . . .`")
time.sleep(0.2)
ScrambleRRL2 = re.sub("l' l'" or "l l","l2",ScrambleAF2)
time.sleep(0.2)
ScrambleRRLL2 = re.sub("L' L'" or "L L","L2",ScrambleRRL2)
time.sleep(0.2)
ScrambleRRLLL2 = re.sub("l2 l2" or "L2 L2" or "l' l' l' l'" or "L' L' L' L'" or "l l l l" or "L L L L" "l' l' l2" or "l2 l' l'" or "l l l2" or "l2 l l" or "L' L' L2" or "L2 L' L'" or "L L L2" or "L2 L L","",ScrambleRRLL2)
time.sleep(0.2)
ScrambleRRR2 = re.sub("r' r'" or "r r","r2",ScrambleRRLLL2)
time.sleep(0.2)
ScrambleRRRR2 = re.sub("R' R'" or "R R","R2",ScrambleRRR2)
time.sleep(0.2)
ScrambleRRRRR2 = re.sub("r2 r2" or "R2 R2" or "r' r' r' r'" or "R' R' R' R'" or "r r r r" or "R R R R" "r' r' r2" or "r2 r' r'" or "r r r2" or "r2 r r" or "R' R' R2" or "R2 R' R'" or "R R R2" or "R2 R R","",ScrambleRRRR2)
time.sleep(0.2)
ScrambleRRF2 = re.sub("f' f'" or "f f","f2",ScrambleRRRRR2)
time.sleep(0.2)
ScrambleRRFF2 = re.sub("F' F'" or "F F","F2",ScrambleRRF2)
time.sleep(0.2)
ScrambleRRFFF2 = re.sub("f2 f2" or "F2 F2" or "f' f' f' f'" or "F' F' F' F'" or "f f f f" or "F F F F" or "f' f' f2" or "f2 f' f'" or "f f f2" or "f2 f f" "F' F' F2" or "F2 F' F'" or "F F F2" or "F2 F F","",ScrambleRRFF2)
time.sleep(0.2)
ScrambleRRD2 = re.sub("D' D'" or "D D","D2",ScrambleRRFFF2)
time.sleep(0.2)
ScrambleRRDD2 = re.sub("D' D' D' D'" or "D D D D","",ScrambleRRD2)
time.sleep(0.2)
ScrambleRRBB2 = re.sub("B' B'" or "B B","B2",ScrambleRRDD2)
time.sleep(0.2)
ScrambleFinal2 = re.sub("B2 B2" or "B' B' B' B'" or "B B B B" or "B' B' B2" or "B2 B' B'" or "B B B2" or "B2 B B","",ScrambleRRBB2)
await ctx1.edit(content = ScrambleFinal2)
if message.content.startswith("!4X4"):
num4 = 0
Scramble4X4 = []
num24 = random.randint(43,47)
while num4 < num24:
notation4 = random.randint(1,36)
num4 += 1
if notation4 == 1:
Scramble4X4.append("U ")
elif notation4 == 2:
Scramble4X4.append("U' ")
elif notation4 == 3:
Scramble4X4.append("U2 ")
elif notation4 == 4:
Scramble4X4.append("Uw ")
elif notation4 == 5:
Scramble4X4.append("Uw' ")
elif notation4 == 6:
Scramble4X4.append("Uw2 ")
elif notation4 == 7:
Scramble4X4.append("D ")
elif notation4 == 8:
Scramble4X4.append("D' ")
elif notation4 == 9:
Scramble4X4.append("D2 ")
elif notation4 == 10:
Scramble4X4.append("Dw ")
elif notation4 == 11:
Scramble4X4.append("Dw' ")
elif notation4 == 12:
Scramble4X4.append("Dw2 ")
elif notation4 == 13:
Scramble4X4.append("R ")
elif notation4 == 14:
Scramble4X4.append("R' ")
elif notation4 == 15:
Scramble4X4.append("R2 ")
elif notation4 == 16:
Scramble4X4.append("Rw ")
elif notation4 == 17:
Scramble4X4.append("Rw' ")
elif notation4 == 18:
Scramble4X4.append("Rw2 ")
elif notation4 == 19:
Scramble4X4.append("L ")
elif notation4 == 20:
Scramble4X4.append("L' ")
elif notation4 == 21:
Scramble4X4.append("L2 ")
elif notation4 == 22:
Scramble4X4.append("Lw ")
elif notation4 == 23:
Scramble4X4.append("Lw' ")
elif notation4 == 24:
Scramble4X4.append("Lw2 ")
elif notation4 == 25:
Scramble4X4.append("F ")
elif notation4 == 26:
Scramble4X4.append("F' ")
elif notation4 == 27:
Scramble4X4.append("F2 ")
elif notation4 == 28:
Scramble4X4.append("Fw ")
elif notation4 == 29:
Scramble4X4.append("Fw' ")
elif notation4 == 30:
Scramble4X4.append("Fw2 ")
elif notation4 == 31:
Scramble4X4.append("B' ")
elif notation4 == 32:
Scramble4X4.append("B ")
elif notation4 == 33:
Scramble4X4.append("B2 ")
elif notation4 == 34:
Scramble4X4.append("Bw ")
elif notation4 == 35:
Scramble4X4.append("Bw' ")
else:
Scramble4X4.append("Bw2 ")
ScrambleBR4 = (','.join(Scramble4X4))
ScrambleAR4 = re.sub(",","",ScrambleBR4)
ctx4 = await message.channel.send("`Generating 4X4 scramble . . .`")
time.sleep(0.2)
ScrambleRRL4 = re.sub("l' l'" or "l l","l2",ScrambleAR4)
time.sleep(0.2)
ScrambleRRLL4 = re.sub("L' L'" or "L L","L2",ScrambleRRL4)
time.sleep(0.2)
ScrambleRRLLL4 = re.sub("l2 l2" or "L2 L2" or "l' l' l' l'" or "L' L' L' L'" or "l l l l" or "L L L L" "l' l' l2" or "l2 l' l'" or "l l l2" or "l2 l l" or "L' L' L2" or "L2 L' L'" or "L L L2" or "L2 L L","",ScrambleRRLL4)
time.sleep(0.2)
ScrambleRRR4 = re.sub("r' r'" or "r r","r2",ScrambleRRLLL4)
time.sleep(0.2)
ScrambleRRRR4 = re.sub("R' R'" or "R R","R2",ScrambleRRR4)
time.sleep(0.2)
ScrambleRRRRR4 = re.sub("r2 r2" or "R2 R2" or "r' r' r' r'" or "R' R' R' R'" or "r r r r" or "R R R R" "r' r' r2" or "r2 r' r'" or "r r r2" or "r2 r r" or "R' R' R2" or "R2 R' R'" or "R R R2" or "R2 R R","",ScrambleRRRR4)
time.sleep(0.2)
ScrambleRRF4 = re.sub("f' f'" or "f f","f2",ScrambleRRRRR4)
time.sleep(0.2)
ScrambleRRFF4 = re.sub("F' F'" or "F F","F2",ScrambleRRF4)
time.sleep(0.2)
ScrambleRRFFF4 = re.sub("f2 f2" or "F2 F2" or "f' f' f' f'" or "F' F' F' F'" or "f f f f" or "F F F F" or "f' f' f2" or "f2 f' f'" or "f f f2" or "f2 f f" "F' F' F2" or "F2 F' F'" or "F F F2" or "F2 F F","",ScrambleRRFF4)
time.sleep(0.2)
ScrambleRRD4 = re.sub("D' D'" or "D D","D2",ScrambleRRFFF4)
time.sleep(0.2)
ScrambleRRDD4 = re.sub("D' D' D' D'" or "D D D D","",ScrambleRRD4)
time.sleep(0.2)
ScrambleRRBB4 = re.sub("B' B'" or "B B","B2",ScrambleRRDD4)
time.sleep(0.2)
ScrambleFinal4 = re.sub("B2 B2" or "B' B' B' B'" or "B B B B" or "B' B' B2" or "B2 B' B'" or "B B B2" or "B2 B B","",ScrambleRRBB4)
await ctx4.edit(content = ScrambleFinal4)
if message.content.startswith("!pyra"):
nump = 0
ScramblePyra = []
nump2 = random.randint(10,12)
while nump < nump2:
notationp = random.randint(1,18)
if notationp == 1:
ScramblePyra.append("U ")
elif notationp == 2:
ScramblePyra.append("U' ")
elif notationp == 3:
ScramblePyra.append("U2 ")
elif notationp == 4:
ScramblePyra.append("R ")
elif notationp == 5:
ScramblePyra.append("R' ")
elif notationp == 6:
ScramblePyra.append("R2 ")
elif notationp == 7:
ScramblePyra.append("L ")
elif notationp == 8:
ScramblePyra.append("L' ")
elif notationp == 9:
ScramblePyra.append("L2 ")
elif notationp == 10:
ScramblePyra.append("r ")
elif notationp == 11:
ScramblePyra.append("r' ")
elif notationp == 12:
ScramblePyra.append("l ")
elif notationp == 13:
ScramblePyra.append("l' ")
elif notationp == 14:
ScramblePyra.append("b ")
elif notationp == 15:
ScramblePyra.append("b' ")
elif notationp == 16:
ScramblePyra.append("B' ")
elif notationp == 17:
ScramblePyra.append("B ")
else:
ScramblePyra.append("B2 ")
nump += 1
ScrambleBRRp = (','.join(ScramblePyra))
ScrambleFinal3 = re.sub(",","",ScrambleBRRp)
await message.channel.send(ScrambleFinal3)
if message.content.startswith("!stop"):
await message.channel.send(timer)
if message.content.startswith("!start"):
timerm = await message.channel.send("`Time will be here`")
ready = await message.channel.send("**3**")
time.sleep(1)
set = await message.channel.send("**2**")
time.sleep(1)
go = await message.channel.send("**1**")
time.sleep(1)
GO = await message.channel.send("**GO!**")
time.sleep(0.97)
while timer < limit:
time.sleep(0.01)
timer += 0.01
print(timer) #for testing if stopwatch works
if message.content.startswith("!stop"):
c = await message.channel.send(timer)
break
keep_alive.keep_alive()
client.run(os.getenv("Token"))
This is the part we are struggling with
if message.content.startswith("!stop"):
await message.channel.send(timer)
if message.content.startswith("!start"):
timerm = await message.channel.send("`Time will be here`")
ready = await message.channel.send("**3**")
time.sleep(1)
set = await message.channel.send("**2**")
time.sleep(1)
go = await message.channel.send("**1**")
time.sleep(1)
GO = await message.channel.send("**GO!**")
time.sleep(0.97)
while timer < limit:
time.sleep(0.01)
timer += 0.01
print(timer) #for testing if stopwatch works
if message.content.startswith("!stop"):
c = await message.channel.send(timer)
break
I have been looking around the internet for answers, some are kind of similar but not what I am looking for. I hope someone can solve this question, because you might change cubing bots forever!
Let's take a look at this:
#client.event
async def on_message(message):
This is called whenever a message is sent. message is passed as a parameter, and you can then use it.
Now, say the user calls "!start".
We will then enter this if-statement:
if message.content.startswith("!start"):
And after some more code, this will be run:
while timer < limit:
#some code
if message.content.startswith("!stop"):
c = await message.channel.send(timer)
break
The problem here is with if message.content.startswith("!stop"):. Nothing here actually reads a new message; this if statement is being run with the same message, which starts with "!start". In this coroutine, the message starts with "!start", and therefore we will never enter this if statement, as it definitely does not start with "!stop".
Now, when "!stop" is actually called, it is in a new coroutine of on_message(message), which means it does not interact with the old while loop. Instead, in the new coroutine this code is run:
await message.channel.send(timer)
The while loop continues, meaning that your timer keeps on going.
What this means is, calling "!stop" will never break the loop as it is done in a separate coroutine, though it will print out the contents of timer.
You can experiment with a few ways of fixing this. You can open a new thread for the while loop of the timer, and kill the thread when the timer ends.
As far as I know, this is the most elegant way to do it, although I'm excited to see what people can come up with in the comments. I'll add those to my answer.

sed -e 's/\n/\000/g' is not replacing newlines with null [duplicate]

This question already has answers here:
How can I replace each newline (\n) with a space using sed?
(43 answers)
Closed 1 year ago.
Why are new lines unaffected by the following code?
echo "line 1" > /tmp/xxx
echo "line 2" >> /tmp/xxx
echo "line 3" >> /tmp/xxx
sed -e 's/\n/\000/g' /tmp/xxx | od -xc
results in:
0000000 696c 656e 3120 6c0a 6e69 2065 0a32 696c
l i n e 1 \n l i n e 2 \n l i
0000020 656e 3320 000a
n e 3 \n
0000025
Why are new lines unaffected by the following code?
Because newline is not read to pattern space, as the newline character delimits lines and is not part of the read line.
From POSIX sed:
In default operation, sed cyclically shall append a line of input, less its terminating <newline> character, into the pattern space. [...]

strange textEdit behavior in Ruby on OSX. Inserts weird characters in my file

I am having strange textEdit behavior in Ruby on OSX. It inserts weird characters in my file. Please tell me what to do to fix this:
[Goldie-MacBook:~/ruby] jja% cat hello.rb
#!/usr/bin/ruby
print "Hello World\n"
[Goldie-MacBook:~/ruby] jja% od -c hello.rb
0000000 # ! / u s r / b i n / r u b y \n
0000020 p r i n t " H e l l o W o r
0000040 l d \ n " \n
0000046
[Goldie-MacBook:~/ruby] jja% ruby hello.rb
Hello World
[Goldie-MacBook:~/ruby] jja% lets do some editing
lets: Command not found.
[Goldie-MacBook:~/ruby] jja% cat hello.rb
#!/usr/bin/ruby
print "Hellooo World!\n”
[Goldie-MacBook:~/ruby] jja% ruby hello.rb
hello.rb:2: unterminated string meets end of file
[Goldie-MacBook:~/ruby] jja% od -c hello.rb
0000000 # ! / u s r / b i n / r u b y \n
0000020 p r i n t " H e l l o o o W
0000040 o r l d ! \ n ” ** ** \n
0000053
[Goldie-MacBook:~/ruby] jja% od -xc hello.rb
0000000 2123 752f 7273 622f 6e69 722f 6275 0a79
# ! / u s r / b i n / r u b y \n
0000020 7270 6e69 2074 4822 6c65 6f6c 6f6f 5720
p r i n t " H e l l o o o W
0000040 726f 646c 5c21 e26e 9d80 000a
o r l d ! \ n ” ** ** \n
0000053
[Goldie-MacBook:~/ruby] jja% ruby -v
ruby 1.8.7 (2010-06-23 patchlevel 299) [i686-darwin10]
[Goldie-MacBook:~/ruby] jja%
Notice that " and ” are not the same character. The latter is what's confusing Ruby.
TextEdit uses "Smart Quotes" by default. Under the Edit menu choose Substitutions and uncheck "Smart Quotes." You may also want to uncheck "Smart Dashes."
#Jordan is right. TextEdit adds things you won't want in your code.
If you want a free editor that doesn't do that you can choose resources like atom or text wrangler. Or one of the many other text editors out there.

Bash: difference between cat and echo

This is file.txt (without an end-of-line for the last line):
foo:bar:baz:qux:quux
one:two:tree:four:five:six:seven
alpha:beta:gamma:delta:epsilon:zeta:eta:teta:iota:kappa:lambda:mu
the quick brown fox jumps over the lazy dog
File read.sh
while read -r line
do
echo $line
done < file.txt
This is what I tried in the terminal:
./read.sh
Output:
foo:bar:baz:qux:quux
one:two:tree:four:five:six:seven
alpha:beta:gamma:delta:epsilon:zeta:eta:teta:iota:kappa:lambda:mu
Why doesn't read.sh show the last end of line like cat file.txt does?
Because there is no end of line in file.txt, if you:
$ od -c file.txt
0000000 f o o : b a r : b a z : q u x :
0000020 q u u x \n o n e : t w o : t r e
0000040 e : f o u r : f i v e : s i x :
0000060 s e v e n \n a l p h a : b e t a
0000100 : g a m m a : d e l t a : e p s
0000120 i l o n : z e t a : e t a : t e
0000140 t a : i o t a : k a p p a : l a
0000160 m b d a : m u \n t h e q u i c
0000200 k b r o w n f o x j u m p
0000220 s o v e r t h e l a z y
0000240 d o g
There are no \n at the end of the file.
echo on the other other hand will always add a new line when you echo a message if there isn't one.
Other answers are right, there is simply no newline character in the end of your file.txt.
Most text editors will end a file with a newline automatically, even nano does that. But your file was generated by a script, right?
To reproduce this behavior all you have to do is:
echo -n 'hello world' >> file.txt
-n flag tells echo not to output the trailing newline.
Also, if you want your read code to work, you can use this:
while read -r line
do
printf "%s\n" "$line"
done < file.txt
[[ -n $line ]] && printf '%s' "$line"
This is going to work because actually read will place the last line into the variable, but it also will return false, thus breaking the while loop.
Your input file doesn't end in a newline.
cat file simply copies the file contents to standard output. It operates by characters, not lines, so it doesn't care if the file ends in a newline or not. But if it doesn't end in a newline, it won't add one to the output.
read -r line will read a line into the variable. It will only report success if the line ends in a newline. If the last line of the input doesn't end in newline, it reports an error, as if EOF had been reached. So the loop terminates when it tries to read the last line, instead of returning that line. That's why the script never displays the line beginning with the quick brown fox.
In general, Unix text-file programs are only defined to work on text files that end in newline. Their treatment of the last line if it doesn't have a newline is not usually specified.
Your file.txt does not contain a newline at the end of the last line. Hence cat does not show it.
Note that read.sh does not display the last line at all... in read.sh, read is waiting for a complete line of input, and since the last line is not terminated by a newline, so it is not actually read.

OSX - "sort" by 1st character only issue, tried -k 1.1,1.1

I'm on OSX 10.6.8
I'm having some issues sorting a text file by the first character.
I'm concatenating three files into one and need the final result sorted by the first alphabetical letter.
Each file has lines that look like this:
A025-001
A118-001
A118-002
B657-001
D316-001
So the file after concatenation via "cat" looks like this:
A025-001
....
A025-001 (where file 2 was appended)
....
A025-001 (where file 3 was appended)
I've tried "sort -k 1.1,1.1 result.txt > sortedresult.txt" and with a large amount of other options in the man page: i,b,f,s (just guessing in hopes that I may have found the right one)
I need all the entries to be put next to each other:
A025-001
A025-001
B.......
B.......
D.......
Hopefully, someone more knowledgeable than thou can help me solve this problem.
Thanks
Update: the data files themselves aren't working well with unix tools. If I cat the results file, only a few lines are shown, of many. Opening them in "vim" shows a bunch of ^M characters. It seems as if sort is not going through the whole file.
There's column header at the top, with fields in quotations, tab-separated e.g. "Product" \t "Category" \t
The rest of the data is tab-separated but without quotations.
sample od -c:
0000000 " P r o d u c t N u m b e r "
0000020 \t " L o o k u p A t t r i b u
0000040 t e 1 G r o u p " \t " L o o
0000060 k u p A t t r i b u t e 1
0000100 N a m e " \t " L o o k u p A t
0000120 t r i b u t e 1 V a l u e "
0000140 \t " L o o k u p A t t r i b u
0000160 t e 1 V a l u e I m a g e
0000200 " \t " L o o k u p A t t r i b
Here's some of the data (not the column header):
0000660 " \n A 0 2 5 - 0 0 1 \t F a c e t
0000700 \t F a c e t C o l o r \t B l u e
0000720 \t C C D D D D \t O P T I O N \t \r
Does anyone know why it is doing this?
Update #2: The files were exported out of FileMaker as ASCII. You'll see a lot of extra tabs, just ignore those, once we get this figured out I'll sed them out. Here is the entire file along with a hexdump and od -c of the file: pastebin.com/UzaUgG6C
Looking at the pastebin, it seems FileMaker is terminating the column headers with \n and separating your records with \r. You need to normalize your line endings first.
cat result.txt | tr '\r' '\n' | sort
I think the problem is just the line endings. The ^M characters are carriage returns. UNIX tools generally expect newlines, and no carriage returns. Try the answers to this question or try running mac2unix if you have it.
Try
sort -k1.1,1.2 result.txt > sortedresult.txt
I hope this helps.
P.S. as you appear to be a new user, if you get an answer that helps you please remember to mark it as accepted, and/or give it a + (or -) as a useful answer.
You should try simply:
cat file1.txt file2.txt file3.txt | sort > result.txt
using the -k 1.1,1.1 will not make any use as there is only one field
To make it stable, that is, the group of entries for which the first characters are same, will keep the relative ordering same, you might use the -s switch with the -k 1.1,1.1 switch.
cat file1.txt file2.txt file3.txt | sort -s -k 1.1,1.1 > result.txt
I think this is the solution you need.

Resources