geordi 11.1.0 → 11.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 310a3633bce8944bb4c56987a2d12cf2ed69013ef978e91f48063acba801c634
4
- data.tar.gz: f5e53286619679e6b5c3f0e2439e5c7589ed7c2e2866c0078b51f056658cc3dd
3
+ metadata.gz: 777831ce74c67b2be9515af1f7d1ba265a7ff57b081d6b02252f573a313caaa7
4
+ data.tar.gz: 0a39b24e79c1fe603acee2e66445542cba13bf807419f18aa13edf64386d5705
5
5
  SHA512:
6
- metadata.gz: 692cd04428cdbc217969425a9c3fcc1ea62f95f0a0692aabec218afdb1b804c1e705a181f387c6ba581c5e3dc25acdb5a0485565571c73d7f33d4521629ce300
7
- data.tar.gz: 8f9c32e800de8532265c3b302bfd821c0a24295c55bfac166ddb1390a2a0e93fb15e6028d1a63526ec0fc8268b1a617687152d8a72055c75a0546f45fec292c4
6
+ metadata.gz: baea0e5dba392efd9a23d19ba910392567d37c5d9502a0adfa7e9cb7d45dadbfccff78abc4144863718fdeea2ffe1da0b076a275877ef0b82a463a7246328611
7
+ data.tar.gz: 68e5f0383171b8c1f8315e1c13828f9aa78f1e4c06b1e62df35e9f2519b0f0c78c66d07228da3c71e50c7eb3fe07ae14e7a4f9d31aedd652f960c5d8a00a3373
@@ -19,6 +19,8 @@ jobs:
19
19
  gemfile: Gemfile
20
20
  - ruby: 3.0.2
21
21
  gemfile: Gemfile
22
+ - ruby: 3.3.6
23
+ gemfile: Gemfile
22
24
  env:
23
25
  BUNDLE_GEMFILE: "${{ matrix.gemfile }}"
24
26
  steps:
data/CHANGELOG.md CHANGED
@@ -7,12 +7,24 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
7
7
 
8
8
  ### Compatible changes
9
9
 
10
+ - Add support for Ruby 3.3
11
+
10
12
  ### Breaking changes
11
13
 
12
- ## 11.1.0 2024-11-20
14
+
15
+ ## 11.2.0 2024-11-22
13
16
 
14
17
  ### Compatible changes
18
+ * Add support for default branches other than "master" (e.g. "main"). Will read
19
+ this information from `origin`.
20
+ * `geordi branch` will not fail if it can't determine local branches.
21
+ * Improved Linear issue menu: now includes the issue id, truncates long issue
22
+ titles and puts metadata last
23
+
15
24
 
25
+ ## 11.1.0 2024-11-20
26
+
27
+ ### Compatible changes
16
28
  * Skip `yarn install` for other package managers:
17
29
  * Before: Check for a `package.json`
18
30
  * After: Check for a `yarn.lock`
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- geordi (11.1.0)
4
+ geordi (11.2.1)
5
5
  thor (~> 1)
6
6
 
7
7
  GEM
@@ -63,7 +63,7 @@ GEM
63
63
  concurrent-ruby (~> 1.0)
64
64
  launchy (2.4.3)
65
65
  addressable (~> 2.3)
66
- method_source (1.0.0)
66
+ method_source (1.1.0)
67
67
  middleware (0.1.0)
68
68
  minitest (5.14.4)
69
69
  multi_test (0.1.2)
@@ -75,12 +75,12 @@ GEM
75
75
  middleware
76
76
  thor
77
77
  thread_safe
78
- pry (0.13.1)
78
+ pry (0.14.2)
79
79
  coderay (~> 1.1)
80
80
  method_source (~> 1.0)
81
- pry-byebug (3.9.0)
81
+ pry-byebug (3.10.1)
82
82
  byebug (~> 11.0)
83
- pry (~> 0.13.0)
83
+ pry (>= 0.13, < 0.15)
84
84
  public_suffix (3.1.1)
85
85
  rake (12.3.3)
86
86
  rspec (3.10.0)
@@ -119,4 +119,4 @@ DEPENDENCIES
119
119
  rspec
120
120
 
121
121
  BUNDLED WITH
122
- 2.3.25
122
+ 2.3.26
data/README.md CHANGED
@@ -1,5 +1,21 @@
1
- Geordi [![Tests](https://github.com/makandra/geordi/workflows/Tests/badge.svg)](https://github.com/makandra/geordi/actions)
2
- ======
1
+ <p>
2
+ <a href="https://makandra.de/">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: light)" srcset="media/makandra-with-bottom-margin.light.svg">
5
+ <source media="(prefers-color-scheme: dark)" srcset="media/makandra-with-bottom-margin.dark.svg">
6
+ <img align="right" width="25%" alt="makandra" src="media/makandra-with-bottom-margin.light.svg">
7
+ </picture>
8
+ </a>
9
+
10
+ <picture>
11
+ <source media="(prefers-color-scheme: light)" srcset="media/logo.light.shapes.svg">
12
+ <source media="(prefers-color-scheme: dark)" srcset="media/logo.dark.shapes.svg">
13
+ <img width="140" alt="Geordi" role="heading" aria-level="1" src="media/logo.light.shapes.svg">
14
+ </picture>
15
+ </p>
16
+
17
+ [![Tests](https://github.com/makandra/geordi/workflows/Tests/badge.svg)](https://github.com/makandra/geordi/actions)
18
+
3
19
 
4
20
  Geordi is a collection of command line tools we use in our daily work with
5
21
  Ruby, Rails and Linux at [makandra](http://makandra.com/).
@@ -32,7 +48,7 @@ On the first execution we ask for your Linear API token. It will be
32
48
  stored in `~/.config/geordi/global.yml`.
33
49
 
34
50
  **Options**
35
- - `-m, [--from-master], [--no-from-master]`: Branch from master instead of the current branch
51
+ - `-m, --from-main, [--from-master], [--no-from-master]`: Branch from master instead of the current branch
36
52
 
37
53
 
38
54
  ### `geordi capistrano COMMAND`
@@ -142,7 +158,8 @@ before it does it.** There are different scenarios where this command is handy:
142
158
  be skipped.
143
159
 
144
160
  Calling the command without arguments will infer the target stage from the
145
- current branch and fall back to master/staging.
161
+ current branch and fall back to master/staging. (Will use the actual main branch
162
+ of the repository, e.g. "main" instead of "master".)
146
163
 
147
164
  Finds available Capistrano stages by their prefix, e.g. `geordi deploy p` will
148
165
  deploy production, `geordi deploy mak` will deploy a `makandra` stage if there
@@ -267,29 +284,20 @@ variable like this: `PARALLEL_TEST_PROCESSORS=6 geordi rspec`
267
284
  Support for performing security updates.
268
285
 
269
286
  Preparation for security update: `geordi security-update`. Checks out production
270
- and pulls.
287
+ and pulls, and will tell each step before performing it.
271
288
 
272
- After performing the update: `geordi security-update finish`. Switches branches,
273
- pulls, pushes and deploys as required by our workflow.
274
-
275
- This command tells what it will do before it does it. In detail:
289
+ Part two after performing the update: `geordi security-update finish`. Switches
290
+ branches, pulls, pushes and deploys as required by our workflow. This as well
291
+ will tell each step before performing it. In detail:
276
292
 
277
293
  1. Ask user if tests are green
278
-
279
294
  2. Push production
280
-
281
295
  3. Check out master and pull
282
-
283
296
  4. Merge production and push in master
284
-
285
297
  5. Deploy staging, if there is a staging environment
286
-
287
298
  6. Ask user if deployment log is okay and staging application is still running
288
-
289
299
  7. Deploy other stages
290
-
291
300
  8. Ask user if deployment log is okay and application is still running on all stages
292
-
293
301
  9. Inform user about the next (manual) steps
294
302
 
295
303
 
@@ -6,7 +6,7 @@ On the first execution we ask for your Linear API token. It will be
6
6
  stored in `~/.config/geordi/global.yml`.
7
7
  LONGDESC
8
8
 
9
- option :from_master, aliases: '-m', type: :boolean, desc: 'Branch from master instead of the current branch'
9
+ option :from_master, aliases: %w[-m --from-main], type: :boolean, desc: 'Branch from master instead of the current branch'
10
10
 
11
11
  def branch
12
12
  require 'geordi/gitlinear'
@@ -19,7 +19,8 @@ before it does it.** There are different scenarios where this command is handy:
19
19
  be skipped.
20
20
 
21
21
  Calling the command without arguments will infer the target stage from the
22
- current branch and fall back to master/staging.
22
+ current branch and fall back to master/staging. (Will use the actual main branch
23
+ of the repository, e.g. "main" instead of "master".)
23
24
 
24
25
  Finds available Capistrano stages by their prefix, e.g. `geordi deploy p` will
25
26
  deploy production, `geordi deploy mak` will deploy a `makandra` stage if there
@@ -37,7 +38,7 @@ option :current_branch, aliases: '-c', type: :boolean,
37
38
 
38
39
  def deploy(target_stage = nil)
39
40
  # Set/Infer default values
40
- branch_stage_map = { 'master' => 'staging', 'production' => 'production' }
41
+ branch_stage_map = { 'master' => 'staging', 'main' => 'staging', 'production' => 'production' }
41
42
  if target_stage && !Util.deploy_targets.include?(target_stage)
42
43
  # Target stage autocompletion from available stages
43
44
  target_stage = Util.deploy_targets.find { |t| t.start_with? target_stage }
@@ -58,7 +59,10 @@ def deploy(target_stage = nil)
58
59
  source_branch = target_branch = Util.current_branch
59
60
  else
60
61
  source_branch = Interaction.prompt 'Source branch:', Util.current_branch
61
- target_branch = Interaction.prompt 'Deploy branch:', branch_stage_map.invert.fetch(target_stage, 'master')
62
+
63
+ deploy_branch = 'production' if target_stage == 'production'
64
+ deploy_branch ||= Util.git_default_branch
65
+ target_branch = Interaction.prompt 'Deploy branch:', deploy_branch
62
66
  end
63
67
 
64
68
  merge_needed = (source_branch != target_branch)
@@ -1,33 +1,16 @@
1
1
  desc 'security-update [STEP]', 'Support for performing security updates'
2
2
  long_desc <<-LONGDESC
3
3
  Preparation for security update: `geordi security-update`. Checks out production
4
- and pulls.
4
+ and pulls, and will tell each step before performing it.
5
5
 
6
- After performing the update: `geordi security-update finish`. Switches branches,
7
- pulls, pushes and deploys as required by our workflow.
8
-
9
- This command tells what it will do before it does it. In detail:
10
-
11
- 1. Ask user if tests are green
12
-
13
- 2. Push production
14
-
15
- 3. Check out master and pull
16
-
17
- 4. Merge production and push in master
18
-
19
- 5. Deploy staging, if there is a staging environment
20
-
21
- 6. Ask user if deployment log is okay and staging application is still running
22
-
23
- 7. Deploy other stages
24
-
25
- 8. Ask user if deployment log is okay and application is still running on all stages
26
-
27
- 9. Inform user about the next (manual) steps
6
+ Part two after performing the update: `geordi security-update finish`. Switches
7
+ branches, pulls, pushes and deploys as required by our workflow. This as well
8
+ will tell each step before performing it.
28
9
  LONGDESC
29
10
 
30
11
  def security_update(step = 'prepare')
12
+ master = Util.git_default_branch
13
+
31
14
  case step
32
15
  when 'prepare'
33
16
  Interaction.announce 'Preparing for security update'
@@ -56,11 +39,11 @@ def security_update(step = 'prepare')
56
39
  Interaction.note 'Working directory clean.'
57
40
  Interaction.prompt('Have you successfully run all tests?', 'n', /y|yes/) || Interaction.fail('Please run tests first.')
58
41
 
59
- Interaction.note 'About to: push production, checkout & pull master, merge production, push master.'
42
+ Interaction.note "About to: push production, checkout & pull #{master}, merge production, push #{master}."
60
43
  Interaction.prompt('Continue?', 'n', /y|yes/) || Interaction.fail('Cancelled.')
61
44
 
62
45
  Util.run!('git push', show_cmd: true)
63
- Util.run!('git checkout master', show_cmd: true)
46
+ Util.run!("git checkout #{master}", show_cmd: true)
64
47
  Util.run!('git pull', show_cmd: true)
65
48
  Util.run!('git merge production', show_cmd: true)
66
49
  Util.run!('git push', show_cmd: true)
@@ -106,5 +89,7 @@ def security_update(step = 'prepare')
106
89
  puts
107
90
  Interaction.note 'Now send an email to customer and project lead, informing them about the update.'
108
91
  Interaction.note 'Do not forget to make a joblog on a security budget, if available.'
92
+ else
93
+ Interaction.fail "Unsupported step #{step.inspect}"
109
94
  end
110
95
  end
@@ -31,11 +31,12 @@ module Geordi
31
31
  matching_local_branch = local_branches.find { |branch_name| branch_name == issue['branchName'] }
32
32
  matching_local_branch ||= local_branches.find { |branch_name| branch_name.include? issue['identifier'].to_s }
33
33
 
34
- if matching_local_branch.nil?
35
- Util.run! ['git', 'checkout', 'master'] if from_master
36
- Util.run! ['git', 'checkout', '-b', issue['branchName']]
37
- else
34
+ if matching_local_branch
38
35
  Util.run! ['git', 'checkout', matching_local_branch]
36
+ else
37
+ default_branch = Util.git_default_branch
38
+ Util.run! ['git', 'checkout', default_branch] if from_master
39
+ Util.run! ['git', 'checkout', '-b', issue['branchName']]
39
40
  end
40
41
  end
41
42
 
@@ -51,11 +52,7 @@ module Geordi
51
52
  `git branch --format="%(refname:short)"`
52
53
  end
53
54
 
54
- if branch_list_string.strip.empty?
55
- Interaction.fail 'Could not determine local Git branches.'
56
- end
57
-
58
- branch_list_string.split("\n")
55
+ branch_list_string.strip.split("\n")
59
56
  end
60
57
  end
61
58
 
@@ -64,42 +61,36 @@ module Geordi
64
61
  return dummy_issue_for_testing
65
62
  end
66
63
 
67
- loading_message = 'Connecting to Linear ...'
68
- print(loading_message)
69
64
  issues = fetch_linear_issues
70
- reset_loading_message = "\r#{' ' * (loading_message.length + issues.length)}\r"
71
-
72
65
  if issues.empty?
73
- print reset_loading_message
74
66
  Geordi::Interaction.fail('No issues to offer.')
75
67
  end
68
+ issues.sort_by! { |i| -i.dig('state', 'position') }
76
69
 
77
70
  highline.choose do |menu|
78
- menu.header = 'Choose an issue'
71
+ max_label_length = 60
72
+ menu.header = 'Choose a started issue (ordered by state)'
79
73
 
80
74
  issues.each do |issue|
75
+ id = issue['identifier']
76
+ title = issue['title']
81
77
  state = issue['state']['name']
82
- if issue['assignee']
83
- assignee = issue['assignee']['name']
84
- assignee_is_me = issue['assignee']['isMe']
85
- else
86
- assignee = "unassigned"
87
- assignee_is_me = false
88
- end
89
-
90
- state += HighLine::BOLD if assignee_is_me
78
+ assignee = issue.dig('assignee', 'displayName') || 'unassigned'
91
79
 
92
- label = "(#{assignee}, #{state}) #{issue['title']}"
93
- label = bold(label) if assignee_is_me
80
+ label = "[#{id}] #{title}"
81
+ label = "#{label[0..(max_label_length - 5)]} ..." if label.length > max_label_length
82
+ label = HighLine::BLUE + HighLine::BOLD + label + HighLine::RESET if issue.dig('assignee', 'isMe')
83
+ label = "#{label} (#{assignee} / #{state})"
94
84
 
95
85
  menu.choice(label) { return issue }
96
86
  end
97
87
 
98
88
  menu.hidden('') { Interaction.fail('No issue selected.') }
99
- print reset_loading_message # Once menu is build
100
89
  end
101
90
 
102
- nil # Return nothing
91
+ # Selecting an issue will return that issue. If we ever get here, return
92
+ # nothing
93
+ nil
103
94
  end
104
95
 
105
96
  def dummy_issue_for_testing
@@ -143,11 +134,12 @@ module Geordi
143
134
  url
144
135
  branchName
145
136
  assignee {
146
- name
137
+ displayName
147
138
  isMe
148
139
  }
149
140
  state {
150
- name
141
+ name
142
+ position
151
143
  }
152
144
  }
153
145
  }
@@ -159,11 +151,14 @@ module Geordi
159
151
 
160
152
  def query_api(attributes, variables)
161
153
  uri = URI(API_ENDPOINT)
154
+ loading_message = "Connecting to #{uri.host} ... "
155
+ clear_loading_message = "\r#{' ' * loading_message.length}\r"
162
156
 
157
+ print(loading_message)
163
158
  https = Net::HTTP.new(uri.host, uri.port)
164
159
  https.use_ssl = true
165
160
 
166
- query = [{ query: attributes.split.join(' '), variables: variables }].to_json
161
+ query = { query: attributes.split.join(' '), variables: variables }.to_json
167
162
 
168
163
  request = Net::HTTP::Post.new(uri.path)
169
164
  request.body = query
@@ -172,17 +167,22 @@ module Geordi
172
167
  request['Authorization'] = settings.linear_api_key
173
168
 
174
169
  response = https.request(request)
170
+ parsed_response = JSON.parse(response.body)
175
171
 
176
- parsed_response = JSON.parse(response.body)[0]
177
172
  if parsed_response.key?('errors')
178
- raise parsed_response.dig('errors')
173
+ errors = parsed_response['errors'].map do |error|
174
+ msg = error.delete('message')
175
+ "#{msg} #{error.inspect}"
176
+ end
177
+ Interaction.fail <<~MSG.strip
178
+ API request failed:
179
+ #{errors.join("\n")}
180
+ MSG
179
181
  else
180
- parsed_response['data']
182
+ print clear_loading_message
183
+ parsed_response.dig('data')
181
184
  end
182
185
  end
183
186
 
184
- def bold(string)
185
- HighLine::BOLD + string + HighLine::RESET
186
- end
187
187
  end
188
188
  end
@@ -57,6 +57,8 @@ module Geordi
57
57
  input = default if input.empty? && default
58
58
 
59
59
  agreement_regex ? !!(input =~ agreement_regex) : input
60
+ rescue Interrupt
61
+ fail 'Cancelled.'
60
62
  end
61
63
 
62
64
  end
@@ -62,8 +62,8 @@ module Geordi
62
62
 
63
63
  if team_ids.empty?
64
64
  Geordi::Interaction.warn 'No team id found.'
65
- Interaction.note 'Please open a team in Linear, open the command menu with CTRL + K and choose'
66
- Interaction.note "\"Copy model UUID\". Store that team id in #{LOCAL_SETTINGS_FILE_NAME}:"
65
+ puts 'Please open a team in Linear, open the command menu with CTRL + K and choose'
66
+ puts "\"Copy model UUID\". Store that team id in #{LOCAL_SETTINGS_FILE_NAME}:"
67
67
  puts 'linear_team_ids: abc-123-123-abc, def-456-456-def'
68
68
  exit 1
69
69
  end
@@ -110,7 +110,12 @@ module Geordi
110
110
  def save_global_settings
111
111
  global_path = GLOBAL_SETTINGS_FILE_NAME
112
112
  global_directory = File.dirname(global_path)
113
- FileUtils.mkdir_p(global_directory) unless File.directory? global_directory
113
+
114
+ unless File.directory?(global_directory)
115
+ require 'fileutils'
116
+ FileUtils.mkdir_p(global_directory)
117
+ end
118
+
114
119
  File.open(global_path, 'w') do |file|
115
120
  file.write @global_settings.to_yaml
116
121
  end
data/lib/geordi/util.rb CHANGED
@@ -116,7 +116,7 @@ module Geordi
116
116
 
117
117
  def current_branch
118
118
  if testing?
119
- 'master'
119
+ git_default_branch
120
120
  else
121
121
  `git rev-parse --abbrev-ref HEAD`.strip
122
122
  end
@@ -217,6 +217,18 @@ module Geordi
217
217
  def rspec_path?(path)
218
218
  %r{(^|\/)spec|_spec\.rb($|:)}.match?(path)
219
219
  end
220
+
221
+ def git_default_branch
222
+ default_branch = if testing?
223
+ ENV['GEORDI_TESTING_DEFAULT_BRANCH']
224
+ else
225
+ head_symref = `git ls-remote --symref origin HEAD`
226
+ head_symref[%r{\Aref: refs/heads/(\S+)\sHEAD}, 1]
227
+ end
228
+
229
+ default_branch || 'master'
230
+ end
231
+
220
232
  end
221
233
  end
222
234
  end
@@ -1,3 +1,3 @@
1
1
  module Geordi
2
- VERSION = '11.1.0'.freeze
2
+ VERSION = '11.2.1'.freeze
3
3
  end
@@ -0,0 +1,125 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6
+ xmlns:cc="http://creativecommons.org/ns#"
7
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8
+ xmlns:svg="http://www.w3.org/2000/svg"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ xmlns:xlink="http://www.w3.org/1999/xlink"
11
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
12
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
13
+ width="35.7663mm"
14
+ height="14.056225mm"
15
+ viewBox="0 0 35.766299 14.056225"
16
+ version="1.1"
17
+ id="svg838"
18
+ inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
19
+ sodipodi:docname="logo.dark.shapes.svg"
20
+ inkscape:export-filename="/home/henning/Projects/capybara-lockstep/media/capybara-lockstep.dark.png"
21
+ inkscape:export-xdpi="196"
22
+ inkscape:export-ydpi="196">
23
+ <defs
24
+ id="defs832">
25
+ <linearGradient
26
+ inkscape:collect="always"
27
+ id="linearGradient1406">
28
+ <stop
29
+ style="stop-color:#ff0844;stop-opacity:1"
30
+ offset="0"
31
+ id="stop1402" />
32
+ <stop
33
+ style="stop-color:#ffb199;stop-opacity:1"
34
+ offset="1"
35
+ id="stop1404" />
36
+ </linearGradient>
37
+ <linearGradient
38
+ inkscape:collect="always"
39
+ xlink:href="#linearGradient1406"
40
+ id="linearGradient1408"
41
+ x1="22.054907"
42
+ y1="91.071762"
43
+ x2="88.956696"
44
+ y2="91.071762"
45
+ gradientUnits="userSpaceOnUse"
46
+ gradientTransform="matrix(0.53371623,0,0,0.08820435,-11.771062,57.908781)" />
47
+ </defs>
48
+ <sodipodi:namedview
49
+ id="base"
50
+ pagecolor="#ffffff"
51
+ bordercolor="#666666"
52
+ borderopacity="1.0"
53
+ inkscape:pageopacity="0.0"
54
+ inkscape:pageshadow="2"
55
+ inkscape:zoom="3.959798"
56
+ inkscape:cx="107.13075"
57
+ inkscape:cy="16.774239"
58
+ inkscape:document-units="mm"
59
+ inkscape:current-layer="layer1"
60
+ showgrid="false"
61
+ fit-margin-top="0"
62
+ fit-margin-left="0"
63
+ fit-margin-right="0"
64
+ fit-margin-bottom="0"
65
+ inkscape:window-width="2560"
66
+ inkscape:window-height="1391"
67
+ inkscape:window-x="1920"
68
+ inkscape:window-y="0"
69
+ inkscape:window-maximized="1"
70
+ inkscape:pagecheckerboard="true" />
71
+ <metadata
72
+ id="metadata835">
73
+ <rdf:RDF>
74
+ <cc:Work
75
+ rdf:about="">
76
+ <dc:format>image/svg+xml</dc:format>
77
+ <dc:type
78
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
79
+ <dc:title></dc:title>
80
+ </cc:Work>
81
+ </rdf:RDF>
82
+ </metadata>
83
+ <g
84
+ inkscape:label="Layer 1"
85
+ inkscape:groupmode="layer"
86
+ id="layer1"
87
+ transform="translate(0.05820833,-52.518951)">
88
+ <g
89
+ aria-label="GEORDI"
90
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:1.25;font-family:'League Spartan';-inkscape-font-specification:'League Spartan';letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332"
91
+ id="text1385">
92
+ <path
93
+ d="m 3.4766249,55.725701 h 3.5612916 v 0.4445 q 0,0.751417 -0.254,1.402292 -0.2487084,0.650875 -0.714375,1.143 -0.4656667,0.492125 -1.11125,0.767291 -0.6455833,0.275167 -1.4287499,0.275167 -0.809625,0 -1.4710833,-0.275167 -0.6561667,-0.280458 -1.13241666,-0.777875 -0.47624999,-0.497416 -0.73024998,-1.153583 -0.25399999,-0.661458 -0.25399999,-1.418167 0,-0.751416 0.25399999,-1.407583 0.25399999,-0.661458 0.73024998,-1.153583 0.47624996,-0.497417 1.13241666,-0.772584 0.6614583,-0.280458 1.4710833,-0.280458 0.6614583,0 1.1641666,0.142875 0.508,0.142875 0.873125,0.381 0.365125,0.238125 0.6191249,0.523875 0.254,0.280458 0.4233334,0.550333 L 5.1064582,54.826118 Q 4.8894999,54.492743 4.5137915,54.244034 4.1433749,53.995326 3.5295416,53.995326 q -0.428625,0 -0.7884584,0.169333 Q 2.3865416,54.333993 2.1272499,54.630326 1.8679583,54.921368 1.7250833,55.312951 1.5875,55.699243 1.5875,56.133159 q 0,0.439209 0.1375833,0.8255 0.142875,0.386292 0.4021666,0.682625 0.2592917,0.296334 0.6138333,0.465667 0.3598334,0.164042 0.7884584,0.164042 0.3757083,0 0.6826249,-0.09525 0.3069167,-0.09525 0.5291667,-0.275167 0.2275416,-0.179917 0.3545416,-0.423333 0.1322917,-0.248709 0.15875,-0.545042 H 3.4766249 Z"
94
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'League Spartan';-inkscape-font-specification:'League Spartan';fill:#ffffff;fill-opacity:1;stroke-width:0.26458332"
95
+ id="path822" />
96
+ <path
97
+ d="m 7.9427778,52.645951 h 4.4608752 v 1.386417 H 9.5196944 v 1.423458 h 2.8574996 v 1.344083 H 9.5196944 v 1.444625 h 2.8839586 v 1.386417 H 7.9427778 Z"
98
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'League Spartan';-inkscape-font-specification:'League Spartan';fill:#ffffff;fill-opacity:1;stroke-width:0.26458332"
99
+ id="path824" />
100
+ <path
101
+ d="m 15.023009,56.133159 q 0,0.597959 0.243416,1.084792 0.248709,0.481542 0.682625,0.767292 0.439209,0.28575 1.016,0.28575 0.576792,0 1.010709,-0.28575 0.439208,-0.28575 0.682625,-0.767292 0.248708,-0.486833 0.248708,-1.084792 0,-0.597958 -0.248708,-1.0795 -0.243417,-0.481541 -0.682625,-0.767291 -0.433917,-0.291042 -1.010709,-0.291042 -0.576791,0 -1.016,0.291042 -0.433916,0.28575 -0.682625,0.767291 -0.243416,0.481542 -0.243416,1.0795 z m -1.645709,0 q 0,-0.762 0.269875,-1.418166 0.269875,-0.661459 0.756709,-1.153584 0.486833,-0.492125 1.143,-0.767291 0.656166,-0.275167 1.418166,-0.275167 0.772584,0 1.423459,0.275167 0.656166,0.275166 1.137708,0.767291 0.486833,0.492125 0.751417,1.153584 0.269875,0.656166 0.269875,1.418166 0,0.767292 -0.259292,1.42875 -0.259292,0.656167 -0.740833,1.153584 -0.481542,0.492125 -1.137709,0.767291 -0.656166,0.275167 -1.444625,0.275167 -0.804333,0 -1.465791,-0.275167 -0.656167,-0.275166 -1.132417,-0.767291 -0.47625,-0.497417 -0.735542,-1.153584 -0.254,-0.661458 -0.254,-1.42875 z"
102
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'League Spartan';-inkscape-font-specification:'League Spartan';fill:#ffffff;fill-opacity:1;stroke-width:0.26458332"
103
+ id="path826" />
104
+ <path
105
+ d="m 21.42062,52.645951 h 2.846916 q 0.608542,0 1.084792,0.254 0.47625,0.254 0.751417,0.735542 0.280458,0.47625 0.280458,1.137708 0,0.661458 -0.238125,1.084792 -0.232833,0.418041 -0.560917,0.629708 -0.328083,0.206375 -0.608541,0.248708 l 1.698625,2.894542 h -1.778 l -1.513417,-2.772833 h -0.381 v 2.772833 H 21.42062 Z m 1.582208,3.116792 h 0.6985 q 0.423333,0 0.740833,-0.206375 0.3175,-0.206375 0.3175,-0.73025 0,-0.523875 -0.312208,-0.724959 -0.312208,-0.206375 -0.735542,-0.206375 h -0.709083 z"
106
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'League Spartan';-inkscape-font-specification:'League Spartan';fill:#ffffff;fill-opacity:1;stroke-width:0.26458332"
107
+ id="path828" />
108
+ <path
109
+ d="m 27.728279,52.645951 h 2.100792 q 1.116542,0 1.846792,0.449792 0.735541,0.4445 1.100666,1.232958 0.365125,0.788458 0.365125,1.804458 0,1.021292 -0.365125,1.80975 -0.365125,0.788459 -1.100666,1.23825 -0.73025,0.449792 -1.846792,0.449792 h -2.100792 z m 1.576917,1.402292 v 4.180416 h 0.381 q 0.597958,0 0.989542,-0.269875 0.391583,-0.275166 0.587375,-0.746125 0.201083,-0.47625 0.201083,-1.068916 0,-0.597959 -0.195792,-1.068917 -0.1905,-0.47625 -0.587375,-0.751417 -0.396875,-0.275166 -0.994833,-0.275166 z"
110
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'League Spartan';-inkscape-font-specification:'League Spartan';fill:#ffffff;fill-opacity:1;stroke-width:0.26458332"
111
+ id="path830" />
112
+ <path
113
+ d="m 34.125883,52.645951 h 1.582208 v 6.985 h -1.582208 z"
114
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'League Spartan';-inkscape-font-specification:'League Spartan';fill:#ffffff;fill-opacity:1;stroke-width:0.26458332"
115
+ id="path832" />
116
+ </g>
117
+ <rect
118
+ style="fill:url(#linearGradient1408);fill-opacity:1;stroke:none;stroke-width:0.02169702;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
119
+ id="rect1387"
120
+ width="35.70657"
121
+ height="1.2668874"
122
+ x="-3.5435547e-15"
123
+ y="65.308289" />
124
+ </g>
125
+ </svg>