Spotify1 ondersteunt al een paar jaar een manier om makkelijk content te delen door zogenaamde Spotify-codes2 te gebruiken voor liedjes, albums of afspeellijsten. Een Spotify-code ziet er een beetje uit als een mix van een klassieke barcode en een QR-code, en kan gescand worden om het corresponderende item te openen in de Spotify-app.
Elk item in de Spotify-catalogus heeft een unieke identificatiecode: een octaal getal dat bestaat uit 23 cijfers (0–7). Daarbij geldt dat het eerste en het laatste cijfer altijd 0 is (de kleinste waarde) en het twaalfde cijfer altijd 7 is (de grootste waarde).
Deze identificatiecodes worden grafisch voorgesteld als Spotify-codes die uit 23 verticale staafjes bestaan: één voor elk cijfer van de identificatiecode (van links naar rechts). Waar een klassieke barcode de dikte van de staafjes identificeert, speelt bij Spotify-codes de hoogte van de staafjes een rol. Er zijn dus acht verschillende hoogtes die corresponderen met de acht octale cijfers (0-7): de kortste staafjes stellen het cijfer 0 voor en de langste staafjes het cijfer 7.
Schrijf een bash shell script spotify-code waaraan een Spotify identificatiecode moet doorgegeven worden. Het script moet een grafische voorstelling van de identificatiecode in SVG-formaat uitschrijven naar stdout. Die voorstelling is enigszins gebaseerd op Spotify-codes, maar dan met een logo aan de rechtkant. Zo moet het script voor identificatiecode 00141367007723652304350 de volgende SVG-afbeelding uitschrijven (regels voor de 19 middelste staafjes zijn weggelaten):
<svg xmlns="http://www.w3.org/2000/svg" width="420" height="110" version="1.1">
<rect width="420" height="110" fill="black" rx="10" /> <rect width="10" height="20" x="10" y="45" fill="white" rx="5" /> <rect width="10" height="20" x="25" y="45" fill="white" rx="5" /> … <rect width="10" height="70" x="325" y="20" fill="white" rx="5" /> <rect width="10" height="20" x="340" y="45" fill="white" rx="5" /> <circle cx="385" cy="55" r="25" fill="white" /> <polygon points="375,70 400,55 375,40" fill="black" /> </svg>
Verderop3 bespreken we stap voor stap hoe deze SVG-afbeelding opgebouwd is, maar grafisch ziet ze er als volgt uit:
Het script moet de volgende opties ondersteunen:
optie -b <string>: gebruik de HTML-kleur4 die aan deze optie doorgegeven wordt als achtergrondkleur voor de afbeelding (standaardwaarde: black)
optie -f <string>: gebruik de HTML-kleur5 die aan deze optie doorgegeven wordt als voorgrondkleur voor de afbeelding (standaardwaarde: white)
optie -l: geef een logo (een cirkel met daarin een driehoek) weer aan de rechterkant van de afbeelding; standaard wordt er geen logo weergegeven
Het script moet voor de verwerking van de opties de flexibiliteit aan de dag leggen die gebruikelijk is bij Unix commando's: volgorde van opties speelt geen rol, opties kunnen samengenomen worden, argument bij een optie moet niet noodzakelijk van de optieletter gescheiden worden door witruimte, …. Daarnaast moet het script de volgende foutafhandeling voorzien:
als niet de gepaste opties doorgegeven worden (enkel ondersteuning voor de opties -b, -f en -l, waarbij verplicht een argument aan de opties -b en -f moet doorgegeven worden), dan moet het script een gepaste boodschap uitschrijven naar stderr en eindigen met exit status 1; het script moet niet expliciet controleren dat het argument dat aan de opties -b en -f doorgegeven wordt een geldige HTML-kleur voorstelt
als er niet juist één argument aan het script wordt doorgegeven, dan moet het script een gepaste boodschap uitschrijven naar stderr en eindigen met exit status 2
als het argument dat aan het script wordt doorgegeven geen geldige Spotify identificatiecode voorstelt (23 cijfers tussen 0–7 waarvan het eerste en laatste cijfer 0 zijn en het twaalfde cijfer 7 is), dan moet het script een gepaste boodschap uitschrijven naar stderr en eindigen met exit status 3
Scalable Vector Graphics (SVG) is een op XML6 gebaseerd bestandsformaat voor vectorafbeeldingen7, waarbij afbeeldingen tekstueel beschreven worden aan de hand van eenvoudige meetkundige bouwstenen zoals punten, lijnen, cirkels en veelhoeken.
Je moet geen SVG kennen om deze opgave op te lossen. We bespreken stap voor stap hoe de grafische voorstelling van een identificatiecode in SVG-formaat opgebouwd wordt op basis van een aantal sjablonen. Daarbij zullen we de variabele onderdelen van een sjabloon in het groen weergeven. Daar moet je dus zelf de juiste waarden invullen. Het is belangrijk dat elk sjabloon exact overgenomen wordt, zodat het resultaat dat het script uitschrijft precies overeenkomt met de beschreven specficatie.
De eerste regel van het SVG-bestand is een SVG start-tag:
<svg xmlns="http://www.w3.org/2000/svg" width="420" height="110" version="1.1">
Daarmee worden de breedte (width) en de hoogte (height) van de afbeelding ingesteld. Onze afbeeldingen hebben altijd een vaste hoogte van 110 pixels. Afbeeldingen zonder logo hebben een breedte van 360 pixels en afbeeldingen met een logo hebben een breedte van 420 pixels.
De tweede regel stelt de achtergrondkleur in door een afgeronde rechthoek (rect) te tekenen die even groot is als de volledige afbeelding. Hiervoor gebruiken we dit sjabloon:
<rect width="420" height="110" fill="black" rx="10" />De breedte (width) en hoogte (height) worden op dezelfde manier ingesteld als bij de eerste regel. De rechthoek wordt opgevuld (fill) met de achtergrondkleur.
Daarna volgen 23 regels die elk één staafje tekenen dat
correspondeert met het $$i$$-de cijfer $$c_i$$ van de identificatiecode
($$i = 0, 1, \ldots, 22$$). Hiervoor gebruiken we het volgende sjabloon om
een afgeronde rechthoek (rect) te tekenen:
<rect width="10" height="20" x="10" y="45" fill="white" rx="5" />
Elk staafje is 10 pixels breed (width). De variabele attributen van het staafje voor het $$i$$-de cijfer $$c_i$$ moeten op de volgende manier ingevuld worden:
height: de hoogte van het staafje is $$20 + 10 \times c_i$$ pixels; een staafje voor het cijfer 0 is bijvoorbeeld 20 pixels hoog en een staafje voor het cijfer 7 is 90 pixels hoog
x: de $$x$$-coördinaat van het staafje is $$10 + 15 \times i$$ pixels; het eerste (meest linkse) staafje heeft bijvoorbeeld $$x$$-coördinaat 10 pixels en het laatste (meeste rechtse) staafje heeft $$x$$-coördinaat 340 pixels
y: de $$y$$-coördinaat van het staafje is $$(110 - h) / 2$$ pixels, waarbij $$h$$ de hoogte van het staafje voorstelt (in pixels); een staafje voor het cijfer 0 heeft bijvoorbeeld $$y$$-coördinaat 45 pixels en een staafje voor het cijfer 7 heeft $$y$$-coördinaat 10 pixels
fill: het staafje wordt opgevuld met de voorgrondkleur
Daarna gebruiken we dit sjabloon van twee regels om het logo te tekenen (indien gewenst):
<circle cx="385" cy="55" r="25" fill="white" /> <polygon points="375,70 400,55 375,40" fill="black" />
Omdat er altijd 23 staafjes zijn, staat het logo altijd op een vaste plaats. De eerste regel van dit sjabloon tekent een cirkel (circle) die moet opgevuld (fill) worden met de voorgrondkleur. De tweede regel tekent een driehoek (polygon) die moet opgevuld (fill) worden met de achtergrondkleur.
Als laatste regel sluiten we de SVG-afbeelding af met een SVG stop-tag:
</svg>
Onderstaande voorbeeldsessie toont hoe het shell script spotify-code moet kunnen gebruikt worden. Het eerste commando genereert de SVG-afbeelding die we in de opgave als voorbeeld gebruikt hebben.
$ spotify-code -l 00141367007723652304350
<svg xmlns="http://www.w3.org/2000/svg" width="420" height="110" version="1.1">
<rect width="420" height="110" fill="black" rx="10" />
<rect width="10" height="20" x="10" y="45" fill="white" rx="5" />
<rect width="10" height="20" x="25" y="45" fill="white" rx="5" />
<rect width="10" height="30" x="40" y="40" fill="white" rx="5" />
<rect width="10" height="60" x="55" y="25" fill="white" rx="5" />
<rect width="10" height="30" x="70" y="40" fill="white" rx="5" />
<rect width="10" height="50" x="85" y="30" fill="white" rx="5" />
<rect width="10" height="80" x="100" y="15" fill="white" rx="5" />
<rect width="10" height="90" x="115" y="10" fill="white" rx="5" />
<rect width="10" height="20" x="130" y="45" fill="white" rx="5" />
<rect width="10" height="20" x="145" y="45" fill="white" rx="5" />
<rect width="10" height="90" x="160" y="10" fill="white" rx="5" />
<rect width="10" height="90" x="175" y="10" fill="white" rx="5" />
<rect width="10" height="40" x="190" y="35" fill="white" rx="5" />
<rect width="10" height="50" x="205" y="30" fill="white" rx="5" />
<rect width="10" height="80" x="220" y="15" fill="white" rx="5" />
<rect width="10" height="70" x="235" y="20" fill="white" rx="5" />
<rect width="10" height="40" x="250" y="35" fill="white" rx="5" />
<rect width="10" height="50" x="265" y="30" fill="white" rx="5" />
<rect width="10" height="20" x="280" y="45" fill="white" rx="5" />
<rect width="10" height="60" x="295" y="25" fill="white" rx="5" />
<rect width="10" height="50" x="310" y="30" fill="white" rx="5" />
<rect width="10" height="70" x="325" y="20" fill="white" rx="5" />
<rect width="10" height="20" x="340" y="45" fill="white" rx="5" />
<circle cx="385" cy="55" r="25" fill="white" />
<polygon points="375,70 400,55 375,40" fill="black" />
</svg>
$ echo $?
0
$ spotify-code -x 00141367007723652304350
Syntax: spotify-code [-b <color>] [-f <color>] [-l] ID
$ echo $?
1
$ spotify-code
Syntax: spotify-code [-b <color>] [-f <color>] [-l] ID
$ echo $?
2
$ spotify-code abcefghjklmnopqrstuvw
Syntax: spotify-code [-b <color>] [-f <color>] [-l] ID
$ echo $?
3