Mixed horizontal and vertical alligned use case nodes - plantuml

I want to display nodes in a Use Case diagram more compact than Graphviz does by default. Say for example the following cases are wrapped in a rectangle:
actor A
actor B
A - (case a)
(case b) - B
A - (mixed case)
(mixed case) - B
By default the cases are aligned vertically. I'd prefer to have (case a) an (case b) side-by-side and (mixed case) centred and below the previous cases. I've also tried to use -[hidden]- links
(case a) -[hidden]- (case b)
but then (mixed case) gets left aligned and cases a and b are too wide apart. Here's how it looks in full beauty:
#startuml
left to right direction
Source <<Operator>>
Sink <<Operator>>
Source ..> Sink : notify service address
rectangle "Init phase" {
Source -> (Prepare service)
(Prepare service) -[hidden]-(Register with service)
(Register with service) <- Sink
Source -> (Secure channel) : <<initiate>>
(Secure channel) <-- Sink : <<participate>>
Source --> (Ensure readiness) : <<participate>>
(Ensure readiness) <- Sink : <<initiate>>
}
#enduml
Image here:

I usually accept the formatting (after a bit of tweaking with -left->, -right-> etc.)
You might consider the use of skinparam to have use cases in one column (default, very compact) and distinguish them by color. This is different than what you have asked for, but I do hope that it
#startuml
left to right direction
Source <<Operator>>
Sink <<Operator>>
Source ..> Sink : notify service address
skinparam usecase {
BackgroundColor<< Source >> DarkSeaGreen
BorderColor<< Source >> DarkSlateGray
BackgroundColor<< Both >> YellowGreen
BorderColor<< Both >> YellowGreen
BackgroundColor<< Sink >> Yellow
BorderColor<< Sink >> Yellow
}
rectangle "Init phase" {
Source -> (Prepare service)<<Source>>
' (Prepare service) -[hidden]-(Register with service)
Source -> (Secure channel)<<Both>> : initiate
(Secure channel) <-- Sink : <<participate>>
Source --> (Ensure readiness) : <<participate>>
(Ensure readiness)<<Both>> <- Sink : <<initiate>>
(Register with service)<<Sink>> <- Sink
}
#enduml
This results in the following:

Related

Connecting SourceShape/PortOpts from a UniformFanOutShape to sources in Akka Streams

Most examples of FanOut shapes in Akka steams either merge the faned-out flows into a single stream, or immediately connect them to a sink. I want to instead return a sequence of Sources that I can then apply transformation and connect to a sinks later on. An example would look something like this
def transformedSources(src: Source[Int,NotUsed]) : Seq[Source[Int,NotUsed]] {
import GraphDSL.Implicits._
val builder = new GraphDSL.Builder
val bcast = builder.add(Broadcast[Int](2))
src.out ~> bcast.in
val sourceShapes = (bcast.out).map { out => SourceShape(out)}}
??? // How to convert sourceShapes into Sources
}
Is there a way to achieve this?
p.s
My real use case is an AmorphousShape that takes X sources, and produces X output. Ideally I would like to apply the AmorphousShape stage, and then continue operating as if nothing changes.
So if my code now is
sources.map{s => s.via(someStage).runWith(Sink.seq)}
I would like to transform it into
transformSource(sources).map{s => s.via(someStage).runWith(Sink.seq)}
def transformSource(sources:Seq[Source[Int, NotUsed]]) : Seq[Source[Int, NotUsed]] = {do some magic with an AmorphousShape graph }

Merging streams when _any_ of the substreams has a value ready

From Akka-stream documentation, it looks like that all stream merging options (merge, mergeSorted, mergePreferred, zipN, zipWithN) work by waiting when all merged streams have the new element ready, then applying the merge strategy (combining elements into a tuple, or applying zip function, etc.)
This works well for offline processing (e.g. reading the data from files or HTTP and combining it), but it introduces latency in online processing. I need to merge streams of data produced by e.g. multiple Websocket connection, and deliver updates in the merged stream as soon as any of the source streams produces a value. Example: if there are source streams A and B, here's what should be in the merged stream:
Output stream starts with some initial value, e.g. (None, None).
(A:1) (B:<not ready>) -> (Some(1), None)
(A:2) (B:<not ready>) -> (Some(2), None)
(A:3) (B:1) -> (Some(3), Some(1))
(A:3) (B:2) -> (Some(3), Some(2))
etc. Again, a new value appears in the output stream when any of the source stream produces a value, immediately.
Is there any combinator to achieve that?
As stated in the comments, Merge and MergePreferred stages do emit elements downstream even if not all upstreams have an element available.
From your example it looks like you are looking for zipping sources though. And yes, Zip emits the zipped tuple downstream only when it has elements to zip from all its upstreams. To overcome this you can 'lift' your sources to produce Options, and make them emit None whenever there is nothing else to emit. The source wrapper can look like this:
def asOption[In, Mat](source: Source[In, Mat]): Source[Option[In], Mat] =
Source.fromGraph(GraphDSL.create(source.map(Option(_))) {
implicit builder: GraphDSL.Builder[Mat] => src =>
import GraphDSL.Implicits._
val noneSource = Source.repeat(None)
val merge = builder.add(MergePreferred[Option[In]](1))
src ~> merge.preferred
noneSource ~> merge.in(0)
SourceShape(merge.out)
})
At this point you can zip your sources as you would normally.
val src1: Source[Int, NotUsed] = ???
val src2: Source[Int, NotUsed] = ???
val zipped = asOption(src1) zip asOption(src2)

GhostScript (PostScript): Printer cut- off borders when scaling down from A* to A4

I'm working on a "GS Wrapper" (using the 9.20 SDK) for use by an external application. There i scale down for example a A0 Sheet to A1, A2 and A3 and it works fine. (PDF to PS, then Print)
Problem: When i scale down any input format to A4, the printer cut off the borders of the content (these are technical drawings with a black border each 5mm from the sheet edge).
Is there an opportunity to scale down the A4 (to A4) again about 95% and center the image? (This should be result in a smaller base image, say the black borders are about ~10mm away from the sheet border afterwards)
I use the following parameter for scaling:
GhostArg[0] = "-dNOPAUSE";
GhostArg[1] = "-dBATCH";
GhostArg[2] = "-dSAFER";
GhostArg[3] = "-dNOPAUSE";
GhostArg[4] = "-g2480x3508";
GhostArg[5] = "-dPDFFitPage";
GhostArg[6] = "-r300x300";
GhostArg[7] = "-sDEVICE=ps2write";
GhostArg[8] = Output;
GhostArg[9] = Input;
Solution Update:
I managed to fix this problem by insert this three lines between Arg[8] and Arg[9]:
GhostArg[9] = "-c";
GhostArg[10] = "<< /BeginPage { 0.99 0.99 scale 10 10 translate } >> setpagedevice";
GhostArg[11] = "-f";
Thanks to KenS for the /BeginPage hint.
It sounds like your printer has a non-printable area. This is not uncommon, the paper handling needs to hold the paper while its being printed, and this can lead to some areas of the media not being printable.
If your content reaches to the edge of the media, its possible that the printer simple cannot print there, resulting in the content being cropped.
It is entirely possible to have ps2write drop the media content to a smaller size, but you can't have it (automatically) scale down and also shift the content location, because the content is fitted to the media size.
However, the FitPage mechanism doesn't look at the content, just the media size requests. So if the input requests A3 and the selected media is A4 (and fixed) then a scale factor is applied to scale the content to the required media size (and the media request for A3 is ignored).
So what you could do is leave the code you have as it is as present, but add a BeginPage or Install procedure which uses the scale operator to further reduce the size of marks on the page, and the translate operator to move the origin slightly so that the final content is centered.
Something like (example only, untested):
<<
/BeginPage {
0.95 0.95 scale
16 20 translate
}
>> setpagedevice
By the way, you do realise Ghostscript is licenced under the AGPL ?
Also, I'd very strongly recommend that you do not use the -g and -r switches, but instead simply use -dDEVICEWIDTHPOINTS and -dDEVICEHEIGHTPOINTS to alter the media size.
The -g switch works in pixels, but high level output devices (eg pdfwrite and ps2write) don't emit pixels, they write high level vector objects. However, due to differences in the PostScript and PDF graphics models, some elements do need to be rendered to images and enclosed in that fashion in the PostScript output. By setting the resolution to 300 you are fixing the resolution at which those elements (eg pages containing transparency) are rendered. I'd suggest that you don't do so, unless you are working in a very tightly controlled workflow and know the resolution of the final output.
By using the DEVICEHEIGHTPOINTS and DEVICEWIDTHPOINTS switches you can control the media size without reference to the resolution. Note that in PostScript (and PDF) 1 point = 1/72 inch.

google protocol buffer wire type start group and end group usage

Trying to parse a message from a server which passes wire type as Start Group .
I am using protobuf-c lib in which start group and end group are unsupported (Latest).Is there any examples how to work with wire type as start group so that can parse the message by my self
Thanks in advance
For background, "groups" are a different way of representing a sub-message. They are declared like this:
message Foo {
repeated group bar = 1 {
optional int32 baz = 2;
optional string qux = 3;
}
}
Semantically, this is almost exactly the same as:
message Foo {
repeated Bar bar = 1;
message Bar {
optional int32 baz = 2;
optional string qux = 3;
}
}
However, the encoding is slightly different (explained below).
Groups were already deprecated at the time that Protobuf was first open sourced, hence a lot of non-Google implementations don't support groups. Google has some very old protocols that still use groups, but probably no one outside of Google should be using groups, so I'm guessing the protocol you're working with is one of Google's. (If not, maybe you just have corrupted data.)
I'll assume you've already read the encoding docs, but they don't explain groups.
Groups are encoded starting with a "start group" tag, followed by the sub-message content, followed by a corresponding "end group" tag. This is the only case in protobufs where a tag appears at the end of a value -- in all other cases a tag only appears at the start.
In contrast, normal sub-messages (as in the second example above) are encoded using the "length-delimited" wire type: a tag, followed by the sub-message size, followed by the content. Notice how the length-delimited encoding means you can skip a sub-message without parsing all of its fields; with a group, the only way to know where the group ends is to parse every field until you see the end-group tag.

How could I create a Gantt-like chart in a datawindow (Powerbuilder)

I want a rather simple (and cheap) solution, just for presentation purposes (and just to show the task duration bars - no connection lines between them). So, I am not interested in buying some advanced custom control like this for example. Have any of you ever used something like this? Are there any code samples available?
I would have pointed to Buck Woolley's dwExtreme site for an example of how to do a gantt in native DataWindow. However, "simple" I don't think is in your future if you want to roll your own. In fact, I'll be pleasantly surprised if someone writes a posting that includes a full description; I think it would take pages. (I'd be happy if someone proved me wrong.) In the meantime, here are some DataWindow basics I think you would need:
You can create an external DataWindow whose data source is not tied to a table
Columns in the data set do not have to be shown on the user interface
Columns in the data set can be used in expressions to evaluate attributes, so you could have a column for each of the following attributes of a rectangle:
x
width
color
I'd expect this to be a lot of work and time, and very likely to be worth the purchase the component (unless your time is valued at next to nothing, which in some IT shops is close to true).
Good luck,
Terry
(source: illudium.com)
You can make a simple Gantt chart with a Stacked Bar Graph (BarStacked (5) in the painter). The trick is to create a dummy series to space the bar out where you want it and make the dummy bar the same color as the graph's background (BackColor). It turns out you also need another dummy series with a small value to sit on the axis. Otherwise when you change the color of the bar that's doing the spacing, the axis line gets cut off. I found that .04 works well for this value.
Create the DataWindow
(This assumes familarity with the DataWindow Wizard. Refer to the PowerBuilder User's Guide for more information on creating graphs in DataWindows)
Click the icon for the new object wizard. Create a Graph DataWindow with an External data source. Create columns task type string(20), ser type string(1), and days type number. Set the Category to the task column and the Values to the days column. Click the Series button and select ser for the series. Don't bother with the title, and select the Stacked Bar graph type. When the painter opens, save the DataWindow. On the General tab in the Painter, change the Legend to None (0). On the Axis tab, select the Category axis, then set the sort to Unsorted (0). Select the Value axis then set the sort to Unsorted (0). Select the Series axis and set the sort to Ascending (1). Save the DataWindow.
Create the Window
Create a window and place a DataWindow control, dw_1. Set the data object to your graph DataWindow. Place the following in the open event (or pfc_postopen if using PFC).
try
dw_1.setRedraw(FALSE)
// LOAD DATA HERE
dw_1.object.gr_1.title = 'Project PBL Pusher'
dw_1.object.gr_1.category.label = 'Phase'
dw_1.object.gr_1.values.label = 'Project-Days'
catch (runtimeerror re)
if isvalid(gnv_app.inv_debug) then gnv_app.inv_debug.of_message(re.text) // could do better
finally
dw_1.setRedraw(TRUE)
end try
You would load the data for your chart where the comment says // LOAD DATA HERE
Script the graphcreate Event
Add an new event to dw_1. Select pbm_dwngraphcreate for the Event ID. I like to name these events by removing the pbm_dwn prefix so I use graphcreate. Add the following code to the event.
string ls_series
long li_color
try
li_color=long(dw_1.object.gr_1.backcolor)
// note first series is a dummy with a small value (0.04 seems to work) to keep the line from being hidden
ls_series = dw_1.seriesName("gr_1", 2)
if 0 = len(ls_series) then return // maybe show error message
// will return -1 when you set color same as the graph's backcolor but it sets the color
dw_1.setSeriesStyle("gr_1", ls_series, BackGround!, li_color) // the box
dw_1.setSeriesStyle("gr_1", ls_series, ForeGround!, li_color) // the inside
catch (runtimeerror re)
if isvalid(gnv_app.inv_debug) then gnv_app.inv_debug.of_message(re.text) // could do better
end try
Data for the Graph
Load the data with the categories in the reverse order of what you want. For each Task, insert 3 rows and set the series to a, b, and c, respectively. For series a in each task, set a small value. I used 0.04. You may have to experiment. For series b in each task, set the number of days before start. For series c, set the number of days. Below is the data in the sample DataWindow.
Task Ser Days
---- --- ----
Test a 0.04
Test b 24
Test c 10
Develop a 0.04
Develop b 10
Develop c 14
Design a 0.04
Design b 0
Design c 10
Sample DataWindow
Below is the source for a sample DataWindow in export format. You should be able to import into any version >= PB 10. Copy the code and paste it into a file with an SRD extension, then import it.
HA$PBExportHeader$d_graph.srd
release 10;
datawindow(units=0 timer_interval=0 color=1073741824 processing=3 HTMLDW=no print.printername="" print.documentname="" print.orientation = 1 print.margin.left = 110 print.margin.right = 110 print.margin.top = 96 print.margin.bottom = 96 print.paper.source = 0 print.paper.size = 0 print.canusedefaultprinter=yes print.prompt=no print.buttons=no print.preview.buttons=no print.cliptext=no print.overrideprintjob=no print.collate=yes hidegrayline=no )
summary(height=0 color="536870912" )
footer(height=0 color="536870912" )
detail(height=0 color="536870912" )
table(column=(type=char(10) updatewhereclause=yes name=task dbname="task" )
column=(type=char(1) updatewhereclause=yes name=ser dbname="ser" )
column=(type=number updatewhereclause=yes name=days dbname="days" )
)
data("Test","a", 0.04,"Test","b", 24,"Test","c", 10,"Develop","a", 0.04,"Develop","b", 10,"Develop","c", 14,"Design","a", 0.04,"Design","b", 0,"Design","c", 10,)
graph(band=background height="1232" width="2798" graphtype="5" perspective="2" rotation="-20" color="0" backcolor="16777215" shadecolor="8355711" range= 0 border="3" overlappercent="0" spacing="100" plotnulldata="0" elevation="20" depth="100"x="0" y="0" height="1232" width="2798" name=gr_1 visible="1" sizetodisplay=1 series="ser" category="task" values="days" title="Title" title.dispattr.backcolor="553648127" title.dispattr.alignment="2" title.dispattr.autosize="1" title.dispattr.font.charset="0" title.dispattr.font.escapement="0" title.dispattr.font.face="Tahoma" title.dispattr.font.family="2" title.dispattr.font.height="0" title.dispattr.font.italic="0" title.dispattr.font.orientation="0" title.dispattr.font.pitch="2" title.dispattr.font.strikethrough="0" title.dispattr.font.underline="0" title.dispattr.font.weight="700" title.dispattr.format="[general]" title.dispattr.textcolor="0" title.dispattr.displayexpression="title" legend="0" legend.dispattr.backcolor="536870912" legend.dispattr.alignment="0" legend.dispattr.autosize="1" legend.dispattr.font.charset="0" legend.dispattr.font.escapement="0" legend.dispattr.font.face="Tahoma" legend.dispattr.font.family="2" legend.dispattr.font.height="0" legend.dispattr.font.italic="0" legend.dispattr.font.orientation="0" legend.dispattr.font.pitch="2" legend.dispattr.font.strikethrough="0" legend.dispattr.font.underline="0" legend.dispattr.font.weight="400" legend.dispattr.format="[general]" legend.dispattr.textcolor="553648127" legend.dispattr.displayexpression="' '"
series.autoscale="1"
series.displayeverynlabels="0" series.droplines="0" series.frame="1" series.label="(None)" series.majordivisions="0" series.majorgridline="0" series.majortic="3" series.maximumvalue="0" series.minimumvalue="0" series.minordivisions="0" series.minorgridline="0" series.minortic="1" series.originline="1" series.primaryline="1" series.roundto="0" series.roundtounit="0" series.scaletype="1" series.scalevalue="1" series.secondaryline="0" series.shadebackedge="0" series.dispattr.backcolor="536870912" series.dispattr.alignment="0" series.dispattr.autosize="1" series.dispattr.font.charset="0" series.dispattr.font.escapement="0" series.dispattr.font.face="Tahoma" series.dispattr.font.family="2" series.dispattr.font.height="0" series.dispattr.font.italic="0" series.dispattr.font.orientation="0" series.dispattr.font.pitch="2" series.dispattr.font.strikethrough="0" series.dispattr.font.underline="0" series.dispattr.font.weight="400" series.dispattr.format="[general]" series.dispattr.textcolor="0" series.dispattr.displayexpression="series" series.labeldispattr.backcolor="553648127" series.labeldispattr.alignment="2" series.labeldispattr.autosize="1" series.labeldispattr.font.charset="0" series.labeldispattr.font.escapement="0" series.labeldispattr.font.face="Tahoma" series.labeldispattr.font.family="2" series.labeldispattr.font.height="0" series.labeldispattr.font.italic="0" series.labeldispattr.font.orientation="0" series.labeldispattr.font.pitch="2" series.labeldispattr.font.strikethrough="0" series.labeldispattr.font.underline="0" series.labeldispattr.font.weight="400" series.labeldispattr.format="[general]" series.labeldispattr.textcolor="0" series.labeldispattr.displayexpression=" seriesaxislabel" series.sort="1"
category.autoscale="1"
category.displayeverynlabels="0" category.droplines="0" category.frame="1" category.label="(None)" category.majordivisions="0" category.majorgridline="0" category.majortic="3" category.maximumvalue="0" category.minimumvalue="0" category.minordivisions="0" category.minorgridline="0" category.minortic="1" category.originline="0" category.primaryline="1" category.roundto="0" category.roundtounit="0" category.scaletype="1" category.scalevalue="1" category.secondaryline="0" category.shadebackedge="1" category.dispattr.backcolor="556870912" category.dispattr.alignment="1" category.dispattr.autosize="1" category.dispattr.font.charset="0" category.dispattr.font.escapement="0" category.dispattr.font.face="Tahoma" category.dispattr.font.family="2" category.dispattr.font.height="0" category.dispattr.font.italic="0" category.dispattr.font.orientation="0" category.dispattr.font.pitch="2" category.dispattr.font.strikethrough="0" category.dispattr.font.underline="0" category.dispattr.font.weight="400" category.dispattr.format="[general]" category.dispattr.textcolor="0" category.dispattr.displayexpression="category" category.labeldispattr.backcolor="556870912" category.labeldispattr.alignment="2" category.labeldispattr.autosize="1" category.labeldispattr.font.charset="0" category.labeldispattr.font.escapement="900" category.labeldispattr.font.face="Tahoma" category.labeldispattr.font.family="2" category.labeldispattr.font.height="0" category.labeldispattr.font.italic="0" category.labeldispattr.font.orientation="900" category.labeldispattr.font.pitch="2" category.labeldispattr.font.strikethrough="0" category.labeldispattr.font.underline="0" category.labeldispattr.font.weight="400" category.labeldispattr.format="[general]" category.labeldispattr.textcolor="0" category.labeldispattr.displayexpression="categoryaxislabel" category.sort="0"
values.autoscale="1"
values.displayeverynlabels="0" values.droplines="0" values.frame="1" values.label="(None)" values.majordivisions="0" values.majorgridline="0" values.majortic="3" values.maximumvalue="1500" values.minimumvalue="0" values.minordivisions="0" values.minorgridline="0" values.minortic="1" values.originline="1" values.primaryline="1" values.roundto="0" values.roundtounit="0" values.scaletype="1" values.scalevalue="1" values.secondaryline="0" values.shadebackedge="0" values.dispattr.backcolor="556870912" values.dispattr.alignment="2" values.dispattr.autosize="1" values.dispattr.font.charset="0" values.dispattr.font.escapement="0" values.dispattr.font.face="Tahoma" values.dispattr.font.family="2" values.dispattr.font.height="0" values.dispattr.font.italic="0" values.dispattr.font.orientation="0" values.dispattr.font.pitch="2" values.dispattr.font.strikethrough="0" values.dispattr.font.underline="0" values.dispattr.font.weight="400" values.dispattr.format="[General]" values.dispattr.textcolor="0" values.dispattr.displayexpression="value" values.labeldispattr.backcolor="553648127" values.labeldispattr.alignment="2" values.labeldispattr.autosize="1" values.labeldispattr.font.charset="0" values.labeldispattr.font.escapement="0" values.labeldispattr.font.face="Tahoma" values.labeldispattr.font.family="2" values.labeldispattr.font.height="0" values.labeldispattr.font.italic="0" values.labeldispattr.font.orientation="0" values.labeldispattr.font.pitch="2" values.labeldispattr.font.strikethrough="0" values.labeldispattr.font.underline="0" values.labeldispattr.font.weight="700" values.labeldispattr.format="[general]" values.labeldispattr.textcolor="0" values.labeldispattr.displayexpression="valuesaxislabel" )
htmltable(border="1" )
htmlgen(clientevents="1" clientvalidation="1" clientcomputedfields="1" clientformatting="0" clientscriptable="0" generatejavascript="1" encodeselflinkargs="1" netscapelayers="0" )
xhtmlgen() cssgen(sessionspecific="0" )
xmlgen(inline="0" )
xsltgen()
jsgen()
export.xml(headgroups="1" includewhitespace="0" metadatatype=0 savemetadata=0 )
import.xml()
export.pdf(method=0 distill.custompostscript="0" xslfop.print="0" )
export.xhtml()

Resources