Planeta Blogów WMI UAM

November 18, 2024

Borkowski Marcin

2024-11-18 Discovering functions and variables in Elisp files

Sometimes I have an Elisp file which I suspect contains some useful functions. Even if the file is well-documented (for example, it belongs to Emacs itself), that does not mean that every function in it is described in the manual. What I need in such a case is a list of functions and variables (possibly also macros) defined in this file.

My usual solution was to isearch for defun (or (defun, or (def, etc.) and just skim the file, pressing C-s repeatedly. (Sometimes I look for the string (interactive, too, for obvious reasons.) It occurred to me recently (pun intended;-)) that I could use Occur for that. Typing M-s o, then (def and RET gives me a list of all defun​s, defvar​s, defcustom​s, defmacro​s etc. What’s even better, pressing n and p in the Occur buffer immediately moves point to the corresponding place in the searched buffer, so that I can easily see the docstrings of the things I found!

I can do better, though. This simplistic approach does not take into account the fact that some functions and variables are “internal” or “private” and are explicitly not the part of the “official” API of the package in question. These “private” entities are easily recognized, since the convention is to use a double dash in their names.

At first, I wanted to write some custom Elisp to generate the occur buffer first, then remove the double-dashed lines from it, or maybe don’t put them there at all, although that would probably require me to construct that buffer completely by hand, not relying on the occur command. (Of course, you can’t construct a regular expression matching “every line that starts with (def, but excluding lines containing --”, so it seemed that a bit of Elisp is necessary here.) Don’t get me wrong – I have nothing against writing Elisp;-) – but why work if you don’t have to? I had a bright idea and wrote this regex instead:

^(def[^ ]+ -?\(?:[^ -]+-?\)+\_>

Let’s analyze it. It matches first the string (def at the beginning of line, followed by one on more non-space characters and then a space – this is just any (defun, (defvar etc. Then the magic happens. The regex in the shy group matches one or more occurrences of one or more characters other than a space or a dash, followed by an optional dash. This means that any valid Elisp symbol except ones that contain double dashes should match it. (Well, a valid symbol could also begin with a dash – that’s why there is -? before the group. Also, there are things which are not valid symbols matching this regex, too, for example some strings containing parentheses – but they should not appear right after a def-something in a syntactically correct Elisp buffer, and even if they did, I don’t care about extremely rare false positives.) I ended the regex with \_> to make sure that the repeated shy group captures the whole symbol. Otherwise, when there is a double dash in it, the regex would just match its part until that double dash.

I have to admit that I am pretty proud of this – I think it is a pretty clever hack. It doesn’t mean that I won’t write any Elisp at all – I decided to wrap in in the following command:

(defun discover-public-api ()
  "Show all public functions, variables etc. in the `*Occur*' buffer."
  (interactive "" emacs-lisp-mode)
  (list-matching-lines "^(\\(?:cl-\\)?def[^ ]+ -?\\(?:[^ -]+-?\\)+\\_>")
  (select-window (get-buffer-window "*Occur*"))
  (message (substitute-command-keys "\\<occur-mode-map>Press \\[next-error-no-select] and \\[previous-error-no-select] to move around.")))

(I added one thing to the regex – an optional cl- prefix, for things like cl-defun and friends. Also, I used the mode indication for interactive.)

Note that the \<occur-mode-map> part is needed, because at the point when message is evaluated, the *Occur* buffer is not the current buffer – it will be made so by the command loop after the function finishes. Therefore I need to tell substitute-command-keys to use occur-mode-map explicitly. My approach here – to use select-window and count on the command loop to switch to the *Occur* buffer – is definitely not a good practice, but at least allows me to show the \[...] construct;-). Also, this will be changed in a few minutes anyway.

Now, this is enough for my use, but definitely not something production-grade and nice – for example, the lines in the occur buffer have the part matching the regex highlighted. For this regex, this includes everything from the opening parenthesis up to the end of the symbol, which looks a bit weird. (This could be remedied by adding .*$ to the regex, but it would mean that the highlighting face – which by default has a bright yellow background – would be used all over the place. While arguably more “consistent”, it would look even worse.) This can be fixed, too, of course – this is Emacs, after all – but it is slightly more work than one could expect.

The highlighting is done by adding the match face to the face property. This means that the value of that property is either just match or a list of faces beginning with match. This way, all the fontification is carried over from the Elisp buffer to the Occur buffer, which is a desirable behavior. For example, faces like font-lock-keyword-face, used in Elisp buffers, are still used in the *Occur* buffer. It is fairly easy to remove all faces from text properties:

(let ((inhibit-read-only t))
  (remove-text-properties (point-min)
                          (point-max)
                          '(face nil)))

(the *Occur* buffer is normally read-only, hence the inhibit-read-only), but this is not what I would like to do, since it also removes the faces installed there by font locking. It turns out that removing only the match face from the whole buffer is a surprising amount of work. Elisp has the add-face-text-property function which can add a face to a text (possibly resulting in combining more than one face), but no remove-face-text-property one. Of course, it’s not impossible to write it, but it is a bit tricky. One of the reasons is that the face text property can be either a symbol (denoting a face) or a list of such symbols. This is nothing difficult to deal with, but it adds complexity, and it helps to have some functions dealing with it:

(defun mbork/contains-or-equals (needle haystack)
  "Return non-nil if NEEDLE is `eq' to HAYSTACK or HAYSTACK cotains NEEDLE."
  (or (eq needle haystack)
      (and (listp haystack)
           (memq needle haystack))))

(defun mbork/remove-face (face face-prop)
  "Remove FACE from FACE-PROP and return the result.
If FACE-PROP is `eq' to FACE, return nil.  If FACE-PROP is a list,
return the result of `(remq face face-prop)'.  Otherwise, return
FACE-PROP."
  (cond ((eq face face-prop)
         nil)
        ((listp face-prop)
         (remq face face-prop))
        (t face-prop)))

If the face property were always a list (possibly containing just one element), it would suffice to use memq and remq in place of those functions. (Note that mbork/remove-face can output a list consisting of just one element, which could then be turned into just that element in the context of the face property – but I don’t think the added complexity would be worth it.)

Now, the code below employs even more trickery. First of all, keep in mind that while-let is more akin to let* in the sense that the bindings are evaluated one after another, so you can use the variable bound in the first one when creating the second one. Next, the very handy function text-property-search-forward called this way searches for a region where the face text property is the same across that region and not nil. (See its docstring for more details.) This means that if prop-match is nil, the while-let will end, but if it is not nil, neither is prop-match-value and the put-text-property will be evaluated, removing the match face whenever it finds one.

(defun mbork/remove-face-text-property (start end face)
  "Remove FACE from properties in the current buffer between START and END."
  (save-excursion
    (save-restriction
      (narrow-to-region start end)
      (goto-char (point-min))
      (while-let
          ((prop-match (text-property-search-forward 'face))
           (prop-match-value (prop-match-value prop-match)))
        (when (mbork/contains-or-equals face prop-match-value)
          (put-text-property (prop-match-beginning prop-match)
                             (prop-match-end prop-match)
                             'face
                             (mbork/remove-face face prop-match-value)))))))

So, to wrap it up, here is the “nicer” version of discover-public-api. Notice that we no longer need the \<occur-mode-map> part – as mbork/remove-face-text-property operates on the current buffer, we needed to switch to it using set-buffer, so occur-mode-map became the current map anyway.

(defun discover-public-api ()
  "Show all public functions, variables etc. in the `*Occur*' buffer."
  (interactive "" emacs-lisp-mode)
  (list-matching-lines "^(\\(?:cl-\\)?def[^ ]+ -?\\([^ -]+-?\\)+\\_>")
  (select-window (get-buffer-window "*Occur*"))
  (set-buffer "*Occur*")
  (let ((inhibit-read-only t))
    (mbork/remove-face-text-property (point-min) (point-max) 'match))
  (message (substitute-command-keys "Press \\[next-error-no-select] and \\[previous-error-no-select] to move around.")))

This is still not ideal – there are lots of ways this code could be improved (as is usually the case). For example, it shows all the opening parens but not the closing ones (unless the (def...) fits in one line, which it almost never does). Also, the pretty complicated regex is still visible at the top of the *Occur* buffer, and that is in fact an implementation detail the user should not be concerned with. In fact, the *Occur* buffer name itself is hardcoded, which is not very good, either (this could be fixed by using occur-1 instead of occur or its alias list-matching-lines, but that function is a bit weird as it does not have a docstring (!), which might mean that it should be considered an “internal” or “private” function). But right now the code is definitely very useful (at least to me) and nice enough to use without the garish yellow, and this post is already long enough, so let’s just stop here. The takeaway here is not that the code is 100% polished, but rather that Emacs has so many useful (and usually pretty general) features that even if you have a need which is somewhat atypical, you don’t always have to code it from scratch.

CategoryEnglish, CategoryBlog, CategoryEmacs

November 18, 2024 06:00 AM

November 11, 2024

Borkowski Marcin

2024-11-11 A situated approach to passwords

It is a well-known mantra that when writing a web application or a similar thing, you should never store your users’ passwords unencrypted.

Well, I’m now going to challenge this idea (a bit). Note: I’m definitely not a security expert by any means, and it’s quite possible that I’m completely wrong. But I think I encountered two cases when storing passwords in plain text is actually pretty fine.

I guess what I’m really trying to say here is that security is just a bunch of trade-offs. If your program is somehow exposed on the network (for example, you can access the database from another machine), it is never “absolutely secure”. And even if you only allow access to your data from the machine the data is one, and that machine is air gapped, and all data reside on an encrypted partition with a very strong password, it is still not “absolutely secure”.

That said, an obligatory disclaimer. Let me repeat, it’s quite possible that I am wrong, and if you do not know a lot about security and you use this very article as a justification for storing passwords in plain text, you are doing it wrong. This is just some rambling, food for thought, written by someone who doesn’t like people telling what they think are absolute rules without any justification. And in fact, encrypting, or hashing, or better, key-stretching passwords is so cheap that there is almost no reason not to use it anyway, so even my use-cases I write about below are rather contrived.

So, when I personally consider storing passwords in plain text an acceptable trade-off? Well, some time ago I read an absolutely fascinating article about a software equivalent of a home cooked meal, also known as situated software. That resonated with me a lot, and I will write about it more in the following weeks. The idea is that some software isn’t meant for the general public (which almost inevitably will include some malicious actors), but for small groups of people instead. (In a special case, this small group is actuall a group of one.) The cases I used the simplistic, naive approach of not encrypting passwords fall into exactly this category.

Here is the first case. I once built a very simple app to render a visual representation of my home budget. I use ledger, and while I like it a lot, I wanted something visual to show me whether I am keeping within my budget or not. Also, I wanted it on the web so that I could open it on my phone while shopping and decide – in a rational way – whether I can afford that fancy thing or not. On the other hand, I wanted some kind of authorization so that only me and my family could access it. This is what I did. First and foremost, the app is 100% read-only, the only thing it does with the ledger file is read it (actually, transform it using ledger itself). And secondly, even if this app had a bug which allows to somehow modify the ledger file, it wouldn’t really matter, since it only has access to a copy of it. (This works in a very simple way: after I update my ledger file, I commit it to Git, and I have a post-commit hook copying it with scp to the server where the app resides.) Now, what could happen if someone somehow got my password? Nothing could be modified, or even if it could, I wouldn’t bother – the worst case would be that my fancy budget chart would be wrong. Equally importantly, I used a unique password I don’t use anywhere else (this is actually the most important thing!), so even if someone gained access to that password, they would only be able to see my monthly budget (and the current state of my monthly expenses). None of it is secret enough that it would be a problem for me (in fact, I probably could make this app totally open to everyone with the right URL and still nothing bad would happen). The method I settled on is trivially simple – the password is a part of a config file, stored in JSON alongside the app. (Interestingly, there are no usernames at all – just a list of passwords, and any of them can be used to log in. It turned out that this created an unexpected problem – I used Passport to implement authorization, and Passport requires a username to operate. I decided to inject a one-line middleware to the POST /login endpoint which just inserts the key username with the value username to the body of the request.) By the way, this approach is very similar to what Oddmuse does. In Oddmuse’s case, the rationale for being apparently lax with even admin passwords is that even an admin usually cannot permanently damage an Oddmuse site.

Another case is similar. Almost a decade ago, I built another app, this time not for myself, but for someone I know who needed such a thing. This app also needed some kind of authorization, but it didn’t contain anything crucial like financial or medical data. Again, the set of users would be very limited (this time it would be a bit higher than single digits number, but still not greater than about a dozene). One argument I had against encrypting passwords was that if I did that, I would have to provide the whole infrastructure for dealing with forgotten passwords. That means that I would have to store email addresses and provide “password reset” links via email. This in turn means that I would have to support sending emails, which is simple, but still needs work and perhaps some maintenance. All of that means work and time I didn’t necessarily want to spend on this. (After I wrote this, I discussed this idea with a friend, who suggested a more secure approach without the overhead – I’ll explain it in a minute.)

Instead, I settled down for another approach. First of all, I decided to store my passwords unencrypted. (In fact, encrypting passwords is in fact very little work, so I could actually change that.) More importantly, even if I decided to encrypt passwords, I would not hash them. Why? Because I decided to use usernames which are explicitly not email addresses, and even more importantly, I didn’t let the user choose their usernames and passwords at all. Yes, you heard that right. The username (aka the login) for every user was set by the admin. The password for every user was just set to a random string of characters. There was an option to reset the password to another random string, and that’s it. Here, the idea is that the administrator (for example me) can physically contact all users and give them their passwords via some other channel. Hence one of the main reasons for encrypting (or hashing passwords) – that any breach might expose the users’ data on other systems where they reuse the password – was gone. And even if someone gained access to this system, again – it didn’t contain any crucial (or personal) data.

After I wrote most of this, I consulted a friend who – unlike me – is a security expert, and he tried very hard to convince me that my approach is wrong. He partially succeeded – I admit that in the latter case I could do better with very little effort. There are two things I could have done to increase security (though let me stress that I still think these gains would be marginal). Firstly, I could avoid storing plain-text passwords and key stretch them instead (which is obviously better than just hashing). Of course, that would mean that the password reset procedure would have to be a bit more involved. The admin would initiate it, the system would show them the new password (just this one time), but then it would completely “forget” the password and only store the “enhanced key” (the result of key stretching) from now on. This way the time the system even has the plain-text password would be reduced to a minimum. (I would still disallow setting the passwords by the users.) Secondly, it is much better to concatenate a few words instead of selecting characters at random, since the resulting passphrase can have very high entropy while being easier to remember. (Predictably, a quick search turned out a lot of tools – from web-based, to command-line, to libraries – to generate diceware-like passwords. Also predictably, the quality of these tools seems to have, so to speak, extreme variability.)

So, this is it for today. I hope no security expert died of heart attack while reading this, and I’m curious if someone can prove me wrong (which, as I said, is quite possible, although I really did think my approach through, so I still would be a bit surprised). Generally, I think the main argument for not storing passwords in plain text is “but it is so little work to do it «correctly»”, and while I agree with that, I am aware that it’s still work. (For the record, I decided to no longer store passwords in plain text in my future projects, just in case and to promote better security practices.)

CategoryEnglish, CategoryBlog

November 11, 2024 12:00 PM

November 04, 2024

Borkowski Marcin

2024-11-04 Persisting variables across Emacs sessions

Today, I have a short tip to all people who write Elisp and want to preserve some variable other than user customizations between Emacs sessions. (For user settings, configuring them manually in init.el is the standard way to go.) A classic example would be histories of the user’s entries.

In fact, I already mentioned the persist package a long time ago. It is a fairly small but extremely useful tool. What it does is, well, persist a variable across Emacs sessions. As I said above, I find it especially useful for variables keeping various completion histories. If you write any Emacs tool which could benefit from being able to remember things even after quitting Emacs and starting it again, persist is definitely your friend!

CategoryEnglish, CategoryBlog, CategoryEmacs

November 04, 2024 08:00 AM

October 28, 2024

Borkowski Marcin

2024-10-28 Command alternatives

Today I’d like to write about an Emacs feature I didn’t know about, even though it’s part of Emacs since quite some time – it appeared in version 24.4, which means it is over 10 years old! It seems I’m not the only one who didn’t know this exists – I’ve just searched my ~/.emacs.d/elpa directory (which contains almost a hundred packages now!), and none of the packages I have installed there uses it, either.

Assume you want to define a user command dired-play which plays a media file the point is on in Dired. There are several ways to play a file, though – you could use mplayer, vlc, or mpv (the latter being probably the best choice, but that’s another topic). You can define three commands – dired-play-mplayer, dired-play-vlc and dired-play-mpv – and allow the user some way to choose one (most probably via an option declared using defcustom). There is, however, an alternative (pun totally intended!) to a defcustom! Let’s define the three commands (for simplicity, they will be just dummies, and I won’t include docstrings for the sake of brevity) and use define-alternatives to allow the user to choose one of them.

(defun dired-play-mplayer ()
  (interactive)
  (message "playing the sound using mplayer"))

(defun dired-play-vlc ()
  (interactive)
  (message "playing the sound using vlc"))

(defun dired-play-mpv ()
  (interactive)
  (message "playing the sound using mpv"))

(defvar dired-play-alternatives '(("MPlayer" . dired-play-mplayer)
                                    ("VLC" . dired-play-vlc)
                                    ("mpv" . dired-play-mpv)))

(define-alternatives dired-play)

Now the user can say M-x dired-play (of course, in practice this would be bound to some key in dired-mode-map, and Emacs will ask them to choose one of the players. From now on, every invocation of dired-play will use the selected player. Should the user want to change their choice, they can just invoke dired-play with a prefix argument. How cool is that?

One thing I don’t like about this feature is that it silently uses customize-save-variable to persist the customization. This means that it modifies and saves my init.el behind the scenes. I’m not a fan of Emacs modifying my init file, but here it is. (Admittedly, it does make sense in this particular case.)

So, that’s basically it for today. Command alternatives seems a nice (and heavily underused) feature of Emacs – not a single one file in Emac core repository uses it, and not a single one of almost 90 packages I have installed in my Emacs uses it, either. Still, it’s there in case you need it.

CategoryEnglish, CategoryBlog, CategoryEmacs

October 28, 2024 09:00 PM

October 19, 2024

Borkowski Marcin

2024-10-19 substitute-command-keys

Today I have a short tip for everyone that codes Elisp (for other people or even only for themselves), inspired by something I wrote recently (and will blog about soon, too). If you want to tell the user things like “press C-c C-c to finish what you are doing”, don’t hardcode the keybindings in the message string. You may bind the command to finish whatever the user is doing to C-c C-c, true, but the user could rebind it to <f10> or even M-s s-a or whatever key they like, or even unbind it completely. Instead, use the following syntax: \[command-name] (of course, you need to double the slash if you put it in an Elisp string), and process the string with substitute-command-keys. This way, Emacs will convert your command-name to the textual representation of the actual binding of your command. If the command has more than one binding, you can set the “preferred one” by setting the :advertised-binding property of the function name using put (or preferably function-put). If that property is not set, the binding used is selected according to where-is-preferred-modifier, which see; note that the docstring of that variable is apparently wrong, since it should say where-is-internal, not where-is. Even better, the resulting string will be fontified so that the binding is in the help-key-binding face.

For example, in emacs -Q, (substitute-command-keys "\\[undo]") yields C-x u, and (substitute-command-keys "\\[describe-face]") yields M-x describe-face (since this one is not bound to any key by default).

In fact, substitute-command-keys can do a lot more – see the relevant section of the documentation in the Elisp reference.

As usual, the self-documenting nature of Emacs shows itself – the support for something as trivial as displaying the binding of a command is superb, and if you want your code to be as user-friendly as possible when showing those bindings, you only need to make use of what Emacs already gives you.

CategoryEnglish, CategoryBlog, CategoryEmacs

October 19, 2024 05:00 PM

October 14, 2024

Borkowski Marcin

2024-10-14 mrr-replace-mode

I have to admit that this is a bit embarrassing. A long time ago I announced a future post (and promised to release my code) for performing multiple regex replacements in a buffer, possibly in an interactive way. A few months later I started my first programming job (yay!) and promptly forgot about it…

Good thing is, I was reminded about this recently, so I have a chance to revisit the topic. Without further ado, let’s go!

As I said in that previous post, I also wrote a minor mode for selectively (and interactively) performing replacements of some regexen. It proved immensely useful when I worked for Wiadomości Matematyczne as a copyeditor and proofreader. In order to use it, you need to configure it first. There is just one option to do that: mrr-interactive-substitutions. It is a list of lists of strings. Every sublist starts with a regex to replace, followed by an optional list of key-value pairs, followed by a list of possible replacements.

As of now, there are two options: :hint (a string, displayed in the echo area when a string matching the regex is found) and :test (a symbol, which should be a predicate function accepting no arguments; the replacement is skipped if that function returns nil).

The default value for mrr-interactive-substitutions – which serves as an example – looks like this:

'(("\\(\\b\\| +\\)-\\{1,3\\}\\(\\b\\| +\\)" :hint "TeX dashes" "-" "--" "~-- ")
  ("d\\([xts]\\)" :hint "Differential operator" :test texmathp "\\\\mathrm{d}\\1"))

Let’s analyze this. The first entry matches a string of one to three hyphens, preceeded (and followed) either by at least one space or a word boundary. The suggested replacements are a hyphen, double hyphen and a double hyphen surrounded by spaces (an unbreakable one on the left and a normal one on the right). The rationale is that many authors do not care about hyphens, en-dashes and em-dashes, so we checked every occurrence of such things and possibly fixed them. (It is disputable whether you really should use an em-dash or just an en-dash surrounded by spaces; we followed Polish typographical customs here, and apparently Robert Bringhurst agrees.)

The second entry is the letter d followed by one of the letters x, t or s, which are the most common differentials (in integrals, for example). Those are potentially replaced by the same thing, but with an upright d. Note the use of a capturing group in the regex and \1 in the replacement. Also, I used the :test keyword here – these strings can appear in words (take “redshift”, for example). Old-time readers of my blog might remember that the function texmathp returns true if the point is in TeX math mode.

Now, if I say M-x mrr-replace-mode, Emacs searches for the first match for any of the given regexen, highlights it with an overlay (using the same face as isearch does) and shows the “hint” in the echo area. You have three options then. You can press C-g to quit mrr-replace-mode, RET to move to the next match (or quit if there are no matches), and TAB to cycle between possible replacements (including the original text – after all, you might decide you want to leave it as it is).

A cool (and rather Emacs’y) thing is that it is a minor mode. This means that you can normally edit the surrounding text while doing the replacements, or do something in a different buffer and come back later. You might even notice that some useful pattern is missing from mrr-interactive-substitutions, move to your init.el, add it, evaluate the setq, get back to the original buffer, move point to the right place and press RET to look for the new list of patterns – all without even leaving the minor mode! You can also manually edit the text under replacement, but be warned that pressing TAB then will remove your edits.

I wrote this code almost a decade ago, and it shows. There is at least one stupid bug left (the “hint” is suggested as one of the replacements (how could I have not noticed that?), and the format of the mrr-interactive-substitutions option is very terse which makes it almost impossible to describe properly in defcustom. I intend to review the code and fix both issues, but it might take a while. Still, the code is usable as-is (assuming you don’t use the :hint option), and I can assure you that it helps tremendously with copyediting. (When I worked for “Wiadomości Matematyczne”, I had almost 50 entries in mrr-interactive-substitutions!) It is not on any Emacs package repository (I am going to finally learn how to add a package to Melpa, and this is going to be one of the packages I am going to put there), but you can find it on Gitlab.

CategoryEnglish, CategoryBlog, CategoryEmacs

October 14, 2024 12:00 PM

October 07, 2024

Borkowski Marcin

2024-10-07 Autoloads

I’ve known about the Emacs autoload feature for a long time, but I never bothered to read about it. I decided to fix that and finally read the relevant part of the Emacs Lisp manual.

It turns out that autoloads are a pretty simple concept. They basically serve as a way of deferring loading a package until it is really needed. If you have a lot of packages, loading them on Emacs startup may take considerable time and memory. (Of course, nowadays we usually don’t care too much for the latter, since computers now have insane amounts of RAM. My first computer had 64 kilobytes of RAM, and my first PC had 4 megabytes, and GNU Emacs was written in times when 4 megabytes was a lot!) Autoloads are a way to tell Emacs when the package should be loaded by defining some functions as “entry points” to the package. (Actually, it is a bit more sophisticated than that, but that’s the main idea.)

If you write a package, you should mark the entry point(s) with the “autoload comment”. That means putting the string ;;;###autoload on the line before the relevant defun (or perhaps other form defining something, like defvar or cl-defun). When the package is installed, Emacs scans it for these comments and generates a special file containing information about these functions, variables etc. During startup, Emacs loads that special file (which is much, much smaller than the main package file or files, and hence faster to load). This means that all autoloaded functions become actually callable – but calling any of them causes Emacs to load the package in question first. This means that autoloaded functions are loaded “on demand” – when they are first called.

That is (of course!) not the whole story. For example, you can make Emacs put basically arbitrary code into the autoloads file by putting it after the autoload comment but on the same line. This way, that piece of code is not evaluated when loading the package (since it is commented out), but on Emacs startup (because it gets copied to the autoloads file). This may be useful if the package uses non-standard ways to define things.

I intend to put this knowledge into practice soon – I’d like to take some of my Elisp code and submit it as a package to Melpa, both to make it more discoverable and hence useful to other people and also to learn the process. Of course, when I do it, I will write about it here!

CategoryEnglish, CategoryBlog, CategoryEmacs

October 07, 2024 07:00 PM

September 30, 2024

Borkowski Marcin

2024-09-30 Backing up small files with Borg

I’ve been using Borg for many years now. Today, however, I had a very specific need. I needed to back up files in some directory (and its subdirectories, of course) but with the exception of “large” files. Usually I exclude files based on their names, but since I started using gocryptfs, I didn’t really know the names of the files I wanted to omit from the backup.

Borg’s manual contains an example of exactly that:

find ~ -size -1000k | borg create --paths-from-stdin /path/to/repo::small-files-only

but it didn’t work for me. The problem was simple – either you provide the list of files to back up on the command line or in stdin, but not both:

borg: error: Must not pass PATH with ``--paths-from-stdin``.

On the other hand, I needed to provide the explicit list of files and directories in my home directory to back up. What to do, then?

It turns out that there exists a simple solution. Borg create command has the --exclude and --exclude-from parameters which allow to exclude given files – either giving a list of paths (possibly using wildcards) or a file containing such list.

So, here is my solution. I used process substitution to create a “temporary filename” to pass the names of all the “big” files to Borg’s --exclude-from. Assuming that I want to back up the directory to-backup, I did this:

borg create --exclude-from <(find to-backup/ -size +100k) repository::archive to-backup/

That’s it for today, see you next time!

CategoryEnglish, CategoryBlog

September 30, 2024 08:00 PM

September 23, 2024

Borkowski Marcin

2024-09-23 npm clean-install --ignore scripts - it's a trap

A few days ago I was scripting a Node.js project and I had a very specific need. I wrote a script run as postinstall, but I wanted to launch it only in specific circumstances. When I found out that npm clean-install has an --ignore-scripts option, I was really glad – until I tried it out.

This is what the documentation says about this option:
If true, npm does not run scripts specified in package.json files.
Note that commands explicitly intended to run a particular script, such as npm start, npm stop, npm restart, npm test, and npm run-script will still run their intended script if ignore-scripts is set, but they will not run any pre- or post-scripts.

Does that imply that – for example – the postinstall script is not run? Yes, it does. Does it imply that when installing individual packages into node_modules, their postinstall scripts are not run? Hard to say, but that is exactly what happens! In my case, the project contained the esbuild package, which relies on postinstall to do some rather mysterious stuff related to installing its binary components. (I tried to fathom its postinstall script, but gave up after a few minutes – it’s certainly doable, but I don’t need this knowledge that much.)

One way to solve this is to issue the npm rebuild command, either in every subdirectory of node_modules (which, I’m afraid, might take ages…) or just in those ones which actually need it. The question is, how do I know which ones do? It occurred to me later that I can easily write some code to parse package.json of every installed module, but this is definitely a case of fighting tools which were supposed to help you…

(Warning: rant incoming, again…)

What’s even worse, while writing this post, I discovered that the npm documentation’s search feature is practically worthless. For example, typing postinstall (or post-install, for that matter) into the search box reveals no results. Interestingly, while I type postinstall, different things happen. After typing p, a bunch of 20 suggestions appears; funnily enough, one of them is a page not found link. Well, it actually starts with p, so it seems legit… When I type o (so I have po in the search box), another set of 20 suggestions appears. I have a hunch that there are less pages matching po than just p, so there must be a limit of 20 suggestions shown. Why someone decided that a 404 page is useful enough to include in the suggestions for the p prefix is of course beyond me.

But wait, there’s more. When I type the next few letters, arriving at posti, I get no suggestions at all. But typing n (so that now I have postin in the search box) yields a suggestion of Reporting malware in an npm package, a page which does not seem to contain the string postin anywhere! I have no idea how this can happen… Even assuming it has postin in some kind of metadata, how come posti didn’t reveal it as well?

Last but not least, as I said, typing postinstall (or post-install) does not reveal anything at all.

Now, I am pretty accustomed to using the Info documentation system present in Emacs. It works infinitely better than npm’s docs:

  • It is easily available locally, so that it is fast and usable without an internet connection (the DevDocs project helps with that, although it still uses an internet browser, which means it’s noticeably slower).
  • It allows for actual searching the whole manual for a string or a regex. By that, I mean finding places where the given string actually appears – something that is clearly beyond the capabilities of npm docs.
  • A long-standing tradition of including a (manually prepared) index in Info manuals makes looking for a specific subject very easy and fast.
  • It is easy to generate a link to some Info section, either its web version or an Elisp form which enables the user to jump to it within Emacs.
  • Lat but not least, Emacs Info reader is written (obviously) in Elisp, so it can be easily extended/hacked on if a need arises.

Compared to Emacs manuals in Info, npm docs are technologically inferior and have significantly lower quality. It appears that I’m better off using DuckDuckGo (or better, Kagi) with a site: filter.

Anyway, it’s time for a conclusion – except that I don’t have any, apart from the obvious one that both the design and documentation of npm are less than ideal. Just be warned that the npm CLI tool does not always do what you wish it were doing…

CategoryEnglish, CategoryBlog, CategoryJavaScript

September 23, 2024 08:00 PM

September 16, 2024

Borkowski Marcin

2024-09-16 Irregular recurring TODOs in Org mode, part II

So, it’s been over a year since the previous part of my attempt to introduce “irregular, but recurring TODOs” into my workflow. This is something I really need, but it’s complicated enough that my inner procrastinator kept putting it off, unfortunately.

Let’s start differently now. First of all, let’s set the “boundary conditions”, or the design goals, more explicitly than before. I don’t want the number of reviews per day to fluctuate too much – that is a given. I also do not want the intervals between reviews to rise dramatically. My goal is not to learn the material, but to be periodically reminded about it, so I prefer reviews in fairly uniform (as opposed to exponentially increasing) intervals. (The first few intervals being larger and larger seems fine, but after that they should stabilize.) Let’s determine the minimum and maximum interval this time. I think that the first interval should be about one week long, the second one about a month, and every subsequent one should be about 2 months. (These numbers are pretty arbitrary, but “seem reasonable”.) Also, every one of these may be made longer, but not too much. So, here is another idea.

Let’s begin with setting the maximum daily number of reviews, and set it to one (initially). After every review of an item, we will schedule the next one for that item, according to the following algorithm:

  • given today’s date d, maximum number of reviews per day m and the number of reviews n this item already had, the function i mapping the number of the reviews to the minimum interval to the next one, and a fixed quotient q,
  • find some random day in the set {d+i(n),...,d+qi(n)} when the number of reviews scheduled is less than m, and schedule the review then, if such a day exists,
  • or increment m and schedule the review on a random day in {d+i(n),...,d+qi(n)} otherwise.

(In the first draft, I wrote that the next review should happen in the first day of the respective set, but I changed it to be more random. The reason was that I was afraid that the order of reviewing the items will stay the same – when some item B is shown after some item A, it might always be shown after A, and I didn’t want that.)

The drawback of this idea is that I’ll need a way to easily answer the question: given a particular day, how many reviews are scheduled then? Assuming that the date of review is associated with the item (for example, stored in its properties), this means being able to scan all the items rather quickly to find out how many are scheduled to d+i(n), to d+i(n)+1 and so on. Org mode is not best suited for that, even though I suspect that the number of items will not be big enough to create a performance problem for the user. Still, maybe it would be better to have a real database for that.

Well, good thing Emacs comes with one, then! Since Emacs 29, the sqlite3 library is one of Emacs’ components. Why not utilize that? One reason is that it would be premature optimization. Let’s keep the idea of using SQLite in mind, but for now Org properties should be more than enough.

But first let’s make another simulation. This time, though, I think I can at least try to predict what is going to happen. Previously, I had no idea what intervals would be selected – my formula determined them only implicitly. Now, the interval lengths are going to be more or less predetermined, so the non-obvious variable is the number of daily reviews. But this time, it can be estimated. Let us assume the following “interval function”:

(defun recurring-next-interval (review-number)
  "Return the minimum interval for the next review."
  (cl-case review-number
    (1 7)
    (2 30)
    (t 60)))

and let us set q=2 (so that the second review after the initial one will happen in between 7 and 14 days, for example). This means that every item will be reviewed at least once every 120 days and at most once every 60 days (after a few initial reviews which are going to be a bit more frequent). While the first few repetitions will happen more often, let’s assume that the average interval between repetitions is going to be 90 days. Assume also that I will add one item per 8 days to the system (and I think this is a safe upper bound). After a year, I’m going to have about 45 items then, so one review per day will stop being enough after two years. In other words, every two years of using the system will add roughly one review per day to my load. This seems to be acceptable for me – if it turns out it’s not, I can always increase the intervals after some time.

Ok, so let’s confirm these back-of-the-envelope calculations. Beware, a long piece of not-the-best-quality Elisp code follows! (Since this is throwaway code, I didn’t bother with good practices etc.)

;; Recurring TODOs - simulation, second attempt

(require 'cl-lib)

(defvar recurring-todos ()
  "A list of \"TODO items\" as plists -- the properties are :id (an
integer), :reviews (dates of review, integers, starting with the
most recent one) and :next (date of the next review).")

(defvar recurring-counter 0
  "The value of :id for the next item created.")

(defvar recurring-date 0
  "The \"date\" (number of days elapsed from the beginning of the
experiment).")

(defvar recurring-buffer-name "*Recurring TODOs simulation data*"
  "Data about recurring TODOs simulation as csv.  Every row
corresponds to one review (including the first one, i.e.,
addition of the item to the system).")

(get-buffer-create recurring-buffer-name)
(with-current-buffer recurring-buffer-name
  (insert "date,id,review,interval\n"))

(defun recurring-add-review-datapoint (date id review interval)
  "Add a datapoint about a review to buffer `recurring-buffer-name'."
  (with-current-buffer recurring-buffer-name
    (goto-char (point-max))
    (insert (format "%s,%s,%s,%s\n"
                    date id review interval))))

(defun recurring-add-empty-row ()
  "Add an empty row to buffer `recurring-buffer-name', signifying that
  the maximum number of repetitions per day was increased."
  (with-current-buffer recurring-buffer-name
    (goto-char (point-max))
    (insert "\n")))

(defun recurring-add-todo ()
  "Add a new recurring todo to `recurring-todos'."
  (let ((new-item (list :id recurring-counter
                        :reviews ()
                        :next nil)))
    (recurring-review-item new-item)
    (push new-item recurring-todos)
    (cl-incf recurring-counter)))

(defun recurring-next-day ()
  "Increment `recurring-date'."
  (cl-incf recurring-date))

(defun recurring-last-review (todo)
  "The date of the last review of TODO."
  (car (plist-get todo :reviews)))

(defun recurring-number-of-reviews (todo)
  "The number of reviews of TODO so far."
  (length (plist-get todo :reviews)))

(defun recurring-next-review (todo)
  "The date of the next review."
  (plist-get todo :next))

(defun recurring-next-interval (review-number)
  "Return the minimum interval for the next review."
  (cl-case review-number
    (1 7)
    (2 30)
    (t 60)))

(defvar recurring-factor 2
  "The maximum factor an interval may be multiplied by.")

(defvar recurring-max-per-day 1
  "The maximum number of reviews per day.
Initially 1.")

(defun recurring-number-of-reviews-on-day (date)
  "The number of reviews scheduled for DATE."
  (cl-reduce (lambda (count todo)
               (if (= date (recurring-next-review todo))
                   (1+ count)
                 count))
             recurring-todos
             :initial-value 0))

(defun recurring-compute-next-review (todo)
  "Return the date of the next review of TODO."
  (let* ((interval (recurring-next-interval (recurring-number-of-reviews todo)))
         (min-date (+ recurring-date interval))
         (max-date (+ recurring-date (ceiling (* recurring-factor interval))))
         (possible-dates (cl-remove-if-not (lambda (date)
                                             (< (recurring-number-of-reviews-on-day date)
                                                recurring-max-per-day))
                                           (number-sequence min-date max-date))))
    (if possible-dates
        (seq-random-elt possible-dates)
      (cl-incf recurring-max-per-day)
      (recurring-add-empty-row)
      (recurring-compute-next-review todo))))

(defun recurring-review-item (todo)
  "Review the TODO item."
  (recurring-add-review-datapoint recurring-date
                                  (plist-get todo :id)
                                  (1+ (length (plist-get todo :reviews)))
                                  (- recurring-date
                                     (or (car (plist-get todo :reviews))
                                         recurring-date)))
  (push recurring-date (plist-get todo :reviews))
  (setf (plist-get todo :next)
        (recurring-compute-next-review todo)))

(defun recurring-review-for-today ()
  "Review items for the current day."
  (mapc #'recurring-review-item
        (cl-remove-if-not (lambda (todo)
                            (= (recurring-next-review todo)
                               recurring-date))
                          recurring-todos)))

(defun recurring-reset ()
  "Reset the recurring reviews simulation."
  (setq recurring-todos ()
        recurring-counter 0
        recurring-date 0
        recurring-max-per-day 1))

(defun recurring-simulate (iterations new-frequency)
  "Simulate ITERATIONS days of reviewing TODOs.
NEW-FREQUENCY is the probability of adding a new TODO every day.
Do not reset the variables, so that a simulation can be resumed."
  (dotimes-with-progress-reporter
      (_ iterations)
      "Simulating reviews..."
    (when (< (cl-random 1.0) new-frequency)
      (recurring-add-todo))
    (recurring-review-for-today)
    (recurring-next-day)))

This time I ran the simulation for 4 years assuming that I add one item every 8 days on average at first, just to see what happens. (In fact, I’ve been actually gathering items for repeating in this system for about one and a half years now, and I have 51 of them so far.) It turned out that I reached 3 repetitions per day (which is roughly consistent with my expectations), and the average interval between repetitions was about 70 days (almost 80 in the fourth year alone). This looks very promising. The second experiment involved 10 years with one item added to the system every 5 days, and the average interval turned out to be 82 days (87 in the last year); the maximum number of repetitions per day reached 9, which is a tiny bit worrying, but probably still acceptable. (Assuming many of my TODOs are of the form “read this article again to be reminded of it”, 9 potentially long articles per day doesn’t look very good – but it just occurred to me that as part of an earlier repetition I might want to summarize the article, which is also very good for keeping it in long-term memory.) Also, if I decide that the daily load is too high, I can just increase the intervals, or even drop some of my items if I decided I no longer need to be reminded of them. Either way, 10 years is long enough that I most probably don’t need to worry about it.

So, the next time I write about this, I really hope to have a functional if minimal setup – in fact, I am (slowly) working on it.

That’s it for today, see you in a few days with the next article!

CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryOrgMode

September 16, 2024 04:00 PM

January 08, 2015

Hromada Mateusz

Warka 9 – American India Pale Ale

Zasyp:

  • pale ale 4kg
  • pszeniczny 0,8kg
  • carapils 0,5kg

Zacieranie w 18l wody, słód dodany w 55°C:

  • 68°C – 65 minut przerwy (po 30 minutach podgrzanie z 65°C do 68°C)

Po filtracji i wysładzaniu wyszło 21,5 litra brzeczki o BLG 11,1.

Chmielenie:

  • 60 minut – 40g Simcoe
  • 20 minut – 30g Simcoe
  • 5 minut – 30g Simcoe
  • 0 minut – 30g Amarillo
  • dry hopping – 30g Simcoe (6 dni), 30g Simcoe (3 dni)

Po schłodzeniu i filtracji wyszło 19 litrów o BLG 16.

Fermentacja (drożdże US-05):

  • 11 dni burzliwej
  • 23 dni cichej

Do refermentacji użyłem 140g cukru i 735g wody.

ABV: ok. 6.2%

by ruanda at January 08, 2015 09:38 PM

Warka 8 – Cydr

Składniki:

  • sok jabłkowy Riviva 22l

Sok ma BLG 12.

Fermentacja (drożdże US-05):

  • 7 dni burzliwej
  • 38 dni cichej

Do refermentacji użyłem 155g cukru i 1135g wody.

ABV: ok. 6.3%

by ruanda at January 08, 2015 09:34 PM

Warka 7 – American Wheat

Zasyp:

  • pszeniczny 2kg
  • pilzneński 2kg

Zacieranie w 16l wody, słód dodany w 45°C:

  • 45°C – 15 minut przerwy
  • 53°C – 15 minut przerwy
  • 68°C – 75 minut przerwy (po 30 minutach podgrzanie z 64°C do 70°C)

Po filtracji i wysładzaniu wyszło 21 litry brzeczki o BLG 7.

Chmielenie:

  • 60 minut – 10g Chinook
  • 20 minut – 20g Palisade
  • 5 minut – 20g Cascade
  • 0 minut – 20g Amarillo
  • dry hopping – 30g Amarillo, 10g Cascade, 10g Palisade

Po schłodzeniu i filtracji wyszło 18 litrów o BLG 12.

Fermentacja (drożdże US-05):

  • 8 dni burzliwej
  • 35 dni cichej

Do refermentacji użyłem 120g cukru i 880g wody.

ABV: ok. 5.5%

by ruanda at January 08, 2015 09:28 PM

November 11, 2014

Girl, lost in IT

Nowy wpis, nowe miejsce

W poprzednim wpisie uprzedzałam, że muszę wprowadzić duże zmiany. Nie jestem już w stanie pisać każdego tekstu w dwóch językach. Dodatkowo czuję, że zmieniłam się przez ostatnie kilka lat – czuję, że „wyrosłam” trochę z tego bloga. Właśnie napisałam pierwszy tekst w nowym miejscu. Blog nazywa się Na miękko - serdecznie zapraszam.

by ynka at November 11, 2014 09:02 PM

October 13, 2014

Krzysztof Szarzyński

Zawieszenie publikacji

Jeśli dobrze liczę, to od 402 dni nic tu nie napisałem. Ponieważ zazwyczaj nie mam niczego interesującego do powiedzenie/napisania, dlatego przerzuciłem się na inne platformy, które lepiej pasują do “beztekstowej” formuły. Nadal robię zdjęcia – więcej niż kiedyś, ale publikuje je w mniejszych porcjach. Zapraszam na mój profil 500px, gdzie wrzucam rożne zdjęcia z całego […]

by Quati at October 13, 2014 06:41 PM

June 12, 2014

Hromada Mateusz

Warka 6 – Żytni Stout

Zasyp:

  • pale ale 2kg
  • żytni 2kg
  • żytni czekoladowy 0,25kg
  • Carafa typ III special 0,25kg

Zacieranie w 16l wody, słód dodany w 55°C:

  • 55°C – 10 minut przerwy
  • 70°C – 60 minut przerwy (po 60 minutach podgrzanie z 62°C do 68°C)
  • 68°C – dodanie ciemnych słodów, 40 minut przerwy

Po filtracji i wysładzaniu wyszło 20,5 litra brzeczki.

Chmielenie:

  • 60 minut – 10g Tomahawk
  • 15 minut – 30g Tomahawk
  • 5 minut – 30g Tomahawk
  • dry hopping – 30g Tomahawk

Po schłodzeniu i filtracji wyszło 18 litrów o BLG 13.

Fermentacja (drożdże S-04):

  • 22 dni burzliwej

Do refermentacji użyłem 125g cukru i 835g wody.

ABV: ok. 4,4%

by ruanda at June 12, 2014 08:38 PM

April 27, 2014

Girl, lost in IT

W planie zmiany + jak tu trafiłam (w obrazkach)

Kolega wyraził ostatnio zaniepokojenie działaniem swojego czytnika RSS. To przecież niemożliwe, żebym tak długo nie napisała nic na swoim blogu! Niestety, możliwe. Do tego powód jest dość absurdalny: piszę mniej, ponieważ piszę więcej. Naprawdę. Pamiętacie, jak przeżywałam swoje 10000. urodziny? Postanowiłam wtedy na poważnie wziąć się za rzeczy, o których zawsze myślałam, że zrobię je […]

by ynka at April 27, 2014 06:28 AM

March 22, 2014

Hromada Mateusz

Warka 5 – Imperial India Pale Ale

Zasyp:

  • pale ale 5kg
  • wiedeński 1kg
  • carapils 0,5kg
  • pszeniczny 0,2kg

Zacieranie w 21l wody, słód dodany w 55°C:

  • 55°C – 10 minut przerwy
  • 65°C – 90 minut przerwy (po 60 minutach podgrzanie z 61°C do 65°C)

Po filtracji i wysładzaniu wyszło 23 litry brzeczki o BLG 14.

Chmielenie:

  • 60 minut – 40g Chinook
  • 10 minut – 20g Citra, 20g Simcoe
  • 5 minut – 30g Citra, 30g Simcoe
  • 0 minut – 15g Cascade, 15g Palisade
  • dry hopping – 15g Cascade, 15g Palisade

Po schłodzeniu i filtracji wyszło 21 litrów o BLG 17.

Fermentacja (drożdże US-05):

  • 9 dni burzliwej
  • 10 dni cichej

Do refermentacji użyłem 130g cukru i 630g wody.

ABV: ok. 7,6%

by ruanda at March 22, 2014 07:44 PM

March 12, 2014

Hromada Mateusz

Warka 4 – American Wheat

Zasyp:

  • pszeniczny 2kg
  • pilzneński 2kg

Zacieranie w 15l wody, słód dodany w 55°C:

  • 55°C – 10 minut przerwy
  • 68°C – 70 minut przerwy (po 50 minutach podgrzanie z 62°C do 67°C)

Po filtracji i wysładzaniu wyszło 21 litry brzeczki o BLG 9,5.

Chmielenie:

  • 60 minut – 10g Chinook
  • 20 minut – 20g Palisade
  • 5 minut – 20g Cascade
  • 0 minut – 20g Amarillo
  • dry hopping – 30g Amarillo

Po schłodzeniu i filtracji wyszło 18 litrów o BLG 13.

Fermentacja (drożdże US-05):

  • 8 dni burzliwej
  • 11 dni cichej

Do refermentacji użyłem 120g cukru i 800g wody.

ABV: ok. 5.3%

by ruanda at March 12, 2014 06:14 PM

February 23, 2014

Girl, lost in IT

Oddam za darmo!

Raz na jakiś czas znajduję w domu coś, co dawno już przestało mi być potrzebne, ale co mogłoby jeszcze przydać się komuś innemu. Niektóre takie rzeczy wystawiam na Allegro (zwłaszcza, jeśli są warte więcej niż kilkadziesiąt złotych), jednak do Allegro często zniechęca mnie konieczność oszacowania kosztów przesyłki. Jeśli chcę pozbyć się czegoś szybko, tanio i […]

by ynka at February 23, 2014 05:23 PM

February 15, 2014

Hromada Mateusz

Instalacja Raspbian przez debootstrap

IMG_20140214_203617

Wymagania

Potrzebny jest Linux, w miarę świeży debootstrap i qemu-arm-static. Oczywiście potrzebny też jest dostęp do użytkownika root.

Partycjonowanie i formatowanie karty SD

Kartę należy podzielić na dwie partycje. Pierwsza, sformatowana w FAT będzie zamontowana jako /boot. Druga partycja będzie zamontowana jako /, można ją sformatować np. w ext4:

root@lol:/mnt# fdisk /dev/sdh
WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
switch off the mode (command 'c') and change display units to
sectors (command 'u').

Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-1021, default 1):
Using default value 1
Last cylinder, +cylinders or +size{K,M,G} (1-1021, default 1021): +64M

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): c
Changed system type of partition 1 to c (W95 FAT32 (LBA))

Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 2
First cylinder (10-1021, default 10):
Using default value 10
Last cylinder, +cylinders or +size{K,M,G} (10-1021, default 1021):
Using default value 1021

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: If you have created or modified any DOS 6.x
partitions, please see the fdisk manual page for additional
information.
Syncing disks.
root@lol:/mnt# mkfs.vfat /dev/sdh1
[...]
root@lol:/mnt# mkfs.ext4 /dev/sdh2
[...]
root@lol:/mnt# mkdir rpi
root@lol:/mnt# mount /dev/sdh2 rpi/
root@lol:/mnt# mkdir rpi/boot
root@lol:/mnt# mount /dev/sdh1 rpi/boot/

Instalacja i konfiguracja

Debootstrap należy przeprowadzić w dwóch etapach, gdyż binarki przeznaczone są na inną architekturę.

root@lol:/mnt# debootstrap --foreign --arch armhf wheezy rpi/ http://archive.raspbian.org/raspbian
[...]
root@lol:/mnt# cp /usr/bin/qemu-arm-static rpi/usr/bin/
root@lol:/mnt# LANG=C chroot rpi/ /debootstrap/debootstrap --second-stage

Następnie można chrootować się na budowany system:

root@lol:/mnt# LANG=C chroot rpi/ /bin/bash

Potrzebne są repozytoria w sources.list:

deb http://archive.raspbian.org/raspbian wheezy main contrib non-free
deb-src http://archive.raspbian.org/raspbian wheezy main contrib non-free

W pliku /boot/cmdline.txt należy dodać parametry do kernela:

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

/etc/fstab:

proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat defaults 0 0

Różne sieciowe ustawienia są w plikach /etc/hostname, /etc/resolv.conf i /etc/network/interfaces.

W chroocie należy doinstalować paczki git, binutils i ca-certificates.

Potrzebne jest narzędzie rpi-update:

root@lol:/# wget http://goo.gl/1BOfJ -O /usr/bin/rpi-update
root@lol:/# chmod +x /usr/bin/rpi-update
root@lol:/# mkdir /lib/modules
root@lol:/# rpi-update
[...]

Aby dostać się do RPi po restarcie potrzebne jest ssh i hasło na roota:

root@lol:/# passwd
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
root@lol:/# apt-get install ssh
[...]

Po wyjściu z chroota, odmontowaniu obu filesystemów i przełożeniu karty do RPi powinien zabootwać się Raspbian dostępny przez ssh:

root@trololo:~# uname -a
Linux trololo 3.10.30+ #640 PREEMPT Fri Feb 14 19:09:14 GMT 2014 armv6l GNU/Linux

Linki

by ruanda at February 15, 2014 01:20 PM

February 02, 2014

Hromada Mateusz

Warka 3 – American Stout

Zasyp:

  • pilzneński 3kg
  • monachijski 1kg
  • jęczmień palony 0,3kg
  • barwiący 0,2kg

Zacieranie w 15l wody, słód dodany w 55°C:

  • 55°C – 10 minut przerwy
  • 68°C – 70 minut przerwy (po 35 minutach podgrzanie z 64°C do 66°C)
  • 66°C – dodanie ciemnych słodów i 15 minut przerwy

Po filtracji i wysładzaniu wyszło 22 litry brzeczki o BLG 11.

Chmielenie:

  • 60 minut – 15g Centennial
  • 15 minut – 15g Centennial
  • 5 minut – 15g Centennial
  • 0 minut – 25g Centennial
  • dry hopping – 30g Centennial

Po schłodzeniu i filtracji wyszło 19,5 litra o BLG 15. Dodałem 1,5l wody.

Fermentacja (drożdże S-04):

  • 8 dni burzliwej
  • 12 dni cichej

Do refermentacji użyłem 140g cukru i 860g wody.

by ruanda at February 02, 2014 09:54 PM

Girl, lost in IT

10000* lat

Parę (naście) dni temu skończyłam 32 lata. Ta magiczna liczba nie doskwiera mi za bardzo i nie ona jest bezpośrednią przyczyną powstania tego tekstu. Do rozmyślań skłoniły mnie życzenia, które składano mi z tej okazji. Kilkoro (młodszych) znajomych, niezależnie od siebie, obdarowało mnie życzeniami brzmiącymi mniej więcej tak: „Wszystkiego najlepszego. Żebyś miała wspaniały rok. I […]

by ynka at February 02, 2014 06:17 PM

January 27, 2014

Hromada Mateusz

Warka 2 – American Pale Ale

Zasyp:

  • pilzneński 2,5kg
  • monachijski 1,3kg
  • karmelowy jasny 0,2kg

Zacieranie w 12l wody, słód dodany w 55°C:

  • 55°C – 10 minut przerwy
  • 69°C – 60 minut przerwy (z podgrzaniem w 40 minucie)

Po filtracji i wysładzaniu BLG 10.

Chmielenie:

  • 60 minut – 15g Simcoe
  • 15 minut – 15g Simcoe
  • 5 minut – 15g Simcoe
  • 0 minut – 25g Simcoe
  • dry hopping – 30g Simcoe

Po schłodzeniu i filtracji wyszło 16,5 litra o BLG 13.

Fermentacja (drożdże US-05):

  • 8 dni burzliwej
  • 10 dni cichej

Do refermentacji użyłem 110g cukru i 740g wody.

ABV: ok. 5%

by ruanda at January 27, 2014 06:25 PM

January 26, 2014

Hromada Mateusz

Warka 1 – American India Pale Ale

Pierwszą warkę uwarzyłem z przygotowanego zestawu surowców.

Zasyp:

  • pale ale 5,5kg
  • Cara Gold 0,5kg
  • pszeniczny 0,2kg

Zacieranie w 18l wody, słód dodany w 55°C:

  • 55°C – 10 minut
  • 69°C – 60 minut (bez podgrzewania, końcowa 62°C)
  • 76°C – mashout

Po filtracji i wysładzaniu wyszło 23 litry brzeczki o BLG 15.

Chmielenie:

  • 60 minut – 25g Warrior
  • 20 minut – 20g Simcoe
  • 10 minut – 10g Amarillo
  • 5 minut – 10g Amarillo
  • dry hopping – 30g Amarillo

Po schłodzeniu i filtracji wyszło 20,5 litra o BLG 17.

Fermentacja (drożdże US-05):

  • 10 dni burzliwej
  • 11 dni fermentacji cichej

Do refermentacji użyłem 135g cukru i 660g wody.

ABV: ok. 7%.

by ruanda at January 26, 2014 07:03 PM

December 15, 2013

Girl, lost in IT

O zmianie (pracy)

Kilka dni temu kolega z poprzedniej pracy spytał, czy przeniosłam blog w nowe miejsce – nie napisałam prawie nic od czasu, gdy zmieniłam pracę. Babcia przy każdym spotkaniu pyta, czy „korporacja” zdążyła już przeżuć mnie i wypluć. Odpowiem krótko: nie i nie! To prawda, że w ciągu ostatnich kilku miesięcy nie napisałam zbyt wiele. Miało […]

by ynka at December 15, 2013 07:46 PM

September 08, 2013

Krzysztof Szarzyński

Warszawa 2013 – Quati w stolicy.

Zanim zaproszę na ostatnią odsłonę zdjęć z mojego krótkiego pobytu w Warszawie, chwila luźnych wywodów. Nocowałem w hotelu przy placu Konstytucji, który oferował dwa rodzaje pokoi: ciche i z widokiem na miasto. Mi się trafiło oglądanie miasta, ale ponieważ ze mną na szkolenie przyjechało kilka innych osób z Poznania, to zdecydowaliśmy się z Adamem iść […]

by Quati at September 08, 2013 06:19 PM

September 04, 2013

Krzysztof Szarzyński

Warszawa 2013 – część druga

Dziś druga porcja obrazków z Warszawy. Hasłem przewodnim miało być “ludzie w Warszawie”, ale chyba troszkę bardziej pasuje “życie w Warszawie”. Chyba nigdy nie byłem dobry w nadawaniu tytułów i nazw. 🙂 Część trzecia zostanie opatrzona moimi przemyśleniami i komentarzem co do samego miasta. Zdjęcia również będą bardziej dotyczyć tego co widziałem i przeżyłem 🙂

by Quati at September 04, 2013 05:27 PM

September 01, 2013

Krzysztof Szarzyński

Warszawa 2013 – część pierwsza

W tym roku wakacje były podzielone na dwie cześći. Najpierw pojechaliśmy z Olą do Zwierzyńca, gdzie odpoczywaliśmy aktywnie zwiedzając Zamojszczyznę i korzystając z dobrodziejstwa krętych rzek i kajaków turystycznych. Ciągle czekam na chwilę weny żeby wybrać kilka zdjęć i je opublikować 🙂  Drugim etapem moich wakacji było… skończenie życia jako student i rozpoczęcie “dorosłości” w […]

by Quati at September 01, 2013 08:07 PM

Girl, lost in IT

Cicho sza!

Wcale nie zarzuciłam pisania tego bloga. Krótko o tym, co ostatnio dzieje się u mnie: Kupiliśmy dom. Trwa remont. Kompletnie nie doszacowałam nakładów czasowych (o finansowych nie będziemy tu rozmawiać) niezbędnych do realizacji takiego przedsięwzięcia. Tłumaczę książkę o C++ i Qt (Dlaczego? Patrz wyżej). Jest gruba. Zamiast tłumaczyć, spędzam godziny na rozmowach z fachowcami. Pół […]

by ynka at September 01, 2013 07:36 PM

July 13, 2013

Girl, lost in IT

Open’er, czyli wieczne poszukiwania

Heineken Open’er to co roku ta sama historia. Wiele tygodni przed festiwalem niecierpliwie zaczynam śledzić lineup i planować, co będę chciała zobaczyć. Bliżej terminu okazuje się, że z pięciu wymarzonych koncertów dwa odbywają się naraz, a trzy inne jeden po drugim – na scenach oddalonych od siebie o kilometr. Planuję także, z kim pojadę i […]

by ynka at July 13, 2013 08:00 AM

June 26, 2013

Krzysztof Szarzyński

Nowe zabawki i noc kupały

Obiecanki – cacanki. Czyli tradycyjnie, jak Quati mówi, że coś napisze, to znaczy, że mówi. 🙂 Dziś mam kilka zdjęć zrobionych za pomocą nowej zabawki, która oprócz tego, że jest świetnym gadżetem, to spełnia też czasami funkcję obiektywu. Otóż moim nabytkiem jest Sigma 50 mm F1.4 DG EX HSM, czyli typowa portretowa “stałka” z dość jasnym […]

by Quati at June 26, 2013 09:43 PM

May 30, 2013

Girl, lost in IT

Feminiści kontra statystyka

Uczestniczyłam ostatnio w konferencji, w której programie znalazł się panel dyskusyjny poświęcony mniejszościom w środowisku informatyków. Podczas panelu miałam okazję porozmawiać z inspirującymi i pełnymi dobrej woli ludźmi, jednak doszło tam również do pewnego zderzenia opinii, które wspominam do tej pory. Był sobie facet. Doświadczony lider, blogger, walczący o zwiększenie liczby kobiet w IT. Osoba, […]

by ynka at May 30, 2013 04:54 PM

April 20, 2013

Girl, lost in IT

Kup swojemu dziecku sobie robota Lego Mindstorms

Pierwszy raz klocki Lego widziałam, będąc małym dzieckiem, nie pamiętam nawet, czy było to Peweksie, „u prywaciarza”, czy może u kolegi, którego tata był kapitanem na statku handlowym, przez co w ich domu zawsze można było trafić na skarby niedostępne w normalnych sklepach (począwszy od mandarynek). Pamiętam, że zachwyciły mnie czyste kolory, przemyślane projekty oraz możliwości, jakie […]

by ynka at April 20, 2013 04:05 PM

March 16, 2013

Girl, lost in IT

Na słodko-gorzko o skutkach asertywności

Minęło już półtora miesiąca od kiedy zmieniłam pracę. Czas… biegnie szybko. Decyzja ciągle wydaje się dobra. Uczę się bardzo dużo. W trakcie ostatnich tygodni dwa razy odwiedziłam Warszawę, po raz pierwszy spróbowałam koreańskiej kuchni (z wyjątkiem zupy kimchi w Art Sushi, którą polecam, ale tylko ludziom o żołądkach ze stali), a także zapisałam się na […]

by ynka at March 16, 2013 12:37 PM

February 24, 2012

Dopierała Andrzej

2011-05-27 Darmowe fotoradary dla nissan connect

Może kogoś zainteresuje - nie znalazłem nigdzie opisu jak to łatwo zrobić “za friko”.

1. Ściągamy listę fotoradarów z http://ump.waw.pl/ plik z mapą fotoradarów (http://ump.waw.pl/update/Jacek.zip).
2. Rozkompresowujemy go
3. Łączymy to co nas interesuje do jednego pliku csv:

undefine@uml:~/tmp$ cat Kontrole\ Drogowe/*.csv Niebezpieczne\ Miejsca/*.csv Przejazdy\ Kolejowe/*.csv >x.csv
undefine@uml:~/tmp$ 

4. Usuwamy polskie znaczki (zapewne można jakoś przekodować, ale nie chciało mi się metodą prób i błędów szukać kodowania):

iconv -f cp1250 -t ascii//TRANSLIT  < x.csv > jacek.csv

5. Plik jacek.csv umieszczamy w katalogu myPOIs/myPOIWarnings na pendrive
6. Pendrive wkładamy do nissan connect i ładujemy POI użytkownika z menu(Setup → Navigation → Download my POIs)
7. Przestrzegamy ograniczeń ;)

February 24, 2012 08:24 AM

December 23, 2011

Dopierała Andrzej

2011-12-23 Ankieta Polskiego Badania Czytelnictwa: Przyszła do mnie prośba o wypełnienie ankiety. Z Polskiego Badania Czytelnictwa, sp. z o.o. Niby nic dziwnego, ale.. przyszła "smailem". A sama ankieta, po podaniu "pinu" z listu do wypełnienia na stronie http://www.ankieta.pbc.pl/ W zamian za wypełnienie ankiety oferują m.in. kupony sodexo na kwotę 20zł. I w sumie... Podszedłem do tematu trochę z mieszanymi uczuciami. Jak? Skąd? Po co? Z tego co znalazłem dane osobowe otrzymali z bazy PESEL na podstawie Dz.U. 2006 nr 139 poz. 993, 44h ust 2 par 2. List - był zaadresowany do mnie (imię, nazwisko, adres). Natomiast w samej ankiecie na stronie zwrot był przez "Pani". Pomyłka? Koniec końców zmarnowałem kwadrans i wypełniłem. Co prawda niezbyt wartościowo, bo z proponowanych czasopism to tylko sporadycznie Metro przeglądam jak akurat mi w korku wcisną, natomiast Fantastyki w ankiecie nie było, ale - jak to badanie statystyczne, to.. czemu nie.

Przyszła do mnie prośba o wypełnienie ankiety.
Z Polskiego Badania Czytelnictwa, sp. z o.o.

Niby nic dziwnego, ale.. przyszła “smailem”. A sama ankieta, po podaniu “pinu” z listu do wypełnienia na stronie http://www.ankieta.pbc.pl/

W zamian za wypełnienie ankiety oferują m.in. kupony sodexo na kwotę 20zł.

I w sumie… Podszedłem do tematu trochę z mieszanymi uczuciami. Jak? Skąd? Po co? Z tego co znalazłem dane osobowe otrzymali z bazy PESEL na podstawie Dz.U. 2006 nr 139 poz. 993, 44h ust 2 par 2.

List - był zaadresowany do mnie (imię, nazwisko, adres). Natomiast w samej ankiecie na stronie zwrot był przez “Pani”. Pomyłka?

Koniec końców zmarnowałem kwadrans i wypełniłem. Co prawda niezbyt wartościowo, bo z proponowanych czasopism to tylko sporadycznie Metro przeglądam jak akurat mi w korku wcisną, natomiast Fantastyki w ankiecie nie było, ale - jak to badanie statystyczne, to.. czemu nie.

December 23, 2011 09:04 PM

November 07, 2011

Dopierała Andrzej

2011-11-07 brother mfc5490CN: drukarka brother mfc 5490cn pod linuksem i.. ipv6.

Stara drukareczka HP 6540 się popsuła (uchwyt od czarnego tuszu przestał kontaktować), naprawa oczywiście nieopłacalna, a mi by się w domu przydał skaner, wiec… Nabyłem nową drukareczkę. Po przejrzeniu dostępnych opcji wybór padł na Brother MFC 5490CN
I - jak na razie nie mam co narzekać.
Drukowanie spod linuksa - ruszyło praktycznie od razu.
Skanowanie spod linuksa - również. Mimo iż po raz pierwszy w życiu konfigurowałem skaner pod linuksem.

A na dokładkę - drukarka działa również po ipv6…

Local> show ip v6

IPv6 is Enabled
IPv6 Static Address is Enabled
IPv6 Addresses are 2A02:848:A::XXXX:XXXX:XXXX:XXXX/64 (via Router)
                   FE80::XXXX:XXXX:XXXX:XXXX/64 (link-local)

The priority IP version of name resolving is IPv4

Będę musiał chyba firewalla wyklikać dla ipv6 :/

November 07, 2011 10:56 PM

September 09, 2011

Ogrodowczyk Wojciech

Koniec tej zabawy

Jak co bystrzejsi czytelnicy mogli zauważyć, nie pisuję już tu praktycznie nic, a zdjęcia tu umieszczane to jedynie opóźnione „przedruki” względem mojego konta na flickr. Kierując się więc brzytwą Okhama i zwykłym lenistwem...

September 09, 2011 08:12 AM

August 22, 2011

Dopierała Andrzej

2011-08-22 Lekko przerobiony multi router looking glass w php: Skrypt do przedstawiania na routerach.

Już kilka osób się mnie pytało jak zrobiłem http://lg.maverick.com.pl/.

Bazuję na lekko zmodyfikowanej wersji MRLG (Multi Router Looking Glass for PHP). Obecnie jego strona niestety nie działa - i oryginału nie mam do pobrania.

Moją zmodyfikowaną wersję umieściłem na mrlg-20091215.tgz, natomiast plik konfiguracyjny do niej na mrlg-config.php. Na pytania nie odpowiadam, w konfiguracji nie pomagam (bo nie mam czasu) - ale może komuś się przyda :).
Licencja - zgodnie z licencja oryginału - GPL.

Ale jak masz jakieś poprawki - podsyłaj :)

Wiem że brzydko zrobione, ale - było potrzebne na szybko i w parę godzin tylko na tyle mnie było stać.

Jak dodasz w swojej sieci kopię - zgłoś na traceroute.org - widoczność swojego miejsca w sieci się często przydaje :).

August 22, 2011 07:55 PM

August 21, 2011

Ogrodowczyk Wojciech

August 11, 2011

Ogrodowczyk Wojciech

August 05, 2011

Dopierała Andrzej

2011-08-05 Problematyczne ipv6 - dziwny resolver: problem z domenami z dodanym rekordem AAAA.

undefine@uml:~$ host aramin.net
aramin.net has address 42.1.94.0
;; Warning: Message parser reports malformed message packet.
;; connection timed out; no servers could be reached

i tak dla sporej części, o ile nie wszystkich adresów z dualstackiem - taki dziwny feature AP DSL-G604T w hotelu.

Do tej pory myślałem że dodanie rekordu AAAA nic nie psuje, teraz - sam się przekonałem że nie jest tak różowo, jak sie okazało że nie mogę się dostać na strony/serwery z dodanym AAAA. Na szczęście - można skorzystać z własnych albo googlowych dnsów.

Oczywiście prawidłowa odpowiedź to

undefine@uml:~$ host aramin.net
aramin.net has address 195.110.48.48
aramin.net has IPv6 address 2a01:5e00:2:52::30
aramin.net mail is handled by 0 mx.aramin.net.

August 05, 2011 04:55 PM

July 29, 2011

Ogrodowczyk Wojciech

July 27, 2011

Ogrodowczyk Wojciech

July 21, 2011

Ogrodowczyk Wojciech

July 14, 2011

Ogrodowczyk Wojciech

June 26, 2011

Dopierała Andrzej

2011-06-26 IPv6 na stronie: ipv6 na stronie

Co prawda po IPv6 day, ale.. wreszcie dołożyłem AAAA do mojej strony(i stron firmowych). Ciekawe co wybuchnie ;)

June 26, 2011 07:24 PM

June 17, 2011

Ogrodowczyk Wojciech

May 31, 2011

Ogrodowczyk Wojciech

Planet shot

Bcn planet shot

Eksperymentale ujęcie wychodka na szczycie świata, krok po...

May 31, 2011 11:44 AM

May 29, 2011

Ogrodowczyk Wojciech

March 12, 2011

Dopierała Andrzej

2011-03-12 IPv6-garsc-statystyk: kilka słów podsumowania o ruchu ipv6

Kilka statystyk z pewnego routerka. Zbierane ip6tables, w dłuższym okresie czasu. Wykresów nie daję, bo za mała próbka by ładnie wyglądało ;)

Dane z pewnej sieci osiedlowej w Poznaniu. IPv6 udostępnione klientom przez radvd. Głównie klienci “prywatni”.

Wejście:
2% - 6to4
pomijalne - PIX
24% - PLIX
3% - natywne IPv6 od Crowleya
69% - tunel z HE

Wyjście:
51% - 6to4(!)
6% - PIX
36% - PLIX
1% - Crowley
6% - tunel z HE.

Wnioski:
- podobnie jak w przypadku ipv4 duża część ruchu przypada na PLIX
- upload to głównie ruch kierowany do 6to4 - jak sądzę ruch p2p.
- bardzo duży download na tunelu z HE. Co prawda miałem trochę wątpliwości czy należy się w to bawić - to jednak obserwując ruch przy włączonym i przy wyłączonym tunelu widać że opóźnienia przez HE są często niższe. Pozatym - alternatywa to pchanie ruchu przez Crowleya, który.. również sporą część ruchu ma przez HE. HAWE jak na razie ipv6 nie dostarcza.

March 12, 2011 11:49 PM

February 22, 2011

Dopierała Andrzej

2011-02-22 IPv6 a 6to4: ipv6 6to4 sit0 routing ruch siec

Powolutku bawię się w wdrożenie IPv6 u pewnego ISP.

Na peeringach (w PIX i PLIX) ipv6 śmiga “natywnie”. Świata niestety jak na razie nikt nie dostarczył, więc leci tunelem z HE.

Do tego rozgłoszenie prefiksów do kilku testowych sieci - i troszkę ruchu widać.

W którymś momencie zauważyłem, że trochę ruchu leci do 6to4. Postawiłem więc bezpośredniego relaya(opis z http://wiki.debian.org/DebianIPv6) i…

mav-ipv6

Wniosek? Wbrew pozorom bardzo dużo (tak na oko 1/3) ruchu to ruch z relayami 6to4. Stąd zapewnienie dobrej komunikacji z nimi powinno być dosyć istotne przy udostępnianiu ipv6. Do testowego ip z którym obserwowałem ruch po ustawieniu bezpośredniego tunelowania 6to4 na moim routerze opóźnienia spadły z ok 80 do 50ms - a ruch wzrósł o kilkanaście procent.

(na wykresie jest widoczny wyłącznie ruch na tunelach - peeringi/polska leci natywnie, stąd nie mam prostej możliwości wyróżnienia go od ipv4)

February 22, 2011 11:06 PM

February 17, 2011

Dopierała Andrzej

2011-02-17 Rozkład ruchu na łączach: rozkład ruchu plix hawe tp pix

Taka mała ciekawostka.

Jest sobie mały operator. Świadczący głównie usługę dostępu do internetu dla “ludzi”. Pakiety - dosyć duże, po kilka/kilkadziesiąt megabitów, upload ciut mniejszy - po 2-3 megabity.
Ogólnie - zazwyczaj mało kto dociera do limitu w którąkolwiek ze stron.

Do tego jest troszkę hostingu i łącz biznesowych… Ale większośc to klienci indywidualni.

Łącza:
- peering w PIX-ie (http://www.pix.net.pl)
- peering w PLIX-ie (http://www.plix.pl)
- PBT HAWE (http://www.pbthawe.eu)
- Transmisję CDP Global od crowleya (http://www.crowley.pl)

i w którymś momencie na parę chwil pojawiła się testowa transmisja do TPSA - normalnie leci przez HAWE (i dalej styk z crowleyem).

Ruch - puszczony przez bgp prawie “samopas”. Lekkie preferencje by sterować ruchem na łączach zagranicznych (hawe/cdp), gdzieniegdzie unikanie problematycznych ścieżek - ale - można powiedzieć że rozkład jest prawie naturalny.

I teraz - procentowy wykres ruchu:
rozklad-lacz

Interesuje nas głównie download - uploadu jest niewiele - ok połowy downloadu, więc zazwyczaj mieści się w ramach kontraktu.

Co jest ciekawe… ok 30% ruchu zamyka się w plixie. Nawet trochę więcej.

PIX - jest malutki. poniżej 3% ruchu. Gdyby nie skala oraz fakt że jest prawie za darmo - nie było by go sensu trzymać.

HAWE i crowley - utrzymują się mniej więcej na zbliżonym poziomie - przerzucanie to głównie zmiany na ich upstreamach oraz “rzucanie” nimi (prepend przez community) by przerzucić na łącze gdzie dalej od kontraktu.

Przez jakiś czas była testowana tpsa. I tutaj niespodzianka - download był ledwo w okolicach 5% sumarycznego ruchu. Czyli - biorąc pod uwagę cenę - malutko. Z koleji upload to ok 20% ruchu - co w tej sytuacji oznaczało że było to jedyne łącze gdzie upload przekraczał download! I przypominam że to nie hosting, tylko głównie klienci indywidualni. Cóż - P2P rządzi.

February 17, 2011 11:59 AM

January 06, 2011

Dopierała Andrzej

2011-01-06 Konto w aliorbank: zakładanie konta w aliorbanku cz.1

Stwierdziłem że w mojej małej firemce przyda się kolejne konto. Obecne mam w mBanku, bo.. wiadomo - za darmo. No - prawie. 1zł za każdy przelew “na zewnątrz” - to już trochę w miesiącu wychodzi.

A Aliorbank ciągle kusi darmowym kontem, 5-cioma darmowymi przelewami w miesiącu i “premią” 50zł przy stanie konta 9k. Czyli więcej niż na lokacie w mbanku.

Z nowym rokiem - próbuję więc założyć konto.
Pierwsze wrażenia po przebrnięciu przez formularz?

  • Nie pozwala mi na wpisywanie polskich znaczków. Przeglądarka chrome. Po wklejeniu tekstu z polskimi znaczkami - ogonki znikają.
  • Do wybrania klasyfikacja usług… Ja w GUS-ie mam zgłoszoną 6202Z(działalność związana z doradztwem w zakresie informatyki - wg klasyfikacji z 2007 roku). A na stronie pozwalają na wybór pomiędzy.. 6201 a 6203.

Ale przebrnąłem - polskie znaczki jak sądzę poprawią mi w oddziale. O efektach pewnie poinformuję…

January 06, 2011 08:40 PM

October 16, 2010

Nawrot Andrzej

Rozmowy ze specjalistą ds. wdrożeń

Taki kwiatek.
Pytanie dotyczące odpowiedzialności za wykonywanie backupów pewnego systemu i odpowiedź konsultanta.

IT: Kto wykonuje backupy?

Specjalista:Backupy wykonuje MS SQL z automatu codziennie, raz na okres np. miesiąc kwartał baza powinna być nagrywana na trwały nośnik i to w zależności od firmy albo my albo dział IT
Danych nie powinniśmy stracić żadnych tylko w przypadku kataklizmu kiedy to stracimy serwer oraz kopie dyskowe – pozostaną nam tylko kopie na trwałych nośnikach, ale to sytuacje bardzo sporadyczna
Kopie na serwerze służą przede wszystkim do ewentualnych porównań w przypadku uszkodzenia – stąd codzienne kopie .

by jendras (noreply@blogger.com) at October 16, 2010 08:34 PM

June 08, 2010

Nawrot Andrzej

PowerShell via GPO

Aby zmienić ustawienia wykonywania skryptów potrzebujemy tego template'a.

http://www.microsoft.com/downloads/details.aspx?familyid=2917a564-dbbc-4da7-82c8-fe08b3ef4e6d&displaylang=en

by jendras (noreply@blogger.com) at June 08, 2010 08:29 AM

March 04, 2010

Nawrot Andrzej

Limit połączeń RDP

Ku pamięci

query session /server:servername


reset session [ID] /server:servername

by jendras (noreply@blogger.com) at March 04, 2010 02:17 PM

October 28, 2009

Nawrot Andrzej

Rodzinka w komplecie

 

Rodzinka w komplecie, brakuje tylko zniewiescialego SL :)
Posted by Picasa

by jendras (noreply@blogger.com) at October 28, 2009 10:08 PM

October 07, 2009

Najtkowski Marcin Jan

Dua Tonight

W trakcie nieustających muzycznych wojaży trafiłem znów na kawałek, którego słucham po kilkanaście-kilkadziesiąt razy dziennie. Kobiecy wokal – oczywiście, fajny, “chwytliwy” rytm oraz ogólna “sympatyczość” sprawiły, że Tonight zespołu Dua stał się moim numerem jeden ostatniego tygodnia.

<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" height="265" width="320"><param name="allowFullScreen" value="true"/><param name="allowscriptaccess" value="always"/><param name="src" value="http://www.youtube-nocookie.com/v/YIfJvPm9-rg&amp;hl=pl&amp;fs=1&amp;rel=0&amp;color1=0x3a3a3a&amp;color2=0x999999"/><param name="allowfullscreen" value="true"/><embed allowfullscreen="true" allowscriptaccess="always" height="265" src="http://www.youtube-nocookie.com/v/YIfJvPm9-rg&amp;hl=pl&amp;fs=1&amp;rel=0&amp;color1=0x3a3a3a&amp;color2=0x999999" type="application/x-shockwave-flash" width="320"></embed></object>

Utwór można znaleźć na A Lounge Supreme vol. 5.

by naytec at October 07, 2009 11:40 AM