How to use File.walk in kotlin - kotlin

I’m trying to walk into folder using file.walk this way:
File.walk(FileWalkDirection.BOTTOM_UP).forEach()
The documentation says:
enum entry BOTTOM_UP defined in kotlin.io.FileWalkDirection
Depth-first search, directory is visited AFTER its files
Enum constant ordinal: 1
If I use FileWalkDirection.BOTTOM_UP it’s my print walk
emergency-support/digital/beginner/.category.yml
emergency-support/digital/.category.yml
emergency-support/physical/beginner/.category.yml
emergency-support/physical/.category.yml
emergency-support/.category.yml
I want to walk for this result:
emergency-support/.category.yml
emergency-support/physical/.category.yml
emergency-support/physical/beginner/.category.yml
emergency-support/digital/.category.yml
emergency-support/digital/beginner/.category.yml
How can I walk visiting files before directory?

I have to admit that I did not totally undersand your question.
If all you want is to print the files first and than the directories and you don't have any other concern you can use the 'sortedBy' function:
File
.walk(FileWalkDirection.BOTTOM_UP)
.sortedBy { it.isDirectory }
.forEach { println(it) }

Related

Terraform: How Do I Setup a Resource Based on Configuration

So here is what I want as a module in Pseudo Code:
IF UseCustom, Create AWS Launch Config With One Custom EBS Device and One Generic EBS Device
ELSE Create AWS Launch Config With One Generic EBS Device
I am aware that I can use the 'count' function within a resource to decide whether it is created or not... So I currently have:
resource aws_launch_configuration "basic_launch_config" {
count = var.boolean ? 0 : 1
blah
}
resource aws_launch_configuration "custom_launch_config" {
count = var.boolean ? 1 : 0
blah
blah
}
Which is great, now it creates the right Launch configuration based on my 'boolean' variable... But in order to then create the AutoScalingGroup using that Launch Configuration, I need the Launch Configuration Name. I know what you're thinking, just output it and grab it, you moron! Well of course I'm outputting it:
output "name" {
description = "The Name of the Default Launch Configuration"
value = aws_launch_configuration.basic_launch_config.*.name
}
output "name" {
description = "The Name of the Custom Launch Configuration"
value = aws_launch_configuration.custom_launch_config.*.name
}
But how the heck do I know from the higher area that I'm calling the module that creates the Launch Configuration and Then the Auto Scaling Group which output to use for passing into the ASG???
Is there a different way to grab the value I want that I'm overlooking? I'm new to Terraform and the whole no real conditional thing is really throwing me for a loop.
Terraform: How to conditionally assign an EBS volume to an ECS Cluster
This seemed to be the cleanest way I could find, using a ternary operator:
output "name {
description = "The Name of the Launch Configuration"
value = "${(var.booleanVar) == 0 ? aws_launch_configuration.default_launch_config.*.name : aws_launch_configuration.custom_launch_config.*.name}
}
Let me know if there is a better way!
You can use the same variable you used to decide which resource to enable to select the appropriate result:
output "name" {
value = var.boolean ? aws_launch_configuration.custom_launch_config[0].name : aws_launch_configuration.basic_launch_config[0].name
}
Another option, which is a little more terse but arguably also a little less clear to a future reader, is to exploit the fact that you will always have one list of zero elements and one list with one elements, like this:
output "name" {
value = concat(
aws_launch_configuration.basic_launch_config[*].name,
aws_launch_configuration.custom_launch_config[*].name,
)[0]
}
Concatenating these two lists will always produce a single-item list due to how the count expressions are written, and so we can use [0] to take that single item and return it.

Trouble importing LESS files among different domains

Warning: The explanation may be a bit long. In case you are in a hurry, just skip directly to the end of the question, where I summarise what I'm looking for based in my problem.
Here is the problem: I have to load a LESS file (from domain A) from another LESS file (from domain B), and build them on real time with LESS.js. Until then, no harm; the instructions in the start of the official website work out of the box.
<link rel="stylesheet/less" type="text/css" href="styles.less" />
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/3.9.0/less.min.js" ></script>
However, there are other LESS files inside B (let's say module1/less, module2/less, and so on), and A should contain the #imports to those files. Also, there are multiple other domains similar to B (C, D, E...). That's where the problem starts. I couldn't find a proper way to do that, considering that I can't update C, D and E (other people need to do it, and for bureaucracy reasons they will only be able to do it after me), only A and B, so A needs to be compatible with the older version of C, D and E (in case they need any change).
When doing an #import inside an imported LESS file, its relative path is according to that same LESS file path, but since that LESS file may be loaded from B, C, D or E, I can't provide an absolute path out of the box.
What I tried (1): I surely need to find a way to provide the domain name from B to A. Firstly, I tried by adding something like that before the less.min.js line in the B domain HTML file:
<script>
less = {plugins: [{
install: function(less, pluginManager, functions) {
functions.add('getRootLessFolder', function() {
var getDomain = function() {
return window.location.protocol + "//" + window.location.host + "/";
}
return getDomain() + "less/";
});
}
}]}
</script>
And then adding that to the start of B's main LESS file:
#root-less-folder: getRootLessFolder();
So I could update the #imports in A to be like that:
#import "#{root-less-folder}module1/less";
That approach worked... until I tried using it with the older version of B, before making the changes mentioned above. In that way, LESS claims that #root-less-folder is undefined, even if I add (optional) to the #import.
What I tried (2): I also tried to use the paths property in server B, like that:
var getDomain = function() {
return window.location.protocol + "//" + window.location.host + "/";
}
var lessFolder = getDomain() + "less/";
less = {paths:[lessFolder]};
Because according to the documentation:
lessc --include-path=PATH1;PATH2 { paths: ['PATH1', 'PATH2'] }
If the file in an #import rule does not exist at that exact location, Less will look for it at the location(s) passed to this option. You might use this for instance to specify a path to a library which you want to be referenced simply and relatively in the Less files.
So I figured I could use it to make less find the LESS files automatically by just using the line below in A:
#import (optional) "module1/less";
So it wouldn't find module1/less in server A, but would find it in server B because of the paths property. Although, it doesn't seem to try to find module1/less in B. Instead, the Chrome Console spills the 404 error from server A, and the contents of module1/less from B are not present in the produced CSS style (no Console error either), like if it don't even tried.
What I need: I need a way to make method 1 or 2 work under those conditions, or even a method 3.
Being able to populate a LESS variable (if it is not populated only) would solve method 1;
Figuring out how LESS's paths is supposed to work may help using method 2;
Although, maybe you have another suggestion to that problem, which could work out as well.
I've managed to solve my problem. In case anyone else is having this trouble, I will describe what I did: apparently, while you can't reference variables that weren't defined, you can reference plugins that were not defined (in those cases, they are identified as strings).
So I added that before the less.min.js line in the B domain HTML file:
<script>
less = {plugins: [{
install: function(less, pluginManager, functions) {
functions.add('getRootLessFolder', function() {
var getDomain = function() {
return window.location.protocol + "//" + window.location.host + "/";
}
return getDomain() + "less/";
});
}
}]}
</script>
And updated the #imports in A to be like that:
#root-less-folder: getRootLessFolder();
#import (optional) "#{root-less-folder}module1/less";
So when getRootLessFolder is defined, the path is based in its returned value, and when it isn't, the path is "getRootLessFolder()module1/less", which will return a 404, but since it's an optional #import, that won't be a problem.
So if server B is updated, the change in server A is going to work. In case server B is not updated, the change is server A won't break it either.

Labels and "Control flow commands not allowed in toplevel" (Possible LTA error message)

This code:
FOO:
"Hey".say;
for <1 2> {
say "1";
last FOO
}
Prints
Hey
1
Control flow commands not allowed in toplevel
The last error message is eliminated if "Hey".say is taken off; this probably means that what the error is actually saying is that non control flow commands are not allowed right behind a label. But the documentation (which needs to be improved cites loops as an "example", and the grammar indicates it should be in front of a statement. So the question is: can it be used for if statements, or just loops?
The error is different if you have this code inside another scope:
{
FOO:
"Hey".say;
for <a b> {
.say;
last FOO
}
}
# Hey
# a
# labeled last without loop construct
which is also LTA in that it doesn't mention the name of the label.
But in short: Perl 6 doesn't currently have a goto. Currently, labels are only usable as a way to specify which loop construct you want to next, redo to or last out of. By putting a statement between the label and the loop construct, you're effectively using it as a goto, which is still Not Yet Implemented.
But indeed a ticket about the LTAness of both errors, seems in place for me.
Also, using the FIRST phaser as an alternative, seems to have the same issue:
FOO:
for <a b> {
FIRST "Hey".say;
.say;
last FOO;
}
# Hey
# a
# labeled last without loop construct
But runs fine without the specific label:
FOO:
for <a b> {
FIRST "Hey".say;
.say;
last;
}
# Hey
# a
The latter issue most definitely is worth a rakudo issue: added as https://github.com/rakudo/rakudo/issues/2699 .

Many inputs to one output, access wildcards in input files

Apologies if this is a straightforward question, I couldn't find anything in the docs.
currently my workflow looks something like this. I'm taking a number of input files created as part of this workflow, and summarizing them.
Is there a way to avoid this manual regex step to parse the wildcards in the filenames?
I thought about an "expand" of cross_ids and config["chromosomes"], but unsure to guarantee conistent order.
rule report:
output:
table="output/mendel_errors.txt"
input:
files=expand("output/{chrom}/{cross}.in", chrom=config["chromosomes"], cross=cross_ids)
params:
req="h_vmem=4G",
run:
df = pd.DataFrame(index=range(len(input.files), columns=["stat", "chrom", "cross"])
for i, fn in enumerate(input.files):
# open fn / make calculations etc // stat =
# manual regex of filename to get chrom cross // chrom, cross =
df.loc[i] = stat, chrom, choss
This seems a bit awkward when this information must be in the environment somewhere.
(via Johannes Köster on the google group)
To answer your question:
Expand uses functools.product from the standard library. Hence, you could write
from functools import product
product(config["chromosomes"], cross_ids)

Passing options to JS function with Amber

I'm trying to write the equivalent of:
$( "#draggable" ).draggable({ axis: "y" });
in Amber smalltalk.
My guess was: '#draggable' asJQuery draggable: {'axis' -> 'y'} but that's not it.
Not working on vanilla 0.9.1, but working on master at least last two months ago is:
'#draggable' asJQuery draggable: #{'axis' -> 'y'}
and afaict this is the recommended way.
P.S.: #{ 'key' -> val. 'key2' -> val } is the syntax for inline creation of HashedCollection, which is implemented (from the aforementioned two-month ago fix) so that only public (aka enumerable) properties are the HashedCollection keys. Before the fix also all the methods were enumerable, which prevented to use it naturally in place of JavaScript objects.
herby's excellent answer points out the recommended way to do it. Appearently, there is now Dictionary-literal support (see his comment below). Didn't know that :-)
Old / Alternate way of doing it
For historical reasons, or for users not using the latest master version, this is an alternative way to do it:
options := <{}>.
options at: #axis put: 'y'.
'#draggable' asJQuery draggable: options.
The first line constructs an empty JavaScript object (it's really an JSObjectProxy).
The second line puts the string "y" in the slot "axis". It has the same effect as:
options.axis = "y"; // JavaScript
Lastly, it is invoked, and passed as a parameter.
Array-literals vs Dictionaries
What you were doing didn't work because in modern Smalltalk (Pharo/Squeak/Amber) the curly-brackets are used for array-literals, not as an object-literal as they are used in JavaScript.
If you evaluate (print-it) this in a Workspace:
{ #elelemt1. #element2. #element3 }.
You get:
a Array (#elelemt1 #element2 #element3)
As a result, if you have something that looks like a JavaScript object-literal in reality it is an Array of Association(s). To illustrate I give you this snippet, with the results of print-it on the right:
arrayLookingLikeObject := { #key1 -> #value1. #key2 -> #value2. #key3 -> #value3}.
arrayLookingLikeObject class. "==> Array"
arrayLookingLikeObject first class. "==> Association"
arrayLookingLikeObject "==> a Array (a Association a Association a Association)"
I wrote about it here:
http://smalltalkreloaded.blogspot.co.at/2012/04/javascript-objects-back-and-forth.html