Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Design a new source format (object representation and/or on-disk representation) #10

Open
simoncozens opened this issue Jan 27, 2021 · 156 comments

Comments

@simoncozens
Copy link
Owner

Ideas for hierarchy so far:
newsource

@alerque
Copy link

alerque commented Jan 27, 2021

Why have masters at all? I understand how they came to be historically and the case for instances (a set of static locations on axes) but if you're designing a new on-disk and object format, why not drop the charade and just go straight for glyphs? Each glyph would have control points that are not just a pair of coordinates but but vectors with enough values to locate them through each axis. Editors could use the instance location data to draw what people currently think of as "masters", but if you're coming up with a new model for holding the data I don't think dragging the current paradigm with you is necessary.

@simoncozens
Copy link
Owner Author

Interesting idea! I started to come up with reasons why not, but I'm not sure any of the reasons I have are valid. Going "variable first" has a lot of advantages, too. Hmm.

Also I'd like to hear any thoughts you have from your investigations on what makes a good version-control-aware on-disk format.

@schriftgestalt
Copy link

I think, the way you set up the masters (containing glyphs) are not useful. They are just some positions in the designspace that have some info attached (coordinates, vertical metrics …).

What you have as top level "glyphs" might be better called encoding. (Not sure why that should be in a different place than the outlines.)

Glyphs and layers should be its own thing. But have some connection to the masters (to get to the vertical metrics).

The idea of one set of control points with different coordinates for each point in the design space is bad. You need to be able to store incompatible outlines per glyphs. Not all font projects are variable fonts. There are color fonts, layer fonts, unfinished fonts.

One thing I never understood: AFAIK the default for an axis is where the outlines in the glyf table are? Then you NEED a proper master (meaning "master layer" aka a set of outlines/shapes) at that location. And what if you set the default in the axes and later move or remove that master? So in the font storage, you need to point to a master that is supposed to go into the glyf table and it's coordinates will be the default.

@florianpircher
Copy link

florianpircher commented Jan 27, 2021

I concur with @alerque in that masters are no longer needed and the “design space” should move into individual glyphs. Since this puts more information into each glyph, I think a glyph should have its own directory. Personally, I dislike the separation of layer in UFO. After working on a glyph, this is what a version control system shows for UFO:

modified:
L glyphs
  L e.glif
L glyphs.background
  L e.glif
L glyphs.some-layer
  L e.glif

whereas this feels more intuitive to me:

modified:
L glyphs
  L e
    L regular.glyph
    L regular-background.glyph
    L some-layer.glyph

There could also be space for a reserved Info file for general information about the glyph:

.
L glyphs
  L e
    L Info.plist
    L regular.glyph
    L regular-background.glyph
    L some-layer.glyph

@simoncozens
Copy link
Owner Author

I would really like to avoid a directory-based system, in favour of a single file, unless there are very strong arguments to do with version control. (And they have to be real arguments - not just that it looks prettier - because git is very good at merging files.)

@simoncozens
Copy link
Owner Author

simoncozens commented Jan 27, 2021

@schriftgestalt What would be the rationale for having layers be their own thing, rather than attached to glyphs (inside a master)?

I take your point about incompatible masters, which would make storing deltas impossible. For example, sometimes I have a “skeleton master” with open paths, and then extrude the paths to get the real masters. That wouldn’t work under a delta-only model.

@schriftgestalt
Copy link

schriftgestalt commented Jan 27, 2021

As a compromise, it could be one file per glyphs (including all its layers and meta data). But as I found out by adding a file format with a similar structure, you need to store the glyph order separately and that is again some data that can get out of sync.

One reason I added that format was to be able to only write changed glyphs. This is mostly relevant for very big files like CJK. Other than that, I totally prefer single files.

@schriftgestalt
Copy link

What would be the rationale for having layers be their own thing, rather than attached to glyphs (inside a master)?

I meant having glyphs and layers as one thing, outside of the masters.

@florianpircher
Copy link

A single-file system makes a lot of stuff more complicated in my experience. Want to hide certain aspects of the project from version control? Ignore the relevant file. (Thank again, @schriftgestalt <3)

Also, diffs become more difficult to render. Since CommitGlyphs does not (yet?) support the new .glyphspackage format I was looking into making my own glyphspackage GUI. One of the main problems is the interface for a diff. Because a modified .glyph files might have changes on one layer or on multiple layers it is difficult to tell which layers were added, which were deleted, and which were modified and how to present this to the user. Having layers separated by files offloaded that distinction to the VCS which is already equipped to present delete/add as rename if applicable, or to show adding a layer without marking the entire glyph as modified.

@florianpircher
Copy link

One reason I added that format was to be able to only write changed glyphs. This is mostly relevant for very big files like CJK. Other than that, I totally prefer single files.

That is a good point against my argument.

@simoncozens
Copy link
Owner Author

Designers should not be looking at raw diffs, so diff rendering is irrelevant. We can write tools to make things look nicer.

@alerque
Copy link

alerque commented Jan 27, 2021

I lean towards the more files is better than one approach. As you (Simon) say Git is really good at merging files, but people are not so good at keeping track of what is what, as Florian says it's hard to present that info in a UI, and they are harder to manipulate by hand. Taking the multiple file approach too far though is a disaster. With the concept of masters out of the way and just storing Glyphs, one file per glyph is a sweet spot. Georg is right this introduces the need for some ordering data that can get out of sync, but re-ordering something in a single file format is a nightmare for diff UIs compared to file based layouts.

What the data files looks like will have at least as big an effect on VCS systems as the file layout. Internally Git tracks blobs across files anyway, but understanding the difference between an addition, a removal, and a change is harder or easier based on the syntax. Git happens to be much better at linewise operations with relatively small amounts of data on each line, with some surrounding container syntax that makes blocks of related stuff easy to match even if everything in the block changes, but not so much that it becomes cruft.

@alerque
Copy link

alerque commented Jan 27, 2021

Designers should not be looking at raw diffs, so diff rendering is irrelevant. We can write tools to make things look nicer.

Yes and no. True designers shouldn't need to be viewing raw diffs, but how well current diff tooling can sort out the difference between adds/removes/changes and how well a programmer can read a diff is a pretty good proxy for how easy it is going to be to come up with visual tooling and a reliable UX that makes sense of the data.

@florianpircher
Copy link

Designers should not be looking at raw diffs, so diff rendering is irrelevant. We can write tools to make things look nicer.

Ideally, yes. In practice I still look at a lot of raw diffs, hb-shape ascii-diagrams, etc.

@simoncozens
Copy link
Owner Author

I meant having glyphs and layers as one thing, outside of the masters.

Yeah - but why? Why shouldn’t glyphs (the layer drawing part, not the common glyph metadata part) but attached to masters?

@simoncozens
Copy link
Owner Author

Hmmm, here's an idea:

newsource

This would (I think) allow you to have layer fonts / incomplete / non-interpolatable layers, but deltas within the interpolatable layers.

@florianpircher
Copy link

Maybe axis should also get a type field, indicating whether it is shared by all glyphs (similar to the current master model) or specific to a glyph/subset of glyphs (similar to Glyphs’s smart components). And maybe there are other type for axis for which it would be useful to have a separate type.

@florianpircher
Copy link

And maybe a type field is not the best solution. My concern is that in my projects I have many smart-component axes with the same name (width, ascent, …) but different min/max/default.

@simoncozens
Copy link
Owner Author

If the layer had a name, then there could be a set of axes defined for each named layer.

@florianpircher
Copy link

Every layer has a name. “Background”, “2021-01-27T23:10:58”, “Condensed”, “BoldDisplay”, “finalfinalfinalv5”. Or are you referring to a specific/format defined name?

@schriftgestalt
Copy link

In your new drawing, where to put vertical metrics?

And why not attache the glyphs to the masters? Each master would have a list of glyphs and to get to all relevant layers (to check compatibility or to interpolate) you need to go to each master, ask for its glyph for the glyph you are looking for (note: two times the same word for totally different things)

@schriftgestalt
Copy link

I don't understand the axis per named layer.
What could work is to have axes on the font level and on the glyph level. How those interact is a bit tricky (but it might be possible to append the glyph axis to the font axis).

@simoncozens
Copy link
Owner Author

We could handle vertical metrics the same way a binary font does: one place of metric metadata, with axis-specific variation store.

@simoncozens
Copy link
Owner Author

Showerthought: We are treating these questions (on disk representation, object hierarchy) as the same but we should address them separately. We might not want to store masters explicitly but we may still want to address them: font.masters[“Light”].capHeight is still a question we might need to answer - for example when converting to UFO.

@schriftgestalt
Copy link

I think we think of slightly different things when we speak about "Master". For me, the place to store axis-specific data is called masters.
Storing it as actual variation stored (as in the variable fonts) is impractical. At least if you store deltas and min/max/default values. That would again be too specific to variable fonts and as stated before, not all projects are variable fonts. And there might be no axes at all.

@schriftgestalt
Copy link

Finding a good structure should work for both the disk representation and the object model. There might be small differences here and there but the general structure should agree. that would be confusing for the user and would need a lot plumbing to read and write stuff.

@madig
Copy link

madig commented Jan 28, 2021

Regarding single file vs. directories: we found that git and single file are frequently problematic. Think of the amount of diffs generated by changing the color of a row of glyphs or renaming a component and how close these diffs can be to one another, making git consider them one hunk. Now throw in multiple designers changing stuff in different places and merging back and forth and you have a solid stream of merge conflicts on your hands (think Row hammer attack). With the amount of diffs a day of work can result in, designers usually give up and just merge everything. GUI tools would be nice but don't exist (GlyphMerge or whatsitcalled is buggy and unmaintained the last time I looked) and then someone has to maintain them. Partitioning glyphs into files is a blunt instrument, but it helps.

@simoncozens
Copy link
Owner Author

The solution to that is not necessarily to use the blunt instrument, but perhaps to think about what aspects of a font are normally changed together, and then arranging the file format to ensure they are in the same place.

@simoncozens
Copy link
Owner Author

(I'm not absolutely wedded to a single-file format, but I want to make sure we're fixing problems, not just applying band-aids to them.)

@alerque
Copy link

alerque commented Jan 28, 2021

Sometimes (not always, but I think in this case) the blunt instrument also makes a better building block for specialized tooling. If the heavy lifting is done you can work that into a friendly UX easier than if you have to muck around in roots of things.

The solution to that is not necessarily to use the blunt instrument, but perhaps to think about what aspects of a font are normally changed together, and then arranging the file format to ensure they are in the same place.

Yes, sort of. If A and B are changed together frequently, separating them from X and Y is a step in the right direction, but keeping A and B independent is even better. Not having changes to A touch B and making sure they are in different hunks is even better.

@simoncozens
Copy link
Owner Author

I think we need to distinguish between images and backgroundImages.

@schriftgestalt
Copy link

In Glyphs, the distinction between svg/sbix image and background images is done by setting a flag on the layer.

@simoncozens
Copy link
Owner Author

Ok. But background images and “foreground” images are sufficiently different things that I think it makes sense to separate them. And I’m not sure a flag on the layer is sufficiently general - obviously you can’t do this in Glyphs, but what if someone wanted both?

@simoncozens
Copy link
Owner Author

simoncozens commented Feb 5, 2021

  • I still don't know what the default in the axes meant for?

It's the "middle" of the variable font, and it creates the two mapping segments (min-default, default-max). See designspace files.

  • what about glyph.script and glyph.writingdirection

I don't think this is actually a meaningful concept in OpenType fonts. What is gained by saying that the letter A is actually RTL Adlam? The shaper's going to ignore you and look in the UCD.

And that makes me wonder about why we need to segment the kerning dictionary by direction, because the direction is determined by the inputs to the shaper, not by the font. Looking at the long threads on the UFO spec discussion, the consensus now seems to be "just store the kerns in visual order".

@schriftgestalt
Copy link

schriftgestalt commented Feb 5, 2021

My last comment was purely informational.

It's the "middle" of the variable font, and it creates the two mapping segments (min-default, default-max). See designspace files.

I know that. My question is why we need to store it with the axes. We need to define a default master (that is used to generate glyf table) anyway (and we dont’t what to imply the default master from the axis.default because that is almost certain not in sync). And if we have a default master, we just use its position as default for the axes. And you even might have export settings for subsetted variable fonts so there are different defaults (and even different min/max) values (so the those shouldn’t be stored, too).

@simoncozens
Copy link
Owner Author

I think one answer is that it just makes things easier; particularly compatibility with designspace-based workflows.

@schriftgestalt
Copy link

But what happens if you have min/default/max settings in your axis and no masters to fill up the space? You always have to compute the values anyway so why store them in the first place?

@simoncozens
Copy link
Owner Author

Because it does make things easier and improves compatibility with designspace-based workflows.

Glyphs is not the only font editor I want to support here.

@schriftgestalt
Copy link

I don't think this is actually a meaningful concept in OpenType fonts. What is gained by saying that the letter A is actually RTL Adlam? The shaper's going to ignore you and look in the UCD.

Because there might be alternate glyphs without an unicode and you need to know the direction in the editor. In Glyphs I don’t need those vales in the file but to support custom naming, it is useful to be able to store it in the file.

And that makes me wonder about why we need to segment the kerning dictionary by direction, because the direction is determined by the inputs to the shaper, not by the font. Looking at the long threads on the UFO spec discussion, the consensus now seems to be "just store the kerns in visual order".

Because you might want to put them in different lookup and you most certainly need different value records for RTL. And the handling of kerning classes are different. A RTL pair class pair is (visually) left class + (visually) right class. In LTR it is the other way around. It is indeed possible to infer most of it (as I did in Glyphs 2) but that is a mess. And there might be pairs that need different values for RTL than for LTR (punctuation).

And if you store the values "visually" you need to switch them back to string order on export. And so you still need to know if a pair is RTL or LTR.

So you either need the distinction while designing or on export.

@schriftgestalt
Copy link

Because it does make things easier and improves compatibility with designspace-based workflows.
Glyphs is not the only font editor I want to support here.

My question is not about Glyphs. I’m trying to understand how designspace-based workflows are supposed to work. Storing (and specially being able to manually set) min/default/max values per axis seems to me like storing the LSB/RSB with the file and expect it to be the values that are used.

@simoncozens
Copy link
Owner Author

simoncozens commented Feb 5, 2021

Because you might want to put them in different lookup and you most certainly need different value records for RTL.
So you either need the distinction while designing or on export.

Sure. I think it makes sense to separate data storage issues (expressing what you want to do) from export issues (working out how you do it). There's obvious a balance when designing file formats about how close to the export format you want to be. In cases like default axis location and vertical metrics, I've gone on the side of being friendly to export. But that's because adding those fields is relatively uncomplicated and doesn't add much space to the file.

Storing kerning direction is a different issue, though; it you either do it by adding four parallel structures, or tagging each kern pair with direction, neither of which is particularly pleasant if you don't need to do it, and is wasteful for the vast majority of fonts that don't have mixed direction kerning.

And I am not convinced that you do need to do it. What we want to be able to express is "these two glyphs should be brought n units together/apart". The second thread (particularly Bahman's example) shows that visual-left-to-right (and equivalent top-to-bottom) storage allows you to create the GPOS lookups you need on export from a single kerning dictionary.

The only edge case is when you want a different number of units for neutral characters based on the script direction. But I don't know if that's a real possibility or just a theoretical one.

@schriftgestalt
Copy link

I just reread that thread. That example makes look simple. And probably it is. I see one potential problem: How to determine what pairs will be duplicated in the RTL lookup? Just use all pairs that are only composed out of BIDI neutral glyphs (another reason to store script/direction per glyph)? That is convenient as you don’t need to kern them again for RTL but may add a lot pairs that are not needed.

And it is not wasteful or anything. So we need horizontal and vertical kerning for sure. Why not add RTL to make it clear? I don’t see a forth?

@simoncozens
Copy link
Owner Author

OK, so we either need to store direction per glyph or multiple kerning tables, but not both!

@schriftgestalt
Copy link

That direction bit in the glyph is used for different purposes. So I would recommend to keep it.

And determining what direction a pair belongs to can be hairy. It need to check all kerning classes and check the direction of all glyphs (again a great source of ambiguity (what if a class contains RTL and LTR and what if you have a LRT plus RTL pair)). Computing min/max values for the axes is a pice of cake in comparison and there your argument was to help the exporter?

@simoncozens
Copy link
Owner Author

simoncozens commented Feb 5, 2021

I hear what you're saying. I think what I'm going to do - because (from the UFO threads) this is a difficult issue - is assume for now that a single dictionary (plus a direction bit on the glyph) can do what we want. And then, when we have actual implementation examples, decide whether something else is necessary. We don't need to design everything up front, and in fact it's probably bad to decide everything up front before we have a working implementation.

@yarmola
Copy link

yarmola commented Feb 6, 2021

Is it about "minimal" data exchange format (similar to UFO) or something that should cover real source data? What I see on the latest diagram is not enough to cover our object model (which we store in VFJ). We can convert to it, but that will require a lot of compromises.

@simoncozens
Copy link
Owner Author

It would be ideal to support a subset of all real-world data. What's missing to support your model? (Note that all objects have an area to support format-specific information which other tools might not be interested in.)

@yarmola
Copy link

yarmola commented Feb 6, 2021

There are some things that we have (or want to) make different at the font/master level, but much more important is sub-layer part of the object model. We do something that is more like SVG (or, better COLRv1) structure which is layer > element > contour, with element containing all the "drawing" rules such as fill, stroke, clipping, effects (shadow, etc) and shape-building properties (if element is "open" so it should be embedded into the final contour).

Element may be defined at the layer level or outside it, then referenced from other layers (a bit similar to lookup/feature relationship in the OT layout definition). Elements may contain references to other elements (we use it to make "filter" elements and element groups).

It can be considered a terminology problem (so proposed "layer" is essentially is similar to our "element"), but then should be a way to specify layers hierarchy (so "Bold" layer/master may contain several layers/layer groups, like "serif"). Of course, our structure may be simplified to create the "final" contour, but that will make the format "export", not "source", at least for us.

Another part that needs to be clarified is a conception of the "value" (at many levels) that can be much more than simple int or float. Many "values" can be expressions, or delta arrays (or "master values" which is more or less the same).

Specification or layer/master horizontal metrics as "zero point" + advance width is OK for "export" but source format may be more flexible: both Glyphs and FL can specify any of LSB/RSB/AW values (as fixed numbers or complex expressions). That, in turn, opens a question of "measurement line": measurement of the SB values as distance from the bounding rectangle is not that effective (at the "source" level). Then italic comes, opening yet another box :).

There are some minor things (like missing "slant" value in the proposed transform structure), but that is less important.

Everything above may be a result of my misunderstanding of the original task: I probably mean something different by the "source" format: is it source as .glyphs or .vfj or source as DS+UFO when it is used to create final font with fontmake?

@simoncozens
Copy link
Owner Author

Thanks very much for the input!

I think the current layer model (including layerIndex and when combined with format-specific data) can do much of what you want, apart from referencing and reusing collections of shapes. I guess we could do that by having layers reference other layers by ID. Reusable layers seems like a good abstraction which we should include. Or maybe it is already possible by treating the referenced layers as smart components? I don't know. Maybe @schriftgestalt can weigh in.

Storing values as expressions is something that @alerque was interested in but we need to find a grammar to do that which would allow all implementations to turn those expressions back into a concrete value when needed. I'm not sure which values "under" a master would require delta arrays. Can you explain that a bit more?

To make the purpose clear, I think it is a little of both; my personal need is for an abstraction around "font source" to be used as input to Flux, but also to fontmake and other things which will eventually output font binaries. But if we can do this in a way that allows for the best possible interchange of multiple master fonts in source format between font editors, then that's an added bonus, and we may as well aim for it.

@yarmola
Copy link

yarmola commented Feb 6, 2021

Storing values as expressions is something that @alerque was interested in but we need to find a grammar to do that which would allow all implementations to turn those expressions back into a concrete value when needed.

I guess it should be both. Same is actually true for "delta exceptions" (where applicable).

Something like "987[=ascender+200]", so "simple" parsers will get current value while "source" data is also available. Same could work for complex element/layer architecture, which should provide "final" contours on top of the source+processing specification. Variable data (where needed) can be done the same way: "500['Bold'=700,'Narrow Light'=380]"

@simoncozens
Copy link
Owner Author

Some metrics in master are promoted to their own field, some need to resort to .otherMetrics. I would put everything into a metrics dictionary and have other metrics use the same format-specific encoding used elsewhere.

Having tried to implement the split fields-versus-dict thing, I have come to agree with this; digging in two different places for metrics is more tricky than I thought.

However, we do need standard format-independent names for common metrics.

@simoncozens
Copy link
Owner Author

Many "values" can be expressions, or delta arrays (or "master values" which is more or less the same).

@yarmola: What sort of values need to support expressions? e.g. do you want this for X and Y of points on a contour? (shiver) And I'm not sure where delta arrays are necessary when most values are related to a master somehow anyway.

(By the way, Glyphs provides a really useful example .glyphs source which demonstrates a lot of the more complex features of the file format. It's an extremely useful test case for implementors working on cross-format support! I wonder if FontLab has anything like this...)

like missing "slant" value in the proposed transform structure

I'm just going to a straightforward six-element affine transform now.

@yarmola
Copy link

yarmola commented Feb 10, 2021

What sort of values need to support expressions?

Eventually we want to make "everything" calculable, but you can imagine how complicated it is )) So for now we have expressions for metrics (LSB/RSB/AW), guides and anchors. We also have glyph-building recipes which may be considered "expressions", but at higher level.

We also have tags in glyphs, font guides (including zones and TT stems). Glyph tags do many things, tags in guides, etc allow to define "local" sets which appear only if there is an intersection with glyph tags (so many sets of zones is possible).

I'll make VFJ sample, but I need to address few issues first: we have "filters" — a kind of element that has some processing instructions instead of path definitions. PowerBrush, Bucket Fill and Glue are simple examples, but there are more. I need to provide "cache" copy of filter-generated paths in VFJ so you will not have to rebuild it. Same thing as the expressions syntax that I propose: "final" data + instructions.

I'm just going to a straightforward six-element affine transform now.

It is not that simple: if you have 2 rotate values, you can interpolate rotate value which is not the same as interpolating 2 linear matrices. (Imagine interpolating from +90 to -90). Currently we do simple affine transform, and it already is not fully compatible with newer specs such as COLRv1.

And I'm not sure where delta arrays are necessary when most values are related to a master somehow anyway.

This is the reality now. But if you look into future, there may be very good reasons to have delta values, first at font dimensions level (or in feature definitions), then at path level.

@simoncozens
Copy link
Owner Author

OK, I've started making the Python implementation document itself, including generating the object hierarchy diagrams:
https://simoncozens.github.io/babelfont/

@simoncozens
Copy link
Owner Author

Recently I have been fighting to get fontmake to handle Glyphs open corners, which is making me worry about something to do with this project: different font editors are extending the standard "list of Bezier curves" glyph model in various non-standard ways (open corners, corner/cap components, etc.) which require specialist knowledge and code to handle when converting between formats (especially to binary).

There are two ways to handle this:

  • Implementations export a standard, dumb "source format" without any of the clever tricks, meaning that the conversion is easier but information gets lost.
  • NFSF clients need to know about everyone's clever tricks, making conversion much, much harder but not losing any information.

Neither is good.

@schriftgestalt
Copy link

but the point of a library like this is to process font sources. And those will contain more and more custom stuff. So the question is not if option 1 or 2 but how do we make option 2 work without getting crazy.

@xorgy
Copy link

xorgy commented Mar 26, 2021

BTW, how would your format store https://twitter.com/justvanrossum/status/811481272333778944 and maybe even custom spacing at certain points in the designspace (I think Just had a problem like that but I can't find the issue)?

Maybe a composite of (possibly nonlinear) functions yielding matrices (linear). The functions can be cached/memoized, and in an editor application, the matrices can help backpropagate edits/inputs to the functions in a way that shouldn't be too unintuitive (i.e. by quantizing on the parameter space, or by inserting a control point in the function). Computing functions like this from masters is also feasible.

@simoncozens
Copy link
Owner Author

You're overthinking it.

https://twitter.com/simoncozens/status/1373175391133655041

@davelab6
Copy link

@simoncozens what are your latest thoughts on "masterless design" and a good source format for COLRv1?

@simoncozens
Copy link
Owner Author

I think that Babelfont format would work fine for masterless design, as layers can have a location. For full COLRv1 support, we would want to be storing the paint tree directly, so we need a serialization format for that.

@madig suggests that axes should be able to declare that they do not affect any advance widths.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests