Feeds

InternetDevels: More profits & less effort with Drupal multisite functionality

Planet Drupal - Fri, 2017-10-13 04:27

Here is another recipe for success. You can have a whole team of websites playing for you, and they don’t have to be created from scratch or managed separately. The secret lies in Drupal’s well-developed multisite functionality. Thanks to this, Drupal will not only let you leave your competitors behind, but also multiply this effect by many times.

Read more
Categories: FLOSS Project Planets

qutebrowser development blog: qutebrowser v1.0.0 released!

Planet Python - Fri, 2017-10-13 03:52

I'm delighted to announce that I just released qutebrowser v1.0.0!

qutebrowser is a keyboard driven browser with a vim-like, minimalistic interface. It's written using PyQt and cross-platform.

This release comes with many big breaking changes such as the new config and QtWebEngine by default, so please take a look at the changelog.

As announced previously, per-domain settings unfortunately didn't make it into v1.0.0 - it's the next thing I plan on tackling. However, there's more than enough big things in v1.0.0! :)

Enjoy!

edit: I just released v1.0.1 which fixes three bugs introduced in v1.0.0:

  • Fixed starting after customizing fonts.tabs or fonts.debug_console.
  • Fixed starting with old PyQt versions compiled against newer Qt versions.
  • Fixed check for PyQt version to correctly enforce 5.7 (not 5.2).

The full changelog for v1.0.0:

Major changes
  • Dependency changes:
    • Support for legacy QtWebKit (before 5.212 which is distributed independently from Qt) is dropped.
    • Support for Python 3.4 is dropped.
    • Support for Qt before 5.7.1 and PyQt before 5.7 is dropped.
    • New dependency on the QtSql module and Qt sqlite support.
    • New dependency on the attrs project (packaged as python-attr in some distributions).
    • The depedency on PyOpenGL (when using QtWebEngine) got removed. Note that PyQt5.QtOpenGL is still a dependency.
    • PyQt5.QtOpenGL is now always required, even with QtWebKit.
  • The QtWebEngine backend is now used by default. Note this means that QtWebEngine now should be a required dependency, and QtWebKit (if new enough) should be changed to an optional dependency.
  • Completely rewritten configuration system which ignores the old config file. See qute://help/configuring.html for details.
  • Various documentation files got moved to the doc/ subfolder; qutebrowser.desktop got moved to misc/.
  • :set now doesn't support toggling/cycling values anymore, that functionality got moved to :config-cycle.
  • New completion engine based on sqlite, which allows to complete the entire browsing history. The default for completion.web_history_max_items got changed to -1 (unlimited). If the completion is too slow on your machine, try setting it to a few 1000 items.
Added
  • QtWebEngine: Spell checking support, see the spellcheck.languages setting.
  • New qt.args setting to pass additional arguments to Qt/Chromium.
  • New backend setting to select the backend to use. Together with the previous setting, this should make most wrapper scripts unnecessary.
  • qutebrowser can now be set as the default browser on macOS.
  • New config commands:
    • :config-cycle to cycle an option between multiple values.
    • :config-unset to remove a configured option.
    • :config-clear to remove all configured options.
    • :config-source to (re-)read a config.py file.
    • :config-edit to open the config.py file in an editor.
    • :config-write-py to write a config.py template file.
  • New :version command which opens qute://version.
  • New back/forward indicator in the statusbar.
  • New bindings.key_mappings setting to map keys to other keys.
  • QtWebEngine: Support for proxy authentication.
Changed
  • Using :download now uses the page's title as filename.
  • Using :back or :forward with a count now skips intermediate pages.
  • When there are multiple messages shown, the timeout is increased.
  • :search now only clears the search if one was displayed before, so pressing <Escape> doesn't un-focus inputs anymore.
  • Pinned tabs now adjust to their text's width, so the tabs.width.pinned setting got removed.
  • :set-cmd-text now has a --run-on-count argument to run the underlying command directly if a count was given.
  • :scroll-perc got renamed to :scroll-to-perc.
Removed
  • Migrating QtWebEngine data written by versions before 2016-11-15 (before v0.9.0) is now not supported anymore.
  • Upgrading qutebrowser with a version older than v0.4.0 still running now won't work properly anymore.
  • The --harfbuzz and --relaxed-config commandline arguments got dropped.
Fixes
  • Exiting fullscreen via :fullscreen or buttons on a page now restores the correct previous window state (maximized/fullscreen).
  • When input.insert_mode.auto_load is set, background tabs now don't enter insert mode anymore.
  • The keybinding help widget now works correctly when using keybindings with a count.
  • The window.hide_wayland_decoration setting now works correctly again.
Categories: FLOSS Project Planets

Appnovation Technologies: A Homeowner's Guide to Drupal Security

Planet Drupal - Fri, 2017-10-13 03:00
A Homeowner's Guide to Drupal Security Working in our Managed Services department, we handle many Drupal 7 and 8 sites - all of which have one thing in common. Despite their different requirements, designs and content - they all need security updates applying and are all in need of some care and attention when it comes to securing them. If a Drupal site was a house: Securi...
Categories: FLOSS Project Planets

Norbert Preining: Scala: parse JSON into nested case classes

Planet Debian - Fri, 2017-10-13 01:24

I was playing around with parsing JSON in Scala, and got spray-json as recommendation from my Senpai. My aim was parsing some nested structure like:

{ "key1" : "value1", "key2" : { "subkey1" : "subval1", "subkey2" : "subval2" } }

into a nested Scala case class:

case class SubClass(subkey1: String, subkey2: String) case class MainClass(key1: String, key2: SubClass)


To achieve this one needs to define one’s own JsonProtocol that describes the parsing:

import spray.json._ object MyJsonProtocol extends DefaultJsonProtocol { implicit val subclassFormat = jsonFormat2(SubClass) implicit val mainclassFormat = jsonFormat2(MainClass) } import MyJsonProtocol._

Using this parsing can be done in the usual way:

val jsonstr = """ { "key1" : "value1", "key2" : { "subkey1" : "subval1", "subkey2" : "subval2" } } """ val jsonAst = jsonstr.parseJson val gotit = jsonAst.convertTo[MainClass]

If the input is from a JSON array of the above arrays:

[ { "key1" : "value1", "key2" : { "subkey1" : "subval1", "subkey2" : "subval2" } }, { "key1" : "value10", "key2" : { "subkey1" : "subval10", "subkey2" : "subval20" } } ]

the only change necessary is to call

val gotit = jsonAst.convertTo[List[MainClass]]
Categories: FLOSS Project Planets

Michal &#268;iha&#345;: Using Trezor to store cryptocurencies

Planet Debian - Fri, 2017-10-13 00:00

For quite some time I have some cryptocurrencies on hold. These mostly come from times it was possible to mine Bitcoin on the CPU, but I've got some small payments recently as well.

I've been using Electrum wallet so far. It worked quite well, but with increasing Bitcoin value, I was considering having some hardware wallet for that. There are few options which you can use, but I've always preferred Trezor as that device is made by guys I know. Also it's probably device with best support out of these (at least I've heard really bad stories about Ledger support).

In the end what decided is that they are also using Weblate to translate their user interface and offered me the wallet for free in exchange. This is price you can not beat :-). Anyway the setup was really smooth and I'm now fully set up. This also made me more open to accept other cryptocurrencies which are supported by Trezor, so you can now see more options on the Weblate donations page.

Filed under: Debian English SUSE Weblate

Categories: FLOSS Project Planets

Dirk Eddelbuettel: GitHub Streak: Round Four

Planet Debian - Thu, 2017-10-12 22:45

Three years ago I referenced the Seinfeld Streak used in an earlier post of regular updates to to the Rcpp Gallery:

This is sometimes called Jerry Seinfeld's secret to productivity: Just keep at it. Don't break the streak.

and showed the first chart of GitHub streaking

And two year ago a first follow-up appeared in this post:

And a year ago we had a followup last year

And as it October 12 again, here is the new one:

Again, special thanks go to Alessandro Pezzè for the Chrome add-on GithubOriginalStreak.

This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. Please report excessive re-aggregation in third-party for-profit settings.

Categories: FLOSS Project Planets

Mike Driscoll: How to Resize a Photo with Python

Planet Python - Thu, 2017-10-12 22:01

Sometimes you will find yourself wanting to resize a photo. I usually want to do this for photos that I want to email or post on a website since some of my images can be quite large. Normal people use an image editor. I usually do as well, but for fun I thought I would look into how to do it with the Python programming language.

The quickest way to do this is to use the Pillow package which you can install with pip. Once you have it, open up your favorite code editor and try the following code:

from PIL import Image   def resize_image(input_image_path, output_image_path, size): original_image = Image.open(input_image_path) width, height = original_image.size print('The original image size is {wide} wide x {height} ' 'high'.format(wide=width, height=height))   resized_image = original_image.resize(size) width, height = resized_image.size print('The resized image size is {wide} wide x {height} ' 'high'.format(wide=width, height=height)) resized_image.show() resized_image.save(output_image_path)   if __name__ == '__main__': resize_image(input_image_path='caterpillar.jpg', output_image_path='caterpillar_small.jpg', size=(800, 400))

Here we import the Image class from the PIL package. Next we have a function that takes 3 arguments: The location of the file we want to open, the location we want to save the resized image and a tuple that represents the new size the image should be where the tuple is the width and height respectively. Next we open our image and print out its size. Then we call the image object’s resize() method with the size tuple we passed in. Finally we grab the new siz, print it out and then show the image before saving the resized photo. Here is what it looks like now:

As you can see, the resize() method doesn’t do any kind of scaling. We will look t how to do that next!

Scaling an Image

Most of the time, you won’t want to resize your image like we did in the previous example unless you want to write a scaling method. The problem with the previous method is that it does not maintain the photo’s aspect ratio when resizing. So instead of resizing, you can just use the thumbnail() method. Let’s take a look:

from PIL import Image   def scale_image(input_image_path, output_image_path, width=None, height=None ): original_image = Image.open(input_image_path) w, h = original_image.size print('The original image size is {wide} wide x {height} ' 'high'.format(wide=w, height=h))   if width and height: max_size = (width, height) elif width: max_size = (width, h) elif height: max_size = (w, height) else: # No width or height specified raise RuntimeError('Width or height required!')   original_image.thumbnail(max_size, Image.ANTIALIAS) original_image.save(output_image_path)   scaled_image = Image.open(output_image_path) width, height = scaled_image.size print('The scaled image size is {wide} wide x {height} ' 'high'.format(wide=width, height=height))     if __name__ == '__main__': scale_image(input_image_path='caterpillar.jpg', output_image_path='caterpillar_scaled.jpg', width=800)

Here we allow the programmer to pass in the input and output paths as well as our max width and height. We then use a conditional to determine what our max size should be and then we call the thumbnail() method on our open image object. We also pass in the Image.ANTIALIAS flag which will apply a high quality down sampling filter which results in a better image. Finally we open the newly saved scaled image and print out its size to compare with the original size. If you open up the scaled image, you will see that the aspect ratio of the photo was maintained.

Wrapping Up

Playing around with the Pillow package is a lot of fun! In this article you learned how to resize an image and how to scale a photo while maintaining its aspect ratio. You can now use this knowledge to create a function that could iterate over a folder and create thumbnails of all the photos in that folder or you might create a simple photo viewing application where this sort of capability might be handy to have.

Related Reading

Categories: FLOSS Project Planets

Justin Mason: Links for 2017-10-12

Planet Apache - Thu, 2017-10-12 19:58
Categories: FLOSS Project Planets

FSF Blogs: Friday the 13th Free Software Directory IRC meetup: October 13th starting at 12:00 p.m. EDT/16:00 UTC

GNU Planet! - Thu, 2017-10-12 14:46

Participate in supporting the Directory by adding new entries and updating existing ones. We will be on IRC in the #fsf channel on irc.freenode.org.

Tens of thousands of people visit directory.fsf.org each month to discover free software. Each entry in the Directory contains a wealth of useful information, from basic category and descriptions, to providing detailed info about version control, IRC channels, documentation, and licensing info that has been carefully checked by FSF staff and trained volunteers.

While the Directory has been and continues to be a great resource to the world for over a decade now, it has the potential to be a resource of even greater value. But it needs your help!

This spooky week we'll be focusing on updating older entries. If an entry isn't kept up to date, it can become a zombie, bringing the overall quality of the Directory down. So we'll be focusing on resurrecting these old entries this Friday. Bring a good luck charm and a friend and help make the Directory even better!

If you are eager to help, and you can't wait or are simply unable to make it onto IRC on Friday, our participation guide will provide you with all the information you need to get started on helping the Directory today! There are also weekly Directory Meeting pages that everyone is welcome to contribute to before, during, and after each meeting.

Categories: FLOSS Project Planets

Friday the 13th Free Software Directory IRC meetup: October 13th starting at 12:00 p.m. EDT/16:00 UTC

FSF Blogs - Thu, 2017-10-12 14:46

Participate in supporting the Directory by adding new entries and updating existing ones. We will be on IRC in the #fsf channel on irc.freenode.org.

Tens of thousands of people visit directory.fsf.org each month to discover free software. Each entry in the Directory contains a wealth of useful information, from basic category and descriptions, to providing detailed info about version control, IRC channels, documentation, and licensing info that has been carefully checked by FSF staff and trained volunteers.

While the Directory has been and continues to be a great resource to the world for over a decade now, it has the potential to be a resource of even greater value. But it needs your help!

This spooky week we'll be focusing on updating older entries. If an entry isn't kept up to date, it can become a zombie, bringing the overall quality of the Directory down. So we'll be focusing on resurrecting these old entries this Friday. Bring a good luck charm and a friend and help make the Directory even better!

If you are eager to help, and you can't wait or are simply unable to make it onto IRC on Friday, our participation guide will provide you with all the information you need to get started on helping the Directory today! There are also weekly Directory Meeting pages that everyone is welcome to contribute to before, during, and after each meeting.

Categories: FLOSS Project Planets

Weekly Python Chat: Namespaces: one honking great idea

Planet Python - Thu, 2017-10-12 14:00

What does the word "namespace" mean? What are some examples of namespaces in Python and why are they such a "honking great idea"?

Categories: FLOSS Project Planets

Joachim Breitner: Isabelle functions: Always total, sometimes undefined

Planet Debian - Thu, 2017-10-12 13:54

Often, when I mention how things work in the interactive theorem prover Isabelle/HOL to people with a strong background in functional programming (whether that means Haskell or Coq or something else), I cause confusion, especially around the issue of what is a function, are function total and what is the business with undefined. In this blog post, I want to explain some these issues, aimed at functional programmers or type theoreticians.

Note that this is not meant to be a tutorial; I will not explain how to do these things, and will focus on what they mean.

HOL is a logic of total functions

If I have a Isabelle function f :: a ⇒ b between two types a and b (the function arrow in Isabelle is ⇒, not →), then – by definition of what it means to be a function in HOL – whenever I have a value x :: a, then the expression f x (i.e. f applied to x) is a value of type b. Therefore, and without exception, every Isabelle function is total.

In particular, it cannot be that f x does not exist for some x :: a. This is a first difference from Haskell, which does have partial functions like

spin :: Maybe Integer -> Bool spin (Just n) = spin (Just (n+1))

Here, neither the expression spin Nothing nor the expression spin (Just 42) produce a value of type Bool: The former raises an exception (“incomplete pattern match”), the latter does not terminate. Confusingly, though, both expressions have type Bool.

Because every function is total, this confusion cannot arise in Isabelle: If an expression e has type t, then it is a value of type t. This trait is shared with other total systems, including Coq.

Did you notice the emphasis I put on the word “is” here, and how I deliberately did not write “evaluates to” or “returns”? This is because of another big source for confusion:

Isabelle functions do not compute

We (i.e., functional programmers) stole the word “function” from mathematics and repurposed it1. But the word “function”, in the context of Isabelle/HOL, refers to the mathematical concept of a function, and it helps to keep that in mind.

What is the difference?

  • A function a → b in functional programming is an algorithm that, given a value of type a, calculates (returns, evaluates to) a value of type b.
  • A function a ⇒ b in math (or Isabelle/HOL) associates with each value of type a a value of type b.

For example, the following is a perfectly valid function definition in math (and HOL), but could not be a function in the programming sense:

definition foo :: "(nat ⇒ real) ⇒ real" where "foo seq = (if convergent seq then lim seq else 0)"

This assigns a real number to every sequence, but it does not compute it in any useful sense.

From this it follows that

Isabelle functions are specified, not defined

Consider this function definition:

fun plus :: "nat ⇒ nat ⇒ nat" where "plus 0 m = m" | "plus (Suc n) m = Suc (plus n m)"

To a functional programmer, this reads

plus is a function that analyses its first argument. If that is 0, then it returns the second argument. Otherwise, it calls itself with the predecessor of the first argument and increases the result by one.

which is clearly a description of a computation.

But to Isabelle/HOL, the above reads

plus is a binary function on natural numbers, and it satisfies the following two equations: …

And in fact, it is not so much Isabelle/HOL that reads it this way, but rather the fun command, which is external to the Isabelle/HOL logic. The fun command analyses the given equations, constructs a non-recursive definition of plus under the hood, passes that to Isabelle/HOL and then proves that the given equations hold for plus.

One interesting consequence of this is that different specifications can lead to the same functions. In fact, if we would define plus' by recursing on the second argument, we’d obtain the the same function (i.e. plus = plus' is a theorem, and there would be no way of telling the two apart).

Termination is a property of specifications, not functions

Because a function does not evaluate, it does not make sense to ask if it terminates. The question of termination arises before the function is defined: The fun command can only construct plus in a way that the equations hold if it can find a termination proof – very much like Fixpoint in Coq.

But while the termination check of Fixpoint in Coq is a deep part of the basic logic, in Isabelle it is simply something that this particular command requires. Other commands may have other means of defining a function that do not require a termination proof.

For example, a function specification that is tail-recursive can be turned in to a function, even without a termination proof: The following definition describes a higher-order function that iterates its first argument f on the second argument x until it finds a fixpoint. It is completely polymorphic (the single quote in 'a indicates that this is a type variable):

partial_function (tailrec) fixpoint :: "('a ⇒ 'a) ⇒ 'a ⇒ 'a" where "fixpoint f x = (if f x = x then x else fixpoint f (f x))"

We can work with this definition just fine. For example, if we instantiate f with (λx. x-1), we can prove that it will always return 0:

lemma "fixpoint (λ n . n - 1) (n::nat) = 0" by (induction n) (auto simp add: fixpoint.simps)

Similarly, if we have a function that works within the option monad (i.e. |Maybe| in Haskell), its specification can always be turned into a function without an explicit termination proof – here one that calculates the Collatz sequence:

partial_function (option) collatz :: "nat ⇒ nat list option" where "collatz n = (if n = 1 then Some [n] else if even n then do { ns <- collatz (n div 2); Some (n # ns) } else do { ns <- collatz (3 * n + 1); Some (n # ns)})"

Note that lists in Isabelle are finite (like in Coq, unlike in Haskell), so this function “returns” a list only if the collatz sequence eventually reaches 1.

I expect these definitions to make a Coq user very uneasy. How can fixpoint be a total function? What is fixpoint (λn. n+1)? What if we run collatz n for a n where the Collatz sequence does not reach 1?2 We will come back to that question after a little detour…

HOL is a logic of non-empty types

Another big difference between Isabelle and Coq is that in Isabelle/HOL, every type is inhabited. Just like the totality of functions, this is a very fundamental fact about what HOL defines to be a type.

Isabelle gets away with that design because in Isabelle, we do not use types for propositions (like we do in Coq), so we do not need empty types to denote false propositions.

This design has an important consequence: It allows the existence of a polymorphic expression that inhabits any type, namely

undefined :: 'a

The naming of this term alone has caused a great deal of confusion for Isabelle beginners, or in communication with users of different systems, so I implore you to not read too much into the name. In fact, you will have a better time if you think of it as arbitrary or, even better, unknown.

Since undefined can be instantiated at any type, we can instantiate it for example at bool, and we can observe an important fact: undefined is not an extra value besides the “usual ones”. It is simply some value of that type, which is demonstrated in the following lemma:

lemma "undefined = True ∨ undefined = False" by auto

In fact, if the type has only one value (such as the unit type), then we know the value of undefined for sure:

lemma "undefined = ()" by auto

It is very handy to be able to produce an expression of any type, as we will see as follows

Partial functions are just underspecified functions

For example, it allows us to translate incomplete function specifications. Consider this definition, Isabelle’s equivalent of Haskell’s partial fromJust function:

fun fromSome :: "'a option ⇒ 'a" where "fromSome (Some x) = x"

This definition is accepted by fun (albeit with a warning), and the generated function fromSome behaves exactly as specified: when applied to Some x, it is x. The term fromSome None is also a value of type 'a, we just do not know which one it is, as the specification does not address that.

So fromSome None behaves just like undefined above, i.e. we can prove

lemma "fromSome None = False ∨ fromSome None = True" by auto

Here is a small exercise for you: Can you come up with an explanation for the following lemma:

fun constOrId :: "bool ⇒ bool" where "constOrId True = True" lemma "constOrId = (λ_.True) ∨ constOrId = (λx. x)" by (metis (full_types) constOrId.simps)

Overall, this behavior makes sense if we remember that function “definitions” in Isabelle/HOL are not really definitions, but rather specifications. And a partial function “definition” is simply a underspecification. The resulting function is simply any function hat fulfills the specification, and the two lemmas above underline that observation.

Nonterminating functions are also just underspecified

Let us return to the puzzle posed by fixpoint above. Clearly, the function – seen as a functional program – is not total: When passed the argument (λn. n + 1) or (λb. ¬b) it will loop forever trying to find a fixed point.

But Isabelle functions are not functional programs, and the definitions are just specifications. What does the specification say about the case when f has no fixed-point? It states that the equation fixpoint f x = fixpoint f (f x) holds. And this equation has a solution, for example fixpoint f _ = undefined.

Or more concretely: The specification of the fixpoint function states that fixpoint (λb. ¬b) True = fixpoint (λb. ¬b) False has to hold, but it does not specify which particular value (True or False) it should denote – any is fine.

Not all function specifications are ok

At this point you might wonder: Can I just specify any equations for a function f and get a function out of that? But rest assured: That is not the case. For example, no Isabelle command allows you define a function bogus :: () ⇒ nat with the equation bogus () = S (bogus ()), because this equation does not have a solution.

We can actually prove that such a function cannot exist:

lemma no_bogus: "∄ bogus. bogus () = Suc (bogus ())" by simp

(Of course, not_bogus () = not_bogus () is just fine…)

You cannot reason about partiality in Isabelle

We have seen that there are many ways to define functions that one might consider “partial”. Given a function, can we prove that it is not “partial” in that sense?

Unfortunately, but unavoidably, no: Since undefined is not a separate, recognizable value, but rather simply an unknown one, there is no way of stating that “A function result is not specified”.

Here is an example that demonstrates this: Two “partial” functions (one with not all cases specified, the other one with a self-referential specification) are indistinguishable from the total variant:

fun partial1 :: "bool ⇒ unit" where "partial1 True = ()" partial_function (tailrec) partial2 :: "bool ⇒ unit" where "partial2 b = partial2 b" fun total :: "bool ⇒ unit" where "total True = ()" | "total False = ()" lemma "partial1 = total ∧ partial2 = total" by auto

If you really do want to reason about partiality of functional programs in Isabelle, you should consider implementing them not as plain HOL functions, but rather use HOLCF, where you can give equational specifications of functional programs and obtain continuous functions between domains. In that setting, ⊥ ≠ () and partial2 = ⊥ ≠ total. We have done that to verify some of HLint’s equations.

You can still compute with Isabelle functions

I hope by this point, I have not scared away anyone who wants to use Isabelle for functional programming, and in fact, you can use it for that. If the equations that you pass to `fun are a reasonable definition for a function (in the programming sense), then these equations, used as rewriting rules, will allow you to “compute” that function quite like you would in Coq or Haskell.

Moreover, Isabelle supports code extraction: You can take the equations of your Isabelle functions and have them expored into Ocaml, Haskell, Scala or Standard ML. See Concon for a conference management system with confidentially verified in Isabelle.

While these usually are the equations you defined the function with, they don't have to: You can declare other proved equations to be used for code extraction, e.g. to refine your elegant definitions to performant ones.

Like with code extraction from Coq to, say, Haskell, the adequacy of the translations rests on a “moral reasoning” foundation. Unlike extraction from Coq, where you have an (unformalized) guarantee that the resulting Haskell code is terminating, you do not get that guarantee from Isabelle. Conversely, this allows you do reason about and extract non-terminating programs, like fixpoint, which is not possible in Coq.

There is currently ongoing work about verified code generation, where the code equations are reflected into a deep embedding of HOL in Isabelle/HOL that would allow explicit termination proofs.

Conclusion

We have seen how in Isabelle/HOL, every function is total. Function declarations have equations, but these do not define the function in an computational sense, but rather specify them. Because in HOL, there are no empty types, many specifications that appear partial (incomplete patterns, non-terminating recursion) have solutions in the space of total functions. Partiality in the specification is no longer visible in the final product.

PS: Axiom undefined in Coq

This section is speculative, and an invitation for discussion.

Coq already distinguishes between types used in programs (Set) and types used in proofs Prop.

Could Coq ensure that every t : Set is non-empty? I imagine this would require additional checks in the Inductive command, similar to the checks that the Isabelle command datatype has to perform3, and it would disallow Empty_set.

If so, then it would be sound to add the following axiom

Axiom undefined : forall (a : Set), a.

wouldn't it? This axiom does not have any computational meaning, but that seems to be ok for optional Coq axioms, like classical reasoning or function extensionality.

With this in place, how much of what I describe above about function definitions in Isabelle could now be done soundly in Coq. Certainly pattern matches would not have to be complete and could sport an implicit case _ ⇒ undefined. Would it “help” with non-obviously terminating functions? Would it allow a Coq command Tailrecursive that accepts any tailrecursive function without a termination check?

  1. At least we do not violate this term as much as the imperative programmers do.

  2. Let me know if you find such an n. Besides n = 0.

  3. Like fun, the constructions by datatype are not part of the logic, but create a type definition from more primitive notions that is isomorphic to the specified data type.

Categories: FLOSS Project Planets

KDE Edu Sprint 2017

Planet KDE - Thu, 2017-10-12 12:59

Two weeks, two posts. Lets see how long I can keep up with this!

Last weekend I was part of the KDE Edu Sprint 2017 in the Endocode offices in Berlin, just a couple of days before the Qt World Summit, which was actually my first KDE Edu sprint (if you do not count Randa 2014). It was great as always to meet other KDE developers working on educational projects and I think we got a lot of work done.

While my primary focus going into the sprint was to work on macro support in Kig (there were many open bugs regarding macros), Aleix Pol's initial remarks helped me realize it was better to "take advantage of the fact that we were all at one place, and work on things you cannot do back home" so I decided to see what others were doing and try to help with that as well. Since Sandro Andrade was working on testing KDE Edu builds in Windows using Craft and I had been working on generating Craft recipes from Portage ebuilds, I finished a script that translates portage ebuilds from Gentoo's Portage tree into Craft recipes. This will automate low-hanging fruits like applications that basically only depend on KDE frameworks and Qt5 libraries. I committed this script to the development scripts repository in case someone finds them useful. It is a very experimental script so you are welcome to improve it!

In the meantime, while we waited for these Windows builds to happen, I did get a lot of work done on macro support in Kig. I implemented a feature that allows for creating macros without given objects and while at it, fixed several other issues regarding macros. Some of the changes are still being reviewed, but they all should land before Applications 17.12.

Since I obviously have no picture about my trip (I am terrible at taking pictures), I will shamelessly steal this one from Aleix's twitter post:



I want to thank the KDE e.V. for sponsoring my trip to this sprint, and Endocode for hosting us and giving us essential coffee for free. Also, big thanks to Free Software Foundation Europe for allowing me to visit their offices in the middle of a Monday while they were working hard to maintain software freedom in Europe.

Categories: FLOSS Project Planets

Texas Creative: Drupal and Wordpress and Joomla, Oh My!

Planet Drupal - Thu, 2017-10-12 12:32

Not all CMS are created equal. Before building your next website, here are a few tips on why your CMS choice matters. (Plot twist: as told by an Account Manager.)

Read More
Categories: FLOSS Project Planets

My first patch on Kate: Signals&Slots

Planet KDE - Thu, 2017-10-12 11:33

A while ago I started to use Kate's code as a base on Atelier. Since Kate uses KTextEditor API, and I need to use it, it was quite handy for me. With that in mind, I noted that all the Signals&Slots of Kate was on the following deprecated pattern of Qt4. With that kind of [...]


Categories: FLOSS Project Planets

Plasma 5.11 Release Party in Heidelberg

Planet KDE - Thu, 2017-10-12 11:00

Date: Friday, 3 November 2017
Time: 19:00
Place: Bier Brezel (sic), Hauptstraße 184, 69117 Heidelberg
Who: You! And fellow KDE developers and users
What we’re going to do: Have a few beers, a delicious dinner, talk, have fun, …

Please ping me, if you’re around and planning to come (contact info can be found in the Impressum, or tell kbroulik in #plasma on Freenode), so I can extend the reservation, if needed.

Categories: FLOSS Project Planets

Vardot: SEO Checklist Before Launching Your Drupal Website

Planet Drupal - Thu, 2017-10-12 10:11
SEO Checklist Before Launching Your Drupal Website Dmitrii Susloparov Thu, 10/12/2017 - 17:11

Search Engine Optimization (SEO) might not be the first thing you think of when designing a new website, but building an optimized framework from the start will help you drive traffic to your site and keep it there. With our Drupal SEO-checklist in hand you can build an excellent website that draws customers from launch day. Briefly speaking, here is a bullet list of what to check before the launch day. Below we’ll speak about each point in more detail.

 

  • Check that all web pages have unique titles using the Page Title module

  • Check if XML Sitemap and Google News Sitemap are configured properly

  • Check if Redirect module is enabled and configured

  • Check if Global Redirect module is enabled and configured

  • Check that .htaccess redirect to site with/without www

  • Check that the homepage title includes a slogan, and is descriptive for the function of the site

  • Check if Meta Tags is filled with descriptive information

  • Check that OG tags are filled correctly and with descriptive information.

  • Check if site's information appears well when shared on Facebook

  • Check if Path aliases patterns are meaningful

  • Check if Google Analytics is enabled and configured

  • Check if Page Title module is enabled and configured

  • Check if Google News Sitemap is enabled and configured

  • Check if Site verification is enabled and configured

  • Check if Search 404 module is enabled and configured

 

Drupal SEO: 12 Things that Will Improve Your Site's Ranking Check that all web pages have unique titles...

...and make sure to write them correctly. All of your pages should be easily identifiable to the end user. Not only should they have unique titles, they should have meaningful titles. Having multiple pages with the same titles (like “Get in touch”, “Contact us” and “Make a booking”) will simply confuse your end users and search engine crawlers.

 

Not only do good page titles help customers who are already on your site, but they help with social sharing, and picking your site out of search engine results. Titles are the first element that any user will see, whether they come directly to your site, find it in a search engine, or see it shared on social media.

 

Writing good titles is extremely important, and having keywords in your title that match a user's search greatly improves the chances of them clicking on your page.

 

Ensuring all your pages have a unique name will help users navigate, boost your SEO ratings, and increase the chances that someone will type the right keywords into a search engine to bring them to your site.

 

You can set up unique page titles much easier if you install the Drupal Page Title module.

10 Drupal Modules that Will Boost Your Website’s SEO

 

 

Check if XML Sitemap and Google News Sitemap are configured properly

The XML Sitemap module creates a robot friendly map of your site that Google and other search engines can crawl to categorise your website. There are a few settings you can alter for your site at admin/config/search/xmlsitemap and you can view the sitemap from http://yoursite.com/sitemap.xml.

 

You should configure XML Sitemap early in your site build for the best effect, but you can also alter the settings later on if needed.

 

Google News Sitemap offers a similar but different service that creates a Google specific map - as suggested in the name. These two modules work nicely side by side to make your site easy for search engines to crawl and index.

 

Please note that if your site contains AMPs, there is no need to create sitemaps for them. The rel=amphtml link is enough for Google to pick up on the accelerated mobile page version, which means you can easily gain traffic from Top Stories carousels and mobile search. Creating AMP on your Drupal site became easy with our step-by-step guide.

 

 

Check if Redirect module is enabled and configured

Redirect is a handy module for making sure users always make it to your site. It uses case-insensitive matching to help catch broken links with redirects and tracks how often users are hitting those redirects. You can use redirects to capture any broken links, set up promotional links, or simply capture typos users are entering when trying to access your site.

 

Check if Global Redirect module is enabled and configured

If you’re using Drupal 8 you can skip this one because the functionality has been rolled into the redirect module. Otherwise install Global Redirect to work in tandem with Redirect to catch any broken links. Global Redirect will test all links with and without a trailing slash, ensure links are case-insensitive and if a link is truly broken it will return a user to your home page, rather than an ugly 404 page that decrease the position of your site in SERPs.

Check that .htaccess redirects to site with/without www

Some users attempting to visit your site will navigate to www.yoursite.com, while others will simply type yoursite.com. By setting up your site to handle either request you can be sure you won’t miss any visitors.

 

 

Check that the homepage title includes a headline, logo and primary image and is descriptive for the function of the site

The headline as well as the slogan represent who you are as a business. Make your first impression a good one as this will also be visible on search engines. This is a good opportunity to stack your website with SEO friendly keywords, but don’t go overboard and sacrifice your image for it - keyword stuffing may not only decrease the trust index of your site, but also its conversion rates.

Ensure Metatags are filled with descriptive information

Writing SEO-optimized metatags is highly important, because they remain one of the top on-page ranking factors. Make sure to install the Metatag module on your site to have an easy, user friendly interface for updating metadata. With the module installed you can easily populate metadata with keywords, page descriptions, and more.

 

SEO tips for your Drupal site

 

The Metatag module will also give you extra control over how your site appears when shared on Twitter or Facebook.

Check that OG tags are filled correctly and with descriptive information.

OG tags are metatags specifically designed to ensure your site communicates nicely with Facebook. By setting these tags correctly you will be able to control exactly how your site appears on Facebook, including what images and what taglines are used.

Check if site's information appears well when shared on Facebook and Twitter

After configuring the metatag module and OG tags, pop over to Facebook and make sure that your site shares the way you would like it too. It’s important to test this out now before users start sharing your site around.

 

Similarly try tweeting a couple of your pages to see how well your Twitter Cards come through. If you don’t want to show your site to your audience until you are sure it is set up properly, you can check Twitter Cards using the Card Validator.

 

For more information on configuring Twitter cards, check out the Twitter user guides.

 

Check if Path aliases patterns are meaningful

By default Drupal will set your URLs to node/123 - while this works great for the database back end, it doesn’t work well for your end users, or for search engines.

 

You can use the Pathauto module to create rules and patterns for your URLs that will significantly cut down on your maintenance times and simplify your site navigation.

Check if Google Analytics is enabled and configured

While having Google Analytics configured won’t improve your SEO, it will give you all the data you need to understand where your users are coming from and how they behave once they hit your site.

 

Installing the Google Analytics module makes setting up and configuring Google Analytics a breeze.

Check if Site verification is enabled and configured

The Site verification module makes it easy to check the boxes that tell search engines that your site is truly yours. Having your site verified will improved how search engines crawl your site, and for Google will allow you to access private search data. With site verification you will receive better data and better search engine rankings for just a few minutes work.

 

Check if Search 404 module is enabled and configured

The Search 404 module is a saving grace for reducing your bounce rate, your SEO and improving your customer experience. Instead of your users finding an ‘Error: Page not Found” in place of the content they were hoping for, they will be offered a search of your site based on the URL string. For example if “www.yoursite.com/great-seo-tips” doesn’t exist, users this module will automatically search your site for ‘Great SEO tips” and show the users the results.

 

 

Bottom line

While SEO may seem like a tricky subject to wrap your head around, the basics are easy with the right modules and the right guidance. Drupal is a great content management system for building search engine optimized websites.

 

With our SEO checklist you can get off on the right foot, and here at Vardot we love educating our customers to build top quality websites. If you’re looking for even more ways to improve your sites SEO, have a look at SEO articles in our blog or get in touch with us.

Categories: FLOSS Project Planets

Lullabot: Incredible Decoupled Performance with Subrequests

Planet Drupal - Thu, 2017-10-12 09:52

In my previous post, Modern Decoupling is More Performant, we discussed how saving HTTP round-trips has a very positive impact on performance. In particular, we demonstrated how the JSON API module could help your application by returning multiple entities in a single request. Doing so eliminates the need for making an individual request per entity. However, this is only possible when fetching entities, not when writing data and only if those entities are related to the entry point (a particular entity or collection).

Sometimes you can solve this problem by writing a custom resource in the back-end every time, but that can lead to many custom resources, which impacts maintainability and is tiresome. If your API is public and you don’t have prior knowledge of what the consumers are going to do with it, it’s not even possible to write these custom endpoints.

The Subrequests module completes that idea by allowing ANY set of requests to be aggregated together. It can aggregate them even when one of them depends on a previous response. The module works with any request, it's not limited to REST or any other constraint. For simplicity, all the examples here will make requests to JSON API.

Why Do We Need It?

The main concept of the Subrequests module is that instead of sending multiple requests to your Drupal instance we will only send a single request. In this master request, we will provide the information about the requests we need to make in a JSON document. We call this document blueprint.

A blueprint is a JSON document containing the instructions for Drupal to make all those requests in our name. The blueprint document contains a list of subrequest objects. Each subrequest object contains the information about a single request being aggregated in the blueprint.

Imagine that our consumer application has a decoupled editorial interface. This editorial interface contains a form to create an article. As part of the editorial experience, we want the form to create the article and a set of tags in the Drupal back-end.

Without using Subrequests, the consumer application should execute the following requests when the form is submitted:

  • Query Drupal to find the UUID for the tags vocabulary.
  • Query Drupal to find the UUID of the user, based on the username present in the editorial app.
  • Create the first tag in the form using the vocabulary UUID.
  • Create the second tag in the form using the vocabulary UUID.
  • Create the article in the form using the user UUID and the newly created tags.

We can query for the user and the vocabulary in parallel. Once that is done, and using the information in the vocabulary response, we can create the tag entities. Once those are created, we can finally create the article. In total, we would be making five requests at three sequential levels. And, this is not even a complex example!

undefined

A JavaScript pseudo-code for the form submission handler could look like:

console.log('Article creation started…'); Promise.all([ httpRequest('GET', 'https://cms.contentacms.io/api/vocabularies?filter[vid-filter][condition][path]=vid&filter[vid-filter][condition][value]=tags'), httpRequest('GET', 'https://cms.contentacms.io/api/users?filter[admin][condition][path]=name&filter[admin][condition][value]=admin'), ]) .then(res => { const [vocab, user] = res; return Promise.all([ Promise.resolve(user), httpRequest('POST', 'https://cms.contentacms.io/api/tags', bodyForTag1, headers), httpRequest('POST', 'https://cms.contentacms.io/api/tags', bodyForTag2, headers), ]) }) .then(res => { const [user, tag1, tag2] = res; const body = buildBodyForArticle(formData, user, tag1, tag2); return httpRequest('POST', 'https://cms.contentacms.io/api/articles', body, headers); }) .then(() => { console.log('Article creation finished!'); }); Using Subrequests

Our goal is to have JavaScript pseudo-code that looks like:

console.log('Article creation started…'); const blueprint = buildBlueprint(formData); httpRequest('POST', 'https://cms.contentacms.io/api/subrequests?_format=json', blueprint, headers) .then(() => { console.log('Article creation finished!'); });

We've reduced our application code to a single POST request that contains a blueprint in the request body. We have reduced the problem to the blueprint creation. That is a big improvement in the developer experience of consumer applications.

undefined Parallel Requests

In our current task we need to perform two initial HTTP requests that can be run in parallel:

  • Query Drupal to find the UUID for the tags vocabulary.
  • Query Drupal to find the UUID of the user based on the username in the editorial app.

That translates to the following blueprint:

[ { "requestId": "vocabulary", "action": "view", "uri": "/api/vocabularies?filter[vid-filter][condition][path]=vid&filter[vid-filter][condition][value]=tags", "headers": ["Accept": "application/vnd.application+json"] }, { "requestId": "user", "action": "view", "uri": "/api/users?filter[admin][condition][path]=name&filter[admin][condition][value]=admin", "headers": ["Accept": "application/vnd.application+json"] } ]

For each subrequest, we can observe that we are providing four keys:

  • requestId A string used to identify the subrequest. This is an arbitrary value generated by the consumer application.
  • action Identifies the action being performed. A "view" action will generate a GET request. A "create" action will generate a POST request, etc.
  • uri The URL where the subrequest will be sent .
  • headers An object containing the headers specific for this subrequest.

The response to this blueprint (after adjusting the permissions in Drupal to view users and vocabularies) will return the response to both subrequests:

{ "vocabulary": { "headers": { "content-id": ["<vocabulary>"], "status": [200] }, "body": "{\"data\":[{\"type\":\"vocabularies\",\"id\":\"47ce8895-0df6-44a4-af43-9ef3b2a924dd\",\"attributes\":{\"status\":true,\"dependencies\":{\"module\":[\"recipes_magazin\"]},\"_core\":\"HJlsFfKP4PFHK1ub6QCSNFmzAnGiBG7tnx53eLK1lnE\",\"name\":\"Tags\",\"vid\":\"tags\",\"description\":\"Use tags to group articles on similar topics into categories.\",\"hierarchy\":0,\"weight\":0},\"links\":{\"self\":\"http:\\/\\/localhost\\/api\\/vocabularies\\/47ce8895-0df6-44a4-af43-9ef3b2a924dd\"}}],\"links\":{\"self\":\"http:\\/\\/localhost\\/api\\/vocabularies?filter%5Bvid-filter%5D%5Bcondition%5D%5Bpath%5D=vid\\u0026filter%5Bvid-filter%5D%5Bcondition%5D%5Bvalue%5D=tags\"}}" }, "user": { "headers": { "content-id": ["<user>"], "status": [200] }, "body": "{\"data\":[{\"type\":\"users\",\"id\":\"a0b7af80-e319-4271-899f-f151d3fbfc8e\",\"attributes\":{\"internalId\":1,\"name\":\"admin\",\"mail\":\"admin@example.com\",\"timezone\":\"Europe\\/Madrid\",\"isActive\":true,\"createdAt\":\"2017-09-15T15:47:26+0200\",\"updatedAt\":\"2017-09-15T20:06:15+0200\",\"access\":1505565434,\"lastLogin\":\"2017-09-15T20:06:07+0200\"},\"relationships\":{\"roles\":{\"data\":[]}},\"links\":{\"self\":\"http:\\/\\/localhost\\/api\\/users\\/a0b7af80-e319-4271-899f-f151d3fbfc8e\"}}],\"links\":{\"self\":\"http:\\/\\/localhost\\/api\\/users?filter%5Badmin%5D%5Bcondition%5D%5Bpath%5D=name\\u0026filter%5Badmin%5D%5Bcondition%5D%5Bvalue%5D=admin\"}}" } }

In the (simplified) response above we can see that for each subrequest, we have one key in the response object. That key is the same as our requestId in the blueprint. Each one of the subresponses contains the information about the response headers and the response body. Note how the response body is an escaped JSON object.

This blueprint is not sufficient to create an article with two tags, but it's a great start. Let's build on top of that to create the tags and the article.

Dependent Requests

The next task we need to execute is the creation of the two tag entities:

  • Create the first tag in the form using the vocabulary UUID.
  • Create the second tag in the form using the vocabulary UUID.

To do this, we will need to expand the blueprint. However, we don't know the vocabulary UUID at the time we are writing the blueprint. What we do know is that the vocabulary UUID will be in the subresponse to the vocabulary subrequest. In particular, we can find the UUID in data[0].id.

We will use that information to create a blueprint that can create tags. Since we don't know the actual value of the vocabulary UUID, we will use a replacement token. At some point, during the blueprint processing by Drupal, the token will be resolved to the actual UUID value.

Replacement Tokens

We can use replacement tokens anywhere in the body or the URI of our subrequests. For those to be resolved, a token needs to be formatted in the following way:

{{<requestId>.<"body"|"headers">@<json-path-expression>}}

In particular, the replacement token for our vocabulary UUID will be:

{{vocabulary.body@$.data[0].id}}

What this replacement says is:

  1. Use the subresponse for the vocabulary subrequest.
  2. Take the body from that subresponse.
  3. Extract the string under data[0].id, by executing the JSON Path expression $.data[0].id. You can execute any JSON Path expression as long as it returns a string. JSON Path is a very powerful way to extract data from an arbitrary JSON object, in our case the body in subresponse to the vocabulary subrequest.

This is what our blueprint looks like after adding the subrequests to create the tag entities. Note the presence of the replacement tokens:

[ { "requestId": "vocabulary", "action": "view", "uri": "/api/vocabularies?filter[vid-filter][condition][path]=vid&filter[vid-filter][condition][value]=tags", "headers": {"Accept": "application/vnd.api+json"} }, { "requestId": "user", "action": "view", "uri": "/api/users?filter[admin][condition][path]=name&filter[admin][condition][value]=admin", "headers": {"Accept": "application/vnd.api+json"} }, { "action": "create", "requestId": "tags-1", "body": "{\"data\":{\"type\":\"tags\",\"attributes\":{\"name\":\"My First Tag\"},\"relationships\":{\"vocabulary\":{\"data\":{\"type\":\"vocabularies\",\"id\":\"{{vocabulary.body@$.data[0].id}}\"}}}}}", "uri": "/api/tags", "headers": {"Content-Type": "application/vnd.api+json"}, "waitFor": ["vocabulary"] }, { "action": "create", "requestId": "tags-2", "body": "{\"data\":{\"type\":\"tags\",\"attributes\":{\"name\":\"My Second Tag\",\"description\":null},\"relationships\":{\"vocabulary\":{\"data\":{\"type\":\"vocabularies\",\"id\":\"{{vocabulary.body@$.data[0].id}}\"}}}}}", "uri": "/api/tags", "headers": {"Content-Type": "application/vnd.api+json"}, "waitFor": ["vocabulary"] } ]

Note that to use a replacement token in a subrequest, we need to add a dependency on the subresponse that contains the information. That's why we added the waitFor key in our tag subrequests.

Finishing the Blueprint undefined

Using the same principles that we used for the tags we can add the subrequest for:

  • Create the article in the form using the user UUID and the newly created tags.

That will leave our completed blueprint as:

[ { "requestId": "vocabulary", "action": "view", "uri": "/api/vocabularies?filter[vid-filter][condition][path]=vid&filter[vid-filter][condition][value]=tags", "headers": {"Accept": "application/vnd.api+json"} }, { "requestId": "user", "action": "view", "uri": "/api/users?filter[admin][condition][path]=name&filter[admin][condition][value]=admin", "headers": {"Accept": "application/vnd.api+json"} }, { "action": "create", "requestId": "tags-1", "body": "{\"data\":{\"type\":\"tags\",\"attributes\":{\"name\":\"My First Tag\"},\"relationships\":{\"vocabulary\":{\"data\":{\"type\":\"vocabularies\",\"id\":\"{{vocabulary.body@$.data[0].id}}\"}}}}}", "uri": "/api/tags", "headers": {"Content-Type": "application/vnd.api+json"}, "waitFor": ["vocabulary"] }, { "action": "create", "requestId": "tags-2", "body": "{\"data\":{\"type\":\"tags\",\"attributes\":{\"name\":\"My Second Tag\",\"description\":null},\"relationships\":{\"vocabulary\":{\"data\":{\"type\":\"vocabularies\",\"id\":\"{{vocabulary.body@$.data[0].id}}\"}}}}}", "uri": "/api/tags", "headers": {"Content-Type": "application/vnd.api+json"}, "waitFor": ["vocabulary"] }, { "action": "create", "requestId": "article", "headers": {"Content-Type": "application/vnd.api+json"}, "body": "{\"data\":{\"type\":\"articles\",\"attributes\":{\"body\":\"Custom value\",\"default_langcode\":\"1\",\"langcode\":\"en\",\"promote\":\"1\",\"status\":\"1\",\"sticky\":\"0\",\"title\":\"Article Created via Subrequests!\"},\"relationships\":{\"tags\":{\"data\":[{\"id\":\"{{tags-1.body@$.data.id}}\",\"type\":\"tags\"},{\"id\":\"{{tags-2.body@$.data.id}}\",\"type\":\"tags\"}]},\"type\":{\"data\":{\"id\":\"article\",\"type\":\"contentTypes\"}},\"owner\":{\"data\":{\"id\":\"{{user.body@$.data[0].id}}\",\"type\":\"users\"}}}}}", "uri": "/api/articles", "waitFor": ["user", "tags-1", "tags-2"] } ] More Powerful Replacements

Imagine that instead of creating an article for a single user, we wanted to create an article for each one of the users on the site. We cannot write a simple blueprint, like the one above, since we don't know how many users there are in the Drupal site. Hence, we cannot write an article creation subrequest for each user.

To solve this problem we can tweak the user subrequest, so instead of returning a single user it returns all the users in the site:

[ … { "requestId": "user", "action": "view", "uri": "/api/users", "headers": {"Accept": "application/vnd.api+json"} }, … ]

Then in our replacement tokens, we can write a JSON Path expression that will return a list of user UUIDs, instead of a single string. Subrequests will accept JSON Path expressions that return either strings or an array of strings for the replacement tokens.

In our article creation subrequest we will need to change {{user.body@$.data[0].id}} by {{user.body@$.data[*].id}}. The Subrequests module will create a duplicate of the article subrequest for each replacement item. In our case this will have the effect of having a copy of the article creation subrequest per each available user in the user subresponse.

The Final Response

The modified blueprint that generates one article per user will have a response like:

undefined

We can see how a single subrequest can generate n subresponses, and we can use each one of those to generate n other subresponses, etc. This highlights how powerful this technique is. In addition, we have seen that we can combine different type of operations. In our example, we mixed GET and POST in a single blueprint (to get the vocabulary and create the new tags).

Conclusion

Sub requests is a great way to fetch or write many resources in a single HTTP request. This allows us to improve performance significantly while maintaining almost the same flexibility that custom code provides.

Further Your Understanding

If you want to know more about the blueprint format you can read the specification. The Subrequests module comes with a JSON schema that you can use to validate your blueprint. You can find the schema here.

The hero image was downloaded from Frankenphotos and use without modifications with a CC BY 3.0 license.

Categories: FLOSS Project Planets

Mediacurrent: Webinar Recap: Security by Design - An Introduction to Drupal Security

Planet Drupal - Thu, 2017-10-12 09:29

With cybercrime on the rise, securing data in Drupal has become a hot topic for developers and project stakeholders alike.

In our latest webinar, we were joined by three Drupal security experts from Townsend Security, Lockr and Mediacurrent who shared their approach for building a secure groundwork to protect site data in Drupal.

Categories: FLOSS Project Planets

Qt Creator 4.5 Beta released

Planet KDE - Thu, 2017-10-12 07:03

We are happy to announce the release of Qt Creator 4.5 Beta!

There has been very little time between the 4.4 release and the 4.5 feature freeze, but 4.5 still comes with a bunch of very nice improvements.

Locator now does fuzzy camel case matching in the same way as code completion does. Type “c andesu” in locator to open the “AndroidDebugSupport” class.

We started on making the File System navigation pane more useful. It is showing a file system tree now, and you can select the root directory from a list containing the “computer” root, your home directory, your default projects directory, and the base directories of all the projects you have open in Qt Creator. More features are to come in the future.

The configuration UI for CMake projects improved. We added grouping of configuration variables, and the option to change their type, so you can set variables to arbitrary values even if CMake reports the wrong type for them.

For a more complete list of fixes and improvements see our change log.

Get Qt Creator 4.5 Beta

The opensource version is available on the Qt download page, and you find commercially licensed packages on the Qt Account Portal. Qt Creator 4.5 Beta is also available under Preview > Qt Creator 4.5.0-beta1 in the online installer. Please post issues in our bug tracker. You can also find us on IRC on #qt-creator on chat.freenode.net, and on the Qt Creator mailing list.

The post Qt Creator 4.5 Beta released appeared first on Qt Blog.

Categories: FLOSS Project Planets
Syndicate content