Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
ToxicFrog
Apr 26, 2008


^^^ You might want to look at this. Short form, you're using let improperly; it's meant to be used as 'let <definitions> in <expression>', for creating local bindings. If you're just defining globals, drop 'let' entirely:
code:
list = [1 .. 1000]
The "incorrect indentation" error it gives you is misleading; the underlying problem is that it sees "let name = value" and then hits another "let" while waiting for you to say "in" and gets confused. (I think fixing this may prompt indentation errors that are actual indentation errors, though).

I'm guessing that you did it this way because you have to use let when declaring functions in ghci; ghci, however, works somewhat differently from ghc, in ways that can be surprising.

Unrelated to your question, but as a matter of style, your use of a do block for what should be pure-functional code (and if-else for a short expression) drove me kind of bonkers until I rewrote it as:
code:
eval n | n `mod` 3 == 0 = True
       | n `mod` 5 == 0 = True
       | otherwise      = False
And then again as:
code:
eval n = (n `mod` 3 == 0) || (n `mod` 5 == 0)
I though there was a Haskell thread around here somewhere, but I can't find it. #haskell on freenode is usually pretty helpful if you run into something bigger than this thread, though.

Coasterphreak posted:

Okay, I've got a small question. I have a filename that seems to be a hash value, in hex. Is there any way I can "decrypt", if you will, the hash and recover the original filename?

No. Hashes are not encryption; they can't be reversed to get the original cleartext.

If it's a bad hashing algorithm you may be able to get a collision in less-than-fuckyou time, ie, some string that generates the same hash, but you have no guarantees it's the same one used originally (hint: it probably isn't).

Adbot
ADBOT LOVES YOU

ToxicFrog
Apr 26, 2008


shrughes posted:

You're blabbing irrelevantly because you like the sight of your own sentence structure. Not even md5 has a workable preimage attack.

This may come as a surprise, but md5 is not the only cryptographic hash in existence, although it or sha1 is probably the most common. md4 has had a feasable preimage attack for years, and back in 2004 Kelsey & Schneier were doing some interesting work on conducting preimage attacks on a certain class of n-bit hashes (to which sha1 belongs) in much less than 2^n time. (It's still not fast enough to be useful in general, though).

Yeah, if the hash is md5 or sha1 - and it's probably one of those two - you aren't going to be able to do a first-preimage attack yet. But blathering on about how preimage attacks are impossible is patent nonsense.

ToxicFrog
Apr 26, 2008


BSTs must be sorted (ordered) for them to be useful as a search tree. However, they don't need to be balanced.

The trees given as examples are ordered (an in-order traversal of them will give 3-4-5 and 5-6-7-8 respectively), but not balanced.

ToxicFrog
Apr 26, 2008


Rocko Bonaparte posted:

I'll try to ask this question I crammed into the end of an earlier post again: does anybody here understand FLTK layout and how resizing affects components? I see something about a resizable bit that affects thing, but that only one component in a group can do it. So how does one cause, say, two text fields to both resize when a window is made larger? Does each field need a group to itself?

Well, according to the first google hit for "fltk resize":

Marc R.J. Brevoort posted:

- to make things more predictable, it helps to fill groups with
widgets only in one direction: either horizontally or vertically.
(this also helps explain the following hints).

- If you need to fill groups both horizontally and vertically,
fill a group WITH GROUPS in one direction, then those 'sub'groups
in the other direction.

- In a group, at most one widget can be set to "resizable".
Attempts to setting several widgets to 'resizable' causes
only the last one to be marked resizable.

- Setting a widget to "resizable" means that that widget can be
resized BOTH horizontally and vertically, not that it is the
only resizable widget in the group.

- all other widgets in the group may resize along proportionally to
the size of the group, but only in one direction (if the group
is populated horizontally, 'nonresizable' widgets only resize
vertically, only the 'resizable' widget resizes in both directions.

- if a group is only resizable in one direction, only the resizable
widget will resize, all other widgets will stay the way they are.

In short, the expectation is that your layout will consist of nested horizontal and vertical groups of widgets, each one with one widget marked resizeable. If you widen a group (increasing the width of a vertical group or the height of a horizontal one), all of the widgets in it will expand along that axis; if you lengthen it (increasing the width of a horizontal group or the height of a vertical one), only the resizeable widget will expand.

code:
+--+ +---+ +--+
|  | | R | |  +
+--+ +---+ +--+

Widen:
+--+ +---+ +--+
|  | |   | |  +
|  | | R | |  +
|  | |   | |  +
+--+ +---+ +--+

Lengthen:
+--+ +-------+ +--+
|  | |   R   | |  +
+--+ +-------+ +--+

ToxicFrog
Apr 26, 2008


Taz posted:

I'm getting "Bad substitution" for the first one and the sed command just hangs like it did before. I suspect that something else is going on to make sed do that but I can't for the life of me work out what it is. I purposefully chose # as the delimiter by the way, as my variables are paths and contain the "/" so commonly used.

Sed, by default, reads from stdin and writes to stdout. The "hanging" is likely just it waiting for you to provide input.

As I understand it, you want to strip all $b from $a and store results in $c? That is to say, if a="foo bar baz" and b=" b", c should be "fooaraz"?

Try:
code:
c=`echo "$a" | sed "s#$b##g"`
E: beaten like a pinata full of Perl developers.

ToxicFrog fucked around with this message at 18:23 on Apr 29, 2010

ToxicFrog
Apr 26, 2008


Seconding the Lua recommendation. The interface is callable from C++, and there are also a bunch of C++ native binding libraries/tools - see here under "C++".

It has a few other properties that make it attractive for embedding, too - primarily that it's small, it's easy to learn, and it's MIT licensed.


If for some reason Lua doesn't fit your needs, I've also seen Python and Guile (a Scheme implementation) used in a few places, but don't know much about either.

ToxicFrog
Apr 26, 2008


Peao posted:

I know Subversion is easy to set up

:pwn:

Compared to what?

More seriously, you'll probably get more help in the version control megathread. Be prepared for lots of people telling you (correctly) to use git/bzr/hg instead, though.

ToxicFrog
Apr 26, 2008


echo and printf are both shell builtins, it doesn't need to fork for that.

Also, you're looking at around 102GB of data here, it's going to take a while no matter what you use.

ToxicFrog
Apr 26, 2008


The Lua-Users Wiki has a list of IDEs and other Lua-aware development environments. There are some debuggers listed here; you may want to just browse the whole LuaAddons section.

Personally, I use JEdit. It's not an IDE, but it has a decent lua mode and integrated shell, and is quite customizeable.

ToxicFrog
Apr 26, 2008


The Gate of Nanna posted:

I know nothing about compiling things on Windows, but I do have the full source code to a small C GUI program which needs some headers generally found in things like Visual Studio. Is there any quick and painless ways to compile something for Windows without having to shell out for Visual Studio?

If you're used to a *nix development environment, MinGW provides a make/gcc/bash build environment with the w32api headers and libraries preinstalled. If you're actually on linux, this makefile will download and build a linux-host, windows-target gcc4 cross compiler, again with the w32api headers and libraries (grab the development version or you'll have to download some of the parts yourself, mingw changed their download URLs since the last release). In either case you can add more windows libs just by putting the headers in include/ and the .dll/.a/.lib files in lib/.

I'm given to understand that there's also a free version of Visual Studio (VS Express?) which you could use if you don't feel like using gcc, but not having used it myself I can't tell you anything about it.

ToxicFrog
Apr 26, 2008


Why bother with those?

code:
find . -depth 1 -type f -exec mktorrent -p -a [url]http://foo.com/[/url] {} ';'

ToxicFrog
Apr 26, 2008


:raise: I use Glade constantly and love it. It's spoiled me on other GUI frameworks because seriously, gently caress laying out all of my widgets using code, I have better things to do, like writing the actual program logic.

ToxicFrog
Apr 26, 2008


Doublequotes.

code:
$ file="a file with spaces"; echo -n "unquoted: "; ls $file; echo -n "quoted: "; ls "$file"
unquoted: ls: cannot access a: No such file or directory
ls: cannot access file: No such file or directory
ls: cannot access with: No such file or directory
ls: cannot access spaces: No such file or directory
quoted: a file with spaces

ToxicFrog
Apr 26, 2008


I can't say about the others, but the Python idiom for efficient string concatenation is to use a list comprehension, or failing that, build a list of strings and then use 'join' on it. Lua is similar except the equivalent function is named 'concat'.

If you're using naive concatenation both suffer from the same performance concerns, it's just that there are other ways to get around that than a StringBuilder.

ToxicFrog
Apr 26, 2008


^^ Yeah, sorry, I didn't set precedence correctly.

(use a list comprehension or manually construct a list of strings) and then use join on it.

ToxicFrog
Apr 26, 2008


As it happens, I have both of those distros installed and neither includes idle with python. They do, however, have it in the repos, and you should probably have tried searching for it in there first. :)

Specifically, in Ubuntu/Mint it's called "idle3" for the default version and "idle-python3.0" for the Python 3 version; in SUSE it's "python-idle" and "python3-idle".

Incidentally, the way you develop more sophisticated stuff in general is by writing it in a seperate editor (ideally one with some language awareness, like jedit) and testing it in the REPL; trying to write everything in the REPL and then saving it when it works gets unwieldy fast. (nb. I have not used IDLE but this seems to be what you're talking about concerning "writing a simple program in Terminal")

ToxicFrog
Apr 26, 2008


ScaerCroe posted:

Two questions: What is the REPL and how do I test any program in it? What are the repos?

REPL: Read-Evaluate-Print Loop. Type 'python' at the command line and this is what you get - as you enter code, it reads what you entered, evaluates it and prints the results. It's good for trying out small snippets of code on their own or using as a desk calculator; it can also be used for testing larger programs by loading them from disk and then calling/examining parts of them.

Repo: short for "package repository" or "software repository". Most linux distros have one (or several), along with a program (the package manager) that interacts with them and can automatically download, install, update, and remove any piece of software in the repos. This should generally be the first place you check when installing software in linux; sometimes what you need isn't in the repos (either absent entirely, or you need a specific version not available), but most of the time, it is.

Ubuntu has the graphical package manager 'synaptic' and command line 'apt-get' and 'apt-cache'; SUSE has graphical 'yast2' and command line 'zypper'.

For example, in SUSE, here's how I might go about installing python 2.x and IDLE from the command line:

code:
$ sudo zypper refresh      # get latest package lists
$ zypper search -s python  # search for packages with 'python' in the name
$ zypper search -s idle    # ditto for 'idle'
$ sudo zypper install python python-idle
...at which point zypper automatically downloads and installs python and idle.

The Ubuntu version is similar; it uses 'apt-get update' instead of 'zypper refresh', 'apt-cache search' instead of 'zypper search -s', and 'apt-get install' instead of 'zypper install'. And on either OS, using the graphical interface is just a matter of starting it from the menu, entering 'python' or 'idle' into the search box and choosing it from the list that results.

ToxicFrog
Apr 26, 2008


Ledneh posted:

Not strictly a programming question, and I know the subject of text editors can be... touchy, so I apologize in advance if I start a Holy War here.

First of all, take all of this with a grain of salt because I've only used emacs for a few months and vi for a few weeks.

NEdit is fantastic and if it supported UTF-8 I would probably still be using it.

JEdit is like a modern NEdit with more features and a plugin architecture and a lovely XML format for syntax hilighting rules. However, it's not rocking' the classic Motif widget set. :( It can do most of the cool stuff emacs and vi can, but is still more a "language-aware editor" than an IDE - although plugins provide things like project management, integrated debugging, and whatnot.

emacs and vi can be used as IDEs, but you will have to contend with:
- both of them have a vicious learning curve
- VI's cool features are hidden behind a UI written by, and for, aliens
- emacs's cool features are provided by undocumented and poorly maintained third-party elisp scripts which can and will randomly break just when you need them

So, I would say: it can be worth it, but you should also investigate whether more friendly editors like NEdit or JEdit do (or can be made to do) what you need.

Now I wait for all of the emacs/vi users to explain why I'm wrong.

ToxicFrog
Apr 26, 2008


I can't remember the last editor I used that doesn't have etags support; nedit jedit, emacs and vi all support it.

NEdit-specific stuff: nedit won't automatically generate the tag file for you (although there may be a script for that). Once it's generated, though (using ctags, or etags, or 'make tags', or whatever), you can load it by hand with File->Load Tags File. The tag file, if loaded, will also be used for calltips.

If you want it to autoload tags, you can either use 'nedit -tags <tagfile>' to launch it, or set the XResource nedit.tagFile to an (absolute or relative) path.

Bear in mind that etags is not the same as a full IDE's intelligent parser; in particular:
- the tags won't auto-update as you change the code, you need to re-run etags to update the tag file as you add/remove/change functions.
- if you have lots of functions with the same name in different scopes, it can't always figure out which one you're referring to and will just list them all and ask you to choose one

vvv :airquote:

ToxicFrog fucked around with this message at 21:22 on Sep 15, 2010

ToxicFrog
Apr 26, 2008


1280x800 crew checking in.

Not windows, though, so I just use 3x7 virtual desktops and Guake, with JEdit for editing.

ToxicFrog
Apr 26, 2008


There's two important questions you need to answer first:
- what the hell is a war file?
- why are you creating backups by copying the folder rather than using a version control system (like git) or backup program (like duplicity)?

ToxicFrog
Apr 26, 2008


zarg posted:

Yes! I figured it was something like that. I tried replacing the "=" with "define," since earlier the tutorial mentioned that it was really just shorthand for define anyway. Of course, now that I think about it "print" is exactly what I wanted.

'define' isn't a lua keyword; what it means by that is that something like 'x = 2' can be read as 'define x as 2'.

The leading '=' in the interactive mode is entirely different (and specific to the command line interpreter, not part of the lua language); it gets translated into 'return ', and in fact if you start the command line interpreter, type something like '= 2', and then hit uparrow to repeat the command, it'll list it as 'return 2'. And the interactive interpreter feeds anything you return to print() automatically.

quote:

You guys are the best guys :) Now back to making a horrible mess of things until my head hurts... learning this from the ground-up is tough.

Feel free to pop into #lua on Freenode, too; we're usually pretty laid-back. :)

ToxicFrog
Apr 26, 2008


I don't know of any program specifically for this purpose, but you should be able to whack the CFG into any parser generator or parser combinator of your choice, then feed the string to it and see if it accepts.

ToxicFrog
Apr 26, 2008


ufarn posted:

After I run some git commands, I can't get back to my prompt.

I've tried Ctrl+C+C, but that won't do it. What's the command in git (Windows Git Bash)?

What commands? Are you sure you aren't in an editor that it's waiting for you to exit or something?

Assuming you're not...

If you're in the msys shell, ctrl-C is interrupt and ctrl-D is EOF. If neither of those work ctrl-Z should background the current process and give you the shell back. If nothing produces any output it's possible you've stopped the terminal itself by pressing ctrl-S at some point - try ctrl-Q to start it again.

If you're in windows cmd.exe and are just using git from there, ctrl-C is still interrupt and ctrl-Z <enter> is EOF and I have no suggestions beyond that.

ToxicFrog
Apr 26, 2008


BrianBoitano posted:

automatic number recognition

Personally, my approach would be something like:
- use imagemagick to automatically crop out the section of the image containing the score (which is always the same part) and make it black-on-white
- use gocr to read the numbers (and discard "," and "ft"), training it as needed

However, this requires gocr and imagemagick, which - as you're on windows - you may not have. There are windows versions of both, though.

ToxicFrog
Apr 26, 2008


The reason I suggested gocr is that it has a fairly simple and effective learning mode. Do something like:

code:
mkdir font
gocr -d 0 -a 99 -f ASCII -m $((256+128+2)) -p font/
This causes it to start up "blank", with no idea what patterns map to what letters. It'll try to break the text into letters, then display each one and ask you what it means, and you can type in anything (including no text or multiple characters). It'll then save the database it builds in the font/ directory for future runs. In this way, provided you're scanning text with a very consistent font (which this is), you can very quickly teach it.

This won't work very well with handwriting - too much variation - but I've used it to automatically transcribe text from programs and video games with great success.

You will need some preprocessing with imagemagick; it expects black-on-white, PNM format - try experimenting with the -threshold command. And use the PNGs as input; compression artifacts from JPEG may confuse it.

EDIT: my automatic transcription command for Septerra Core screenshots:

code:
function ocr() {
    convert $ss -crop 640x96+0+384 -negate -level 60%,61% pnm:/tmp/ocr.pnm
    gocr -d 0 -a 99 -f ASCII -m $((256+128+2)) -p ocr/ /tmp/ocr.pnm | tee -a transcription.txt
}

ToxicFrog fucked around with this message at 21:42 on Nov 25, 2010

ToxicFrog
Apr 26, 2008


ufarn posted:

I want to use git commit with the -v option, but, embarrassingly, I don't know how to save and commit the file, after I've entered some text to describe the changes. Do I need to use a keyboard shortcut (Windows git bash), or what do I do to send it along?

Depends on what editor it's using. I don't recall which one wingit uses by default.

If it's vi, try hitting escape a few times and then typing :wq<enter>.
If it's pico or nano, try ctrl-O <enter> ctrl-X.

Alternately, configure it to use an editor that you know how to use - for example, git config --global core.editor nano

ToxicFrog
Apr 26, 2008


ufarn posted:

No dice. It's the default terminal-esque client you get when you install the Windows git package.

The bottom line says ~\repo\.git\COMMIT_EDITMSG[+][RO] [unix], if that says anything.

What's "no dice"? The key sequences I suggested didn't work? 'git config' didn't? Neither? Changing core.editor should definitely work in msysgit, I've done it before.

And that's the editor status line (telling you what file you're editing, what mode it has, what line ending convention it uses, etc), but I don't recognize which editor uses that format.

ToxicFrog
Apr 26, 2008


ufarn posted:

The shortcuts didn't seem to work. I like using the regular git bash, since it works fine aside from the whole not being able to commit thing.

...what shortcuts? You haven't said anything about shortcuts - I thought we were talking about editing commit messages when you're making a commit from the command line?

Please try the stuff I suggested, both the key sequences and changing core.editor to something you're more comfortable with. (If you aren't familiar with any text-mode editors, try 'nano' or 'pico', they're pretty friendly.)

ToxicFrog
Apr 26, 2008


I suspect that if you revise the algorithm to "if the start time is earlier than the latest recorded end time" rather than just the end time of the previous event, it'll work (and still be O(nlogn)), but I don't have a proof.

ToxicFrog
Apr 26, 2008


Gothmog1065 posted:

I'll pop over to the python thread and continue asking there.

No need, this isn't really a Python-specific thing.

What you're looking at there is python's REPL - Read-Evaluate-Print Loop. Most interpreted languages have one; it's a program that reads code as you enter it, evaluates the code and prints the result. It's useful for testing, experimenting with small pieces of code, and as a desk calculator.

To do what you're after, ignore the REPL for now. Just use IDLE's editor (file->new should get you a new editor window if you don't have one) to write a program normally. Once that's done you can run it in IDLE using the menu, or from the command line with python filename.py.

ToxicFrog
Apr 26, 2008


Three possible solutions in descending order of preference:

Use rsync with the --rsh option (note: requires public-key authentication working between 'gateway' and 'remote'):
code:
rsync -avvPh --rsh='ssh user@gateway ssh' user@remote:/path/to/files /local/path/to/files
Skip scp entirely and just pipe a tarball over the connection:
code:
ssh user@gateway ssh user@remote tar c -C /path/to/files . | tar xv
Use SSH port forwarding:
code:
ssh -L2222:remote:22 user@gateway
scp -P 2222 user@localhost:/path/to/files /local/path/to/files
I'd also suggest using rsync in favour of scp in general; it's much more capable.

ToxicFrog
Apr 26, 2008


Jam2 posted:

It is really just about writing a lot of programs.

Pretty much this.

Which tools you use can make it easier or harder, and there's important theory to be learned as well, but fundamentally, the way you become a good programmer is by programming.

ToxicFrog
Apr 26, 2008


^^ Yeah, that was in the coding horrors thread. I wouldn't be surprised if the discussion has happened in this thread as well, though.

C is good to know and makes a good second language, but it has enough up-front complexity that teaching it as a first language means that learning the specifics of the language gets in the way of learning the concepts of programming.

ToxicFrog
Apr 26, 2008


Pucklynn posted:

I'm learning to program as a hobby, and I spend seven hours a day parked in front of a computer at work. My work really doesn't require much, so I spend a lot of that time here on the forums. I don't have admin access to the computers, so I can't install Ruby or Python on them, so no matter how much time I spend reading about it, I can't get any actual programming practice during that time.

My question is, are there any ways I can practice programming over the internet? IE, set up a server on my home computer or something and upload files to it? I could just write stuff all day and test it when I get home, but I feel like I wouldn't really get there with that approach.

At the very least, is there a web-based version of IRB (interactive Ruby something something) where I could test my code?

Others have already linked you to online interpreters. Other approaches you can use:

- Portable Cygwin does not require admin rights to run, and is a complete linuxy development environment, including python, ruby, lua, etc interpreters and C/C++ compilers. Requires some comfort with the command line.
- You can also set up a server at home and use a portable version of PuTTY or NXClient to talk to it from work, either simple uploading/downloading of files, or doing actual development remotely.

ToxicFrog
Apr 26, 2008


The regex is a straightforward translation of your description.

[any upper character or digit 0-9] = [A-Z0-9]
[dash] = -

So the regex is [A-Z0-9]-[A-Z0-9]

As for the actual problem - given a string and a regex, return a list of all substrings matching that regex - there's bound to be something in PHP's string library that does that, right? (I don't know PHP.)

Quarantini posted:

edit: I tried ([A-Za-z0-9-]+) with some online regex maker but it only seems to match the 1st valid needle in a haystack and not any of the others, i want to be able to feed the expression a bunch of data containing the above strings and be able to have it returned into a cleaned array

The problem with that is not the regex (although it is wrong) but presumably the fact that you're searching using a function that returns the first match rather than all matches.

ToxicFrog
Apr 26, 2008


^^ Looks like it should work to me.

Of course, this means that while foo.Test(3) will work, and DoSomethingFourTimes(foo.Test) will work, foo:Test(3) will not (which can be an interesting surprise violation for other Lua coders looking at your program).

I'm pretty sure that there's an unofficial patch on the lua-users wiki that makes foo:bar syntactic sugar for function(...) return foo:bar(...) end, which you could use if you don't mind breaking compatibility with "stock" lua.

Alternately, you can wrap it in something more explicit:

code:
function Foo:close(method_name)
  return function(...) return self[method_name](self, ...) end
end

-- ... --

DoSomethingFourTimes(foo:close "Test")

ToxicFrog
Apr 26, 2008


Hammerite posted:

This seems to betray a failure to truly treat functions as ordinary values just like any other type of values. If they were really so, you should have to write

Python has first-class functions but does not permit the definition of anonymous functions (except via the restricted keyword lambda).

code:
>>> def foo(x, y):
...     return x+y
... 
>>> bar = foo
>>> bar
<function foo at 0x1f57848>
>>> bar(4,5)
9
Even in languages which do have full anonymous functions, such as Lua, it's not uncommon to have syntactic sugar for function definition; these two statements are both legal and equivalent:

code:
function foo(x, y)
    return x+y
end

foo = function(x,y)
    return x+y
end
E: holy poo poo beaten so hard

ToxicFrog
Apr 26, 2008


haveblue posted:

In other languages/environments this can be called a semaphore.

Semaphores are different (perhaps you're thinking of monitors, which are closely related and sometimes used synonymously?) The main distinction is that posting a semaphore will always increment it, and waiting it will block only if has a value <= 0; in contrast, signaling or broadcasting a CV is a no-op if no-one is waiting on it, and waiting will always block.

That said, there's a lot of situations where semaphores and condition variables can be used pretty much interchangeably, although often one or the other will result in clearer code or greater efficiency.

ToxicFrog fucked around with this message at 16:22 on Aug 18, 2011

Adbot
ADBOT LOVES YOU

ToxicFrog
Apr 26, 2008


In addition to the aforementioned Beagleboards, there's Gumstix and Arduino.

Carthag posted:

Well a small stolen computer will cost you about fifty bucks. If you pay more, you got robbed. Also, are you serious?

He's saying that there's a high risk of the finished project being stolen or damaged, so he'd rather not spend a lot of money building it.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply